MF-798 - Add utf8 support for email validation (#1082)
* Add utf8 support for email validation Signed-off-by: Vadim Filin <phil192@yandex.ru> * Fix review comments Signed-off-by: Vadim Filin <phil192@yandex.ru> * Refactor Signed-off-by: Vadim Filin <phil192@yandex.ru> Co-authored-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com>
This commit is contained in:
parent
a2d70c8907
commit
b8818c4dd2
|
@ -9,9 +9,18 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/mainflux/mainflux/errors"
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
const minPassLen = 8
|
||||
const (
|
||||
minPassLen = 8
|
||||
maxLocalLen = 64
|
||||
maxDomainLen = 255
|
||||
maxTLDLen = 24 // longest TLD currently in existence
|
||||
|
||||
atSeparator = "@"
|
||||
dotSeparator = "."
|
||||
)
|
||||
|
||||
var (
|
||||
userRegexp = regexp.MustCompile("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$")
|
||||
|
@ -57,23 +66,43 @@ type UserRepository interface {
|
|||
}
|
||||
|
||||
func isEmail(email string) bool {
|
||||
if len(email) < 6 || len(email) > 254 {
|
||||
if email == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
at := strings.LastIndex(email, "@")
|
||||
if at <= 0 || at > len(email)-3 {
|
||||
es := strings.Split(email, atSeparator)
|
||||
if len(es) != 2 {
|
||||
return false
|
||||
}
|
||||
local, host := es[0], es[1]
|
||||
|
||||
if local == "" || len(local) > maxLocalLen {
|
||||
return false
|
||||
}
|
||||
|
||||
user := email[:at]
|
||||
host := email[at+1:]
|
||||
hs := strings.Split(host, dotSeparator)
|
||||
if len(hs) != 2 {
|
||||
return false
|
||||
}
|
||||
domain, ext := hs[0], hs[1]
|
||||
|
||||
if len(user) > 64 {
|
||||
if domain == "" || len(domain) > maxDomainLen {
|
||||
return false
|
||||
}
|
||||
if ext == "" || len(ext) > maxTLDLen {
|
||||
return false
|
||||
}
|
||||
|
||||
if userDotRegexp.MatchString(user) || !userRegexp.MatchString(user) || !hostRegexp.MatchString(host) {
|
||||
punyLocal, err := idna.ToASCII(local)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
punyHost, err := idna.ToASCII(host)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if userDotRegexp.MatchString(punyLocal) || !userRegexp.MatchString(punyLocal) || !hostRegexp.MatchString(punyHost) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ package users_test
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/mainflux/mainflux/errors"
|
||||
|
@ -16,8 +17,22 @@ const (
|
|||
email = "user@example.com"
|
||||
password = "password"
|
||||
metadata = `{"role":"manager"}`
|
||||
|
||||
maxLocalLen = 64
|
||||
maxDomainLen = 255
|
||||
maxTLDLen = 24
|
||||
)
|
||||
|
||||
var letters = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
func randomString(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
user users.User
|
||||
|
@ -51,6 +66,62 @@ func TestValidate(t *testing.T) {
|
|||
},
|
||||
err: users.ErrMalformedEntity,
|
||||
},
|
||||
"validate user with utf8 email (cyrillic)": {
|
||||
user: users.User{
|
||||
Email: "почта@кино-россия.рф",
|
||||
Password: password,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
"validate user with utf8 email (hieroglyph)": {
|
||||
user: users.User{
|
||||
Email: "艾付忧西开@艾付忧西开.再得",
|
||||
Password: password,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
"validate user with no email tld": {
|
||||
user: users.User{
|
||||
Email: "user@example.",
|
||||
Password: password,
|
||||
},
|
||||
err: users.ErrMalformedEntity,
|
||||
},
|
||||
"validate user with too long email tld": {
|
||||
user: users.User{
|
||||
Email: "user@example." + randomString(maxTLDLen+1),
|
||||
Password: password,
|
||||
},
|
||||
err: users.ErrMalformedEntity,
|
||||
},
|
||||
"validate user with no email domain": {
|
||||
user: users.User{
|
||||
Email: "user@.com",
|
||||
Password: password,
|
||||
},
|
||||
err: users.ErrMalformedEntity,
|
||||
},
|
||||
"validate user with too long email domain": {
|
||||
user: users.User{
|
||||
Email: "user@" + randomString(maxDomainLen+1) + ".com",
|
||||
Password: password,
|
||||
},
|
||||
err: users.ErrMalformedEntity,
|
||||
},
|
||||
"validate user with no email local": {
|
||||
user: users.User{
|
||||
Email: "@example.com",
|
||||
Password: password,
|
||||
},
|
||||
err: users.ErrMalformedEntity,
|
||||
},
|
||||
"validate user with too long email local": {
|
||||
user: users.User{
|
||||
Email: randomString(maxLocalLen+1) + "@example.com",
|
||||
Password: password,
|
||||
},
|
||||
err: users.ErrMalformedEntity,
|
||||
},
|
||||
}
|
||||
|
||||
for desc, tc := range cases {
|
||||
|
|
Loading…
Reference in New Issue