diff --git a/cmd/root.go b/cmd/root.go index 28d68e1e..c1e7b5c7 100755 --- a/cmd/root.go +++ b/cmd/root.go @@ -12,6 +12,7 @@ import ( "github.com/lindell/multi-gitter/internal/git/cmdgit" "github.com/lindell/multi-gitter/internal/git/gogit" "github.com/lindell/multi-gitter/internal/http" + internallog "github.com/lindell/multi-gitter/internal/log" "github.com/lindell/multi-gitter/internal/multigitter" "github.com/lindell/multi-gitter/internal/scm/gitea" "github.com/lindell/multi-gitter/internal/scm/github" @@ -200,19 +201,35 @@ func logFlagInit(cmd *cobra.Command, args []string) error { // Parse and set the log format strFormat, _ := cmd.Flags().GetString("log-format") + + var formatter log.Formatter switch strFormat { case "text": - log.SetFormatter(&log.TextFormatter{}) + formatter = &log.TextFormatter{} case "json": - log.SetFormatter(&log.JSONFormatter{}) + formatter = &log.JSONFormatter{} case "json-pretty": - log.SetFormatter(&log.JSONFormatter{ + formatter = &log.JSONFormatter{ PrettyPrint: true, - }) + } default: return fmt.Errorf(`unknown log-format "%s"`, strFormat) } + // Make sure sensitive data is censored before logging them + var censorItems []internallog.CensorItem + if token, err := getToken(cmd.Flags()); err == nil && token != "" { + censorItems = append(censorItems, internallog.CensorItem{ + Sensitive: token, + Replacement: "", + }) + } + + log.SetFormatter(&internallog.CensorFormatter{ + CensorItems: censorItems, + UnderlyingFormatter: formatter, + }) + // Set the output (file) strFile, _ := cmd.Flags().GetString("log-file") if strFile == "" { diff --git a/internal/log/censor-formatter.go b/internal/log/censor-formatter.go new file mode 100644 index 00000000..6c9667c7 --- /dev/null +++ b/internal/log/censor-formatter.go @@ -0,0 +1,38 @@ +package log + +import ( + "bytes" + "strings" + + log "github.com/sirupsen/logrus" +) + +// CensorFormatter makes sure sensitive data is not logged. +// It works as a middleware and sensors the data before sending it to an underlying formatter +type CensorFormatter struct { + CensorItems []CensorItem + UnderlyingFormatter log.Formatter +} + +// CensorItem is something that should be censored, Sensitive will be replaced with Replacement +type CensorItem struct { + Sensitive string + Replacement string +} + +// Format censors some data and sends the entry to the underlying formatter +func (f *CensorFormatter) Format(entry *log.Entry) ([]byte, error) { + for _, s := range f.CensorItems { + entry.Message = strings.ReplaceAll(entry.Message, s.Sensitive, s.Replacement) + + for key := range entry.Data { + if str, ok := entry.Data[key].(string); ok { + entry.Data[key] = strings.ReplaceAll(str, s.Sensitive, s.Replacement) + } + if bb, ok := entry.Data[key].([]byte); ok { + entry.Data[key] = bytes.ReplaceAll(bb, []byte(s.Sensitive), []byte(s.Replacement)) + } + } + } + return f.UnderlyingFormatter.Format(entry) +}