add ratelimits
This commit is contained in:
parent
78ff25034c
commit
7b6ffb5010
|
@ -6,7 +6,10 @@ import { PicsurThrottlerGuard } from './throttler/PicsurThrottler.guard';
|
|||
import { ZodValidationPipe } from './validate/zod-validator.pipe';
|
||||
|
||||
@Module({
|
||||
imports: [ThrottlerModule.forRoot()],
|
||||
imports: [ThrottlerModule.forRoot({
|
||||
ttl: 60,
|
||||
limit: 60,
|
||||
})],
|
||||
providers: [
|
||||
PicsurThrottlerGuard,
|
||||
MainExceptionFilter,
|
||||
|
|
|
@ -5,6 +5,6 @@ import { Fail, FT } from 'picsur-shared/dist/types';
|
|||
@Injectable()
|
||||
export class PicsurThrottlerGuard extends ThrottlerGuard {
|
||||
protected override throwThrottlingException(context: ExecutionContext): void {
|
||||
throw Fail(FT.Permission, undefined, 'Too many requests');
|
||||
throw Fail(FT.RateLimit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
ApiKeyCreateResponse,
|
||||
ApiKeyDeleteRequest,
|
||||
|
@ -8,14 +9,14 @@ import {
|
|||
ApiKeyListRequest,
|
||||
ApiKeyListResponse,
|
||||
ApiKeyUpdateRequest,
|
||||
ApiKeyUpdateResponse,
|
||||
ApiKeyUpdateResponse
|
||||
} from 'picsur-shared/dist/dto/api/apikeys.dto';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types';
|
||||
import { ApiKeyDbService } from '../../../collections/apikey-db/apikey-db.service';
|
||||
import {
|
||||
HasPermission,
|
||||
RequiredPermissions,
|
||||
RequiredPermissions
|
||||
} from '../../../decorators/permissions.decorator';
|
||||
import { ReqUserID } from '../../../decorators/request-user.decorator';
|
||||
import { Returns } from '../../../decorators/returns.decorator';
|
||||
|
@ -53,6 +54,7 @@ export class ApiKeysController {
|
|||
|
||||
@Post('create')
|
||||
@Returns(ApiKeyCreateResponse)
|
||||
@Throttle(10)
|
||||
async createApiKey(
|
||||
@ReqUserID() userID: string,
|
||||
): Promise<ApiKeyCreateResponse> {
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
import { Controller, Get, Request, Response } from '@nestjs/common';
|
||||
import type { FastifyReply } from 'fastify';
|
||||
import { UserInfoResponse } from 'picsur-shared/dist/dto/api/user-manage.dto';
|
||||
import { Controller } from '@nestjs/common';
|
||||
import { NoPermissions } from '../../../decorators/permissions.decorator';
|
||||
import { Returns } from '../../../decorators/returns.decorator';
|
||||
import type AuthFastifyRequest from '../../../models/interfaces/authrequest.dto';
|
||||
@Controller('api/experiment')
|
||||
@NoPermissions()
|
||||
export class ExperimentController {
|
||||
constructor() {}
|
||||
|
||||
@Get()
|
||||
@Returns(UserInfoResponse)
|
||||
async testRoute(
|
||||
@Request() req: AuthFastifyRequest,
|
||||
@Response({ passthrough: true }) res: FastifyReply,
|
||||
): Promise<UserInfoResponse> {
|
||||
res.header('Location', '/error/delete-success');
|
||||
res.code(302);
|
||||
return req.user;
|
||||
}
|
||||
// @Get()
|
||||
// @Returns(UserInfoResponse)
|
||||
// async testRoute(
|
||||
// @Request() req: AuthFastifyRequest,
|
||||
// @Response({ passthrough: true }) res: FastifyReply,
|
||||
// ): Promise<UserInfoResponse> {
|
||||
// res.header('Location', '/error/delete-success');
|
||||
// res.code(302);
|
||||
// return req.user;
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Body, Controller, Get, Logger, Param, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
GetPreferenceResponse,
|
||||
MultiplePreferencesResponse,
|
||||
UpdatePreferenceRequest,
|
||||
UpdatePreferenceResponse,
|
||||
UpdatePreferenceResponse
|
||||
} from 'picsur-shared/dist/dto/api/pref.dto';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types';
|
||||
import { SysPreferenceDbService } from '../../../collections/preference-db/sys-preference-db.service';
|
||||
|
@ -20,6 +21,7 @@ export class SysPrefController {
|
|||
|
||||
@Get()
|
||||
@Returns(MultiplePreferencesResponse)
|
||||
@Throttle(20)
|
||||
async getAllSysPrefs(): Promise<MultiplePreferencesResponse> {
|
||||
const prefs = ThrowIfFailed(await this.prefService.getAllPreferences());
|
||||
|
||||
|
@ -39,6 +41,7 @@ export class SysPrefController {
|
|||
|
||||
@Post(':key')
|
||||
@Returns(UpdatePreferenceResponse)
|
||||
@Throttle(30)
|
||||
async setSysPref(
|
||||
@Param('key') key: string,
|
||||
@Body() body: UpdatePreferenceRequest,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Body, Controller, Get, Logger, Param, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
GetPreferenceResponse,
|
||||
MultiplePreferencesResponse,
|
||||
UpdatePreferenceRequest,
|
||||
UpdatePreferenceResponse,
|
||||
UpdatePreferenceResponse
|
||||
} from 'picsur-shared/dist/dto/api/pref.dto';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types';
|
||||
import { UsrPreferenceDbService } from '../../../collections/preference-db/usr-preference-db.service';
|
||||
|
@ -21,7 +22,8 @@ export class UsrPrefController {
|
|||
|
||||
@Get()
|
||||
@Returns(MultiplePreferencesResponse)
|
||||
async getAllSysPrefs(
|
||||
@Throttle(20)
|
||||
async getAllUsrPrefs(
|
||||
@ReqUserID() userid: string,
|
||||
): Promise<MultiplePreferencesResponse> {
|
||||
const prefs = ThrowIfFailed(
|
||||
|
@ -36,7 +38,7 @@ export class UsrPrefController {
|
|||
|
||||
@Get(':key')
|
||||
@Returns(GetPreferenceResponse)
|
||||
async getSysPref(
|
||||
async getUsrPref(
|
||||
@Param('key') key: string,
|
||||
@ReqUserID() userid: string,
|
||||
): Promise<GetPreferenceResponse> {
|
||||
|
@ -49,7 +51,8 @@ export class UsrPrefController {
|
|||
|
||||
@Post(':key')
|
||||
@Returns(UpdatePreferenceResponse)
|
||||
async setSysPref(
|
||||
@Throttle(30)
|
||||
async setUsrPref(
|
||||
@Param('key') key: string,
|
||||
@ReqUserID() userid: string,
|
||||
@Body() body: UpdatePreferenceRequest,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Body, Controller, Get, Logger, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
RoleCreateRequest,
|
||||
RoleCreateResponse,
|
||||
|
@ -9,7 +10,7 @@ import {
|
|||
RoleListResponse,
|
||||
RoleUpdateRequest,
|
||||
RoleUpdateResponse,
|
||||
SpecialRolesResponse,
|
||||
SpecialRolesResponse
|
||||
} from 'picsur-shared/dist/dto/api/roles.dto';
|
||||
import { Fail, FT, ThrowIfFailed } from 'picsur-shared/dist/types';
|
||||
import { RoleDbService } from '../../../collections/role-db/role-db.service';
|
||||
|
@ -21,7 +22,7 @@ import {
|
|||
DefaultRolesList,
|
||||
ImmutableRolesList,
|
||||
SoulBoundRolesList,
|
||||
UndeletableRolesList,
|
||||
UndeletableRolesList
|
||||
} from '../../../models/constants/roles.const';
|
||||
import { isPermissionsArray } from '../../../models/validators/permissions.validator';
|
||||
|
||||
|
@ -56,6 +57,7 @@ export class RolesController {
|
|||
|
||||
@Post('update')
|
||||
@Returns(RoleUpdateResponse)
|
||||
@Throttle(20)
|
||||
async updateRole(
|
||||
@Body() body: RoleUpdateRequest,
|
||||
): Promise<RoleUpdateResponse> {
|
||||
|
@ -73,6 +75,7 @@ export class RolesController {
|
|||
|
||||
@Post('create')
|
||||
@Returns(RoleCreateResponse)
|
||||
@Throttle(10)
|
||||
async createRole(
|
||||
@Body() role: RoleCreateRequest,
|
||||
): Promise<RoleCreateResponse> {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Controller, Logger, Post, Req, Res } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { Fail, FT, ThrowIfFailed } from 'picsur-shared/dist/types';
|
||||
import { UsageConfigService } from '../../../config/late/usage.config.service';
|
||||
|
@ -14,6 +15,7 @@ export class UsageController {
|
|||
|
||||
@Post(['report', 'report/*'])
|
||||
@ReturnsAnything()
|
||||
@Throttle(120)
|
||||
async deleteRole(
|
||||
@Req() req: FastifyRequest,
|
||||
@Res({
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Body, Controller, Get, Logger, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
GetSpecialUsersResponse,
|
||||
UserCreateRequest,
|
||||
|
@ -10,7 +11,7 @@ import {
|
|||
UserListRequest,
|
||||
UserListResponse,
|
||||
UserUpdateRequest,
|
||||
UserUpdateResponse,
|
||||
UserUpdateResponse
|
||||
} from 'picsur-shared/dist/dto/api/user-manage.dto';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types';
|
||||
import { UserDbService } from '../../../collections/user-db/user-db.service';
|
||||
|
@ -20,7 +21,7 @@ import { Permission } from '../../../models/constants/permissions.const';
|
|||
import {
|
||||
ImmutableUsersList,
|
||||
LockedLoginUsersList,
|
||||
UndeletableUsersList,
|
||||
UndeletableUsersList
|
||||
} from '../../../models/constants/special-users.const';
|
||||
import { EUserBackend2EUser } from '../../../models/transformers/user.transformer';
|
||||
|
||||
|
@ -46,6 +47,7 @@ export class UserAdminController {
|
|||
|
||||
@Post('create')
|
||||
@Returns(UserCreateResponse)
|
||||
@Throttle(10)
|
||||
async register(
|
||||
@Body() create: UserCreateRequest,
|
||||
): Promise<UserCreateResponse> {
|
||||
|
@ -78,6 +80,7 @@ export class UserAdminController {
|
|||
|
||||
@Post('update')
|
||||
@Returns(UserUpdateResponse)
|
||||
@Throttle(20)
|
||||
async setPermissions(
|
||||
@Body() body: UserUpdateRequest,
|
||||
): Promise<UserUpdateResponse> {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Body, Controller, Get, Logger, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
UserCheckNameRequest,
|
||||
UserCheckNameResponse,
|
||||
|
@ -6,7 +7,7 @@ import {
|
|||
UserMePermissionsResponse,
|
||||
UserMeResponse,
|
||||
UserRegisterRequest,
|
||||
UserRegisterResponse,
|
||||
UserRegisterResponse
|
||||
} from 'picsur-shared/dist/dto/api/user.dto';
|
||||
import type { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types';
|
||||
|
@ -14,7 +15,7 @@ import { UserDbService } from '../../../collections/user-db/user-db.service';
|
|||
import {
|
||||
NoPermissions,
|
||||
RequiredPermissions,
|
||||
UseLocalAuth,
|
||||
UseLocalAuth
|
||||
} from '../../../decorators/permissions.decorator';
|
||||
import { ReqUser, ReqUserID } from '../../../decorators/request-user.decorator';
|
||||
import { Returns } from '../../../decorators/returns.decorator';
|
||||
|
@ -34,6 +35,7 @@ export class UserController {
|
|||
@Post('login')
|
||||
@Returns(UserLoginResponse)
|
||||
@UseLocalAuth(Permission.UserLogin)
|
||||
@Throttle(30, 300)
|
||||
async login(@ReqUser() user: EUser): Promise<UserLoginResponse> {
|
||||
const jwt_token = ThrowIfFailed(await this.authService.createToken(user));
|
||||
|
||||
|
@ -43,6 +45,7 @@ export class UserController {
|
|||
@Post('register')
|
||||
@Returns(UserRegisterResponse)
|
||||
@RequiredPermissions(Permission.UserRegister)
|
||||
@Throttle(5, 300)
|
||||
async register(
|
||||
@Body() register: UserRegisterRequest,
|
||||
): Promise<UserRegisterResponse> {
|
||||
|
@ -56,6 +59,7 @@ export class UserController {
|
|||
@Post('checkname')
|
||||
@Returns(UserCheckNameResponse)
|
||||
@RequiredPermissions(Permission.UserRegister)
|
||||
@Throttle(20)
|
||||
async checkName(
|
||||
@Body() checkName: UserCheckNameRequest,
|
||||
): Promise<UserCheckNameResponse> {
|
||||
|
@ -67,6 +71,7 @@ export class UserController {
|
|||
@Get('me')
|
||||
@Returns(UserMeResponse)
|
||||
@RequiredPermissions(Permission.UserKeepLogin)
|
||||
@Throttle(10)
|
||||
async me(@ReqUserID() userid: string): Promise<UserMeResponse> {
|
||||
const backenduser = ThrowIfFailed(await this.usersService.findOne(userid));
|
||||
|
||||
|
@ -81,6 +86,7 @@ export class UserController {
|
|||
@Get('me/permissions')
|
||||
@Returns(UserMePermissionsResponse)
|
||||
@NoPermissions()
|
||||
@Throttle(20)
|
||||
async refresh(
|
||||
@ReqUserID() userid: string,
|
||||
): Promise<UserMePermissionsResponse> {
|
||||
|
|
|
@ -5,8 +5,9 @@ import {
|
|||
Logger,
|
||||
Param,
|
||||
Post,
|
||||
Res,
|
||||
Res
|
||||
} from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import type { FastifyReply } from 'fastify';
|
||||
import {
|
||||
ImageDeleteRequest,
|
||||
|
@ -17,14 +18,14 @@ import {
|
|||
ImageListResponse,
|
||||
ImageUpdateRequest,
|
||||
ImageUpdateResponse,
|
||||
ImageUploadResponse,
|
||||
ImageUploadResponse
|
||||
} from 'picsur-shared/dist/dto/api/image-manage.dto';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
import { HasFailed, ThrowIfFailed } from 'picsur-shared/dist/types';
|
||||
import { MultiPart } from '../../decorators/multipart/multipart.decorator';
|
||||
import {
|
||||
HasPermission,
|
||||
RequiredPermissions,
|
||||
RequiredPermissions
|
||||
} from '../../decorators/permissions.decorator';
|
||||
import { ReqUserID } from '../../decorators/request-user.decorator';
|
||||
import { Returns } from '../../decorators/returns.decorator';
|
||||
|
@ -39,6 +40,7 @@ export class ImageManageController {
|
|||
|
||||
@Post('upload')
|
||||
@Returns(ImageUploadResponse)
|
||||
@Throttle(20)
|
||||
async uploadImage(
|
||||
@MultiPart() multipart: ImageUploadDto,
|
||||
@ReqUserID() userid: string,
|
||||
|
|
|
@ -10,6 +10,7 @@ export enum FT {
|
|||
SysValidation = 'sysvalidation',
|
||||
UsrValidation = 'usrvalidation',
|
||||
Permission = 'permission',
|
||||
RateLimit = 'ratelimit',
|
||||
NotFound = 'notfound',
|
||||
RouteNotFound = 'routenotfound',
|
||||
Conflict = 'conflict',
|
||||
|
@ -63,6 +64,11 @@ const FTProps: {
|
|||
code: 403,
|
||||
message: 'Permission denied',
|
||||
},
|
||||
[FT.RateLimit]: {
|
||||
important: false,
|
||||
code: 429,
|
||||
message: 'Rate limit exceeded',
|
||||
},
|
||||
[FT.NotFound]: {
|
||||
important: false,
|
||||
code: 404,
|
||||
|
|
Loading…
Reference in New Issue