From 6e28dd868ec302a93767d77b4792129570f4c8ec Mon Sep 17 00:00:00 2001 From: masnn Date: Thu, 9 Apr 2020 20:47:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B3=A8=E5=86=8C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hydro/handler/ui.js | 3 ++ hydro/handler/user.js | 53 ++++++++++++++------------ hydro/model/opcount.js | 2 +- hydro/model/token.js | 4 +- hydro/model/user.js | 25 +++++++----- hydro/options.js | 3 +- templates/user_register.html | 1 + templates/user_register_with_code.html | 3 +- 8 files changed, 55 insertions(+), 39 deletions(-) diff --git a/hydro/handler/ui.js b/hydro/handler/ui.js index 64217478..174d85ee 100644 --- a/hydro/handler/ui.js +++ b/hydro/handler/ui.js @@ -122,6 +122,9 @@ MIDDLEWARE(async (ctx, next) => { ctx.response.type = 'application/octet-stream'; ctx.redirect(ctx.setRedirect); } + } else if (ctx.setRedirect) { + ctx.response.type = 'application/octet-stream'; + ctx.redirect(ctx.setRedirect); } else { throw new NotFoundError(); } diff --git a/hydro/handler/user.js b/hydro/handler/user.js index 63396967..8fe0fa5c 100644 --- a/hydro/handler/user.js +++ b/hydro/handler/user.js @@ -37,37 +37,43 @@ POST('/logout', requirePerm(PERM_LOGGEDIN), async ctx => { ctx.session = { uid: 1 }; ctx.body = {}; }); -GET('/register/:code', requirePerm(PERM_REGISTER_USER), async ctx => { - let code = ctx.request.body.code; - let { mail } = await token.get(code, token.TYPE_REGISTRATION); - if (!mail) throw new InvalidTokenError(token.TYPE_REGISTRATION, code); - ctx.body = { mail }; +GET('/register', requirePerm(PERM_REGISTER_USER), async ctx => { + ctx.templateName = 'user_register.html'; }); GET('/register/:code', requirePerm(PERM_REGISTER_USER), async ctx => { - let { code, password, verify_password, uname } = ctx.request.body; - let { mail } = await token.get(code, token.TYPE_REGISTRATION); - if (!mail) throw new InvalidTokenError(token.TYPE_REGISTRATION, code); + ctx.templateName = 'user_register_with_code.html'; + let code = ctx.params.code; + let { email } = await token.get(code, token.TYPE_REGISTRATION); + if (!email) throw new InvalidTokenError(token.TYPE_REGISTRATION, code); + ctx.body = { email }; +}); +POST('/register/:code', requirePerm(PERM_REGISTER_USER), async ctx => { + let code = ctx.params.code; + let { password, verify_password, uname } = ctx.request.body; + let { email } = await token.get(code, token.TYPE_REGISTRATION); + if (!email) throw new InvalidTokenError(token.TYPE_REGISTRATION, code); if (password != verify_password) throw new VerifyPasswordError(); let uid = await system.incUserCounter(); - await user.add(uid, uname, password, mail, ctx.remote_ip); + await user.create({ uid, uname, password, email, regip: ctx.request.ip }); await token.delete(code, token.TYPE_REGISTRATION); ctx.session.uid = uid; ctx.body = {}; + ctx.setRedirect = '/'; }); if (options.smtp.user) { POST('/register', requirePerm(PERM_REGISTER_USER), limitRate('send_mail', 3600, 30), async ctx => { - let email = ctx.request.body.email; - validator.check_mail(email); - if (await user.get_by_mail(email)) throw new UserAlreadyExistError(email); - let rid = await token.add(token.TYPE_REGISTRATION, options.registration_token_expire_seconds, { mail: email }); + let email = ctx.request.body.mail; + validator.checkEmail(email); + if (await user.getByEmail(email, true)) throw new UserAlreadyExistError(email); + let rid = await token.add(token.TYPE_REGISTRATION, options.registration_token_expire_seconds, { email }); let m = await ctx.render('user_register_mail', { url: `/register/${rid}` }, true); - await mail.send_mail(email, 'Sign Up', 'user_register_mail', m); + await mail.sendMail(email, 'Sign Up', 'user_register_mail', m); ctx.body = {}; }); POST('/lostpass', limitRate('send_mail', 3600, 30), async ctx => { let email = ctx.request.body.mail; - validator.check_mail(email); + validator.checkEmail(email); let udoc = await user.getByEmail(email); if (!udoc) throw new UserNotFoundError(email); let tid = await token.add( @@ -76,7 +82,7 @@ if (options.smtp.user) { { uid: udoc._id } ); let m = await ctx.render('user_lostpass_mail', { url: `/lostpass/${tid}`, uname: udoc.uname }, true); - await mail.send_mail(email, 'Lost Password', 'user_lostpass_mail', m); + await mail.sendMail(email, 'Lost Password', 'user_lostpass_mail', m); ctx.body = {}; }); GET('/lostpass/:code', async ctx => { @@ -93,19 +99,18 @@ if (options.smtp.user) { let tdoc = await token.get(code, token.TYPE_LOSTPASS); if (!tdoc) throw new InvalidTokenError(token.TYPE_LOSTPASS, code); if (password != verify_password) throw new VerifyPasswordError(); - await user.set_password(tdoc.uid, password); + await user.setPassword(tdoc.uid, password); await token.delete(code, token.TYPE_LOSTPASS); ctx.redirect('/'); }); } else - POST('/register', requirePerm(PERM_REGISTER_USER), async ctx => { - let email = ctx.request.body.email; - validator.check_mail(email); - if (await user.get_by_mail(email)) throw new UserAlreadyExistError(email); - let token = await token.add(token.TYPE_REGISTRATION, options.registration_token_expire_seconds, { mail: email }); - ctx.body = { token }; + POST('/register', requirePerm(PERM_REGISTER_USER), limitRate('send_mail', 3600, 60), async ctx => { + let email = ctx.request.body.mail; + validator.checkEmail(email); + if (await user.getByEmail(email, true)) throw new UserAlreadyExistError(email); + let t = await token.add(token.TYPE_REGISTRATION, options.session.registration_token_expire_seconds, { email }); + ctx.setRedirect = `/register/${t[0]}`; }); - /* @app.route('/user/{uid:-?\d+}', 'user_detail') diff --git a/hydro/model/opcount.js b/hydro/model/opcount.js index ad832711..3b8ec5a3 100644 --- a/hydro/model/opcount.js +++ b/hydro/model/opcount.js @@ -15,7 +15,7 @@ module.exports = { let begin_at = new Date(cur_time - cur_time % (period_secs * 1000)); let expire_at = new Date(begin_at.getTime() + period_secs * 1000); try { - await coll.find_one_and_update({ + await coll.findOneAndUpdate({ ident, begin_at, expire_at, op: { $not: { $gte: max_operations } } }, { $inc: { op: 1 } }, { upsert: true }); diff --git a/hydro/model/token.js b/hydro/model/token.js index f6939c15..bcf7f08a 100644 --- a/hydro/model/token.js +++ b/hydro/model/token.js @@ -11,7 +11,7 @@ module.exports = { * @param {number} tokenType type of the token. * @param {number} expireSeconds expire time, in seconds. * @param {object} data extra data. - * @returns {string} token ID + * @returns {Array} token ID, token data */ async add(tokenType, expireSeconds, data) { let now = new Date(); @@ -62,7 +62,7 @@ module.exports = { * @returns {boolean} true if deleted, or false. */ async delete(tokenId, tokenType) { - let result = await coll.delete_one({ _id: tokenId, tokenType }); + let result = await coll.deleteOne({ _id: tokenId, tokenType }); return !!result.deletedCount; }, diff --git a/hydro/model/user.js b/hydro/model/user.js index d08902b5..0ebc7fba 100644 --- a/hydro/model/user.js +++ b/hydro/model/user.js @@ -1,8 +1,9 @@ const - { UserNotFoundError, UserAlreadyExistError } = require('../error'), system = require('./system'), - { pwhash, validator } = require('../utils'), - db = require('../service/db.js'), + { UserNotFoundError, UserAlreadyExistError } = require('../error'), + { pwhash } = require('../utils'), + validator = require('../lib/validator'), + db = require('../service/db'), coll = db.collection('user'), coll_role = db.collection('role'); @@ -40,10 +41,13 @@ async function getByUname(uname) { udoc.perm = role.perm; return new USER(udoc); } -async function getByEmail(email) { +async function getByEmail(email, ignoreMissing = false) { let emailLower = email.trim().toLowerCase(); let udoc = await coll.findOne({ emailLower }); - if (!udoc) throw new UserNotFoundError(email); + if (!udoc) { + if (ignoreMissing) return null; + else throw new UserNotFoundError(email); + } let role = await coll_role.findOne({ _id: udoc.role || 'default' }); udoc.perm = role.perm; return new USER(udoc); @@ -73,7 +77,7 @@ async function changePassword(uid, currentPassword, newPassword) { $set: { salt, hash: pwhash.hash(newPassword, salt) } }); } -async function create({ uid, email, uname, password, regip, perm = this.perm.PERM_DEFAULT || 0 }) { +async function create({ uid, email, uname, password, regip = '127.0.0.1', role = 'default' }) { validator.checkUname(uname); validator.checkPassword(password); validator.checkEmail(email); @@ -81,21 +85,22 @@ async function create({ uid, email, uname, password, regip, perm = this.perm.PER if (!uid) uid = system.incUserCounter(); try { await coll.insertOne({ + _id: uid, email, - emailLower: email.strip().toLowerCase(), + emailLower: email.trim().toLowerCase(), uname, - unameLower: uname.strip().toLowerCase(), + unameLower: uname.trim().toLowerCase(), password: pwhash.hash(password, salt), salt, regat: new Date(), regip, loginat: new Date(), loginip: regip, - perm, + role, gravatar: email }); } catch (e) { - throw new UserAlreadyExistError(uid, uname, email); + throw new UserAlreadyExistError([uid, uname, email]); } } diff --git a/hydro/options.js b/hydro/options.js index 3c00a308..f6c738dd 100644 --- a/hydro/options.js +++ b/hydro/options.js @@ -34,7 +34,8 @@ let options = { secure: false, domain: '127.0.0.1', saved_expire_seconds: 3600 * 24, - unsaved_expire_seconds: 600 + unsaved_expire_seconds: 600, + registration_token_expire_seconds: 600 }, constants: { PROBLEM_PER_PAGE: 100, diff --git a/templates/user_register.html b/templates/user_register.html index b392d1a5..dfd083a7 100644 --- a/templates/user_register.html +++ b/templates/user_register.html @@ -1,3 +1,4 @@ +{% set page_name = "user_register" %} {% extends "layout/immersive.html" %} {% block content %}
diff --git a/templates/user_register_with_code.html b/templates/user_register_with_code.html index 0b46a43e..0388e574 100644 --- a/templates/user_register_with_code.html +++ b/templates/user_register_with_code.html @@ -1,3 +1,4 @@ +{% set page_name = "user_register_with_code" %} {% extends "layout/immersive.html" %} {% block content %}
@@ -6,7 +7,7 @@