core: user: private and public projection (#507)

This commit is contained in:
undefined authored and GitHub committed 2023-02-24 14:58:22 +08:00
1 parent 4fe734a6f3
commit bd13c57d82
6 files changed
+44 -26

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
interface SerializeOptions {
showDisplayName: boolean;
currentSerializer?: (k: string, v: any) => any;
}
export default function serializer(options: SerializeOptions, ignoreSerializeFunction = false) {
options.currentSerializer = (k: string, v: any) => {
if (typeof k.startsWith !== 'function') console.log(k, v);
if (k.startsWith('_') && k !== '_id') return undefined;
if (typeof v === 'bigint') return `BigInt::${v.toString()}`;
if (!ignoreSerializeFunction && v && typeof v === 'object'
&& 'serialize' in v && typeof v.serialize === 'function') return v.serialize(options);
return v;
};
return options.currentSerializer;
}
+17
View File
@@ -7,6 +7,7 @@ import {
ownerInfo, Udict, Udoc, VUdoc,
} from '../interface';
import pwhash from '../lib/hash.hydro';
import serializer from '../lib/serializer';
import * as bus from '../service/bus';
import db from '../service/db';
import { Value } from '../typeutils';
@@ -47,6 +48,7 @@ bus.on('user/delcache', (content) => deleteUserCache(typeof content === 'string'
export class User {
_id: number;
_isPrivate = false;
_udoc: Udoc;
_dudoc: any;
@@ -149,6 +151,21 @@ export class User {
UserModel.setPassword(this._id, password);
}
}
async private() {
const user = await new User(this._udoc, this._dudoc, this.scope).init();
user._isPrivate = true;
return user;
}
serialize(options) {
if (!this._isPrivate) {
const fields = ['_id', 'uname', 'mail', 'perm', 'role', 'priv', 'regat', 'loginat', 'tfa', 'authn'];
if (options.showDisplayName) fields.push('displayName');
return pick(this, fields);
}
return JSON.stringify(this, serializer({ showDisplayName: options.showDisplayName }, true));
}
}
function handleMailLower(mail: string) {
@@ -1,17 +1,10 @@
import { ObjectID } from 'mongodb';
import avatar from '../../lib/avatar';
import serializer from '../../lib/serializer';
import { PERM } from '../../model/builtin';
import * as system from '../../model/system';
import { User } from '../../model/user';
import type { KoaContext } from '../server';
const serializer = (showDisplayName = false) => (k: string, v: any) => {
if (k.startsWith('_') && k !== '_id') return undefined;
if (typeof v === 'bigint') return `BigInt::${v.toString()}`;
if (v instanceof User && !showDisplayName) delete v.displayName;
return v;
};
export default (router, logger) => async (ctx: KoaContext, next) => {
const { request, response } = ctx.HydroContext;
ctx.renderHTML = (templateName, args) => {
@@ -22,7 +15,9 @@ export default (router, logger) => async (ctx: KoaContext, next) => {
viewLang: ctx.translate('__id'),
};
const engine = global.Hydro.lib.template?.render
|| (() => JSON.stringify(args, serializer(user?.hasPerm(PERM.PREM_VIEW_DISPLAYNAME))));
|| (() => JSON.stringify(args, serializer({
showDisplayName: user?.hasPerm(PERM.PREM_VIEW_DISPLAYNAME),
})));
return engine(templateName, {
handler: ctx.handler,
UserContext,
@@ -1,16 +1,9 @@
import { errorMessage } from '@hydrooj/utils/lib/utils';
import { SystemError, UserFacingError } from '../../error';
import serializer from '../../lib/serializer';
import { PERM } from '../../model/builtin';
import { User } from '../../model/user';
import type { KoaContext } from '../server';
const serializer = (showDisplayName = false) => (k: string, v: any) => {
if (k.startsWith('_') && k !== '_id') return undefined;
if (typeof v === 'bigint') return `BigInt::${v.toString()}`;
if (v instanceof User && !showDisplayName) delete v.displayName;
return v;
};
export default (logger) => async (ctx: KoaContext, next) => {
const { request, response } = ctx.HydroContext;
try {
@@ -34,7 +27,7 @@ export default (logger) => async (ctx: KoaContext, next) => {
response.body.UiContext = UiContext;
response.body.UserContext = user;
}
response.body = JSON.stringify(response.body, serializer(user?.hasPerm(PERM.PREM_VIEW_DISPLAYNAME)));
response.body = JSON.stringify(response.body, serializer({ showDisplayName: user?.hasPerm(PERM.PREM_VIEW_DISPLAYNAME) }));
} catch (e) {
response.body = new SystemError('Serialize failure', e.message);
}
+1 -1
View File
@@ -16,7 +16,7 @@ export default async (ctx: KoaContext, next) => {
}
if (user._id === 0) delete user.viewLang;
user.avatarUrl = avatar(user.avatar, 128);
ctx.HydroContext.user = user;
ctx.HydroContext.user = await user.private();
if (!domain) {
ctx.pendingError = new NotFoundError(args.domainId);
args.domainId = 'system';
+4 -7
View File
@@ -17,6 +17,7 @@ import {
PrivilegeError, UserFacingError,
} from '../error';
import { DomainDoc } from '../interface';
import serializer from '../lib/serializer';
import { Types } from '../lib/validator';
import { Logger } from '../logger';
import { PERM, PRIV } from '../model/builtin';
@@ -109,12 +110,6 @@ wsServer.on('error', (error) => {
});
const ignoredLimit = `,${argv.options.ignoredLimit},`;
const serializer = (showDisplayName = false) => (k: string, v: any) => {
if (k.startsWith('_') && k !== '_id') return undefined;
if (typeof v === 'bigint') return `BigInt::${v.toString()}`;
if (v instanceof User && !showDisplayName) delete v.displayName;
return v;
};
export class HandlerCommon {
render: (name: string, args?: any) => Promise<void>;
@@ -341,7 +336,9 @@ export class ConnectionHandler extends HandlerCommon {
conn: WebSocket;
send(data: any) {
this.conn.send(JSON.stringify(data, serializer(this.user?.hasPerm(PERM.PREM_VIEW_DISPLAYNAME))));
this.conn.send(JSON.stringify(data, serializer({
showDisplayName: this.user?.hasPerm(PERM.PREM_VIEW_DISPLAYNAME),
})));
}
close(code: number, reason: string) {