@@ -37,7 +37,7 @@ func Handled(err error) error {
37
37
if err == nil {
38
38
return nil
39
39
}
40
- return HandledWithMessage (err , err . Error ( ))
40
+ return HandledWithSafeMessage (err , redact . Sprint ( err ))
41
41
}
42
42
43
43
// HandledWithMessage is like Handled except the message is overridden.
@@ -47,7 +47,14 @@ func HandledWithMessage(err error, msg string) error {
47
47
if err == nil {
48
48
return nil
49
49
}
50
- return & barrierError {maskedErr : err , msg : msg }
50
+ return HandledWithSafeMessage (err , redact .Sprint (msg ))
51
+ }
52
+
53
+ // HandledWithSafeMessage is like Handled except the message is overridden.
54
+ // This can be used e.g. to hide message details or to prevent
55
+ // downstream code to make assertions on the message's contents.
56
+ func HandledWithSafeMessage (err error , msg redact.RedactableString ) error {
57
+ return & barrierErr {maskedErr : err , smsg : msg }
51
58
}
52
59
53
60
// HandledWithMessagef is like HandledWithMessagef except the message
@@ -56,34 +63,34 @@ func HandledWithMessagef(err error, format string, args ...interface{}) error {
56
63
if err == nil {
57
64
return nil
58
65
}
59
- return & barrierError {maskedErr : err , msg : fmt .Sprintf (format , args ... )}
66
+ return & barrierErr {maskedErr : err , smsg : redact .Sprintf (format , args ... )}
60
67
}
61
68
62
- // barrierError is a leaf error type. It encapsulates a chain of
69
+ // barrierErr is a leaf error type. It encapsulates a chain of
63
70
// original causes, but these causes are hidden so that they inhibit
64
71
// matching via Is() and the Cause()/Unwrap() recursions.
65
- type barrierError struct {
72
+ type barrierErr struct {
66
73
// Message for the barrier itself.
67
74
// In the common case, the message from the masked error
68
75
// is used as-is (see Handled() above) however it is
69
76
// useful to cache it here since the masked error may
70
77
// have a long chain of wrappers and its Error() call
71
78
// may be expensive.
72
- msg string
79
+ smsg redact. RedactableString
73
80
// Masked error chain.
74
81
maskedErr error
75
82
}
76
83
77
- var _ error = (* barrierError )(nil )
78
- var _ errbase.SafeDetailer = (* barrierError )(nil )
79
- var _ errbase.SafeFormatter = (* barrierError )(nil )
80
- var _ fmt.Formatter = (* barrierError )(nil )
84
+ var _ error = (* barrierErr )(nil )
85
+ var _ errbase.SafeDetailer = (* barrierErr )(nil )
86
+ var _ errbase.SafeFormatter = (* barrierErr )(nil )
87
+ var _ fmt.Formatter = (* barrierErr )(nil )
81
88
82
- // barrierError is an error.
83
- func (e * barrierError ) Error () string { return e .msg }
89
+ // barrierErr is an error.
90
+ func (e * barrierErr ) Error () string { return e .smsg . StripMarkers () }
84
91
85
92
// SafeDetails reports the PII-free details from the masked error.
86
- func (e * barrierError ) SafeDetails () []string {
93
+ func (e * barrierErr ) SafeDetails () []string {
87
94
var details []string
88
95
for err := e .maskedErr ; err != nil ; err = errbase .UnwrapOnce (err ) {
89
96
sd := errbase .GetSafeDetails (err )
@@ -94,10 +101,10 @@ func (e *barrierError) SafeDetails() []string {
94
101
}
95
102
96
103
// Printing a barrier reveals the details.
97
- func (e * barrierError ) Format (s fmt.State , verb rune ) { errbase .FormatError (e , s , verb ) }
104
+ func (e * barrierErr ) Format (s fmt.State , verb rune ) { errbase .FormatError (e , s , verb ) }
98
105
99
- func (e * barrierError ) SafeFormatError (p errbase.Printer ) (next error ) {
100
- p .Print (e .msg )
106
+ func (e * barrierErr ) SafeFormatError (p errbase.Printer ) (next error ) {
107
+ p .Print (e .smsg )
101
108
if p .Detail () {
102
109
p .Printf ("-- cause hidden behind barrier\n %+v" , e .maskedErr )
103
110
}
@@ -108,19 +115,37 @@ func (e *barrierError) SafeFormatError(p errbase.Printer) (next error) {
108
115
func encodeBarrier (
109
116
ctx context.Context , err error ,
110
117
) (msg string , details []string , payload proto.Message ) {
111
- e := err .(* barrierError )
118
+ e := err .(* barrierErr )
112
119
enc := errbase .EncodeError (ctx , e .maskedErr )
113
- return e . msg , e .SafeDetails (), & enc
120
+ return string ( e . smsg ) , e .SafeDetails (), & enc
114
121
}
115
122
116
123
// A barrier error is decoded exactly.
117
124
func decodeBarrier (ctx context.Context , msg string , _ []string , payload proto.Message ) error {
118
125
enc := payload .(* errbase.EncodedError )
119
- return & barrierError { msg : msg , maskedErr : errbase .DecodeError (ctx , * enc )}
126
+ return & barrierErr { smsg : redact . RedactableString ( msg ) , maskedErr : errbase .DecodeError (ctx , * enc )}
120
127
}
121
128
129
+ // Previous versions of barrier errors.
130
+ func decodeBarrierPrev (ctx context.Context , msg string , _ []string , payload proto.Message ) error {
131
+ enc := payload .(* errbase.EncodedError )
132
+ return & barrierErr {smsg : redact .Sprint (msg ), maskedErr : errbase .DecodeError (ctx , * enc )}
133
+ }
134
+
135
+ // barrierError is the "old" type name of barrierErr. We use a new
136
+ // name now to ensure a different decode function is used when
137
+ // importing barriers from the previous structure, where the
138
+ // message is not redactable.
139
+ type barrierError struct {
140
+ msg string
141
+ maskedErr error
142
+ }
143
+
144
+ func (b * barrierError ) Error () string { return "" }
145
+
122
146
func init () {
123
- tn := errbase .GetTypeKey ((* barrierError )(nil ))
147
+ errbase .RegisterLeafDecoder (errbase .GetTypeKey ((* barrierError )(nil )), decodeBarrierPrev )
148
+ tn := errbase .GetTypeKey ((* barrierErr )(nil ))
124
149
errbase .RegisterLeafDecoder (tn , decodeBarrier )
125
150
errbase .RegisterLeafEncoder (tn , encodeBarrier )
126
151
}
0 commit comments