@@ -11,6 +11,7 @@ import (
1111"slices"
1212"strconv"
1313"strings"
14+"sync"
14151516"github.com/rclone/rclone/fs/config/configmap"
1617)
@@ -462,11 +463,61 @@ func configAll(ctx context.Context, name string, m configmap.Mapper, ri *RegInfo
462463return nil, fmt.Errorf("internal error: bad state %q", state)
463464}
464465466+// redactDumpAuthWarnOnce makes sure the --dump auth warning is only shown once
467+var redactDumpAuthWarnOnce sync.Once
468+469+// RedactValue makes value safe for inclusion in the debug log.
470+//
471+// Non-empty values are replaced with "XXX" as they may contain
472+// secrets such as passwords or tokens, unless --dump auth is in use
473+// in which case the value is returned quoted.
474+func RedactValue(ci *ConfigInfo, value string) string {
475+if value == "" || ci.Dump&DumpAuth != 0 {
476+return fmt.Sprintf("%q", value)
477+ }
478+return "XXX"
479+}
480+481+// RedactOptionValue is like RedactValue except that value is only
482+// redacted if opt is unknown (nil), a password or sensitive.
483+func RedactOptionValue(ci *ConfigInfo, opt *Option, value string) string {
484+if opt == nil || opt.IsPassword || opt.Sensitive {
485+return RedactValue(ci, value)
486+ }
487+return fmt.Sprintf("%q", value)
488+}
489+490+// redactConfigOut renders out for the debug log, redacting any
491+// values which may contain secrets.
492+func redactConfigOut(ci *ConfigInfo, out *ConfigOut) string {
493+if out == nil {
494+return "<nil>"
495+ }
496+var b strings.Builder
497+fmt.Fprintf(&b, "{State:%q", out.State)
498+if out.Option != nil {
499+fmt.Fprintf(&b, " Option:%s=%s", out.Option.Name, RedactOptionValue(ci, out.Option, out.Option.String()))
500+ }
501+if out.OAuth != nil {
502+b.WriteString(" OAuth:set")
503+ }
504+if out.Error != "" {
505+fmt.Fprintf(&b, " Error:%q", out.Error)
506+ }
507+fmt.Fprintf(&b, " Result:%s}", RedactValue(ci, out.Result))
508+return b.String()
509+}
510+465511func backendConfigStep(ctx context.Context, name string, m configmap.Mapper, ri *RegInfo, choices configmap.Getter, in ConfigIn) (out *ConfigOut, err error) {
466512ci := GetConfig(ctx)
467-Debugf(name, "config in: state=%q, result=%q", in.State, in.Result)
513+if ci.Dump&DumpAuth != 0 {
514+redactDumpAuthWarnOnce.Do(func() {
515+Logf(nil, "--dump auth is in use - debug output may contain secrets such as passwords and tokens")
516+ })
517+ }
518+Debugf(name, "config in: state=%q, result=%s", in.State, RedactValue(ci, in.Result))
468519defer func() {
469-Debugf(name, "config out: out=%+v, err=%v", out, err)
520+Debugf(name, "config out: out=%s, err=%v", redactConfigOut(ci, out), err)
470521 }()
471522472523switch {
@@ -510,13 +561,13 @@ func backendConfigStep(ctx context.Context, name string, m configmap.Mapper, ri
510561 }
511562// If override value is set in the choices then use that
512563if result, ok := choices.Get(out.Option.Name); ok {
513-Debugf(nil, "Override value found, choosing value %q for state %q", result, out.State)
564+Debugf(nil, "Override value found, choosing value %s for state %q", RedactOptionValue(ci, out.Option, result), out.State)
514565return ConfigResult(out.State, result)
515566 }
516567// If AutoConfirm is set, choose the default value
517568if ci.AutoConfirm {
518569result := fmt.Sprint(out.Option.Default)
519-Debugf(nil, "Auto confirm is set, choosing default %q for state %q, override by setting config parameter %q", result, out.State, out.Option.Name)
570+Debugf(nil, "Auto confirm is set, choosing default %s for state %q, override by setting config parameter %q", RedactOptionValue(ci, out.Option, result), out.State, out.Option.Name)
520571return ConfigResult(out.State, result)
521572 }
522573// If fs.ConfigEdit is set then make the default value
@@ -527,7 +578,7 @@ func backendConfigStep(ctx context.Context, name string, m configmap.Mapper, ri
527578oldValue := newOption.Value
528579err = newOption.Set(value)
529580if err != nil {
530-Errorf(nil, "Failed to set %q from %q - using default: %v", out.Option.Name, value, err)
581+Errorf(nil, "Failed to set %q from %s - using default: %v", out.Option.Name, RedactOptionValue(ci, newOption, value), err)
531582 } else {
532583newOption.Default = newOption.Value
533584newOption.Value = oldValue