diff --git a/.github/workflows/natscontext.yaml b/.github/workflows/natscontext.yaml new file mode 100644 index 0000000..5a617b8 --- /dev/null +++ b/.github/workflows/natscontext.yaml @@ -0,0 +1,59 @@ +name: natscontext +on: + push: + paths: + - 'natscontext/**' + + pull_request: + paths: + - 'natscontext/**' + + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 'stable' + + - name: Install deps + working-directory: natscontext + shell: bash --noprofile --norc -x -eo pipefail {0} + run: | + go get -t ./... + go install honnef.co/go/tools/cmd/staticcheck@latest + go install github.com/client9/misspell/cmd/misspell@latest + + - name: Run linters + working-directory: natscontext + shell: bash --noprofile --norc -x -eo pipefail {0} + run: | + $(exit $(go fmt ./... | wc -l)) + go vet ./... + go vet ./test/... + staticcheck ./... + staticcheck ./test/... + find . -type f -name "*.go" | xargs misspell -error -locale US + + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 'stable' + + - name: Run tests + working-directory: natscontext + shell: bash --noprofile --norc -x -eo pipefail {0} + run: | + go test -v -count=1 ./... + go test -v -count=1 ./test/... diff --git a/README.md b/README.md index a02b72b..04f22a1 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ You can use the library as a whole, or pick just what you need. # Utilities -| Module | Description | Docs | -|----------------------|----------------------|--------------------------------| -| Core NATS Extensions | Core NATS extensions | [README.md](natsext/README.md) | +| Module | Description | Docs | +|----------------------|----------------------------------------------|------------------------------------| +| Core NATS Extensions | Core NATS extensions | [README.md](natsext/README.md) | +| `natscontext` | Allow connecting to NATS using NATS Contexts | [README.md](natscontext/README.md) | diff --git a/natscontext/README.md b/natscontext/README.md new file mode 100644 index 0000000..d1ea34a --- /dev/null +++ b/natscontext/README.md @@ -0,0 +1,37 @@ +# NATS Context Connection Helper + +This is a package that helps Go developers connect to NATS using a NATS Context as featured in the `nats` Command Line +Tool. + +## Installation + +```bash +go get github.com/synadia-io/orbit.go/natscontext +``` + +## Usage + +Using the `nats` command line create a Context that can connect to your server, here we use a credential in a file: + +```bash +nats context add staging --creds /home/user/staging.creds --js-domain STAGING +``` + +We can now use the context called `staging` from Go: + +```go +nc, settings, err := natscontext.Connect("staging", nats.Name("my application")) +if err != nil { + // handle error +} + +// Get a JetStream handle using the domain in the context +js, err := jetstream.NewWithDomain(nc, settings.JSDomain) +if err != nil { + // handle error +} +``` + +If the full path to a context JSON file is given instead of the friendly name then that file will be used. + +All context settings are supported except Windows Certificate Store related settings. \ No newline at end of file diff --git a/natscontext/context.go b/natscontext/context.go new file mode 100644 index 0000000..43317b4 --- /dev/null +++ b/natscontext/context.go @@ -0,0 +1,337 @@ +// Copyright 2022-2024 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package natscontext + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "os/user" + "path/filepath" + "strings" + + "github.com/nats-io/nats.go" +) + +type context struct { + Name string `json:"-"` + config *Settings + path string +} + +type nscCreds struct { + UserCreds string `json:"user_creds"` + Operator struct { + Service []string `json:"service"` + } `json:"operator"` +} + +type Settings struct { + Name string `json:"name,omitempty"` + Description string `json:"description"` + URL string `json:"url"` + nscUrl string + SocksProxy string `json:"socks_proxy"` + Token string `json:"token"` + User string `json:"user"` + Password string `json:"password"` + Creds string `json:"creds"` + nscCreds string + NKey string `json:"nkey"` + Cert string `json:"cert"` + Key string `json:"key"` + CA string `json:"ca"` + NSCLookup string `json:"nsc"` + JSDomain string `json:"jetstream_domain"` + JSAPIPrefix string `json:"jetstream_api_prefix"` + JSEventPrefix string `json:"jetstream_event_prefix"` + InboxPrefix string `json:"inbox_prefix"` + UserJwt string `json:"user_jwt"` + ColorScheme string `json:"color_scheme"` + TLSFirst bool `json:"tls_first"` + WinCertStoreType string `json:"windows_cert_store"` + WinCertStoreMatchBy string `json:"windows_cert_match_by"` + WinCertStoreMatch string `json:"windows_cert_match"` + WinCertStoreCaMatch []string `json:"windows_ca_certs_match"` +} + +// Connect connects to the NATS server configured by the named context, empty name connects to selected context. +// If the name is a absolute name to a context configuration that will be used. The settings that are returned +// will include all the values from the Context so values like the JetStream Domain etc can be used later +func Connect(name string, opts ...nats.Option) (*nats.Conn, Settings, error) { + var nctx *context + var err error + + absName, _ := filepath.Abs(name) + if name != "" && absName == name { + nctx, err = newFromFile(name) + } else { + nctx, err = newFromName(name) + } + if err != nil { + return nil, Settings{}, err + } + + nc, err := nctx.connect(opts...) + if err != nil { + return nil, Settings{}, err + } + + return nc, *nctx.config, nil +} + +func (c *context) connect(opts ...nats.Option) (*nats.Conn, error) { + nopts, err := c.natsOptions(opts...) + if err != nil { + return nil, err + } + + return nats.Connect(c.config.URL, nopts...) +} + +func (c *context) natsOptions(opts ...nats.Option) ([]nats.Option, error) { + var nopts []nats.Option + + switch { + case c.config.User != "": + nopts = append(nopts, nats.UserInfo(c.config.User, c.config.Password)) + case c.config.Creds != "": + nopts = append(nopts, nats.UserCredentials(expandHomedir(c.config.Creds))) + + case c.config.NKey != "": + nko, err := nats.NkeyOptionFromSeed(expandHomedir(c.config.NKey)) + if err != nil { + return nil, err + } + + nopts = append(nopts, nko) + } + + if c.config.Token != "" { + nopts = append(nopts, nats.Token(expandHomedir(c.config.Token))) + } + + if c.config.Cert != "" && c.config.Key != "" { + nopts = append(nopts, nats.ClientCert(expandHomedir(c.config.Cert), expandHomedir(c.config.Key))) + } + + if c.config.CA != "" { + nopts = append(nopts, nats.RootCAs(expandHomedir(c.config.CA))) + } + + if c.config.SocksProxy != "" { + nopts = append(nopts, nats.SetCustomDialer(c.SOCKSDialer())) + } + + if c.config.InboxPrefix != "" { + nopts = append(nopts, nats.CustomInboxPrefix(c.config.InboxPrefix)) + } + + if c.config.TLSFirst { + nopts = append(nopts, nats.TLSHandshakeFirst()) + } + + if c.config.WinCertStoreType != "" { + return nil, fmt.Errorf("windows cert stores are not supported") + } + + nopts = append(nopts, opts...) + + return nopts, nil +} + +func expandHomedir(path string) string { + if path[0] != '~' { + return path + } + + usr, err := user.Current() + if err != nil { + return path + } + + return strings.Replace(path, "~", usr.HomeDir, 1) +} + +func newFromName(name string) (*context, error) { + c := &context{ + Name: name, + config: &Settings{}, + } + + err := c.loadActiveContext() + if err != nil { + return nil, err + } + + return c, nil +} + +func newFromFile(filename string) (*context, error) { + c := &context{ + Name: strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename)), + config: &Settings{}, + path: filename, + } + + err := c.loadActiveContext() + if err != nil { + return nil, err + } + + return c, nil +} + +func readCtxFromFile(file string) string { + parent, err := parentDir() + if err != nil { + return "" + } + + currentFile := filepath.Join(parent, "nats", file) + + _, err = os.Stat(currentFile) + if os.IsNotExist(err) { + return "" + } + + fc, err := os.ReadFile(currentFile) + if err != nil { + return "" + } + + return strings.TrimSpace(string(fc)) +} + +func selectedContext() string { + return readCtxFromFile("context.txt") +} + +func validName(name string) bool { + return name != "" && !strings.Contains(name, "..") && !strings.Contains(name, string(os.PathSeparator)) +} + +func ctxDir(parent string) string { + return filepath.Join(parent, "nats", "context") +} + +func knownContext(parent string, name string) bool { + if !validName(name) { + return false + } + + _, err := os.Stat(filepath.Join(ctxDir(parent), name+".json")) + return !os.IsNotExist(err) +} + +func (c *context) loadActiveContext() error { + if c.path == "" { + parent, err := parentDir() + if err != nil { + return err + } + + // none given, lets try to find it via the fs + if c.Name == "" { + c.Name = selectedContext() + if c.Name == "" { + return nil + } + } + + if !validName(c.Name) { + return fmt.Errorf("invalid context name %s", c.Name) + } + + if !knownContext(parent, c.Name) { + return fmt.Errorf("unknown context %q", c.Name) + } + + c.path = filepath.Join(parent, "nats", "context", c.Name+".json") + } + + ctxContent, err := os.ReadFile(c.path) + if err != nil { + return err + } + + err = json.Unmarshal(ctxContent, c.config) + if err != nil { + return err + } + + // performing environment variable expansion for the path of the cerds. + c.config.Creds = os.ExpandEnv(c.config.Creds) + + if c.config.NSCLookup != "" { + err := c.resolveNscLookup() + if err != nil { + return err + } + } + + return nil +} + +func (c *context) resolveNscLookup() error { + if c.config.NSCLookup == "" { + return nil + } + + path, err := exec.LookPath("nsc") + if err != nil { + return fmt.Errorf("cannot find 'nsc' in user path") + } + + cmd := exec.Command(path, "generate", "profile", c.config.NSCLookup) + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("nsc invoke failed: %s", string(out)) + } + + var result nscCreds + err = json.Unmarshal(out, &result) + if err != nil { + return fmt.Errorf("could not parse nsc output: %s", err) + } + + if result.UserCreds != "" { + c.config.nscCreds = result.UserCreds + } + + if len(result.Operator.Service) > 0 { + c.config.nscUrl = strings.Join(result.Operator.Service, ",") + } + + return nil +} + +func parentDir() (string, error) { + parent := os.Getenv("XDG_CONFIG_HOME") + if parent != "" { + return parent, nil + } + + u, err := user.Current() + if err != nil { + return "", err + } + + if u.HomeDir == "" { + return "", fmt.Errorf("cannot determine home directory") + } + + return filepath.Join(u.HomeDir, parent, ".config"), nil +} diff --git a/natscontext/dialer.go b/natscontext/dialer.go new file mode 100644 index 0000000..392452a --- /dev/null +++ b/natscontext/dialer.go @@ -0,0 +1,52 @@ +// Copyright 2022-2024 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package natscontext + +import ( + "net" + "net/url" + + "github.com/nats-io/nats.go" + "golang.org/x/net/proxy" +) + +// In context.go we have the regular accessors for the context, +// WithSocksProxy and SocksProxy. +// +// The NATSOptions builder will call SOCKSDialer to get our custom dialer, +// to pass along, if the proxy is set. The result has to satisfy the +// nats.CustomDialer interface. + +// SocksDialer should satisfy the NATS CustomDialer interface +type SocksDialer struct { + proxy string +} + +var _ nats.CustomDialer = SocksDialer{} + +func (c *context) SOCKSDialer() SocksDialer { + return SocksDialer{proxy: c.config.SocksProxy} +} + +func (sd SocksDialer) Dial(network, address string) (net.Conn, error) { + u, err := url.Parse(sd.proxy) + if err != nil { + return nil, err + } + dialer, err := proxy.FromURL(u, proxy.Direct) + if err != nil { + return nil, err + } + return dialer.Dial(network, address) +} diff --git a/natscontext/expansion_test.go b/natscontext/expansion_test.go new file mode 100644 index 0000000..860a3d2 --- /dev/null +++ b/natscontext/expansion_test.go @@ -0,0 +1,36 @@ +// Copyright 2022 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package natscontext + +import "testing" + +func TestContext(t *testing.T) { + // Do nothing if the string does not start with ~ + t1 := expandHomedir("foo") + if t1 != "foo" { + t.Fatalf("failed to expand home directory for string 'foo': %s", t1) + } + + // Expand ~ to HOMEDIR if string starts with ~ + t2 := expandHomedir("~/foo") + if t2 == "~/foo" { + t.Fatalf("failed to expand home directory for string 'foo': %s", t2) + } + + // Do nothing if there is a ~ but it is not the first character of the string + t3 := expandHomedir("/~/foo") + if t3 != "/~/foo" { + t.Fatalf("failed to expand home directory for string 'foo': %s", t3) + } +} diff --git a/natscontext/go.mod b/natscontext/go.mod new file mode 100644 index 0000000..ceaf3cb --- /dev/null +++ b/natscontext/go.mod @@ -0,0 +1,16 @@ +module github.com/synadia-io/orbit.go/natscontext + +go 1.22.0 + +require ( + github.com/nats-io/nats.go v1.37.0 + golang.org/x/net v0.31.0 +) + +require ( + github.com/klauspost/compress v1.17.11 // indirect + github.com/nats-io/nkeys v0.4.7 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + golang.org/x/crypto v0.29.0 // indirect + golang.org/x/sys v0.27.0 // indirect +) diff --git a/natscontext/go.sum b/natscontext/go.sum new file mode 100644 index 0000000..3736a01 --- /dev/null +++ b/natscontext/go.sum @@ -0,0 +1,14 @@ +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE= +github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/natscontext/go.work b/natscontext/go.work new file mode 100644 index 0000000..080652d --- /dev/null +++ b/natscontext/go.work @@ -0,0 +1,6 @@ +go 1.22.1 + +use ( + . + ./test +) diff --git a/natscontext/go.work.sum b/natscontext/go.work.sum new file mode 100644 index 0000000..b4b2a84 --- /dev/null +++ b/natscontext/go.work.sum @@ -0,0 +1,13 @@ +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= diff --git a/natscontext/test/context_test.go b/natscontext/test/context_test.go new file mode 100644 index 0000000..11bc469 --- /dev/null +++ b/natscontext/test/context_test.go @@ -0,0 +1,100 @@ +package test + +import ( + "encoding/json" + "github.com/nats-io/nats-server/v2/server" + natsserver "github.com/nats-io/nats-server/v2/test" + "github.com/nats-io/nats.go" + "github.com/synadia-io/orbit.go/natscontext" + "os" + "testing" + "time" +) + +func TestContext(t *testing.T) { + srv, _ := RunServerWithConfig("testdata/server.conf") + defer srv.Shutdown() + + nctx := natscontext.Settings{ + URL: srv.ClientURL(), + User: "test", + Password: "s3cret", + } + + j, _ := json.Marshal(nctx) + tf, err := os.CreateTemp("", "") + if err != nil { + t.Fatalf("creating temp file failed: %v", err) + } + defer os.Remove(tf.Name()) + + _, err = tf.Write(j) + if err != nil { + t.Fatalf("writing temp file failed: %v", err) + } + tf.Close() + + nc, _, err := natscontext.Connect(tf.Name(), nats.Name("unit tests")) + if err != nil { + t.Fatalf("connecting to nats server failed: %v", err) + } + + resp, err := nc.Request("$SYS.REQ.SERVER.PING.CONNZ", nil, 2*time.Second) + if err != nil { + t.Fatalf("user info failed: %v", err) + } + + type connz struct { + Data struct { + Connections server.ConnInfos `json:"connections"` + } `json:"data"` + } + + var nfo connz + err = json.Unmarshal(resp.Data, &nfo) + if err != nil { + t.Fatalf("invalid user info: %v", err) + } + + if len(nfo.Data.Connections) != 1 { + t.Fatalf("invalid number of connections: %d", len(nfo.Data.Connections)) + } + + if nfo.Data.Connections[0].Name != "unit tests" { + t.Fatalf("invalid connection name: %q", nfo.Data.Connections[0].Name) + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Running nats server in separate Go routines +//////////////////////////////////////////////////////////////////////////////// + +// RunDefaultServer will run a server on the default port. +func RunDefaultServer() *server.Server { + return RunServerOnPort(nats.DefaultPort) +} + +// RunServerOnPort will run a server on the given port. +func RunServerOnPort(port int) *server.Server { + opts := natsserver.DefaultTestOptions + opts.Port = port + opts.Cluster.Name = "testing" + return RunServerWithOptions(&opts) +} + +// RunServerWithOptions will run a server with the given options. +func RunServerWithOptions(opts *server.Options) *server.Server { + return natsserver.RunServer(opts) +} + +// RunServerWithConfig will run a server with the given configuration file. +func RunServerWithConfig(configFile string) (*server.Server, *server.Options) { + return natsserver.RunServerWithConfig(configFile) +} + +func RunBasicJetStreamServer() *server.Server { + opts := natsserver.DefaultTestOptions + opts.Port = -1 + opts.JetStream = true + return RunServerWithOptions(&opts) +} diff --git a/natscontext/test/go.mod b/natscontext/test/go.mod new file mode 100644 index 0000000..f18ad5b --- /dev/null +++ b/natscontext/test/go.mod @@ -0,0 +1,17 @@ +module github.com/synadia-io/orbit.go/natscontext/test + +go 1.22.1 + +require github.com/nats-io/nats-server/v2 v2.10.22 + +require ( + github.com/klauspost/compress v1.17.11 // indirect + github.com/minio/highwayhash v1.0.3 // indirect + github.com/nats-io/jwt/v2 v2.5.8 // indirect + github.com/nats-io/nats.go v1.37.0 // indirect + github.com/nats-io/nkeys v0.4.7 // indirect + github.com/nats-io/nuid v1.0.1 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/time v0.7.0 // indirect +) diff --git a/natscontext/test/go.sum b/natscontext/test/go.sum new file mode 100644 index 0000000..3db62c5 --- /dev/null +++ b/natscontext/test/go.sum @@ -0,0 +1,23 @@ +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/nats-io/jwt/v2 v2.5.8 h1:uvdSzwWiEGWGXf+0Q+70qv6AQdvcvxrv9hPM0RiPamE= +github.com/nats-io/jwt/v2 v2.5.8/go.mod h1:ZdWS1nZa6WMZfFwwgpEaqBV8EPGVgOTDHN/wTbz0Y5A= +github.com/nats-io/nats-server/v2 v2.10.22 h1:Yt63BGu2c3DdMoBZNcR6pjGQwk/asrKU7VX846ibxDA= +github.com/nats-io/nats-server/v2 v2.10.22/go.mod h1:X/m1ye9NYansUXYFrbcDwUi/blHkrgHh2rgCJaakonk= +github.com/nats-io/nats.go v1.36.0 h1:suEUPuWzTSse/XhESwqLxXGuj8vGRuPRoG7MoRN/qyU= +github.com/nats-io/nats.go v1.36.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE= +github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= diff --git a/natscontext/test/testdata/server.conf b/natscontext/test/testdata/server.conf new file mode 100644 index 0000000..4d48013 --- /dev/null +++ b/natscontext/test/testdata/server.conf @@ -0,0 +1,6 @@ +port: -1 + +authorization { + user: "test" + password: "s3cret" +} \ No newline at end of file diff --git a/natsext/go.work.sum b/natsext/go.work.sum index ce021a9..0e53159 100644 --- a/natsext/go.work.sum +++ b/natsext/go.work.sum @@ -1,17 +1,21 @@ github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/nats-io/nats.go v1.36.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=