0

Initial commit

This commit is contained in:
eleksir
2022-09-04 02:34:54 +03:00
commit d9de157ad8
1017 changed files with 407553 additions and 0 deletions

15
vendor/github.com/cockroachdb/redact/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,15 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/

7
vendor/github.com/cockroachdb/redact/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,7 @@
language: go
go:
- 1.12.x
- 1.13.x
- 1.14.x
- 1.15.x

201
vendor/github.com/cockroachdb/redact/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

5
vendor/github.com/cockroachdb/redact/README.md generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# redact
Utilities to redact Go strings for confidentiality
Godoc link: https://pkg.go.dev/github.com/cockroachdb/redact?tab=doc

126
vendor/github.com/cockroachdb/redact/api.go generated vendored Normal file
View File

@@ -0,0 +1,126 @@
// Copyright 2020 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 redact
import "fmt"
// SafeFormatter is implemented by object types that want to separate
// safe and non-safe information when printed out by a Printf-like
// formatter.
type SafeFormatter interface {
// SafeFormat is like the Format method of fmt.Formatter, except
// that it operates using a SafePrinter instead of a fmt.State for
// output.
//
// The verb argument is the control character that defines
// the formatting mode in the surrounding Printf call.
// For example, if this method is called to format %03d,
// the verb is 'd'.
SafeFormat(s SafePrinter, verb rune)
}
// SafeValue is a marker interface to be implemented by types that
// alias base Go types and whose natural representation via Printf is
// always safe for reporting.
//
// This is recognized by the SafePrinter interface as an alternative
// to SafeFormatter.
//
// It is provided to decorate "leaf" Go types, such as aliases to int.
//
// Typically, a linter enforces that a type can only implement this
// interface if it aliases a base go type. More complex types should
// implement SafeFormatter instead.
//
// It is advised to build an automatic process during builds to
// collect all the types that implement this interface, as well as all
// uses of this type, and produce a report. Changes to this report
// should receive maximal amount of scrutiny during code reviews.
type SafeValue interface {
SafeValue()
}
// SafeMessager is an alternative to SafeFormatter used in previous
// versions of CockroachDB.
// NB: this interface is obsolete. Use SafeFormatter instead.
// TODO(knz): Remove this.
type SafeMessager interface {
SafeMessage() string
}
// SafePrinter is a stateful helper that abstracts an output stream in
// the context of printf-like formatting, but with the ability to
// separate safe and unsafe bits of data.
//
// This package provides one implementation of this using marker
// delimiters for unsafe data, see markers.go. We would like to aim
// for alternate implementations to generate more structured formats.
type SafePrinter interface {
// SafePrinter inherits fmt.State to access format flags, however
// calls to fmt.State's underlying Write() as unsafe.
fmt.State
// SafePrinter provides the SafeWriter interface.
SafeWriter
}
// SafeWriter provides helper functions for use in implementations of
// SafeFormatter, to format mixes of safe and unsafe strings.
type SafeWriter interface {
// SafeString emits a safe string.
SafeString(SafeString)
// SafeRune emits a safe rune.
SafeRune(SafeRune)
// Print emits its arguments separated by spaces.
// For each argument it dynamically checks for the SafeFormatter or
// SafeValue interface and either use that, or mark the argument
// payload as unsafe.
Print(args ...interface{})
// For printf, a linter checks that the format string is
// a constant literal, so the implementation can assume it's always
// safe.
Printf(format string, arg ...interface{})
// UnsafeString writes an unsafe string.
UnsafeString(string)
// UnsafeByte writes an unsafe byte.
UnsafeByte(byte)
// UnsafeBytes writes an unsafe byte slice.
UnsafeBytes([]byte)
// UnsafeRune writes an unsafe rune.
UnsafeRune(rune)
}
// SafeString aliases string. This is not meant to be used directly;
// the type definition ensures that SafePrinter's SafeString method
// can only take constant string literals as arguments. Typically, a
// Go linter would ensure that ConstantString is never used to cast a
// value.
type SafeString string
// SafeValue makes SafeString a SafeValue.
func (SafeString) SafeValue() {}
// SafeRune aliases rune. See the explanation for SafeString.
type SafeRune rune
// SafeValue makes SafeRune a SafeValue.
func (SafeRune) SafeValue() {}

149
vendor/github.com/cockroachdb/redact/builder.go generated vendored Normal file
View File

@@ -0,0 +1,149 @@
// Copyright 2020 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 redact
import (
"bytes"
"fmt"
"io"
"unicode/utf8"
)
// StringBuilder accumulates strings with optional redaction markers.
//
// It implements io.Writer but marks direct writes as redactable.
// To distinguish safe and unsafe bits, it also implements the SafeWriter
// interface.
type StringBuilder struct {
// we use bytes.Buffer internally to simplify the implementation of
// the SafeWriter interface.
buf bytes.Buffer
}
// String returns the accumulated string, with redaction markers stripped out.
// To obtain the redactable string, call RedactableString().
func (b StringBuilder) String() string { return b.RedactableString().StripMarkers() }
var _ fmt.Stringer = StringBuilder{}
var _ fmt.Stringer = (*StringBuilder)(nil)
// RedactableString returns the accumulated string, including redaction markers.
func (b StringBuilder) RedactableString() RedactableString { return RedactableString(b.buf.String()) }
// RedactableBytes returns the accumulated bytes, including redaction markers.
func (b StringBuilder) RedactableBytes() RedactableBytes { return RedactableBytes(b.buf.Bytes()) }
// SafeFormat implements SafeFormatter.
func (b StringBuilder) SafeFormat(p SafePrinter, _ rune) {
// We only support the %v / %s natural print here.
// Go supports other formatting verbs for strings: %x/%X/%q.
//
// We don't do this here, keeping in mind that the output
// of a SafeFormat must remain a redactable string.
//
// %x/%X cannot be implemented because they would turn redaction
// markers into hex codes, and the entire result string would
// appear safe for reporting, which would break the semantics
// of this package.
//
// %q cannot be implemented because it replaces non-ASCII characters
// with numeric unicode escapes, which breaks redaction
// markers too.
p.Print(b.RedactableString())
}
var _ SafeFormatter = StringBuilder{}
var _ SafeFormatter = (*StringBuilder)(nil)
// Len returns the number of accumulated bytes, including redaction
// markers; b.Len() == len(b.RedactableString()).
func (b *StringBuilder) Len() int { return b.buf.Len() }
// Cap returns the capacity of the builder's underlying byte slice. It is the
// total space allocated for the string being built and includes any bytes
// already written.
func (b *StringBuilder) Cap() int { return b.buf.Cap() }
// Reset resets the Builder to be empty.
func (b *StringBuilder) Reset() { b.buf.Reset() }
// StringBuilder implements io.Writer.
// Direct Write() calls are considered unsafe.
var _ io.Writer = (*StringBuilder)(nil)
// Write implements the io.Writer interface.
func (b *StringBuilder) Write(s []byte) (int, error) {
b.UnsafeBytes(s)
return len(s), nil
}
// StringBuilder implements SafeWriter.
var _ SafeWriter = (*StringBuilder)(nil)
// Print is part of the SafeWriter interface.
func (b *StringBuilder) Print(args ...interface{}) {
_, _ = Fprint(&b.buf, args...)
}
// Printf is part of the SafeWriter interface.
func (b *StringBuilder) Printf(format string, args ...interface{}) {
_, _ = Fprintf(&b.buf, format, args...)
}
// SafeString is part of the SafeWriter interface.
func (b *StringBuilder) SafeString(s SafeString) {
w := escapeWriter{w: &b.buf, enclose: false}
_, _ = w.Write([]byte(s))
}
// SafeRune is part of the SafeWriter interface.
func (b *StringBuilder) SafeRune(s SafeRune) {
if s == startRedactable || s == endRedactable {
s = escapeMark
}
_, _ = b.buf.WriteRune(rune(s))
}
// UnsafeString is part of the SafeWriter interface.
func (b *StringBuilder) UnsafeString(s string) {
w := escapeWriter{w: &b.buf, enclose: true, strip: true}
_, _ = w.Write([]byte(s))
}
// UnsafeRune is part of the SafeWriter interface.
func (b *StringBuilder) UnsafeRune(s rune) {
_, _ = b.buf.WriteRune(startRedactable)
b.SafeRune(SafeRune(s))
_, _ = b.buf.WriteRune(endRedactable)
}
// UnsafeByte is part of the SafeWriter interface.
func (b *StringBuilder) UnsafeByte(s byte) {
_, _ = b.buf.WriteRune(startRedactable)
if s >= utf8.RuneSelf ||
s == startRedactableBytes[0] || s == endRedactableBytes[0] {
// Unsafe byte. Escape it.
_, _ = b.buf.Write(escapeBytes)
} else {
_ = b.buf.WriteByte(s)
}
_, _ = b.buf.WriteRune(endRedactable)
}
// UnsafeBytes is part of the SafeWriter interface.
func (b *StringBuilder) UnsafeBytes(s []byte) {
w := escapeWriter{w: &b.buf, enclose: true, strip: true}
_, _ = w.Write(s)
}

