core: list all domains for users with PRIV_VIEW_ALL_DOMAIN

This commit is contained in:
undefined committed 2021-05-11 23:38:34 +08:00
1 parent ced60e6567
commit 29965f323b
16 files changed
+53 -26

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "2.25.9", "version": "2.25.10",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "dist/loader.js", "main": "dist/loader.js",
"typings": "dist/loader.d.ts", "typings": "dist/loader.d.ts",
+3 -1
View File
@@ -296,7 +296,9 @@ export class ContestProblemFileDownloadHandler extends ContestProblemHandler {
@param('filename', Types.Name) @param('filename', Types.Name)
@param('noDisposition', Types.Boolean) @param('noDisposition', Types.Boolean)
async get(domainId: string, type = 'additional_file', filename: string, noDisposition = false) { async get(domainId: string, type = 'additional_file', filename: string, noDisposition = false) {
if (type === 'testdata' && !this.user.own(this.pdoc)) this.checkPerm(PERM.PERM_READ_PROBLEM_DATA); if (type === 'testdata' && !this.user.own(this.pdoc)) {
if (!this.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)) this.checkPerm(PERM.PERM_READ_PROBLEM_DATA);
}
this.response.redirect = await storage.signDownloadLink( this.response.redirect = await storage.signDownloadLink(
`problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${filename}`, `problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${filename}`,
noDisposition ? undefined : filename, false, 'user', noDisposition ? undefined : filename, false, 'user',
+11 -4
View File
@@ -5,7 +5,7 @@ import {
NotFoundError, UserNotFoundError, PermissionError, NotFoundError, UserNotFoundError, PermissionError,
DomainAlreadyExistsError, ValidationError, BlacklistedError, DomainAlreadyExistsError, ValidationError, BlacklistedError,
} from '../error'; } from '../error';
import { Mdoc, Setting } from '../interface'; import { Mdoc, Setting, DomainDoc } from '../interface';
import * as bus from '../service/bus'; import * as bus from '../service/bus';
import { import {
Route, Connection, Handler, ConnectionHandler, param, Types, Route, Connection, Handler, ConnectionHandler, param, Types,
@@ -281,9 +281,16 @@ class HomeDomainHandler extends Handler {
['Hydro', 'homepage'], ['Hydro', 'homepage'],
['home_domain', null], ['home_domain', null],
]; ];
const dudict = await domain.getDictUserByDomainId(this.user._id); let ddocs: DomainDoc[];
const dids = Object.keys(dudict); let dudict: Record<string, DomainDoc>;
const ddocs = await domain.getMulti({ _id: { $in: dids } }).toArray(); if (!this.user.hasPriv(PRIV.PRIV_VIEW_ALL_DOMAIN)) {
dudict = await domain.getDictUserByDomainId(this.user._id);
const dids = Object.keys(dudict);
ddocs = await domain.getMulti({ _id: { $in: dids } }).toArray();
} else {
ddocs = await domain.getMulti().toArray();
for (const ddoc of ddocs) dudict[ddoc._id] = ddoc;
}
const canManage = {}; const canManage = {};
for (const ddoc of ddocs) { for (const ddoc of ddocs) {
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
+2 -2
View File
@@ -13,7 +13,7 @@ import {
} from '../service/server'; } from '../service/server';
import * as bus from '../service/bus'; import * as bus from '../service/bus';
import domain from '../model/domain'; import domain from '../model/domain';
import { PERM } from '../model/builtin'; import { PERM, PRIV } from '../model/builtin';
import user from '../model/user'; import user from '../model/user';
import * as system from '../model/system'; import * as system from '../model/system';
import * as contest from '../model/contest'; import * as contest from '../model/contest';
@@ -391,7 +391,7 @@ class HomeworkScoreboardDownloadHandler extends Handler {
class HomeworkCodeHandler extends Handler { class HomeworkCodeHandler extends Handler {
@param('tid', Types.ObjectID) @param('tid', Types.ObjectID)
async get(domainId: string, tid: ObjectID) { async get(domainId: string, tid: ObjectID) {
this.checkPerm(PERM.PERM_READ_RECORD_CODE); if (!this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE)) this.checkPerm(PERM.PERM_READ_RECORD_CODE);
await this.limitRate('homework_code', 3600, 60); await this.limitRate('homework_code', 3600, 60);
const [tdoc, tsdocs] = await contest.getAndListStatus( const [tdoc, tsdocs] = await contest.getAndListStatus(
domainId, tid, document.TYPE_HOMEWORK, domainId, tid, document.TYPE_HOMEWORK,
+7 -3
View File
@@ -380,7 +380,9 @@ export class ProblemFilesHandler extends ProblemDetailHandler {
@param('testdata', Types.Boolean) @param('testdata', Types.Boolean)
@param('additional_file', Types.Boolean) @param('additional_file', Types.Boolean)
async get(domainId: string, getTestdata = true, getAdditionalFile = true) { async get(domainId: string, getTestdata = true, getAdditionalFile = true) {
const canReadData = !this.user.own(this.pdoc) || this.user.hasPerm(PERM.PERM_READ_PROBLEM_DATA); const canReadData = this.user.own(this.pdoc)
|| this.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)
|| this.user.hasPerm(PERM.PERM_READ_PROBLEM_DATA);
this.response.body.testdata = (getTestdata && canReadData) ? sortFiles(this.pdoc.data || []) : []; this.response.body.testdata = (getTestdata && canReadData) ? sortFiles(this.pdoc.data || []) : [];
this.response.body.additional_file = getAdditionalFile ? sortFiles(this.pdoc.additional_file || []) : []; this.response.body.additional_file = getAdditionalFile ? sortFiles(this.pdoc.additional_file || []) : [];
this.response.template = 'problem_files.html'; this.response.template = 'problem_files.html';
@@ -390,7 +392,7 @@ export class ProblemFilesHandler extends ProblemDetailHandler {
@post('type', Types.Range(['testdata', 'additional_file']), true) @post('type', Types.Range(['testdata', 'additional_file']), true)
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)) {
this.checkPerm(PERM.PERM_READ_PROBLEM_DATA); if (!this.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)) this.checkPerm(PERM.PERM_READ_PROBLEM_DATA);
} }
const links = {}; const links = {};
for (const file of files) { for (const file of files) {
@@ -449,7 +451,9 @@ export class ProblemFileDownloadHandler extends ProblemDetailHandler {
@param('filename', Types.Name) @param('filename', Types.Name)
@param('noDisposition', Types.Boolean) @param('noDisposition', Types.Boolean)
async get(domainId: string, type = 'additional_file', filename: string, noDisposition = false) { async get(domainId: string, type = 'additional_file', filename: string, noDisposition = false) {
if (type === 'testdata' && !this.user.own(this.pdoc)) this.checkPerm(PERM.PERM_READ_PROBLEM_DATA); if (type === 'testdata' && !this.user.own(this.pdoc)) {
if (!this.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)) this.checkPerm(PERM.PERM_READ_PROBLEM_DATA);
}
this.response.redirect = await storage.signDownloadLink( this.response.redirect = await storage.signDownloadLink(
`problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${filename}`, `problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${filename}`,
noDisposition ? undefined : filename, false, 'user', noDisposition ? undefined : filename, false, 'user',
+3 -1
View File
@@ -92,7 +92,9 @@ class RecordDetailHandler extends Handler {
const tdoc = await contest.get(domainId, rdoc.contest.tid, rdoc.contest.type); const tdoc = await contest.get(domainId, rdoc.contest.tid, rdoc.contest.type);
if (!contest.canShowRecord.call(this, tdoc, true)) throw new PermissionError(rid); if (!contest.canShowRecord.call(this, tdoc, true)) throw new PermissionError(rid);
} }
if (rdoc.uid !== this.user._id && !this.user.hasPerm(PERM.PERM_READ_RECORD_CODE)) rdoc.code = null; if (rdoc.uid !== this.user._id && !this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE)) {
if (!this.user.hasPerm(PERM.PERM_READ_RECORD_CODE)) rdoc.code = null;
}
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let [pdoc, udoc] = await Promise.all([ let [pdoc, udoc] = await Promise.all([
problem.get(domainId, rdoc.pid), problem.get(domainId, rdoc.pid),
+3 -3
View File
@@ -6,7 +6,7 @@ import { PermissionError, InvalidTokenError, RemoteOnlineJudgeError } from '../e
import { Logger } from '../logger'; import { Logger } from '../logger';
import { logAndReturn } from '../utils'; import { logAndReturn } from '../utils';
import { ProblemAdd } from '../lib/ui'; import { ProblemAdd } from '../lib/ui';
import { PERM } from '../model/builtin'; import { PERM, PRIV } from '../model/builtin';
import token from '../model/token'; import token from '../model/token';
import problem from '../model/problem'; import problem from '../model/problem';
import * as system from '../model/system'; import * as system from '../model/system';
@@ -30,7 +30,7 @@ export class ProblemSendHandler extends Handler {
const target = _target.split('@'); const target = _target.split('@');
if (target[1].endsWith('/')) target[1] = target[1].substr(0, target[1].length - 1); if (target[1].endsWith('/')) target[1] = target[1].substr(0, target[1].length - 1);
const getHidden = this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN); const getHidden = this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
const getData = this.user.hasPerm(PERM.PERM_READ_PROBLEM_DATA); const getData = this.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA) || this.user.hasPerm(PERM.PERM_READ_PROBLEM_DATA);
const pdocs = await problem.getList(domainId, _pids, true, true, ['docId', 'owner', 'hidden']); const pdocs = await problem.getList(domainId, _pids, true, true, ['docId', 'owner', 'hidden']);
const pids = new Set<number>(); const pids = new Set<number>();
for (const key in pdocs) { for (const key in pdocs) {
@@ -38,7 +38,7 @@ export class ProblemSendHandler extends Handler {
if (pdocs[key].hidden && !getHidden && !this.user.own(pdocs[key])) { if (pdocs[key].hidden && !getHidden && !this.user.own(pdocs[key])) {
throw new PermissionError(PERM.PERM_VIEW_PROBLEM_HIDDEN); throw new PermissionError(PERM.PERM_VIEW_PROBLEM_HIDDEN);
} }
if (!getData && !this.user.own(pdocs[key])) { if (!getData && !this.user.own(pdocs[key]) && !this.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA)) {
throw new PermissionError(PERM.PERM_READ_PROBLEM_DATA); throw new PermissionError(PERM.PERM_READ_PROBLEM_DATA);
} }
} }
+5 -2
View File
@@ -227,8 +227,6 @@ export const PRIV = {
PRIV_USER_PROFILE: 1 << 2, PRIV_USER_PROFILE: 1 << 2,
PRIV_REGISTER_USER: 1 << 3, PRIV_REGISTER_USER: 1 << 3,
PRIV_READ_PROBLEM_DATA: 1 << 4, PRIV_READ_PROBLEM_DATA: 1 << 4,
PRIV_READ_PRETEST_DATA: 1 << 5, // deprecated
PRIV_READ_PRETEST_DATA_SELF: 1 << 6, // deprecated
PRIV_READ_RECORD_CODE: 1 << 7, PRIV_READ_RECORD_CODE: 1 << 7,
PRIV_VIEW_HIDDEN_RECORD: 1 << 8, PRIV_VIEW_HIDDEN_RECORD: 1 << 8,
PRIV_JUDGE: 1 << 9, // (renamed) PRIV_JUDGE: 1 << 9, // (renamed)
@@ -239,11 +237,16 @@ export const PRIV = {
PRIV_VIEW_USER_SECRET: 1 << 14, PRIV_VIEW_USER_SECRET: 1 << 14,
PRIV_VIEW_JUDGE_STATISTICS: 1 << 15, PRIV_VIEW_JUDGE_STATISTICS: 1 << 15,
PRIV_UNLIMITED_ACCESS: 1 << 22, PRIV_UNLIMITED_ACCESS: 1 << 22,
PRIV_VIEW_SYSTEM_NOTIFICATION: 1 << 23,
PRIV_ALL: -1, PRIV_ALL: -1,
PRIV_DEFAULT: 0, PRIV_DEFAULT: 0,
PRIV_NEVER: 1 << 20, PRIV_NEVER: 1 << 20,
/** @deprecated */
PRIV_READ_PRETEST_DATA: 1 << 5,
/** @deprecated */
PRIV_READ_PRETEST_DATA_SELF: 1 << 6,
/** @deprecated */ /** @deprecated */
PRIV_CREATE_FILE: 1 << 16, PRIV_CREATE_FILE: 1 << 16,
/** @deprecated */ /** @deprecated */
+7 -2
View File
@@ -4,13 +4,13 @@ import {
ObjectID, Cursor, FilterQuery, UpdateQuery, OnlyFieldsOfType, ObjectID, Cursor, FilterQuery, UpdateQuery, OnlyFieldsOfType,
} from 'mongodb'; } from 'mongodb';
import { import {
Pdoc, Ddoc, Drdoc, Tdoc, TrainingDoc, ProblemStatusDoc, Pdoc, Ddoc, Drdoc, Tdoc, TrainingDoc,
ProblemStatusDoc, User, Content,
} from '../interface'; } from '../interface';
import { buildProjection } from '../utils'; import { buildProjection } from '../utils';
import { NumberKeys, ArrayKeys, Projection, MaybeArray } from '../typeutils'; import { NumberKeys, ArrayKeys, Projection, MaybeArray } from '../typeutils';
import db from '../service/db'; import db from '../service/db';
import * as bus from '../service/bus'; import * as bus from '../service/bus';
import { Content } from '../loader';
type DocID = ObjectID | string | number; type DocID = ObjectID | string | number;
@@ -44,6 +44,11 @@ export interface DocStatusType {
[key: number]: any [key: number]: any
} }
export async function canView<T extends keyof DocType>(doc: DocType[T], user: User): Promise<boolean> {
if (doc.owner === user._id || doc.maintainers.includes(user._id) || doc.participants.includes(user._id)) return true;
if ()
}
export async function add<T extends keyof DocType, K extends DocType[T]['docId']>( export async function add<T extends keyof DocType, K extends DocType[T]['docId']>(
domainId: string, content: Content, owner: number, domainId: string, content: Content, owner: number,
docType: T, docId: K, docType: T, docId: K,
+5 -1
View File
@@ -303,7 +303,11 @@ class UserModel {
@ArgMethod @ArgMethod
static async setJudge(uid: number) { static async setJudge(uid: number) {
return await UserModel.setPriv(uid, PRIV.PRIV_USER_PROFILE | PRIV.PRIV_JUDGE); return await UserModel.setPriv(
uid,
PRIV.PRIV_USER_PROFILE | PRIV.PRIV_JUDGE | PRIV.PRIV_VIEW_ALL_DOMAIN
| PRIV.PRIV_READ_PROBLEM_DATA,
);
} }
@ArgMethod @ArgMethod
+1 -1
View File
@@ -519,7 +519,7 @@ export class Handler extends HandlerCommon {
icon: global.Hydro.lib[key].icon, icon: global.Hydro.lib[key].icon,
text: global.Hydro.lib[key].text, text: global.Hydro.lib[key].text,
})); }));
if (!this.noCheckPermView) this.checkPerm(PERM.PERM_VIEW); if (!this.noCheckPermView && !this.user.hasPriv(PRIV.PRIV_VIEW_ALL_DOMAIN)) this.checkPerm(PERM.PERM_VIEW);
if (this.request.method === 'post' && this.request.headers.referer) { if (this.request.method === 'post' && this.request.headers.referer) {
const host = new URL(this.request.headers.referer).host; const host = new URL(this.request.headers.referer).host;
if (host !== this.request.host) throw new CsrfTokenError(host); if (host !== this.request.host) throw new CsrfTokenError(host);
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@hydrooj/ui-default", "name": "@hydrooj/ui-default",
"version": "4.8.6", "version": "4.8.7",
"author": "undefined <i@undefined.moe>", "author": "undefined <i@undefined.moe>",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"main": "hydro.js", "main": "hydro.js",
@@ -57,7 +57,7 @@
<span class="icon icon-edit"></span> {{ _('Edit Contest') }} <span class="icon icon-edit"></span> {{ _('Edit Contest') }}
</a></li> </a></li>
{% endif %} {% endif %}
{% if handler.user.hasPerm(perm.PERM_READ_RECORD_CODE) %} {% if handler.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE) or handler.user.hasPerm(perm.PERM_READ_RECORD_CODE) %}
<li class="menu__item"><a class="menu__link" href="{{ url('contest_code', tid=tdoc.docId) }}"> <li class="menu__item"><a class="menu__link" href="{{ url('contest_code', tid=tdoc.docId) }}">
<span class="icon icon-download"></span> {{ _('Export All Code') }} <span class="icon icon-download"></span> {{ _('Export All Code') }}
</a></li> </a></li>
@@ -57,7 +57,7 @@
<span class="icon icon-edit"></span> {{ _('Edit Homework') }} <span class="icon icon-edit"></span> {{ _('Edit Homework') }}
</a></li> </a></li>
{% endif %} {% endif %}
{% if handler.user.hasPerm(perm.PERM_READ_RECORD_CODE) %} {% if handler.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE) or handler.user.hasPerm(perm.PERM_READ_RECORD_CODE) %}
<li class="menu__item"><a class="menu__link" href="{{ url('homework_code', tid=tdoc.docId) }}"> <li class="menu__item"><a class="menu__link" href="{{ url('homework_code', tid=tdoc.docId) }}">
<span class="icon icon-download"></span> {{ _('Export All Code') }} <span class="icon icon-download"></span> {{ _('Export All Code') }}
</a></li> </a></li>
@@ -84,7 +84,7 @@
<span class="icon icon-edit"></span> {{ _('Edit') }} <span class="icon icon-edit"></span> {{ _('Edit') }}
</a></li> </a></li>
{% endif %} {% endif %}
{% if page_name == 'problem_detail' and (handler.user.own(pdoc) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA)) %} {% if page_name == 'problem_detail' and (handler.user.own(pdoc) or handler.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA)) %}
<div style="display: none" class="dialog__body--send-to"> <div style="display: none" class="dialog__body--send-to">
<div> <div>
<div class="row"><div class="columns"> <div class="row"><div class="columns">
@@ -48,7 +48,7 @@
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
{% if handler.user.own(pdoc) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA) %} {% if handler.user.own(pdoc) or handler.user.hasPriv(PRIV.PRIV_READ_PROBLEM_DATA) or handler.user.hasPerm(perm.PERM_READ_PROBLEM_DATA) %}
{{ nothing.render('No testdata at current.') }} {{ nothing.render('No testdata at current.') }}
{% else %} {% else %}
{{ nothing.render("You don't have permission to read testdata.")}} {{ nothing.render("You don't have permission to read testdata.")}}