feat: rate limiter (#4011)

This commit is contained in:
DarkSky
2023-08-31 20:29:25 +08:00
committed by GitHub
parent 8e48255ef8
commit 4ef1425299
15 changed files with 184 additions and 12 deletions
@@ -42,8 +42,6 @@ export class MailService {
};
}
) {
console.log('invitationInfo', invitationInfo);
const buttonUrl = `${this.config.baseUrl}/invite/${inviteId}`;
const workspaceAvatar = invitationInfo.workspace.avatar;
@@ -9,6 +9,7 @@ import {
Query,
Req,
Res,
UseGuards,
} from '@nestjs/common';
import { hash, verify } from '@node-rs/argon2';
import type { User } from '@prisma/client';
@@ -19,6 +20,7 @@ import { AuthHandler } from 'next-auth/core';
import { Config } from '../../config';
import { PrismaService } from '../../prisma/service';
import { CloudThrottlerGuard, Throttle } from '../../throttler';
import { NextAuthOptionsProvide } from './next-auth-options';
import { AuthService } from './service';
@@ -41,6 +43,8 @@ export class NextAuthController {
this.callbackSession = nextAuthOptions.callbacks!.session;
}
@UseGuards(CloudThrottlerGuard)
@Throttle(20, 60)
@All('*')
async auth(
@Req() req: Request,
+17 -1
View File
@@ -1,4 +1,4 @@
import { ForbiddenException } from '@nestjs/common';
import { ForbiddenException, UseGuards } from '@nestjs/common';
import {
Args,
Context,
@@ -12,6 +12,7 @@ import {
import type { Request } from 'express';
import { Config } from '../../config';
import { CloudThrottlerGuard, Throttle } from '../../throttler';
import { UserType } from '../users/resolver';
import { CurrentUser } from './guard';
import { AuthService } from './service';
@@ -25,6 +26,13 @@ export class TokenType {
refresh!: string;
}
/**
* Auth resolver
* Token rate limit: 20 req/m
* Sign up/in rate limit: 10 req/m
* Other rate limit: 5 req/m
*/
@UseGuards(CloudThrottlerGuard)
@Resolver(() => UserType)
export class AuthResolver {
constructor(
@@ -32,6 +40,7 @@ export class AuthResolver {
private auth: AuthService
) {}
@Throttle(20, 60)
@ResolveField(() => TokenType)
token(@CurrentUser() currentUser: UserType, @Parent() user: UserType) {
if (user.id !== currentUser.id) {
@@ -44,6 +53,7 @@ export class AuthResolver {
};
}
@Throttle(10, 60)
@Mutation(() => UserType)
async signUp(
@Context() ctx: { req: Request },
@@ -56,6 +66,7 @@ export class AuthResolver {
return user;
}
@Throttle(10, 60)
@Mutation(() => UserType)
async signIn(
@Context() ctx: { req: Request },
@@ -67,6 +78,7 @@ export class AuthResolver {
return user;
}
@Throttle(5, 60)
@Mutation(() => UserType)
async changePassword(
@Context() ctx: { req: Request },
@@ -78,6 +90,7 @@ export class AuthResolver {
return user;
}
@Throttle(5, 60)
@Mutation(() => UserType)
async changeEmail(
@Context() ctx: { req: Request },
@@ -89,6 +102,7 @@ export class AuthResolver {
return user;
}
@Throttle(5, 60)
@Mutation(() => Boolean)
async sendChangePasswordEmail(
@Args('email') email: string,
@@ -99,6 +113,7 @@ export class AuthResolver {
return !res.rejected.length;
}
@Throttle(5, 60)
@Mutation(() => Boolean)
async sendSetPasswordEmail(
@Args('email') email: string,
@@ -109,6 +124,7 @@ export class AuthResolver {
return !res.rejected.length;
}
@Throttle(5, 60)
@Mutation(() => Boolean)
async sendChangeEmail(
@Args('email') email: string,
+12
View File
@@ -2,6 +2,7 @@ import {
BadRequestException,
ForbiddenException,
HttpException,
UseGuards,
} from '@nestjs/common';
import {
Args,
@@ -19,6 +20,7 @@ import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs';
import { Config } from '../../config';
import { PrismaService } from '../../prisma/service';
import { CloudThrottlerGuard, Throttle } from '../../throttler';
import type { FileUpload } from '../../types';
import { Auth, CurrentUser, Public } from '../auth/guard';
import { StorageService } from '../storage/storage.service';
@@ -69,6 +71,11 @@ export class AddToNewFeaturesWaitingList {
type!: NewFeaturesKind;
}
/**
* User resolver
* All op rate limit: 10 req/m
*/
@UseGuards(CloudThrottlerGuard)
@Auth()
@Resolver(() => UserType)
export class UserResolver {
@@ -78,6 +85,7 @@ export class UserResolver {
private readonly config: Config
) {}
@Throttle(10, 60)
@Query(() => UserType, {
name: 'currentUser',
description: 'Get current user',
@@ -100,6 +108,7 @@ export class UserResolver {
};
}
@Throttle(10, 60)
@Query(() => UserType, {
name: 'user',
description: 'Get user by email',
@@ -135,6 +144,7 @@ export class UserResolver {
return user;
}
@Throttle(10, 60)
@Mutation(() => UserType, {
name: 'uploadAvatar',
description: 'Upload user avatar',
@@ -155,6 +165,7 @@ export class UserResolver {
});
}
@Throttle(10, 60)
@Mutation(() => DeleteAccount)
async deleteAccount(@CurrentUser() user: UserType): Promise<DeleteAccount> {
await this.prisma.user.delete({
@@ -172,6 +183,7 @@ export class UserResolver {
};
}
@Throttle(10, 60)
@Mutation(() => AddToNewFeaturesWaitingList)
async addToNewFeaturesWaitingList(
@CurrentUser() user: UserType,
+16 -2
View File
@@ -1,5 +1,10 @@
import type { Storage } from '@affine/storage';
import { ForbiddenException, Inject, NotFoundException } from '@nestjs/common';
import {
ForbiddenException,
Inject,
NotFoundException,
UseGuards,
} from '@nestjs/common';
import {
Args,
Field,
@@ -24,6 +29,7 @@ import { applyUpdate, Doc } from 'yjs';
import { PrismaService } from '../../prisma';
import { StorageProvide } from '../../storage';
import { CloudThrottlerGuard, Throttle } from '../../throttler';
import type { FileUpload } from '../../types';
import { Auth, CurrentUser, Public } from '../auth';
import { MailService } from '../auth/mailer';
@@ -113,6 +119,12 @@ export class UpdateWorkspaceInput extends PickType(
id!: string;
}
/**
* Workspace resolver
* Public apis rate limit: 10 req/m
* Other rate limit: 120 req/m
*/
@UseGuards(CloudThrottlerGuard)
@Auth()
@Resolver(() => WorkspaceType)
export class WorkspaceResolver {
@@ -258,10 +270,11 @@ export class WorkspaceResolver {
});
}
@Throttle(10, 30)
@Public()
@Query(() => WorkspaceType, {
description: 'Get public workspace by id',
})
@Public()
async publicWorkspace(@Args('id') id: string) {
const workspace = await this.prisma.workspace.findUnique({
where: { id },
@@ -463,6 +476,7 @@ export class WorkspaceResolver {
}
}
@Throttle(10, 30)
@Public()
@Query(() => InvitationType, {
description: 'Update workspace',