mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
Hydro.error; csrf_token validation
This commit is contained in:
1 parent
b22082beba
commit
e15c05d36b
9 files changed
+134
-267
No files matched your search
@@ -3,7 +3,7 @@
|
|||||||
Hydro是一个高效的信息学在线测评系统。
|
Hydro是一个高效的信息学在线测评系统。
|
||||||
特点: 易于部署,轻量,功能强大。
|
特点: 易于部署,轻量,功能强大。
|
||||||
|
|
||||||
[中文文档](wiki/deploy.md)
|
[中文文档](wiki/admin/deploy.md)
|
||||||
|
|
||||||
Hydro 的界面基于 Vijos 二次开发。
|
Hydro 的界面基于 Vijos 二次开发。
|
||||||
|
|
||||||
|
|||||||
+72
-237
@@ -1,254 +1,92 @@
|
|||||||
class UserFacingError extends Error {
|
/* eslint-disable func-names */
|
||||||
constructor(type) {
|
const { isClass } = require('./utils');
|
||||||
super(type);
|
|
||||||
this.code = 500;
|
|
||||||
// this.stack = '';
|
|
||||||
this.params = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SystemError extends Error {
|
const Err = (name, ...classMessageCode) => {
|
||||||
constructor(type) {
|
let Class;
|
||||||
super(type);
|
let msg;
|
||||||
this.code = 500;
|
let code;
|
||||||
// this.stack = '';
|
for (const item of classMessageCode) {
|
||||||
this.params = [];
|
if (typeof item === 'number') {
|
||||||
}
|
code = item;
|
||||||
}
|
} else if (typeof item === 'string') {
|
||||||
|
msg = function () { return item; };
|
||||||
class BadRequestError extends UserFacingError {
|
} else if (isClass(item)) {
|
||||||
constructor(type) {
|
Class = item;
|
||||||
super(type);
|
} else if (typeof item === 'function') {
|
||||||
this.code = 400;
|
msg = item;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ForbiddenError extends UserFacingError {
|
|
||||||
constructor(type) {
|
|
||||||
super(type);
|
|
||||||
this.code = 403;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotFoundError extends UserFacingError {
|
|
||||||
constructor(type) {
|
|
||||||
super(type || 'NotFoundError');
|
|
||||||
this.code = 404;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RemoteOnlineJudgeError extends UserFacingError {
|
|
||||||
constructor(message) {
|
|
||||||
super('RemoteOnlineJudgeError');
|
|
||||||
this.params = [message];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AlreadyVotedError extends BadRequestError {
|
|
||||||
constructor(psid, uid) {
|
|
||||||
super('You\'ve already voted.');
|
|
||||||
this.params = [psid, uid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoginError extends ForbiddenError {
|
|
||||||
constructor(uname) {
|
|
||||||
super('LoginError');
|
|
||||||
this.params = [uname];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserAlreadyExistError extends ForbiddenError {
|
|
||||||
constructor(uname) {
|
|
||||||
super('UserAlreadyExistError');
|
|
||||||
this.params = [uname];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class InvalidTokenError extends ForbiddenError {
|
|
||||||
constructor(token) {
|
|
||||||
super('InvalidTokenError');
|
|
||||||
this.params = [token];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BlacklistedError extends ForbiddenError {
|
|
||||||
constructor(ip) {
|
|
||||||
super('Address {0} is blacklisted.');
|
|
||||||
this.params = [ip];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserNotFoundError extends NotFoundError {
|
|
||||||
constructor(user) {
|
|
||||||
super('UserNotFoundError');
|
|
||||||
this.params = [user];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NoProblemError extends NotFoundError {
|
|
||||||
constructor() {
|
|
||||||
super('NoProblemError');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class VerifyPasswordError extends ForbiddenError {
|
|
||||||
constructor() {
|
|
||||||
super('VerifyPasswordError');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OpcountExceededError extends ForbiddenError {
|
|
||||||
constructor(op, periodSecs, maxOperations) {
|
|
||||||
super('OpcountExceededError');
|
|
||||||
this.params = [op, periodSecs, maxOperations];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PermissionError extends ForbiddenError {
|
|
||||||
constructor(perm) {
|
|
||||||
super('PermissionError');
|
|
||||||
this.params = [perm];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PrivilegeError extends ForbiddenError {
|
|
||||||
constructor(priv) {
|
|
||||||
if (priv === global.Hydro.model.builtin.PRIV.PRIV_USER_PROFILE) {
|
|
||||||
super("You're not logged in.");
|
|
||||||
} else {
|
|
||||||
super("You don't have the required privilege.");
|
|
||||||
}
|
}
|
||||||
this.params = [priv];
|
}
|
||||||
|
const HydroError = class extends Class { };
|
||||||
|
HydroError.prototype.name = name;
|
||||||
|
if (msg) HydroError.prototype.msg = msg;
|
||||||
|
if (code) HydroError.prototype.code = code;
|
||||||
|
return HydroError;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HydroError extends Error {
|
||||||
|
constructor(...params) {
|
||||||
|
super();
|
||||||
|
this.params = params;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ValidationError extends ForbiddenError {
|
const UserFacingError = Err('UserFacingError', HydroError, 'UserFacingError', 400);
|
||||||
constructor(field0, field1) {
|
const SystemError = Err('SystemError', HydroError, 'SystemError', 500);
|
||||||
super('ValidationError');
|
|
||||||
if (!field1) this.params = [field0];
|
|
||||||
else this.params = [field0, field1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ContestNotAttendedError extends ForbiddenError {
|
const BadRequestError = Err('BadRequestError', UserFacingError, 400);
|
||||||
constructor(tid) {
|
const ForbiddenError = Err('ForbiddenError', UserFacingError, 403);
|
||||||
super('You haven\'t attended this contest yet.');
|
const NotFoundError = Err('NotFoundError', UserFacingError, 404);
|
||||||
this.params = [tid];
|
const RemoteOnlineJudgeError = Err('RemoteOnlineJudgeError', UserFacingError, 500);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ContestAlreadyAttendedError extends ForbiddenError {
|
const AlreadyVotedError = Err('AlreadyVotedError', ForbiddenError, "You've already voted.");
|
||||||
constructor(tid, uid) {
|
const LoginError = Err('LoginError', ForbiddenError, 'Invalid password for user {0}.');
|
||||||
super('You\'ve already attended this contest.');
|
const UserAlreadyExistError = Err('UserAlreadyExistError', ForbiddenError, 'User {0} already exists.');
|
||||||
this.params = [tid, uid];
|
const InvalidTokenError = Err('InvalidTokenError', ForbiddenError);
|
||||||
|
const BlacklistedError = Err('BlacklistedError', ForbiddenError, 'Address or user {0} is blacklisted.');
|
||||||
|
const VerifyPasswordError = Err('VerifyPasswordError', ForbiddenError, "Passwords don't match.");
|
||||||
|
const OpcountExceededError = Err('OpcountExceededError', ForbiddenError, 'Too frequent operations of {0} (limit: {2} operations in {1} seconds).');
|
||||||
|
const PermissionError = Err('PermissionError', ForbiddenError, "You don't have the required permission ({0}) in this domain.");
|
||||||
|
const PrivilegeError = Err('PrivilegeError', ForbiddenError, function () {
|
||||||
|
if (this.params.includes(global.Hydro.model.builtin.PRIV.PRIV_USER_PROFILE)) {
|
||||||
|
return "You're not logged in.";
|
||||||
}
|
}
|
||||||
}
|
return "You don't have the required privilege.";
|
||||||
|
});
|
||||||
|
const ValidationError = Err('ValidationError', ForbiddenError, function () {
|
||||||
|
if (this.params.length === 1) return 'Field {0} validation failed.';
|
||||||
|
return 'Field {0} or {1} validation failed.';
|
||||||
|
});
|
||||||
|
const ContestNotAttendedError = Err('ContestNotAttendedError', ForbiddenError, "You haven't attended this contest yet.");
|
||||||
|
const ContestAlreadyAttendedError = Err('ContestAlreadyAttendedError', ForbiddenError, "You've already attended this contest.");
|
||||||
|
const ContestNotLiveError = Err('ContestNotLiveError', ForbiddenError, 'This contest is not live.');
|
||||||
|
const ContestScoreboardHiddenError = Err('ContestScoreboardHiddenError', ForbiddenError, 'Contest scoreboard is not visible.');
|
||||||
|
const TrainingAlreadyEnrollError = Err('TrainingAlreadyEnrollError', ForbiddenError, "You've already enrolled this training.");
|
||||||
|
const RoleAlreadyExistError = Err('RoleAlreadyExistError', ForbiddenError, 'This role already exists.');
|
||||||
|
const CsrfTokenError = Err('CsrfTokenError', ForbiddenError);
|
||||||
|
|
||||||
class ContestNotLiveError extends ForbiddenError {
|
const UserNotFoundError = Err('UserNotFoundError', NotFoundError, 'User {0} not found.');
|
||||||
constructor(tid) {
|
const NoProblemError = Err('NoProblemError', NotFoundError, 'No problem.');
|
||||||
super('This contest is not live.');
|
const RecordNotFoundError = Err('RecordNotFoundError', NotFoundError, 'Record {0} not found.');
|
||||||
this.params = [tid];
|
const ProblemDataNotFoundError = Err('ProblemDataNotFoundError', NotFoundError, 'Data of problem {1} not found.');
|
||||||
}
|
const MessageNotFoundError = Err('MessageNotFoundError', NotFoundError, 'Message {0} not found.');
|
||||||
}
|
const DocumentNotFoundError = Err('DocumentNotFoundError', NotFoundError, 'Document {2} not found.');
|
||||||
|
|
||||||
class ContestScoreboardHiddenError extends ForbiddenError {
|
const ProblemNotFoundError = Err('ProblemNotFountError', DocumentNotFoundError, 'Problem {1} not found.');
|
||||||
constructor(tid) {
|
const SolutionNotFoundError = Err('SolutionNotFoundError', DocumentNotFoundError);
|
||||||
super('Contest scoreboard is not visible.');
|
const TrainingNotFoundError = Err('TrainingNotFoundError', DocumentNotFoundError);
|
||||||
this.params = [tid];
|
const ContestNotFoundError = Err('ContestNotFoundError', DocumentNotFoundError);
|
||||||
}
|
const DiscussionNotFoundError = Err('DiscussionNotFoundError', DocumentNotFoundError, 'Discussion {0} not found.');
|
||||||
}
|
const DiscussionNodeNotFoundError = Err('DiscussionNodeNotFoundError', DocumentNotFoundError, 'Discussion node {1} not found.');
|
||||||
|
|
||||||
class TrainingAlreadyEnrollError extends ForbiddenError {
|
|
||||||
constructor(tid, uid) {
|
|
||||||
super("You've already enrolled this training.");
|
|
||||||
this.params = [tid, uid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RoleAlreadyExistError extends ForbiddenError {
|
|
||||||
constructor(role) {
|
|
||||||
super('This role already exists.');
|
|
||||||
this.params = [role];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ProblemNotFoundError extends NotFoundError {
|
|
||||||
constructor(domainId, pid) {
|
|
||||||
super('ProblemNotFoundError');
|
|
||||||
this.params = [domainId, pid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RecordNotFoundError extends NotFoundError {
|
|
||||||
constructor(rid) {
|
|
||||||
super('RecordNotFoundError');
|
|
||||||
this.params = [rid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SolutionNotFoundError extends NotFoundError {
|
|
||||||
constructor(psid) {
|
|
||||||
super('SolutionNotFoundError');
|
|
||||||
this.params = [psid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TrainingNotFoundError extends NotFoundError {
|
|
||||||
constructor(tid) {
|
|
||||||
super('TrainingNotFoundError');
|
|
||||||
this.params = [tid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ContestNotFoundError extends NotFoundError {
|
|
||||||
constructor(cid) {
|
|
||||||
super('ContestNotFoundError');
|
|
||||||
this.params = [cid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ProblemDataNotFoundError extends NotFoundError {
|
|
||||||
constructor(pid) {
|
|
||||||
super('Data of problem {0} not found.');
|
|
||||||
this.params = [pid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DiscussionNodeNotFoundError extends NotFoundError {
|
|
||||||
constructor(type, docId) {
|
|
||||||
super('Discussion node {0}/{1} not found.');
|
|
||||||
this.params = [type, docId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DocumentNotFoundError extends NotFoundError {
|
|
||||||
constructor(docId) {
|
|
||||||
super('Document {0} not found.');
|
|
||||||
this.params = [docId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DiscussionNotFoundError extends NotFoundError {
|
|
||||||
constructor(did) {
|
|
||||||
super('Discussion {0} not found.');
|
|
||||||
this.params = [did];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MessageNotFoundError extends NotFoundError {
|
|
||||||
constructor(mid) {
|
|
||||||
super('Message {0} not found.');
|
|
||||||
this.params = [mid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Hydro.error = module.exports = {
|
global.Hydro.error = module.exports = {
|
||||||
|
Err,
|
||||||
|
HydroError,
|
||||||
BadRequestError,
|
BadRequestError,
|
||||||
BlacklistedError,
|
BlacklistedError,
|
||||||
ForbiddenError,
|
ForbiddenError,
|
||||||
NotFoundError,
|
NotFoundError,
|
||||||
LoginError,
|
LoginError,
|
||||||
|
CsrfTokenError,
|
||||||
UserAlreadyExistError,
|
UserAlreadyExistError,
|
||||||
InvalidTokenError,
|
InvalidTokenError,
|
||||||
UserNotFoundError,
|
UserNotFoundError,
|
||||||
@@ -291,9 +129,6 @@ class FileTypeNotAllowedError(ValidationError):
|
|||||||
def message(self):
|
def message(self):
|
||||||
return 'This type of files are not allowed to be uploaded.'
|
return 'This type of files are not allowed to be uploaded.'
|
||||||
|
|
||||||
class CsrfTokenError(ForbiddenError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class InvalidOperationError(ForbiddenError):
|
class InvalidOperationError(ForbiddenError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
const setting = require('../model/setting');
|
const setting = require('../model/setting');
|
||||||
const system = require('../model/system');
|
const system = require('../model/system');
|
||||||
const { STATUS } = require('../model/builtin');
|
const { STATUS, PRIV } = require('../model/builtin');
|
||||||
const record = require('../model/record');
|
const record = require('../model/record');
|
||||||
const judge = require('./judge');
|
const judge = require('./judge');
|
||||||
const { Route, Handler } = require('../service/server');
|
const { Route, Handler } = require('../service/server');
|
||||||
const hpm = require('../lib/hpm');
|
const hpm = require('../lib/hpm');
|
||||||
const loader = require('../loader');
|
const loader = require('../loader');
|
||||||
const { PermissionError } = require('../error');
|
|
||||||
|
|
||||||
class SystemHandler extends Handler {
|
class SystemHandler extends Handler {
|
||||||
async prepare() {
|
async prepare() {
|
||||||
if (!this.user.priv) throw new PermissionError('???');
|
this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
|
||||||
this.response.body = {
|
this.response.body = {
|
||||||
path: [
|
path: [
|
||||||
['Hydro', 'homepage'],
|
['Hydro', 'homepage'],
|
||||||
|
|||||||
+2
-2
@@ -42,8 +42,8 @@ Item('homework_main', null, 'homework', PERM.PERM_VIEW_HOMEWORK);
|
|||||||
Item('discussion_main', null, 'discussion', PERM.PERM_VIEW_DISCUSSION);
|
Item('discussion_main', null, 'discussion', PERM.PERM_VIEW_DISCUSSION);
|
||||||
Item('contest_main', null, 'contest', PERM.PERM_VIEW_CONTEST);
|
Item('contest_main', null, 'contest', PERM.PERM_VIEW_CONTEST);
|
||||||
Item('record_main', null, 'record');
|
Item('record_main', null, 'record');
|
||||||
Item('ranking', null, 'ranking');
|
Item('ranking', null, 'ranking', PERM.PERM_VIEW_RANKING);
|
||||||
Item('domain_dashboard', null, 'domain', PERM.PERM_EDIT_DOMAIN);
|
Item('domain_dashboard', null, 'domain', PERM.PERM_EDIT_DOMAIN);
|
||||||
Item('manage_dashboard', null, 'manage', PRIV.PRIV_SET_PRIV);
|
Item('manage_dashboard', null, 'manage', PRIV.PRIV_EDIT_SYSTEM);
|
||||||
|
|
||||||
global.Hydro.lib.nav = module.exports = Item;
|
global.Hydro.lib.nav = module.exports = Item;
|
||||||
@@ -160,7 +160,8 @@ PERM.PERM_BASIC = PERM.PERM_VIEW
|
|||||||
+ PERM.PERM_VIEW_CONTEST_SCOREBOARD
|
+ PERM.PERM_VIEW_CONTEST_SCOREBOARD
|
||||||
+ PERM.PERM_VIEW_HOMEWORK
|
+ PERM.PERM_VIEW_HOMEWORK
|
||||||
+ PERM.PERM_VIEW_HOMEWORK_SCOREBOARD
|
+ PERM.PERM_VIEW_HOMEWORK_SCOREBOARD
|
||||||
+ PERM.PERM_VIEW_TRAINING;
|
+ PERM.PERM_VIEW_TRAINING
|
||||||
|
+ PERM.PERM_VIEW_RANKING;
|
||||||
|
|
||||||
PERM.PERM_DEFAULT = PERM.PERM_VIEW
|
PERM.PERM_DEFAULT = PERM.PERM_VIEW
|
||||||
+ PERM.PERM_VIEW_PROBLEM
|
+ PERM.PERM_VIEW_PROBLEM
|
||||||
@@ -203,7 +204,8 @@ PERM.PERM_DEFAULT = PERM.PERM_VIEW
|
|||||||
+ PERM.PERM_REPLY_DISCUSSION
|
+ PERM.PERM_REPLY_DISCUSSION
|
||||||
+ PERM.PERM_ATTEND_CONTEST
|
+ PERM.PERM_ATTEND_CONTEST
|
||||||
+ PERM.PERM_CREATE_TRAINING
|
+ PERM.PERM_CREATE_TRAINING
|
||||||
+ PERM.PERM_ATTEND_HOMEWORK;
|
+ PERM.PERM_ATTEND_HOMEWORK
|
||||||
|
+ PERM.PERM_VIEW_RANKING;
|
||||||
|
|
||||||
PERM.PERM_ADMIN = PERM.PERM_ALL;
|
PERM.PERM_ADMIN = PERM.PERM_ALL;
|
||||||
|
|
||||||
|
|||||||
+10
-7
@@ -53,14 +53,17 @@ async function get(tokenId, tokenType) {
|
|||||||
*/
|
*/
|
||||||
async function update(tokenId, tokenType, expireSeconds, data) {
|
async function update(tokenId, tokenType, expireSeconds, data) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const res = await coll.findOneAndUpdate({ _id: tokenId, tokenType }, {
|
const res = await coll.updateOne(
|
||||||
$set: {
|
{ _id: tokenId, tokenType },
|
||||||
...data,
|
{
|
||||||
updateAt: now,
|
$set: {
|
||||||
expireAt: new Date(now.getTime() + expireSeconds * 1000),
|
...data,
|
||||||
tokenType,
|
updateAt: now,
|
||||||
|
expireAt: new Date(now.getTime() + expireSeconds * 1000),
|
||||||
|
tokenType,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
);
|
||||||
return res.value;
|
return res.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-14
@@ -22,6 +22,7 @@ const opcount = require('../model/opcount');
|
|||||||
const {
|
const {
|
||||||
UserNotFoundError, BlacklistedError, PermissionError,
|
UserNotFoundError, BlacklistedError, PermissionError,
|
||||||
UserFacingError, ValidationError, PrivilegeError,
|
UserFacingError, ValidationError, PrivilegeError,
|
||||||
|
CsrfTokenError,
|
||||||
} = require('../error');
|
} = require('../error');
|
||||||
|
|
||||||
let enableLog = true;
|
let enableLog = true;
|
||||||
@@ -282,6 +283,11 @@ class Handler {
|
|||||||
this.preferJson = (this.request.headers.accept || '').includes('application/json');
|
this.preferJson = (this.request.headers.accept || '').includes('application/json');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async checkCsrfToken(csrfToken) {
|
||||||
|
const sdoc = await token.get(csrfToken, token.TYPE_CSRF_TOKEN);
|
||||||
|
if (!sdoc || sdoc.uid !== this.user._id) throw new CsrfTokenError(csrfToken);
|
||||||
|
}
|
||||||
|
|
||||||
async ___cleanup() {
|
async ___cleanup() {
|
||||||
try {
|
try {
|
||||||
await this.renderBody();
|
await this.renderBody();
|
||||||
@@ -361,12 +367,12 @@ class Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async onerror(error) {
|
async onerror(error) {
|
||||||
console.error(error.message, error.params);
|
console.error(error.msg(), error.params);
|
||||||
console.error(error.stack);
|
console.error(error.stack);
|
||||||
this.response.status = error instanceof UserFacingError ? error.code : 500;
|
this.response.status = error instanceof UserFacingError ? error.code : 500;
|
||||||
this.response.template = error instanceof UserFacingError ? 'error.html' : 'bsod.html';
|
this.response.template = error instanceof UserFacingError ? 'error.html' : 'bsod.html';
|
||||||
this.response.body = {
|
this.response.body = {
|
||||||
error: { message: error.message, params: error.params, stack: error.stack },
|
error: { message: error.msg(), params: error.params, stack: error.stack },
|
||||||
};
|
};
|
||||||
await this.___cleanup().catch(() => { });
|
await this.___cleanup().catch(() => { });
|
||||||
}
|
}
|
||||||
@@ -384,6 +390,7 @@ async function handle(ctx, HandlerClass, checker) {
|
|||||||
|
|
||||||
if (h.___prepare) await h.___prepare(args);
|
if (h.___prepare) await h.___prepare(args);
|
||||||
if (checker) checker.call(h);
|
if (checker) checker.call(h);
|
||||||
|
if (method === 'post') await h.checkCsrfToken(args.csrfToken);
|
||||||
|
|
||||||
let checking = '';
|
let checking = '';
|
||||||
try {
|
try {
|
||||||
@@ -421,10 +428,16 @@ async function handle(ctx, HandlerClass, checker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Checker = (perm, priv, checker) => function __() {
|
||||||
|
checker();
|
||||||
|
if (perm) this.checkPerm(perm);
|
||||||
|
if (priv) this.checkPriv(priv);
|
||||||
|
};
|
||||||
|
|
||||||
function Route(name, route, RouteHandler, ...permPrivChecker) {
|
function Route(name, route, RouteHandler, ...permPrivChecker) {
|
||||||
let _priv;
|
let _priv;
|
||||||
let _perm;
|
let _perm;
|
||||||
let checker;
|
let checker = () => { };
|
||||||
for (const item of permPrivChecker) {
|
for (const item of permPrivChecker) {
|
||||||
if (typeof item === 'object') {
|
if (typeof item === 'object') {
|
||||||
if (typeof item.call !== 'undefined') {
|
if (typeof item.call !== 'undefined') {
|
||||||
@@ -440,17 +453,7 @@ function Route(name, route, RouteHandler, ...permPrivChecker) {
|
|||||||
_perm = item;
|
_perm = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((_perm || _priv) && checker) {
|
checker = Checker(_perm, _priv, checker);
|
||||||
checker = ((_chk) => function __() {
|
|
||||||
_chk();
|
|
||||||
if (_perm) this.checkPerm(_perm);
|
|
||||||
if (_priv) this.checkPriv(_priv);
|
|
||||||
})(checker);
|
|
||||||
} else if (_perm) {
|
|
||||||
checker = function __() {
|
|
||||||
this.checkPerm(_perm);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
router.all(name, route, (ctx) => handle(ctx, RouteHandler, checker));
|
router.all(name, route, (ctx) => handle(ctx, RouteHandler, checker));
|
||||||
router.all(`${name}_with_domainId`, `/d/:domainId${route}`, (ctx) => handle(ctx, RouteHandler, checker));
|
router.all(`${name}_with_domainId`, `/d/:domainId${route}`, (ctx) => handle(ctx, RouteHandler, checker));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,3 +130,27 @@ function parseMemoryMB(str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exports.parseMemoryMB = parseMemoryMB;
|
exports.parseMemoryMB = parseMemoryMB;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an object could be an instantiable class.
|
||||||
|
* @param {any} obj
|
||||||
|
* @param {boolean} strict
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function isClass(obj, strict = false) {
|
||||||
|
if (typeof obj !== 'function') return false;
|
||||||
|
const str = obj.toString();
|
||||||
|
if (obj.prototype === undefined) return false;
|
||||||
|
if (obj.prototype.constructor !== obj) return false;
|
||||||
|
if (str.slice(0, 5) === 'class') return true;
|
||||||
|
if (Object.getOwnPropertyNames(obj.prototype).length >= 2) return true;
|
||||||
|
if (/^function\s+\(|^function\s+anonymous\(/.test(str)) return false;
|
||||||
|
if (strict && /^function\s+[A-Z]/.test(str)) return true;
|
||||||
|
if (/\b\(this\b|\bthis[.[]\b/.test(str)) {
|
||||||
|
if (!strict || /classCallCheck\(this/.test(str)) return true;
|
||||||
|
return /^function\sdefault_\d+\s*\(/.test(str);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.isClass = isClass;
|
||||||
+2
-1
@@ -25,7 +25,8 @@
|
|||||||
<span style="color: #66d9ef">return</span> <span style="color: #ae81ff">0</span><span style="color: #f8f8f2">;</span>
|
<span style="color: #66d9ef">return</span> <span style="color: #ae81ff">0</span><span style="color: #f8f8f2">;</span>
|
||||||
<span style="color: #f8f8f2">}</span>
|
<span style="color: #f8f8f2">}</span>
|
||||||
<span style="color: #75715e">/*</span>
|
<span style="color: #75715e">/*</span>
|
||||||
<span style="color: #75715e">{{error.stack}}</span>
|
<span style="color: #75715e">{{ error.message }}</span>
|
||||||
|
<span style="color: #75715e">{{ error.stack }}</span>
|
||||||
<span style="color: #75715e">*/</span>
|
<span style="color: #75715e">*/</span>
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user