core: restrict testdata access from contest

This commit is contained in:
undefined committed 2021-11-23 23:17:07 +08:00
1 parent 89b32f7768
commit 40b04e900c
5 files changed
+11 -13

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "3.1.33", "version": "3.1.34",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "src/loader", "main": "src/loader",
"module": "src/loader", "module": "src/loader",
+1
View File
@@ -86,6 +86,7 @@ export const ContestNotAttendedError = Err('ContestNotAttendedError', ForbiddenE
export const RequireProError = Err('RequireProError', ForbiddenError, 'RequireProError'); export const RequireProError = Err('RequireProError', ForbiddenError, 'RequireProError');
export const ContestAlreadyAttendedError = Err('ContestAlreadyAttendedError', ForbiddenError, "You've already attended this contest."); 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 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 ContestScoreboardHiddenError = Err('ContestScoreboardHiddenError', ForbiddenError, 'Contest scoreboard is not visible.');
export const TrainingAlreadyEnrollError = Err('TrainingAlreadyEnrollError', ForbiddenError, "You've already enrolled this training."); export const TrainingAlreadyEnrollError = Err('TrainingAlreadyEnrollError', ForbiddenError, "You've already enrolled this training.");
export const HomeworkNotLiveError = Err('HomeworkNotLiveError', ForbiddenError, 'This homework is not open.'); export const HomeworkNotLiveError = Err('HomeworkNotLiveError', ForbiddenError, 'This homework is not open.');
+6 -4
View File
@@ -5,10 +5,10 @@ import { lookup } from 'mime-types';
import { FilterQuery, ObjectID } from 'mongodb'; import { FilterQuery, ObjectID } from 'mongodb';
import { sortFiles } from '@hydrooj/utils/lib/utils'; import { sortFiles } from '@hydrooj/utils/lib/utils';
import { import {
BadRequestError, ContestNotAttendedError, ContestNotFoundError, BadRequestError, ContestNotAttendedError, ContestNotEndedError,
ContestNotLiveError, ForbiddenError, NoProblemError, ContestNotFoundError, ContestNotLiveError,
NotFoundError, PermissionError, ProblemNotFoundError, ForbiddenError, NoProblemError, NotFoundError,
SolutionNotFoundError, ValidationError, PermissionError, ProblemNotFoundError, SolutionNotFoundError, ValidationError,
} from '../error'; } from '../error';
import { import {
ProblemConfig, ProblemConfig,
@@ -491,6 +491,7 @@ export class ProblemFilesHandler extends ProblemDetailHandler {
async postGetLinks(domainId: string, files: Set<string>, type = 'testdata') { async postGetLinks(domainId: string, files: Set<string>, type = 'testdata') {
if (type === 'testdata' && !this.user.own(this.pdoc)) { 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.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); if (this.pdoc.reference) this.pdoc = await problem.get(this.pdoc.reference.domainId, this.pdoc.reference.pid);
const links = {}; const links = {};
@@ -599,6 +600,7 @@ export class ProblemFileDownloadHandler extends ProblemDetailHandler {
} }
if (type === 'testdata' && !this.user.own(this.pdoc)) { 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.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 target = `problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${filename}`;
const file = await storage.getMeta(target); const file = await storage.getMeta(target);
+1 -1
View File
@@ -203,7 +203,7 @@ class UserRegisterWithCodeHandler extends Handler {
@param('password', Types.String, isPassword) @param('password', Types.String, isPassword)
@param('verifyPassword', Types.String) @param('verifyPassword', Types.String)
@param('uname', Types.String, isUname) @param('uname', Types.Name, isUname)
@param('code', Types.String) @param('code', Types.String)
async post( async post(
domainId: string, password: string, verify: string, domainId: string, password: string, verify: string,
+2 -7
View File
@@ -2,10 +2,9 @@ import { ValidationError } from '../error';
const RE_UID = /^-?\d+$/i; const RE_UID = /^-?\d+$/i;
const RE_DOMAINID = /^[a-zA-Z][a-zA-Z0-9_]{3,31}$/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_PID = /^[a-zA-Z]+[a-zA-Z0-9]*$/i;
const RE_UNAME = /^.{3,254}$/i; const RE_UNAME = /^.{3,31}$/i;
const RE_ROLE = /^[_0-9A-Za-z]{1,256}$/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; const RE_MAIL = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+$/i;
// eslint-disable-next-line consistent-return // 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 checkTitle = (s) => { if (!(s && s.length < 64)) throw new ValidationError('title'); else return s; };
export const isDomainId = (s) => RE_DOMAINID.test(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 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 isUid = (s) => RE_UID.test(s);
export const checkUid = (s) => { if (!isUid(s)) throw new ValidationError('uid'); else return s; }; export const checkUid = (s) => { if (!isUid(s)) throw new ValidationError('uid'); else return s; };
export const isUname = (s) => RE_UNAME.test(s); export const isUname = (s) => RE_UNAME.test(s);
@@ -95,8 +92,6 @@ global.Hydro.lib.validator = {
checkTitle, checkTitle,
isDomainId, isDomainId,
checkDomainId, checkDomainId,
isExternalPid,
checkExternalPid,
isUid, isUid,
checkUid, checkUid,
isUname, isUname,