Skip to content

Commit

Permalink
13 ppe hostedcom showing in provider (#21)
Browse files Browse the repository at this point in the history
* add ppe-hosted

* convert non-ascii to ascii

* fix test
  • Loading branch information
mattbr0wn authored Aug 17, 2024
1 parent 5c093a5 commit 485882a
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 22 deletions.
2 changes: 1 addition & 1 deletion bulkvalidate/bulkvalidate.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func RunBulkValidation(inputFilePath, outputFilePath string) {
if err != nil {
log.Printf("Error: %s %s", email, err.Error())
}
emailResults, err := mailvalidate.ValidateEmail(request)
emailResults, err := mailvalidate.ValidateEmail(request, syntaxResults)
if err != nil {
log.Printf("Error: %s %s", email, err.Error())
}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ require (
github.com/schollz/progressbar/v3 v3.14.6 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
2 changes: 1 addition & 1 deletion internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func VerifyEmail(email string) {
request := run.BuildRequest(email)
syntaxResults := VerifySyntax(email, false)
domainResults := VerifyDomain(syntaxResults.Domain, false)
emailResults, err := mailvalidate.ValidateEmail(request)
emailResults, err := mailvalidate.ValidateEmail(request, syntaxResults)
if err != nil {
fmt.Println(err)
}
Expand Down
1 change: 1 addition & 0 deletions internal/dns/known_email_providers.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ domains = [
["ondmarc.com", "ondmarc"],
["powerspf.com", "power spf"],
["pphosted.com", "proofpoint"],
["ppe-hosted.com", "proofpoint"],
["redpoints.com", "red points"],
["reflexion.net", "sophos"],
["res.cisco.com", "cisco"],
Expand Down
7 changes: 6 additions & 1 deletion internal/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,13 @@ func BuildResponse(emailAddress string, syntax mailvalidate.SyntaxValidation, do
Description: email.Description,
}

cleanEmail := emailAddress
if syntax.IsValid {
cleanEmail = fmt.Sprintf("%s@%s", syntax.User, syntax.Domain)
}

response := VerifyEmailResponse{
Email: emailAddress,
Email: cleanEmail,
IsDeliverable: email.IsDeliverable,
Provider: domain.Provider,
Firewall: domain.Firewall,
Expand Down
45 changes: 33 additions & 12 deletions internal/syntax/syntax.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,44 @@ package syntax
import (
"regexp"
"strings"
"unicode"

"golang.org/x/net/publicsuffix"
"golang.org/x/text/runes"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
)

var (
usernameRegex = regexp.MustCompile(`^[\p{L}\p{N}.!#$%&'+-/=?^_` + "`" + `{|}~]+$`)
domainRegex = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](?:\.[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])*$`)
)

func IsValidEmailSyntax(email string) bool {
func IsValidEmailSyntax(email string) (bool, string) {
normalizedEmail := convertToAscii(email)

if !isValidEmailFormat(email) {
return false
return false, ""
}

username, domain, ok := splitEmail(email)
if !ok {
return false
return false, ""
}

return isValidUsername(username) && isValidDomain(domain)
return isValidUsername(username) && isValidDomain(domain), normalizedEmail
}

func GetEmailUserAndDomain(email string) (string, string, bool) {
if strings.TrimSpace(email) != email {
return "", "", false
}
user, domain, ok := splitEmail(email)
if !isValidUsername(user) || !isValidDomain(domain) {
return "", "", false
}

return user, domain, ok
}

func isValidEmailFormat(email string) bool {
Expand Down Expand Up @@ -90,14 +108,17 @@ func isValidTLD(tld string) bool {
return icann
}

func GetEmailUserAndDomain(email string) (string, string, bool) {
if strings.TrimSpace(email) != email {
return "", "", false
}
user, domain, ok := splitEmail(email)
if !isValidUsername(user) || !isValidDomain(domain) {
return "", "", false
func convertToAscii(input string) string {
t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
result, _, _ := transform.String(t, input)

// Step 2: Remove any remaining non-ASCII characters
ascii := make([]rune, 0, len(result))
for _, r := range result {
if r <= unicode.MaxASCII {
ascii = append(ascii, r)
}
}

return user, domain, ok
return string(ascii)
}
2 changes: 1 addition & 1 deletion internal/syntax/syntax_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestIsValidEmailSyntax(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsValidEmailSyntax(tt.email); got != tt.want {
if got, _ := IsValidEmailSyntax(tt.email); got != tt.want {
t.Errorf("IsValidEmailSyntax(%q) = %v, want %v", tt.email, got, tt.want)
}
})
Expand Down
17 changes: 11 additions & 6 deletions mailvalidate/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ type SyntaxValidation struct {

func ValidateEmailSyntax(email string) SyntaxValidation {
var results SyntaxValidation
ok := syntax.IsValidEmailSyntax(email)
ok, cleanEmail := syntax.IsValidEmailSyntax(email)
if !ok {
return results
}

user, domain, ok := syntax.GetEmailUserAndDomain(email)
user, domain, ok := syntax.GetEmailUserAndDomain(cleanEmail)
if !ok {
return results
}
Expand Down Expand Up @@ -121,11 +121,14 @@ func ValidateDomainWithCustomKnownProviders(validationRequest EmailValidationReq
return results, nil
}

func ValidateEmail(validationRequest EmailValidationRequest) (EmailValidation, error) {
func ValidateEmail(validationRequest EmailValidationRequest, emailSyntaxResults SyntaxValidation) (EmailValidation, error) {
var results EmailValidation
if err := validateRequest(&validationRequest); err != nil {
return results, errors.Wrap(err, "Invalid request")
}
if !emailSyntaxResults.IsValid {
return results, fmt.Errorf("Invalid email address")
}

freeEmails, err := GetFreeEmailList()
if err != nil {
Expand All @@ -137,20 +140,22 @@ func ValidateEmail(validationRequest EmailValidationRequest) (EmailValidation, e
log.Fatal(err)
}

isFreeEmail, err := IsFreeEmailCheck(validationRequest.Email, freeEmails)
email := fmt.Sprintf("%s@%s", emailSyntaxResults.User, emailSyntaxResults.Domain)

isFreeEmail, err := IsFreeEmailCheck(email, freeEmails)
if err != nil {
return results, errors.Wrap(err, "Error executing free email check")
}
results.IsFreeAccount = isFreeEmail

isRoleAccount, err := IsRoleAccountCheck(validationRequest.Email, roleAccounts)
isRoleAccount, err := IsRoleAccountCheck(email, roleAccounts)
if err != nil {
return results, errors.Wrap(err, "Error executing role account check")
}
results.IsRoleAccount = isRoleAccount

isVerified, smtpValidation, err := mailserver.VerifyEmailAddress(
validationRequest.Email,
email,
validationRequest.FromDomain,
validationRequest.FromEmail,
validationRequest.Dns,
Expand Down

0 comments on commit 485882a

Please sign in to comment.