core: allow disable builtin-login

This commit is contained in:
undefined committed 2021-03-08 18:17:52 +08:00
1 parent 514078132e
commit dd72b7690d
4 files changed
+41 -27

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "2.20.12", "version": "2.20.13",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "dist/loader.js", "main": "dist/loader.js",
"typings": "dist/loader.d.ts", "typings": "dist/loader.d.ts",
+37 -21
View File
@@ -2,10 +2,10 @@ import moment from 'moment-timezone';
import { import {
UserAlreadyExistError, InvalidTokenError, VerifyPasswordError, UserAlreadyExistError, InvalidTokenError, VerifyPasswordError,
UserNotFoundError, SystemError, BlacklistedError, UserNotFoundError, SystemError, BlacklistedError,
UserFacingError, UserFacingError, LoginError,
} from '../error'; } from '../error';
import { import {
Route, Handler, Types, param, Route, Handler, Types, param, post,
} from '../service/server'; } from '../service/server';
import * as user from '../model/user'; import * as user from '../model/user';
import * as oauth from '../model/oauth'; import * as oauth from '../model/oauth';
@@ -23,6 +23,7 @@ import { User } from '../interface';
class UserLoginHandler extends Handler { class UserLoginHandler extends Handler {
async get() { async get() {
if (!system.get('server.login')) throw new LoginError('Builtin login disabled.');
this.response.template = 'user_login.html'; this.response.template = 'user_login.html';
} }
@@ -30,6 +31,7 @@ class UserLoginHandler extends Handler {
@param('password', Types.String) @param('password', Types.String)
@param('rememberme', Types.Boolean) @param('rememberme', Types.Boolean)
async post(domainId: string, uname: string, password: string, rememberme = false) { async post(domainId: string, uname: string, password: string, rememberme = false) {
if (!system.get('server.login')) throw new LoginError('Builtin login disabled.');
const udoc = await user.getByUname(domainId, uname); const udoc = await user.getByUname(domainId, uname);
if (!udoc) throw new UserNotFoundError(uname); if (!udoc) throw new UserNotFoundError(uname);
udoc.checkPassword(password); udoc.checkPassword(password);
@@ -60,24 +62,36 @@ class UserRegisterHandler extends Handler {
this.response.template = 'user_register.html'; this.response.template = 'user_register.html';
} }
@param('mail', Types.String, isEmail) @post('mail', Types.String, true, isEmail)
async post(domainId: string, mail: string) { @post('phone', Types.String, true, (s) => /^\d{11}$/.test(s))
if (await user.getByEmail('system', mail)) throw new UserAlreadyExistError(mail); async post(domainId: string, mail: string, phoneNumber: string) {
this.limitRate('send_mail', 3600, 30); if (mail) {
const t = await token.add( if (await user.getByEmail('system', mail)) throw new UserAlreadyExistError(mail);
token.TYPE_REGISTRATION, this.limitRate('send_mail', 3600, 30);
system.get('session.unsaved_expire_seconds'), const t = await token.add(
{ mail }, token.TYPE_REGISTRATION,
); system.get('session.unsaved_expire_seconds'),
if (system.get('smtp.user')) { { mail },
const m = await this.renderHTML('user_register_mail.html', { );
path: `register/${t[0]}`, if (system.get('smtp.user')) {
url_prefix: system.get('server.url'), const m = await this.renderHTML('user_register_mail.html', {
}); path: `register/${t[0]}`,
await sendMail(mail, 'Sign Up', 'user_register_mail', m); url_prefix: system.get('server.url'),
this.response.template = 'user_register_mail_sent.html'; });
} else { await sendMail(mail, 'Sign Up', 'user_register_mail', m);
this.response.redirect = this.url('user_register_with_code', { code: t[0] }); this.response.template = 'user_register_mail_sent.html';
} else this.response.redirect = this.url('user_register_with_code', { code: t[0] });
} else if (phoneNumber) {
if (!global.Hydro.lib.sendSms) throw new SystemError('Cannot send sms');
this.limitRate('send_sms', 60, 3);
const t = await token.add(
token.TYPE_REGISTRATION,
system.get('session.unsaved_expire_seconds'),
{ phone: phoneNumber },
String.random(6),
);
await global.Hydro.lib.sendSms(phoneNumber, 'register', t[0]);
this.response.template = 'user_register_sms.html';
} }
} }
} }
@@ -100,8 +114,9 @@ class UserRegisterWithCodeHandler extends Handler {
uname: string, code: string, uname: string, code: string,
) { ) {
const tdoc = await token.get(code, token.TYPE_REGISTRATION); const tdoc = await token.get(code, token.TYPE_REGISTRATION);
if (!tdoc || !tdoc.mail) throw new InvalidTokenError(token.TYPE_REGISTRATION, code); if (!tdoc || (!tdoc.mail && !tdoc.phone)) throw new InvalidTokenError(token.TYPE_REGISTRATION, code);
if (password !== verify) throw new VerifyPasswordError(); if (password !== verify) throw new VerifyPasswordError();
if (tdoc.phone) tdoc.mail = `${tdoc.phone}@hydro.local`;
const uid = await user.create(tdoc.mail, uname, password, undefined, this.request.ip); const uid = await user.create(tdoc.mail, uname, password, undefined, this.request.ip);
await token.del(code, token.TYPE_REGISTRATION); await token.del(code, token.TYPE_REGISTRATION);
this.session.uid = uid; this.session.uid = uid;
@@ -281,6 +296,7 @@ export async function apply() {
Route('user_oauth', '/oauth/:type', OauthHandler); Route('user_oauth', '/oauth/:type', OauthHandler);
Route('user_oauth_callback', '/oauth/:type/callback', OauthCallbackHandler); Route('user_oauth_callback', '/oauth/:type/callback', OauthCallbackHandler);
Route('user_register', '/register', UserRegisterHandler, PRIV.PRIV_REGISTER_USER); Route('user_register', '/register', UserRegisterHandler, PRIV.PRIV_REGISTER_USER);
Route('user_register_without_code', '/register/code', UserRegisterWithCodeHandler, PRIV.PRIV_REGISTER_USER);
Route('user_register_with_code', '/register/:code', UserRegisterWithCodeHandler, PRIV.PRIV_REGISTER_USER); Route('user_register_with_code', '/register/:code', UserRegisterWithCodeHandler, PRIV.PRIV_REGISTER_USER);
Route('user_logout', '/logout', UserLogoutHandler, PRIV.PRIV_USER_PROFILE); Route('user_logout', '/logout', UserLogoutHandler, PRIV.PRIV_USER_PROFILE);
Route('user_lostpass', '/lostpass', UserLostPassHandler); Route('user_lostpass', '/lostpass', UserLostPassHandler);
+2 -3
View File
@@ -1,13 +1,12 @@
export type NumberKeys<O> = { export type NumberKeys<O> = {
[K in keyof O]: number extends O[K] ? K : never [K in keyof O]: number extends O[K] ? K : never
}[keyof O]; }[keyof O];
export type ArrayKeys<O, P = any> = { export type ArrayKeys<O, P = any> = {
[K in keyof O]: P[] extends O[K] ? K : never [K in keyof O]: P[] extends O[K] ? K : never
}[keyof O]; }[keyof O];
export type Value<O, V = ''> = { export type Value<O, V = ''> = {
[K in keyof O]: V [K in keyof O]: V
}; };
export type Projection<O> = (string & keyof O)[]; export type Projection<O> = (string & keyof O)[];
export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
export type Filter<T, U> = T extends U ? T : never;
+1 -2
View File
@@ -1,11 +1,10 @@
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import { ObjectID, Collection } from 'mongodb'; import { ObjectID } from 'mongodb';
import AdmZip from 'adm-zip'; import AdmZip from 'adm-zip';
import Queue from 'p-queue'; import Queue from 'p-queue';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
import { Progress } from './ui'; import { Progress } from './ui';
import { Ufdoc } from './interface';
import { Logger } from './logger'; import { Logger } from './logger';
import { DomainDoc } from './loader'; import { DomainDoc } from './loader';
import { streamToBuffer } from './utils'; import { streamToBuffer } from './utils';