core: add jsc loader

This commit is contained in:
undefined committed 2022-02-28 14:21:44 +08:00
1 parent 5d27bce80e
commit 6a289f788d
5 files changed
+48 -39

No files matched your search

+32
View File
@@ -18,6 +18,7 @@ require('source-map-support').install({
}); });
const os = require('os'); const os = require('os');
const path = require('path'); const path = require('path');
const vm = require('vm');
const fs = require('fs-extra'); const fs = require('fs-extra');
const argv = require('cac')().parse(); const argv = require('cac')().parse();
const child = require('child_process'); const child = require('child_process');
@@ -60,6 +61,10 @@ function transform(filename) {
return result.code; return result.code;
} }
const ESM = ['p-queue', 'p-timeout']; 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) { require.extensions['.js'] = function loader(module, filename) {
if (ESM.filter((i) => filename.includes(i)).length || major < 14) { if (ESM.filter((i) => filename.includes(i)).length || major < 14) {
return module._compile(transform(filename), filename); 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) { require.extensions['.ts'] = require.extensions['.tsx'] = function loader(module, filename) {
return module._compile(transform(filename), 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) { function buildUrl(opts) {
let mongourl = `${opts.protocol || 'mongodb'}://`; let mongourl = `${opts.protocol || 'mongodb'}://`;
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "3.5.4", "version": "3.5.5",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "src/loader", "main": "src/loader",
"module": "src/loader", "module": "src/loader",
+2 -31
View File
@@ -105,40 +105,11 @@ export interface GDoc {
export type ownerInfo = { owner: number, maintainer?: number[] }; export type ownerInfo = { owner: number, maintainer?: number[] };
export interface User extends Record<string, any> { export type User = import('./model/user').User;
_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<T extends ownerInfo>(doc: T, checkPerm: bigint): boolean
own<T extends ownerInfo>(doc: T, exact: boolean): boolean
own<T extends ownerInfo>(doc: T): boolean
own<T extends { owner: number, maintainer?: number[] }>(doc: T): boolean;
hasPerm: (...perm: bigint[]) => boolean;
hasPriv: (...priv: number[]) => boolean;
checkPassword: (password: string) => void;
}
export type Udict = NumericDictionary<User>; export type Udict = NumericDictionary<User>;
export interface FileInfo { export interface FileInfo {
/** duplicate to filename */ /** storage path */
_id: string, _id: string,
/** filename */ /** filename */
name: string, name: string,
+1
View File
@@ -146,6 +146,7 @@ Worker.addHandler('task.daily', async () => {
if (global.Hydro.model.system.get('server.checkUpdate')) { if (global.Hydro.model.system.get('server.checkUpdate')) {
await global.Hydro.script.checkUpdate?.run({}, new Logger('task/checkUpdate').debug); 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.on('domain/delete', (domainId) => coll.deleteMany({ domainId }));
bus.once('app/started', async () => { bus.once('app/started', async () => {
+12 -7
View File
@@ -3,8 +3,8 @@ import LRU from 'lru-cache';
import { Collection, ObjectID } from 'mongodb'; import { Collection, ObjectID } from 'mongodb';
import { LoginError, UserAlreadyExistError, UserNotFoundError } from '../error'; import { LoginError, UserAlreadyExistError, UserNotFoundError } from '../error';
import { import {
FileInfo, GDoc, Udict, FileInfo, GDoc, ownerInfo,
Udoc, User as _User, VUdoc, Udict, Udoc, VUdoc,
} from '../interface'; } from '../interface';
import pwhash from '../lib/hash.hydro'; import pwhash from '../lib/hash.hydro';
import { Logger } from '../logger'; import { Logger } from '../logger';
@@ -18,10 +18,10 @@ import * as setting from './setting';
import * as system from './system'; import * as system from './system';
import token from './token'; import token from './token';
const coll: Collection<Udoc> = db.collection('user'); export const coll: Collection<Udoc> = db.collection('user');
// Virtual user, only for display in contest. // Virtual user, only for display in contest.
const collV: Collection<VUdoc> = db.collection('vuser'); export const collV: Collection<VUdoc> = db.collection('vuser');
const collGroup: Collection<GDoc> = db.collection('user.group'); export const collGroup: Collection<GDoc> = db.collection('user.group');
const logger = new Logger('model/user'); const logger = new Logger('model/user');
const cache = new LRU<string, User>({ max: 500, maxAge: 300 * 1000 }); const cache = new LRU<string, User>({ 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)); bus.on('user/delcache', (content) => deleteUserCache(JSON.parse(content), true));
class User implements _User { export class User {
_id: number; _id: number;
_udoc: Udoc; _udoc: Udoc;
@@ -108,6 +108,10 @@ class User implements _User {
return this; return this;
} }
own<T extends ownerInfo>(doc: T, checkPerm: bigint): boolean;
own<T extends ownerInfo>(doc: T, exact: boolean): boolean;
own<T extends ownerInfo>(doc: T): boolean;
own<T extends { owner: number, maintainer?: number[] }>(doc: T): boolean;
own(doc: any, arg1: any = false): boolean { own(doc: any, arg1: any = false): boolean {
if (typeof arg1 === 'bigint' && !this.hasPerm(arg1)) return false; if (typeof arg1 === 'bigint' && !this.hasPerm(arg1)) return false;
return (typeof arg1 === 'boolean' && arg1) return (typeof arg1 === 'boolean' && arg1)
@@ -135,7 +139,8 @@ class User implements _User {
const result = h(password, this._salt, this); const result = h(password, this._salt, this);
if (result !== true && result !== this._hash) { if (result !== true && result !== this._hash) {
throw new LoginError(this.uname); throw new LoginError(this.uname);
} else if (this.hashType !== 'hydro') { }
if (this.hashType !== 'hydro') {
// eslint-disable-next-line @typescript-eslint/no-use-before-define // eslint-disable-next-line @typescript-eslint/no-use-before-define
UserModel.setPassword(this._id, password); UserModel.setPassword(this._id, password);
} }