mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-22 20:46:38 +08:00
feat(server): make captcha modular (#5961)
This commit is contained in:
@@ -526,4 +526,10 @@ export const USER_FRIENDLY_ERRORS = {
|
||||
type: 'action_forbidden',
|
||||
message: 'Cannot delete own account.',
|
||||
},
|
||||
|
||||
// captcha errors
|
||||
captcha_verification_failed: {
|
||||
type: 'bad_request',
|
||||
message: 'Captcha verification failed.',
|
||||
},
|
||||
} satisfies Record<string, UserFriendlyErrorOptions>;
|
||||
|
||||
@@ -533,6 +533,12 @@ export class CannotDeleteOwnAccount extends UserFriendlyError {
|
||||
super('action_forbidden', 'cannot_delete_own_account', message);
|
||||
}
|
||||
}
|
||||
|
||||
export class CaptchaVerificationFailed extends UserFriendlyError {
|
||||
constructor(message?: string) {
|
||||
super('bad_request', 'captcha_verification_failed', message);
|
||||
}
|
||||
}
|
||||
export enum ErrorNames {
|
||||
INTERNAL_SERVER_ERROR,
|
||||
TOO_MANY_REQUEST,
|
||||
@@ -604,7 +610,8 @@ export enum ErrorNames {
|
||||
INVALID_RUNTIME_CONFIG_TYPE,
|
||||
MAILER_SERVICE_IS_NOT_CONFIGURED,
|
||||
CANNOT_DELETE_ALL_ADMIN_ACCOUNT,
|
||||
CANNOT_DELETE_OWN_ACCOUNT
|
||||
CANNOT_DELETE_OWN_ACCOUNT,
|
||||
CAPTCHA_VERIFICATION_FAILED
|
||||
}
|
||||
registerEnumType(ErrorNames, {
|
||||
name: 'ErrorNames'
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
applyDecorators,
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
SetMetadata,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
|
||||
import { GUARD_PROVIDER, NamedGuards } from './provider';
|
||||
|
||||
const BasicGuardSymbol = Symbol('BasicGuard');
|
||||
|
||||
@Injectable()
|
||||
export class BasicGuard implements CanActivate {
|
||||
constructor(private readonly reflector: Reflector) {}
|
||||
|
||||
async canActivate(context: ExecutionContext) {
|
||||
// get registered guard name
|
||||
const providerName = this.reflector.get<string>(
|
||||
BasicGuardSymbol,
|
||||
context.getHandler()
|
||||
);
|
||||
|
||||
const provider = GUARD_PROVIDER[providerName as NamedGuards];
|
||||
if (provider) {
|
||||
return await provider.canActivate(context);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This guard is used to protect routes/queries/mutations that use a registered guard
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```typescript
|
||||
* \@UseNamedGuard('captcha') // use captcha guard
|
||||
* \@Auth()
|
||||
* \@Query(() => UserType)
|
||||
* user(@CurrentUser() user: CurrentUser) {
|
||||
* return user;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const UseNamedGuard = (name: NamedGuards) =>
|
||||
applyDecorators(UseGuards(BasicGuard), SetMetadata(BasicGuardSymbol, name));
|
||||
@@ -0,0 +1,2 @@
|
||||
export { UseNamedGuard } from './guard';
|
||||
export { GuardProvider, type RegisterGuardName } from './provider';
|
||||
@@ -0,0 +1,26 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
Logger,
|
||||
OnModuleInit,
|
||||
} from '@nestjs/common';
|
||||
|
||||
export interface RegisterGuardName {}
|
||||
|
||||
export type NamedGuards = keyof RegisterGuardName;
|
||||
|
||||
export const GUARD_PROVIDER: Partial<Record<NamedGuards, GuardProvider>> = {};
|
||||
|
||||
@Injectable()
|
||||
export abstract class GuardProvider implements OnModuleInit, CanActivate {
|
||||
private readonly logger = new Logger(GuardProvider.name);
|
||||
abstract name: NamedGuards;
|
||||
|
||||
onModuleInit() {
|
||||
GUARD_PROVIDER[this.name] = this;
|
||||
this.logger.log(`Guard provider [${this.name}] registered`);
|
||||
}
|
||||
|
||||
abstract canActivate(context: ExecutionContext): boolean | Promise<boolean>;
|
||||
}
|
||||
@@ -16,6 +16,7 @@ export {
|
||||
export * from './error';
|
||||
export { EventEmitter, type EventPayload, OnEvent } from './event';
|
||||
export type { GraphqlContext } from './graphql';
|
||||
export * from './guard';
|
||||
export { CryptoHelper, URLHelper } from './helpers';
|
||||
export { MailService } from './mailer';
|
||||
export { CallCounter, CallTimer, metrics } from './metrics';
|
||||
|
||||
Reference in New Issue
Block a user