51
vendor/github.com/cockroachdb/redact/doc.go generated vendored Normal file
View File

@@ -0,0 +1,51 @@
// Copyright 2020 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 redact provides facilities for separating “safe” and
// “unsafe” pieces of data when logging and constructing error object.
//
// An item is said to be “safe” if it is proven to not contain
// PII or otherwise confidential information that should not escape
// the boundaries of the current system, for example via telemetry
// or crash reporting. Conversely, data is considered “unsafe”
// until/unless it is known to be “safe”.
//
// Example use:
//
// redactable := redact.Sprintf("hello %s", "universe")
//
// // At this point, 'redactable' contains "hello ‹universe›".
//
// // This prints "hello universe":
// fmt.Println(redactable.StripMarkers())
//
// // This reports "hello ‹×›":
// fmt.Println(redactable.Redact())
//
//
// When defining your own custom types, you can define
// a SafeFormat method, implementing the redact.SafeFormatter
// interface in a way you'd otherwise implement fmt.Formatter.
// This is then recognized by this package's API automatically.
//
// Alternatively:
//
// - you can implement the SafeValue interface, which tells the
// redact package to always the default formatting of a type
// as safe and thus not included inside redaction markers.
//
// - you can include a value within redact.Safe() and redact.Unsafe()
// in redact.Sprintf / redact.Fprintf calls, to force
// the omission or inclusion of redaction markers.
package redact

View File

@@ -0,0 +1,52 @@
Overall code structure
======================
This directory imports the "printf" logic as-is from the Go standard
library and instruments it for redaction of sensitive data.
Overall, the original Go code is structured as follows:
- the top-level API functions (`Printf` `Fprintf` etc) instantiate a
"printer" struct called `pp`, then call the `doPrint*()` methods
on it.
- the `pp` contains a byte slice (`pp.buf`, type `buffer`) that
accumulates the result of formatting *regardless of the final output
of the API* - i.e. a buffer is used even when using `Fprint` to an
`io.Writer`. Only after the `doPrint()` method finishes, is the
`buffer` copied to the final `io.Writer` in the `Fprint*` variants.
- each of the `doPrint` methods does some analysis on the argument
list - quite simple for e.g. `doPrintln`, more intricate for
`doPrintf`. As part of the analysis it emits "spacing" or no-op
bytes directly on the `pp.buf`. For example `doPrint` emits spaces
between arguments directly, `doPrintf` emits the non-formatting
characters from the format string, as well as certain *constant*
error strings (e.g. `%(BADPREC)`).
At this point **we make the following assumption**: there is no data
from the printed *arguments* that is emitted to `pp.buf` directly by a
`doPrint()` method. This is true of the implementation as of Go 1.14.
From this point, this package contains a *custom patch* onto the
default implementation: the calls to `p.printArg` performed by the
`doPrint()` methods are redirected to a function callback that is
injected by the `redact` package.
Refreshing the sources
======================
The files in this directory have been imported from
`$GOROOT/src/fmt/{format,print}.go`
and
`$GOROOT/src/internal/fmtsort`
And patched using the included `.diff` files.
To upgrade to a newer Go implementation, import the files anew and
re-apply the patches.
See the script `refresh.sh` for details.

View File

@@ -0,0 +1,222 @@
// Code generated from the Go standard library. DO NOT EDIT
// GENERATED FILE DO NOT EDIT
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package fmtsort provides a general stable ordering mechanism
// for maps, on behalf of the fmt and text/template packages.
// It is not guaranteed to be efficient and works only for types
// that are valid map keys.
package fmtsort
import (
"reflect"
"sort"
)
// Note: Throughout this package we avoid calling reflect.Value.Interface as
// it is not always legal to do so and it's easier to avoid the issue than to face it.
// SortedMap represents a map's keys and values. The keys and values are
// aligned in index order: Value[i] is the value in the map corresponding to Key[i].
type SortedMap struct {
Key []reflect.Value
Value []reflect.Value
}
func (o *SortedMap) Len() int { return len(o.Key) }
func (o *SortedMap) Less(i, j int) bool { return compare(o.Key[i], o.Key[j]) < 0 }
func (o *SortedMap) Swap(i, j int) {
o.Key[i], o.Key[j] = o.Key[j], o.Key[i]
o.Value[i], o.Value[j] = o.Value[j], o.Value[i]
}
// Sort accepts a map and returns a SortedMap that has the same keys and
// values but in a stable sorted order according to the keys, modulo issues
// raised by unorderable key values such as NaNs.
//
// The ordering rules are more general than with Go's < operator:
//
// - when applicable, nil compares low
// - ints, floats, and strings order by <
// - NaN compares less than non-NaN floats
// - bool compares false before true
// - complex compares real, then imag
// - pointers compare by machine address
// - channel values compare by machine address
// - structs compare each field in turn
// - arrays compare each element in turn.
// Otherwise identical arrays compare by length.
// - interface values compare first by reflect.Type describing the concrete type
// and then by concrete value as described in the previous rules.
//
func Sort(mapValue reflect.Value) *SortedMap {
if mapValue.Type().Kind() != reflect.Map {
return nil
}
// Note: this code is arranged to not panic even in the presence
// of a concurrent map update. The runtime is responsible for
// yelling loudly if that happens. See issue 33275.
n := mapValue.Len()
key := make([]reflect.Value, 0, n)
value := make([]reflect.Value, 0, n)
iter := mapValue.MapRange()
for iter.Next() {
key = append(key, iter.Key())
value = append(value, iter.Value())
}
sorted := &SortedMap{
Key: key,
Value: value,
}
sort.Stable(sorted)
return sorted
}
// compare compares two values of the same type. It returns -1, 0, 1
// according to whether a > b (1), a == b (0), or a < b (-1).
// If the types differ, it returns -1.
// See the comment on Sort for the comparison rules.
func compare(aVal, bVal reflect.Value) int {
aType, bType := aVal.Type(), bVal.Type()
if aType != bType {
return -1 // No good answer possible, but don't return 0: they're not equal.
}
switch aVal.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
a, b := aVal.Int(), bVal.Int()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
a, b := aVal.Uint(), bVal.Uint()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.String:
a, b := aVal.String(), bVal.String()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.Float32, reflect.Float64:
return floatCompare(aVal.Float(), bVal.Float())
case reflect.Complex64, reflect.Complex128:
a, b := aVal.Complex(), bVal.Complex()
if c := floatCompare(real(a), real(b)); c != 0 {
return c
}
return floatCompare(imag(a), imag(b))
case reflect.Bool:
a, b := aVal.Bool(), bVal.Bool()
switch {
case a == b:
return 0
case a:
return 1
default:
return -1
}
case reflect.Ptr:
a, b := aVal.Pointer(), bVal.Pointer()
switch {
case a < b:
return -1
case a > b:
return 1
default:
return 0
}
case reflect.Chan:
if c, ok := nilCompare(aVal, bVal); ok {
return c
}
ap, bp := aVal.Pointer(), bVal.Pointer()
switch {
case ap < bp:
return -1
case ap > bp:
return 1
default:
return 0
}
case reflect.Struct:
for i := 0; i < aVal.NumField(); i++ {
if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 {
return c
}
}
return 0
case reflect.Array:
for i := 0; i < aVal.Len(); i++ {
if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 {
return c
}
}
return 0
case reflect.Interface:
if c, ok := nilCompare(aVal, bVal); ok {
return c
}
c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type()))
if c != 0 {
return c
}
return compare(aVal.Elem(), bVal.Elem())
default:
// Certain types cannot appear as keys (maps, funcs, slices), but be explicit.
panic("bad type in compare: " + aType.String())
}
}
// nilCompare checks whether either value is nil. If not, the boolean is false.
// If either value is nil, the boolean is true and the integer is the comparison
// value. The comparison is defined to be 0 if both are nil, otherwise the one
// nil value compares low. Both arguments must represent a chan, func,
// interface, map, pointer, or slice.
func nilCompare(aVal, bVal reflect.Value) (int, bool) {
if aVal.IsNil() {
if bVal.IsNil() {
return 0, true
}
return -1, true
}
if bVal.IsNil() {
return 1, true
}
return 0, false
}
// floatCompare compares two floating-point values. NaNs compare low.
func floatCompare(a, b float64) int {
switch {
case isNaN(a):
return -1 // No good answer if b is a NaN so don't bother checking.
case isNaN(b):
return 1
case a < b:
return -1
case a > b:
return 1
}
return 0
}
func isNaN(a float64) bool {
return a != a
}

