log.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. //Package for a safer logging wrapper around the standard logging package
  2. //import "git.torproject.org/pluggable-transports/snowflake.git/common/safelog"
  3. package safelog
  4. import (
  5. "bytes"
  6. "io"
  7. "regexp"
  8. "sync"
  9. )
  10. const ipv4Address = `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`
  11. const ipv6Address = `([0-9a-fA-F]{0,4}:){5,7}([0-9a-fA-F]{0,4})?`
  12. const ipv6Compressed = `([0-9a-fA-F]{0,4}:){0,5}([0-9a-fA-F]{0,4})?(::)([0-9a-fA-F]{0,4}:){0,5}([0-9a-fA-F]{0,4})?`
  13. const ipv6Full = `(` + ipv6Address + `(` + ipv4Address + `))` +
  14. `|(` + ipv6Compressed + `(` + ipv4Address + `))` +
  15. `|(` + ipv6Address + `)` + `|(` + ipv6Compressed + `)`
  16. const optionalPort = `(:\d{1,5})?`
  17. const addressPattern = `((` + ipv4Address + `)|(\[(` + ipv6Full + `)\])|(` + ipv6Full + `))` + optionalPort
  18. const fullAddrPattern = `(^|\s|[^\w:])` + addressPattern + `(\s|(:\s)|[^\w:]|$)`
  19. var scrubberPatterns = []*regexp.Regexp{
  20. regexp.MustCompile(fullAddrPattern),
  21. }
  22. var addressRegexp = regexp.MustCompile(addressPattern)
  23. // An io.Writer that can be used as the output for a logger that first
  24. // sanitizes logs and then writes to the provided io.Writer
  25. type LogScrubber struct {
  26. Output io.Writer
  27. buffer []byte
  28. lock sync.Mutex
  29. }
  30. func (ls *LogScrubber) Lock() { (*ls).lock.Lock() }
  31. func (ls *LogScrubber) Unlock() { (*ls).lock.Unlock() }
  32. func scrub(b []byte) []byte {
  33. scrubbedBytes := b
  34. for _, pattern := range scrubberPatterns {
  35. // this is a workaround since go does not yet support look ahead or look
  36. // behind for regular expressions.
  37. scrubbedBytes = pattern.ReplaceAllFunc(scrubbedBytes, func(b []byte) []byte {
  38. return addressRegexp.ReplaceAll(b, []byte("[scrubbed]"))
  39. })
  40. }
  41. return scrubbedBytes
  42. }
  43. func (ls *LogScrubber) Write(b []byte) (n int, err error) {
  44. ls.Lock()
  45. defer ls.Unlock()
  46. n = len(b)
  47. ls.buffer = append(ls.buffer, b...)
  48. for {
  49. i := bytes.LastIndexByte(ls.buffer, '\n')
  50. if i == -1 {
  51. return
  52. }
  53. fullLines := ls.buffer[:i+1]
  54. _, err = ls.Output.Write(scrub(fullLines))
  55. if err != nil {
  56. return
  57. }
  58. ls.buffer = ls.buffer[i+1:]
  59. }
  60. }