fix(auth): disable trial grants on public email flows
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 5m29s

This commit is contained in:
shanshanzhong 2026-04-25 01:11:27 -07:00
parent 9db4762904
commit 5b49aa8242
6 changed files with 35 additions and 3 deletions

View File

@ -126,7 +126,9 @@ func (l *EmailLoginLogic) EmailLogin(req *types.EmailLoginRequest) (resp *types.
return err
}
rc := l.svcCtx.Config.Register
if ShouldGrantTrialForEmail(rc, req.Email) && !NormalizedEmailHasTrial(l.ctx, l.svcCtx.DB, req.Email, rc.TrialSubscribe) {
if ShouldAutoGrantTrialOnPublicEmailFlows(rc) &&
ShouldGrantTrialForEmail(rc, req.Email) &&
!NormalizedEmailHasTrial(l.ctx, l.svcCtx.DB, req.Email, rc.TrialSubscribe) {
if err = l.activeTrial(userInfo.Id); err != nil {
return err
}

View File

@ -396,7 +396,10 @@ func (l *OAuthLoginGetTokenLogic) register(email, avatar, method, openid, reques
}
rc := l.svcCtx.Config.Register
shouldActivateTrial := email != "" && authlogic.ShouldGrantTrialForEmail(rc, email) && !authlogic.NormalizedEmailHasTrial(l.ctx, l.svcCtx.DB, email, rc.TrialSubscribe)
shouldActivateTrial := email != "" &&
authlogic.ShouldAutoGrantTrialOnPublicEmailFlows(rc) &&
authlogic.ShouldGrantTrialForEmail(rc, email) &&
!authlogic.NormalizedEmailHasTrial(l.ctx, l.svcCtx.DB, email, rc.TrialSubscribe)
if shouldActivateTrial {
l.Debugw("activating trial subscription",

View File

@ -54,6 +54,14 @@ func ShouldGrantTrialForEmail(register config.RegisterConfig, email string) bool
return true
}
// ShouldAutoGrantTrialOnPublicEmailFlows defines whether browser/email-originated
// flows may auto-create a trial subscription. The current policy disables trial
// creation for email registration, email login auto-register, OAuth-with-email,
// and email binding/verification to avoid abuse through public email channels.
func ShouldAutoGrantTrialOnPublicEmailFlows(register config.RegisterConfig) bool {
return false
}
// IsDisposableAlias detects Gmail dot trick and + alias abuse.
// For Gmail-like domains, local part containing "." or "+" is rejected.
// For all other domains, only "+" alias is rejected.

View File

@ -4,6 +4,7 @@ import (
"testing"
"github.com/perfect-panel/server/internal/config"
"github.com/stretchr/testify/assert"
)
func TestNormalizeEmail(t *testing.T) {
@ -162,6 +163,15 @@ func TestShouldGrantTrialForEmail(t *testing.T) {
}
}
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 {

View File

@ -148,7 +148,9 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp *
// Activate trial subscription after transaction success (moved outside transaction to reduce lock time)
rc := l.svcCtx.Config.Register
if ShouldGrantTrialForEmail(rc, req.Email) && !NormalizedEmailHasTrial(l.ctx, l.svcCtx.DB, req.Email, rc.TrialSubscribe) {
if ShouldAutoGrantTrialOnPublicEmailFlows(rc) &&
ShouldGrantTrialForEmail(rc, req.Email) &&
!NormalizedEmailHasTrial(l.ctx, l.svcCtx.DB, req.Email, rc.TrialSubscribe) {
trialSubscribe, err = l.activeTrial(userInfo.Id)
if err != nil {
l.Errorw("Failed to activate trial subscription", logger.Field("error", err.Error()))

View File

@ -14,6 +14,13 @@ import (
func tryGrantTrialOnEmailBind(ctx context.Context, svcCtx *svc.ServiceContext, log logger.Logger, ownerUserId int64, email string) {
rc := svcCtx.Config.Register
if !auth.ShouldAutoGrantTrialOnPublicEmailFlows(rc) {
log.Infow("auto trial on email flow disabled, skip",
logger.Field("email", email),
logger.Field("owner_user_id", ownerUserId),
)
return
}
if !auth.ShouldGrantTrialForEmail(rc, email) {
if rc.EnableTrial && rc.EnableTrialEmailWhitelist {
log.Infow("email domain not in trial whitelist, skip",