All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 5m29s
199 lines
5.4 KiB
Go
199 lines
5.4 KiB
Go
package auth
|
||
|
||
import (
|
||
"testing"
|
||
|
||
"github.com/perfect-panel/server/internal/config"
|
||
"github.com/stretchr/testify/assert"
|
||
)
|
||
|
||
func TestNormalizeEmail(t *testing.T) {
|
||
tests := []struct {
|
||
input string
|
||
want string
|
||
}{
|
||
// Gmail dot trick
|
||
{"a.v.x.xx@gmail.com", "avxxx@gmail.com"},
|
||
{"john.doe@gmail.com", "johndoe@gmail.com"},
|
||
{"a.b.c.d.e@gmail.com", "abcde@gmail.com"},
|
||
// Gmail + alias
|
||
{"user+tag@gmail.com", "user@gmail.com"},
|
||
{"a.b+tag@gmail.com", "ab@gmail.com"},
|
||
// Googlemail
|
||
{"a.b@googlemail.com", "ab@googlemail.com"},
|
||
// Non-Gmail: dots preserved
|
||
{"john.doe@outlook.com", "john.doe@outlook.com"},
|
||
{"john.doe@qq.com", "john.doe@qq.com"},
|
||
// + alias stripped for all providers
|
||
{"user+spam@outlook.com", "user@outlook.com"},
|
||
{"user+spam@qq.com", "user@qq.com"},
|
||
// Case insensitive
|
||
{"User@Gmail.COM", "user@gmail.com"},
|
||
{"A.B@Gmail.com", "ab@gmail.com"},
|
||
// No change for normal non-gmail email
|
||
{"abc@163.com", "abc@163.com"},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.input, func(t *testing.T) {
|
||
got := NormalizeEmail(tt.input)
|
||
if got != tt.want {
|
||
t.Errorf("NormalizeEmail(%q) = %q, want %q", tt.input, got, tt.want)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestNormalizeEmail_NoChangeSkipsCheck(t *testing.T) {
|
||
// These emails should NOT trigger cross-user check (normalized == original)
|
||
noChangeCases := []string{
|
||
"abc@163.com",
|
||
"john.doe@outlook.com",
|
||
"user@qq.com",
|
||
}
|
||
for _, email := range noChangeCases {
|
||
normalized := NormalizeEmail(email)
|
||
lower := email
|
||
if normalized == lower {
|
||
// correct: no normalization change, NormalizedEmailHasTrial would return false early
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestShouldGrantTrialForEmail(t *testing.T) {
|
||
// 模拟线上配置:白名单开启,gmail.com 也在名单里
|
||
rcWithGmail := config.RegisterConfig{
|
||
EnableTrial: true,
|
||
EnableTrialEmailWhitelist: true,
|
||
TrialEmailDomainWhitelist: "hifastapp.com,hifastvpn.com,126.com,139.com,163.com,gmail.com",
|
||
}
|
||
// 白名单关闭
|
||
rcNoWhitelist := config.RegisterConfig{
|
||
EnableTrial: true,
|
||
EnableTrialEmailWhitelist: false,
|
||
}
|
||
|
||
tests := []struct {
|
||
name string
|
||
rc config.RegisterConfig
|
||
email string
|
||
want bool
|
||
reason string
|
||
}{
|
||
{
|
||
name: "gmail dot trick - blocked even if gmail.com in whitelist",
|
||
rc: rcWithGmail,
|
||
email: "s.m.s.n.fsmbt.d.ndny@gmail.com",
|
||
want: false,
|
||
reason: "gmail 泛域名(含点号)应拒绝",
|
||
},
|
||
{
|
||
name: "gmail plus alias - blocked",
|
||
rc: rcWithGmail,
|
||
email: "user+tag@gmail.com",
|
||
want: false,
|
||
reason: "gmail +别名应拒绝",
|
||
},
|
||
{
|
||
name: "clean gmail - allowed",
|
||
rc: rcWithGmail,
|
||
email: "normaluser@gmail.com",
|
||
want: true,
|
||
reason: "干净的 gmail 应放行",
|
||
},
|
||
{
|
||
name: "163 with dot - allowed (non-gmail dot is ok)",
|
||
rc: rcWithGmail,
|
||
email: "s.m.s.n@163.com",
|
||
want: true,
|
||
reason: "非 gmail 域点号不拦截",
|
||
},
|
||
{
|
||
name: "163 plus alias - blocked",
|
||
rc: rcWithGmail,
|
||
email: "user+spam@163.com",
|
||
want: false,
|
||
reason: "所有域名的 +别名都拦截",
|
||
},
|
||
{
|
||
name: "gmail typo squatting domain - blocked even if accidentally whitelisted",
|
||
rc: config.RegisterConfig{EnableTrial: true, EnableTrialEmailWhitelist: true, TrialEmailDomainWhitelist: "gmail.com,gmaial.com"},
|
||
email: "1.2.3.4xxx@gmaial.com",
|
||
want: false,
|
||
reason: "易混淆 Gmail 域名不应发放试用",
|
||
},
|
||
{
|
||
name: "invalid empty local - blocked",
|
||
rc: rcWithGmail,
|
||
email: "@gmail.com",
|
||
want: false,
|
||
reason: "邮箱 local 为空应拒绝",
|
||
},
|
||
{
|
||
name: "subdomain spoof - blocked",
|
||
rc: rcWithGmail,
|
||
email: "user@fake.gmail.com",
|
||
want: false,
|
||
reason: "白名单必须精确匹配域名,不匹配子域",
|
||
},
|
||
{
|
||
name: "whitelist disabled - gmail dot trick still blocked",
|
||
rc: rcNoWhitelist,
|
||
email: "s.m.s.n.fsmbt.d.ndny@gmail.com",
|
||
want: false,
|
||
reason: "白名单未启用,但泛域名仍应拒绝",
|
||
},
|
||
{
|
||
name: "trial disabled - always blocked",
|
||
rc: config.RegisterConfig{EnableTrial: false},
|
||
email: "user@163.com",
|
||
want: false,
|
||
reason: "试用未开启",
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
got := ShouldGrantTrialForEmail(tt.rc, tt.email)
|
||
if got != tt.want {
|
||
t.Errorf("ShouldGrantTrialForEmail(%q) = %v, want %v | reason: %s",
|
||
tt.email, got, tt.want, tt.reason)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestShouldAutoGrantTrialOnPublicEmailFlows(t *testing.T) {
|
||
assert.False(t, ShouldAutoGrantTrialOnPublicEmailFlows(config.RegisterConfig{}))
|
||
assert.False(t, ShouldAutoGrantTrialOnPublicEmailFlows(config.RegisterConfig{
|
||
EnableTrial: true,
|
||
EnableTrialEmailWhitelist: true,
|
||
TrialEmailDomainWhitelist: "gmail.com,example.com",
|
||
}))
|
||
}
|
||
|
||
func TestIsEmailDomainWhitelisted(t *testing.T) {
|
||
whitelist := "gmail.com,edu.cn,outlook.com"
|
||
tests := []struct {
|
||
email string
|
||
want bool
|
||
}{
|
||
{"user@gmail.com", true},
|
||
{"user@edu.cn", true},
|
||
{"User@Gmail.COM", true},
|
||
{"user@yahoo.com", false},
|
||
{"user@fake.gmail.com", false}, // subdomain not matched
|
||
{"user@", false},
|
||
{"notanemail", false},
|
||
{"@gmail.com", false},
|
||
}
|
||
for _, tt := range tests {
|
||
t.Run(tt.email, func(t *testing.T) {
|
||
got := IsEmailDomainWhitelisted(tt.email, whitelist)
|
||
if got != tt.want {
|
||
t.Errorf("IsEmailDomainWhitelisted(%q) = %v, want %v", tt.email, got, tt.want)
|
||
}
|
||
})
|
||
}
|
||
}
|