From 40b04e900cd64b1f96845befdbe602df1031268c Mon Sep 17 00:00:00 2001 From: undefined Date: Tue, 23 Nov 2021 23:17:07 +0800 Subject: [PATCH] core: restrict testdata access from contest --- packages/hydrooj/package.json | 2 +- packages/hydrooj/src/error.ts | 1 + packages/hydrooj/src/handler/problem.ts | 10 ++++++---- packages/hydrooj/src/handler/user.ts | 2 +- packages/hydrooj/src/lib/validator.ts | 9 ++------- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 8ba20ec4f..b2c94002f 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "3.1.33", + "version": "3.1.34", "bin": "bin/hydrooj.js", "main": "src/loader", "module": "src/loader", diff --git a/packages/hydrooj/src/error.ts b/packages/hydrooj/src/error.ts index f9ff4ac41..ae74765b6 100644 --- a/packages/hydrooj/src/error.ts +++ b/packages/hydrooj/src/error.ts @@ -86,6 +86,7 @@ export const ContestNotAttendedError = Err('ContestNotAttendedError', ForbiddenE export const RequireProError = Err('RequireProError', ForbiddenError, 'RequireProError'); export const ContestAlreadyAttendedError = Err('ContestAlreadyAttendedError', ForbiddenError, "You've already attended this contest."); export const ContestNotLiveError = Err('ContestNotLiveError', ForbiddenError, 'This contest is not live.'); +export const ContestNotEndedError = Err('ContestNotEndedError', ForbiddenError, 'This contest is not ended.'); export const ContestScoreboardHiddenError = Err('ContestScoreboardHiddenError', ForbiddenError, 'Contest scoreboard is not visible.'); export const TrainingAlreadyEnrollError = Err('TrainingAlreadyEnrollError', ForbiddenError, "You've already enrolled this training."); export const HomeworkNotLiveError = Err('HomeworkNotLiveError', ForbiddenError, 'This homework is not open.'); diff --git a/packages/hydrooj/src/handler/problem.ts b/packages/hydrooj/src/handler/problem.ts index 2f5d41961..aef60b280 100644 --- a/packages/hydrooj/src/handler/problem.ts +++ b/packages/hydrooj/src/handler/problem.ts @@ -5,10 +5,10 @@ import { lookup } from 'mime-types'; import { FilterQuery, ObjectID } from 'mongodb'; import { sortFiles } from '@hydrooj/utils/lib/utils'; import { - BadRequestError, ContestNotAttendedError, ContestNotFoundError, - ContestNotLiveError, ForbiddenError, NoProblemError, - NotFoundError, PermissionError, ProblemNotFoundError, - SolutionNotFoundError, ValidationError, + BadRequestError, ContestNotAttendedError, ContestNotEndedError, + ContestNotFoundError, ContestNotLiveError, + ForbiddenError, NoProblemError, NotFoundError, + PermissionError, ProblemNotFoundError, SolutionNotFoundError, ValidationError, } from '../error'; import { ProblemConfig, @@ -491,6 +491,7 @@ export class ProblemFilesHandler extends ProblemDetailHandler { async postGetLinks(domainId: string, files: Set, type = 'testdata') { if (type === 'testdata' && !this.user.own(this.pdoc)) { if (!this.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)) this.checkPerm(PERM.PERM_READ_PROBLEM_DATA); + if (this.tdoc && !contest.isDone(this.tdoc)) throw new ContestNotEndedError(this.tdoc.domainId, this.tdoc.docId); } if (this.pdoc.reference) this.pdoc = await problem.get(this.pdoc.reference.domainId, this.pdoc.reference.pid); const links = {}; @@ -599,6 +600,7 @@ export class ProblemFileDownloadHandler extends ProblemDetailHandler { } if (type === 'testdata' && !this.user.own(this.pdoc)) { if (!this.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)) this.checkPerm(PERM.PERM_READ_PROBLEM_DATA); + if (this.tdoc && !contest.isDone(this.tdoc)) throw new ContestNotEndedError(this.tdoc.domainId, this.tdoc.docId); } const target = `problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${filename}`; const file = await storage.getMeta(target); diff --git a/packages/hydrooj/src/handler/user.ts b/packages/hydrooj/src/handler/user.ts index d34a46ab9..887602066 100644 --- a/packages/hydrooj/src/handler/user.ts +++ b/packages/hydrooj/src/handler/user.ts @@ -203,7 +203,7 @@ class UserRegisterWithCodeHandler extends Handler { @param('password', Types.String, isPassword) @param('verifyPassword', Types.String) - @param('uname', Types.String, isUname) + @param('uname', Types.Name, isUname) @param('code', Types.String) async post( domainId: string, password: string, verify: string, diff --git a/packages/hydrooj/src/lib/validator.ts b/packages/hydrooj/src/lib/validator.ts index bc085558b..0fe0a4d2f 100644 --- a/packages/hydrooj/src/lib/validator.ts +++ b/packages/hydrooj/src/lib/validator.ts @@ -2,10 +2,9 @@ import { ValidationError } from '../error'; const RE_UID = /^-?\d+$/i; const RE_DOMAINID = /^[a-zA-Z][a-zA-Z0-9_]{3,31}$/i; -const RE_EXTERNAL_PID = /^[a-zA-Z][a-zA-Z0-9_]{3,31}:\d+$/i; const RE_PID = /^[a-zA-Z]+[a-zA-Z0-9]*$/i; -const RE_UNAME = /^.{3,254}$/i; -const RE_ROLE = /^[_0-9A-Za-z]{1,256}$/i; +const RE_UNAME = /^.{3,31}$/i; +const RE_ROLE = /^[_0-9A-Za-z]{1,31}$/i; const RE_MAIL = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+$/i; // eslint-disable-next-line consistent-return @@ -64,8 +63,6 @@ export const isTitle = (s) => s && s.length < 64; export const checkTitle = (s) => { if (!(s && s.length < 64)) throw new ValidationError('title'); else return s; }; export const isDomainId = (s) => RE_DOMAINID.test(s); export const checkDomainId = (s) => { if (!isDomainId(s)) throw new ValidationError('domainId'); else return s; }; -export const isExternalPid = (s) => RE_EXTERNAL_PID.test(s); -export const checkExternalPid = (s) => { if (!isExternalPid(s)) throw new ValidationError('pid'); else return s; }; export const isUid = (s) => RE_UID.test(s); export const checkUid = (s) => { if (!isUid(s)) throw new ValidationError('uid'); else return s; }; export const isUname = (s) => RE_UNAME.test(s); @@ -95,8 +92,6 @@ global.Hydro.lib.validator = { checkTitle, isDomainId, checkDomainId, - isExternalPid, - checkExternalPid, isUid, checkUid, isUname,