-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsecretstring.go
More file actions
137 lines (120 loc) · 3.57 KB
/
secretstring.go
File metadata and controls
137 lines (120 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Package secretstring is a simple package that provides a type that can be used to store secrets.
// The secret is masked when printed or marshalled, but can be retrieved using the GetSecret() method.
package secretstring
import (
"strings"
)
const (
defaultMask string = "********"
defaultMarshallMasked bool = false
)
// secretString is the (private) underlying type of SecretString that holds the actual secret.
// It is used to prevent fmt.Sprint or alike from printing the secret,
// since they don't call the String() method, but instead read the underlying value from memory.
type secretString string
// SecretString is a string that is masked when printed.
// It implements the Stringer interface.
type SecretString struct {
secret secretString
mask string
marshallMasked bool
}
// Options are used to configure the SecretString.
type Options struct {
// MarshallMasked determines whether the secret is masked or not when marshalled as JSON.
MarshallMasked bool
// Mask is the string that is used to mask the secret.
Mask string
}
// New creates a new instance of SecretString with default options.
func New(secret string) *SecretString {
return &SecretString{
secret: secretString(secret),
mask: defaultMask,
marshallMasked: defaultMarshallMasked,
}
}
// NewWithOptions creates a new instance of SecretString with custom options.
func NewWithOptions(secret string, options Options) *SecretString {
return &SecretString{
secret: secretString(secret),
mask: options.Mask,
marshallMasked: options.MarshallMasked,
}
}
// String returns the masked secret.
func (s *secretString) String() string {
return "********"
}
// GetSecret returns the actual secret.
func (s *secretString) GetSecret() string {
return string(*s)
}
// String returns the masked secret.
//
// Example:
//
// s := New("my magic secret")
// s.String() // returns "********"
func (s *SecretString) String() string {
return s.mask
}
// GetSecret returns the actual secret.
//
// Example:
//
// s := New("my magic secret")
// s.GetSecret() // returns "my magic secret"
func (s *SecretString) GetSecret() string {
return s.secret.GetSecret()
}
// MarshalJSON returns the actual secret as JSON if Options.MarshallMasked is true
// or the masked secret if Options.MarshallMasked is false.
//
// Example of a masked secret:
//
// o := Options{
// MarshallMasked: true,
// Mask: "???",
// }
// s := NewWithOptions("hello world", o)
// s.MarshalJSON() // returns "???"
//
// Example of an unmasked secret:
//
// o := Options{
// MarshallMasked: false,
// Mask: "********",
// }
// s := NewWithOptions("hello world", o)
// s.MarshalJSON() // returns "hello world"
func (s *SecretString) MarshalJSON() ([]byte, error) {
var marshalled []byte
if s.marshallMasked {
marshalled = []byte("\"" + s.String() + "\"")
} else {
marshalled = []byte("\"" + s.GetSecret() + "\"")
}
return marshalled, nil
}
// UnmarshalJSON sets the secret from JSON. Any value is treated as a string.
//
// Example:
//
// body := []byte(`{"pin_number":"0000"}`)
// type testStruct struct {
// PinNumber *SecretString `json:"pin_number"`
// }
// var t testStruct
// json.Unmarshal(body, &t)
// t.PinNumber.String() // returns "********"
// t.PinNumber.GetSecret() // returns "0000"
//
func (s *SecretString) UnmarshalJSON(b []byte) error {
encodedValue := string(b)
encodedValue = strings.Trim(encodedValue, "\"")
s.secret = secretString(encodedValue)
s.mask = defaultMask
s.marshallMasked = defaultMarshallMasked
return nil
}