This repository has no description
1package models
2
3import (
4 "encoding/base64"
5 "strings"
6)
7
8// SecretMask replaces secret values in strings with "***".
9type SecretMask struct {
10 replacer *strings.Replacer
11 // length of the longest secret. writers keep the last window-1
12 // bytes unflushed so a secret split across writes can still match
13 // whole
14 window int
15}
16
17// NewSecretMask creates a mask for the given secret values.
18// Also registers base64-encoded variants of each secret.
19func NewSecretMask(values []string) *SecretMask {
20 var pairs []string
21
22 for _, value := range values {
23 if value == "" {
24 continue
25 }
26
27 pairs = append(pairs, value, "***")
28
29 b64 := base64.StdEncoding.EncodeToString([]byte(value))
30 if b64 != value {
31 pairs = append(pairs, b64, "***")
32 }
33
34 b64NoPad := strings.TrimRight(b64, "=")
35 if b64NoPad != b64 && b64NoPad != value {
36 pairs = append(pairs, b64NoPad, "***")
37 }
38 }
39
40 if len(pairs) == 0 {
41 return nil
42 }
43
44 window := 0
45 for i := 0; i < len(pairs); i += 2 {
46 window = max(window, len(pairs[i]))
47 }
48
49 return &SecretMask{
50 replacer: strings.NewReplacer(pairs...),
51 window: window,
52 }
53}
54
55// trailing bytes a streaming caller must keep unflushed so a secret
56// spanning a write boundary still matches
57func (m *SecretMask) Window() int {
58 if m == nil {
59 return 0
60 }
61 if m.window <= 1 {
62 return 0
63 }
64 return m.window - 1
65}
66
67// Mask replaces all registered secret values with "***".
68func (m *SecretMask) Mask(input string) string {
69 if m == nil || m.replacer == nil {
70 return input
71 }
72 return m.replacer.Replace(input)
73}