Skip to content

Commit

Permalink
feat(pp): WIP: log redaction
Browse files Browse the repository at this point in the history
  • Loading branch information
favonia committed Jul 6, 2024
1 parent d724a60 commit 39a7a62
Show file tree
Hide file tree
Showing 13 changed files with 255 additions and 85 deletions.
2 changes: 1 addition & 1 deletion cmd/ddns/ddns.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func main() {

func realMain() int { //nolint:funlen
ppfmt := pp.New(os.Stdout)
if !config.ReadEmoji("EMOJI", &ppfmt) || !config.ReadQuiet("QUIET", &ppfmt) {
if !config.InitializePP(&ppfmt) {
ppfmt.Infof(pp.EmojiUserError, "Bye!")
return 1
}
Expand Down
21 changes: 16 additions & 5 deletions internal/config/config_print.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,19 @@ func (c *Config) Print(ppfmt pp.PP) {

section("Domains and IP providers:")
if c.Provider[ipnet.IP4] != nil {
item("IPv4 domains:", "%s", describeDomains(c.Domains[ipnet.IP4]))
if ppfmt.ShouldRedact(pp.PrivateDataTypeDomains) {
item("IPv4 domains:", "(redacted)")
} else {
item("IPv4 domains:", "%s", describeDomains(c.Domains[ipnet.IP4]))
}
item("IPv4 provider:", "%s", provider.Name(c.Provider[ipnet.IP4]))
}
if c.Provider[ipnet.IP6] != nil {
item("IPv6 domains:", "%s", describeDomains(c.Domains[ipnet.IP6]))
if ppfmt.ShouldRedact(pp.PrivateDataTypeDomains) {
item("IPv6 domains:", "(redacted)")
} else {
item("IPv6 domains:", "%s", describeDomains(c.Domains[ipnet.IP6]))
}
item("IPv6 provider:", "%s", provider.Name(c.Provider[ipnet.IP6]))
}

Expand All @@ -85,9 +93,12 @@ func (c *Config) Print(ppfmt pp.PP) {
item("Delete on stop?", "%t", c.DeleteOnStop)
item("Cache expiration:", "%v", c.CacheExpiration)

section("New DNS records:")
section("Parameters of new DNS records:")
item("TTL:", "%s", c.TTL.Describe())
{
if ppfmt.ShouldRedact(pp.PrivateDataTypeDomains) {
item("Proxied domains:", "(redacted)")
item("Unproxied domains:", "(redacted)")
} else {
_, inverseMap := getInverseMap(c.Proxied)
item("Proxied domains:", "%s", describeDomains(inverseMap[true]))
item("Unproxied domains:", "%s", describeDomains(inverseMap[false]))
Expand All @@ -106,7 +117,7 @@ func (c *Config) Print(ppfmt pp.PP) {
}

if len(c.Notifiers) > 0 {
section("Notifiers (via shoutrrr):")
section("Notification services (via shoutrrr):")
notifier.DescribeAll(func(service, params string) {
item(service+":", "%s", params)
}, c.Notifiers)
Expand Down
15 changes: 11 additions & 4 deletions internal/config/config_print_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ func TestPrintDefault(t *testing.T) {
mockPP.EXPECT().IncIndent().Return(mockPP),
mockPP.EXPECT().IncIndent().Return(innerMockPP),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Domains and IP providers:"),
mockPP.EXPECT().ShouldRedact(pp.PrivateDataTypeDomains).Return(false),
printItem(innerMockPP, "IPv4 domains:", "(none)"),
printItem(innerMockPP, "IPv4 provider:", "cloudflare.trace"),
mockPP.EXPECT().ShouldRedact(pp.PrivateDataTypeDomains).Return(false),
printItem(innerMockPP, "IPv6 domains:", "(none)"),
printItem(innerMockPP, "IPv6 provider:", "cloudflare.trace"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Scheduling:"),
Expand All @@ -42,8 +44,9 @@ func TestPrintDefault(t *testing.T) {
printItem(innerMockPP, "Update on start?", "true"),
printItem(innerMockPP, "Delete on stop?", "false"),
printItem(innerMockPP, "Cache expiration:", "6h0m0s"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "New DNS records:"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Parameters of new DNS records:"),
printItem(innerMockPP, "TTL:", "1 (auto)"),
mockPP.EXPECT().ShouldRedact(pp.PrivateDataTypeDomains).Return(false),
printItem(innerMockPP, "Proxied domains:", "(none)"),
printItem(innerMockPP, "Unproxied domains:", "(none)"),
printItem(innerMockPP, "Record comment:", "(empty)"),
Expand All @@ -68,8 +71,10 @@ func TestPrintValues(t *testing.T) {
mockPP.EXPECT().IncIndent().Return(mockPP),
mockPP.EXPECT().IncIndent().Return(innerMockPP),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Domains and IP providers:"),
mockPP.EXPECT().ShouldRedact(pp.PrivateDataTypeDomains).Return(false),
printItem(innerMockPP, "IPv4 domains:", "test4.org, *.test4.org"),
printItem(innerMockPP, "IPv4 provider:", "cloudflare.trace"),
mockPP.EXPECT().ShouldRedact(pp.PrivateDataTypeDomains).Return(false),
printItem(innerMockPP, "IPv6 domains:", "test6.org, *.test6.org"),
printItem(innerMockPP, "IPv6 provider:", "cloudflare.trace"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Scheduling:"),
Expand All @@ -78,8 +83,9 @@ func TestPrintValues(t *testing.T) {
printItem(innerMockPP, "Update on start?", "true"),
printItem(innerMockPP, "Delete on stop?", "false"),
printItem(innerMockPP, "Cache expiration:", "6h0m0s"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "New DNS records:"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Parameters of new DNS records:"),
printItem(innerMockPP, "TTL:", "30000"),
mockPP.EXPECT().ShouldRedact(pp.PrivateDataTypeDomains).Return(false),
printItem(innerMockPP, "Proxied domains:", "a, b"),
printItem(innerMockPP, "Unproxied domains:", "c, d"),
printItem(innerMockPP, "Record comment:", "\"Created by Cloudflare DDNS\""),
Expand All @@ -88,7 +94,7 @@ func TestPrintValues(t *testing.T) {
printItem(innerMockPP, "Record updating:", "30s"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Monitors:"),
printItem(innerMockPP, "Meow:", "purrrr"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Notifiers (via shoutrrr):"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Notification services (via shoutrrr):"),
printItem(innerMockPP, "Snake:", "hissss"),
)

Expand Down Expand Up @@ -144,8 +150,9 @@ func TestPrintEmpty(t *testing.T) {
printItem(innerMockPP, "Update on start?", "false"),
printItem(innerMockPP, "Delete on stop?", "false"),
printItem(innerMockPP, "Cache expiration:", "0s"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "New DNS records:"),
mockPP.EXPECT().Infof(pp.EmojiConfig, "Parameters of new DNS records:"),
printItem(innerMockPP, "TTL:", "0"),
mockPP.EXPECT().ShouldRedact(pp.PrivateDataTypeDomains).Return(false),
printItem(innerMockPP, "Proxied domains:", "(none)"),
printItem(innerMockPP, "Unproxied domains:", "(none)"),
printItem(innerMockPP, "Record comment:", "(empty)"),
Expand Down
4 changes: 4 additions & 0 deletions internal/config/config_read.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"github.com/favonia/cloudflare-ddns/internal/provider"
)

func InitializePP(ppfmt *pp.PP) bool {
return ReadEmoji("EMOJI", ppfmt) && ReadQuiet("QUIET", ppfmt) && ReadRedaction("LOG_REDACTION", ppfmt)
}

// ReadEnv calls the relevant readers to read all relevant environment variables except TZ
// and update relevant fields. One should subsequently call [Config.NormalizeConfig]
// to maintain invariants across different fields.
Expand Down
27 changes: 25 additions & 2 deletions internal/config/env_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,37 @@ func ReadQuiet(key string, ppfmt *pp.PP) bool {
}

if quiet {
*ppfmt = (*ppfmt).SetLevel(pp.Quiet)
*ppfmt = (*ppfmt).SetVerbosity(pp.Quiet)
} else {
*ppfmt = (*ppfmt).SetLevel(pp.Verbose)
*ppfmt = (*ppfmt).SetVerbosity(pp.Verbose)
}

return true
}

// ReadRedaction reads an environment variable as the redaction mask.
func ReadRedaction(key string, ppfmt *pp.PP) bool {
valRedaction := Getenv(key)
if valRedaction == "" {
return true
}

switch valRedaction {
case "min":
*ppfmt = (*ppfmt).SetRedactMask(pp.RedactNone)
return true
case "token":
*ppfmt = (*ppfmt).SetRedactMask(pp.RedactTokens)
return true
case "max":
*ppfmt = (*ppfmt).SetRedactMask(pp.RedactMaximum)
return true
default:
(*ppfmt).Errorf(pp.EmojiUserError, "%s (%q) is not a supported redaction mode", key, valRedaction)
return false
}
}

// ReadBool reads an environment variable as a boolean value.
func ReadBool(ppfmt pp.PP, key string, field *bool) bool {
val := Getenv(key)
Expand Down
4 changes: 2 additions & 2 deletions internal/config/env_base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,13 @@ func TestReadQuiet(t *testing.T) {
"true": {
true, " true", true,
func(m *mocks.MockPP) {
m.EXPECT().SetLevel(pp.Notice)
m.EXPECT().SetVerbosity(pp.Notice)
},
},
"false": {
true, " false ", true,
func(m *mocks.MockPP) {
m.EXPECT().SetLevel(pp.Info)
m.EXPECT().SetVerbosity(pp.Info)
},
},
"illform": {
Expand Down
106 changes: 91 additions & 15 deletions internal/mocks/mock_pp.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions internal/pp/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@ type PP interface {
// SetEmoji sets whether emojis should be used.
SetEmoji(emoji bool) PP

// SetLevel sets the level under which messages will be hidden.
SetLevel(level Level) PP
// SetVerbosity sets the level under which messages will be hidden.
SetVerbosity(v Verbosity) PP

// IsEnabledFor checks whether a message of a certain level will be displayed.
IsEnabledFor(level Level) bool
IsEnabledFor(v Verbosity) bool

// SetRedactMask sets the mask to determine the redaction.
SetRedactMask(m RedactMask) PP

// ShouldRedact(t) returns whether data of type t should be redacted.
ShouldRedact(t PrivateDataType) bool

// IncIndent returns a new pretty-printer with more indentation.
IncIndent() PP
Expand Down
Loading

0 comments on commit 39a7a62

Please sign in to comment.