Refactored server log scrubber into package

The server log scrubbing code from ticket #21304 is now refactored into
a safelog package, along with the appropriate tests
This commit is contained in:
Cecylia Bocovich 2019-04-11 14:02:18 -04:00
parent 6399ef9d4f
commit 49042511a3
4 changed files with 201 additions and 187 deletions

View file

@ -3,7 +3,6 @@
package main
import (
"bytes"
"crypto/tls"
"errors"
"flag"
@ -16,13 +15,13 @@ import (
"os"
"os/signal"
"path/filepath"
"regexp"
"strings"
"sync"
"syscall"
"time"
"git.torproject.org/pluggable-transports/goptlib.git"
"git.torproject.org/pluggable-transports/snowflake.git/common/safelog"
"git.torproject.org/pluggable-transports/websocket.git/websocket"
"golang.org/x/crypto/acme/autocert"
"golang.org/x/net/http2"
@ -56,55 +55,6 @@ additional HTTP listener on port 80 to work with ACME.
flag.PrintDefaults()
}
const ipv4Address = `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`
const ipv6Address = `(([0-9a-fA-F]{0,4}:){2,7}([0-9a-fA-F]{0,4})?(` + ipv4Address + `))` +
`|(([0-9a-fA-F]{0,4}:){2,7}([0-9a-fA-F]{0,4})?)`
const optionalPort = `(:\d{1,5})?`
const addressPattern = `((` + ipv4Address + `)|(\[(` + ipv6Address + `)\])|(` + ipv6Address + `))` + optionalPort
const fullAddrPattern = `(^|\s|[^\w:])` + addressPattern + `(\s|(:\s)|[^\w:]|$)`
var scrubberPatterns = []*regexp.Regexp{
regexp.MustCompile(fullAddrPattern),
}
var addressRegexp = regexp.MustCompile(addressPattern)
// An io.Writer that can be used as the output for a logger that first
// sanitizes logs and then writes to the provided io.Writer
type logScrubber struct {
output io.Writer
buffer []byte
}
func scrub(b []byte) []byte {
scrubbedBytes := b
for _, pattern := range scrubberPatterns {
// this is a workaround since go does not yet support look ahead or look
// behind for regular expressions.
scrubbedBytes = pattern.ReplaceAllFunc(scrubbedBytes, func(b []byte) []byte {
return addressRegexp.ReplaceAll(b, []byte("[scrubbed]"))
})
}
return scrubbedBytes
}
func (ls *logScrubber) Write(b []byte) (n int, err error) {
n = len(b)
ls.buffer = append(ls.buffer, b...)
for {
i := bytes.LastIndexByte(ls.buffer, '\n')
if i == -1 {
return
}
fullLines := ls.buffer[:i+1]
_, err = ls.output.Write(scrub(fullLines))
if err != nil {
return
}
ls.buffer = ls.buffer[i+1:]
}
}
// An abstraction that makes an underlying WebSocket connection look like an
// io.ReadWriteCloser.
type webSocketConn struct {
@ -336,7 +286,7 @@ func main() {
logOutput = f
}
//We want to send the log output through our scrubber first
log.SetOutput(&logScrubber{output: logOutput})
log.SetOutput(&safelog.LogScrubber{Output: logOutput})
if !disableTLS && acmeHostnamesCommas == "" {
log.Fatal("the --acme-hostnames option is required")