diff --git a/hydro/declare.ts b/hydro/declare.ts index 2dbe926de..93f364490 100644 --- a/hydro/declare.ts +++ b/hydro/declare.ts @@ -22,7 +22,7 @@ declare global { } declare module 'cluster' { - var isFirstWorker: boolean; + let isFirstWorker: boolean; } export { }; diff --git a/hydro/handler/home.ts b/hydro/handler/home.ts index 7b9875355..9988206dd 100644 --- a/hydro/handler/home.ts +++ b/hydro/handler/home.ts @@ -1,4 +1,3 @@ -import fs from 'fs'; import { VerifyPasswordError, UserAlreadyExistError, InvalidTokenError, NotFoundError, diff --git a/hydro/handler/homework.ts b/hydro/handler/homework.ts index 0027ab47f..22d9b1acd 100644 --- a/hydro/handler/homework.ts +++ b/hydro/handler/homework.ts @@ -347,7 +347,7 @@ class HomeworkCodeHandler extends HomeworkHandler { } } -async function apply() { +export async function apply() { Route('homework_main', '/homework', HomeworkMainHandler, PERM.PERM_VIEW_HOMEWORK); Route('homework_create', '/homework/create', HomeworkCreateHandler, PERM.PERM_CREATE_HOMEWORK); Route('homework_detail', '/homework/:tid', HomeworkDetailHandler, PERM.PERM_VIEW_HOMEWORK); diff --git a/hydro/handler/import.ts b/hydro/handler/import.ts index 949ab74e7..8dedff9b8 100644 --- a/hydro/handler/import.ts +++ b/hydro/handler/import.ts @@ -1,10 +1,10 @@ import fs from 'fs'; import path from 'path'; import os from 'os'; -import { ValidationError } from '../error' +import { ValidationError } from '../error'; import * as problem from '../model/problem'; import { PERM } from '../model/builtin'; -import { Route, Handler } from '../service/server' +import { Route, Handler } from '../service/server'; class ProblemImportHandler extends Handler { async prepare() { diff --git a/hydro/handler/judge.ts b/hydro/handler/judge.ts index b2b183612..71251b595 100644 --- a/hydro/handler/judge.ts +++ b/hydro/handler/judge.ts @@ -6,7 +6,7 @@ import * as builtin from '../model/builtin'; import * as contest from '../model/contest'; import * as user from '../model/user'; import * as task from '../model/task'; -import * as bus from '../service/bus'; +import * as bus from '../service/bus'; import { Route, Handler, Connection, ConnectionHandler, } from '../service/server'; diff --git a/hydro/handler/manage.ts b/hydro/handler/manage.ts index d52515a8f..c95f50280 100644 --- a/hydro/handler/manage.ts +++ b/hydro/handler/manage.ts @@ -8,6 +8,7 @@ import * as record from '../model/record'; import { Route, Connection, Handler, ConnectionHandler, } from '../service/server'; +import { validate } from '../lib/validator'; import * as hpm from '../lib/hpm'; function set(key, value) { @@ -103,7 +104,9 @@ class SystemScriptHandler extends SystemHandler { } async post({ domainId, id, args = '{}' }) { + if (!global.Hydro.script[id]) throw new ValidationError('id'); args = JSON.parse(args); + validate(global.Hydro.script[id].validate, args); const rid = await record.add(domainId, { pid: id, uid: this.user._id, @@ -161,7 +164,7 @@ class SystemSettingHandler extends SystemHandler { } } - async post(args) { + async post(args: any) { const tasks = []; for (const key in args) { if (typeof args[key] === 'object') { diff --git a/hydro/handler/training.ts b/hydro/handler/training.ts index e179e7119..4ed016137 100644 --- a/hydro/handler/training.ts +++ b/hydro/handler/training.ts @@ -1,14 +1,14 @@ import assert from 'assert'; +import { ObjectID } from 'mongodb'; import { ValidationError, ProblemNotFoundError } from '../error'; import paginate from '../lib/paginate'; import { PERM, PRIV } from '../model/builtin'; import * as problem from '../model/problem'; -import * as builtin from '../model/builtin'; +import * as builtin from '../model/builtin'; import * as training from '../model/training'; import * as user from '../model/user'; import * as system from '../model/system'; import { Route, Handler } from '../service/server'; -import { ObjectID } from 'mongodb'; async function _parseDagJson(domainId, dag) { const parsed = []; diff --git a/hydro/lib/validator.ts b/hydro/lib/validator.ts index 796e29459..096d01484 100644 --- a/hydro/lib/validator.ts +++ b/hydro/lib/validator.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-empty */ import { ValidationError } from '../error'; const RE_UID = /^-?\d+$/i; @@ -6,6 +7,75 @@ const RE_UNAME = /[^\s\u3000](.{,254}[^\s\u3000])?$/i; const RE_ROLE = /^[_0-9A-Za-z]{1,256}$/i; const RE_MAIL = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+$/i; +// eslint-disable-next-line consistent-return +function _validate(scheme: any, arg: any, base: string) { + if (!(scheme instanceof Object)) return _validate({ $type: scheme }, arg, base); + if (scheme.$validate) scheme.$validate(arg); + if (scheme.$group) _validate(scheme.$group, arg, base); + if (scheme.$or) { + if (scheme.$or instanceof Array) { + for (const s of scheme.$or) { + let success = false; + try { + _validate(s, arg, base); + success = true; + } catch { } + // TODO beautify output + if (!success) throw new ValidationError(scheme.$or); + } + } else { + for (const skey in scheme.$or) { + let success = false; + try { + _validate(scheme.$or[skey], arg[skey], `${base}.${skey}`); + success = true; + } catch { } + // TODO beautify output + if (!success) throw new ValidationError(base, scheme.$or); + } + } + } + if (scheme.$and) for (const s of scheme.$and) _validate(s, arg, base); + if (scheme.$type) { + if (typeof scheme.$type === 'string') { + if (!typeof arg === scheme.$type) { + throw new ValidationError(); + } + } else if (!(arg instanceof scheme.$type)) { + throw new ValidationError(); + } + } + if (scheme.$eq && scheme.$eq !== arg) throw new ValidationError(base); + if (scheme.$not && scheme.$not === arg) throw new ValidationError(base); + if (scheme.$in && !(scheme.$in.includes(arg))) throw new ValidationError(base); + if (scheme.$nin && scheme.$nin.includes(arg)) throw new ValidationError(base); + for (const key in scheme) { + if (key[0] !== '$') { + if (arg instanceof Object) { + _validate(scheme[key], arg[key], `${base}.${key}`); + } else { + throw new ValidationError(); + } + } + } +} + +function descriptor(scheme: any) { + return function desc(target: any, name: string, descriptor: any) { + const originalMethod = descriptor.value; + descriptor.value = function val(...args: any[]) { + _validate(scheme, args[0], ''); + return originalMethod.call(this, ...args); + }; + return descriptor; + }; +} + +export function validate(scheme: any, arg: any) { + if (arguments.length === 1) return descriptor(scheme); + return _validate(scheme, arg, ''); +} + export const isTitle = (s) => s && s.length < 64; export const checkTitle = (s) => { if (!isTitle(s)) throw new ValidationError('title'); else return s; }; export const isUid = (s) => RE_UID.test(s); @@ -30,28 +100,29 @@ export const isDescription = () => true; export const checkDescription = (s) => { if (!isDescription()) throw new ValidationError('description'); else return s; }; global.Hydro.lib.validator = { - isTitle, - checkTitle, - isUid, - checkUid, - isUname, - checkUname, - isRole, - checkRole, - isPassword, - checkPassword, - isEmail, - checkEmail, - isContent, - checkContent, - isName, - checkName, - isPid, - checkPid, - isIntro, - checkIntro, - isDescription, - checkDescription, + validate: _validate, + isTitle, + checkTitle, + isUid, + checkUid, + isUname, + checkUname, + isRole, + checkRole, + isPassword, + checkPassword, + isEmail, + checkEmail, + isContent, + checkContent, + isName, + checkName, + isPid, + checkPid, + isIntro, + checkIntro, + isDescription, + checkDescription, }; /* ID_RE = re.compile(r'[^\\/\s\u3000]([^\\/\n\r]*[^\\/\s\u3000])?') diff --git a/hydro/model/domain.ts b/hydro/model/domain.ts index 9d78c7293..17c9b7b09 100644 --- a/hydro/model/domain.ts +++ b/hydro/model/domain.ts @@ -42,7 +42,7 @@ export function getMany(query: any, sort: any, page: number, limit: number) { .toArray(); } -export function getMulti(query: any) { +export function getMulti(query: any = {}) { return coll.find(query); } diff --git a/hydro/model/user.ts b/hydro/model/user.ts index 0fc04330c..2e29d1cea 100644 --- a/hydro/model/user.ts +++ b/hydro/model/user.ts @@ -44,6 +44,10 @@ export class User { role: string; + regip: () => string; + + loginip: () => string; + constructor(udoc, dudoc) { this.udoc = () => udoc; this.dudoc = () => dudoc; @@ -55,7 +59,9 @@ export class User { this.hashType = udoc.hashType || 'hydro'; this.priv = udoc.priv; this.regat = udoc.regat; + this.regip = () => udoc.regip; this.loginat = udoc.loginat; + this.loginip = () => udoc.loginip; this.perm = dudoc.perm; this.role = dudoc.role || 'default'; diff --git a/hydro/script/blacklist.js b/hydro/script/blacklist.js deleted file mode 100644 index ff875ae38..000000000 --- a/hydro/script/blacklist.js +++ /dev/null @@ -1,66 +0,0 @@ -const description = 'Add blacklist by ip, uid'; - -// This code format is just for fun. DO NOT DO THIS IN YOUR CODE ! -/* eslint-disable */ -const { ObjectID } = require('mongodb'); -const document = require('../model/document'); -const discussion = require('../model/discussion'); -const user = require('../model/user'); -const blacklist = require('../model/blacklist'); -const db = require('../service/db'); - -async function _address(ip, bset, uset, dset, dryrun, report) { - if (bset.has(ip)) - return - bset.add(ip) - report({ message: `ip ${ip}` }) - const users = await db.collection('user').find({ loginip: ip }).toArray() - const tasks = [] - for (const udoc of users) { - tasks.push(_user(udoc._id, bset, uset, dset, dryrun, report)) } - await Promise.all(tasks) - if (!dryrun) - await blacklist.add(ip) } - -async function _discussion(domainId, did, bset, uset, dset, dryrun, report) { - if (dset.has(did)) - return - dset.add(did) - const ddoc = await discussion.get(domainId, did) - if (!ddoc) - return - report({ message: `discussion ${ddoc['title']}` }) - await _user(ddoc['owner'], bset, uset, dset, dryrun, report) - if (ddoc.ip) - await _address(ddoc['ip'], bset, uset, dset, dryrun, report) - if (!dryrun) - await discussion.delete(domainId, ddoc['docId']) } - -async function _user(uid, bset, uset, dset, dryrun, report) { - if (uset.has(uid)) - return - uset.add(uid) - const udoc = await user.getById(uid) - if (!udoc) - return - report({ message: `user ${udoc['_id']} ${udoc['uname']}` }) - await _address(udoc['loginip'], bset, uset, dset, dryrun, report) - const ddocs = await db.collection('document') - .find({ docType: document.TYPE_DISCUSSION }).sort({ domainId: 1, docId: 1 }).toArray() - const tasks = [] - for (const ddoc of ddocs) - tasks.push(_discussion(ddoc.domainId, ddoc.docId, bset, uset, dset, dryrun, report)) - await Promise.all(tasks) - if (!dryrun) - await user.ban(uid) } - -async function run({address = null, discuss = null, user = null, dryrun = true}, report) { - if (address) - await _address(address, new Set(), new Set(), new Set(), dryrun, report) - if (discuss) - await _discussion(discuss.domainId, new ObjectID(discuss.did), - new Set(), new Set(), new Set(), dryrun, report) - if (user) - await _user(user, new Set(), new Set(), new Set(), dryrun, report) } - -global.Hydro.script.blacklist = module.exports = { run, description }; diff --git a/hydro/script/blacklist.ts b/hydro/script/blacklist.ts new file mode 100644 index 000000000..b78aa163c --- /dev/null +++ b/hydro/script/blacklist.ts @@ -0,0 +1,86 @@ +/* eslint-disable no-use-before-define */ +import { ObjectID } from 'mongodb'; +import * as document from '../model/document'; +import * as discussion from '../model/discussion'; +import * as user from '../model/user'; +import * as blacklist from '../model/blacklist'; +import * as db from '../service/db'; + +export const description = 'Add blacklist by ip, uid'; + +async function _address( + ip: string, + bset: Set, uset: Set, dset: Set, + dryrun: boolean, report: Function, +) { + if (bset.has(ip)) return; + bset.add(ip); + report({ message: `ip ${ip}` }); + const users = await db.collection('user').find({ loginip: ip }).toArray(); + const tasks = []; + for (const udoc of users) { + tasks.push(_user(udoc._id, bset, uset, dset, dryrun, report)); + } + await Promise.all(tasks); + if (!dryrun) await blacklist.add(ip); +} + +async function _discussion( + domainId: string, did: ObjectID, + bset: Set, uset: Set, dset: Set, + dryrun: boolean, report: Function, +) { + if (dset.has(did)) return; + dset.add(did); + const ddoc = await discussion.get(domainId, did); + if (!ddoc) return; + report({ message: `discussion ${ddoc.title}` }); + await _user(ddoc.owner, bset, uset, dset, dryrun, report); + if (ddoc.ip) await _address(ddoc.ip, bset, uset, dset, dryrun, report); + if (!dryrun) await discussion.del(domainId, ddoc.docId); +} + +async function _user( + uid: number, + bset: Set, uset: Set, dset: Set, + dryrun: boolean, report: Function, +) { + if (uset.has(uid)) return; + uset.add(uid); + const udoc = await user.getById('system', uid); + if (!udoc) return; + report({ message: `user ${udoc._id} ${udoc.uname}` }); + await _address(udoc.loginip(), bset, uset, dset, dryrun, report); + const ddocs = await db.collection('document').find({ docType: document.TYPE_DISCUSSION }) + .sort({ domainId: 1, docId: 1 }).toArray(); + const tasks = []; + for (const ddoc of ddocs) { + tasks.push(_discussion(ddoc.domainId, ddoc.docId, bset, uset, dset, dryrun, report)); + } + await Promise.all(tasks); + if (!dryrun) await user.ban(uid); +} + +export async function run({ + address = null, discuss = null, user = null, dryrun = true, +}, report) { + if (address) await _address(address, new Set(), new Set(), new Set(), dryrun, report); + if (discuss) { + await _discussion( + discuss.domainId, new ObjectID(discuss.did), + new Set(), new Set(), new Set(), dryrun, report, + ); + } + if (user) await _user(user, new Set(), new Set(), new Set(), dryrun, report); +} + +export const validate = { + $or: { + address: 'string', + discuss: ObjectID, + user: 'number', + }, + dryrun: 'boolean', +}; + +global.Hydro.script.blacklist = { run, description, validate }; diff --git a/hydro/script/deleteUser.js b/hydro/script/deleteUser.ts similarity index 81% rename from hydro/script/deleteUser.js rename to hydro/script/deleteUser.ts index bf96f090d..a6ff2e489 100644 --- a/hydro/script/deleteUser.js +++ b/hydro/script/deleteUser.ts @@ -1,12 +1,12 @@ -const description = 'Delete a user'; - /* eslint-disable no-await-in-loop */ -const user = require('../model/user'); -const document = require('../model/document'); -const setting = require('../model/setting'); -const db = require('../service/db'); -const paginate = require('../lib/paginate'); -const { STATUS, PRIV } = require('../model/builtin'); +import * as user from '../model/user'; +import * as document from '../model/document'; +import * as setting from '../model/setting'; +import * as db from '../service/db'; +import paginate from '../lib/paginate'; +import { STATUS, PRIV } from '../model/builtin'; + +export const description = 'Delete a user'; const collDocument = db.collection('document'); const collStatus = db.collection('document.status'); @@ -19,7 +19,7 @@ for (const s of setting.PREFERENCE_SETTINGS) { $unset[s.key] = ''; } -async function deleteRecord(uid) { +async function deleteRecord(uid: number) { const [, pcount] = await paginate( collRecord.find(), 1, @@ -45,7 +45,7 @@ async function deleteRecord(uid) { await collRecord.deleteMany({ uid }); } -async function deleteDiscussion(uid) { +async function deleteDiscussion(uid: number) { const [, pcount] = await paginate( collDocument.find({ docType: document.TYPE_DISCUSSION, owner: uid }), 1, @@ -70,7 +70,7 @@ async function deleteDiscussion(uid) { // TODO delete replies } -async function run({ +export async function run({ uid, }) { await deleteRecord(uid); @@ -87,4 +87,8 @@ async function run({ return uid; } -global.Hydro.script.deleteUser = module.exports = { run, description }; +export const validate = { + uid: 'number', +}; + +global.Hydro.script.deleteUser = { run, description, validate }; diff --git a/hydro/script/install.js b/hydro/script/install.ts similarity index 73% rename from hydro/script/install.js rename to hydro/script/install.ts index d3a94efab..27a4eaa51 100644 --- a/hydro/script/install.js +++ b/hydro/script/install.ts @@ -1,12 +1,12 @@ -const description = 'Install'; +import { PRIV } from '../model/builtin'; +import * as system from '../model/system'; +import * as user from '../model/user'; +import * as domain from '../model/domain'; +import pwhash from '../lib/hash.hydro'; -const { PRIV_ALL } = require('../model/builtin').PRIV; -const system = require('../model/system'); -const user = require('../model/user'); -const domain = require('../model/domain'); -const pwhash = require('../lib/hash.hydro'); +export const description = 'Install'; -async function run({ username, password } = {}) { +export async function run({ username = '', password = '' } = {}) { const def = { PROBLEM_PER_PAGE: 100, RECORD_PER_PAGE: 100, @@ -52,7 +52,7 @@ async function run({ username, password } = {}) { uname: username, password, regip: '127.0.0.1', - priv: PRIV_ALL, + priv: PRIV.PRIV_ALL, }); } else { const salt = String.random(); @@ -60,11 +60,18 @@ async function run({ username, password } = {}) { uname: username, unameLower: username.trim().toLowerCase(), salt, - hash: pwhash.default(password, salt), + hash: pwhash(password, salt), hashType: 'hydro', }); } } } -global.Hydro.script.install = module.exports = { run, description }; +export const validate = { + $or: [ + { username: 'string', password: 'string' }, + { username: 'undefined', password: 'undefined' }, + ], +}; + +global.Hydro.script.install = { run, description, validate }; diff --git a/hydro/script/problemStat.js b/hydro/script/problemStat.ts similarity index 65% rename from hydro/script/problemStat.js rename to hydro/script/problemStat.ts index f3b308292..265ebf63a 100644 --- a/hydro/script/problemStat.js +++ b/hydro/script/problemStat.ts @@ -1,10 +1,10 @@ -const description = 'Recalcuates nSubmit and nAccept in problem status.'; +import * as db from '../service/db'; +import { STATUS } from '../model/builtin'; +import * as document from '../model/document'; -const db = require('../service/db'); -const { STATUS_ACCEPTED } = require('../model/builtin').STATUS; -const document = require('../model/document'); +export const description = 'Recalcuates nSubmit and nAccept in problem status.'; -async function run() { +export async function run() { const pipeline = [ { $match: { hidden: false, type: { $ne: 'run' } }, @@ -15,7 +15,7 @@ async function run() { nSubmit: { $sum: 1 }, nAccept: { $sum: { - $cond: [{ $eq: ['$status', STATUS_ACCEPTED] }, 1, 0], + $cond: [{ $eq: ['$status', STATUS.STATUS_ACCEPTED] }, 1, 0], }, }, }, @@ -29,8 +29,8 @@ async function run() { }, ]; const bulk = db.collection('document').initializeUnorderedBulkOp(); - db.collection('record').aggregate(pipeline).forEach( - (adoc) => bulk.find({ + db.collection('record').aggregate(pipeline).each( + (err, adoc: any) => bulk.find({ domainId: adoc._id.domainId, docType: document.TYPE_PROBLEM, docId: adoc._id.pid, @@ -44,4 +44,6 @@ async function run() { await bulk.execute(); } -global.Hydro.script.problemStat = module.exports = { run, description }; +export const validate = {}; + +global.Hydro.script.problemStat = { run, description, validate }; diff --git a/hydro/script/rating.js b/hydro/script/rating.ts similarity index 58% rename from hydro/script/rating.js rename to hydro/script/rating.ts index ce533c6f0..2e0bb0f7d 100644 --- a/hydro/script/rating.js +++ b/hydro/script/rating.ts @@ -1,11 +1,11 @@ -const description = 'Calculate the rating of a contest'; +import { ObjectID } from 'mongodb'; +import * as contest from '../model/contest'; +import * as user from '../model/user'; +import rating from '../lib/rating'; -const { ObjectID } = require('mongodb'); -const contest = require('../model/contest'); -const user = require('../model/user'); -const rating = require('../lib/rating'); +export const description = 'Calculate the rating of a contest'; -async function run({ domainId, contestId }) { +export async function run({ domainId, contestId }) { contestId = new ObjectID(contestId); const tdoc = await contest.get(domainId, contestId); const tsdocs = await contest.getMultiStatus(domainId, { docId: contestId }) @@ -20,4 +20,9 @@ async function run({ domainId, contestId }) { return rated; } -global.Hydro.script.rating = module.exports = { run, description }; +export const validate = { + domainId: { $type: 'string' }, + contestId: { $type: ObjectID }, +}; + +global.Hydro.script.rating = { run, description, validate }; diff --git a/hydro/script/recalcRating.js b/hydro/script/recalcRating.ts similarity index 81% rename from hydro/script/recalcRating.js rename to hydro/script/recalcRating.ts index 9095a690a..42b38cae3 100644 --- a/hydro/script/recalcRating.js +++ b/hydro/script/recalcRating.ts @@ -1,13 +1,13 @@ -const description = 'Calculate rating of a domain, or all domains'; - /* eslint-disable no-await-in-loop */ -const domain = require('../model/domain'); -const contest = require('../model/contest'); -const user = require('../model/user'); -const rating = require('../lib/rating'); -const { STATUS } = require('../model/builtin'); +import * as domain from '../model/domain'; +import * as contest from '../model/contest'; +import * as user from '../model/user'; +import rating from '../lib/rating'; +import { STATUS } from '../model/builtin'; -async function run({ domainId, isSub = false }, report) { +export const description = 'Calculate rating of a domain, or all domains'; + +export async function run({ domainId, isSub = false }, report) { if (!domainId) { const domains = await domain.getMulti().toArray(); await report({ message: `Found ${domains.length} domains` }); @@ -66,4 +66,11 @@ async function run({ domainId, isSub = false }, report) { return true; } -global.Hydro.script.recalcRating = module.exports = { run, description }; +export const validate = { + $or: [ + { domainId: 'string' }, + { domainId: 'undefined' }, + ], +}; + +global.Hydro.script.recalcRating = { run, description, validate }; diff --git a/hydro/script/register.js b/hydro/script/register.js deleted file mode 100644 index 4e6fcb074..000000000 --- a/hydro/script/register.js +++ /dev/null @@ -1,18 +0,0 @@ -const description = 'Create a new user'; - -const user = require('../model/user'); -const system = require('../model/system'); - -async function run({ - uname, password, mail, uid, -}) { - if (!uid) uid = await system.inc('user'); - else uid = parseInt(uid, 10); - if (Number.isNaN(uid)) throw new Error('uid'); - await user.create({ - uid, uname, password, mail, regip: '127.0.0.1', - }); - return uid; -} - -global.Hydro.script.register = module.exports = { run, description }; diff --git a/hydro/script/register.ts b/hydro/script/register.ts new file mode 100644 index 000000000..52e0b402d --- /dev/null +++ b/hydro/script/register.ts @@ -0,0 +1,24 @@ +import * as user from '../model/user'; +import * as system from '../model/system'; + +export const description = 'Create a new user'; + +export async function run({ + uname, password, mail, uid, +}) { + if (!uid) uid = await system.inc('user'); + else uid = parseInt(uid, 10); + if (Number.isNaN(uid)) throw new Error('uid'); + await user.create({ + uid, uname, password, mail, regip: '127.0.0.1', + }); + return uid; +} + +export const validate = { + uname: { $type: 'string' }, + password: { $type: 'string' }, + mail: { $type: 'string' }, +}; + +global.Hydro.script.register = { run, description, validate }; diff --git a/hydro/script/setSuperadmin.js b/hydro/script/setSuperadmin.js deleted file mode 100644 index 28c163c48..000000000 --- a/hydro/script/setSuperadmin.js +++ /dev/null @@ -1,15 +0,0 @@ -const description = 'Set a user as superadmin.'; - -const user = require('../model/user'); -const { PRIV_ALL } = require('../model/builtin').PRIV; - -async function run({ - uid, -}) { - uid = parseInt(uid, 10); - if (Number.isNaN(uid)) throw new Error('uid'); - await user.setPriv(uid, PRIV_ALL); - return uid; -} - -global.Hydro.script.setSuperadmin = module.exports = { run, description }; diff --git a/hydro/script/setSuperadmin.ts b/hydro/script/setSuperadmin.ts new file mode 100644 index 000000000..10404b2fc --- /dev/null +++ b/hydro/script/setSuperadmin.ts @@ -0,0 +1,17 @@ +import * as user from '../model/user'; +import { PRIV } from '../model/builtin'; + +export const description = 'Set a user as superadmin.'; + +export async function run({ uid }) { + uid = parseInt(uid, 10); + if (Number.isNaN(uid)) throw new Error('uid'); + await user.setPriv(uid, PRIV.PRIV_ALL); + return uid; +} + +export const validate = { + uid: { $type: 'number' }, +}; + +global.Hydro.script.setSuperadmin = { run, description, validate }; diff --git a/hydro/service/db.ts b/hydro/service/db.ts index a198001c4..dcdc5fcfe 100644 --- a/hydro/service/db.ts +++ b/hydro/service/db.ts @@ -6,6 +6,7 @@ let mongourl = 'mongodb://'; if (options.username) mongourl += `${options.username}:${options.password}@`; mongourl += `${options.host}:${options.port}/${options.name}`; +// eslint-disable-next-line import/no-mutable-exports export let db: mongodb.Db = null; mongodb.MongoClient.connect(mongourl, { useNewUrlParser: true, useUnifiedTopology: true }) diff --git a/package.json b/package.json index d47933a92..901ec1645 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "build:all": "cd ui && yarn && yarn build:production && cd .. && yarn && yarn build && yarn pack:production", "start": "ts-node hydro/loader.ts", "pkg": "pkg .", - "lint": "eslint build hydro module tool --fix", + "lint": "eslint build hydro module tool --ext ts,js --fix", "snyk-protect": "snyk protect", "prepare": "yarn run snyk-protect" }, @@ -86,4 +86,4 @@ ] }, "snyk": true -} \ No newline at end of file +}