-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathemail_rules.go
More file actions
117 lines (98 loc) · 2.81 KB
/
Copy pathemail_rules.go
File metadata and controls
117 lines (98 loc) · 2.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package sval
import (
"regexp"
"slices"
"strings"
)
type EmailRuleName = string
const (
EmailRuleNameStrategy EmailRuleName = "strategy"
EmailRuleNameMinDomainLen EmailRuleName = "min_domain_len"
EmailRuleNameExcludedDomains EmailRuleName = "excluded_domains"
EmailRuleNameAllowedDomains EmailRuleName = "allowed_domains"
EmailRuleNameRegexp EmailRuleName = "regex"
)
var (
// TODO: remove global regex, use compiled regex in rules
emailRegexp *regexp.Regexp
)
type EmailRules struct {
BaseRules
Strategy string `json:"strategy" yaml:"strategy"`
MinDomainLen int `json:"min_domain_len" yaml:"min_domain_len"`
ExcludedDomains []string `json:"excluded_domains" yaml:"excluded_domains"`
AllowedDomains []string `json:"allowed_domains" yaml:"allowed_domains"`
Regex *string `json:"regex,omitempty" yaml:"regex,omitempty"`
// TODO: add compiled regex for performance
}
func (r *EmailRules) Validate(i any) error {
err := NewValidationError()
if i == nil {
if r.Required {
err.AddError(BaseRuleNameRequired, r.Required, i, FieldIsRequired)
return err
}
return nil
}
if ptr, ok := i.(*string); ok {
if ptr == nil {
if r.Required {
err.AddError(BaseRuleNameRequired, r.Required, i, FieldIsRequired)
return err
}
return nil
}
i = *ptr
}
val, ok := i.(string)
if !ok {
err.AddError(BaseRuleNameType, TypeEmail, i, "value must be a string")
return err
}
if val == "" {
if r.Required {
err.AddError(BaseRuleNameRequired, r.Required, i, FieldIsRequired)
return err
}
return nil
}
if r.Strategy != "" {
if !validateEmail(val, EmailValidationStrategy(r.Strategy)) {
err.AddError(EmailRuleNameStrategy, r.Strategy, i, "email does not conform to chosen strategy")
}
}
atIndex := strings.LastIndex(val, "@")
if atIndex == -1 {
return err
}
domain := val[atIndex+1:]
if r.MinDomainLen > 0 && len(domain) < r.MinDomainLen {
err.AddError(EmailRuleNameMinDomainLen, r.MinDomainLen, i, "domain part of email is too short")
}
if len(r.ExcludedDomains) > 0 {
for _, excluded := range r.ExcludedDomains {
if domain == excluded {
err.AddError(EmailRuleNameExcludedDomains, r.ExcludedDomains, i, "email domain is excluded")
}
}
}
if len(r.AllowedDomains) > 0 {
if !slices.Contains(r.AllowedDomains, domain) {
err.AddError(EmailRuleNameAllowedDomains, r.AllowedDomains, i, "email domain is not allowed")
}
}
if r.Regex != nil {
// TODO: compilation will be removed to avoid performance issues
re, compileErr := regexp.Compile(*r.Regex)
if compileErr == nil && !re.MatchString(val) {
err.AddError(EmailRuleNameRegexp, *r.Regex, i, "email does not match the regex pattern")
}
}
if err.HasErrors() {
return err
}
return nil
}
func matchRegex(value string) bool {
return emailRegexp.MatchString(value)
}