161 lines
4.5 KiB
Go
161 lines
4.5 KiB
Go
// Copyright 2021 The Cockroach Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
// implied. See the License for the specific language governing
|
|
// permissions and limitations under the License.
|
|
|
|
package rfmt
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
i "github.com/cockroachdb/redact/interfaces"
|
|
b "github.com/cockroachdb/redact/internal/buffer"
|
|
"github.com/cockroachdb/redact/internal/escape"
|
|
m "github.com/cockroachdb/redact/internal/markers"
|
|
rwrap "github.com/cockroachdb/redact/internal/redact"
|
|
)
|
|
|
|
type overrideMode int
|
|
|
|
const (
|
|
noOverride overrideMode = iota
|
|
// Consider unsafe values as safe.
|
|
overrideSafe
|
|
// Consider safe and pre-redactable values as unsafe.
|
|
overrideUnsafe
|
|
)
|
|
|
|
func (p *pp) startUnsafe() restorer {
|
|
prevMode := p.buf.GetMode()
|
|
if p.override != overrideSafe {
|
|
p.buf.SetMode(b.UnsafeEscaped)
|
|
}
|
|
return restorer{p, prevMode, p.override}
|
|
}
|
|
|
|
func (p *pp) startPreRedactable() restorer {
|
|
prevMode := p.buf.GetMode()
|
|
if p.override != overrideUnsafe {
|
|
p.buf.SetMode(b.PreRedactable)
|
|
}
|
|
return restorer{p, prevMode, p.override}
|
|
}
|
|
|
|
func (p *pp) startSafeOverride() restorer {
|
|
prevMode := p.buf.GetMode()
|
|
prevOverride := p.override
|
|
if p.override == noOverride {
|
|
p.buf.SetMode(b.SafeEscaped)
|
|
p.override = overrideSafe
|
|
}
|
|
return restorer{p, prevMode, prevOverride}
|
|
}
|
|
|
|
func (p *pp) startUnsafeOverride() restorer {
|
|
prevMode := p.buf.GetMode()
|
|
prevOverride := p.override
|
|
if p.override == noOverride {
|
|
p.buf.SetMode(b.UnsafeEscaped)
|
|
p.override = overrideUnsafe
|
|
}
|
|
return restorer{p, prevMode, prevOverride}
|
|
}
|
|
|
|
type restorer struct {
|
|
p *pp
|
|
prevMode b.OutputMode
|
|
prevOverride overrideMode
|
|
}
|
|
|
|
func (r restorer) restore() {
|
|
r.p.buf.SetMode(r.prevMode)
|
|
r.p.override = r.prevOverride
|
|
}
|
|
|
|
func (p *pp) handleSpecialValues(
|
|
value reflect.Value, t reflect.Type, verb rune, depth int,
|
|
) (handled bool) {
|
|
switch t {
|
|
case safeWrapperType:
|
|
handled = true
|
|
defer p.startSafeOverride().restore()
|
|
p.printValue(value.Field(0), verb, depth+1)
|
|
|
|
case unsafeWrapperType:
|
|
handled = true
|
|
defer p.startUnsafeOverride().restore()
|
|
p.printValue(value.Field(0), verb, depth+1)
|
|
|
|
case redactableStringType:
|
|
handled = true
|
|
defer p.startPreRedactable().restore()
|
|
p.buf.WriteString(value.String())
|
|
|
|
case redactableBytesType:
|
|
handled = true
|
|
defer p.startPreRedactable().restore()
|
|
p.buf.Write(value.Bytes())
|
|
}
|
|
|
|
return handled
|
|
}
|
|
|
|
// Sprintfn produces a RedactableString using the provided
|
|
// SafeFormat-alike function.
|
|
func Sprintfn(printer func(w i.SafePrinter)) m.RedactableString {
|
|
p := newPrinter()
|
|
printer(p)
|
|
s := p.buf.TakeRedactableString()
|
|
p.free()
|
|
return s
|
|
}
|
|
|
|
// HelperForErrorf is a helper to implement a redaction-aware
|
|
// fmt.Errorf-compatible function in a different package. It formats
|
|
// the string according to the given format and arguments in the same
|
|
// way as Sprintf, but in addition to this if the format contains %w
|
|
// and an error object in the proper argument position it also returns
|
|
// that error object.
|
|
//
|
|
// Note: This function only works if an error redaction function
|
|
// has been injected with RegisterRedactErrorFn().
|
|
func HelperForErrorf(format string, args ...interface{}) (m.RedactableString, error) {
|
|
p := newPrinter()
|
|
p.wrapErrs = true
|
|
p.doPrintf(format, args)
|
|
e := p.wrappedErr
|
|
s := p.buf.TakeRedactableString()
|
|
p.free()
|
|
return s, e
|
|
}
|
|
|
|
// EscapeBytes escapes markers inside the given byte slice and encloses
|
|
// the entire byte slice between redaction markers.
|
|
// EscapeBytes escapes markers inside the given byte slice and encloses
|
|
// the entire byte slice between redaction markers.
|
|
func EscapeBytes(s []byte) m.RedactableBytes {
|
|
buf := make([]byte, 0, len(s)+len(m.StartS)+len(m.EndS))
|
|
buf = append(buf, m.StartS...)
|
|
start := len(buf)
|
|
buf = append(buf, s...)
|
|
buf = escape.InternalEscapeBytes(buf, start, true /* breakNewLine */, false /* strip */)
|
|
buf = append(buf, m.EndS...)
|
|
return m.RedactableBytes(buf)
|
|
}
|
|
|
|
var (
|
|
unsafeWrapperType = reflect.TypeOf(rwrap.UnsafeWrap{})
|
|
safeWrapperType = reflect.TypeOf(rwrap.SafeWrapper{})
|
|
redactableStringType = reflect.TypeOf(m.RedactableString(""))
|
|
redactableBytesType = reflect.TypeOf(m.RedactableBytes{})
|
|
)
|