Continue work on account management and password reset

This commit is contained in:
calzoneman 2013-05-29 14:19:43 -04:00
parent f3da02566c
commit 74203ad223
5 changed files with 168 additions and 9 deletions

52
api.js
View File

@ -26,10 +26,12 @@ var jsonHandlers = {
"login" : handleLogin,
"register" : handleRegister,
"changepass" : handlePasswordChange,
"resetpass" : handlePasswordReset,
"recoverpw" : handlePasswordRecover,
"setemail" : handleEmailChange,
"globalbans" : handleGlobalBans,
"admreports" : handleAdmReports,
"pwreset" : handlePasswordReset
"acppwreset" : handleAcpPasswordReset
};
function handle(path, req, res) {
@ -229,6 +231,50 @@ function handlePasswordChange(params, req, res) {
}
}
function handlePasswordReset(params, req, res) {
var name = params.name || "";
var email = unescape(params.email || "");
var ip = req.socket.address().address;
try {
Database.generatePasswordReset(ip, name, email);
}
catch(e) {
sendJSON(res, {
success: false,
error: e
});
return;
}
sendJSON(res, {
success: true
});
}
function handlePasswordRecover(params, req, res) {
var hash = params.hash || "";
var ip = req.socket.address().address;
try {
var info = Database.recoverPassword(hash);
sendJSON(res, {
success: true,
name: info[0],
pw: info[1]
});
Logger.syslog.log(ip + " recovered password for " + name);
return;
}
catch(e) {
sendJSON(res, {
success: false,
error: e
});
}
}
function handleEmailChange(params, req, res) {
var name = params.name || "";
var pw = params.pw || "";
@ -309,7 +355,7 @@ function handleRegister(params, req, res) {
else {
sendJSON(res, {
success: false,
error: "I dunno what went wrong"
error: "Registration error. Contact an admin for assistance."
});
}
}
@ -373,7 +419,7 @@ function handleAdmReports(params, req, res) {
});
}
function handlePasswordReset(params, req, res) {
function handleAcpPasswordReset(params, req, res) {
var name = params.name || "";
var pw = params.pw || "";
var session = params.session || "";

View File

@ -58,7 +58,7 @@ exports.register = function(name, pw) {
var hash = bcrypt.hashSync(pw, 10);
var query = Database.createQuery(
["INSERT INTO `registrations` VALUES ",
"(NULL, ?, ?, 1, '', 0, '', '')"].join(""),
"(NULL, ?, ?, 1, '', 0, '', '', '')"].join(""),
[name, hash]
);
var results = db.querySync(query);

View File

@ -2,6 +2,7 @@ var mysql = require("mysql-libmysqlclient");
var Logger = require("./logger");
var Media = require("./media").Media;
var bcrypt = require("bcrypt");
var hashlib = require("node_hash");
var db = false;
var SERVER = "";
@ -620,13 +621,14 @@ function generatePasswordReset(ip, name, email) {
// Validation complete, now time to reset it
var hash = hashlib.sha256(Date.now() + name);
var exp = Date.now() + 24*60*60*1000;
query = createQuery(
["INSERT INTO `password_reset` (",
"`ip`, `name`, `hash`, `email`, `expire",
"`ip`, `name`, `hash`, `email`, `expire`",
") VALUES (",
"?, ?, ?, ?, ?",
")"].join(""),
[ip, name, hash, email, Date.now() + 24*60*60]
") ON DUPLICATE KEY UPDATE `expire`=?"].join(""),
[ip, name, hash, email, exp, exp]
);
results = db.querySync(query);
@ -638,6 +640,45 @@ function generatePasswordReset(ip, name, email) {
return true;
}
function recoverPassword(hash) {
var db = getConnection();
if(!db) {
return false;
}
var query = createQuery(
"SELECT * FROM password_reset WHERE hash=?",
[hash]
);
var results = db.querySync(query);
if(!results) {
Logger.errlog.log("! Failed to retrieve from password_reset");
throw "Database error. Contact an administrator";
}
var rows = results.fetchAllSync();
if(rows.length == 0) {
throw "Invalid password reset link";
}
db.querySync(createQuery(
"DELETE FROM password_reset WHERE hash=?",
[hash]
));
if(Date.now() > rows[0].expire) {
throw "Link expired. Password resets are valid for 24 hours";
}
var pw;
if(!(pw = resetPassword(rows[0].name))) {
throw "Operation failed. Contact an administrator.";
}
return [rows[0].name, pw];
}
function resetPassword(name) {
var db = getConnection();
if(!db) {
@ -684,4 +725,5 @@ exports.channelUnbanName = channelUnbanName;
exports.setProfile = setProfile;
exports.setUserEmail = setUserEmail;
exports.generatePasswordReset = generatePasswordReset;
exports.recoverPassword = recoverPassword;
exports.resetPassword = resetPassword;

View File

@ -160,6 +160,28 @@
</div>
</form>
</div>
<div class="span7" id="pwresetpane" style="display: none">
<h3>Reset Password</h3>
<form class="form-horizontal" action="javascript:void(0)">
<div class="control-group">
<label class="control-label" for="rpusername">Username</label>
<div class="controls">
<input type="text" id="rpusername">
</div>
</div>
<div class="control-group">
<label class="control-label" for="rpemail">Email</label>
<div class="controls">
<input type="text" id="rpemail">
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary" id="rpbtn">Send Reset</button>
</div>
</div>
</form>
</div>
</div>
</div> <!-- /container -->
<div class="push"></div>

View File

@ -40,17 +40,18 @@ function makeTabCallback(tabid, paneid) {
$("#register").click(makeTabCallback("#register", "#registerpane"));
$("#pwchange").click(makeTabCallback("#pwchange", "#changepwpane"));
$("#pwreset").click(makeTabCallback("#pwreset", "#pwresetpane"));
$("#email").click(makeTabCallback("#email", "#changeemailpane"));
$("#registerbtn").click(function() {
$("#registerpane").find(".alert-error").remove();
$("#registerpane").find(".error").removeClass("error");
var uname = $("#regusername").val();
var name = $("#regusername").val();
var pw = $("#regpw").val();
var pwc = $("#regpwconfirm").val();
var err = false;
if(!uname.match(/^[a-z0-9_]{1,20}$/i)) {
if(!name.match(/^[a-z0-9_]{1,20}$/i)) {
$("<div/>").addClass("alert alert-error")
.text("Usernames must be 1-20 characters long and contain only a-z, 0-9, and underscores")
.insertAfter($("#regusername").parent().parent());
@ -78,6 +79,28 @@ $("#registerbtn").click(function() {
}
// Input valid, try registering
var url = api + "register?" + [
"name=" + name,
"pw=" + pw
].join("&") + "&callback=?";
$.getJSON(url, function(data) {
if(data.success) {
uname = name;
session = data.session;
onLogin();
$("<div/>").addClass("alert alert-success")
.text("Registration successful")
.insertBefore($("#registerpane form"));
$("#regpw").val("");
$("#regusername").val("");
}
else {
$("<div/>").addClass("alert alert-error")
.text(data.error)
.insertBefore($("#registerpane form"));
}
});
});
$("#loginbtn").click(function() {
@ -227,6 +250,32 @@ $("#cebtn").click(function() {
});
$("#rpbtn").click(function() {
$("#pwresetpane").find(".alert-error").remove();
$("#pwresetpane").find(".alert-success").remove();
var name = $("#rpusername").val();
var email = $("#rpemail").val();
email = escape(email);
var url = api + "resetpass?" + [
"name=" + name,
"email=" + email
].join("&") + "&callback=?";
$.getJSON(url, function(data) {
if(data.success) {
$("<div/>").addClass("alert alert-success")
.text("Password reset link issued. Check your email.")
.insertBefore($("#pwresetpane form"));
}
else {
$("<div/>").addClass("alert alert-error")
.text(data.error)
.insertBefore($("#pwresetpane form"));
}
});
});
$("#login").click(function() {
if(!loggedin) {
makeTabCallback("#login", "#loginpane")();