github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/emails/utils.go (about) 1 package emails 2 3 import ( 4 "context" 5 "net/mail" 6 "strings" 7 8 "github.com/keybase/client/go/externals" 9 "github.com/keybase/client/go/libkb" 10 ) 11 12 // splitBulk splits on newline or comma. 13 func splitBulk(s string) []string { 14 f := func(c rune) bool { 15 return c == '\n' || c == ',' 16 } 17 split := strings.FieldsFunc(s, f) 18 for i, s := range split { 19 split[i] = strings.TrimSpace(s) 20 } 21 return split 22 } 23 24 // ParseSeparatedEmails parses a comma-or-new-line-separated email list that 25 // comes in a string. It can extract emails that conform to RFC 5322 and RFC 26 // 6532 (see net/mail documentation for more info). 27 // 28 // Examples of a valid e-mail entities would be: 29 // - Jan Smith <jan@example.com> 30 // - alice@example.org 31 // 32 // The "name" portion is ignored, caller will always get the raw e-mails, in 33 // this case: { "jan@example.com", "alice@example.org" }. 34 // 35 // Individual e-mails have to be separated by comma or newline, and they can be 36 // surrounded by any amount of whitespace characters that will be ignored. 37 // 38 // `malformed` is an optional pointer to string list to which this function can 39 // append malformed e-mails for the caller. It can be nil. 40 func ParseSeparatedEmails(mctx libkb.MetaContext, emails string, malformed *[]string) (ret []string) { 41 emailList := splitBulk(emails) 42 mctx.Debug("ParseSeparatedEmails: bulk email invite count: %d", len(emailList)) 43 for _, email := range emailList { 44 addr, parseErr := mail.ParseAddress(email) 45 if parseErr != nil { 46 mctx.Debug("ParseSeparatedEmails: skipping malformed email %q: %s", email, parseErr) 47 if malformed != nil { 48 *malformed = append(*malformed, email) 49 } 50 continue 51 } 52 53 // API server side of this only accepts x.yy domain name: 54 parts := strings.Split(addr.Address, ".") 55 if len(parts[len(parts)-1]) < 2 { 56 mctx.Debug("ParseSeparatedEmails: skipping malformed email (domain) %q", email) 57 if malformed != nil { 58 *malformed = append(*malformed, email) 59 } 60 continue 61 } 62 63 ret = append(ret, addr.Address) 64 } 65 return ret 66 } 67 68 // CreateAssertionFromEmail creates AssertionURL from an e-mail address. E-mail 69 // address is not validated apart from the minimal validation that assertion 70 // code does, so pretty much anything that has '@' in it will pass. 71 func CreateAssertionFromEmail(ctx context.Context, email string) (libkb.AssertionURL, error) { 72 actx := externals.MakeStaticAssertionContext(ctx) 73 // `strict` argument here doesn't actually do anything for "email" assertions. 74 return libkb.ParseAssertionURLKeyValue(actx, "email", email, false /* strict */) 75 }