Start working on account management

This commit is contained in:
calzoneman 2013-05-29 11:49:09 -04:00
parent 8592c17bec
commit f3da02566c
4 changed files with 525 additions and 3 deletions

52
api.js
View File

@ -26,6 +26,7 @@ var jsonHandlers = {
"login" : handleLogin,
"register" : handleRegister,
"changepass" : handlePasswordChange,
"setemail" : handleEmailChange,
"globalbans" : handleGlobalBans,
"admreports" : handleAdmReports,
"pwreset" : handlePasswordReset
@ -194,7 +195,7 @@ function handleLogin(params, req, res) {
}
else {
sendJSON(res, {
error: "Invalid session",
error: "Invalid username/password",
success: false
});
}
@ -216,13 +217,58 @@ function handlePasswordChange(params, req, res) {
var success = Auth.setUserPassword(name, newpw);
sendJSON(res, {
success: success,
error: success ? "" : "Change password failed"
error: success ? "" : "Change password failed",
session: row.session_hash
});
}
else {
sendJSON(res, {
success: false,
error: "Invalid username or password"
error: "Invalid username/password"
});
}
}
function handleEmailChange(params, req, res) {
var name = params.name || "";
var pw = params.pw || "";
var email = unescape(params.email) || "";
if(!email.match(/^[a-z0-9_\.]+@[a-z0-9_\.]+[a-z]+$/)) {
sendJSON(res, {
success: false,
error: "Invalid email"
});
return;
}
if(email.match(/.*@(localhost|127\.0\.0\.1)/i)) {
sendJSON(res, {
success: false,
error: "Nice try, but no."
});
return;
}
if(pw == "") {
sendJSON(res, {
success: false,
error: "Password cannot be empty"
});
return;
}
var row = Auth.login(name, pw);
if(row) {
var success = Database.setUserEmail(name, email);
sendJSON(res, {
success: success,
error: success ? "" : "Email update failed",
session: row.session_hash
});
}
else {
sendJSON(res, {
success: false,
error: "Invalid username/password"
});
}
}

View File

