Finish password recovery
This commit is contained in:
parent
9562bc3757
commit
0603a02d2e
|
@ -19,6 +19,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||||
|
|
||||||
var Logger = require("./logger");
|
var Logger = require("./logger");
|
||||||
var Config = require("./config");
|
var Config = require("./config");
|
||||||
|
var db = require("./database");
|
||||||
|
|
||||||
var init = null;
|
var init = null;
|
||||||
|
|
||||||
|
@ -28,7 +29,6 @@ function initStats(Server) {
|
||||||
var STAT_EXPIRE = Config.get("stats.max-age");
|
var STAT_EXPIRE = Config.get("stats.max-age");
|
||||||
|
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
var db = Server.db;
|
|
||||||
var chancount = Server.channels.length;
|
var chancount = Server.channels.length;
|
||||||
var usercount = 0;
|
var usercount = 0;
|
||||||
Server.channels.forEach(function (chan) {
|
Server.channels.forEach(function (chan) {
|
||||||
|
@ -49,7 +49,7 @@ function initAliasCleanup(Server) {
|
||||||
var CLEAN_EXPIRE = Config.get("aliases.max-age");
|
var CLEAN_EXPIRE = Config.get("aliases.max-age");
|
||||||
|
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
Server.db.cleanOldAliases(CLEAN_EXPIRE, function (err) {
|
db.cleanOldAliases(CLEAN_EXPIRE, function (err) {
|
||||||
Logger.syslog.log("Cleaned old aliases");
|
Logger.syslog.log("Cleaned old aliases");
|
||||||
if (err)
|
if (err)
|
||||||
Logger.errlog.log(err);
|
Logger.errlog.log(err);
|
||||||
|
@ -57,6 +57,18 @@ function initAliasCleanup(Server) {
|
||||||
}, CLEAN_INTERVAL);
|
}, CLEAN_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Password reset cleanup */
|
||||||
|
function initPasswordResetCleanup(Server) {
|
||||||
|
var CLEAN_INTERVAL = 8*60*60*1000;
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
db.cleanOldPasswordResets(function (err) {
|
||||||
|
if (err)
|
||||||
|
Logger.errlog.log(err);
|
||||||
|
});
|
||||||
|
}, CLEAN_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Clean out old rate limiters */
|
/* Clean out old rate limiters */
|
||||||
function initIpThrottleCleanup(Server) {
|
function initIpThrottleCleanup(Server) {
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
|
@ -91,4 +103,5 @@ module.exports = function (Server) {
|
||||||
initAliasCleanup(Server);
|
initAliasCleanup(Server);
|
||||||
initIpThrottleCleanup(Server);
|
initIpThrottleCleanup(Server);
|
||||||
initChannelDumper(Server);
|
initChannelDumper(Server);
|
||||||
|
initPasswordResetCleanup(Server);
|
||||||
};
|
};
|
||||||
|
|
|
@ -249,6 +249,18 @@ module.exports.globalUnbanIP = function (ip, callback) {
|
||||||
|
|
||||||
/* password recovery */
|
/* password recovery */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes recovery rows older than the given time
|
||||||
|
*/
|
||||||
|
module.exports.cleanOldPasswordResets = function (callback) {
|
||||||
|
if (typeof callback === "undefined") {
|
||||||
|
callback = blackHole;
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = "DELETE FROM aliases WHERE time < ?";
|
||||||
|
module.exports.query(query, [Date.now() - 24*60*60*1000], callback);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.addPasswordReset = function (data, cb) {
|
module.exports.addPasswordReset = function (data, cb) {
|
||||||
if (typeof cb !== "function") {
|
if (typeof cb !== "function") {
|
||||||
cb = blackHole;
|
cb = blackHole;
|
||||||
|
@ -270,6 +282,23 @@ module.exports.addPasswordReset = function (data, cb) {
|
||||||
[ip, name, email, hash, expire, ip, hash, email, expire], cb);
|
[ip, name, email, hash, expire, ip, hash, email, expire], cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports.lookupPasswordReset = function (hash, cb) {
|
||||||
|
if (typeof cb !== "function") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.query("SELECT * FROM `password_reset` WHERE hash=?", [hash],
|
||||||
|
function (err, rows) {
|
||||||
|
if (err) {
|
||||||
|
cb(err, null);
|
||||||
|
} else if (rows.length === 0) {
|
||||||
|
cb("Invalid password reset link", null);
|
||||||
|
} else {
|
||||||
|
cb(null, rows[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.deletePasswordReset = function (hash) {
|
module.exports.deletePasswordReset = function (hash) {
|
||||||
module.exports.query("DELETE FROM `password_reset` WHERE hash=?", [hash]);
|
module.exports.query("DELETE FROM `password_reset` WHERE hash=?", [hash]);
|
||||||
};
|
};
|
||||||
|
|
|
@ -69,4 +69,4 @@ var eventlog = makeConsoleLogger(path.join(__dirname, "..", "events.log"));
|
||||||
exports.Logger = Logger;
|
exports.Logger = Logger;
|
||||||
exports.errlog = errlog;
|
exports.errlog = errlog;
|
||||||
exports.syslog = syslog;
|
exports.syslog = syslog;
|
||||||
exports.eventlog = syslog;
|
exports.eventlog = eventlog;
|
||||||
|
|
|
@ -459,7 +459,7 @@ function handlePasswordResetPage(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a POST request to reset a user"s password
|
* Handles a POST request to reset a user's password
|
||||||
*/
|
*/
|
||||||
function handlePasswordReset(req, res) {
|
function handlePasswordReset(req, res) {
|
||||||
logRequest(req);
|
logRequest(req);
|
||||||
|
@ -548,7 +548,7 @@ function handlePasswordReset(req, res) {
|
||||||
"not initiate this, there is no need to take action."+
|
"not initiate this, there is no need to take action."+
|
||||||
" To reset your password, copy and paste the " +
|
" To reset your password, copy and paste the " +
|
||||||
"following link into your browser: " +
|
"following link into your browser: " +
|
||||||
Config.get("http.domain") + "/passwordrecover/"+hash;
|
Config.get("http.domain") + "/account/passwordrecover/"+hash;
|
||||||
|
|
||||||
var mail = {
|
var mail = {
|
||||||
from: "CyTube Services <" + Config.get("mail.from") + ">",
|
from: "CyTube Services <" + Config.get("mail.from") + ">",
|
||||||
|
@ -579,10 +579,10 @@ function handlePasswordReset(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a request for /passwordreceover/<hash>
|
* Handles a request for /account/passwordrecover/<hash>
|
||||||
*/
|
*/
|
||||||
function handlePasswordRecover(req, res) {
|
function handlePasswordRecover(req, res) {
|
||||||
var hash = req.query.hash;
|
var hash = req.params.hash;
|
||||||
if (typeof hash !== "string") {
|
if (typeof hash !== "string") {
|
||||||
res.send(400);
|
res.send(400);
|
||||||
return;
|
return;
|
||||||
|
@ -592,7 +592,7 @@ function handlePasswordRecover(req, res) {
|
||||||
|
|
||||||
db.lookupPasswordReset(hash, function (err, row) {
|
db.lookupPasswordReset(hash, function (err, row) {
|
||||||
if (err) {
|
if (err) {
|
||||||
sendJade(req, "account-passwordrecover", {
|
sendJade(res, "account-passwordrecover", {
|
||||||
recovered: false,
|
recovered: false,
|
||||||
recoverErr: err,
|
recoverErr: err,
|
||||||
loginName: false
|
loginName: false
|
||||||
|
@ -601,7 +601,7 @@ function handlePasswordRecover(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row.ip && row.ip !== ip) {
|
if (row.ip && row.ip !== ip) {
|
||||||
sendJade(req, "account-passwordrecover", {
|
sendJade(res, "account-passwordrecover", {
|
||||||
recovered: false,
|
recovered: false,
|
||||||
recoverErr: "Your IP address does not match the address " +
|
recoverErr: "Your IP address does not match the address " +
|
||||||
"used to submit the reset request. For your " +
|
"used to submit the reset request. For your " +
|
||||||
|
@ -613,7 +613,7 @@ function handlePasswordRecover(req, res) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Date.now() >= row.expire) {
|
if (Date.now() >= row.expire) {
|
||||||
sendJade(req, "account-passwordrecover", {
|
sendJade(res, "account-passwordrecover", {
|
||||||
recovered: false,
|
recovered: false,
|
||||||
recoverErr: "This password recovery link has expired. Password " +
|
recoverErr: "This password recovery link has expired. Password " +
|
||||||
"recovery links are valid only for 24 hours after " +
|
"recovery links are valid only for 24 hours after " +
|
||||||
|
@ -630,7 +630,7 @@ function handlePasswordRecover(req, res) {
|
||||||
}
|
}
|
||||||
db.users.setPassword(row.name, newpw, function (err) {
|
db.users.setPassword(row.name, newpw, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
sendJade(req, "account-passwordrecover", {
|
sendJade(res, "account-passwordrecover", {
|
||||||
recovered: false,
|
recovered: false,
|
||||||
recoverErr: "Database error. Please contact an administrator if " +
|
recoverErr: "Database error. Please contact an administrator if " +
|
||||||
"this persists.",
|
"this persists.",
|
||||||
|
@ -641,7 +641,7 @@ function handlePasswordRecover(req, res) {
|
||||||
|
|
||||||
db.deletePasswordReset(hash);
|
db.deletePasswordReset(hash);
|
||||||
|
|
||||||
sendJade(req, "account-passwordrecover", {
|
sendJade(res, "account-passwordrecover", {
|
||||||
recovered: true,
|
recovered: true,
|
||||||
recoverPw: newpw,
|
recoverPw: newpw,
|
||||||
loginName: false
|
loginName: false
|
||||||
|
@ -663,5 +663,6 @@ module.exports = {
|
||||||
app.post("/account/profile", handleAccountProfile);
|
app.post("/account/profile", handleAccountProfile);
|
||||||
app.get("/account/passwordreset", handlePasswordResetPage);
|
app.get("/account/passwordreset", handlePasswordResetPage);
|
||||||
app.post("/account/passwordreset", handlePasswordReset);
|
app.post("/account/passwordreset", handlePasswordReset);
|
||||||
|
app.get("/account/passwordrecover/:hash", handlePasswordRecover);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
28
templates/account-passwordrecover.jade
Normal file
28
templates/account-passwordrecover.jade
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
doctype html
|
||||||
|
html(lang="en")
|
||||||
|
head
|
||||||
|
include head
|
||||||
|
mixin head()
|
||||||
|
body
|
||||||
|
#wrap
|
||||||
|
nav.navbar.navbar-inverse.navbar-fixed-top(role="navigation")
|
||||||
|
include nav
|
||||||
|
mixin navheader()
|
||||||
|
#nav-collapsible.collapse.navbar-collapse
|
||||||
|
ul.nav.navbar-nav
|
||||||
|
mixin navdefaultlinks("/account/passwordrecover/")
|
||||||
|
mixin navloginlogout("/account/passwordrecover/")
|
||||||
|
section#mainpage
|
||||||
|
.container
|
||||||
|
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
||||||
|
h3 Recover Password
|
||||||
|
if recovered
|
||||||
|
.alert.alert-success.center.messagebox
|
||||||
|
strong Your password has been changed
|
||||||
|
p Your account has been assigned the temporary password <code>#{recoverPw}</code>. You may now use this password to log in and choose a new password by visiting the <a href="/account/edit">change password/email</a> page.
|
||||||
|
else
|
||||||
|
.alert.alert-danger.center.messagebox
|
||||||
|
strong Password recovery failed
|
||||||
|
p= recoverErr
|
||||||
|
include footer
|
||||||
|
mixin footer()
|
|
@ -34,6 +34,7 @@ html(lang="en")
|
||||||
.form-group
|
.form-group
|
||||||
label(for="password") Password
|
label(for="password") Password
|
||||||
input#password.form-control(type="password", name="password")
|
input#password.form-control(type="password", name="password")
|
||||||
|
a(href="/account/passwordreset") Forgot password?
|
||||||
button.btn.btn-success.btn-block(type="submit") Login
|
button.btn.btn-success.btn-block(type="submit") Login
|
||||||
else
|
else
|
||||||
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
.col-lg-6.col-lg-offset-3.col-md-6.col-md-offset-3
|
||||||
|
|
Loading…
Reference in a new issue