feat: restrict signup invite links to a specific email domain

This commit is contained in:
ItalyPaleAle
2026-07-16 06:44:59 -07:00
parent 525946e94e
commit fdfaac8a35
25 changed files with 442 additions and 35 deletions
+25
View File
@@ -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
}
+36
View File
@@ -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