@ -574,6 +574,25 @@ function setProfile(name, data) {
return db.querySync(query);
}
function setUserEmail(name, email) {
var db = getConnection();
if(!db) {
return false;
}
var query = createQuery(
"UPDATE `registrations` SET `email`=? WHERE `uname`=?",
[email, name]
);
var results = db.querySync(query);
if(!results) {
Logger.errlog.log("! Failed to set user email");
return false;
}
return true;
}
function generatePasswordReset(ip, name, email) {
var db = getConnection();
if(!db) {
@ -663,5 +682,6 @@ exports.channelBan = channelBan;
exports.channelUnbanIP = channelUnbanIP;
exports.channelUnbanName = channelUnbanName;
exports.setProfile = setProfile;
exports.setUserEmail = setUserEmail;
exports.generatePasswordReset = generatePasswordReset;
exports.resetPassword = resetPassword;

187
www/account.html Normal file
View File

@ -0,0 +1,187 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CyTube</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="Calvin 'calzoneman' Montgomery">
<link href="./assets/css/bootstrap.css" rel="stylesheet">
<link href="./assets/css/ytsync.css" rel="stylesheet">
<style>
body {
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
}
</style>
<link href="./assets/css/bootstrap-responsive.css" rel="stylesheet">
</head>
<body>
<div class="wrapper">
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="index.html">CyTube</a>
<div class="">
<ul class="nav">
<li class="active"><a href="index.html">Home</a></li>
<li><a href="help.html">Help</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="span4 well" style="padding: 8px 0;">
<ul class="nav nav-list" id="accountnav">
<li class="nav-header">Not Logged In</li>
<li><a href="javascript:void(0)" id="register">Register</a></li>
<li><a href="javascript:void(0)" id="login">Login</a></li>
<li class="nav-header">Account Control</li>
<li><a href="javascript:void(0)" id="pwchange">Change Password</a></li>
<li><a href="javascript:void(0)" id="pwreset">Reset Password</a></li>
<li><a href="javascript:void(0)" id="profile">Edit Profile</a></li>
<li><a href="javascript:void(0)" id="email">Change Email</a></li>
</ul>
</div>
<div class="span7" id="registerpane" style="display: none">
<h3>Register New Account</h3>
<form class="form-horizontal" action="javascript:void(0)">
<div class="control-group">
<label class="control-label" for="regusername">Username</label>
<div class="controls">
<input type="text" id="regusername">
</div>
</div>
<div class="control-group">
<label class="control-label" for="regpw">Password</label>
<div class="controls">
<input type="password" id="regpw">
</div>
</div>
<div class="control-group">
<label class="control-label" for="regpwconfirm">Confirm Password</label>
<div class="controls">
<input type="password" id="regpwconfirm">
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary" id="registerbtn">Register</button>
</div>
</div>
</form>
</div>
<div class="span7" id="changepwpane" style="display: none">
<h3>Change Password</h3>
<form class="form-horizontal" action="javascript:void(0)">
<div class="control-group">
<label class="control-label" for="cpwusername">Username</label>
<div class="controls">
<input type="text" id="cpwusername">
</div>
</div>
<div class="control-group">
<label class="control-label" for="cpwoldpw">Old Password</label>
<div class="controls">
<input type="password" id="cpwoldpw">
</div>
</div>
<div class="control-group">
<label class="control-label" for="cpwnewpw">New Password</label>
<div class="controls">
<input type="password" id="cpwnewpw">
</div>
</div>
<div class="control-group">
<label class="control-label" for="cpwconfirm">Confirm New Password</label>
<div class="controls">
<input type="password" id="cpwconfirm">
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary" id="cpwbtn">Change Password</button>
</div>
</div>
</form>
</div>
<div class="span7" id="loginpane" style="display: none">
<h3>Login</h3>
<form class="form-horizontal" action="javascript:void(0)">
<div class="control-group">
<label class="control-label" for="loginusername">Username</label>
<div class="controls">
<input type="text" id="loginusername">
</div>
</div>
<div class="control-group">
<label class="control-label" for="loginpw">Password</label>
<div class="controls">
<input type="password" id="loginpw">
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary" id="loginbtn">Login</button>
</div>
</div>
</form>
</div>
<div class="span7" id="changeemailpane" style="display: none">
<h3>Change Email</h3>
<form class="form-horizontal" action="javascript:void(0)">
<div class="control-group">
<label class="control-label" for="ceusername">Username</label>
<div class="controls">
<input type="text" id="ceusername">
</div>
</div>
<div class="control-group">
<label class="control-label" for="cepw">Password</label>
<div class="controls">
<input type="password" id="cepw">
</div>
</div>
<div class="control-group">
<label class="control-label" for="ceemail">Email</label>
<div class="controls">
<input type="text" id="ceemail">
</div>
</div>
<div class="control-group">
<div class="controls">
<button class="btn btn-primary" id="cebtn">Update</button>
</div>
</div>
</form>
</div>
</div>
</div> <!-- /container -->
<div class="push"></div>
<div id="sitefooter">
</div>
</div>
<div id="footer">
<p class="muted">
CyTube Software Copyright &copy; 2013 Calvin Montgomery&nbsp;&middot;&nbsp;Available for free on <a href="http://github.com/calzoneman/sync">GitHub</a>&nbsp;&middot;
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=5Y7PUVVGVSEWG&lc=US&item_name=CyTube&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted">Donate</a>
</p>
</div>
<!-- Third party -->
<script src="./assets/js/jquery.js"></script>
<script src="./assets/js/bootstrap.js"></script>
<script src="./assets/js/bootstrap-transition.js"></script>
<script src="./assets/js/bootstrap-modal.js"></script>
<!-- Mine -->
<script src="./assets/js/iourl.js"></script>
<script src="./assets/js/account.js"></script>
</body>
</html>

269
www/assets/js/account.js Normal file
View File

@ -0,0 +1,269 @@
var uname = readCookie("sync_uname") || "";
var session = readCookie("sync_session") || "";
var api = WEB_URL + "/api/json/";
var loggedin = false;
if(uname && session) {
var loginstr = "name=" + uname + "&session=" + session;
var url = api + "login?" + loginstr + "&callback=?";
$.getJSON(url, function(data) {
if(data.success) {
onLogin();
}
});
}
function onLogin() {
$("#cpwusername").val(uname);
$("#ceusername").val(uname);
$("#accountnav li")[0].innerHTML = "Logged in as " + uname;
$("#register").hide();
loggedin = true;
$("#login").text("Logout");
createCookie("sync_uname", uname, 7);
createCookie("sync_session", session, 7);
}
function makeTabCallback(tabid, paneid) {
return function() {
$("#accountnav li").each(function() {
$(this).removeClass("active");
});
$(tabid).parent().addClass("active");
$(".span7").each(function() {
$(this).css("display", "none");
});
$(paneid).css("display", "");
};
}
$("#register").click(makeTabCallback("#register", "#registerpane"));
$("#pwchange").click(makeTabCallback("#pwchange", "#changepwpane"));
$("#email").click(makeTabCallback("#email", "#changeemailpane"));
$("#registerbtn").click(function() {
$("#registerpane").find(".alert-error").remove();
$("#registerpane").find(".error").removeClass("error");
var uname = $("#regusername").val();
var pw = $("#regpw").val();
var pwc = $("#regpwconfirm").val();
var err = false;
if(!uname.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());
err = true;
}
if(pw == "") {
$("<div/>").addClass("alert alert-error")
.text("Password must not be blank")
.insertAfter($("#regpw").parent().parent());
$("#regpw").parent().parent().addClass("error");
err = true;
}
if(pw != pwc) {
$("<div/>").addClass("alert alert-error")
.text("Passwords do not match")
.insertAfter($("#regpwconfirm").parent().parent());
$("#regpwconfirm").parent().parent().addClass("error");
err = true;
}
if(err) {
return;
}
// Input valid, try registering
});
$("#loginbtn").click(function() {
$("#loginpane").find(".alert-error").remove();
$("#loginpane").find(".alert-success").remove();
if($("#loginpw").val() == "") {
$("<div/>").addClass("alert alert-error")
.text("Please provide a password")
.insertAfter($("#loginpw").parent().parent());
$("#loginpw").parent().parent().addClass("error");
return;
}
uname = $("#loginusername").val();
var loginstr = "name=" + uname + "&pw=" + $("#loginpw").val();
var url = api + "login?" + loginstr + "&callback=?";
$.getJSON(url, function(data) {
if(data.success) {
session = data.session;
onLogin();
$("<div/>").addClass("alert alert-success")
.text("Login successful")
.insertBefore($("#loginpane form"));
$("#loginpw").val("");
$("#loginusername").val("");
}
else {
$("<div/>").addClass("alert alert-error")
.text(data.error)
.insertBefore($("#loginpane form"));
}
});
});
$("#cpwbtn").click(function() {
$("#changepwpane").find(".alert-error").remove();
$("#changepwpane").find(".alert-success").remove();
$("#changepwpane").find(".error").removeClass("error");
var name = $("#cpwusername").val();
var oldpw = $("#cpwoldpw").val();
var newpw = $("#cpwnewpw").val();
var newpwc = $("#cpwconfirm").val();
var err = false;
if(oldpw == "") {
$("<div/>").addClass("alert alert-error")
.text("Password must not be empty")
.insertAfter($("#cpwoldpw").parent().parent());
$("#cpwoldpw").parent().parent().addClass("error");
err = true;
}
if(newpw == "") {
$("<div/>").addClass("alert alert-error")
.text("Password must not be empty")
.insertAfter($("#cpwnewpw").parent().parent());
$("#cpwnewpw").parent().parent().addClass("error");
err = true;
}
if(newpw != newpwc) {
$("<div/>").addClass("alert alert-error")
.text("Passwords do not match")
.insertAfter($("#cpwconfirm").parent().parent());
$("#cpwconfirm").parent().parent().addClass("error");
err = true;
}
if(err) {
return;
}
// Input valid, try changing password
var url = api + "changepass?" + [
"name=" + name,
"oldpw=" + oldpw,
"newpw=" + newpw
].join("&") + "&callback=?";
$.getJSON(url, function(data) {
if(data.success) {
$("<div/>").addClass("alert alert-success")
.text("Password changed.")
.insertBefore($("#changepwpane form"));
uname = name;
session = data.session;
onLogin();
}
else {
$("<div/>").addClass("alert alert-error")
.text(data.error)
.insertBefore($("#changepwpane form"));
}
});
});
$("#cebtn").click(function() {
$("#changeemailpane").find(".alert-error").remove();
$("#changeemailpane").find(".alert-success").remove();
var name = $("#ceusername").val();
var pw = $("#cepw").val();
var email = $("#ceemail").val();
if(pw == "") {
$("<div/>").addClass("alert alert-error")
.text("Please provide a password")
.insertAfter($("#cepw").parent().parent());
$("#cepw").parent().parent().addClass("error");
return;
}
if(!email.match(/^[a-z0-9_\.]+@[a-z0-9_\.]+[a-z]+$/)) {
$("<div/>").addClass("alert alert-error")
.text("Invalid email")
.insertAfter($("#ceemail").parent().parent());
$("#ceemail").parent().parent().addClass("error");
return;
}
if(email.match(/.*@(localhost|127\.0\.0\.1)/i)) {
$("<div/>").addClass("alert alert-error")
.text("Nice try, but no.")
.insertAfter($("#ceemail").parent().parent());
$("#ceemail").parent().parent().addClass("error");
return;
}
email = escape(email);
var url = api + "setemail?" + [
"name=" + name,
"pw=" + pw,
"email=" + email
].join("&") + "&callback=?";
$.getJSON(url, function(data) {
if(data.success) {
$("<div/>").addClass("alert alert-success")
.text("Email updated")
.insertBefore($("#changeemailpane form"));
uname = name;
session = data.session;
onLogin();
}
else {
$("<div/>").addClass("alert alert-error")
.text(data.error)
.insertBefore($("#changeemailpane form"));
}
});
});
$("#login").click(function() {
if(!loggedin) {
makeTabCallback("#login", "#loginpane")();
}
else {
uname = "";
session = "";
eraseCookie("sync_uname");
eraseCookie("sync_session");
$("#accountnav li")[0].innerHTML = "Not Logged In";
$("#register").show();
$("#login").text("Login");
loggedin = false;
}
});
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(";");
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==" ") c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function eraseCookie(name) {
createCookie(name,"",-1);
}