Password changing now works.

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2018-12-04 19:31:06 -08:00
parent 2186862e2f
commit 0e750d5931
4 changed files with 213 additions and 33 deletions

View File

@ -790,8 +790,13 @@
},
profile: function(event) {
if (this.mode == "profile") {
this.mode = this.lastMode;
} else {
this.$.profile.user = this.user;
this.lastMode = this.mode;
this.mode = "profile";
}
},
logout: function(event) {

View File

@ -5,6 +5,7 @@ const config = require("config"),
hb = require("handlebars");
const templates = {
"verify": {
"html": [
"<p>Hello {{username}},</p>",
"",
@ -30,6 +31,25 @@ const templates = {
"Sincerely,",
"James"
].join("\n")
},
"password": {
"html": [
"<p>Hello {{username}},</p>",
"",
"<p>You changed your password on <b>ketrenos.com</b>.</p>",
"",
"<p>Sincerely,</p>",
"<p>James</p>"
].join("\n"),
"text": [
"Hello {{username}},",
"",
"You changed your password on ketrenos.com.",
"",
"Sincerely,</p>",
"James"
].join("\n")
}
};
const sendVerifyMail = function(userDB, req, user) {
@ -79,8 +99,8 @@ const sendVerifyMail = function(userDB, req, user) {
subject: "Request to ketrenos.com create account for '" + data.username + "'",
cc: "",
bcc: config.get("admin.mail"),
text: hb.compile(templates.text)(data),
html: hb.compile(templates.html)(data)
text: hb.compile(templates.verify.text)(data),
html: hb.compile(templates.verify.html)(data)
};
return new Promise(function (resolve, reject) {
let attempts = 10;
@ -111,6 +131,53 @@ const sendVerifyMail = function(userDB, req, user) {
});
};
module.exports = {
sendVerifyMail
const sendPasswordChangedMail = function(userDB, req, user) {
const transporter = req.app.get("transporter");
if (!transporter) {
console.log("Not sending VERIFY email; SMTP not configured.");
return;
}
let data = {
username: user.displayName,
mail: user.mail,
url: req.protocol + "://" + req.hostname + req.app.get("basePath")
}, envelope = {
to: data.mail,
from: config.get("smtp.sender"),
subject: "Password changed on ketrenos.com for '" + data.username + "'",
cc: "",
bcc: config.get("admin.mail"),
text: hb.compile(templates.password.text)(data),
html: hb.compile(templates.password.html)(data)
};
return new Promise(function (resolve, reject) {
let attempts = 10;
function send(envelope) {
/* Rate limit to ten per second */
transporter.sendMail(envelope, function (error, info) {
if (!error) {
console.log('Message sent: ' + info.response);
return resolve();
}
if (attempts == 0) {
console.log("Error sending email: ", error);
return reject(error);
}
attempts--;
console.log("Unable to send mail. Trying again in 100ms (" + attempts + " attempts remain): ", error);
setTimeout(send.bind(undefined, envelope), 100);
});
}
send(envelope);
});
};
module.exports = {
sendVerifyMail,
sendPasswordChangedMail
}

View File

@ -108,8 +108,6 @@ function init(moment) {
if (ds.length) { return ds.join('|'); }
}
});
console.log("Pascha initialized");
}
module.exports = init;

View File

@ -3,7 +3,7 @@
const express = require("express"),
config = require("config"),
LdapAuth = require("ldapauth-fork"),
{ sendVerifyMail } = require("../lib/mail"),
{ sendVerifyMail, sendPasswordChangedMail } = require("../lib/mail"),
crypto = require("crypto");
const router = express.Router();
@ -45,6 +45,116 @@ function ldapPromise(username, password) {
});
}
const ldapJS = require("ldapjs"),
ldapConfig = config.get("ldap");
const ldapSetPassword = function(username, password) {
const client = ldapJS.createClient({
url: ldapConfig.url
});
return new Promise(function(resolve, reject) {
client.bind(ldapConfig.bindDn, ldapConfig.bindCredentials, function(err) {
if (err) {
return reject("Error binding to LDAP: " + err);
}
var change = new ldapJS.Change({
operation: "replace",
modification: {
userPassword : password,
}
});
client.modify("uid=" + username + ",ou=people," + ldapConfig.searchBase, change, function(err) {
if (err) {
return reject("Error changing password: " + err);
}
return resolve();
});
});
}).catch(function(error) {
console.error(error);
}).then(function() {
client.unbind(function(err) {
if (err) {
console.error("Error unbinding: " + err);
}
});
});
};
router.put("/password", function(req, res) {
console.log("/users/password");
const changes = {
currentPassword: req.query.c || req.body.c,
newPassword: req.query.n || req.body.n
};
if (!changes.currentPassword || !changes.newPassword) {
return res.status(400).send("Missing current password and/or new password.");
}
if (changes.currentPassword == changes.newPassword) {
return res.status(400).send("Attempt to set new password to current password.");
}
return getSessionUser(req).then(function(user) {
if (req.session.userId == "LDAP") {
return ldapPromise(user.username, changes.currentPassword).then(function() {
return user;
}).catch(function() {
return null;
});
}
/* Not an LDAP user, so query in the DB */
return userDB.sequelize.query("SELECT id FROM users " +
"WHERE uid=:username AND password=:password", {
replacements: {
username: user.username,
password: crypto.createHash('sha256').update(changes.currentPassword).digest('base64')
},
type: userDB.Sequelize.QueryTypes.SELECT,
raw: true
}).then(function(users) {
if (users.length != 1) {
return null;
}
return user;
});
}).then(function(user) {
if (!user) {
console.log("Invalid password");
/* Invalid password */
res.status(401).send("Invalid password");
return null;
}
let updatePromise;
if (req.session.userId == "LDAP") {
updatePromise = ldapSetPassword(user.username, changes.newPassword);
} else {
updatePromise = userDB.sequelize.query("UPDATE users SET password=:password WHERE uid=:username", {
replacements: {
username: user.username,
password: crypto.createHash('sha256').update(changes.newPassword).digest('base64')
}
});
}
updatePromise.then(function() {
console.log("Password changed for user " + user.username + " to '" + changes.newPassword + "'.");
res.status(200).send(user);
user.id = req.session.userId;
return sendPasswordChangedMail(userDB, req, user);
});
});
});
router.post("/create", function(req, res) {
console.log("/users/create");