595
vendor/github.com/cockroachdb/redact/internal/format.go generated vendored Normal file
View File

@@ -0,0 +1,595 @@
// Code generated from the Go standard library. DO NOT EDIT
// GENERATED FILE DO NOT EDIT
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fmt
import (
"strconv"
"unicode/utf8"
)
const (
ldigits = "0123456789abcdefx"
udigits = "0123456789ABCDEFX"
)
const (
signed = true
unsigned = false
)
// flags placed in a separate struct for easy clearing.
type fmtFlags struct {
widPresent bool
precPresent bool
minus bool
plus bool
sharp bool
space bool
zero bool
// For the formats %+v %#v, we set the plusV/sharpV flags
// and clear the plus/sharp flags since %+v and %#v are in effect
// different, flagless formats set at the top level.
plusV bool
sharpV bool
}
// A fmt is the raw formatter used by Printf etc.
// It prints into a buffer that must be set up separately.
type fmt struct {
buf *buffer
fmtFlags
wid int // width
prec int // precision
// intbuf is large enough to store %b of an int64 with a sign and
// avoids padding at the end of the struct on 32 bit architectures.
intbuf [68]byte
}
func (f *fmt) clearflags() {
f.fmtFlags = fmtFlags{}
}
func (f *fmt) init(buf *buffer) {
f.buf = buf
f.clearflags()
}
// writePadding generates n bytes of padding.
func (f *fmt) writePadding(n int) {
if n <= 0 { // No padding bytes needed.
return
}
buf := *f.buf
oldLen := len(buf)
newLen := oldLen + n
// Make enough room for padding.
if newLen > cap(buf) {
buf = make(buffer, cap(buf)*2+n)
copy(buf, *f.buf)
}
// Decide which byte the padding should be filled with.
padByte := byte(' ')
if f.zero {
padByte = byte('0')
}
// Fill padding with padByte.
padding := buf[oldLen:newLen]
for i := range padding {
padding[i] = padByte
}
*f.buf = buf[:newLen]
}
// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) pad(b []byte) {
if !f.widPresent || f.wid == 0 {
f.buf.write(b)
return
}
width := f.wid - utf8.RuneCount(b)
if !f.minus {
// left padding
f.writePadding(width)
f.buf.write(b)
} else {
// right padding
f.buf.write(b)
f.writePadding(width)
}
}
// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
func (f *fmt) padString(s string) {
if !f.widPresent || f.wid == 0 {
f.buf.writeString(s)
return
}
width := f.wid - utf8.RuneCountInString(s)
if !f.minus {
// left padding
f.writePadding(width)
f.buf.writeString(s)
} else {
// right padding
f.buf.writeString(s)
f.writePadding(width)
}
}
// fmtBoolean formats a boolean.
func (f *fmt) fmtBoolean(v bool) {
if v {
f.padString("true")
} else {
f.padString("false")
}
}
// fmtUnicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'".
func (f *fmt) fmtUnicode(u uint64) {
buf := f.intbuf[0:]
// With default precision set the maximum needed buf length is 18
// for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits
// into the already allocated intbuf with a capacity of 68 bytes.
prec := 4
if f.precPresent && f.prec > 4 {
prec = f.prec
// Compute space needed for "U+" , number, " '", character, "'".
width := 2 + prec + 2 + utf8.UTFMax + 1
if width > len(buf) {
buf = make([]byte, width)
}
}
// Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left.
i := len(buf)
// For %#U we want to add a space and a quoted character at the end of the buffer.
if f.sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) {
i--
buf[i] = '\''
i -= utf8.RuneLen(rune(u))
utf8.EncodeRune(buf[i:], rune(u))
i--
buf[i] = '\''
i--
buf[i] = ' '
}
// Format the Unicode code point u as a hexadecimal number.
for u >= 16 {
i--
buf[i] = udigits[u&0xF]
prec--
u >>= 4
}
i--
buf[i] = udigits[u]
prec--
// Add zeros in front of the number until requested precision is reached.
for prec > 0 {
i--
buf[i] = '0'
prec--
}
// Add a leading "U+".
i--
buf[i] = '+'
i--
buf[i] = 'U'
oldZero := f.zero
f.zero = false
f.pad(buf[i:])
f.zero = oldZero
}
// fmtInteger formats signed and unsigned integers.
func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, verb rune, digits string) {
negative := isSigned && int64(u) < 0
if negative {
u = -u
}
buf := f.intbuf[0:]
// The already allocated f.intbuf with a capacity of 68 bytes
// is large enough for integer formatting when no precision or width is set.
if f.widPresent || f.precPresent {
// Account 3 extra bytes for possible addition of a sign and "0x".
width := 3 + f.wid + f.prec // wid and prec are always positive.
if width > len(buf) {
// We're going to need a bigger boat.
buf = make([]byte, width)
}
}
// Two ways to ask for extra leading zero digits: %.3d or %03d.
// If both are specified the f.zero flag is ignored and
// padding with spaces is used instead.
prec := 0
if f.precPresent {
prec = f.prec
// Precision of 0 and value of 0 means "print nothing" but padding.
if prec == 0 && u == 0 {
oldZero := f.zero
f.zero = false
f.writePadding(f.wid)
f.zero = oldZero
return
}
} else if f.zero && f.widPresent {
prec = f.wid
if negative || f.plus || f.space {
prec-- // leave room for sign
}
}
// Because printing is easier right-to-left: format u into buf, ending at buf[i].
// We could make things marginally faster by splitting the 32-bit case out
// into a separate block but it's not worth the duplication, so u has 64 bits.
i := len(buf)
// Use constants for the division and modulo for more efficient code.
// Switch cases ordered by popularity.
switch base {
case 10:
for u >= 10 {
i--
next := u / 10
buf[i] = byte('0' + u - next*10)
u = next
}
case 16:
for u >= 16 {
i--
buf[i] = digits[u&0xF]
u >>= 4
}
case 8:
for u >= 8 {
i--
buf[i] = byte('0' + u&7)
u >>= 3
}
case 2:
for u >= 2 {
i--
buf[i] = byte('0' + u&1)
u >>= 1
}
default:
panic("fmt: unknown base; can't happen")
}
i--
buf[i] = digits[u]
for i > 0 && prec > len(buf)-i {
i--
buf[i] = '0'
}
// Various prefixes: 0x, -, etc.
if f.sharp {
switch base {
case 2:
// Add a leading 0b.
i--
buf[i] = 'b'
i--
buf[i] = '0'
case 8:
if buf[i] != '0' {
i--
buf[i] = '0'
}
case 16:
// Add a leading 0x or 0X.
i--
buf[i] = digits[16]
i--
buf[i] = '0'
}
}
if verb == 'O' {
i--
buf[i] = 'o'
i--
buf[i] = '0'
}
if negative {
i--
buf[i] = '-'
} else if f.plus {
i--
buf[i] = '+'
} else if f.space {
i--
buf[i] = ' '
}
// Left padding with zeros has already been handled like precision earlier
// or the f.zero flag is ignored due to an explicitly set precision.
oldZero := f.zero
f.zero = false
f.pad(buf[i:])
f.zero = oldZero
}
// truncate truncates the string s to the specified precision, if present.
func (f *fmt) truncateString(s string) string {
if f.precPresent {
n := f.prec
for i := range s {
n--
if n < 0 {
return s[:i]
}
}
}
return s
}
// truncate truncates the byte slice b as a string of the specified precision, if present.
func (f *fmt) truncate(b []byte) []byte {
if f.precPresent {
n := f.prec
for i := 0; i < len(b); {
n--
if n < 0 {
return b[:i]
}
wid := 1
if b[i] >= utf8.RuneSelf {
_, wid = utf8.DecodeRune(b[i:])
}
i += wid
}
}
return b
}
// fmtS formats a string.
func (f *fmt) fmtS(s string) {
s = f.truncateString(s)
f.padString(s)
}
// fmtBs formats the byte slice b as if it was formatted as string with fmtS.
func (f *fmt) fmtBs(b []byte) {
b = f.truncate(b)
f.pad(b)
}
// fmtSbx formats a string or byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmtSbx(s string, b []byte, digits string) {
length := len(b)
if b == nil {
// No byte slice present. Assume string s should be encoded.
length = len(s)
}
// Set length to not process more bytes than the precision demands.
if f.precPresent && f.prec < length {
length = f.prec
}
// Compute width of the encoding taking into account the f.sharp and f.space flag.
width := 2 * length
if width > 0 {
if f.space {
// Each element encoded by two hexadecimals will get a leading 0x or 0X.
if f.sharp {
width *= 2
}
// Elements will be separated by a space.
width += length - 1
} else if f.sharp {
// Only a leading 0x or 0X will be added for the whole string.
width += 2
}
} else { // The byte slice or string that should be encoded is empty.
if f.widPresent {
f.writePadding(f.wid)
}
return
}
// Handle padding to the left.
if f.widPresent && f.wid > width && !f.minus {
f.writePadding(f.wid - width)
}
// Write the encoding directly into the output buffer.
buf := *f.buf
if f.sharp {
// Add leading 0x or 0X.
buf = append(buf, '0', digits[16])
}
var c byte
for i := 0; i < length; i++ {
if f.space && i > 0 {
// Separate elements with a space.
buf = append(buf, ' ')
if f.sharp {
// Add leading 0x or 0X for each element.
buf = append(buf, '0', digits[16])
}
}
if b != nil {
c = b[i] // Take a byte from the input byte slice.
} else {
c = s[i] // Take a byte from the input string.
}
// Encode each byte as two hexadecimal digits.
buf = append(buf, digits[c>>4], digits[c&0xF])
}
*f.buf = buf
// Handle padding to the right.
if f.widPresent && f.wid > width && f.minus {
f.writePadding(f.wid - width)
}
}
// fmtSx formats a string as a hexadecimal encoding of its bytes.
func (f *fmt) fmtSx(s, digits string) {
f.fmtSbx(s, nil, digits)
}
// fmtBx formats a byte slice as a hexadecimal encoding of its bytes.
func (f *fmt) fmtBx(b []byte, digits string) {
f.fmtSbx("", b, digits)
}
// fmtQ formats a string as a double-quoted, escaped Go string constant.
// If f.sharp is set a raw (backquoted) string may be returned instead
// if the string does not contain any control characters other than tab.
func (f *fmt) fmtQ(s string) {
s = f.truncateString(s)
if f.sharp && strconv.CanBackquote(s) {
f.padString("`" + s + "`")
return
}
buf := f.intbuf[:0]
if f.plus {
f.pad(strconv.AppendQuoteToASCII(buf, s))
} else {
f.pad(strconv.AppendQuote(buf, s))
}
}
// fmtC formats an integer as a Unicode character.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmtC(c uint64) {
r := rune(c)
if c > utf8.MaxRune {
r = utf8.RuneError
}
buf := f.intbuf[:0]
w := utf8.EncodeRune(buf[:utf8.UTFMax], r)
f.pad(buf[:w])
}
// fmtQc formats an integer as a single-quoted, escaped Go character constant.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmtQc(c uint64) {
r := rune(c)
if c > utf8.MaxRune {
r = utf8.RuneError
}
buf := f.intbuf[:0]
if f.plus {
f.pad(strconv.AppendQuoteRuneToASCII(buf, r))
} else {
f.pad(strconv.AppendQuoteRune(buf, r))
}
}
// fmtFloat formats a float64. It assumes that verb is a valid format specifier
// for strconv.AppendFloat and therefore fits into a byte.
func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) {
// Explicit precision in format specifier overrules default precision.
if f.precPresent {
prec = f.prec
}
// Format number, reserving space for leading + sign if needed.
num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size)
if num[1] == '-' || num[1] == '+' {
num = num[1:]
} else {
num[0] = '+'
}
// f.space means to add a leading space instead of a "+" sign unless
// the sign is explicitly asked for by f.plus.
if f.space && num[0] == '+' && !f.plus {
num[0] = ' '
}
// Special handling for infinities and NaN,
// which don't look like a number so shouldn't be padded with zeros.
if num[1] == 'I' || num[1] == 'N' {
oldZero := f.zero
f.zero = false
// Remove sign before NaN if not asked for.
if num[1] == 'N' && !f.space && !f.plus {
num = num[1:]
}
f.pad(num)
f.zero = oldZero
return
}
// The sharp flag forces printing a decimal point for non-binary formats
// and retains trailing zeros, which we may need to restore.
if f.sharp && verb != 'b' {
digits := 0
switch verb {
case 'v', 'g', 'G', 'x':
digits = prec
// If no precision is set explicitly use a precision of 6.
if digits == -1 {
digits = 6
}
}
// Buffer pre-allocated with enough room for
// exponent notations of the form "e+123" or "p-1023".
var tailBuf [6]byte
tail := tailBuf[:0]
hasDecimalPoint := false
sawNonzeroDigit := false
// Starting from i = 1 to skip sign at num[0].
for i := 1; i < len(num); i++ {
switch num[i] {
case '.':
hasDecimalPoint = true
case 'p', 'P':
tail = append(tail, num[i:]...)
num = num[:i]
case 'e', 'E':
if verb != 'x' && verb != 'X' {
tail = append(tail, num[i:]...)
num = num[:i]
break
}
fallthrough
default:
if num[i] != '0' {
sawNonzeroDigit = true
}
// Count significant digits after the first non-zero digit.
if sawNonzeroDigit {
digits--
}
}
}
if !hasDecimalPoint {
// Leading digit 0 should contribute once to digits.
if len(num) == 2 && num[1] == '0' {
digits--
}
num = append(num, '.')
}
for digits > 0 {
num = append(num, '0')
digits--
}
num = append(num, tail...)
}
// We want a sign if asked for and if the sign is not positive.
if f.plus || num[0] != '+' {
// If we're zero padding to the left we want the sign before the leading zeros.
// Achieve this by writing the sign out and then padding the unsigned number.
if f.zero && f.widPresent && f.wid > len(num) {
f.buf.writeByte(num[0])
f.writePadding(f.wid - len(num))
f.buf.write(num[1:])
return
}
f.pad(num)
return
}
// No sign to show and the number is positive; just print the unsigned number.
f.pad(num[1:])
}

