diff --git a/packages/hydrooj/bin/hydrooj.js b/packages/hydrooj/bin/hydrooj.js index dfcb18204..f2058544e 100755 --- a/packages/hydrooj/bin/hydrooj.js +++ b/packages/hydrooj/bin/hydrooj.js @@ -18,6 +18,7 @@ require('source-map-support').install({ }); const os = require('os'); const path = require('path'); +const vm = require('vm'); const fs = require('fs-extra'); const argv = require('cac')().parse(); const child = require('child_process'); @@ -60,6 +61,10 @@ function transform(filename) { return result.code; } const ESM = ['p-queue', 'p-timeout']; +const _script = new vm.Script('"Hydro"', { produceCachedData: true }); +const bytecode = (_script.createCachedData && _script.createCachedData.call) + ? _script.createCachedData() + : _script.cachedData; require.extensions['.js'] = function loader(module, filename) { if (ESM.filter((i) => filename.includes(i)).length || major < 14) { return module._compile(transform(filename), filename); @@ -70,6 +75,33 @@ require.extensions['.js'] = function loader(module, filename) { require.extensions['.ts'] = require.extensions['.tsx'] = function loader(module, filename) { return module._compile(transform(filename), filename); }; +require.extensions['.jsc'] = function loader(module, filename) { + const buf = fs.readFileSync(filename); + bytecode.slice(12, 16).copy(buf, 12); + if (![12, 13, 14, 15, 16, 17].filter((i) => process.version.startsWith(`v${i}`)).length) { + bytecode.slice(16, 20).copy(buf, 16); + } + // eslint-disable-next-line no-return-assign + const length = buf.slice(8, 12).reduce((sum, number, power) => sum += number * (256 ** power), 0); + let dummyCode = ''; + if (length > 1) dummyCode = `"${'\u200b'.repeat(length - 2)}"`; + const script = new vm.Script(dummyCode, { + filename, + lineOffset: 0, + displayErrors: true, + cachedData: buf, + }); + if (script.cachedDataRejected) throw new Error(`cacheDataRejected on ${filename}`); + const compiledWrapper = script.runInThisContext({ + filename, + lineOffset: 0, + columnOffset: 0, + displayErrors: true, + }); + const dirname = path.dirname(filename); + const args = [module.exports, require, module, filename, dirname, process, global]; + return compiledWrapper.apply(module.exports, args); +}; function buildUrl(opts) { let mongourl = `${opts.protocol || 'mongodb'}://`; diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index e2a5c3f19..acfacec05 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "3.5.4", + "version": "3.5.5", "bin": "bin/hydrooj.js", "main": "src/loader", "module": "src/loader", diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index d64fe694b..14486c7bf 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -105,40 +105,11 @@ export interface GDoc { export type ownerInfo = { owner: number, maintainer?: number[] }; -export interface User extends Record { - _id: number; - _udoc: Udoc; - _dudoc: any; - _salt: string; - _hash: string; - _regip: string; - _loginip: string; - _tfa: string; - - mail: string; - uname: string; - hashType: string; - priv: number; - regat: Date; - loginat: Date; - perm: bigint; - scope: bigint; - role: string; - group?: string[]; - tfa: boolean; - own(doc: T, checkPerm: bigint): boolean - own(doc: T, exact: boolean): boolean - own(doc: T): boolean - own(doc: T): boolean; - hasPerm: (...perm: bigint[]) => boolean; - hasPriv: (...priv: number[]) => boolean; - checkPassword: (password: string) => void; -} - +export type User = import('./model/user').User; export type Udict = NumericDictionary; export interface FileInfo { - /** duplicate to filename */ + /** storage path */ _id: string, /** filename */ name: string, diff --git a/packages/hydrooj/src/model/task.ts b/packages/hydrooj/src/model/task.ts index 0e776d811..6208b0e65 100644 --- a/packages/hydrooj/src/model/task.ts +++ b/packages/hydrooj/src/model/task.ts @@ -146,6 +146,7 @@ Worker.addHandler('task.daily', async () => { if (global.Hydro.model.system.get('server.checkUpdate')) { await global.Hydro.script.checkUpdate?.run({}, new Logger('task/checkUpdate').debug); } + await bus.serial('task/daily'); }); bus.on('domain/delete', (domainId) => coll.deleteMany({ domainId })); bus.once('app/started', async () => { diff --git a/packages/hydrooj/src/model/user.ts b/packages/hydrooj/src/model/user.ts index 94b3f7078..d1073bb95 100644 --- a/packages/hydrooj/src/model/user.ts +++ b/packages/hydrooj/src/model/user.ts @@ -3,8 +3,8 @@ import LRU from 'lru-cache'; import { Collection, ObjectID } from 'mongodb'; import { LoginError, UserAlreadyExistError, UserNotFoundError } from '../error'; import { - FileInfo, GDoc, Udict, - Udoc, User as _User, VUdoc, + FileInfo, GDoc, ownerInfo, + Udict, Udoc, VUdoc, } from '../interface'; import pwhash from '../lib/hash.hydro'; import { Logger } from '../logger'; @@ -18,10 +18,10 @@ import * as setting from './setting'; import * as system from './system'; import token from './token'; -const coll: Collection = db.collection('user'); +export const coll: Collection = db.collection('user'); // Virtual user, only for display in contest. -const collV: Collection = db.collection('vuser'); -const collGroup: Collection = db.collection('user.group'); +export const collV: Collection = db.collection('vuser'); +export const collGroup: Collection = db.collection('user.group'); const logger = new Logger('model/user'); const cache = new LRU({ max: 500, maxAge: 300 * 1000 }); @@ -45,7 +45,7 @@ export function deleteUserCache(udoc: User | Udoc | string | undefined | null, r } bus.on('user/delcache', (content) => deleteUserCache(JSON.parse(content), true)); -class User implements _User { +export class User { _id: number; _udoc: Udoc; @@ -108,6 +108,10 @@ class User implements _User { return this; } + own(doc: T, checkPerm: bigint): boolean; + own(doc: T, exact: boolean): boolean; + own(doc: T): boolean; + own(doc: T): boolean; own(doc: any, arg1: any = false): boolean { if (typeof arg1 === 'bigint' && !this.hasPerm(arg1)) return false; return (typeof arg1 === 'boolean' && arg1) @@ -135,7 +139,8 @@ class User implements _User { const result = h(password, this._salt, this); if (result !== true && result !== this._hash) { throw new LoginError(this.uname); - } else if (this.hashType !== 'hydro') { + } + if (this.hashType !== 'hydro') { // eslint-disable-next-line @typescript-eslint/no-use-before-define UserModel.setPassword(this._id, password); }