diff --git a/packages/backend/server/src/core/auth/token.ts b/packages/backend/server/src/core/auth/token.ts index 5eed3435f8..4234c1c01c 100644 --- a/packages/backend/server/src/core/auth/token.ts +++ b/packages/backend/server/src/core/auth/token.ts @@ -40,6 +40,48 @@ export class TokenService { return this.crypto.encrypt(token); } + /** + * get token by type + * + * token will be revoked if expired or keep is not set + */ + async getToken(type: TokenType, token: string, keep?: boolean) { + token = this.crypto.decrypt(token); + const record = await this.db.verificationToken.findUnique({ + where: { + type_token: { + token, + type, + }, + }, + }); + + if (!record) { + return null; + } + + const expired = record.expiresAt <= new Date(); + + // always revoke expired token + if (expired || !keep) { + const deleted = await this.revokeToken(type, token); + + // already deleted, means token has been used + if (!deleted.count) { + return null; + } + } + + return !expired ? record : null; + } + + /** + * get token and verify credential + * + * if credential is not provided, it will be failed + * + * token will be revoked if expired or keep is not set + */ async verifyToken( type: TokenType, token: string, diff --git a/packages/backend/server/src/plugins/captcha/service.ts b/packages/backend/server/src/plugins/captcha/service.ts index e3f35974fd..d3ebafdfd0 100644 --- a/packages/backend/server/src/plugins/captcha/service.ts +++ b/packages/backend/server/src/plugins/captcha/service.ts @@ -90,7 +90,7 @@ export class CaptchaService { const challenge = credential.challenge; if (typeof challenge === 'string' && challenge) { const resource = await this.token - .verifyToken(TokenType.Challenge, challenge) + .getToken(TokenType.Challenge, challenge) .then(token => token?.credential); if (!resource) {