83
vendor/github.com/cockroachdb/redact/internal/hooks.go generated vendored Normal file
View File

@@ -0,0 +1,83 @@
// Copyright 2020 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 fmt
// printArg overrides the original implementation by redirecting the
// call to a substitute function in the printer, if available.
func (p *pp) printArg(a interface{}, verb rune) {
if p.printArgSubstituteFn != nil {
p.substituteState = p.printArgSubstituteFn(p, a, verb)
} else {
p.printArgOrig(a, verb)
}
}
// InternalPrinter exposes pp to the redact package.
type InternalPrinter = pp
// InternalBuffer exposes buffer to the redact package.
type InternalBuffer = buffer
// NewInternalPrinter exposes pp allocation to the redact package.
func NewInternalPrinter() *InternalPrinter { return newPrinter() }
// SetHook connects an outer printer to the inner printer.
func SetHook(
p *InternalPrinter, fn func(p *InternalPrinter, arg interface{}, verb rune) (newState int),
) {
p.printArgSubstituteFn = fn
}
// Free exposes pp deallocation to the redact package.
func Free(p *InternalPrinter) {
p.substituteState = 0
p.printArgSubstituteFn = nil
p.free()
}
// Buf exposes the string buffer to the redact package.
func Buf(p *InternalPrinter) []byte { return []byte(p.buf) }
// GetState exposes the state to the redact package.
func GetState(p *InternalPrinter) int {
return p.substituteState
}
// SetState exposes the string buffer to the redact package.
func SetState(p *InternalPrinter, b []byte) {
p.buf = buffer(b)
p.substituteState = len(p.buf)
}
// Append adds bytes to the buffer.
func Append(p *InternalPrinter, b []byte) { p.buf.write(b) }
// PrintArg exposes the printArgOrig() method to the redact package.
func PrintArg(p *InternalPrinter, a interface{}, verb rune) { p.printArgOrig(a, verb) }
// DoPrint exposes the doPrint() method to the redact package.
func DoPrint(p *InternalPrinter, a []interface{}) { p.doPrint(a) }
// DoPrintf exposes the doPrintf() method to the redact package.
func DoPrintf(p *InternalPrinter, format string, a []interface{}) { p.doPrintf(format, a) }
// SetCollectError enables wrapped error collection.
func SetCollectError(p *InternalPrinter) { p.wrapErrs = true }
// CollectingError exposes wrapped error collection.
func CollectingError(p *InternalPrinter) bool { return p.wrapErrs }
// WrappedError retrieves the wrapped error if found.
func WrappedError(p *InternalPrinter) error { return p.wrappedErr }

