From ac1a09873d2944d7147efb7c42830d1844fe2c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Pi=C3=B1a?= Date: Thu, 17 Dec 2020 14:06:09 -0800 Subject: [PATCH] Validate setting JetStream APIPrefix This adds a check to nats.ApiPrefix that prevents the prefix from containing wildcards. When @wallyqs and I were exploring the code, we found that we could end up with invalid API subjects like foo.>.STREAM.NAMES. Also, this removes what appears to be outdated prefix TODOs. --- js.go | 23 ++++++++++++++++++--- nats_test.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/js.go b/js.go index abd71c7ff..e86dd59d6 100644 --- a/js.go +++ b/js.go @@ -165,10 +165,27 @@ func (opt jsOptFn) configureJSContext(opts *js) error { // APIPrefix changes the default prefix used for the JetStream API. func APIPrefix(pre string) JSOpt { return jsOptFn(func(js *js) error { - js.pre = pre - if !strings.HasSuffix(js.pre, ".") { - js.pre = js.pre + "." + pre = strings.TrimSuffix(pre, ".") + + if pre == ">" { + return ErrJetStreamBadPre } + + toks := strings.Split(pre, ".") + for i, tok := range toks { + if tok == "" || tok == "*" { + return ErrJetStreamBadPre + } + + if tok == ">" && i < len(toks)-1 { + return ErrBadSubject + } else if tok == ">" && i == len(toks)-1 { + js.pre = pre + return nil + } + } + + js.pre = fmt.Sprintf("%s.", pre) return nil }) } diff --git a/nats_test.go b/nats_test.go index 665fa6722..b76a4c62d 100644 --- a/nats_test.go +++ b/nats_test.go @@ -2599,3 +2599,61 @@ func TestMsg_RespondMsg(t *testing.T) { t.Fatalf("did not get correct response: %q", resp.Data) } } + +func TestJetStreamAPIPrefix(t *testing.T) { + cases := []struct { + prefix string + wantPrefix string + wantErr bool + }{ + { + prefix: "foo", + wantPrefix: "foo.", + }, + { + prefix: "foo.", + wantPrefix: "foo.", + }, + { + prefix: "foo.>", + wantPrefix: "foo.>", + }, + { + prefix: "foo.b*r.baz", + wantPrefix: "foo.b*r.baz.", + }, + { + prefix: "foo.*", + wantErr: true, + }, + { + prefix: "foo.*.bar", + wantErr: true, + }, + { + prefix: "foo.>.bar", + wantErr: true, + }, + { + prefix: ">", + wantErr: true, + }, + } + for _, c := range cases { + t.Run(c.prefix, func(t *testing.T) { + jsOpt := APIPrefix(c.prefix) + + js := new(js) + if err := jsOpt.configureJSContext(js); err != nil && !c.wantErr { + t.Fatal(err) + } else if err == nil && c.wantErr { + t.Fatal("unexpected success") + } + + if js.pre != c.wantPrefix { + t.Error("unexpected api prefix") + t.Fatalf("got=%s; want=%s", js.pre, c.wantPrefix) + } + }) + } +}