From db2361aee9679f1c0900db9af26e55d322db67ba Mon Sep 17 00:00:00 2001 From: Calvin Montgomery Date: Wed, 11 Jul 2018 19:21:32 -0700 Subject: [PATCH] Misc fixes for password reset * Remove messaging about asking an administrator for help if no email is associated with the account (no longer correct or relevant) * Compare user-provided email with registered email case-insensitively (#755) * Replace antiquated hash generator with cryptographically secure random byte string generator --- package.json | 2 +- src/web/account.js | 120 +++++++++++++++++++++++++-------------------- 2 files changed, 69 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index 1eeceb10..c1231cdb 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Calvin Montgomery", "name": "CyTube", "description": "Online media synchronizer and chat", - "version": "3.56.3", + "version": "3.56.4", "repository": { "url": "http://github.com/calzoneman/sync" }, diff --git a/src/web/account.js b/src/web/account.js index a6a821e9..41bf6733 100644 --- a/src/web/account.js +++ b/src/web/account.js @@ -13,6 +13,7 @@ var Config = require("../config"); var session = require("../session"); var csrf = require("./csrf"); const url = require("url"); +import crypto from 'crypto'; const LOGGER = require('@calzoneman/jsli')('web/accounts'); @@ -536,76 +537,91 @@ function handlePasswordReset(req, res) { return; } - if (actualEmail !== email.trim()) { + if (actualEmail === '') { + sendPug(res, "account-passwordreset", { + reset: false, + resetEmail: "", + resetErr: `Username ${name} cannot be recovered because it ` + + "doesn't have an email address associated with it." + }); + return; + } else if (actualEmail.toLowerCase() !== email.trim().toLowerCase()) { sendPug(res, "account-passwordreset", { reset: false, resetEmail: "", resetErr: "Provided email does not match the email address on record for " + name }); return; - } else if (actualEmail === "") { - sendPug(res, "account-passwordreset", { - reset: false, - resetEmail: "", - resetErr: name + " doesn't have an email address on record. Please contact an " + - "administrator to manually reset your password." - }); - return; } - var hash = $util.sha1($util.randomSalt(64)); - // 24-hour expiration - var expire = Date.now() + 86400000; - var ip = req.realIP; - - db.addPasswordReset({ - ip: ip, - name: name, - email: email, - hash: hash, - expire: expire - }, function (err, _dbres) { + crypto.randomBytes(20, (err, bytes) => { if (err) { + LOGGER.error( + 'Could not generate random bytes for password reset: %s', + err.stack + ); sendPug(res, "account-passwordreset", { reset: false, - resetEmail: "", - resetErr: err + resetEmail: email, + resetErr: "Internal error when generating password reset" }); return; } - Logger.eventlog.log("[account] " + ip + " requested password recovery for " + - name + " <" + email + ">"); + var hash = bytes.toString('hex'); + // 24-hour expiration + var expire = Date.now() + 86400000; + var ip = req.realIP; - if (!emailConfig.getPasswordReset().isEnabled()) { - sendPug(res, "account-passwordreset", { - reset: false, - resetEmail: email, - resetErr: "This server does not have mail support enabled. Please " + - "contact an administrator for assistance." - }); - return; - } + db.addPasswordReset({ + ip: ip, + name: name, + email: actualEmail, + hash: hash, + expire: expire + }, function (err, _dbres) { + if (err) { + sendPug(res, "account-passwordreset", { + reset: false, + resetEmail: "", + resetErr: err + }); + return; + } - const baseUrl = `${req.realProtocol}://${req.header("host")}`; + Logger.eventlog.log("[account] " + ip + " requested password recovery for " + + name + " <" + email + ">"); - emailController.sendPasswordReset({ - username: name, - address: email, - url: `${baseUrl}/account/passwordrecover/${hash}` - }).then(_result => { - sendPug(res, "account-passwordreset", { - reset: true, - resetEmail: email, - resetErr: false - }); - }).catch(error => { - LOGGER.error("Sending password reset email failed: %s", error); - sendPug(res, "account-passwordreset", { - reset: false, - resetEmail: email, - resetErr: "Sending reset email failed. Please contact an " + - "administrator for assistance." + if (!emailConfig.getPasswordReset().isEnabled()) { + sendPug(res, "account-passwordreset", { + reset: false, + resetEmail: email, + resetErr: "This server does not have mail support enabled. Please " + + "contact an administrator for assistance." + }); + return; + } + + const baseUrl = `${req.realProtocol}://${req.header("host")}`; + + emailController.sendPasswordReset({ + username: name, + address: email, + url: `${baseUrl}/account/passwordrecover/${hash}` + }).then(_result => { + sendPug(res, "account-passwordreset", { + reset: true, + resetEmail: email, + resetErr: false + }); + }).catch(error => { + LOGGER.error("Sending password reset email failed: %s", error); + sendPug(res, "account-passwordreset", { + reset: false, + resetEmail: email, + resetErr: "Sending reset email failed. Please contact an " + + "administrator for assistance." + }); }); }); });