1189
vendor/github.com/cockroachdb/redact/internal/print.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
--- print.go.orig 2020-08-26 14:49:30.396184000 +0200
+++ print.go 2020-08-26 14:50:29.330829000 +0200
@@ -1,3 +1,6 @@
+// Code generated from print.go.orig. DO NOT EDIT
+// GENERATED FILE DO NOT EDIT
+//
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -5,12 +8,16 @@
package fmt
import (
- "internal/fmtsort"
+ // CUSTOM: needed to avoid a type mismatch on Formatter.
+ origFmt "fmt"
"io"
"os"
"reflect"
"sync"
"unicode/utf8"
+
+ // CUSTOM: our own import since we can't use internal from go stdlib.
+ "github.com/cockroachdb/redact/internal/fmtsort"
)
// Strings for use with buffer.WriteString.
@@ -51,7 +58,8 @@
// The implementation of Format may call Sprint(f) or Fprint(f) etc.
// to generate its output.
type Formatter interface {
- Format(f State, c rune)
+ // CUSTOM: refer to the original type, not the one defined here.
+ Format(f origFmt.State, c rune)
}
// Stringer is implemented by any value that has a String method,
@@ -105,6 +113,10 @@
type pp struct {
buf buffer
+ // CUSTOM: hook fn for the redact package.
+ printArgSubstituteFn func(p *pp, a interface{}, verb rune) (newState int)
+ substituteState int
+
// arg holds the current item, as an interface{}.
arg interface{}
@@ -635,7 +647,8 @@
return false
}
-func (p *pp) printArg(arg interface{}, verb rune) {
+// CUSTOM: printArg() renamed to printArgOrig().
+func (p *pp) printArgOrig(arg interface{}, verb rune) {
p.arg = arg
p.value = reflect.Value{}

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
#
# This file re-generates the sources in this directory from the Go
# standard library.
#
set -euxo pipefail
(
echo "// Code generated from the Go standard library. DO NOT EDIT"
echo "// GENERATED FILE DO NOT EDIT"
cat $GOROOT/src/fmt/format.go
) >format.go
cp $GOROOT/src/fmt/print.go print.go
patch -p0 <print.go.diff
mkdir -p fmtsort
for a in $GOROOT/src/internal/fmtsort/*; do
if expr "$a" : ".*_test.go"; then
continue
fi
n=$(basename "$a")
(
echo "// Code generated from the Go standard library. DO NOT EDIT"
echo "// GENERATED FILE DO NOT EDIT"
cat "$a"
) >fmtsort/"$n"
done

86
vendor/github.com/cockroachdb/redact/make_format.go generated vendored Normal file
View File

@@ -0,0 +1,86 @@
// Copyright 2020 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 redact
import (
"fmt"
"io"
"strconv"
"strings"
)
func reproducePrintf(w io.Writer, s fmt.State, verb rune, arg interface{}) {
justV, revFmt := MakeFormat(s, verb)
if justV {
// Common case, avoids generating then parsing the format again.
fmt.Fprint(w, arg)
} else {
fmt.Fprintf(w, revFmt, arg)
}
}
// MakeFormat is a helper for use by implementations of the
// SafeFormatter interface. It reproduces the format currently active
// in fmt.State and verb. This is provided because Go's standard
// fmt.State does not make the original format string available to us.
//
// If the return value justV is true, then the current state
// was found to be %v exactly; in that case the caller
// can avoid a full-blown Printf call and use just Print instead
// to take a shortcut.
func MakeFormat(s fmt.State, verb rune) (justV bool, format string) {
plus, minus, hash, sp, z := s.Flag('+'), s.Flag('-'), s.Flag('#'), s.Flag(' '), s.Flag('0')
w, wp := s.Width()
p, pp := s.Precision()
if !plus && !minus && !hash && !sp && !z && !wp && !pp {
switch verb {
case 'v':
return true, "%v"
case 's':
return false, "%s"
case 'd':
return false, "%d"
}
// Other cases handled in the slow path below.
}
var f strings.Builder
f.WriteByte('%')
if plus {
f.WriteByte('+')
}
if minus {
f.WriteByte('-')
}
if hash {
f.WriteByte('#')
}
if sp {
f.WriteByte(' ')
}
if z {
f.WriteByte('0')
}
if wp {
f.WriteString(strconv.Itoa(w))
}
if pp {
f.WriteByte('.')
f.WriteString(strconv.Itoa(p))
}
f.WriteRune(verb)
return false, f.String()
}

109
vendor/github.com/cockroachdb/redact/markers.go generated vendored Normal file
View File

@@ -0,0 +1,109 @@
// Copyright 2020 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 redact
import "bytes"
// RedactableString is a string that contains a mix of safe and unsafe
// bits of data, but where it is known that unsafe bits are enclosed
// by redaction markers ‹ and ›, and occurrences of the markers
// inside the original data items have been escaped.
//
// Instances of RedactableString should not be constructed directly;
// instead use the facilities from print.go (Sprint, Sprintf)
// or the methods below.
type RedactableString string
// StripMarkers removes the redaction markers from the
// RedactableString. This returns an unsafe string where all safe and
// unsafe bits are mixed together.
func (s RedactableString) StripMarkers() string {
return reStripMarkers.ReplaceAllString(string(s), "")
}
// Redact replaces all occurrences of unsafe substrings by the
// “Redacted” marker, ‹×›. The result string is still safe.
func (s RedactableString) Redact() RedactableString {
return RedactableString(reStripSensitive.ReplaceAllString(string(s), redactedS))
}
// ToBytes converts the string to a byte slice.
func (s RedactableString) ToBytes() RedactableBytes {
return RedactableBytes([]byte(string(s)))
}
// SafeFormat formats the redactable safely.
func (s RedactableString) SafeFormat(sp SafePrinter, _ rune) {
// As per annotateArgs() in markers_internal_print.go,
// we consider the redactable string not further formattable.
sp.Print(s)
}
// RedactableBytes is like RedactableString but is a byte slice.
//
// Instances of RedactableBytes should not be constructed directly;
// instead use the facilities from print.go (Sprint, Sprintf)
// or the methods below.
type RedactableBytes []byte
// StripMarkers removes the redaction markers from the
// RedactableBytes. This returns an unsafe string where all safe and
// unsafe bits are mixed together.
func (s RedactableBytes) StripMarkers() []byte {
return reStripMarkers.ReplaceAll([]byte(s), nil)
}
// Redact replaces all occurrences of unsafe substrings by the
// “Redacted” marker, ‹×›.
func (s RedactableBytes) Redact() RedactableBytes {
return RedactableBytes(reStripSensitive.ReplaceAll(s, redactedBytes))
}
// ToString converts the byte slice to a string.
func (s RedactableBytes) ToString() RedactableString {
return RedactableString(string([]byte(s)))
}
// SafeFormat formats the redactable safely.
func (s RedactableBytes) SafeFormat(sp SafePrinter, _ rune) {
// As per annotateArgs() in markers_internal_print.go,
// we consider the redactable bytes not further formattable.
sp.Print(s)
}
// EscapeBytes escapes markers inside the given byte slice and encloses
// the entire byte slice between redaction markers.
func EscapeBytes(s []byte) RedactableBytes {
var buf bytes.Buffer
buf.Grow(len(s) + len(startRedactableS) + len(endRedactableS))
e := escapeWriter{w: &buf, enclose: true, strip: false}
_, _ = e.Write(s)
return RedactableBytes(buf.Bytes())
}
// StartMarker returns the start delimiter for an unsafe string.
func StartMarker() []byte { return startRedactableBytes }
// EndMarker returns the end delimiter for an unsafe string.
func EndMarker() []byte { return endRedactableBytes }
// RedactedMarker returns the special string used by Redact.
func RedactedMarker() []byte { return redactedBytes }
// EscapeMarkers escapes the special delimiters from the provided
// byte slice.
func EscapeMarkers(s []byte) []byte {
return reStripMarkers.ReplaceAll(s, escapeBytes)
}

View File

@@ -0,0 +1,40 @@
// Copyright 2020 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 redact
import "regexp"
const startRedactable = '‹'
const startRedactableS = string(startRedactable)
var startRedactableBytes = []byte(startRedactableS)
const endRedactable = '›'
const endRedactableS = string(endRedactable)
var endRedactableBytes = []byte(endRedactableS)
const escapeMark = '?'
const escapeMarkS = string(escapeMark)
var escapeBytes = []byte(escapeMarkS)
const redactedS = startRedactableS + "×" + endRedactableS
var redactedBytes = []byte(redactedS)
var reStripSensitive = regexp.MustCompile(startRedactableS + "[^" + startRedactableS + endRedactableS + "]*" + endRedactableS)
var reStripMarkers = regexp.MustCompile("[" + startRedactableS + endRedactableS + "]")

View File

@@ -0,0 +1,217 @@
// Copyright 2020 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 redact
import (
"bytes"
"fmt"
"io"
)
// escapeState abstracts on top of fmt.State and ensures that call
// calls to Write() enclose the writtne bytes between unsafe markers.
type escapeState struct {
fmt.State
w escapeWriter
}
var _ fmt.State = (*escapeState)(nil)
func makeEscapeState(s fmt.State, buf *bytes.Buffer) escapeState {
e := escapeState{State: s}
e.w = escapeWriter{w: buf, enclose: true}
return e
}
// Write is part of the fmt.State interface and implements the io.Writer interface.
func (p *escapeState) Write(b []byte) (int, error) {
return p.w.Write(b)
}
// escapeWriter abstracts on top of io.Writer and ensures that all
// calls to Write() escape markers.
// Also, final spaces and newlines are stripped if strip is set.
// Also, the overall result is enclosed inside redaction markers
// if enclose is true.
type escapeWriter struct {
w io.Writer
enclose bool
strip bool
}
var _ io.Writer = (*escapeWriter)(nil)
// Write implements the io.Writer interface.
func (p *escapeWriter) Write(b []byte) (int, error) {
st := escapeResult{0, nil}
if p.strip {
// Trim final newlines/spaces, for convenience.
end := len(b)
for i := end - 1; i >= 0; i-- {
if b[i] == '\n' || b[i] == ' ' {
end = i
} else {
break
}
}
b = b[:end]
}
// Here we could choose to omit the output
// entirely if there was nothing but empty space:
// if len(b) == 0 { return 0, nil }
// Note: we use len(...RedactableS) and not len(...RedactableBytes)
// because the ...S variant is a compile-time constant so this
// accelerates the loops below.
start, ls := startRedactableBytes, len(startRedactableS)
end, le := endRedactableBytes, len(endRedactableS)
escape := escapeBytes
if p.enclose {
st = p.doWrite(start, st, false)
}
// Now write the string.
// k is the index in b up to (and excluding) the byte which we've
// already copied into the output.
k := 0
for i := 0; i < len(b); i++ {
if b[i] == '\n' && p.enclose {
// Avoid enclosing newline characters inside redaction markers.
// This is important when redact is used to render errors, where
// sub-strings split at newline characters are rendered
// separately.
st = p.doWrite(b[k:i], st, true)
st = p.doWrite(end, st, false)
// Advance to the last newline character. We want to forward
// them all in a single call to doWrite, for performance.
lastNewLine := i
for b[lastNewLine] == '\n' && lastNewLine < len(b) {
lastNewLine++
}
st = p.doWrite(b[i:lastNewLine], st, true)
st = p.doWrite(start, st, false)
// Advance the counters by the number of newline characters.
k = lastNewLine
i = lastNewLine - 1 /* -1 because we have i++ at the end of every iteration */
} else {
// Ensure that occurrences of the delimiter inside the string get
// escaped.
// Reminder: ls and le are likely greater than 1, as we are scanning
// utf-8 encoded delimiters (the utf-8 encoding is multibyte).
if i+ls <= len(b) && bytes.Equal(b[i:i+ls], start) {
st = p.doWrite(b[k:i], st, true)
st = p.doWrite(escape, st, false)
// Advance the counters by the length (in bytes) of the delimiter.
st.l += ls
k = i + ls
i += ls - 1 /* -1 because we have i++ at the end of every iteration */
} else if i+le <= len(b) && bytes.Equal(b[i:i+le], end) {
st = p.doWrite(b[k:i], st, true)
st = p.doWrite(escape, st, false)
// Advance the counters by the length (in bytes) of the delimiter.
st.l += le
k = i + le
i += le - 1 /* -1 because we have i++ at the end of every iteration */
}
}
}
st = p.doWrite(b[k:], st, true)
if p.enclose {
st = p.doWrite(end, st, false)
}
return st.l, st.err
}
type escapeResult struct {
l int
err error
}
func (p *escapeWriter) doWrite(b []byte, st escapeResult, count bool) escapeResult {
if st.err != nil {
// An error was encountered previously.
// No-op.
return st
}
sz, err := p.w.Write(b)
if count {
st.l += sz
}
st.err = err
return st
}
// internalEscapeBytes escapes redaction markers in the provided buf
// starting at the location startLoc.
// The bytes before startLoc are considered safe (already escaped).
func internalEscapeBytes(b []byte, startLoc int) (res []byte) {
// Note: we use len(...RedactableS) and not len(...RedactableBytes)
// because the ...S variant is a compile-time constant so this
// accelerates the loops below.
start, ls := startRedactableBytes, len(startRedactableS)
end, le := endRedactableBytes, len(endRedactableS)
escape := escapeBytes
// res is the output slice. In the common case where there is
// nothing to escape, the input slice is returned directly
// and no allocation takes place.
res = b
// copied is true if and only if `res` is a copy of `b`. It only
// turns to true if the loop below finds something to escape.
copied := false
// k is the index in b up to (and excluding) the byte which we've
// already copied into res (if copied=true).
k := 0
for i := startLoc; i < len(b); i++ {
// Ensure that occurrences of the delimiter inside the string get
// escaped.
// Reminder: ls and le are likely greater than 1, as we are scanning
// utf-8 encoded delimiters (the utf-8 encoding is multibyte).
if i+ls <= len(b) && bytes.Equal(b[i:i+ls], start) {
if !copied {
// We only allocate an output slice when we know we definitely
// need it.
res = make([]byte, 0, len(b)+len(escape))
copied = true
}
res = append(res, b[k:i]...)
res = append(res, escape...)
// Advance the counters by the length (in bytes) of the delimiter.
k = i + ls
i += ls - 1 /* -1 because we have i++ at the end of every iteration */
} else if i+le <= len(b) && bytes.Equal(b[i:i+le], end) {
if !copied {
// See the comment above about res allocation.
res = make([]byte, 0, len(b)+len(escape))
copied = true
}
res = append(res, b[k:i]...)
res = append(res, escape...)
// Advance the counters by the length (in bytes) of the delimiter.
k = i + le
i += le - 1 /* -1 because we have i++ at the end of every iteration */
}
}
if copied {
res = append(res, b[k:]...)
}
return
}

