Skip to content

Commit

Permalink
Merge pull request #6 from viafintech/feature/extend-email-options
Browse files Browse the repository at this point in the history
Extend email anonymizer to allow anonymizing domains
  • Loading branch information
martinseener authored Jul 7, 2023
2 parents 322c7db + 4a3a49e commit 1c483c0
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 17 deletions.
59 changes: 49 additions & 10 deletions postgres/email_anonymizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,41 @@ import (
//
// would be anonymized by a 15 character string based on the md5 hash of the local part.
type EmailAnonymizer struct {
mailLocalPartLength int
mailAnonymizedPartLength int
mailAnonymizeDomainPart bool
}

// EmailAnonymizerOption is the function type for passing options
// to the EmailAnonymizer during initialization.
type EmailAnonymizerOption func(*EmailAnonymizer)

// EmailAnonymizedPartLengthOption allows setting the target length for the local part
// of the anonymization rule
func EmailAnonymizedPartLengthOption(length int) EmailAnonymizerOption {
return func(anonymizer *EmailAnonymizer) {
anonymizer.mailAnonymizedPartLength = length
}
}

// EmailAnonymizeDomainPartOption allows configuring whether the domain part should
// also explicitly be anonymized
func EmailAnonymizeDomainPartOption(anonymizeDomainPart bool) EmailAnonymizerOption {
return func(anonymizer *EmailAnonymizer) {
anonymizer.mailAnonymizeDomainPart = anonymizeDomainPart
}
}

// NewEmailAnonymizer initializes a new EmailAnonymizer object
func NewEmailAnonymizer() *EmailAnonymizer {
return &EmailAnonymizer{
mailLocalPartLength: 15,
func NewEmailAnonymizer(options ...EmailAnonymizerOption) *EmailAnonymizer {
anonymizer := &EmailAnonymizer{
mailAnonymizedPartLength: 15,
}

for _, option := range options {
option(anonymizer)
}

return anonymizer
}

// Build returns the partial query holding the logic to overwrite
Expand All @@ -38,16 +65,28 @@ func (a *EmailAnonymizer) Build(tableName, columnName string) string {
) ||
'@'::text
) ||
split_part(
(%[1]s)::text,
'@'::text,
2
)
%[3]s
)
)::CHARACTER VARYING
ELSE %[1]s
END`,
gotidus.FullColumnName(tableName, columnName),
a.mailLocalPartLength,
a.mailAnonymizedPartLength,
a.domainPart(tableName, columnName),
)
}

func (a *EmailAnonymizer) domainPart(tableName, columnName string) string {
if a.mailAnonymizeDomainPart {
return fmt.Sprintf(
`("left"(md5(split_part((%[1]s)::text, '@'::text, 2)::text), %[2]d) || '.com')`,
gotidus.FullColumnName(tableName, columnName),
a.mailAnonymizedPartLength,
)
}

return fmt.Sprintf(
`split_part((%s)::text, '@'::text, 2)`,
gotidus.FullColumnName(tableName, columnName),
)
}
56 changes: 49 additions & 7 deletions postgres/email_anonymizer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ func TestEmailAnonymizerBuild(t *testing.T) {
columnName := "bar"

cases := []struct {
title string
title string
options []EmailAnonymizerOption

expectedString string
}{
Expand All @@ -28,11 +29,52 @@ func TestEmailAnonymizerBuild(t *testing.T) {
) ||
'@'::text
) ||
split_part(
(foo.bar)::text,
'@'::text,
2
)
split_part((foo.bar)::text, '@'::text, 2)
)
)::CHARACTER VARYING
ELSE foo.bar
END`,
},
{
title: "email overlay with different length",
options: []EmailAnonymizerOption{
EmailAnonymizedPartLengthOption(10),
},

expectedString: `CASE WHEN ((foo.bar)::TEXT ~~ '%@%'::TEXT)
THEN (
(
(
"left"(
md5((foo.bar)::text),
10
) ||
'@'::text
) ||
split_part((foo.bar)::text, '@'::text, 2)
)
)::CHARACTER VARYING
ELSE foo.bar
END`,
},
{
title: "email overlay with anonymized domain part length",
options: []EmailAnonymizerOption{
EmailAnonymizedPartLengthOption(10),
EmailAnonymizeDomainPartOption(true),
},

expectedString: `CASE WHEN ((foo.bar)::TEXT ~~ '%@%'::TEXT)
THEN (
(
(
"left"(
md5((foo.bar)::text),
10
) ||
'@'::text
) ||
("left"(md5(split_part((foo.bar)::text, '@'::text, 2)::text), 10) || '.com')
)
)::CHARACTER VARYING
ELSE foo.bar
Expand All @@ -43,7 +85,7 @@ func TestEmailAnonymizerBuild(t *testing.T) {
for _, c := range cases {
t.Run(c.title, func(t *testing.T) {

anonymizer := NewEmailAnonymizer()
anonymizer := NewEmailAnonymizer(c.options...)

testutils.CompareStrings(
anonymizer.Build(tableName, columnName),
Expand Down

0 comments on commit 1c483c0

Please sign in to comment.