|
package main |
|
|
|
import ( |
|
"fmt" |
|
"io" |
|
"os" |
|
"sort" |
|
"strings" |
|
) |
|
|
|
// ByLength implements the sort.Interface for []string based on the string length. |
|
type ByLength []string |
|
|
|
func (s ByLength) Len() int { |
|
return len(s) |
|
} |
|
|
|
func (s ByLength) Swap(i, j int) { |
|
s[i], s[j] = s[j], s[i] |
|
} |
|
|
|
func (s ByLength) Less(i, j int) bool { |
|
return len(s[i]) > len(s[j]) // Sort in descending order (longest first) |
|
} |
|
|
|
type HidePasswordsWriter struct { |
|
buffer []byte |
|
writer io.Writer |
|
passwords []string |
|
longest int |
|
hideString string |
|
} |
|
|
|
func NewHidePasswordsWriter(writer io.Writer, passwords []string, hideString string) *HidePasswordsWriter { |
|
c := &HidePasswordsWriter{ |
|
passwords: passwords, |
|
hideString: hideString, |
|
writer: writer, |
|
} |
|
c.createBuffer() |
|
return c |
|
} |
|
|
|
func (cw *HidePasswordsWriter) Write(p []byte) (n int, err error) { |
|
for _, char := range p { |
|
cw.buffer = append(cw.buffer, []byte(string(char))...) |
|
pq := false |
|
|
|
for _, v := range cw.passwords { |
|
if string(cw.buffer) == v { |
|
cw.buffer = []byte(cw.hideString) |
|
pq = true |
|
break |
|
} |
|
if strings.HasPrefix(v, string(cw.buffer)) { |
|
pq = false |
|
break |
|
} |
|
pq = true |
|
} |
|
|
|
if len(cw.buffer) >= cw.longest { |
|
pq = true |
|
} |
|
|
|
if pq { |
|
cw.Flush() |
|
} |
|
} |
|
return len(p), nil |
|
} |
|
|
|
func keepLongestOfSamePrefix(allstrings []string) []string { |
|
ret := []string{} |
|
sort.Strings(allstrings) |
|
for k, v := range allstrings { |
|
if k < len(allstrings)-1 && strings.HasPrefix(allstrings[k+1], v) { |
|
continue |
|
} |
|
ret = append(ret, v) |
|
} |
|
return ret |
|
} |
|
|
|
func (cw *HidePasswordsWriter) createBuffer() { |
|
cw.longest = 0 |
|
cw.passwords = keepLongestOfSamePrefix(cw.passwords) |
|
cw.longest = len(cw.passwords[0]) |
|
cw.buffer = make([]byte, 0, cw.longest) |
|
} |
|
|
|
func (cw *HidePasswordsWriter) Flush() { |
|
if len(cw.buffer) > 0 { |
|
cw.writer.Write(cw.buffer) |
|
cw.buffer = cw.buffer[:0] // Clear the buffer |
|
} |
|
} |
|
|
|
func test() { |
|
passwords := []string{"foofofofofoofofofoaofoofaofao", "password", "password2", "helloworld", "anotherpassword2"} |
|
|
|
// stdout writer |
|
stdoutWriter := NewHidePasswordsWriter(os.Stdout, passwords, "XXXXXX") |
|
|
|
// output to a file writer |
|
outputFile, err := os.Create("/tmp/output.txt") |
|
defer outputFile.Close() |
|
fileWriter := NewHidePasswordsWriter(outputFile, passwords, "XXXXXX") |
|
|
|
// write stdin to both |
|
multiWriter := io.MultiWriter(fileWriter, stdoutWriter) |
|
_, err = io.Copy(multiWriter, os.Stdin) |
|
if err != nil { |
|
fmt.Println(err) |
|
} |
|
|
|
// flush the rest if needed |
|
fileWriter.Flush() |
|
stdoutWriter.Flush() |
|
} |
|
|
|
func main() { |
|
test() |
|
} |