diff --git a/cmd/user_data.go b/cmd/user_data.go index 610a8933..eba9b110 100644 --- a/cmd/user_data.go +++ b/cmd/user_data.go @@ -264,7 +264,13 @@ var UserData = &cli.Command{ Name: "type", Aliases: []string{"t"}, Required: false, - Usage: "Specific token type, supports \"normal\" and \"mcp\", default is \"normal\"", + Usage: "Specific token type, supports \"api\" and \"mcp\", default is \"api\"", + }, + &cli.Int64Flag{ + Name: "expiresInSeconds", + Aliases: []string{"e"}, + Required: true, + Usage: "Token expiration time in seconds (0 - 4294967295, 0 means no expiration).", }, }, }, @@ -722,17 +728,23 @@ func createNewUserToken(c *core.CliContext) error { username := c.String("username") tokenType := c.String("type") + expiresInSeconds := c.Int64("expiresInSeconds") if tokenType == "" { - tokenType = "normal" + tokenType = "api" } - if tokenType != "normal" && tokenType != "mcp" { + if tokenType != "api" && tokenType != "mcp" { log.CliErrorf(c, "[user_data.createNewUserToken] token type is invalid") return nil } - token, tokenString, err := clis.UserData.CreateNewUserToken(c, username, tokenType) + if expiresInSeconds < 0 || expiresInSeconds > 4294967295 { + log.CliErrorf(c, "[user_data.createNewUserToken] expiresInSeconds is out of range (0 - 4294967295)") + return nil + } + + token, tokenString, err := clis.UserData.CreateNewUserToken(c, username, tokenType, expiresInSeconds) if err != nil { log.CliErrorf(c, "[user_data.createNewUserToken] error occurs when creating user token") diff --git a/cmd/webserver.go b/cmd/webserver.go index 83cde5d4..233622e7 100644 --- a/cmd/webserver.go +++ b/cmd/webserver.go @@ -318,6 +318,7 @@ func startWebServer(c *core.CliContext) error { { // Tokens apiV1Route.GET("/tokens/list.json", bindApi(api.Tokens.TokenListHandler)) + apiV1Route.POST("/tokens/generate/api.json", bindApi(api.Tokens.TokenGenerateAPIHandler)) apiV1Route.POST("/tokens/generate/mcp.json", bindApi(api.Tokens.TokenGenerateMCPHandler)) apiV1Route.POST("/tokens/revoke.json", bindApi(api.Tokens.TokenRevokeHandler)) apiV1Route.POST("/tokens/revoke_all.json", bindApi(api.Tokens.TokenRevokeAllHandler)) diff --git a/conf/ezbookkeeping.ini b/conf/ezbookkeeping.ini index 7813012e..5e8aec32 100644 --- a/conf/ezbookkeeping.ini +++ b/conf/ezbookkeeping.ini @@ -263,6 +263,9 @@ email_verify_token_expired_time = 3600 # Password reset token expired seconds (60 - 4294967295), default is 3600 (60 minutes) password_reset_token_expired_time = 3600 +# Set to true to enable API token generation +enable_generate_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 @@ -382,6 +385,7 @@ max_user_avatar_size = 1048576 # 14: Create Transactions from AI Image Recognition # 15: OAuth 2.0 Login # 16: Unlink Third-party Login +# 17: Generate API Token default_feature_restrictions = [data] diff --git a/pkg/api/server_settings.go b/pkg/api/server_settings.go index 60e76cbb..1842adab 100644 --- a/pkg/api/server_settings.go +++ b/pkg/api/server_settings.go @@ -39,6 +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, "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 5c8f9715..e0978714 100644 --- a/pkg/api/tokens.go +++ b/pkg/api/tokens.go @@ -69,7 +69,9 @@ func (a *TokensApi) TokenListHandler(c *core.WebContext) (any, *errs.Error) { tokenResp.IsCurrent = true } - if token.TokenType == core.USER_TOKEN_TYPE_MCP && token.UserAgent != services.TokenUserAgentCreatedViaCli { + if token.TokenType == core.USER_TOKEN_TYPE_API && token.UserAgent != services.TokenUserAgentCreatedViaCli { + tokenResp.UserAgent = services.TokenUserAgentForAPI + } else if token.TokenType == core.USER_TOKEN_TYPE_MCP && token.UserAgent != services.TokenUserAgentCreatedViaCli { tokenResp.UserAgent = services.TokenUserAgentForMCP } @@ -81,6 +83,52 @@ func (a *TokensApi) TokenListHandler(c *core.WebContext) (any, *errs.Error) { return tokenResps, nil } +// 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 + } + + var generateAPITokenReq models.TokenGenerateAPIRequest + err := c.ShouldBindJSON(&generateAPITokenReq) + + if err != nil { + log.Warnf(c, "[tokens.TokenGenerateAPIHandler] parse request failed, because %s", err.Error()) + return nil, errs.NewIncompleteOrIncorrectSubmissionError(err) + } + + uid := c.GetCurrentUid() + user, err := a.users.GetUserById(c, uid) + + if err != nil { + log.Warnf(c, "[tokens.TokenGenerateAPIHandler] failed to get user \"uid:%d\" info, because %s", uid, err.Error()) + return nil, errs.ErrUserNotFound + } + + if user.FeatureRestriction.Contains(core.USER_FEATURE_RESTRICTION_TYPE_GENERATE_API_TOKEN) { + return false, errs.ErrNotPermittedToPerformThisAction + } + + if !a.users.IsPasswordEqualsUserPassword(generateAPITokenReq.Password, user) { + return nil, errs.ErrUserPasswordWrong + } + + token, claims, err := a.tokens.CreateAPIToken(c, user, generateAPITokenReq.ExpiredInSeconds) + + if err != nil { + log.Errorf(c, "[tokens.TokenGenerateAPIHandler] failed to create api token for user \"uid:%d\", because %s", user.Uid, err.Error()) + return nil, errs.Or(err, errs.ErrTokenGenerating) + } + + log.Infof(c, "[tokens.TokenGenerateAPIHandler] user \"uid:%d\" has generated api token, new token will be expired at %d", user.Uid, claims.ExpiresAt) + + generateAPITokenResp := &models.TokenGenerateAPIResponse{ + Token: token, + } + + return generateAPITokenResp, nil +} + // TokenGenerateMCPHandler generates a new MCP token for current user func (a *TokensApi) TokenGenerateMCPHandler(c *core.WebContext) (any, *errs.Error) { if !a.CurrentConfig().EnableMCPServer { @@ -111,7 +159,7 @@ func (a *TokensApi) TokenGenerateMCPHandler(c *core.WebContext) (any, *errs.Erro return nil, errs.ErrUserPasswordWrong } - token, claims, err := a.tokens.CreateMCPToken(c, user) + token, claims, err := a.tokens.CreateMCPToken(c, user, generateMCPTokenReq.ExpiredInSeconds) if err != nil { log.Errorf(c, "[tokens.TokenGenerateMCPHandler] failed to create mcp token for user \"uid:%d\", because %s", user.Uid, err.Error()) diff --git a/pkg/cli/user_data.go b/pkg/cli/user_data.go index c59e2d4a..e24c6e40 100644 --- a/pkg/cli/user_data.go +++ b/pkg/cli/user_data.go @@ -405,7 +405,7 @@ func (l *UserDataCli) ListUserTokens(c *core.CliContext, username string) ([]*mo } // CreateNewUserToken returns a new token for the specified user -func (l *UserDataCli) CreateNewUserToken(c *core.CliContext, username string, tokenType string) (*models.TokenRecord, string, error) { +func (l *UserDataCli) CreateNewUserToken(c *core.CliContext, username string, tokenType string, expiresInSeconds int64) (*models.TokenRecord, string, error) { if username == "" { log.CliErrorf(c, "[user_data.CreateNewUserToken] user name is empty") return nil, "", errs.ErrUsernameIsEmpty @@ -421,7 +421,17 @@ func (l *UserDataCli) CreateNewUserToken(c *core.CliContext, username string, to var token string var tokenRecord *models.TokenRecord - if tokenType == "mcp" { + if tokenType == "api" { + if !l.CurrentConfig().EnableGenerateAPIToken { + return nil, "", errs.ErrNotAllowedToGenerateAPIToken + } + + if user.FeatureRestriction.Contains(core.USER_FEATURE_RESTRICTION_TYPE_GENERATE_API_TOKEN) { + return nil, "", errs.ErrNotPermittedToPerformThisAction + } + + token, tokenRecord, err = l.tokens.CreateAPITokenViaCli(c, user, expiresInSeconds) + } else if tokenType == "mcp" { if !l.CurrentConfig().EnableMCPServer { return nil, "", errs.ErrMCPServerNotEnabled } @@ -430,9 +440,7 @@ func (l *UserDataCli) CreateNewUserToken(c *core.CliContext, username string, to return nil, "", errs.ErrNotPermittedToPerformThisAction } - token, tokenRecord, err = l.tokens.CreateMCPTokenViaCli(c, user) - } else if tokenType == "normal" { - token, tokenRecord, err = l.tokens.CreateTokenViaCli(c, user) + token, tokenRecord, err = l.tokens.CreateMCPTokenViaCli(c, user, expiresInSeconds) } else { return nil, "", errs.ErrParameterInvalid } diff --git a/pkg/core/context_cli.go b/pkg/core/context_cli.go index 60d07a43..14b355b9 100644 --- a/pkg/core/context_cli.go +++ b/pkg/core/context_cli.go @@ -32,6 +32,11 @@ func (c *CliContext) Int(name string) int { return c.command.Int(name) } +// Int64 returns the long integer value of parameter +func (c *CliContext) Int64(name string) int64 { + return c.command.Int64(name) +} + // String returns the string value of parameter func (c *CliContext) String(name string) string { return c.command.String(name) diff --git a/pkg/core/token_claims.go b/pkg/core/token_claims.go index b0242e80..cd98c5e0 100644 --- a/pkg/core/token_claims.go +++ b/pkg/core/token_claims.go @@ -18,6 +18,7 @@ const ( USER_TOKEN_TYPE_MCP TokenType = 5 USER_TOKEN_TYPE_OAUTH2_CALLBACK_REQUIRE_VERIFY TokenType = 6 USER_TOKEN_TYPE_OAUTH2_CALLBACK TokenType = 7 + USER_TOKEN_TYPE_API TokenType = 8 ) // UserTokenClaims represents user token diff --git a/pkg/core/user_feature_restriction.go b/pkg/core/user_feature_restriction.go index 76519d1d..7939f7da 100644 --- a/pkg/core/user_feature_restriction.go +++ b/pkg/core/user_feature_restriction.go @@ -92,10 +92,11 @@ const ( USER_FEATURE_RESTRICTION_TYPE_CREATE_TRANSACTION_FROM_AI_IMAGE_RECOGNITION UserFeatureRestrictionType = 14 USER_FEATURE_RESTRICTION_TYPE_OAUTH2_LOGIN UserFeatureRestrictionType = 15 USER_FEATURE_RESTRICTION_TYPE_UNLINK_THIRD_PARTY_LOGIN UserFeatureRestrictionType = 16 + USER_FEATURE_RESTRICTION_TYPE_GENERATE_API_TOKEN UserFeatureRestrictionType = 17 ) const userFeatureRestrictionTypeMinValue UserFeatureRestrictionType = USER_FEATURE_RESTRICTION_TYPE_UPDATE_PASSWORD -const userFeatureRestrictionTypeMaxValue UserFeatureRestrictionType = USER_FEATURE_RESTRICTION_TYPE_UNLINK_THIRD_PARTY_LOGIN +const userFeatureRestrictionTypeMaxValue UserFeatureRestrictionType = USER_FEATURE_RESTRICTION_TYPE_GENERATE_API_TOKEN // String returns a textual representation of the restriction type of user features func (t UserFeatureRestrictionType) String() string { @@ -132,6 +133,8 @@ func (t UserFeatureRestrictionType) String() string { return "OAuth 2.0 Login" case USER_FEATURE_RESTRICTION_TYPE_UNLINK_THIRD_PARTY_LOGIN: return "Unlink Third-Party Login" + case USER_FEATURE_RESTRICTION_TYPE_GENERATE_API_TOKEN: + return "Generate API Token" default: return fmt.Sprintf("Invalid(%d)", int(t)) } diff --git a/pkg/errs/token.go b/pkg/errs/token.go index af326421..ab5c89f9 100644 --- a/pkg/errs/token.go +++ b/pkg/errs/token.go @@ -21,4 +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") ) diff --git a/pkg/middlewares/authorization.go b/pkg/middlewares/authorization.go index 3ef96d80..7fa2e06f 100644 --- a/pkg/middlewares/authorization.go +++ b/pkg/middlewares/authorization.go @@ -149,7 +149,7 @@ func jwtAuthorization(c *core.WebContext, source TokenSourceType) { return } - if claims.Type != core.USER_TOKEN_TYPE_NORMAL { + 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 diff --git a/pkg/models/token_record.go b/pkg/models/token_record.go index 250f848d..f138f9f9 100644 --- a/pkg/models/token_record.go +++ b/pkg/models/token_record.go @@ -25,9 +25,16 @@ type OAuth2CallbackTokenContext struct { ExternalEmail string `json:"externalEmail"` } +// TokenGenerateAPIRequest represents all parameters of api token generation request +type TokenGenerateAPIRequest struct { + ExpiredInSeconds int64 `json:"expiresInSeconds" binding:"omitempty,min=0,max=4294967295"` + Password string `json:"password" binding:"omitempty,min=6,max=128"` +} + // TokenGenerateMCPRequest represents all parameters of mcp token generation request type TokenGenerateMCPRequest struct { - Password string `json:"password" binding:"omitempty,min=6,max=128"` + ExpiredInSeconds int64 `json:"expiresInSeconds" binding:"omitempty,min=0,max=4294967295"` + Password string `json:"password" binding:"omitempty,min=6,max=128"` } // TokenRevokeRequest represents all parameters of token revoking request @@ -35,6 +42,11 @@ type TokenRevokeRequest struct { TokenId string `json:"tokenId" binding:"required,notBlank"` } +// TokenGenerateAPIResponse represents all response parameters of generated api token +type TokenGenerateAPIResponse struct { + Token string `json:"token"` +} + // TokenGenerateMCPResponse represents all response parameters of generated mcp token type TokenGenerateMCPResponse struct { Token string `json:"token"` diff --git a/pkg/services/tokens.go b/pkg/services/tokens.go index 5664ab74..74f06490 100644 --- a/pkg/services/tokens.go +++ b/pkg/services/tokens.go @@ -23,6 +23,9 @@ import ( // TokenUserAgentCreatedViaCli is the user agent of token created via cli const TokenUserAgentCreatedViaCli = "ezbookkeeping Cli" +// TokenUserAgentForAPI is the user agent for API token +const TokenUserAgentForAPI = "ezbookkeeping API" + // TokenUserAgentForMCP is the user agent for MCP token const TokenUserAgentForMCP = "ezbookkeeping MCP" @@ -67,7 +70,7 @@ func (s *TokenService) GetAllUnexpiredNormalAndMCPTokensByUid(c core.Context, ui now := time.Now().Unix() var tokenRecords []*models.TokenRecord - err := s.TokenDB(uid).NewSession(c).Cols("uid", "user_token_id", "token_type", "user_agent", "created_unix_time", "expired_unix_time", "last_seen_unix_time").Where("uid=? AND (token_type=? OR token_type=?) AND expired_unix_time>?", uid, core.USER_TOKEN_TYPE_NORMAL, core.USER_TOKEN_TYPE_MCP, now).Find(&tokenRecords) + err := s.TokenDB(uid).NewSession(c).Cols("uid", "user_token_id", "token_type", "user_agent", "created_unix_time", "expired_unix_time", "last_seen_unix_time").Where("uid=? AND (token_type=? OR token_type=? OR token_type=?) AND expired_unix_time>?", uid, core.USER_TOKEN_TYPE_NORMAL, core.USER_TOKEN_TYPE_MCP, core.USER_TOKEN_TYPE_API, now).Find(&tokenRecords) return tokenRecords, err } @@ -77,12 +80,6 @@ func (s *TokenService) ParseToken(c core.Context, token string) (*jwt.Token, *co return s.parseToken(c, token) } -// CreateTokenViaCli generates a new normal token and saves to database -func (s *TokenService) CreateTokenViaCli(c *core.CliContext, user *models.User) (string, *models.TokenRecord, error) { - token, _, tokenRecord, err := s.createToken(c, user, core.USER_TOKEN_TYPE_NORMAL, TokenUserAgentCreatedViaCli, "", s.CurrentConfig().TokenExpiredTimeDuration) - return token, tokenRecord, err -} - // CreateToken generates a new normal token and saves to database func (s *TokenService) CreateToken(c *core.WebContext, user *models.User) (string, *core.UserTokenClaims, error) { token, claims, _, err := s.createToken(c, user, core.USER_TOKEN_TYPE_NORMAL, s.getUserAgent(c), "", s.CurrentConfig().TokenExpiredTimeDuration) @@ -119,16 +116,58 @@ func (s *TokenService) CreatePasswordResetTokenWithoutUserAgent(c core.Context, return token, claims, err } +// CreateAPIToken generates a new API token and saves to database +func (s *TokenService) CreateAPIToken(c *core.WebContext, user *models.User, expiresInSeconds int64) (string, *core.UserTokenClaims, error) { + var tokenExpiredTimeDuration time.Duration + + if expiresInSeconds > 0 { + tokenExpiredTimeDuration = time.Duration(expiresInSeconds) * time.Second + } else { + tokenExpiredTimeDuration = time.Unix(tokenMaxExpiredAtUnixTime, 0).Sub(time.Now()) + } + + token, claims, _, err := s.createToken(c, user, core.USER_TOKEN_TYPE_API, s.getUserAgent(c), "", tokenExpiredTimeDuration) + return token, claims, err +} + +// CreateAPITokenViaCli generates a new API token and saves to database +func (s *TokenService) CreateAPITokenViaCli(c *core.CliContext, user *models.User, expiresInSeconds int64) (string, *models.TokenRecord, error) { + var tokenExpiredTimeDuration time.Duration + + if expiresInSeconds > 0 { + tokenExpiredTimeDuration = time.Duration(expiresInSeconds) * time.Second + } else { + tokenExpiredTimeDuration = time.Unix(tokenMaxExpiredAtUnixTime, 0).Sub(time.Now()) + } + + token, _, tokenRecord, err := s.createToken(c, user, core.USER_TOKEN_TYPE_API, TokenUserAgentCreatedViaCli, "", tokenExpiredTimeDuration) + return token, tokenRecord, err +} + // CreateMCPToken generates a new MCP token and saves to database -func (s *TokenService) CreateMCPToken(c *core.WebContext, user *models.User) (string, *core.UserTokenClaims, error) { - tokenExpiredTimeDuration := time.Unix(tokenMaxExpiredAtUnixTime, 0).Sub(time.Now()) +func (s *TokenService) CreateMCPToken(c *core.WebContext, user *models.User, expiresInSeconds int64) (string, *core.UserTokenClaims, error) { + var tokenExpiredTimeDuration time.Duration + + if expiresInSeconds > 0 { + tokenExpiredTimeDuration = time.Duration(expiresInSeconds) * time.Second + } else { + tokenExpiredTimeDuration = time.Unix(tokenMaxExpiredAtUnixTime, 0).Sub(time.Now()) + } + token, claims, _, err := s.createToken(c, user, core.USER_TOKEN_TYPE_MCP, s.getUserAgent(c), "", tokenExpiredTimeDuration) return token, claims, err } // CreateMCPTokenViaCli generates a new MCP token and saves to database -func (s *TokenService) CreateMCPTokenViaCli(c *core.CliContext, user *models.User) (string, *models.TokenRecord, error) { - tokenExpiredTimeDuration := time.Unix(tokenMaxExpiredAtUnixTime, 0).Sub(time.Now()) +func (s *TokenService) CreateMCPTokenViaCli(c *core.CliContext, user *models.User, expiresInSeconds int64) (string, *models.TokenRecord, error) { + var tokenExpiredTimeDuration time.Duration + + if expiresInSeconds > 0 { + tokenExpiredTimeDuration = time.Duration(expiresInSeconds) * time.Second + } else { + tokenExpiredTimeDuration = time.Unix(tokenMaxExpiredAtUnixTime, 0).Sub(time.Now()) + } + token, _, tokenRecord, err := s.createToken(c, user, core.USER_TOKEN_TYPE_MCP, TokenUserAgentCreatedViaCli, "", tokenExpiredTimeDuration) return token, tokenRecord, err } diff --git a/pkg/settings/setting.go b/pkg/settings/setting.go index 92857d31..feca6091 100644 --- a/pkg/settings/setting.go +++ b/pkg/settings/setting.go @@ -357,6 +357,7 @@ type Config struct { EmailVerifyTokenExpiredTimeDuration time.Duration PasswordResetTokenExpiredTime uint32 PasswordResetTokenExpiredTimeDuration time.Duration + EnableGenerateAPIToken bool MaxFailuresPerIpPerMinute uint32 MaxFailuresPerUserPerMinute uint32 @@ -977,6 +978,8 @@ 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.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 5de4e607..ea0662b1 100644 --- a/src/lib/server_settings.ts +++ b/src/lib/server_settings.ts @@ -19,6 +19,10 @@ export function isUserForgetPasswordEnabled(): boolean { return getServerSetting('f') === 1; } +export function isGenerateAPITokenEnabled(): boolean { + return getServerSetting('t') === 1; +} + export function isUserVerifyEmailEnabled(): boolean { return getServerSetting('v') === 1; } diff --git a/src/lib/services.ts b/src/lib/services.ts index 52bb5541..31368911 100644 --- a/src/lib/services.ts +++ b/src/lib/services.ts @@ -112,8 +112,10 @@ import type { TransactionTemplateInfoResponse } from '@/models/transaction_template.ts'; import type { + TokenGenerateAPIRequest, TokenGenerateMCPRequest, TokenRevokeRequest, + TokenGenerateAPIResponse, TokenGenerateMCPResponse, TokenRefreshResponse, TokenInfoResponse @@ -345,6 +347,9 @@ export default { getTokens: (): ApiResponsePromise => { return axios.get>('v1/tokens/list.json'); }, + generateAPIToken: (req: TokenGenerateAPIRequest): ApiResponsePromise => { + return axios.post>('v1/tokens/generate/api.json', req); + }, generateMCPToken: (req: TokenGenerateMCPRequest): ApiResponsePromise => { return axios.post>('v1/tokens/generate/mcp.json', req); }, diff --git a/src/lib/session.ts b/src/lib/session.ts index 3d9b3b9f..aa4d99e0 100644 --- a/src/lib/session.ts +++ b/src/lib/session.ts @@ -1,9 +1,10 @@ import uaParser from 'ua-parser-js'; import { - TOKEN_TYPE_MCP, - TOKEN_CLI_USER_AGENT, type TokenInfoResponse, + TOKEN_TYPE_API, + TOKEN_TYPE_MCP, + SessionDeviceType, SessionInfo } from '@/models/token.ts'; @@ -43,10 +44,6 @@ function parseUserAgent(ua: string): UserAgentInfo { }; } -function isSessionUserAgentCreatedByCli(ua: string): boolean { - return ua === TOKEN_CLI_USER_AGENT; -} - function parseDeviceInfo(uaInfo: UserAgentInfo): string { if (!uaInfo) { return ''; @@ -86,30 +83,39 @@ function parseDeviceInfo(uaInfo: UserAgentInfo): string { } export function parseSessionInfo(token: TokenInfoResponse): SessionInfo { + const isCreateForAPI = token.tokenType === TOKEN_TYPE_API; const isCreateForMCP = token.tokenType === TOKEN_TYPE_MCP; - const isCreatedByCli = isSessionUserAgentCreatedByCli(token.userAgent); const uaInfo = parseUserAgent(token.userAgent); - let deviceType = ''; + let deviceType: SessionDeviceType = SessionDeviceType.Default; + let deviceName: string = 'Other Device'; - if (isCreateForMCP) { - deviceType = 'mcp'; - } else if (isCreatedByCli) { - deviceType = 'cli'; + if (isCreateForAPI) { + deviceType = SessionDeviceType.Api; + deviceName = 'API Token'; + } else if (isCreateForMCP) { + deviceType = SessionDeviceType.MCP; + deviceName = 'MCP Token'; } else { if (uaInfo && uaInfo.device) { if (uaInfo.device.type === 'mobile') { - deviceType = 'phone'; + deviceType = SessionDeviceType.Phone; } else if (uaInfo.device.type === 'wearable') { - deviceType = 'wearable'; + deviceType = SessionDeviceType.Wearable; } else if (uaInfo.device.type === 'tablet') { - deviceType = 'tablet'; + deviceType = SessionDeviceType.Tablet; } else if (uaInfo.device.type === 'smarttv') { - deviceType = 'tv'; + deviceType = SessionDeviceType.TV; } else { - deviceType = 'default'; + deviceType = SessionDeviceType.Default; } } else { - deviceType = 'default'; + deviceType = SessionDeviceType.Default; + } + + if (token.isCurrent) { + deviceName = 'Current'; + } else { + deviceName = 'Other Device'; } } @@ -117,8 +123,8 @@ export function parseSessionInfo(token: TokenInfoResponse): SessionInfo { token.tokenId, token.isCurrent, deviceType, - isCreateForMCP || isCreatedByCli ? token.userAgent : parseDeviceInfo(uaInfo), - isCreatedByCli, + isCreateForAPI || isCreateForMCP ? token.userAgent : parseDeviceInfo(uaInfo), + deviceName, token.lastSeen ); } diff --git a/src/locales/de.json b/src/locales/de.json index 31fb12f1..3ec02d03 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -107,6 +107,10 @@ "EndYY": "GJ {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "{hours} Stunde(n) hinter der Standardzeitzone", @@ -1105,6 +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", "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", @@ -1307,7 +1312,8 @@ "page": "Seitenindex", "count": "Anzahl", "templateType": "Vorlagentyp", - "comment": "Beschreibung" + "comment": "Beschreibung", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} ist ungültig", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Versteckte Transaktionsvorlagen anzeigen", "Hide Hidden Transaction Templates": "Versteckte Transaktionsvorlagen ausblenden", "Template name cannot be blank": "Vorlagenname darf nicht leer sein", - "Generate MCP token": "Generate MCP token", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Unable to generate token", "Are you sure you want to logout from this session?": "Sind Sie sicher, dass Sie sich von dieser Sitzung abmelden möchten?", "Unable to logout from this session": "Abmeldung von dieser Sitzung nicht möglich", diff --git a/src/locales/en.json b/src/locales/en.json index d397038c..b7027335 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -107,6 +107,10 @@ "EndYY": "FY {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "{hours} hour(s) behind default timezone", @@ -1105,6 +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", "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", @@ -1307,7 +1312,8 @@ "page": "Page Index", "count": "Count", "templateType": "Template Type", - "comment": "Description" + "comment": "Description", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} is invalid", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Show Hidden Transaction Templates", "Hide Hidden Transaction Templates": "Hide Hidden Transaction Templates", "Template name cannot be blank": "Template name cannot be blank", - "Generate MCP token": "Generate MCP token", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Unable to generate token", "Are you sure you want to logout from this session?": "Are you sure you want to logout from this session?", "Unable to logout from this session": "Unable to logout from this session", diff --git a/src/locales/es.json b/src/locales/es.json index 9b2b6e5c..925bb64e 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -107,6 +107,10 @@ "EndYY": "Ejercicio {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "{hours} hora(s) de retraso en la zona horaria predeterminada", @@ -1105,6 +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", "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", @@ -1307,7 +1312,8 @@ "page": "Índice de páginas", "count": "Contar", "templateType": "Tipo de plantilla", - "comment": "Descripción" + "comment": "Descripción", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} no es válido", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Mostrar plantillas de transacciones ocultas", "Hide Hidden Transaction Templates": "Ocultar plantillas de transacciones ocultas", "Template name cannot be blank": "El nombre de la plantilla no puede estar en blanco", - "Generate MCP token": "Generate MCP token", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Unable to generate token", "Are you sure you want to logout from this session?": "¿Está seguro de que desea cerrar sesión en esta sesión?", "Unable to logout from this session": "No se puede cerrar sesión en esta sesión", diff --git a/src/locales/fr.json b/src/locales/fr.json index d90698fd..42c7baa2 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -107,6 +107,10 @@ "EndYY": "Exercice {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "{hours} heure(s) de retard sur le fuseau horaire par défaut", @@ -1105,6 +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", "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", @@ -1307,7 +1312,8 @@ "page": "Index de page", "count": "Nombre", "templateType": "Type de modèle", - "comment": "Description" + "comment": "Description", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} est invalide", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Afficher les modèles de transaction masqués", "Hide Hidden Transaction Templates": "Masquer les modèles de transaction masqués", "Template name cannot be blank": "Le nom du modèle ne peut pas être vide", - "Generate MCP token": "Générer un jeton MCP", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Impossible de générer le jeton", "Are you sure you want to logout from this session?": "Êtes-vous sûr de vouloir vous déconnecter de cette session ?", "Unable to logout from this session": "Impossible de se déconnecter de cette session", diff --git a/src/locales/it.json b/src/locales/it.json index a93848cd..fcbbcca9 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -107,6 +107,10 @@ "EndYY": "AF {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "Indietro di {hours} ore rispetto al fuso orario standard", @@ -1105,6 +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", "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", @@ -1307,7 +1312,8 @@ "page": "Indice pagina", "count": "Conteggio", "templateType": "Tipo modello", - "comment": "Descrizione" + "comment": "Descrizione", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} non è valido", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Mostra modelli transazione nascosti", "Hide Hidden Transaction Templates": "Nascondi modelli transazione nascosti", "Template name cannot be blank": "Il nome del modello non può essere vuoto", - "Generate MCP token": "Generate MCP token", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Unable to generate token", "Are you sure you want to logout from this session?": "Sei sicuro di voler uscire da questa sessione?", "Unable to logout from this session": "Impossibile uscire da questa sessione", diff --git a/src/locales/ja.json b/src/locales/ja.json index 6149f5f6..f66aa24e 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -107,6 +107,10 @@ "EndYY": "{EndYY}年度" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": "、", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "デフォルトのタイムゾーンより{hours}時間遅れています", @@ -1105,6 +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", "passcode is invalid": "パスコードが無効です", "two-factor backup code is invalid": "二要素バックアップコードが無効です", "two-factor is not enabled": "二要素が有効になっていません", @@ -1307,7 +1312,8 @@ "page": "ページインデックス", "count": "カウント", "templateType": "テンプレートタイプ", - "comment": "説明" + "comment": "説明", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter}は無効です", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "非表示取引テンプレートを表示します", "Hide Hidden Transaction Templates": "非表示取引テンプレートを非表示にします", "Template name cannot be blank": "テンプレート名は空欄にできません", - "Generate MCP token": "Generate MCP token", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Unable to generate token", "Are you sure you want to logout from this session?": "このセッションからログアウトしますか?", "Unable to logout from this session": "このセッションからログアウトできません", diff --git a/src/locales/ko.json b/src/locales/ko.json index 176028e7..a7636f28 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -107,6 +107,10 @@ "EndYY": "{EndYY}년도" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "기본 시간대보다 {hours}시간 느립니다", @@ -1105,6 +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", "passcode is invalid": "일회용 비밀번호가 유효하지 않습니다", "two-factor backup code is invalid": "2단계 백업 코드가 유효하지 않습니다", "two-factor is not enabled": "2단계 인증이 활성화되지 않았습니다", @@ -1307,7 +1312,8 @@ "page": "페이지 인덱스", "count": "개수", "templateType": "템플릿 유형", - "comment": "설명" + "comment": "설명", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter}가 유효하지 않습니다", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "숨겨진 거래 템플릿 표시", "Hide Hidden Transaction Templates": "숨겨진 거래 템플릿 숨기기", "Template name cannot be blank": "템플릿 이름은 비워둘 수 없습니다.", - "Generate MCP token": "MCP 토큰 생성", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "토큰을 생성할 수 없습니다.", "Are you sure you want to logout from this session?": "이 세션에서 로그아웃하시겠습니까?", "Unable to logout from this session": "이 세션에서 로그아웃할 수 없습니다.", diff --git a/src/locales/nl.json b/src/locales/nl.json index 00fd25cd..9f7b3d94 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -107,6 +107,10 @@ "EndYY": "Boekjaar {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "{hours} uur achter standaardtijdzone", @@ -1105,6 +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", "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", @@ -1307,7 +1312,8 @@ "page": "Paginanummer", "count": "Aantal", "templateType": "Sjabloontype", - "comment": "Beschrijving" + "comment": "Beschrijving", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} is ongeldig", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Verborgen transactiesjablonen tonen", "Hide Hidden Transaction Templates": "Verborgen transactiesjablonen verbergen", "Template name cannot be blank": "Sjabloonnaam mag niet leeg zijn", - "Generate MCP token": "MCP-token genereren", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Kan token niet genereren", "Are you sure you want to logout from this session?": "Weet je zeker dat je deze sessie wilt uitloggen?", "Unable to logout from this session": "Kan niet uitloggen uit deze sessie", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index 27ba4579..50b57f4b 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -107,6 +107,10 @@ "EndYY": "AF {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "{hours} hora(s) atrás do fuso horário padrão", @@ -1105,6 +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", "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", @@ -1307,7 +1312,8 @@ "page": "Índice da Página", "count": "Quantidade", "templateType": "Tipo de Modelo", - "comment": "Descrição" + "comment": "Descrição", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} é inválido", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Mostrar Modelos de Transação Ocultos", "Hide Hidden Transaction Templates": "Ocultar Modelos de Transação Ocultos", "Template name cannot be blank": "O nome do modelo não pode estar em branco", - "Generate MCP token": "Generate MCP token", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Unable to generate token", "Are you sure you want to logout from this session?": "Tem certeza de que deseja sair desta sessão?", "Unable to logout from this session": "Não foi possível sair desta sessão", diff --git a/src/locales/ru.json b/src/locales/ru.json index 944464c9..1622f5b6 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -107,6 +107,10 @@ "EndYY": "ФГ {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "{hours} час(ов) позади часового пояса по умолчанию", @@ -1105,6 +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", "passcode is invalid": "Код доступа недействителен", "two-factor backup code is invalid": "Резервный код двухфакторной аутентификации недействителен", "two-factor is not enabled": "Двухфакторная аутентификация не включена", @@ -1307,7 +1312,8 @@ "page": "Индекс страницы", "count": "Количество", "templateType": "Тип шаблона", - "comment": "Описание" + "comment": "Описание", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} недействителен", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Показать скрытые шаблоны транзакций", "Hide Hidden Transaction Templates": "Скрыть скрытые шаблоны транзакций", "Template name cannot be blank": "Название шаблона не может быть пустым", - "Generate MCP token": "Generate MCP token", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Unable to generate token", "Are you sure you want to logout from this session?": "Вы уверены, что хотите выйти из этой сессии?", "Unable to logout from this session": "Не удалось выйти из этой сессии", diff --git a/src/locales/th.json b/src/locales/th.json index b5d9139d..b070c647 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -107,6 +107,10 @@ "EndYY": "ปีงบประมาณ {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "ช้ากว่าเขตเวลาเริ่มต้น {hours} ชั่วโมง", @@ -1105,6 +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", "passcode is invalid": "รหัสผ่านชั่วคราวไม่ถูกต้อง", "two-factor backup code is invalid": "รหัสสำรองสองขั้นตอนไม่ถูกต้อง", "two-factor is not enabled": "ยังไม่ได้เปิดใช้งานการยืนยันสองขั้นตอน", @@ -1307,7 +1312,8 @@ "page": "ดัชนีหน้า", "count": "จำนวน", "templateType": "ประเภทแม่แบบ", - "comment": "คำอธิบาย" + "comment": "คำอธิบาย", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} ไม่ถูกต้อง", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "แสดงแม่แบบรายการที่ซ่อนอยู่", "Hide Hidden Transaction Templates": "ซ่อนแม่แบบรายการที่ซ่อนอยู่", "Template name cannot be blank": "ชื่อแม่แบบไม่สามารถเว้นว่างได้", - "Generate MCP token": "สร้างโทเคน MCP", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "ไม่สามารถสร้างโทเคนได้", "Are you sure you want to logout from this session?": "คุณแน่ใจหรือว่าต้องการออกจากระบบเซสชันนี้?", "Unable to logout from this session": "ไม่สามารถออกจากระบบเซสชันนี้ได้", diff --git a/src/locales/uk.json b/src/locales/uk.json index 4003882a..9e290b44 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -107,6 +107,10 @@ "EndYY": "{EndYY} фінансовий рік" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "{hours} год позаду часового поясу за замовчуванням", @@ -1105,6 +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", "passcode is invalid": "Код доступу недійсний", "two-factor backup code is invalid": "Резервний код двофакторної автентифікації недійсний", "two-factor is not enabled": "Двофакторна автентифікація не увімкнена", @@ -1307,7 +1312,8 @@ "page": "Номер сторінки", "count": "Кількість", "templateType": "Тип шаблону", - "comment": "Опис" + "comment": "Опис", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} недійсний", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Показати приховані шаблони транзакцій", "Hide Hidden Transaction Templates": "Приховати приховані шаблони транзакцій", "Template name cannot be blank": "Назва шаблону не може бути порожньою", - "Generate MCP token": "Generate MCP token", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Unable to generate token", "Are you sure you want to logout from this session?": "Ви впевнені, що хочете вийти з цієї сесії?", "Unable to logout from this session": "Не вдалося вийти з цієї сесії", diff --git a/src/locales/vi.json b/src/locales/vi.json index ada7f906..52b09b3c 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -107,6 +107,10 @@ "EndYY": "FY {EndYY}" }, "misc": { + "nHour": "{n} Hour", + "nHours": "{n} Hours", + "nDay": "{n} Day", + "nDays": "{n} Days", "multiTextJoinSeparator": ", ", "loginWithCustomProvider": "Log in with {name}", "hoursBehindDefaultTimezone": "{hours} giờ sau múi giờ mặc định", @@ -1105,6 +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", "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", @@ -1307,7 +1312,8 @@ "page": "Chỉ số trang", "count": "Số lượng", "templateType": "Loại mẫu", - "comment": "Mô tả" + "comment": "Mô tả", + "expiredInSeconds": "Expiration Time (Seconds)" }, "parameterizedError": { "parameter invalid": "{parameter} không hợp lệ", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "Hiển thị mẫu giao dịch ẩn", "Hide Hidden Transaction Templates": "Ẩn mẫu giao dịch ẩn", "Template name cannot be blank": "Tên mẫu không được để trống", - "Generate MCP token": "Generate MCP token", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", + "Generate Token": "Generate Token", + "Token Type": "Token Type", + "Expiration Time (Seconds)": "Expiration Time (Seconds)", + "Custom Expiration Time (Seconds)": "Custom Expiration Time (Seconds)", + "No Expiration": "No Expiration", + "API Token": "API Token", + "MCP Token": "MCP Token", + "Your token does not expire, please keep it secure.": "Your token does not expire, please keep it secure.", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.", "Unable to generate token": "Unable to generate token", "Are you sure you want to logout from this session?": "Bạn có chắc chắn muốn đăng xuất khỏi phiên này không?", "Unable to logout from this session": "Không thể đăng xuất khỏi phiên này", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 5dbe0004..40e5c887 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -107,6 +107,10 @@ "EndYY": "{EndYY}财年" }, "misc": { + "nHour": "{n} 小时", + "nHours": "{n} 小时", + "nDay": "{n} 天", + "nDays": "{n} 天", "multiTextJoinSeparator": "、", "loginWithCustomProvider": "使用 {name} 登录", "hoursBehindDefaultTimezone": "比默认时区晚{hours}小时", @@ -1105,6 +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 认证令牌", "passcode is invalid": "验证码无效", "two-factor backup code is invalid": "两步验证备用码无效", "two-factor is not enabled": "两步验证没有启用", @@ -1307,7 +1312,8 @@ "page": "页码索引", "count": "数量", "templateType": "模板类型", - "comment": "描述" + "comment": "描述", + "expiredInSeconds": "过期时间(秒)" }, "parameterizedError": { "parameter invalid": "{parameter}无效", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "显示隐藏的模板", "Hide Hidden Transaction Templates": "不显示隐藏的模板", "Template name cannot be blank": "模板名不能为空", - "Generate MCP token": "生成 MCP 令牌", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "您的 MCP 令牌不会过期,请妥善保管。当连接到第三方应用时,请注意它们及其使用的大语言模型(LLM)可以获取到您的隐私数据。", + "Generate Token": "生成令牌", + "Token Type": "令牌类型", + "Expiration Time (Seconds)": "过期时间(秒)", + "Custom Expiration Time (Seconds)": "自定义过期时间(秒)", + "No Expiration": "永不过期", + "API Token": "API 令牌", + "MCP Token": "MCP 令牌", + "Your token does not expire, please keep it secure.": "您的令牌不会过期,请妥善保管。", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "当连接到第三方应用时,请注意它们及其使用的大语言模型(LLM)可以获取到您的隐私数据。", "Unable to generate token": "无法生成令牌", "Are you sure you want to logout from this session?": "您确定要退出该会话?", "Unable to logout from this session": "无法退出该会话", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index 7b7ffb7e..a4d66f3a 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -107,6 +107,10 @@ "EndYY": "{EndYY}財政年度" }, "misc": { + "nHour": "{n} 小時", + "nHours": "{n} 小時", + "nDay": "{n} 天", + "nDays": "{n} 天", "multiTextJoinSeparator": "、", "loginWithCustomProvider": "使用 {name} 登入", "hoursBehindDefaultTimezone": "比預設時區晚{hours}小時", @@ -1105,6 +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 認證令牌", "passcode is invalid": "驗證碼無效", "two-factor backup code is invalid": "二步驟驗證備用碼無效", "two-factor is not enabled": "二步驟驗證沒有啟用", @@ -1307,7 +1312,8 @@ "page": "頁面索引", "count": "數量", "templateType": "範本類型", - "comment": "描述" + "comment": "描述", + "expiredInSeconds": "到期時間(秒)" }, "parameterizedError": { "parameter invalid": "{parameter}無效", @@ -2261,8 +2267,15 @@ "Show Hidden Transaction Templates": "顯示隱藏的範本", "Hide Hidden Transaction Templates": "不顯示隱藏的範本", "Template name cannot be blank": "範本名稱不能為空", - "Generate MCP token": "產生 MCP 令牌", - "Your MCP token does not expire, please keep it secure. When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "您的 MCP 令牌不會過期,請妥善保管。當連接至第三方應用程式時,請留意它們及其使用的大型語言模型(LLM)可以存取您的隱私資料。", + "Generate Token": "產生令牌", + "Token Type": "令牌類型", + "Expiration Time (Seconds)": "到期時間(秒)", + "Custom Expiration Time (Seconds)": "自訂到期時間(秒)", + "No Expiration": "永不過期", + "API Token": "API 令牌", + "MCP Token": "MCP 令牌", + "Your token does not expire, please keep it secure.": "您的令牌不會過期,請妥善保管。", + "When connecting to third-party apps, be aware that they and any large language models they use can access your private data.": "當連接至第三方應用程式時,請留意它們及其使用的大型語言模型(LLM)可以存取您的隱私資料。", "Unable to generate token": "無法產生令牌", "Are you sure you want to logout from this session?": "您確定要登出此會話?", "Unable to logout from this session": "無法登出此會話", diff --git a/src/models/token.ts b/src/models/token.ts index 49cfa329..c9304c5d 100644 --- a/src/models/token.ts +++ b/src/models/token.ts @@ -2,11 +2,16 @@ import type { ApplicationCloudSetting } from '@/core/setting.ts'; import type { UserBasicInfo } from './user.ts'; +export const TOKEN_TYPE_API: number = 8; export const TOKEN_TYPE_MCP: number = 5; -export const TOKEN_CLI_USER_AGENT: string = 'ezbookkeeping Cli'; +export interface TokenGenerateAPIRequest { + readonly expiresInSeconds: number; + readonly password: string; +} export interface TokenGenerateMCPRequest { + readonly expiresInSeconds: number; readonly password: string; } @@ -14,6 +19,10 @@ export interface TokenRevokeRequest { readonly tokenId: string; } +export interface TokenGenerateAPIResponse { + readonly token: string; +} + export interface TokenGenerateMCPResponse { readonly token: string; readonly mcpUrl: string; @@ -35,24 +44,34 @@ export interface TokenInfoResponse { readonly isCurrent: boolean; } +export enum SessionDeviceType { + Api = 'api', + MCP = 'mcp', + Phone = 'phone', + Tablet = 'tablet', + TV = 'tv', + Wearable = 'wearable', + Default = 'default' +} + export class SessionInfo { public readonly tokenId: string; public readonly isCurrent: boolean; - public readonly deviceType: string; + public readonly deviceType: SessionDeviceType; public readonly deviceInfo: string; - public readonly createdByCli: boolean; + public readonly deviceName: string; public readonly lastSeen: number; - protected constructor(tokenId: string, isCurrent: boolean, deviceType: string, deviceInfo: string, createdByCli: boolean, lastSeen: number) { + protected constructor(tokenId: string, isCurrent: boolean, deviceType: SessionDeviceType, deviceInfo: string, deviceName: string, lastSeen: number) { this.tokenId = tokenId; this.isCurrent = isCurrent; this.deviceType = deviceType; this.deviceInfo = deviceInfo; - this.createdByCli = createdByCli; + this.deviceName = deviceName; this.lastSeen = lastSeen; } - public static of(tokenId: string, isCurrent: boolean, deviceType: string, deviceInfo: string, createdByCli: boolean, lastSeen: number): SessionInfo { - return new SessionInfo(tokenId, isCurrent, deviceType, deviceInfo, createdByCli, lastSeen); + public static of(tokenId: string, isCurrent: boolean, deviceType: SessionDeviceType, deviceInfo: string, deviceName: string, lastSeen: number): SessionInfo { + return new SessionInfo(tokenId, isCurrent, deviceType, deviceInfo, deviceName, lastSeen); } } diff --git a/src/stores/token.ts b/src/stores/token.ts index 348d8133..25d79a20 100644 --- a/src/stores/token.ts +++ b/src/stores/token.ts @@ -3,7 +3,12 @@ import { defineStore } from 'pinia'; import { useSettingsStore } from './setting.ts'; import { useUserStore } from './user.ts'; -import type { TokenGenerateMCPResponse, TokenRefreshResponse, TokenInfoResponse } from '@/models/token.ts'; +import type { + TokenGenerateAPIResponse, + TokenGenerateMCPResponse, + TokenRefreshResponse, + TokenInfoResponse +} from '@/models/token.ts'; import { isObject } from '@/lib/common.ts'; import { updateCurrentToken } from '@/lib/userstate.ts'; @@ -69,9 +74,20 @@ export const useTokensStore = defineStore('tokens', () => { }); } - function generateMCPToken({ password }: { password: string }): Promise { + function generateToken({ type, expiresInSeconds, password }: { type: T, expiresInSeconds: number, password: string }): Promise<{ 'api': TokenGenerateAPIResponse, 'mcp': TokenGenerateMCPResponse }[T]> { return new Promise((resolve, reject) => { - services.generateMCPToken({ password }).then(response => { + let promise = null; + + if (type === 'api') { + promise = services.generateAPIToken({ expiresInSeconds, password }); + } else if (type === 'mcp') { + promise = services.generateMCPToken({ expiresInSeconds, password }); + } else { + reject({ message: 'An error occurred' }); + return; + } + + promise.then(response => { const data = response.data; if (!data || !data.success || !data.result) { @@ -79,7 +95,7 @@ export const useTokensStore = defineStore('tokens', () => { return; } - resolve(data.result); + resolve(data.result as { 'api': TokenGenerateAPIResponse, 'mcp': TokenGenerateMCPResponse }[T]); }).catch(error => { logger.error('failed to generate token', error); @@ -148,7 +164,7 @@ export const useTokensStore = defineStore('tokens', () => { // functions getAllTokens, refreshTokenAndRevokeOldToken, - generateMCPToken, + generateToken, revokeToken, revokeAllTokens }; diff --git a/src/views/desktop/user/settings/dialogs/UserGenerateMCPTokenDialog.vue b/src/views/desktop/user/settings/dialogs/UserGenerateMCPTokenDialog.vue deleted file mode 100644 index b65d1fa9..00000000 --- a/src/views/desktop/user/settings/dialogs/UserGenerateMCPTokenDialog.vue +++ /dev/null @@ -1,170 +0,0 @@ - - - diff --git a/src/views/desktop/user/settings/dialogs/UserGenerateTokenDialog.vue b/src/views/desktop/user/settings/dialogs/UserGenerateTokenDialog.vue new file mode 100644 index 00000000..e42f9f8c --- /dev/null +++ b/src/views/desktop/user/settings/dialogs/UserGenerateTokenDialog.vue @@ -0,0 +1,248 @@ + + + diff --git a/src/views/desktop/user/settings/tabs/UserSecuritySettingTab.vue b/src/views/desktop/user/settings/tabs/UserSecuritySettingTab.vue index 5217cb0e..13be7684 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 MCP token') }} + @click="generateToken" v-if="isGenerateAPITokenEnabled() || isMCPServerEnabled()">{{ tt('Generate Token') }} @@ -198,7 +198,7 @@