diff --git a/cmd/webserver.go b/cmd/webserver.go index 233622e7..2388d4e5 100644 --- a/cmd/webserver.go +++ b/cmd/webserver.go @@ -176,7 +176,7 @@ func startWebServer(c *core.CliContext) error { if config.AvatarProvider == core.USER_AVATAR_PROVIDER_INTERNAL { avatarRoute := router.Group("/avatar") - avatarRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByQueryString)) + avatarRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByQueryString(config))) { avatarRoute.GET("/:fileName", bindImage(api.Users.UserGetAvatarHandler)) } @@ -184,7 +184,7 @@ func startWebServer(c *core.CliContext) error { if config.EnableTransactionPictures { pictureRoute := router.Group("/pictures") - pictureRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByQueryString)) + pictureRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByQueryString(config))) { pictureRoute.GET("/:fileName", bindImage(api.TransactionPictures.TransactionPictureGetHandler)) } @@ -193,7 +193,7 @@ func startWebServer(c *core.CliContext) error { router.GET("/healthz.json", bindApi(api.Healths.HealthStatusHandler)) proxyRoute := router.Group("/proxy") - proxyRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByQueryString)) + proxyRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByQueryString(config))) { if config.EnableMapDataFetchProxy { if config.MapProvider == settings.OpenStreetMapProvider || @@ -217,7 +217,7 @@ func startWebServer(c *core.CliContext) error { if config.MapProvider == settings.AmapProvider && config.AmapSecurityVerificationMethod == settings.AmapSecurityVerificationInternalProxyMethod { amapApiProxyRoute := router.Group("/_AMapService") - amapApiProxyRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByCookie)) + amapApiProxyRoute.Use(bindMiddleware(middlewares.JWTAuthorizationByCookie(config))) { amapApiProxyRoute.GET("/*action", bindProxy(api.AmapApis.AmapApiProxyHandler)) } @@ -235,7 +235,7 @@ func startWebServer(c *core.CliContext) error { mcpRoute.Use(bindMiddleware(middlewares.RequestId(config))) mcpRoute.Use(bindMiddleware(middlewares.RequestLog)) mcpRoute.Use(bindMiddleware(middlewares.MCPServerIpLimit(config))) - mcpRoute.Use(bindMiddleware(middlewares.JWTMCPAuthorization)) + mcpRoute.Use(bindMiddleware(middlewares.JWTMCPAuthorization(config))) { mcpRoute.POST("", bindJSONRPCApi(map[string]core.JSONRPCApiHandlerFunc{ "initialize": api.ModelContextProtocols.InitializeHandler, @@ -272,7 +272,7 @@ func startWebServer(c *core.CliContext) error { if config.EnableInternalAuth && config.EnableTwoFactor { twoFactorRoute := apiRoute.Group("/2fa") - twoFactorRoute.Use(bindMiddleware(middlewares.JWTTwoFactorAuthorization)) + twoFactorRoute.Use(bindMiddleware(middlewares.JWTTwoFactorAuthorization(config))) { twoFactorRoute.POST("/authorize.json", bindApiWithTokenUpdate(api.Authorizations.TwoFactorAuthorizeHandler, config)) twoFactorRoute.POST("/recovery.json", bindApiWithTokenUpdate(api.Authorizations.TwoFactorAuthorizeByRecoveryCodeHandler, config)) @@ -281,7 +281,7 @@ func startWebServer(c *core.CliContext) error { if config.EnableOAuth2Login { oauth2Route := apiRoute.Group("/oauth2") - oauth2Route.Use(bindMiddleware(middlewares.JWTOAuth2CallbackAuthorization)) + oauth2Route.Use(bindMiddleware(middlewares.JWTOAuth2CallbackAuthorization(config))) { oauth2Route.POST("/authorize.json", bindApiWithTokenUpdate(api.Authorizations.OAuth2CallbackAuthorizeHandler, config)) } @@ -295,7 +295,7 @@ func startWebServer(c *core.CliContext) error { apiRoute.POST("/verify_email/resend.json", bindApi(api.Users.UserSendVerifyEmailByUnloginUserHandler)) emailVerifyRoute := apiRoute.Group("/verify_email") - emailVerifyRoute.Use(bindMiddleware(middlewares.JWTEmailVerifyAuthorization)) + emailVerifyRoute.Use(bindMiddleware(middlewares.JWTEmailVerifyAuthorization(config))) { emailVerifyRoute.POST("/by_token.json", bindApi(api.Users.UserEmailVerifyHandler)) } @@ -305,7 +305,7 @@ func startWebServer(c *core.CliContext) error { apiRoute.POST("/forget_password/request.json", bindApi(api.ForgetPasswords.UserForgetPasswordRequestHandler)) resetPasswordRoute := apiRoute.Group("/forget_password/reset") - resetPasswordRoute.Use(bindMiddleware(middlewares.JWTResetPasswordAuthorization)) + resetPasswordRoute.Use(bindMiddleware(middlewares.JWTResetPasswordAuthorization(config))) { resetPasswordRoute.POST("/by_token.json", bindApi(api.ForgetPasswords.UserResetPasswordHandler)) } @@ -314,7 +314,7 @@ func startWebServer(c *core.CliContext) error { apiRoute.GET("/logout.json", bindApiWithTokenUpdate(api.Tokens.TokenRevokeCurrentHandler, config)) apiV1Route := apiRoute.Group("/v1") - apiV1Route.Use(bindMiddleware(middlewares.JWTAuthorization)) + apiV1Route.Use(bindMiddleware(middlewares.JWTAuthorization(config))) { // Tokens apiV1Route.GET("/tokens/list.json", bindApi(api.Tokens.TokenListHandler)) diff --git a/conf/ezbookkeeping.ini b/conf/ezbookkeeping.ini index 5e8aec32..c54f3c15 100644 --- a/conf/ezbookkeeping.ini +++ b/conf/ezbookkeeping.ini @@ -264,7 +264,7 @@ email_verify_token_expired_time = 3600 password_reset_token_expired_time = 3600 # Set to true to enable API token generation -enable_generate_api_token = false +enable_api_token = false # Maximum count of password / token check failures (0 - 4294967295) per IP per minute (use the above duplicate checker), default is 5, set to 0 to disable max_failures_per_ip_per_minute = 5 diff --git a/pkg/api/server_settings.go b/pkg/api/server_settings.go index 1842adab..57c78793 100644 --- a/pkg/api/server_settings.go +++ b/pkg/api/server_settings.go @@ -39,7 +39,7 @@ func (a *ServerSettingsApi) ServerSettingsJavascriptHandler(c *core.WebContext) a.appendBooleanSetting(builder, "o", config.EnableOAuth2Login) a.appendBooleanSetting(builder, "r", config.EnableInternalAuth && config.EnableUserRegister) a.appendBooleanSetting(builder, "f", config.EnableInternalAuth && config.EnableUserForgetPassword) - a.appendBooleanSetting(builder, "t", config.EnableGenerateAPIToken) + a.appendBooleanSetting(builder, "t", config.EnableAPIToken) a.appendBooleanSetting(builder, "v", config.EnableUserVerifyEmail) a.appendBooleanSetting(builder, "p", config.EnableTransactionPictures) a.appendBooleanSetting(builder, "s", config.EnableScheduledTransaction) diff --git a/pkg/api/tokens.go b/pkg/api/tokens.go index e0978714..e5a03a28 100644 --- a/pkg/api/tokens.go +++ b/pkg/api/tokens.go @@ -85,8 +85,8 @@ func (a *TokensApi) TokenListHandler(c *core.WebContext) (any, *errs.Error) { // TokenGenerateAPIHandler generates a new API token for current user func (a *TokensApi) TokenGenerateAPIHandler(c *core.WebContext) (any, *errs.Error) { - if !a.CurrentConfig().EnableGenerateAPIToken { - return nil, errs.ErrNotAllowedToGenerateAPIToken + if !a.CurrentConfig().EnableAPIToken { + return nil, errs.ErrAPITokenNotEnabled } var generateAPITokenReq models.TokenGenerateAPIRequest diff --git a/pkg/cli/user_data.go b/pkg/cli/user_data.go index e24c6e40..cd580e4f 100644 --- a/pkg/cli/user_data.go +++ b/pkg/cli/user_data.go @@ -422,8 +422,8 @@ func (l *UserDataCli) CreateNewUserToken(c *core.CliContext, username string, to var tokenRecord *models.TokenRecord if tokenType == "api" { - if !l.CurrentConfig().EnableGenerateAPIToken { - return nil, "", errs.ErrNotAllowedToGenerateAPIToken + if !l.CurrentConfig().EnableAPIToken { + return nil, "", errs.ErrAPITokenNotEnabled } if user.FeatureRestriction.Contains(core.USER_FEATURE_RESTRICTION_TYPE_GENERATE_API_TOKEN) { diff --git a/pkg/errs/token.go b/pkg/errs/token.go index ab5c89f9..de707efc 100644 --- a/pkg/errs/token.go +++ b/pkg/errs/token.go @@ -21,5 +21,5 @@ var ( ErrTokenIsEmpty = NewNormalError(NormalSubcategoryToken, 12, http.StatusBadRequest, "token is empty") ErrEmailVerifyTokenIsInvalidOrExpired = NewNormalError(NormalSubcategoryToken, 13, http.StatusBadRequest, "email verify token is invalid or expired") ErrPasswordResetTokenIsInvalidOrExpired = NewNormalError(NormalSubcategoryToken, 14, http.StatusBadRequest, "password reset token is invalid or expired") - ErrNotAllowedToGenerateAPIToken = NewNormalError(NormalSubcategoryToken, 15, http.StatusForbidden, "not allowed to generate api token") + ErrAPITokenNotEnabled = NewNormalError(NormalSubcategoryToken, 15, http.StatusForbidden, "api token is not enabled") ) diff --git a/pkg/middlewares/authorization.go b/pkg/middlewares/authorization.go index 7fa2e06f..06b13797 100644 --- a/pkg/middlewares/authorization.go +++ b/pkg/middlewares/authorization.go @@ -7,6 +7,7 @@ import ( "github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/log" "github.com/mayswind/ezbookkeeping/pkg/services" + "github.com/mayswind/ezbookkeeping/pkg/settings" "github.com/mayswind/ezbookkeeping/pkg/utils" ) @@ -21,143 +22,161 @@ const ( ) // JWTAuthorization verifies whether current request is valid by jwt token in header -func JWTAuthorization(c *core.WebContext) { - jwtAuthorization(c, TOKEN_SOURCE_TYPE_HEADER) +func JWTAuthorization(config *settings.Config) core.MiddlewareHandlerFunc { + return jwtAuthorization(config, TOKEN_SOURCE_TYPE_HEADER) } // JWTAuthorizationByQueryString verifies whether current request is valid by jwt token in query string -func JWTAuthorizationByQueryString(c *core.WebContext) { - jwtAuthorization(c, TOKEN_SOURCE_TYPE_ARGUMENT) +func JWTAuthorizationByQueryString(config *settings.Config) core.MiddlewareHandlerFunc { + return jwtAuthorization(config, TOKEN_SOURCE_TYPE_ARGUMENT) } // JWTAuthorizationByCookie verifies whether current request is valid by jwt token in cookie -func JWTAuthorizationByCookie(c *core.WebContext) { - jwtAuthorization(c, TOKEN_SOURCE_TYPE_COOKIE) +func JWTAuthorizationByCookie(config *settings.Config) core.MiddlewareHandlerFunc { + return jwtAuthorization(config, TOKEN_SOURCE_TYPE_COOKIE) } // JWTTwoFactorAuthorization verifies whether current request is valid by 2fa passcode -func JWTTwoFactorAuthorization(c *core.WebContext) { - claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_HEADER) +func JWTTwoFactorAuthorization(config *settings.Config) core.MiddlewareHandlerFunc { + return func(c *core.WebContext) { + claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_HEADER) - if err != nil { - utils.PrintJsonErrorResult(c, err) - return + if err != nil { + utils.PrintJsonErrorResult(c, err) + return + } + + if claims.Type != core.USER_TOKEN_TYPE_REQUIRE_2FA { + log.Warnf(c, "[authorization.JWTTwoFactorAuthorization] user \"uid:%d\" token is not need two-factor authorization", claims.Uid) + utils.PrintJsonErrorResult(c, errs.ErrCurrentTokenNotRequire2FA) + return + } + + c.SetTokenClaims(claims) + c.SetTokenContext(tokenContext) + c.Next() } - - if claims.Type != core.USER_TOKEN_TYPE_REQUIRE_2FA { - log.Warnf(c, "[authorization.JWTTwoFactorAuthorization] user \"uid:%d\" token is not need two-factor authorization", claims.Uid) - utils.PrintJsonErrorResult(c, errs.ErrCurrentTokenNotRequire2FA) - return - } - - c.SetTokenClaims(claims) - c.SetTokenContext(tokenContext) - c.Next() } // JWTEmailVerifyAuthorization verifies whether current request is email verification -func JWTEmailVerifyAuthorization(c *core.WebContext) { - claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_ARGUMENT) +func JWTEmailVerifyAuthorization(config *settings.Config) core.MiddlewareHandlerFunc { + return func(c *core.WebContext) { + claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_ARGUMENT) - if err != nil { - utils.PrintJsonErrorResult(c, errs.ErrEmailVerifyTokenIsInvalidOrExpired) - return + if err != nil { + utils.PrintJsonErrorResult(c, errs.ErrEmailVerifyTokenIsInvalidOrExpired) + return + } + + if claims.Type != core.USER_TOKEN_TYPE_EMAIL_VERIFY { + log.Warnf(c, "[authorization.JWTEmailVerifyAuthorization] user \"uid:%d\" token is not for email verification", claims.Uid) + utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidToken) + return + } + + c.SetTokenClaims(claims) + c.SetTokenContext(tokenContext) + c.Next() } - - if claims.Type != core.USER_TOKEN_TYPE_EMAIL_VERIFY { - log.Warnf(c, "[authorization.JWTEmailVerifyAuthorization] user \"uid:%d\" token is not for email verification", claims.Uid) - utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidToken) - return - } - - c.SetTokenClaims(claims) - c.SetTokenContext(tokenContext) - c.Next() } // JWTResetPasswordAuthorization verifies whether current request is password reset -func JWTResetPasswordAuthorization(c *core.WebContext) { - claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_ARGUMENT) +func JWTResetPasswordAuthorization(config *settings.Config) core.MiddlewareHandlerFunc { + return func(c *core.WebContext) { + claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_ARGUMENT) - if err != nil { - utils.PrintJsonErrorResult(c, errs.ErrPasswordResetTokenIsInvalidOrExpired) - return + if err != nil { + utils.PrintJsonErrorResult(c, errs.ErrPasswordResetTokenIsInvalidOrExpired) + return + } + + if claims.Type != core.USER_TOKEN_TYPE_PASSWORD_RESET { + log.Warnf(c, "[authorization.JWTResetPasswordAuthorization] user \"uid:%d\" token is not for password request", claims.Uid) + utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidToken) + return + } + + c.SetTokenClaims(claims) + c.SetTokenContext(tokenContext) + c.Next() } - - if claims.Type != core.USER_TOKEN_TYPE_PASSWORD_RESET { - log.Warnf(c, "[authorization.JWTResetPasswordAuthorization] user \"uid:%d\" token is not for password request", claims.Uid) - utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidToken) - return - } - - c.SetTokenClaims(claims) - c.SetTokenContext(tokenContext) - c.Next() } // JWTMCPAuthorization verifies whether current request is valid by jwt mcp token in header -func JWTMCPAuthorization(c *core.WebContext) { - claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_HEADER) +func JWTMCPAuthorization(config *settings.Config) core.MiddlewareHandlerFunc { + return func(c *core.WebContext) { + claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_HEADER) - if err != nil { - utils.PrintJsonErrorResult(c, err) - return + if err != nil { + utils.PrintJsonErrorResult(c, err) + return + } + + if claims.Type != core.USER_TOKEN_TYPE_MCP { + log.Warnf(c, "[authorization.jwtAuthorization] user \"uid:%d\" token type (%d) is not mcp token", claims.Uid, claims.Type) + utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidTokenType) + return + } + + c.SetTokenClaims(claims) + c.SetTokenContext(tokenContext) + c.Next() } - - if claims.Type != core.USER_TOKEN_TYPE_MCP { - log.Warnf(c, "[authorization.jwtAuthorization] user \"uid:%d\" token type (%d) is not mcp token", claims.Uid, claims.Type) - utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidTokenType) - return - } - - c.SetTokenClaims(claims) - c.SetTokenContext(tokenContext) - c.Next() } // JWTOAuth2CallbackAuthorization verifies whether current request is OAuth 2.0 callback -func JWTOAuth2CallbackAuthorization(c *core.WebContext) { - claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_HEADER) +func JWTOAuth2CallbackAuthorization(config *settings.Config) core.MiddlewareHandlerFunc { + return func(c *core.WebContext) { + claims, tokenContext, err := getTokenClaims(c, TOKEN_SOURCE_TYPE_HEADER) - if err != nil { - utils.PrintJsonErrorResult(c, errs.ErrTokenExpired) - return + if err != nil { + utils.PrintJsonErrorResult(c, errs.ErrTokenExpired) + return + } + + if claims.Type != core.USER_TOKEN_TYPE_OAUTH2_CALLBACK && claims.Type != core.USER_TOKEN_TYPE_OAUTH2_CALLBACK_REQUIRE_VERIFY { + log.Warnf(c, "[authorization.JWTOAuth2CallbackAuthorization] user \"uid:%d\" token is not for oauth 2.0 callback request", claims.Uid) + utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidToken) + return + } + + c.SetTokenClaims(claims) + c.SetTokenContext(tokenContext) + c.Next() } - - if claims.Type != core.USER_TOKEN_TYPE_OAUTH2_CALLBACK && claims.Type != core.USER_TOKEN_TYPE_OAUTH2_CALLBACK_REQUIRE_VERIFY { - log.Warnf(c, "[authorization.JWTOAuth2CallbackAuthorization] user \"uid:%d\" token is not for oauth 2.0 callback request", claims.Uid) - utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidToken) - return - } - - c.SetTokenClaims(claims) - c.SetTokenContext(tokenContext) - c.Next() } -func jwtAuthorization(c *core.WebContext, source TokenSourceType) { - claims, tokenContext, err := getTokenClaims(c, source) +func jwtAuthorization(config *settings.Config, source TokenSourceType) core.MiddlewareHandlerFunc { + return func(c *core.WebContext) { + claims, tokenContext, err := getTokenClaims(c, source) - if err != nil { - utils.PrintJsonErrorResult(c, err) - return + if err != nil { + utils.PrintJsonErrorResult(c, err) + return + } + + if claims.Type == core.USER_TOKEN_TYPE_REQUIRE_2FA { + log.Warnf(c, "[authorization.jwtAuthorization] user \"uid:%d\" token requires 2fa", claims.Uid) + utils.PrintJsonErrorResult(c, errs.ErrCurrentTokenRequire2FA) + return + } + + if claims.Type != core.USER_TOKEN_TYPE_NORMAL && claims.Type != core.USER_TOKEN_TYPE_API { + log.Warnf(c, "[authorization.jwtAuthorization] user \"uid:%d\" token type (%d) is invalid", claims.Uid, claims.Type) + utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidTokenType) + return + } + + if claims.Type == core.USER_TOKEN_TYPE_API && !config.EnableAPIToken { + log.Warnf(c, "[authorization.jwtAuthorization] api token is not enabled") + utils.PrintJsonErrorResult(c, errs.ErrAPITokenNotEnabled) + return + } + + c.SetTokenClaims(claims) + c.SetTokenContext(tokenContext) + c.Next() } - - if claims.Type == core.USER_TOKEN_TYPE_REQUIRE_2FA { - log.Warnf(c, "[authorization.jwtAuthorization] user \"uid:%d\" token requires 2fa", claims.Uid) - utils.PrintJsonErrorResult(c, errs.ErrCurrentTokenRequire2FA) - return - } - - if claims.Type != core.USER_TOKEN_TYPE_NORMAL && claims.Type != core.USER_TOKEN_TYPE_API { - log.Warnf(c, "[authorization.jwtAuthorization] user \"uid:%d\" token type (%d) is invalid", claims.Uid, claims.Type) - utils.PrintJsonErrorResult(c, errs.ErrCurrentInvalidTokenType) - return - } - - c.SetTokenClaims(claims) - c.SetTokenContext(tokenContext) - c.Next() } func getTokenClaims(c *core.WebContext, source TokenSourceType) (*core.UserTokenClaims, string, *errs.Error) { diff --git a/pkg/settings/setting.go b/pkg/settings/setting.go index feca6091..391a2471 100644 --- a/pkg/settings/setting.go +++ b/pkg/settings/setting.go @@ -357,7 +357,7 @@ type Config struct { EmailVerifyTokenExpiredTimeDuration time.Duration PasswordResetTokenExpiredTime uint32 PasswordResetTokenExpiredTimeDuration time.Duration - EnableGenerateAPIToken bool + EnableAPIToken bool MaxFailuresPerIpPerMinute uint32 MaxFailuresPerUserPerMinute uint32 @@ -978,7 +978,7 @@ func loadSecurityConfiguration(config *Config, configFile *ini.File, sectionName config.PasswordResetTokenExpiredTimeDuration = time.Duration(config.PasswordResetTokenExpiredTime) * time.Second - config.EnableGenerateAPIToken = getConfigItemBoolValue(configFile, sectionName, "enable_generate_api_token", false) + config.EnableAPIToken = getConfigItemBoolValue(configFile, sectionName, "enable_api_token", false) config.MaxFailuresPerIpPerMinute = getConfigItemUint32Value(configFile, sectionName, "max_failures_per_ip_per_minute", defaultMaxFailuresPerIpPerMinute) config.MaxFailuresPerUserPerMinute = getConfigItemUint32Value(configFile, sectionName, "max_failures_per_user_per_minute", defaultMaxFailuresPerUserPerMinute) diff --git a/src/lib/server_settings.ts b/src/lib/server_settings.ts index ea0662b1..8eb546dc 100644 --- a/src/lib/server_settings.ts +++ b/src/lib/server_settings.ts @@ -19,7 +19,7 @@ export function isUserForgetPasswordEnabled(): boolean { return getServerSetting('f') === 1; } -export function isGenerateAPITokenEnabled(): boolean { +export function isAPITokenEnabled(): boolean { return getServerSetting('t') === 1; } diff --git a/src/locales/de.json b/src/locales/de.json index 3ec02d03..12319f7c 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1109,7 +1109,7 @@ "token is empty": "Token ist leer", "email verify token is invalid or expired": "E-Mail-Verifizierungstoken ist ungültig oder abgelaufen", "password reset token is invalid or expired": "Passwort-Zurücksetzungstoken ist ungültig oder abgelaufen", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "Passcode ist ungültig", "two-factor backup code is invalid": "Zwei-Faktor-Backup-Code ist ungültig", "two-factor is not enabled": "Zwei-Faktor-Authentifizierung ist nicht aktiviert", diff --git a/src/locales/en.json b/src/locales/en.json index b7027335..0cdac330 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1109,7 +1109,7 @@ "token is empty": "Token is empty", "email verify token is invalid or expired": "Email verify token is invalid or expired", "password reset token is invalid or expired": "Password reset token is invalid or expired", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "Passcode is invalid", "two-factor backup code is invalid": "Two-factor backup code is invalid", "two-factor is not enabled": "Two-factor is not enabled", diff --git a/src/locales/es.json b/src/locales/es.json index 925bb64e..60298f87 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -1109,7 +1109,7 @@ "token is empty": "El token está vacío.", "email verify token is invalid or expired": "El token de verificación de correo electrónico no es válido o ha caducado", "password reset token is invalid or expired": "El token de restablecimiento de contraseña no es válido o ha caducado", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "El código de acceso no es válido", "two-factor backup code is invalid": "El código de respaldo de dos factores no es válido", "two-factor is not enabled": "El doble factor no está habilitado", diff --git a/src/locales/fr.json b/src/locales/fr.json index 42c7baa2..079838f5 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1109,7 +1109,7 @@ "token is empty": "Le token est vide", "email verify token is invalid or expired": "Le token de vérification d'email est invalide ou expiré", "password reset token is invalid or expired": "Le token de réinitialisation de mot de passe est invalide ou expiré", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "Le code d'accès est invalide", "two-factor backup code is invalid": "Le code de sauvegarde à deux facteurs est invalide", "two-factor is not enabled": "L'authentification à deux facteurs n'est pas activée", diff --git a/src/locales/it.json b/src/locales/it.json index fcbbcca9..433bfc28 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -1109,7 +1109,7 @@ "token is empty": "Token vuoto", "email verify token is invalid or expired": "Il token di verifica email non è valido o è scaduto", "password reset token is invalid or expired": "Il token di reimpostazione della password non è valido o è scaduto", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "Passcode non valido", "two-factor backup code is invalid": "Codice di backup a due fattori non valido", "two-factor is not enabled": "L'autenticazione a due fattori non è abilitata", diff --git a/src/locales/ja.json b/src/locales/ja.json index f66aa24e..9f9b8e5c 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1109,7 +1109,7 @@ "token is empty": "トークンを記入してください", "email verify token is invalid or expired": "メール認証トークンが無効または期限切れです", "password reset token is invalid or expired": "パスワードリセットトークンが無効または期限切れです", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "パスコードが無効です", "two-factor backup code is invalid": "二要素バックアップコードが無効です", "two-factor is not enabled": "二要素が有効になっていません", diff --git a/src/locales/ko.json b/src/locales/ko.json index a7636f28..87556979 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1109,7 +1109,7 @@ "token is empty": "토큰이 비어 있습니다", "email verify token is invalid or expired": "이메일 확인 토큰이 유효하지 않거나 만료되었습니다", "password reset token is invalid or expired": "비밀번호 재설정 토큰이 유효하지 않거나 만료되었습니다", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "일회용 비밀번호가 유효하지 않습니다", "two-factor backup code is invalid": "2단계 백업 코드가 유효하지 않습니다", "two-factor is not enabled": "2단계 인증이 활성화되지 않았습니다", diff --git a/src/locales/nl.json b/src/locales/nl.json index 9f7b3d94..0ee5d3a1 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -1109,7 +1109,7 @@ "token is empty": "Token is leeg", "email verify token is invalid or expired": "E-mailverificatietoken is ongeldig of verlopen", "password reset token is invalid or expired": "Wachtwoord-resettoken is ongeldig of verlopen", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "Verificatiecode is ongeldig", "two-factor backup code is invalid": "Back-upcode voor twee-stapsverificatie is ongeldig", "two-factor is not enabled": "Twee-stapsverificatie is niet ingeschakeld", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index 50b57f4b..1a5d90dd 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -1109,7 +1109,7 @@ "token is empty": "Token está vazio", "email verify token is invalid or expired": "O token de verificação de e-mail é inválido ou expirado", "password reset token is invalid or expired": "O token de redefinição de senha é inválido ou expirado", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "Código é inválido", "two-factor backup code is invalid": "Código de backup de duas etapas é inválido", "two-factor is not enabled": "Autenticação em duas etapas não está ativada", diff --git a/src/locales/ru.json b/src/locales/ru.json index 1622f5b6..b2c64cb4 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1109,7 +1109,7 @@ "token is empty": "Токен пуст", "email verify token is invalid or expired": "Токен подтверждения электронной почты недействителен или истек", "password reset token is invalid or expired": "Токен сброса пароля недействителен или истек", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "Код доступа недействителен", "two-factor backup code is invalid": "Резервный код двухфакторной аутентификации недействителен", "two-factor is not enabled": "Двухфакторная аутентификация не включена", diff --git a/src/locales/th.json b/src/locales/th.json index b070c647..6aa264d9 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -1109,7 +1109,7 @@ "token is empty": "โทเค็นว่างเปล่า", "email verify token is invalid or expired": "โทเค็นยืนยันอีเมลไม่ถูกต้องหรือหมดอายุ", "password reset token is invalid or expired": "โทเค็นรีเซ็ตรหัสผ่านไม่ถูกต้องหรือหมดอายุ", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "รหัสผ่านชั่วคราวไม่ถูกต้อง", "two-factor backup code is invalid": "รหัสสำรองสองขั้นตอนไม่ถูกต้อง", "two-factor is not enabled": "ยังไม่ได้เปิดใช้งานการยืนยันสองขั้นตอน", diff --git a/src/locales/uk.json b/src/locales/uk.json index 9e290b44..7bf02dc2 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -1109,7 +1109,7 @@ "token is empty": "Токен порожній", "email verify token is invalid or expired": "Токен підтвердження електронної пошти недійсний або прострочений", "password reset token is invalid or expired": "Токен скидання пароля недійсний або прострочений", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "Код доступу недійсний", "two-factor backup code is invalid": "Резервний код двофакторної автентифікації недійсний", "two-factor is not enabled": "Двофакторна автентифікація не увімкнена", diff --git a/src/locales/vi.json b/src/locales/vi.json index 52b09b3c..42deeef7 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -1109,7 +1109,7 @@ "token is empty": "Mã thông báo trống", "email verify token is invalid or expired": "Mã thông báo xác minh email không hợp lệ hoặc đã hết hạn", "password reset token is invalid or expired": "Mã thông báo đặt lại mật khẩu không hợp lệ hoặc đã hết hạn", - "not allowed to generate api token": "Not allowed to generate API token", + "api token is not enabled": "API token is not enabled", "passcode is invalid": "Mã số không hợp lệ", "two-factor backup code is invalid": "Mã sao lưu hai yếu tố không hợp lệ", "two-factor is not enabled": "Xác thực hai yếu tố chưa được bật", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 40e5c887..bd73dc5f 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -1109,7 +1109,7 @@ "token is empty": "认证令牌为空", "email verify token is invalid or expired": "邮箱验证令牌无效或已过期", "password reset token is invalid or expired": "密码重置令牌无效或已过期", - "not allowed to generate api token": "不允许生成 API 认证令牌", + "api token is not enabled": "API 令牌没有启用", "passcode is invalid": "验证码无效", "two-factor backup code is invalid": "两步验证备用码无效", "two-factor is not enabled": "两步验证没有启用", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index a4d66f3a..882f13e4 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -1109,7 +1109,7 @@ "token is empty": "驗證令牌為空", "email verify token is invalid or expired": "電子郵件驗證令牌無效或已過期", "password reset token is invalid or expired": "密碼重設令牌無效或已過期", - "not allowed to generate api token": "不允許產生 API 認證令牌", + "api token is not enabled": "API 令牌未啟用", "passcode is invalid": "驗證碼無效", "two-factor backup code is invalid": "二步驟驗證備用碼無效", "two-factor is not enabled": "二步驟驗證沒有啟用", diff --git a/src/views/desktop/user/settings/dialogs/UserGenerateTokenDialog.vue b/src/views/desktop/user/settings/dialogs/UserGenerateTokenDialog.vue index e42f9f8c..8e180727 100644 --- a/src/views/desktop/user/settings/dialogs/UserGenerateTokenDialog.vue +++ b/src/views/desktop/user/settings/dialogs/UserGenerateTokenDialog.vue @@ -123,7 +123,7 @@ import { useTokensStore } from '@/stores/token.ts'; import { type NameValue } from '@/core/base.ts'; import { type TokenGenerateMCPResponse } from '@/models/token.ts'; -import { isGenerateAPITokenEnabled, isMCPServerEnabled } from '@/lib/server_settings.ts'; +import { isAPITokenEnabled, isMCPServerEnabled } from '@/lib/server_settings.ts'; import { copyTextToClipboard } from '@/lib/ui/common.ts'; type SnackBarType = InstanceType; @@ -139,7 +139,7 @@ let resolveFunc: (() => void) | null = null; let rejectFunc: ((reason?: unknown) => void) | null = null; const showState = ref(false); -const tokenType = ref<'api' | 'mcp'>(isGenerateAPITokenEnabled() ? 'api' : (isMCPServerEnabled() ? 'mcp' : 'api')); +const tokenType = ref<'api' | 'mcp'>(isAPITokenEnabled() ? 'api' : (isMCPServerEnabled() ? 'mcp' : 'api')); const tokenExpirationTime = ref(86400); const tokenCustomExpirationTime = ref(86400); const currentPassword = ref(''); @@ -151,7 +151,7 @@ const generatedToken = ref(''); const tokenTypeOptions = computed(() => { const options: NameValue[] = []; - if (isGenerateAPITokenEnabled()) { + if (isAPITokenEnabled()) { options.push({ name: tt('API Token'), value: 'api' }); } @@ -179,7 +179,7 @@ const mcpServerConfiguration = computed(() => { function open(): Promise { showState.value = true; currentPassword.value = ''; - tokenType.value = isGenerateAPITokenEnabled() ? 'api' : (isMCPServerEnabled() ? 'mcp' : 'api'); + tokenType.value = isAPITokenEnabled() ? 'api' : (isMCPServerEnabled() ? 'mcp' : 'api'); tokenExpirationTime.value = 86400; tokenCustomExpirationTime.value = 86400; generating.value = false; diff --git a/src/views/desktop/user/settings/tabs/UserSecuritySettingTab.vue b/src/views/desktop/user/settings/tabs/UserSecuritySettingTab.vue index 13be7684..363548f2 100644 --- a/src/views/desktop/user/settings/tabs/UserSecuritySettingTab.vue +++ b/src/views/desktop/user/settings/tabs/UserSecuritySettingTab.vue @@ -132,7 +132,7 @@
{{ tt('Device & Sessions') }} {{ tt('Generate Token') }} + @click="generateToken" v-if="isAPITokenEnabled() || isMCPServerEnabled()">{{ tt('Generate Token') }}