mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-04 08:49:03 +02:00
feat: restrict signup invite links to a specific email domain
This commit is contained in:
@@ -21,6 +21,9 @@ var validateUsernameRegex = regexp.MustCompile("^[a-zA-Z0-9]([a-zA-Z0-9_.@-]*[a-
|
||||
|
||||
var validateClientIDRegex = regexp.MustCompile("^[a-zA-Z0-9._-]+$")
|
||||
|
||||
// emailDomainRegex validates the domain part of an email address (e.g. "example.com" or "mail.example.co.uk")
|
||||
var emailDomainRegex = regexp.MustCompile(`^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$`)
|
||||
|
||||
func init() {
|
||||
engine := binding.Validator.Engine().(*validator.Validate)
|
||||
|
||||
@@ -34,6 +37,9 @@ func init() {
|
||||
"client_id": func(fl validator.FieldLevel) bool {
|
||||
return ValidateClientID(fl.Field().String())
|
||||
},
|
||||
"email_domain": func(fl validator.FieldLevel) bool {
|
||||
return ValidateEmailDomain(fl.Field().String())
|
||||
},
|
||||
"ttl": func(fl validator.FieldLevel) bool {
|
||||
ttl, ok := fl.Field().Interface().(utils.JSONDuration)
|
||||
if !ok {
|
||||
@@ -106,3 +112,22 @@ func ValidateCallbackURL(str string) bool {
|
||||
func ValidateCallbackURLPattern(raw string) bool {
|
||||
return utils.ValidateCallbackURLPattern(raw) == nil
|
||||
}
|
||||
|
||||
// ValidateEmailDomain validates an optional email domain.
|
||||
// It accepts inputs with or without a leading "@"
|
||||
func ValidateEmailDomain(domain string) bool {
|
||||
if domain == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
domain = strings.TrimPrefix(strings.ToLower(domain), "@")
|
||||
if domain == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !emailDomainRegex.MatchString(domain) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -112,6 +112,42 @@ func TestValidateCallbackURL(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateEmailDomain(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected bool
|
||||
}{
|
||||
{"valid simple", "example.com", true},
|
||||
{"valid with leading at", "@example.com", true},
|
||||
{"valid subdomain", "mail.example.co.uk", true},
|
||||
{"valid uppercase", "EXAMPLE.COM", true},
|
||||
{"valid with at and uppercase", "@Example.Com", true},
|
||||
{"valid with hyphen", "my-domain.com", true},
|
||||
{"valid with digits", "example123.com", true},
|
||||
{"valid single char label", "a.com", true},
|
||||
{"empty", "", false},
|
||||
{"only at", "@", false},
|
||||
{"no tld", "example", false},
|
||||
{"tld too short", "example.c", false},
|
||||
{"trailing dot", "example.com.", false},
|
||||
{"leading dot", ".example.com", false},
|
||||
{"double dot", "example..com", false},
|
||||
{"label starts with hyphen", "-example.com", false},
|
||||
{"label ends with hyphen", "example-.com", false},
|
||||
{"numeric tld", "example.123", false},
|
||||
{"contains space", "exa mple.com", false},
|
||||
{"double at", "@@example.com", false},
|
||||
{"trailing space", "example.com ", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.expected, ValidateEmailDomain(tt.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCallbackURLPattern(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user