aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/email
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-07-05 19:45:56 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-07-05 19:45:56 +0200
commit6fe1bcf384a34fdfc1704ff98ee5151a75d031a2 (patch)
treeec0fc9cc5a17cdafacd6a04bb599865a2d959dbe /pkg/email
parent6231964849eb9362c20b82279d92da96fb556209 (diff)
pkg/email: add AddAddrContext/RemoveAddrContext
Replace extractBugID function with more general AddAddrContext/RemoveAddrContext.
Diffstat (limited to 'pkg/email')
-rw-r--r--pkg/email/parser.go69
-rw-r--r--pkg/email/parser_test.go81
2 files changed, 88 insertions, 62 deletions
diff --git a/pkg/email/parser.go b/pkg/email/parser.go
index 5d8c54d2c..f0297a588 100644
--- a/pkg/email/parser.go
+++ b/pkg/email/parser.go
@@ -50,11 +50,12 @@ func Parse(r io.Reader, ownEmail string) (*Email, error) {
bugID := ""
var ccList []string
for _, addr := range append(cc, to...) {
- bugID1, own := extractBugID(addr.Address, ownEmail)
- if bugID == "" {
- bugID = bugID1
- }
- if !own {
+ cleaned, context, _ := RemoveAddrContext(addr.Address)
+ if cleaned == ownEmail {
+ if bugID == "" {
+ bugID = context
+ }
+ } else {
ccList = append(ccList, addr.String())
}
}
@@ -87,31 +88,39 @@ func Parse(r io.Reader, ownEmail string) (*Email, error) {
return email, nil
}
-// extractBugID extracts bug ID encoded in receiver email.
-// We send emails from <something+BUG_ID_HASH@something.com>.
-// from is potentially such email address, canonical is <something@something.com>.
-// This function returns BUG_ID_HASH, or an empty string if from does not contain
-// the hash or is different from canonical.
-func extractBugID(from, canonical string) (string, bool) {
- if email, err := mail.ParseAddress(canonical); err == nil {
- canonical = email.Address
- }
- canonical = strings.ToLower(canonical)
- plusPos := strings.IndexByte(from, '+')
- if plusPos == -1 {
- return "", strings.ToLower(from) == canonical
- }
- atPos := strings.IndexByte(from[plusPos:], '@')
- if atPos == -1 {
- return "", false
- }
- user := from[:plusPos]
- domain := from[plusPos+atPos:]
- hash := from[plusPos+1 : plusPos+atPos]
- if strings.ToLower(user+domain) != canonical {
- return "", false
- }
- return hash, true
+// AddAddrContext embeds context into local part of the provided email address using '+'.
+// Returns the resulting email address.
+func AddAddrContext(email, context string) (string, error) {
+ addr, err := mail.ParseAddress(email)
+ if err != nil {
+ return "", fmt.Errorf("failed to parse %q as email: %v", email, err)
+ }
+ at := strings.IndexByte(addr.Address, '@')
+ if at == -1 {
+ return "", fmt.Errorf("failed to parse %q as email: no @", email)
+ }
+ addr.Address = addr.Address[:at] + "+" + context + addr.Address[at:]
+ return addr.String(), nil
+}
+
+// RemoveAddrContext extracts context after '+' from the local part of the provided email address.
+// Returns address without the context and the context.
+func RemoveAddrContext(email string) (string, string, error) {
+ addr, err := mail.ParseAddress(email)
+ if err != nil {
+ return "", "", fmt.Errorf("failed to parse %q as email: %v", email, err)
+ }
+ at := strings.IndexByte(addr.Address, '@')
+ if at == -1 {
+ return "", "", fmt.Errorf("failed to parse %q as email: no @", email)
+ }
+ plus := strings.LastIndexByte(addr.Address[:at], '+')
+ if plus == -1 {
+ return email, "", nil
+ }
+ context := addr.Address[plus+1 : at]
+ addr.Address = addr.Address[:plus] + addr.Address[at:]
+ return addr.String(), context, nil
}
// extractCommand extracts command to syzbot from email body.
diff --git a/pkg/email/parser_test.go b/pkg/email/parser_test.go
index 7b2aa9a0f..d05a597be 100644
--- a/pkg/email/parser_test.go
+++ b/pkg/email/parser_test.go
@@ -23,16 +23,55 @@ func TestExtractCommand(t *testing.T) {
}
}
-func TestExtractBugID(t *testing.T) {
- for i, test := range extractBugIDTests {
- t.Run(fmt.Sprint(i), func(t *testing.T) {
- bugID, own := extractBugID(test.email, `"Foo Bar" <foo@bar.com>`)
- if bugID != test.bugID || own != test.own {
- t.Logf("expect: own=%v %q", test.own, test.bugID)
- t.Logf("got : own=%v %q", test.own, bugID)
- t.Fail()
- }
- })
+func TestAddRemoveAddrContext(t *testing.T) {
+ email := `"Foo Bar" <foo@bar.com>`
+ email00, context00, err := RemoveAddrContext(email)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if email != email00 {
+ t.Fatalf("want: %q, got %q", email, email00)
+ }
+ if context00 != "" {
+ t.Fatalf("want context: %q, got %q", "", context00)
+ }
+ context1 := "context1"
+ email1, err := AddAddrContext(email, context1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want1 := `"Foo Bar" <foo+context1@bar.com>`
+ if want1 != email1 {
+ t.Fatalf("want: %q, got %q", want1, email1)
+ }
+ context2 := "context2"
+ email2, err := AddAddrContext(email1, context2)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want2 := `"Foo Bar" <foo+context1+context2@bar.com>`
+ if want2 != email2 {
+ t.Fatalf("want: %q, got %q", want2, email2)
+ }
+ email1, context20, err := RemoveAddrContext(email2)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if want1 != email1 {
+ t.Fatalf("want: %q, got %q", want1, email1)
+ }
+ if context2 != context20 {
+ t.Fatalf("want context: %q, got %q", context2, context20)
+ }
+ email0, context10, err := RemoveAddrContext(email1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if email != email0 {
+ t.Fatalf("want: %q, got %q", email, email0)
+ }
+ if context1 != context10 {
+ t.Fatalf("want context: %q, got %q", context1, context10)
}
}
@@ -86,28 +125,6 @@ line 2
},
}
-var extractBugIDTests = []struct {
- email string
- bugID string
- own bool
-}{
- {
- `foo@bar.com`,
- ``,
- true,
- },
- {
- `foo+123@baz.com`,
- ``,
- false,
- },
- {
- `foo+123@bar.com`,
- `123`,
- true,
- },
-}
-
var parseTests = []struct {
email string
res *Email