0
Files
2023-10-21 12:18:19 +03:00

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{})
)