@@ -37,7 +37,7 @@ func Handled(err error) error {
3737 if err == nil {
3838 return nil
3939 }
40- return HandledWithMessage (err , err . Error ( ))
40+ return HandledWithSafeMessage (err , redact . Sprint ( err ))
4141}
4242
4343// HandledWithMessage is like Handled except the message is overridden.
@@ -47,7 +47,14 @@ func HandledWithMessage(err error, msg string) error {
4747 if err == nil {
4848 return nil
4949 }
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 }
5158}
5259
5360// HandledWithMessagef is like HandledWithMessagef except the message
@@ -56,34 +63,34 @@ func HandledWithMessagef(err error, format string, args ...interface{}) error {
5663 if err == nil {
5764 return nil
5865 }
59- return & barrierError {maskedErr : err , msg : fmt .Sprintf (format , args ... )}
66+ return & barrierErr {maskedErr : err , smsg : redact .Sprintf (format , args ... )}
6067}
6168
62- // barrierError is a leaf error type. It encapsulates a chain of
69+ // barrierErr is a leaf error type. It encapsulates a chain of
6370// original causes, but these causes are hidden so that they inhibit
6471// matching via Is() and the Cause()/Unwrap() recursions.
65- type barrierError struct {
72+ type barrierErr struct {
6673 // Message for the barrier itself.
6774 // In the common case, the message from the masked error
6875 // is used as-is (see Handled() above) however it is
6976 // useful to cache it here since the masked error may
7077 // have a long chain of wrappers and its Error() call
7178 // may be expensive.
72- msg string
79+ smsg redact. RedactableString
7380 // Masked error chain.
7481 maskedErr error
7582}
7683
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 )
8188
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 () }
8491
8592// SafeDetails reports the PII-free details from the masked error.
86- func (e * barrierError ) SafeDetails () []string {
93+ func (e * barrierErr ) SafeDetails () []string {
8794 var details []string
8895 for err := e .maskedErr ; err != nil ; err = errbase .UnwrapOnce (err ) {
8996 sd := errbase .GetSafeDetails (err )
@@ -94,10 +101,10 @@ func (e *barrierError) SafeDetails() []string {
94101}
95102
96103// 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 ) }
98105
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 )
101108 if p .Detail () {
102109 p .Printf ("-- cause hidden behind barrier\n %+v" , e .maskedErr )
103110 }
@@ -108,19 +115,37 @@ func (e *barrierError) SafeFormatError(p errbase.Printer) (next error) {
108115func encodeBarrier (
109116 ctx context.Context , err error ,
110117) (msg string , details []string , payload proto.Message ) {
111- e := err .(* barrierError )
118+ e := err .(* barrierErr )
112119 enc := errbase .EncodeError (ctx , e .maskedErr )
113- return e . msg , e .SafeDetails (), & enc
120+ return string ( e . smsg ) , e .SafeDetails (), & enc
114121}
115122
116123// A barrier error is decoded exactly.
117124func decodeBarrier (ctx context.Context , msg string , _ []string , payload proto.Message ) error {
118125 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 )}
120127}
121128
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+
122146func init () {
123- tn := errbase .GetTypeKey ((* barrierError )(nil ))
147+ errbase .RegisterLeafDecoder (errbase .GetTypeKey ((* barrierError )(nil )), decodeBarrierPrev )
148+ tn := errbase .GetTypeKey ((* barrierErr )(nil ))
124149 errbase .RegisterLeafDecoder (tn , decodeBarrier )
125150 errbase .RegisterLeafEncoder (tn , encodeBarrier )
126151}
0 commit comments