From f5828e5cb35ab4ac0b7a0065572498ef1618b24c Mon Sep 17 00:00:00 2001 From: undefined Date: Tue, 13 Sep 2022 18:59:04 +0800 Subject: [PATCH] core: use saslprep to limit usernames --- packages/hydrooj/package.json | 2 ++ packages/hydrooj/src/handler/user.ts | 6 +++--- packages/hydrooj/src/lib/validator.ts | 4 ---- packages/hydrooj/src/service/decorators.ts | 7 +++++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index 0757cdea4..f6003dfc5 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -43,6 +43,7 @@ "p-queue": "^7.3.0", "path-to-regexp": "^6.2.1", "require-resolve-hook": "^1.1.0", + "saslprep": "^1.0.3", "schemastery": "^3.5.4", "semver": "^7.3.7", "serialize-javascript": "^6.0.0", @@ -64,6 +65,7 @@ "@types/mongodb": "^3.6.20", "@types/nodemailer": "^6.4.5", "@types/notp": "^2.0.2", + "@types/saslprep": "^1.0.1", "@types/semver": "^7.3.12", "@types/serialize-javascript": "^5.0.2", "@types/superagent": "^4.1.15", diff --git a/packages/hydrooj/src/handler/user.ts b/packages/hydrooj/src/handler/user.ts index abf7c38ea..9450ec043 100644 --- a/packages/hydrooj/src/handler/user.ts +++ b/packages/hydrooj/src/handler/user.ts @@ -9,7 +9,7 @@ import { import { OAuthUserResponse, Udoc, User } from '../interface'; import avatar from '../lib/avatar'; import { sendMail } from '../lib/mail'; -import { isEmail, isPassword, isUname } from '../lib/validator'; +import { isEmail, isPassword } from '../lib/validator'; import BlackListModel from '../model/blacklist'; import { PERM, PRIV, STATUS } from '../model/builtin'; import domain from '../model/domain'; @@ -109,7 +109,7 @@ class UserLoginHandler extends Handler { this.response.template = 'user_login.html'; } - @param('uname', Types.String) + @param('uname', Types.Username) @param('password', Types.String) @param('rememberme', Types.Boolean) @param('redirect', Types.String, true) @@ -211,7 +211,7 @@ class UserRegisterWithCodeHandler extends Handler { @param('password', Types.String, isPassword) @param('verifyPassword', Types.String) - @param('uname', Types.Name, isUname) + @param('uname', Types.Username) @param('code', Types.String) async post( domainId: string, password: string, verify: string, diff --git a/packages/hydrooj/src/lib/validator.ts b/packages/hydrooj/src/lib/validator.ts index 5829cf32c..432c38df2 100644 --- a/packages/hydrooj/src/lib/validator.ts +++ b/packages/hydrooj/src/lib/validator.ts @@ -75,8 +75,6 @@ export const isEmail = (s) => RE_MAIL.test(s); export const checkEmail = (s) => { if (!RE_MAIL.test(s)) throw new ValidationError('mail'); else return s; }; export const isContent = (s: any) => s && s.length < 65536; export const checkContent = (s) => { if (!(s && s.length < 65536)) throw new ValidationError('content'); else return s; }; -export const isName = (s) => s && s.length < 256; -export const checkName = (s) => { if (!isName(s)) throw new ValidationError('name'); else return s; }; export const isPid = (s) => RE_PID.test(s.toString()); export const checkPid = (s) => { if (!RE_PID.test(s)) throw new ValidationError('pid'); else return s; }; export const isIntro = () => true; @@ -102,8 +100,6 @@ global.Hydro.lib.validator = { checkEmail, isContent, checkContent, - isName, - checkName, isPid, checkPid, isIntro, diff --git a/packages/hydrooj/src/service/decorators.ts b/packages/hydrooj/src/service/decorators.ts index 7c0071f57..332b115f5 100644 --- a/packages/hydrooj/src/service/decorators.ts +++ b/packages/hydrooj/src/service/decorators.ts @@ -3,8 +3,9 @@ import emojiRegex from 'emoji-regex'; import { isSafeInteger } from 'lodash'; import moment from 'moment-timezone'; import { ObjectID } from 'mongodb'; +import saslprep from 'saslprep'; import { ValidationError } from '../error'; -import { isContent, isName, isTitle } from '../lib/validator'; +import { isContent, isTitle } from '../lib/validator'; import type { Handler } from './server'; type MethodDecorator = (target: any, name: string, obj: any) => any; @@ -23,6 +24,7 @@ type Type = [Converter, Validator, boolean?]; export interface Types { Content: Type, Name: Type, + Username: Type, Title: Type, String: Type, Int: Type, @@ -43,7 +45,8 @@ export interface Types { export const Types: Types = { Content: [(v) => v.toString().trim(), isContent], - Name: [(v) => v.toString().trim(), isName], + Name: [(v) => saslprep(v.toString().trim()), (v) => /^.{1,255}$/.test(saslprep(v.toString().trim()))], + Username: [(v) => saslprep(v.toString().trim()), (v) => /^.{3,31}$/.test(saslprep(v.toString().trim()))], Title: [(v) => v.toString().trim(), isTitle], String: [(v) => v.toString(), null], Int: [(v) => parseInt(v, 10), (v) => isSafeInteger(parseInt(v, 10))],