From 79138861a6a68b879f7476c702afb0af3005c3cd Mon Sep 17 00:00:00 2001 From: undefined Date: Wed, 22 Sep 2021 23:17:53 +0800 Subject: [PATCH] core: simple vuser --- packages/hydrojudge/package.json | 4 +-- packages/hydrooj/package.json | 6 ++-- packages/hydrooj/src/interface.ts | 29 ++++++++++++++++++-- packages/hydrooj/src/model/user.ts | 44 +++++++++++++++++++++--------- 4 files changed, 63 insertions(+), 20 deletions(-) diff --git a/packages/hydrojudge/package.json b/packages/hydrojudge/package.json index 7e6442ba5..2b37b9837 100644 --- a/packages/hydrojudge/package.json +++ b/packages/hydrojudge/package.json @@ -9,7 +9,7 @@ "@hydrooj/utils": "workspace:*", "axios": "^0.21.4", "cac": "^6.7.3", - "esbuild": "^0.12.28", + "esbuild": "^0.12.29", "fs-extra": "^10.0.0", "js-yaml": "^4.1.0", "lodash": "^4.17.21", @@ -21,7 +21,7 @@ "preferUnplugged": true, "license": "AGPL-3.0-or-later", "devDependencies": { - "@types/fs-extra": "^9.0.12", + "@types/fs-extra": "^9.0.13", "@types/js-yaml": "^4.0.3", "@types/lodash": "^4.14.173", "@types/shell-quote": "^1.7.1", diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index cefe281a4..3bdc60c5a 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -1,6 +1,6 @@ { "name": "hydrooj", - "version": "2.37.8", + "version": "2.38.0", "bin": "bin/hydrooj.js", "main": "src/loader", "module": "src/loader", @@ -18,7 +18,7 @@ "cac": "^6.7.3", "cookies": "^0.8.0", "detect-browser": "^5.2.1", - "esbuild": "^0.12.28", + "esbuild": "^0.12.29", "fs-extra": "^10.0.0", "graphql": "^15.6.0", "graphql-scalars": "^1.10.1", @@ -47,7 +47,7 @@ }, "devDependencies": { "@types/adm-zip": "^0.4.34", - "@types/fs-extra": "^9.0.12", + "@types/fs-extra": "^9.0.13", "@types/js-yaml": "^4.0.3", "@types/koa": "^2.13.4", "@types/koa-compress": "^4.0.3", diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts index be95b4f52..a4d3dae1c 100644 --- a/packages/hydrooj/src/interface.ts +++ b/packages/hydrooj/src/interface.ts @@ -73,6 +73,22 @@ export interface Udoc extends Dictionary { loginip: string; } +export interface VUdoc { + _id: number; + mail: string; + mailLower: string; + uname: string; + unameLower: string; + salt: ''; + hash: ''; + hashType: 'hydro'; + priv: 0; + regat: Date; + loginat: Date; + ip: ['127.0.0.1']; + loginip: '127.0.0.1'; +} + export type ownerInfo = { owner: number, maintainer?: number[] }; export interface User extends Record { @@ -539,6 +555,14 @@ export interface EventDoc { expire: Date; } +export interface OpCountDoc { + _id: ObjectID; + op: string; + ident: string; + expireAt: Date; + opcount: number; +} + export interface Collections { 'blacklist': BlacklistDoc; 'contest': Tdoc; @@ -547,8 +571,10 @@ export interface Collections { 'domain.union': DomainUnion; 'record': RecordDoc; 'document': any; + 'document.status': any; 'problem': ProblemDoc; 'user': Udoc; + 'vuser': VUdoc; 'check': any; 'message': MessageDoc; 'token': TokenDoc; @@ -559,10 +585,9 @@ export interface Collections { 'storage': FileNode; 'oplog': OplogDoc; 'event': EventDoc; - 'opcount': any; + 'opcount': OpCountDoc; 'fs.chunks': any; 'fs.files': any; - 'document.status': any; } export interface Model { diff --git a/packages/hydrooj/src/model/user.ts b/packages/hydrooj/src/model/user.ts index f9459a208..91b5ffdfe 100644 --- a/packages/hydrooj/src/model/user.ts +++ b/packages/hydrooj/src/model/user.ts @@ -4,7 +4,7 @@ import { Collection } from 'mongodb'; import { LoginError, UserAlreadyExistError, UserNotFoundError } from '../error'; import { FileInfo, Udict, Udoc, - User as _User, + User as _User, VUdoc, } from '../interface'; import pwhash from '../lib/hash.hydro'; import { Logger } from '../logger'; @@ -19,6 +19,8 @@ import * as system from './system'; import token from './token'; const coll: Collection = db.collection('user'); +// Virtual user, only for display in contest. +const collV: Collection = db.collection('vuser'); const logger = new Logger('model/user'); const cache = new LRU({ max: 500, maxAge: 300 * 1000 }); @@ -154,7 +156,7 @@ class UserModel { @ArgMethod static async getById(domainId: string, _id: number, scope: bigint | string = PERM.PERM_ALL): Promise { if (cache.has(`id/${_id}/${domainId}`)) return cache.get(`id/${_id}/${domainId}`) || null; - const udoc = await coll.findOne({ _id }); + const udoc = await (_id < -999 ? collV : coll).findOne({ _id }); if (!udoc) return null; const dudoc = await domain.getDomainUser(domainId, udoc); if (typeof scope === 'string') scope = BigInt(scope); @@ -177,7 +179,8 @@ class UserModel { static async getByUname(domainId: string, uname: string): Promise { const unameLower = uname.trim().toLowerCase(); if (cache.has(`name/${unameLower}/${domainId}`)) return cache.get(`name/${unameLower}/${domainId}`) || null; - const udoc = await coll.findOne({ unameLower }); + let udoc = await coll.findOne({ unameLower }); + if (!udoc) udoc = await collV.findOne({ unameLower }); if (!udoc) return null; const dudoc = await domain.getDomainUser(domainId, udoc); const res = await new UserModel.User(udoc, dudoc).init(); @@ -203,6 +206,7 @@ class UserModel { @ArgMethod static async setById(uid: number, $set?: Partial, $unset?: Value, ''>) { + if (uid < 1000) return null; const op: any = {}; if ($set && Object.keys($set).length) op.$set = $set; if ($unset && Object.keys($unset).length) op.$unset = $unset; @@ -236,6 +240,7 @@ class UserModel { @ArgMethod static async inc(_id: number, field: string, n: number = 1) { + if (_id < -999) return null; const udoc = await coll.findOne({ _id }); if (!udoc) throw new UserNotFoundError(_id); udoc[field] = udoc[field] + n || n; @@ -279,16 +284,29 @@ class UserModel { } @ArgMethod - static async changeUsername(uid: number, uname: string) { - const udoc = await coll.findOne({ _id: uid }); - deleteUserCache(udoc); - const res = await coll.findOneAndUpdate( - { _id: uid }, - { $set: { uname, unameLower: uname.trim().toLowerCase() } }, - { returnDocument: 'after' }, - ); - deleteUserCache(res.value); - return res.value; + static async ensureVuser(uname: string) { + const [[min], current] = await Promise.all([ + collV.find({}).sort({ _id: -1 }).limit(1).toArray(), + collV.findOne({ unameLower: uname.toLowerCase() }), + ]); + if (current) return current._id; + const uid = min?._id ? min._id - 1 : -1000; + await collV.insertOne({ + _id: uid, + mail: `${-uid}@vuser.local`, + mailLower: `${-uid}@vuser.local`, + uname, + unameLower: uname.trim().toLowerCase(), + hash: '', + salt: '', + hashType: 'hydro', + regat: new Date(), + ip: ['127.0.0.1'], + loginat: new Date(), + loginip: '127.0.0.1', + priv: 0, + }); + return uid; } static getMulti(params: any = {}) {