View File

@@ -0,0 +1,264 @@
// Copyright 2020 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 redact
import (
"fmt"
internalFmt "github.com/cockroachdb/redact/internal"
)
// printArgFn is the hook injected into the standard fmt logic
// by the printer functions in markers_print.go.
func printArgFn(p *internalFmt.InternalPrinter, arg interface{}, verb rune) (newState int) {
redactLastWrites(p)
switch verb {
case 'T':
// If the value was wrapped, reveal its original type. Anything else is not very useful.
switch v := arg.(type) {
case safeWrapper:
arg = v.a
case unsafeWrap:
arg = v.a
}
// Shortcut: %T is always safe to print as-is.
internalFmt.PrintArg(p, arg, verb)
return len(internalFmt.Buf(p))
case 'p':
// Printing a pointer via %p is handled as special case in printf,
// so we need a special case here too. The other cases of
// printing a pointer via %v / %d %x etc is handled by the common path.
switch v := arg.(type) {
case safeWrapper:
// If the value was meant to be safe, then print it as-is.
internalFmt.PrintArg(p, v.a, verb)
return len(internalFmt.Buf(p))
case unsafeWrap:
// If it's been wrapped, unwrap it. This helps preserve the
// original pointer value in the output.
arg = v.a
}
// Now perform an unsafe print: we are assuming that the pointer
// representation by the fmt.printf code does not contain
// redaction markers, and go a short route. If that assumption did
// not hold (or is invalidated by changes upstream after this
// comment is written), this code should be changed to use the
// escapeWriter instead.
internalFmt.Append(p, startRedactableBytes)
internalFmt.PrintArg(p, arg, verb)
internalFmt.Append(p, endRedactableBytes)
return len(internalFmt.Buf(p))
}
// nil arguments are printed as-is. Note: a nil argument under
// interface{} is not the same as a nil pointer passed via a pointer
// of a concrete type. The latter kind of nil goes through
// redaction as usual, because it may have its own custom Format() method.
if arg == nil {
internalFmt.PrintArg(p, arg, verb)
return len(internalFmt.Buf(p))
}
// RedactableBytes/RedactableString are already formatted as
// redactable. Include them as-is.
//
// NB: keep this logic synchronized with
// (RedactableString/Bytes).SafeFormat().
switch v := arg.(type) {
case RedactableString:
internalFmt.Append(p, []byte(v))
return len(internalFmt.Buf(p))
case RedactableBytes:
internalFmt.Append(p, []byte(v))
return len(internalFmt.Buf(p))
}
arg = annotateArg(arg, internalFmt.CollectingError(p))
internalFmt.PrintArg(p, arg, verb)
return len(internalFmt.Buf(p))
}
// redactLastWrites escapes any markers that were added by the
// internals of the printf functions, for example
// if markers were present in the format string.
func redactLastWrites(p *internalFmt.InternalPrinter) {
state := internalFmt.GetState(p)
newBuf := internalEscapeBytes(internalFmt.Buf(p), state)
internalFmt.SetState(p, newBuf)
}
// annotateArg wraps the arguments to one of the print functions with
// an indirect formatter which ensures that redaction markers inside
// the representation of the object are escaped, and optionally
// encloses the result of the display between redaction markers.
//
// collectingError is true iff we are in the context of
// HelperForErrorf, where we want the %w verb to work properly. This
// adds a little overhead to the processing, but this is OK because
// typically the error path is not perf-critical.
func annotateArg(arg interface{}, collectingError bool) interface{} {
var newArg fmt.Formatter
err, isError := arg.(error)
switch v := arg.(type) {
case SafeFormatter:
// calls to Format() by fmt.Print will be redirected to
// v.SafeFormat(). This delegates the task of adding markers to
// the object itself.
newArg = &redactFormatRedirect{
func(p SafePrinter, verb rune) { v.SafeFormat(p, verb) },
}
case SafeValue:
// calls to Format() by fmt.Print will be redirected to a
// display of v without redaction markers.
//
// Note that we can't let the value be displayed as-is because
// we must prevent any marker inside the value from leaking into
// the result. (We want to avoid mismatched markers.)
newArg = &escapeArg{arg: arg, enclose: false}
case SafeMessager:
// Obsolete interface.
// TODO(knz): Remove this.
newArg = &escapeArg{arg: v.SafeMessage(), enclose: false}
default:
if isError && redactErrorFn != nil {
// We place this case after the other cases above, in case
// the error object knows how to print itself safely already.
newArg = &redactFormatRedirect{
func(p SafePrinter, verb rune) { redactErrorFn(err, p, verb) },
}
} else {
// calls to Format() by fmt.Print will be redirected to a
// display of v within redaction markers if the type is
// considered unsafe, without markers otherwise. In any case,
// occurrences of delimiters within are escaped.
newArg = &escapeArg{arg: v, enclose: !isSafeValue(v)}
}
}
if isError && collectingError {
// Ensure the arg still implements the `error` interface for
// detection by the handling of %w, while also implementing
// fmt.Formatter to forward the implementation to the objects
// constructed above.
newArg = &makeError{err: err, arg: newArg}
}
return newArg
}
type makeError struct {
err error
arg fmt.Formatter
}
// Error implements error.
func (m *makeError) Error() string { return m.err.Error() }
// Format implements fmt.Formatter.
func (m *makeError) Format(f fmt.State, verb rune) { m.arg.Format(f, verb) }
// redactFormatRedirect wraps a safe print callback and uses it to
// implement fmt.Formatter.
type redactFormatRedirect struct {
printFn func(p SafePrinter, verb rune)
}
// Format implements fmt.Formatter.
func (r *redactFormatRedirect) Format(s fmt.State, verb rune) {
defer func() {
if p := recover(); p != nil {
e := escapeWriter{w: s}
fmt.Fprintf(&e, "%%!%c(PANIC=SafeFormatter method: %v)", verb, p)
}
}()
p := &printer{}
p.escapeState = makeEscapeState(s, &p.buf)
r.printFn(p, verb)
_, _ = s.Write(p.buf.Bytes())
}
// passthrough passes a pre-formatted string through.
type passthrough struct{ arg []byte }
// Format implements fmt.Formatter.
func (p *passthrough) Format(s fmt.State, _ rune) {
_, _ = s.Write(p.arg)
}
// escapeArg wraps an arbitrary value and ensures that any occurrence
// of the redaction markers in its representation are escaped.
//
// The result of printing out the value is enclosed within markers or
// not depending on the value of the enclose bool.
type escapeArg struct {
arg interface{}
enclose bool
}
func (r *escapeArg) Format(s fmt.State, verb rune) {
switch t := r.arg.(type) {
case fmt.Formatter:
// This is a special case from the default case below, which
// allows a shortcut through the layers of the fmt package.
p := &escapeState{
State: s,
w: escapeWriter{
w: s,
enclose: r.enclose,
strip: r.enclose,
}}
defer func() {
if recovered := recover(); recovered != nil {
fmt.Fprintf(p, "%%!%c(PANIC=Format method: %v)", verb, recovered)
}
}()
t.Format(p, verb)
default:
// TODO(knz): It would be possible to implement struct formatting
// with conditional redaction based on field tag annotations here.
p := &escapeWriter{w: s, enclose: r.enclose, strip: r.enclose}
reproducePrintf(p, s, verb, r.arg)
}
}
// printerfn is a helper struct for use by Sprintfn.
type printerfn struct {
fn func(SafePrinter)
}
// SafeFormat implements the SafeFormatter interface.
func (p printerfn) SafeFormat(w SafePrinter, _ rune) {
p.fn(w)
}
// redactErrorFn can be injected from an error library
// to render error objects safely.
var redactErrorFn func(err error, p SafePrinter, verb rune)
// RegisterRedactErrorFn registers an error redaction function for use
// during automatic redaction by this package.
// Provided e.g. by cockroachdb/errors.
func RegisterRedactErrorFn(fn func(err error, p SafePrinter, verb rune)) {
redactErrorFn = fn
}

