Skip to content

Commit

Permalink
Prepare v3 release (#35)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rsjethani authored Jun 1, 2024
1 parent 4526b39 commit d4bea90
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 58 deletions.
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
27 changes: 10 additions & 17 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down Expand Up @@ -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:*****}
Expand All @@ -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))
Expand Down
54 changes: 26 additions & 28 deletions secret.go
Original file line number Diff line number Diff line change
@@ -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),
Expand All @@ -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
Expand All @@ -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)
}
Expand Down

0 comments on commit d4bea90

Please sign in to comment.