Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/setec: be more deliberate about whitespace in text values #108

Merged
merged 2 commits into from
May 1, 2024
Merged
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
59 changes: 46 additions & 13 deletions cmd/setec/setec.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,11 @@ With --from-file, the new value is read from the specified file; otherwise if
stdin is connected to a pipe, its contents are fully read to obtain the new
value. Otherwise, the user is prompted for a new value and confirmation.

By default, leading and trailing whitespace is trimmed from plain text values.
Use --verbatim to suppress this behaviour for values where whitespace matters,
such as SSH keys.`,
If the provided value is plain UTF-8 text with leading or trailing whitespace,
you must specify what to do with the whitespace. Use --verbatim to keep it, or
--trim-space to remove it. If you do not specify either, an error is reported.
If you specify both, --verbatim takes precedence. Use --verbatim for values
where whitespace matters, such as PEM-formatted certificates and SSH keys.`,

SetFlags: command.Flags(flax.MustBind, &putArgs),
Run: command.Adapt(runPut),
Expand Down Expand Up @@ -367,9 +369,10 @@ func runGet(env *command.Env, name string) error {
}

var putArgs struct {
File string `flag:"from-file,Read secret value from this file instead of stdin"`
EmptyOK bool `flag:"empty-ok,Allow an empty secret value"`
Verbatim bool `flag:"verbatim,Do not trim whitespace from plain text values"`
File string `flag:"from-file,Read secret value from this file instead of stdin"`
EmptyOK bool `flag:"empty-ok,Allow an empty secret value"`
Verbatim bool `flag:"verbatim,Do not trim whitespace from plain text values"`
TrimSpace bool `flag:"trim-space,Trim whitespace from plain text values"`
}

func runPut(env *command.Env, name string) error {
Expand All @@ -386,13 +389,11 @@ func runPut(env *command.Env, name string) error {
if err != nil {
return err
}
// If the value we read is all valid UTF-8 and the user has not asked us
// to do otherwise, trim leading and trailing whitespace. For non-text
// inputs we shouldn't do that.
if utf8.Valid(value) && !putArgs.Verbatim {
value = bytes.TrimSpace(value)
}
if len(value) == 0 && !putArgs.EmptyOK {

value, err = checkPutText(value)
if err != nil {
return err
} else if len(value) == 0 && !putArgs.EmptyOK {
return errors.New("empty secret value")
}
} else if term.IsTerminal(int(os.Stdin.Fd())) {
Expand Down Expand Up @@ -424,6 +425,11 @@ func runPut(env *command.Env, name string) error {
value, err = io.ReadAll(os.Stdin)
if err != nil {
return fmt.Errorf("read from stdin: %w", err)
}

value, err = checkPutText(value)
if err != nil {
return err
} else if len(value) == 0 && !putArgs.EmptyOK {
return errors.New("empty secret value")
}
Expand Down Expand Up @@ -527,3 +533,30 @@ func checkConfirmation(req, token string) error {
func newTabWriter(w io.Writer) *tabwriter.Writer {
return tabwriter.NewWriter(w, 0, 4, 1, ' ', 0)
}

// checkPutText checks whether value is plain UTF-8 text. If value is not
// UTF-8, or if it has no leading or trailing whitespace, it returns (value,
// nil).
//
// Otherwise, the value is UTF-8 text with leading or trailing whitespace.
//
// If --verbatim is set, it returns (value, nil), including the spaces.
// If --trim-space is set, it returns (trimmed, nil), omitting the spaces.
// If neither is set, it reports an error.
func checkPutText(value []byte) ([]byte, error) {
if !utf8.Valid(value) {
return value, nil // binary value, always handle verbatim
}
trimmed := bytes.TrimSpace(value)
if len(trimmed) == len(value) {
return value, nil // no extra whitespace, leave it alone
} else if putArgs.Verbatim {
return value, nil // user wants value verbatim, leave it alone
} else if putArgs.TrimSpace {
return trimmed, nil // user wants value trimmed
}
// Reaching here, the value is text with extra space, but the user did not
// specify its disposition. Report an error.
return nil, errors.New("text value has surrounding whitespace, " +
"specify --verbatim to keep the space or --trim-space to remove it")
}
60 changes: 30 additions & 30 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ module github.com/tailscale/setec
go 1.22.0

require (
github.com/aws/aws-sdk-go-v2 v1.24.1
github.com/aws/aws-sdk-go-v2/config v1.26.5
github.com/aws/aws-sdk-go-v2/credentials v1.16.16
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.7
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7
github.com/creachadair/command v0.1.5
github.com/creachadair/flax v0.0.0-20231211041532-4d51c109e3c1
github.com/creachadair/mds v0.12.2
github.com/aws/aws-sdk-go-v2 v1.26.1
github.com/aws/aws-sdk-go-v2/config v1.27.11
github.com/aws/aws-sdk-go-v2/credentials v1.17.11
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6
github.com/creachadair/command v0.1.13
github.com/creachadair/flax v0.0.0-20240212192608-428acafa3bbe
github.com/creachadair/mds v0.14.6
github.com/google/go-cmp v0.6.0
github.com/tink-crypto/tink-go-awskms v0.0.0-20230616072154-ba4f9f22c3e9
github.com/tink-crypto/tink-go/v2 v2.1.0
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
golang.org/x/sync v0.6.0
golang.org/x/term v0.16.0
honnef.co/go/tools v0.4.6
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
golang.org/x/sync v0.7.0
golang.org/x/term v0.19.0
honnef.co/go/tools v0.4.7
tailscale.com v1.65.0-pre.0.20240415164925-952e06aa46b6
)

Expand All @@ -27,20 +27,20 @@ require (
github.com/akutz/memconn v0.1.0 // indirect
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
github.com/aws/aws-sdk-go v1.44.267 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect
github.com/aws/smithy-go v1.19.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect
github.com/aws/smithy-go v1.20.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
Expand Down Expand Up @@ -95,14 +95,14 @@ require (
github.com/x448/float16 v0.8.4 // indirect
go4.org/mem v0.0.0-20220726221520-4f986261bf13 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20240119083558-1b970713d09a // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.17.0 // indirect
golang.org/x/tools v0.20.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
google.golang.org/protobuf v1.32.0 // indirect
Expand Down
Loading