View File

@@ -0,0 +1,88 @@
// Copyright 2020 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 redact
import (
"bytes"
"fmt"
"unicode/utf8"
)
// printer implements SafePrinter.
// This is the machinery for the Print() functions offered
// by this package.
type printer struct {
escapeState
buf bytes.Buffer
}
var _ fmt.State = (*printer)(nil)
var _ SafeWriter = (*printer)(nil)
// Print is part of the SafeWriter interface.
func (b *printer) Print(args ...interface{}) {
_, _ = Fprint(&b.buf, args...)
}
// Printf is part of the SafeWriter interface.
func (b *printer) Printf(format string, args ...interface{}) {
_, _ = Fprintf(&b.buf, format, args...)
}
// SafeString is part of the SafeWriter interface.
func (b *printer) SafeString(s SafeString) {
w := escapeWriter{w: &b.buf, enclose: false}
_, _ = w.Write([]byte(s))
}
// SafeRune is part of the SafeWriter interface.
func (b *printer) SafeRune(s SafeRune) {
if s == startRedactable || s == endRedactable {
s = escapeMark
}
_, _ = b.buf.WriteRune(rune(s))
}
// UnsafeString is part of the SafeWriter interface.
func (b *printer) UnsafeString(s string) {
w := escapeWriter{w: &b.buf, enclose: true, strip: true}
_, _ = w.Write([]byte(s))
}
// UnsafeRune is part of the SafeWriter interface.
func (b *printer) UnsafeRune(s rune) {
_, _ = b.buf.WriteRune(startRedactable)
b.SafeRune(SafeRune(s))
_, _ = b.buf.WriteRune(endRedactable)
}
// UnsafeByte is part of the SafeWriter interface.
func (b *printer) UnsafeByte(s byte) {
_, _ = b.buf.WriteRune(startRedactable)
if s >= utf8.RuneSelf ||
s == startRedactableBytes[0] || s == endRedactableBytes[0] {
// Unsafe byte. Escape it.
_, _ = b.buf.Write(escapeBytes)
} else {
_ = b.buf.WriteByte(s)
}
_, _ = b.buf.WriteRune(endRedactable)
}
// UnsafeBytes is part of the SafeWriter interface.
func (b *printer) UnsafeBytes(s []byte) {
w := escapeWriter{w: &b.buf, enclose: true, strip: true}
_, _ = w.Write(s)
}

