mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-04-19 04:27:27 +00:00
fix CI/CD Error
This commit is contained in:
@@ -19,7 +19,7 @@ func TestAdminAuthJWTValidatesTokenVersion(t *testing.T) {
|
|||||||
gin.SetMode(gin.TestMode)
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
cfg := &config.Config{JWT: config.JWTConfig{Secret: "test-secret", ExpireHour: 1}}
|
cfg := &config.Config{JWT: config.JWTConfig{Secret: "test-secret", ExpireHour: 1}}
|
||||||
authService := service.NewAuthService(nil, nil, nil, cfg, nil, nil, nil, nil, nil, nil)
|
authService := service.NewAuthService(nil, nil, nil, nil, cfg, nil, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
admin := &service.User{
|
admin := &service.User{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func newJWTTestEnv(users map[int64]*service.User) (*gin.Engine, *service.AuthSer
|
|||||||
cfg.JWT.AccessTokenExpireMinutes = 60
|
cfg.JWT.AccessTokenExpireMinutes = 60
|
||||||
|
|
||||||
userRepo := &stubJWTUserRepo{users: users}
|
userRepo := &stubJWTUserRepo{users: users}
|
||||||
authSvc := service.NewAuthService(userRepo, nil, nil, cfg, nil, nil, nil, nil, nil, nil)
|
authSvc := service.NewAuthService(nil, userRepo, nil, nil, cfg, nil, nil, nil, nil, nil, nil)
|
||||||
userSvc := service.NewUserService(userRepo, nil, nil)
|
userSvc := service.NewUserService(userRepo, nil, nil)
|
||||||
mw := NewJWTAuthMiddleware(authSvc, userSvc)
|
mw := NewJWTAuthMiddleware(authSvc, userSvc)
|
||||||
|
|
||||||
|
|||||||
@@ -647,6 +647,11 @@ func (s *AuthService) LoginOrRegisterOAuthWithTokenPair(ctx context.Context, ema
|
|||||||
} else {
|
} else {
|
||||||
user = newUser
|
user = newUser
|
||||||
s.assignDefaultSubscriptions(ctx, user.ID)
|
s.assignDefaultSubscriptions(ctx, user.ID)
|
||||||
|
if invitationRedeemCode != nil {
|
||||||
|
if err := s.redeemRepo.Use(ctx, invitationRedeemCode.ID, user.ID); err != nil {
|
||||||
|
return nil, nil, ErrInvitationCodeInvalid
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
146
backend/internal/service/auth_service_pending_oauth_test.go
Normal file
146
backend/internal/service/auth_service_pending_oauth_test.go
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
//go:build unit
|
||||||
|
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Wei-Shaw/sub2api/internal/config"
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newAuthServiceForPendingOAuthTest() *AuthService {
|
||||||
|
cfg := &config.Config{
|
||||||
|
JWT: config.JWTConfig{
|
||||||
|
Secret: "test-secret-pending-oauth",
|
||||||
|
ExpireHour: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return NewAuthService(nil, nil, nil, nil, cfg, nil, nil, nil, nil, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestVerifyPendingOAuthToken_ValidToken 验证正常签发的 pending token 可以被成功解析。
|
||||||
|
func TestVerifyPendingOAuthToken_ValidToken(t *testing.T) {
|
||||||
|
svc := newAuthServiceForPendingOAuthTest()
|
||||||
|
|
||||||
|
token, err := svc.CreatePendingOAuthToken("user@example.com", "alice")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, token)
|
||||||
|
|
||||||
|
email, username, err := svc.VerifyPendingOAuthToken(token)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "user@example.com", email)
|
||||||
|
require.Equal(t, "alice", username)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestVerifyPendingOAuthToken_RegularJWTRejected 用普通 access token 尝试验证,应返回 ErrInvalidToken。
|
||||||
|
func TestVerifyPendingOAuthToken_RegularJWTRejected(t *testing.T) {
|
||||||
|
svc := newAuthServiceForPendingOAuthTest()
|
||||||
|
|
||||||
|
// 签发一个普通 access token(JWTClaims,无 Purpose 字段)
|
||||||
|
accessToken, err := svc.GenerateToken(&User{
|
||||||
|
ID: 1,
|
||||||
|
Email: "user@example.com",
|
||||||
|
Role: RoleUser,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = svc.VerifyPendingOAuthToken(accessToken)
|
||||||
|
require.ErrorIs(t, err, ErrInvalidToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestVerifyPendingOAuthToken_WrongPurpose 手动构造 purpose 字段不匹配的 JWT,应返回 ErrInvalidToken。
|
||||||
|
func TestVerifyPendingOAuthToken_WrongPurpose(t *testing.T) {
|
||||||
|
svc := newAuthServiceForPendingOAuthTest()
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
claims := &pendingOAuthClaims{
|
||||||
|
Email: "user@example.com",
|
||||||
|
Username: "alice",
|
||||||
|
Purpose: "some_other_purpose",
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(now.Add(10 * time.Minute)),
|
||||||
|
IssuedAt: jwt.NewNumericDate(now),
|
||||||
|
NotBefore: jwt.NewNumericDate(now),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tok := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
tokenStr, err := tok.SignedString([]byte(svc.cfg.JWT.Secret))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = svc.VerifyPendingOAuthToken(tokenStr)
|
||||||
|
require.ErrorIs(t, err, ErrInvalidToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestVerifyPendingOAuthToken_MissingPurpose 手动构造无 purpose 字段的 JWT(模拟旧 token),应返回 ErrInvalidToken。
|
||||||
|
func TestVerifyPendingOAuthToken_MissingPurpose(t *testing.T) {
|
||||||
|
svc := newAuthServiceForPendingOAuthTest()
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
claims := &pendingOAuthClaims{
|
||||||
|
Email: "user@example.com",
|
||||||
|
Username: "alice",
|
||||||
|
Purpose: "", // 旧 token 无此字段,反序列化后为零值
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(now.Add(10 * time.Minute)),
|
||||||
|
IssuedAt: jwt.NewNumericDate(now),
|
||||||
|
NotBefore: jwt.NewNumericDate(now),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tok := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
tokenStr, err := tok.SignedString([]byte(svc.cfg.JWT.Secret))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = svc.VerifyPendingOAuthToken(tokenStr)
|
||||||
|
require.ErrorIs(t, err, ErrInvalidToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestVerifyPendingOAuthToken_ExpiredToken 过期 token 应返回 ErrInvalidToken。
|
||||||
|
func TestVerifyPendingOAuthToken_ExpiredToken(t *testing.T) {
|
||||||
|
svc := newAuthServiceForPendingOAuthTest()
|
||||||
|
|
||||||
|
past := time.Now().Add(-1 * time.Hour)
|
||||||
|
claims := &pendingOAuthClaims{
|
||||||
|
Email: "user@example.com",
|
||||||
|
Username: "alice",
|
||||||
|
Purpose: pendingOAuthPurpose,
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(past),
|
||||||
|
IssuedAt: jwt.NewNumericDate(past.Add(-10 * time.Minute)),
|
||||||
|
NotBefore: jwt.NewNumericDate(past.Add(-10 * time.Minute)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tok := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
tokenStr, err := tok.SignedString([]byte(svc.cfg.JWT.Secret))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = svc.VerifyPendingOAuthToken(tokenStr)
|
||||||
|
require.ErrorIs(t, err, ErrInvalidToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestVerifyPendingOAuthToken_WrongSecret 不同密钥签发的 token 应返回 ErrInvalidToken。
|
||||||
|
func TestVerifyPendingOAuthToken_WrongSecret(t *testing.T) {
|
||||||
|
other := NewAuthService(nil, nil, nil, nil, &config.Config{
|
||||||
|
JWT: config.JWTConfig{Secret: "other-secret"},
|
||||||
|
}, nil, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
|
token, err := other.CreatePendingOAuthToken("user@example.com", "alice")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
svc := newAuthServiceForPendingOAuthTest()
|
||||||
|
_, _, err = svc.VerifyPendingOAuthToken(token)
|
||||||
|
require.ErrorIs(t, err, ErrInvalidToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestVerifyPendingOAuthToken_TooLong 超长 token 应返回 ErrInvalidToken。
|
||||||
|
func TestVerifyPendingOAuthToken_TooLong(t *testing.T) {
|
||||||
|
svc := newAuthServiceForPendingOAuthTest()
|
||||||
|
giant := make([]byte, maxTokenLength+1)
|
||||||
|
for i := range giant {
|
||||||
|
giant[i] = 'a'
|
||||||
|
}
|
||||||
|
_, _, err := svc.VerifyPendingOAuthToken(string(giant))
|
||||||
|
require.ErrorIs(t, err, ErrInvalidToken)
|
||||||
|
}
|
||||||
@@ -130,6 +130,7 @@ func newAuthService(repo *userRepoStub, settings map[string]string, emailCache E
|
|||||||
}
|
}
|
||||||
|
|
||||||
return NewAuthService(
|
return NewAuthService(
|
||||||
|
nil, // entClient
|
||||||
repo,
|
repo,
|
||||||
nil, // redeemRepo
|
nil, // redeemRepo
|
||||||
nil, // refreshTokenCache
|
nil, // refreshTokenCache
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ func newAuthServiceForRegisterTurnstileTest(settings map[string]string, verifier
|
|||||||
turnstileService := NewTurnstileService(settingService, verifier)
|
turnstileService := NewTurnstileService(settingService, verifier)
|
||||||
|
|
||||||
return NewAuthService(
|
return NewAuthService(
|
||||||
|
nil, // entClient
|
||||||
&userRepoStub{},
|
&userRepoStub{},
|
||||||
nil, // redeemRepo
|
nil, // redeemRepo
|
||||||
nil, // refreshTokenCache
|
nil, // refreshTokenCache
|
||||||
|
|||||||
Reference in New Issue
Block a user