From 273a0563b30173e365a77c2c46552c0dc992236c Mon Sep 17 00:00:00 2001 From: undefined Date: Sat, 19 Nov 2022 10:27:57 +0800 Subject: [PATCH] core: limits: allow by-user --- packages/hydrooj/src/handler/contest.ts | 4 ++-- packages/hydrooj/src/handler/problem.ts | 4 ++-- packages/hydrooj/src/handler/user.ts | 6 +++--- packages/hydrooj/src/model/setting.ts | 1 + packages/hydrooj/src/service/server.ts | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/hydrooj/src/handler/contest.ts b/packages/hydrooj/src/handler/contest.ts index 7dbca825e..3d7826ad1 100644 --- a/packages/hydrooj/src/handler/contest.ts +++ b/packages/hydrooj/src/handler/contest.ts @@ -287,7 +287,7 @@ export class ContestScoreboardHandler extends ContestDetailBaseHandler { } async exportScoreboard(domainId: string, tid: ObjectID, ext: string) { - await this.limitRate('scoreboard_download', 120, 3); + await this.limitRate('scoreboard_download', 60, 3); if (ext === 'ghost') { await this.exportGhost(domainId, tid); return; @@ -415,7 +415,7 @@ export class ContestCodeHandler extends Handler { @param('tid', Types.ObjectID) @param('all', Types.Boolean) async get(domainId: string, tid: ObjectID, all: boolean) { - await this.limitRate('contest_code', 3600, 60); + await this.limitRate('contest_code', 60, 10); const [tdoc, tsdocs] = await contest.getAndListStatus(domainId, tid); if (!this.user.own(tdoc) && !this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE)) { this.checkPerm(PERM.PERM_READ_RECORD_CODE); diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index aaedcdb4e..9d92e9ec2 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -525,7 +525,7 @@ export class ProblemSubmitHandler extends ProblemDetailHandler { } } await this.limitRate('add_record', 60, system.get('limit.submission_user'), true); - await this.limitRate('add_record', 60, system.get('limit.submission')); + await this.limitRate('add_record', 60, system.get('limit.submission'), false); const files: Record = {}; if (!code) { const file = this.request.files?.file; @@ -599,7 +599,7 @@ export class ProblemHackHandler extends ProblemDetailHandler { @param('tid', Types.ObjectID, true) async post(domainId: string, input = '', tid?: ObjectID) { await this.limitRate('add_record', 60, system.get('limit.submission_user'), true); - await this.limitRate('add_record', 60, system.get('limit.submission')); + await this.limitRate('add_record', 60, system.get('limit.submission'), false); const id = `${this.user._id}/${nanoid()}`; if (this.request.files?.file?.size > 0) { const file = this.request.files.file; diff --git a/packages/hydrooj/src/handler/user.ts b/packages/hydrooj/src/handler/user.ts index cf4e2e8bb..ff70d606c 100644 --- a/packages/hydrooj/src/handler/user.ts +++ b/packages/hydrooj/src/handler/user.ts @@ -121,8 +121,8 @@ class UserLoginHandler extends Handler { if (!udoc) udoc = await user.getByUname(domainId, uname); if (!udoc) throw new UserNotFoundError(uname); await Promise.all([ - this.limitRate('user_login', 60, 30), - this.limitRate(`user_login_${uname}`, 60, 5), + this.limitRate('user_login', 60, 30, false), + this.limitRate(`user_login_${uname}`, 60, 5, false), oplog.log(this, 'user.login', { redirect }), ]); if (udoc._tfa && !verifyToken(udoc._tfa, tfa)) throw new InvalidTokenError('2FA token invalid.'); @@ -199,7 +199,7 @@ export class UserRegisterHandler extends Handler { const mailDomain = mail.split('@')[1]; if (await BlackListModel.get(`mail::${mailDomain}`)) throw new BlacklistedError(mailDomain); await Promise.all([ - this.limitRate('send_mail', 3600, 30), + this.limitRate('send_mail', 3600, 30, false), oplog.log(this, 'user.register', {}), ]); const t = await token.add( diff --git a/packages/hydrooj/src/model/setting.ts b/packages/hydrooj/src/model/setting.ts index 48aeb872c..0a3a72341 100644 --- a/packages/hydrooj/src/model/setting.ts +++ b/packages/hydrooj/src/model/setting.ts @@ -208,6 +208,7 @@ SystemSetting( Setting('setting_server', 'server.checkUpdate', true, 'boolean', 'server.checkUpdate', 'Daily update check'), Setting('setting_server', 'server.ignoreUA', ignoreUA, 'textarea', 'server.ignoreUA', 'ignoredUA'), ServerLangSettingNode, + Setting('setting_limits', 'limit.by_user', false, 'boolean', 'limit.by_user', 'Use per-user limits instead of per ip limits'), Setting('setting_limits', 'limit.problem_files_max', 100, 'number', 'limit.problem_files_max', 'Max files per problem'), Setting('setting_limits', 'limit.problem_files_max_size', 256 * 1024 * 1024, 'number', 'limit.problem_files_max_size', 'Max files size per problem'), Setting('setting_limits', 'limit.user_files', 100, 'number', 'limit.user_files', 'Max files for user'), diff --git a/packages/hydrooj/src/service/server.ts b/packages/hydrooj/src/service/server.ts index d54d00c21..fec9da67c 100644 --- a/packages/hydrooj/src/service/server.ts +++ b/packages/hydrooj/src/service/server.ts @@ -131,7 +131,7 @@ export class HandlerCommon { this.domainId = args.domainId; } - async limitRate(op: string, periodSecs: number, maxOperations: number, withUserId = false) { + async limitRate(op: string, periodSecs: number, maxOperations: number, withUserId = system.get('limit.by_user')) { if (ignoredLimit.includes(op)) return; if (this.user && this.user.hasPriv(PRIV.PRIV_UNLIMITED_ACCESS)) return; const overrideLimit = system.get(`limit.${op}`); @@ -177,7 +177,7 @@ export class Handler extends HandlerCommon { } async init() { - if (!argv.options.benchmark) await this.limitRate('global', 5, 88); + if (!argv.options.benchmark) await this.limitRate('global', 5, 100); if (!this.noCheckPermView && !this.user.hasPriv(PRIV.PRIV_VIEW_ALL_DOMAIN)) this.checkPerm(PERM.PERM_VIEW); this.loginMethods = Object.keys(global.Hydro.module.oauth) .map((key) => ({