From d4bea90d7eb788fa8d65d53040046ddcc44dd379 Mon Sep 17 00:00:00 2001 From: Ravi Shekhar Jethani Date: Sat, 1 Jun 2024 22:46:26 +0200 Subject: [PATCH] Prepare v3 release (#35) Prepare for v3 release Rename `.RedactHint()` to `.RedactAs()` as more meaningful name that is more inline with its purpose. Rename `.Value()` to `.Secret()` as more meaningful name to return secret string. Polish doc comments. Restructure and cleanup README to be in sync with latest changes. --- README.md | 31 ++++++++++++++++------------ example_test.go | 27 +++++++++---------------- secret.go | 54 ++++++++++++++++++++++++------------------------- 3 files changed, 54 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 6f83117..26b8658 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,32 @@ [![Build Status](https://github.com/rsjethani/secret/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/rsjethani/secret/actions) [![Go Report Card](https://goreportcard.com/badge/github.com/rsjethani/secret)](https://goreportcard.com/report/github.com/rsjethani/secret) -# secret v2 - -### What secret is? -- It provides simple Go types like [secret.Text](https://pkg.go.dev/github.com/rsjethani/secret/v2#Text) to encapsulate your secret. Example: +# Installation +``` +go get github.com/rsjethani/secret/v3 ``` + +# What secret is? +It provides simple Go types like `Text` to securely store secrets. For example: +```go type Login struct { User string Password secret.Text } ``` -- The encapsulated secret remains inaccessible to operations like printing, logging, JSON serializtion etc. A (customizable) redact hint like `*****` is returned instead. -- The only way to access the actual secret value is by asking explicitly via the `.Value()` method. -- See [godev reference](https://pkg.go.dev/github.com/rsjethani/secret/v2#pkg-examples) for usage examples. +The encapsulated secret remains inaccessible to operations like printing, logging, JSON serialization etc. A (customizable) redact hint like `*****` is returned instead. The only way to access the actual secret value is by asking explicitly via the `.Secret()` method. See package documentation more reference and examples. -### What secret is not? +# What secret is not? - It is not a secret management service or your local password manager. - It is not a Go client to facilitate communication with secret managers like Hashicorp Vault, AWS secret Manager etc. Checkout [teller](https://github.com/spectralops/teller) if that is what you are looking for. -### Installation -``` -go get github.com/rsjethani/secret/v2 -``` -NOTE: v1 is deprecated now. +# Versions + +### v3 +Current version, same functionality as v2 but much cleaner API. + +### v2 +Perfectly usable but no longer maintained. +### v1 +Deprecated. \ No newline at end of file diff --git a/example_test.go b/example_test.go index b37a6e6..a854299 100644 --- a/example_test.go +++ b/example_test.go @@ -7,29 +7,22 @@ import ( "github.com/rsjethani/secret/v2" ) -func ExampleText() { - s := secret.Text{} - fmt.Println(s, s.Value()) - - // Output: ***** -} - func ExampleNew() { s := secret.New("$ecre!") - fmt.Println(s, s.Value()) + fmt.Println(s, s.Secret()) // Output: ***** $ecre! } -func ExampleRedactHint() { - s := secret.New("$ecre!", secret.RedactHint(secret.FiveX)) - fmt.Println(s, s.Value()) +func ExampleRedactAs() { + s := secret.New("$ecre!", secret.RedactAs(secret.FiveX)) + fmt.Println(s, s.Secret()) - s = secret.New("$ecre!", secret.RedactHint(secret.Redacted)) - fmt.Println(s, s.Value()) + s = secret.New("$ecre!", secret.RedactAs(secret.Redacted)) + fmt.Println(s, s.Secret()) - s = secret.New("$ecre!", secret.RedactHint("my redact hint")) - fmt.Println(s, s.Value()) + s = secret.New("$ecre!", secret.RedactAs("my redact hint")) + fmt.Println(s, s.Secret()) // Output: // XXXXX $ecre! @@ -68,7 +61,7 @@ func ExampleText_UnmarshalText() { } fmt.Printf("%+v\n", login) - fmt.Println(login.Password.Value()) + fmt.Println(login.Password.Secret()) // Output: // {User:John Password:*****} @@ -77,7 +70,7 @@ func ExampleText_UnmarshalText() { func ExampleEqual() { tx1 := secret.New("hello") - tx2 := secret.New("hello", secret.RedactHint(secret.Redacted)) + tx2 := secret.New("hello", secret.RedactAs(secret.Redacted)) tx3 := secret.New("world") fmt.Println(secret.Equal(tx1, tx2)) fmt.Println(secret.Equal(tx1, tx3)) diff --git a/secret.go b/secret.go index b9b5383..749e308 100644 --- a/secret.go +++ b/secret.go @@ -1,18 +1,16 @@ -// Package secret provides types to guard your secret values from leaking into logs, std* etc. -// -// The objective is to disallow writing/serializing of secret values to std*, logs, JSON string -// etc. but provide access to the secret when requested explicitly. package secret -// Text provides a way to safely store your secret value and a corresponding redact hint. This -// redact hint is what is used in operations like printing and serializing. +// Text provides a way to safely store your secret string until you actually need it. Operations +// like printing and serializing see a proxy/redact string there by avoiding leaking the secret. +// Once created, the instance is readonly except for the [Text.UnmarshalText] operation, but that +// too only modifies the local copy. Hence the type is concurrent safe. type Text struct { secret *string redact *string } -// New returns [Text] for the secret with [FiveStar] as the default redact hint. Provide options -// like [RedactHint] to modify default behavior. +// New returns [Text] for the secret with [FiveStar] as the default redact string. Provide options +// like [RedactAs] to modify default behavior. func New(secret string, options ...func(*Text)) Text { tx := Text{ secret: new(string), @@ -29,36 +27,36 @@ func New(secret string, options ...func(*Text)) Text { return tx } -// Some common redact hints. +// RedactAs is a functional option to set r as the redact string for [Text]. You can use one of +// the common redact strings provided with this package like [FiveX] or provide your own. +func RedactAs(r string) func(*Text) { + return func(t *Text) { + *t.redact = r + } +} + +// Some common redact strings. const ( FiveX string = "XXXXX" FiveStar string = "*****" Redacted string = "[REDACTED]" ) -// RedactHint is a functional option to set r as the redact hint for the [Text]. You can use one of -// the common redact hints provided with this package like [FiveX] or provide your own string. -func RedactHint(r string) func(*Text) { - return func(t *Text) { - *t.redact = r - } -} - -// String implements the [fmt.Stringer] interface and returns only the redact hint. This prevents the -// secret value from being printed to std*, logs etc. +// String implements the [fmt.Stringer] interface and returns only the redact string. This prevents +// the actual secret string from being sent to std*, logs etc. func (tx Text) String() string { - if tx.redact == nil { - return FiveStar + if tx.redact != nil { + return *tx.redact } - return *tx.redact + return FiveStar } -// Value gives you access to the actual secret value stored inside Text. -func (tx Text) Value() string { - if tx.secret == nil { - return "" +// Secret returns the actual secret string stored inside [Text]. +func (tx Text) Secret() string { + if tx.secret != nil { + return *tx.secret } - return *tx.secret + return "" } // MarshalText implements [encoding.TextMarshaler]. It marshals redact string into bytes rather than @@ -74,7 +72,7 @@ func (tx *Text) UnmarshalText(b []byte) error { // If the original redact is not nil then use it otherwise fallback to default. if tx.redact != nil { - *tx = New(s, RedactHint(*tx.redact)) + *tx = New(s, RedactAs(*tx.redact)) } else { *tx = New(s) }