View File

@@ -0,0 +1,31 @@
// Copyright 2020 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 redact
import "reflect"
// RegisterSafeType registers a data type to always be considered safe
// during the production of redactable strings.
func RegisterSafeType(t reflect.Type) {
safeTypeRegistry[t] = true
}
// safeTypeRegistry registers Go data types that are to be always
// considered safe, even when they don't implement SafeValue.
var safeTypeRegistry = map[reflect.Type]bool{}
func isSafeValue(a interface{}) bool {
return safeTypeRegistry[reflect.TypeOf(a)]
}

122
vendor/github.com/cockroachdb/redact/markers_print.go generated vendored Normal file
View File

@@ -0,0 +1,122 @@
// Copyright 2020 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 redact
import (
"io"
internalFmt "github.com/cockroachdb/redact/internal"
)
// Sprint prints out the arguments and encloses unsafe bits
// between redaction markers.
// If either safe and unsafe bits of data contain the markers
// in their representation already, they are escaped first.
// If a RedactableString or RedactableBytes argument is passed,
// it is reproduced as-is without escaping.
func Sprint(args ...interface{}) RedactableString {
p := internalFmt.NewInternalPrinter()
internalFmt.SetHook(p, printArgFn)
internalFmt.DoPrint(p, args)
redactLastWrites(p)
s := RedactableString(internalFmt.Buf(p))
internalFmt.Free(p)
return s
}
// Sprintf formats the arguments and encloses unsafe bits
// between redaction markers.
// If either safe and unsafe bits of data contain the markers
// in their representation already, they are escaped first.
// The format is always considered safe and the caller
// is responsible to ensure that the markers are not present
// in the format string.
func Sprintf(format string, args ...interface{}) RedactableString {
p := internalFmt.NewInternalPrinter()
internalFmt.SetHook(p, printArgFn)
internalFmt.DoPrintf(p, format, args)
redactLastWrites(p)
s := RedactableString(internalFmt.Buf(p))
internalFmt.Free(p)
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{}) (RedactableString, error) {
p := internalFmt.NewInternalPrinter()
internalFmt.SetCollectError(p)
internalFmt.SetHook(p, printArgFn)
internalFmt.DoPrintf(p, format, args)
redactLastWrites(p)
s := RedactableString(internalFmt.Buf(p))
e := internalFmt.WrappedError(p)
internalFmt.Free(p)
if m, ok := e.(*makeError); ok {
e = m.err
}
return s, e
}
// Sprintfn produces a RedactableString using the provided
// SafeFormat-alike function.
func Sprintfn(printer func(w SafePrinter)) RedactableString {
return Sprint(printerfn{printer})
}
// StringWithoutMarkers formats the provided SafeFormatter and strips
// the redaction markers from the result. This is provided for
// convenience to facilitate the implementation of String() methods
// alongside SafeFormat() to avoid code duplication.
//
// Note: if this function is ever found to be a performance
// bottleneck, one can consider using an alternate implementation of
// Sprint() which similarly calls the SafeFormat() methods but does
// not introduce markers and instead writes to a string buffer
// directly.
func StringWithoutMarkers(f SafeFormatter) string {
return Sprint(f).StripMarkers()
}
// Fprint is like Sprint but outputs the redactable
// string to the provided Writer.
func Fprint(w io.Writer, args ...interface{}) (n int, err error) {
p := internalFmt.NewInternalPrinter()
internalFmt.SetHook(p, printArgFn)
internalFmt.DoPrint(p, args)
redactLastWrites(p)
n, err = w.Write(internalFmt.Buf(p))
internalFmt.Free(p)
return
}
// Fprintf is like Sprintf but outputs the redactable string to the
// provided Writer.
func Fprintf(w io.Writer, format string, args ...interface{}) (n int, err error) {
p := internalFmt.NewInternalPrinter()
internalFmt.SetHook(p, printArgFn)
internalFmt.DoPrintf(p, format, args)
redactLastWrites(p)
n, err = w.Write(internalFmt.Buf(p))
internalFmt.Free(p)
return
}

63
vendor/github.com/cockroachdb/redact/wrappers.go generated vendored Normal file
View File

@@ -0,0 +1,63 @@
// Copyright 2020 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 redact
import "fmt"
// Unsafe turns any value that would otherwise be considered safe,
// into an unsafe value.
func Unsafe(a interface{}) interface{} {
return unsafeWrap{a}
}
type unsafeWrap struct {
a interface{}
}
func (w unsafeWrap) Format(s fmt.State, verb rune) {
reproducePrintf(s, s, verb, w.a)
}
// Safe turns any value into an object that is considered as safe by
// the formatter.
//
// This is provided as an “escape hatch” for cases where the other
// interfaces and conventions fail. Increased usage of this mechanism
// should be taken as a signal that a new abstraction is missing.
// The implementation is also slow.
func Safe(a interface{}) SafeValue {
return safeWrapper{a}
}
type safeWrapper struct {
a interface{}
}
var _ SafeValue = safeWrapper{}
var _ fmt.Formatter = safeWrapper{}
var _ SafeMessager = safeWrapper{}
// SafeValue implements the SafeValue interface.
func (w safeWrapper) SafeValue() {}
// Format implements the fmt.Formatter interface.
func (w safeWrapper) Format(s fmt.State, verb rune) {
reproducePrintf(s, s, verb, w.a)
}
// SafeMessage implements SafeMessager.
func (w safeWrapper) SafeMessage() string {
return fmt.Sprintf("%v", w.a)
}