Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ replace github.com/MoeForge/moego v0.1.0-alpha.1 => github.com/router-for-me/moe
require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dlclark/regexp2/v2 v2.5.1 // indirect
github.com/nats-io/nkeys v0.4.17 // indirect
github.com/pion/datachannel v1.6.2 // indirect
github.com/pion/dtls/v3 v3.1.5 // indirect
github.com/pion/logging v0.2.4 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/nats-io/nkeys v0.4.17 h1:JAJrlDhOyQqOt0a1eg4cbIZ1Kc7+vmkCigAltpwQpVA=
github.com/nats-io/nkeys v0.4.17/go.mod h1:llLgWoI0o4z/Q57q2R1kHfmocyhGV6VG/U18Glg1Afs=
github.com/pelletier/go-toml/v2 v2.4.3-0.20260624044523-35f78d5908f1 h1:gIZQQ2+wbsdQGWLPDSdJFptR25tBCjSC0KbSIQZ1rgE=
github.com/pelletier/go-toml/v2 v2.4.3-0.20260624044523-35f78d5908f1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pierrec/xxHash v0.1.5 h1:n/jBpwTHiER4xYvK3/CdPVnLDPchj8eTJFFLUb4QHBo=
Expand Down
63 changes: 63 additions & 0 deletions internal/store/natsstore/secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Package natsstore holds the NATS JetStream connection, settings and bucket
// bootstrap that back the NATS token store.
package natsstore

import (
"fmt"
"strings"
)

const redacted = "[redacted]"

// Secret wraps a credential so it never reaches logs, errors or serialized
// output by accident. Only Reveal returns the value.
type Secret struct {
value string
}

// NewSecret wraps value, reporting false for an empty one because empty counts as unset.
func NewSecret(value string) (Secret, bool) {
if value == "" {
return Secret{}, false
}
return Secret{value: value}, true
}

// Reveal returns the wrapped value for the one place that hands it to the NATS client.
func (s Secret) Reveal() string { return s.value }

func (s Secret) String() string { return redacted }

func (s Secret) GoString() string { return redacted }

// Format redacts the secret under every fmt verb, including %v and %+v on a struct holding it.
func (s Secret) Format(f fmt.State, _ rune) { _, _ = f.Write([]byte(redacted)) }

func (s Secret) MarshalText() ([]byte, error) { return []byte(redacted), nil }

func (s Secret) MarshalJSON() ([]byte, error) { return []byte(`"` + redacted + `"`), nil }

// redactServer strips URL userinfo so a server address is safe to log.
func redactServer(server string) string {
rest := server
scheme := ""
if i := strings.Index(rest, "://"); i >= 0 {
scheme, rest = rest[:i+3], rest[i+3:]
}
host := rest
if i := strings.IndexAny(rest, "/?#"); i >= 0 {
host = rest[:i]
}
if at := strings.LastIndex(host, "@"); at >= 0 {
return scheme + redacted + "@" + rest[at+1:]
}
return server
}

func redactServers(servers []string) []string {
out := make([]string, len(servers))
for i, server := range servers {
out[i] = redactServer(server)
}
return out
}
Loading
Loading