You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Hydro/hydro/handler/user.js

191 lines
6.5 KiB
JavaScript

5 years ago
const { Route, Handler } = require('../service/server.js');
const user = require('../model/user');
const token = require('../model/token');
const system = require('../model/system');
const { sendMail } = require('../lib/mail');
const misc = require('../lib/misc');
const validator = require('../lib/validator');
const options = require('../options');
const { PERM_REGISTER_USER, PERM_LOGGEDIN } = require('../permission');
const {
UserAlreadyExistError, InvalidTokenError, VerifyPasswordError,
UserNotFoundError, LoginError, SystemError,
} = require('../error');
class UserLoginHandler extends Handler {
async get() {
this.response.template = 'user_login.html';
}
5 years ago
async post({ uname, password, rememberme = false }) {
5 years ago
const udoc = await user.getByUname(uname);
if (!udoc) throw new LoginError(uname);
if (udoc) udoc.checkPassword(password);
await user.setById(udoc._id, { loginat: new Date(), loginip: this.request.ip });
udoc.salt = '';
udoc.password = '';
this.session.uid = udoc._id;
this.session.rememberme = rememberme;
this.response.body = {};
5 years ago
const referer = this.request.headers.referer || '/';
this.response.redirect = referer.endsWith('/login') ? '/' : referer;
}
}
class UserLogoutHandler extends Handler {
constructor(ctx) {
super(ctx);
this.checkPerm(PERM_LOGGEDIN);
}
5 years ago
async get() {
this.response.template = 'user_logout.html';
}
5 years ago
async post() {
this.session = { uid: 1 };
this.response.body = {};
}
}
class UserRegisterHandler extends Handler {
constructor(ctx) {
super(ctx);
this.checkPerm(PERM_REGISTER_USER);
}
5 years ago
async get() {
this.response.template = 'user_register.html';
}
5 years ago
async post({ mail }) {
validator.checkEmail(mail);
if (await user.getByEmail(mail, true)) throw new UserAlreadyExistError(mail);
this.limitRate('send_mail', 3600, 30);
5 years ago
const t = await token.add(
token.TYPE_REGISTRATION,
options.registration_token_expire_seconds,
{ mail },
);
if (options.smtp.user) {
5 years ago
const m = await this.renderHTML('user_register_mail', { url: `/register/${t}` });
await sendMail(mail, 'Sign Up', 'user_register_mail', m);
this.response.body = {};
this.response.template = 'user_register_mail_sent.html';
} else {
this.response.redirect = `/register/${t[0]}`;
}
}
}
class UserRegisterWithCodeHandler extends Handler {
constructor(ctx) {
super(ctx);
this.checkPerm(PERM_REGISTER_USER);
}
5 years ago
async get({ code }) {
this.response.template = 'user_register_with_code.html';
5 years ago
const { mail } = await token.get(code, token.TYPE_REGISTRATION);
if (!mail) throw new InvalidTokenError(token.TYPE_REGISTRATION, code);
this.response.body = { mail };
}
5 years ago
async post({
code, password, verifyPassword, uname,
}) {
const { mail } = await token.get(code, token.TYPE_REGISTRATION);
if (!mail) throw new InvalidTokenError(token.TYPE_REGISTRATION, code);
5 years ago
if (password !== verifyPassword) throw new VerifyPasswordError();
const uid = await system.incUserCounter();
await user.create({
uid, uname, password, mail, regip: this.request.ip,
});
await token.delete(code, token.TYPE_REGISTRATION);
this.session.uid = uid;
this.response.body = {};
this.response.redirect = '/';
}
}
class UserLostPassHandler extends Handler {
constructor(ctx) {
if (!options.smtp.user) throw new SystemError('Cannot send mail');
super(ctx);
}
5 years ago
async get() {
this.response.template = 'user_lostpass.html';
}
5 years ago
async post({ mail }) {
validator.checkEmail(mail);
5 years ago
const udoc = await user.getByEmail(mail);
if (!udoc) throw new UserNotFoundError(mail);
5 years ago
const tid = await token.add(
token.TYPE_LOSTPASS,
options.lostpass_token_expire_seconds,
5 years ago
{ uid: udoc._id },
);
5 years ago
const m = await this.renderHTML('user_lostpass_mail', { url: `/lostpass/${tid}`, uname: udoc.uname });
await sendMail(mail, 'Lost Password', 'user_lostpass_mail', m);
this.response.body = {};
this.response.template = 'user_lostpass_mail_sent.html';
}
}
class UserLostPassWithCodeHandler extends Handler {
async get({ code }) {
5 years ago
const tdoc = await token.get(code, token.TYPE_LOSTPASS);
if (!tdoc) throw new InvalidTokenError(token.TYPE_LOSTPASS, code);
5 years ago
const udoc = await user.getById(tdoc.uid);
this.response.body = { uname: udoc.uname };
}
5 years ago
async post({ code, password, verifyPassword }) {
const tdoc = await token.get(code, token.TYPE_LOSTPASS);
if (!tdoc) throw new InvalidTokenError(token.TYPE_LOSTPASS, code);
5 years ago
if (password !== verifyPassword) throw new VerifyPasswordError();
5 years ago
await user.setPassword(tdoc.uid, password);
await token.delete(code, token.TYPE_LOSTPASS);
this.response.redirect = '/';
}
}
class UserDetailHandler extends Handler {
constructor(ctx) {
super(ctx);
this.response.template = 'user_detail.html';
}
5 years ago
async get({ uid }) {
5 years ago
const isSelfProfile = this.ctx.state.user._id === uid;
const udoc = await user.getById(uid);
if (!udoc) throw new UserNotFoundError(uid);
5 years ago
const sdoc = await token.getMostRecentSessionByUid(uid);
this.ctx.body = { isSelfProfile, udoc, sdoc };
}
}
class UserSearchHandler extends Handler {
5 years ago
async get({ q, exactMatch = false }) {
let udocs;
5 years ago
if (exactMatch) udocs = [];
else udocs = await user.getPrefixList(q, 20);
try {
5 years ago
const udoc = await user.getById(parseInt(q));
if (udoc) udocs.insert(0, udoc);
} catch (e) {
/* Ignore */
}
5 years ago
for (const i in udocs) {
if (udocs[i].gravatar) {
udocs[i].gravatar_url = misc.gravatar_url[udocs[i].gravatar];
5 years ago
}
}
this.ctx.body = { udocs };
}
}
Route('/login', UserLoginHandler);
Route('/register', UserRegisterHandler);
Route('/register/:code', UserRegisterWithCodeHandler);
Route('/logout', UserLogoutHandler);
Route('/lostpass', UserLostPassHandler);
Route('/lostpass/:code', UserLostPassWithCodeHandler);
Route('/user/:uid', UserDetailHandler);
Route('/user/search', UserSearchHandler);