From 6c370485d1ab8fabfed10d4f1fe8564bca819556 Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Wed, 4 Mar 2026 03:03:51 -0800 Subject: [PATCH] fix gitea workflow path and runner label --- .../database/02136_verify_code_unify.down.sql | 47 ++++++++++ .../database/02136_verify_code_unify.up.sql | 4 + initialize/verify.go | 17 ++++ initialize/verify_test.go | 94 +++++++++++++++++++ internal/config/config.go | 52 +++++----- .../public/user/deleteAccountHandler.go | 2 +- .../public/user/deleteAccountHandler_test.go | 2 +- internal/logic/auth/emailLoginLogic.go | 2 +- internal/logic/auth/resetPasswordLogic.go | 2 +- internal/logic/auth/userRegisterLogic.go | 2 +- internal/logic/common/sendEmailCodeLogic.go | 2 +- internal/logic/common/sendSmsCodeLogic.go | 2 +- .../user/bindEmailWithVerificationLogic.go | 2 +- .../logic/public/user/verifyEmailLogic.go | 2 +- 14 files changed, 197 insertions(+), 35 deletions(-) create mode 100644 initialize/migrate/database/02136_verify_code_unify.down.sql create mode 100644 initialize/migrate/database/02136_verify_code_unify.up.sql create mode 100644 initialize/verify_test.go diff --git a/initialize/migrate/database/02136_verify_code_unify.down.sql b/initialize/migrate/database/02136_verify_code_unify.down.sql new file mode 100644 index 0000000..fd0b8f9 --- /dev/null +++ b/initialize/migrate/database/02136_verify_code_unify.down.sql @@ -0,0 +1,47 @@ +INSERT INTO `system` (`category`, `key`, `value`, `type`, `desc`, `created_at`, `updated_at`) +SELECT 'verify_code', + 'ExpireTime', + COALESCE(MAX(CASE WHEN `key` = 'VerifyCodeExpireTime' THEN `value` END), '900'), + 'int', + 'Verify code expire time (legacy)', + NOW(3), + NOW(3) +FROM `system` +WHERE `category` = 'verify_code' +ON DUPLICATE KEY UPDATE + `value` = VALUES(`value`), + `type` = VALUES(`type`), + `desc` = VALUES(`desc`), + `updated_at` = VALUES(`updated_at`); + +INSERT INTO `system` (`category`, `key`, `value`, `type`, `desc`, `created_at`, `updated_at`) +SELECT 'verify_code', + 'Limit', + COALESCE(MAX(CASE WHEN `key` = 'VerifyCodeLimit' THEN `value` END), '15'), + 'int', + 'Verify code limit (legacy)', + NOW(3), + NOW(3) +FROM `system` +WHERE `category` = 'verify_code' +ON DUPLICATE KEY UPDATE + `value` = VALUES(`value`), + `type` = VALUES(`type`), + `desc` = VALUES(`desc`), + `updated_at` = VALUES(`updated_at`); + +INSERT INTO `system` (`category`, `key`, `value`, `type`, `desc`, `created_at`, `updated_at`) +SELECT 'verify_code', + 'Interval', + COALESCE(MAX(CASE WHEN `key` = 'VerifyCodeInterval' THEN `value` END), '60'), + 'int', + 'Verify code interval (legacy)', + NOW(3), + NOW(3) +FROM `system` +WHERE `category` = 'verify_code' +ON DUPLICATE KEY UPDATE + `value` = VALUES(`value`), + `type` = VALUES(`type`), + `desc` = VALUES(`desc`), + `updated_at` = VALUES(`updated_at`); diff --git a/initialize/migrate/database/02136_verify_code_unify.up.sql b/initialize/migrate/database/02136_verify_code_unify.up.sql new file mode 100644 index 0000000..00091ad --- /dev/null +++ b/initialize/migrate/database/02136_verify_code_unify.up.sql @@ -0,0 +1,4 @@ +DELETE +FROM `system` +WHERE `category` = 'verify_code' + AND `key` IN ('ExpireTime', 'Limit', 'Interval'); diff --git a/initialize/verify.go b/initialize/verify.go index 965e021..cdfa61c 100644 --- a/initialize/verify.go +++ b/initialize/verify.go @@ -44,5 +44,22 @@ func Verify(svc *svc.ServiceContext) { return } tool.SystemConfigSliceReflectToStruct(cfg, &verifyCodeConfig) + applyVerifyCodeDefaults(&verifyCodeConfig) svc.Config.VerifyCode = verifyCodeConfig } + +func applyVerifyCodeDefaults(cfg *config.VerifyCode) { + if cfg == nil { + return + } + + if cfg.VerifyCodeExpireTime <= 0 { + cfg.VerifyCodeExpireTime = 900 + } + if cfg.VerifyCodeLimit <= 0 { + cfg.VerifyCodeLimit = 15 + } + if cfg.VerifyCodeInterval <= 0 { + cfg.VerifyCodeInterval = 60 + } +} diff --git a/initialize/verify_test.go b/initialize/verify_test.go new file mode 100644 index 0000000..c902476 --- /dev/null +++ b/initialize/verify_test.go @@ -0,0 +1,94 @@ +package initialize + +import ( + "testing" + + "github.com/perfect-panel/server/internal/config" + "github.com/perfect-panel/server/internal/model/system" + "github.com/perfect-panel/server/pkg/tool" + "github.com/stretchr/testify/assert" +) + +func TestApplyVerifyCodeDefaults(t *testing.T) { + testCases := []struct { + name string + in config.VerifyCode + want config.VerifyCode + }{ + { + name: "apply defaults when all zero", + in: config.VerifyCode{}, + want: config.VerifyCode{ + VerifyCodeExpireTime: 900, + VerifyCodeLimit: 15, + VerifyCodeInterval: 60, + }, + }, + { + name: "keep provided values", + in: config.VerifyCode{ + VerifyCodeExpireTime: 901, + VerifyCodeLimit: 16, + VerifyCodeInterval: 61, + }, + want: config.VerifyCode{ + VerifyCodeExpireTime: 901, + VerifyCodeLimit: 16, + VerifyCodeInterval: 61, + }, + }, + { + name: "fix invalid non-positive values", + in: config.VerifyCode{ + VerifyCodeExpireTime: -1, + VerifyCodeLimit: 0, + VerifyCodeInterval: -10, + }, + want: config.VerifyCode{ + VerifyCodeExpireTime: 900, + VerifyCodeLimit: 15, + VerifyCodeInterval: 60, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + got := testCase.in + applyVerifyCodeDefaults(&got) + assert.Equal(t, testCase.want, got) + }) + } +} + +func TestVerifyCodeReflectUsesCanonicalKeys(t *testing.T) { + configs := []*system.System{ + {Category: "verify_code", Key: "VerifyCodeExpireTime", Value: "901"}, + {Category: "verify_code", Key: "VerifyCodeLimit", Value: "16"}, + {Category: "verify_code", Key: "VerifyCodeInterval", Value: "61"}, + } + + var got config.VerifyCode + tool.SystemConfigSliceReflectToStruct(configs, &got) + applyVerifyCodeDefaults(&got) + + assert.Equal(t, int64(901), got.VerifyCodeExpireTime) + assert.Equal(t, int64(16), got.VerifyCodeLimit) + assert.Equal(t, int64(61), got.VerifyCodeInterval) +} + +func TestVerifyCodeReflectIgnoresLegacyKeys(t *testing.T) { + configs := []*system.System{ + {Category: "verify_code", Key: "ExpireTime", Value: "901"}, + {Category: "verify_code", Key: "Limit", Value: "16"}, + {Category: "verify_code", Key: "Interval", Value: "61"}, + } + + var got config.VerifyCode + tool.SystemConfigSliceReflectToStruct(configs, &got) + applyVerifyCodeDefaults(&got) + + assert.Equal(t, int64(900), got.VerifyCodeExpireTime) + assert.Equal(t, int64(15), got.VerifyCodeLimit) + assert.Equal(t, int64(60), got.VerifyCodeInterval) +} diff --git a/internal/config/config.go b/internal/config/config.go index d63afcf..a1de61e 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -9,32 +9,32 @@ import ( ) type Config struct { - Model string `yaml:"Model" default:"prod"` - Host string `yaml:"Host" default:"0.0.0.0"` - Port int `yaml:"Port" default:"8080"` - Debug bool `yaml:"Debug" default:"false"` - TLS TLS `yaml:"TLS"` - JwtAuth JwtAuth `yaml:"JwtAuth"` - Logger logger.LogConf `yaml:"Logger"` - MySQL orm.Config `yaml:"MySQL"` - Redis RedisConfig `yaml:"Redis"` - Site SiteConfig `yaml:"Site"` - Node NodeConfig `yaml:"Node"` - Mobile MobileConfig `yaml:"Mobile"` - Email EmailConfig `yaml:"Email"` - Device DeviceConfig `yaml:"device"` - Verify Verify `yaml:"Verify"` - VerifyCode VerifyCode `yaml:"VerifyCode"` - Register RegisterConfig `yaml:"Register"` - Subscribe SubscribeConfig `yaml:"Subscribe"` - Invite InviteConfig `yaml:"Invite"` + Model string `yaml:"Model" default:"prod"` + Host string `yaml:"Host" default:"0.0.0.0"` + Port int `yaml:"Port" default:"8080"` + Debug bool `yaml:"Debug" default:"false"` + TLS TLS `yaml:"TLS"` + JwtAuth JwtAuth `yaml:"JwtAuth"` + Logger logger.LogConf `yaml:"Logger"` + MySQL orm.Config `yaml:"MySQL"` + Redis RedisConfig `yaml:"Redis"` + Site SiteConfig `yaml:"Site"` + Node NodeConfig `yaml:"Node"` + Mobile MobileConfig `yaml:"Mobile"` + Email EmailConfig `yaml:"Email"` + Device DeviceConfig `yaml:"device"` + Verify Verify `yaml:"Verify"` + VerifyCode VerifyCode `yaml:"VerifyCode"` + Register RegisterConfig `yaml:"Register"` + Subscribe SubscribeConfig `yaml:"Subscribe"` + Invite InviteConfig `yaml:"Invite"` Kutt KuttConfig `yaml:"Kutt"` OpenInstall OpenInstallConfig `yaml:"OpenInstall"` Loki LokiConfig `yaml:"Loki"` - Telegram Telegram `yaml:"Telegram"` - Log Log `yaml:"Log"` - Currency Currency `yaml:"Currency"` - Trace trace.Config `yaml:"Trace"` + Telegram Telegram `yaml:"Telegram"` + Log Log `yaml:"Log"` + Currency Currency `yaml:"Currency"` + Trace trace.Config `yaml:"Trace"` Administrator struct { Email string `yaml:"Email" default:"admin@ppanel.dev"` Password string `yaml:"Password" default:"password"` @@ -261,9 +261,9 @@ type TLS struct { } type VerifyCode struct { - ExpireTime int64 `yaml:"ExpireTime" default:"900"` - Limit int64 `yaml:"Limit" default:"15"` - Interval int64 `yaml:"Interval" default:"60"` + VerifyCodeExpireTime int64 `yaml:"VerifyCodeExpireTime" default:"900"` + VerifyCodeLimit int64 `yaml:"VerifyCodeLimit" default:"15"` + VerifyCodeInterval int64 `yaml:"VerifyCodeInterval" default:"60"` } type Log struct { diff --git a/internal/handler/public/user/deleteAccountHandler.go b/internal/handler/public/user/deleteAccountHandler.go index a0ac59e..1bb6383 100644 --- a/internal/handler/public/user/deleteAccountHandler.go +++ b/internal/handler/public/user/deleteAccountHandler.go @@ -73,7 +73,7 @@ func verifyEmailCode(ctx context.Context, serverCtx *svc.ServiceContext, email s continue } // 检查验证码是否匹配且未过期 - if payload.Code == code && time.Now().Unix()-payload.LastAt <= serverCtx.Config.VerifyCode.ExpireTime { + if payload.Code == code && time.Now().Unix()-payload.LastAt <= serverCtx.Config.VerifyCode.VerifyCodeExpireTime { verified = true cacheKeyUsed = cacheKey break diff --git a/internal/handler/public/user/deleteAccountHandler_test.go b/internal/handler/public/user/deleteAccountHandler_test.go index 0eea8e7..d66fe41 100644 --- a/internal/handler/public/user/deleteAccountHandler_test.go +++ b/internal/handler/public/user/deleteAccountHandler_test.go @@ -74,7 +74,7 @@ func TestDeleteAccountHandlerVerifyCodeErrorUsesUnifiedResponse(t *testing.T) { Redis: redisClient, Config: config.Config{ VerifyCode: config.VerifyCode{ - ExpireTime: 900, + VerifyCodeExpireTime: 900, }, }, } diff --git a/internal/logic/auth/emailLoginLogic.go b/internal/logic/auth/emailLoginLogic.go index 1cc594f..881d2f9 100644 --- a/internal/logic/auth/emailLoginLogic.go +++ b/internal/logic/auth/emailLoginLogic.go @@ -61,7 +61,7 @@ func (l *EmailLoginLogic) EmailLogin(req *types.EmailLoginRequest) (resp *types. if err := json.Unmarshal([]byte(value), &payload); err != nil { continue } - if payload.Code == req.Code && time.Now().Unix()-payload.LastAt <= l.svcCtx.Config.VerifyCode.ExpireTime { + if payload.Code == req.Code && time.Now().Unix()-payload.LastAt <= l.svcCtx.Config.VerifyCode.VerifyCodeExpireTime { verified = true cacheKeyUsed = cacheKey break diff --git a/internal/logic/auth/resetPasswordLogic.go b/internal/logic/auth/resetPasswordLogic.go index 85800d7..363604e 100644 --- a/internal/logic/auth/resetPasswordLogic.go +++ b/internal/logic/auth/resetPasswordLogic.go @@ -85,7 +85,7 @@ func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordRequest) (res l.Errorw("Verification code error", logger.Field("cacheKey", cacheKey), logger.Field("error", "Verification code error"), logger.Field("reqCode", req.Code), logger.Field("payloadCode", payload.Code)) return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "Verification code error") } - if time.Now().Unix()-payload.LastAt > l.svcCtx.Config.VerifyCode.ExpireTime { + if time.Now().Unix()-payload.LastAt > l.svcCtx.Config.VerifyCode.VerifyCodeExpireTime { return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code expired") } l.svcCtx.Redis.Del(l.ctx, cacheKey) diff --git a/internal/logic/auth/userRegisterLogic.go b/internal/logic/auth/userRegisterLogic.go index 80cf27b..f49ec23 100644 --- a/internal/logic/auth/userRegisterLogic.go +++ b/internal/logic/auth/userRegisterLogic.go @@ -80,7 +80,7 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp * return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") } // 校验有效期 - if time.Now().Unix()-payload.LastAt > l.svcCtx.Config.VerifyCode.ExpireTime { + if time.Now().Unix()-payload.LastAt > l.svcCtx.Config.VerifyCode.VerifyCodeExpireTime { return nil, errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code expired") } l.svcCtx.Redis.Del(l.ctx, cacheKey) diff --git a/internal/logic/common/sendEmailCodeLogic.go b/internal/logic/common/sendEmailCodeLogic.go index bfd248c..516d47f 100644 --- a/internal/logic/common/sendEmailCodeLogic.go +++ b/internal/logic/common/sendEmailCodeLogic.go @@ -92,7 +92,7 @@ func (l *SendEmailCodeLogic) SendEmailCode(req *types.SendCodeRequest) (resp *ty taskPayload.Email = req.Email taskPayload.Subject = "Verification code" - expireTime := l.svcCtx.Config.VerifyCode.ExpireTime + expireTime := l.svcCtx.Config.VerifyCode.VerifyCodeExpireTime if expireTime == 0 { expireTime = 900 } diff --git a/internal/logic/common/sendSmsCodeLogic.go b/internal/logic/common/sendSmsCodeLogic.go index 7f5037a..26efc33 100644 --- a/internal/logic/common/sendSmsCodeLogic.go +++ b/internal/logic/common/sendSmsCodeLogic.go @@ -91,7 +91,7 @@ func (l *SendSmsCodeLogic) SendSmsCode(req *types.SendSmsCodeRequest) (resp *typ } // Marshal the payload val, _ := json.Marshal(payload) - if err = l.svcCtx.Redis.Set(l.ctx, cacheKey, string(val), time.Second*time.Duration(l.svcCtx.Config.VerifyCode.ExpireTime)).Err(); err != nil { + if err = l.svcCtx.Redis.Set(l.ctx, cacheKey, string(val), time.Second*time.Duration(l.svcCtx.Config.VerifyCode.VerifyCodeExpireTime)).Err(); err != nil { l.Errorw("[SendSmsCode]: Redis Error", logger.Field("error", err.Error()), logger.Field("cacheKey", cacheKey)) return nil, errors.Wrap(xerr.NewErrCode(xerr.ERROR), "Failed to set verification code") } diff --git a/internal/logic/public/user/bindEmailWithVerificationLogic.go b/internal/logic/public/user/bindEmailWithVerificationLogic.go index 063b270..86a9877 100644 --- a/internal/logic/public/user/bindEmailWithVerificationLogic.go +++ b/internal/logic/public/user/bindEmailWithVerificationLogic.go @@ -59,7 +59,7 @@ func (l *BindEmailWithVerificationLogic) BindEmailWithVerification(req *types.Bi if err := json.Unmarshal([]byte(value), &p); err != nil { continue } - if p.Code == req.Code && time.Now().Unix()-p.LastAt <= l.svcCtx.Config.VerifyCode.ExpireTime { + if p.Code == req.Code && time.Now().Unix()-p.LastAt <= l.svcCtx.Config.VerifyCode.VerifyCodeExpireTime { _ = l.svcCtx.Redis.Del(l.ctx, cacheKey).Err() verified = true break diff --git a/internal/logic/public/user/verifyEmailLogic.go b/internal/logic/public/user/verifyEmailLogic.go index 89ebd30..d9c59de 100644 --- a/internal/logic/public/user/verifyEmailLogic.go +++ b/internal/logic/public/user/verifyEmailLogic.go @@ -55,7 +55,7 @@ func (l *VerifyEmailLogic) VerifyEmail(req *types.VerifyEmailRequest) error { if payload.Code != req.Code { return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code error") } - if time.Now().Unix()-payload.LastAt > l.svcCtx.Config.VerifyCode.ExpireTime { + if time.Now().Unix()-payload.LastAt > l.svcCtx.Config.VerifyCode.VerifyCodeExpireTime { return errors.Wrapf(xerr.NewErrCode(xerr.VerifyCodeError), "code expired") } l.svcCtx.Redis.Del(l.ctx, cacheKey)