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
This commit is contained in:
Calvin Montgomery 2018-07-11 19:21:32 -07:00
parent 3db751b65f
commit db2361aee9
2 changed files with 69 additions and 53 deletions

View File

@ -2,7 +2,7 @@
"author": "Calvin Montgomery", "author": "Calvin Montgomery",
"name": "CyTube", "name": "CyTube",
"description": "Online media synchronizer and chat", "description": "Online media synchronizer and chat",
"version": "3.56.3", "version": "3.56.4",
"repository": { "repository": {
"url": "http://github.com/calzoneman/sync" "url": "http://github.com/calzoneman/sync"
}, },

View File

@ -13,6 +13,7 @@ var Config = require("../config");
var session = require("../session"); var session = require("../session");
var csrf = require("./csrf"); var csrf = require("./csrf");
const url = require("url"); const url = require("url");
import crypto from 'crypto';
const LOGGER = require('@calzoneman/jsli')('web/accounts'); const LOGGER = require('@calzoneman/jsli')('web/accounts');
@ -536,76 +537,91 @@ function handlePasswordReset(req, res) {
return; 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", { sendPug(res, "account-passwordreset", {
reset: false, reset: false,
resetEmail: "", resetEmail: "",
resetErr: "Provided email does not match the email address on record for " + name resetErr: "Provided email does not match the email address on record for " + name
}); });
return; 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)); crypto.randomBytes(20, (err, bytes) => {
// 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) {
if (err) { if (err) {
LOGGER.error(
'Could not generate random bytes for password reset: %s',
err.stack
);
sendPug(res, "account-passwordreset", { sendPug(res, "account-passwordreset", {
reset: false, reset: false,
resetEmail: "", resetEmail: email,
resetErr: err resetErr: "Internal error when generating password reset"
}); });
return; return;
} }
Logger.eventlog.log("[account] " + ip + " requested password recovery for " + var hash = bytes.toString('hex');
name + " <" + email + ">"); // 24-hour expiration
var expire = Date.now() + 86400000;
var ip = req.realIP;
if (!emailConfig.getPasswordReset().isEnabled()) { db.addPasswordReset({
sendPug(res, "account-passwordreset", { ip: ip,
reset: false, name: name,
resetEmail: email, email: actualEmail,
resetErr: "This server does not have mail support enabled. Please " + hash: hash,
"contact an administrator for assistance." expire: expire
}); }, function (err, _dbres) {
return; 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({ if (!emailConfig.getPasswordReset().isEnabled()) {
username: name, sendPug(res, "account-passwordreset", {
address: email, reset: false,
url: `${baseUrl}/account/passwordrecover/${hash}` resetEmail: email,
}).then(_result => { resetErr: "This server does not have mail support enabled. Please " +
sendPug(res, "account-passwordreset", { "contact an administrator for assistance."
reset: true, });
resetEmail: email, return;
resetErr: false }
});
}).catch(error => { const baseUrl = `${req.realProtocol}://${req.header("host")}`;
LOGGER.error("Sending password reset email failed: %s", error);
sendPug(res, "account-passwordreset", { emailController.sendPasswordReset({
reset: false, username: name,
resetEmail: email, address: email,
resetErr: "Sending reset email failed. Please contact an " + url: `${baseUrl}/account/passwordrecover/${hash}`
"administrator for assistance." }).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."
});
}); });
}); });
}); });