diff --git a/lib/database.js b/lib/database.js index 39b4f3c7..28768a87 100644 --- a/lib/database.js +++ b/lib/database.js @@ -4,10 +4,14 @@ var bcrypt = require("bcrypt"); var $util = require("./utilities"); var Logger = require("./logger"); -var Database = function (cfg) { - var self = this; - self.cfg = cfg; - self.pool = mysql.createPool({ +var cfg = {}; +var pool = null; +var global_ipbans = {}; +var users = null; + +module.exports.init = function (cfg) { + cfg = cfg; + pool = mysql.createPool({ host: cfg["mysql-server"], user: cfg["mysql-user"], password: cfg["mysql-pw"], @@ -16,21 +20,22 @@ var Database = function (cfg) { }); // Test the connection - self.pool.getConnection(function (err, conn) { + pool.getConnection(function (err, conn) { if(err) { Logger.errlog.log("! DB connection failed"); return; } else { - self.init(); + // Refresh global IP bans + module.exports.listGlobalIPBans(); } }); - self.global_ipbans = {}; - self.users = require("./database/accounts")(self); - self.users.init(); + global_ipbans = {}; + users = require("./database/accounts"); + users.init(); }; -Database.prototype.query = function (query, sub, callback) { +module.exports.query = function (query, sub, callback) { // 2nd argument is optional if(typeof sub === "function") { callback = sub; @@ -40,8 +45,7 @@ Database.prototype.query = function (query, sub, callback) { if(typeof callback !== "function") callback = blackHole; - var self = this; - self.pool.getConnection(function (err, conn) { + pool.getConnection(function (err, conn) { if(err) { Logger.errlog.log("! DB connection failed: " + err); callback("Database failure", null); @@ -72,8 +76,7 @@ function blackHole() { } -Database.prototype.init = function () { - var self = this; +module.exports.oldinit = function () { var query; // Create channel table query = ["CREATE TABLE IF NOT EXISTS `channels` (", @@ -84,7 +87,7 @@ Database.prototype.init = function () { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { Logger.errlog.log("! Failed to create channels table"); } @@ -105,7 +108,7 @@ Database.prototype.init = function () { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { Logger.errlog.log("! Failed to create registration table"); } @@ -119,7 +122,7 @@ Database.prototype.init = function () { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { Logger.errlog.log("! Failed to create global ban table"); } @@ -136,7 +139,7 @@ Database.prototype.init = function () { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { Logger.errlog.log("! Failed to create password reset table"); } @@ -153,7 +156,7 @@ Database.prototype.init = function () { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { Logger.errlog.log("! Failed to create user playlist table"); } @@ -169,7 +172,7 @@ Database.prototype.init = function () { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { Logger.errlog.log("! Failed to create user aliases table"); } @@ -186,7 +189,7 @@ Database.prototype.init = function () { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { Logger.errlog.log("! Failed to create action log table"); } @@ -202,19 +205,19 @@ Database.prototype.init = function () { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { Logger.errlog.log("! Failed to create stats table"); } }); // Refresh global IP bans - self.listGlobalIPBans(); + module.exports.listGlobalIPBans(); }; /* REGION global bans */ -Database.prototype.isGlobalIPBanned = function (ip, callback) { +module.exports.isGlobalIPBanned = function (ip, callback) { if(typeof callback !== "function") return; const re = /(\d+)\.(\d+)\.(\d+)\.(\d+)/; @@ -222,59 +225,56 @@ Database.prototype.isGlobalIPBanned = function (ip, callback) { var s16 = ip.replace(re, "$1.$2"); var s24 = ip.replace(re, "$1.$2.$3"); - var banned = ip in this.global_ipbans || - s16 in this.global_ipbans || - s24 in this.global_ipbans; + var banned = ip in global_ipbans || + s16 in global_ipbans || + s24 in global_ipbans; callback(null, banned); }; -Database.prototype.listGlobalIPBans = function (callback) { - var self = this; +module.exports.listGlobalIPBans = function (callback) { if(typeof callback !== "function") callback = blackHole; - self.query("SELECT * FROM global_bans WHERE 1", function (err, res) { + module.exports.query("SELECT * FROM global_bans WHERE 1", function (err, res) { if(err) { callback(err, null); return; } - self.global_ipbans = {}; + global_ipbans = {}; for(var i in res) { - self.global_ipbans[res[i].ip] = res[i].note; + global_ipbans[res[i].ip] = res[i].note; } - callback(null, self.global_ipbans); + callback(null, global_ipbans); }); }; -Database.prototype.setGlobalIPBan = function (ip, reason, callback) { - var self = this; +module.exports.setGlobalIPBan = function (ip, reason, callback) { if(typeof callback !== "function") callback = blackHole; var query = "INSERT INTO global_bans VALUES (?, ?)" + " ON DUPLICATE KEY UPDATE note=?"; - self.query(query, [ip, reason, reason], function (err, res) { + module.exports.query(query, [ip, reason, reason], function (err, res) { if(err) { callback(err, null); return; } - self.listGlobalIPBans(); + module.exports.listGlobalIPBans(); callback(null, res); }); }; -Database.prototype.clearGlobalIPBan = function (ip, callback) { - var self = this; +module.exports.clearGlobalIPBan = function (ip, callback) { if(typeof callback !== "function") callback = blackHole; var query = "DELETE FROM global_bans WHERE ip=?"; - self.query(query, [ip], function (err, res) { + module.exports.query(query, [ip], function (err, res) { if(err) { callback(err, null); return; @@ -288,8 +288,7 @@ Database.prototype.clearGlobalIPBan = function (ip, callback) { /* REGION channels */ -Database.prototype.searchChannel = function (field, value, callback) { - var self = this; +module.exports.searchChannel = function (field, value, callback) { if(typeof callback !== "function") return; @@ -299,11 +298,10 @@ Database.prototype.searchChannel = function (field, value, callback) { else if(field === "name") query += "name LIKE ?"; - self.query(query, ["%" + value + "%"], callback); + module.exports.query(query, ["%" + value + "%"], callback); }; -Database.prototype.channelExists = function (name, callback) { - var self = this; +module.exports.channelExists = function (name, callback) { if(typeof callback !== "function") return; if(!$util.isValidChannelName(name)) { @@ -312,13 +310,12 @@ Database.prototype.channelExists = function (name, callback) { } var query = "SELECT name FROM channels WHERE name=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { callback(err, res.length > 0); }); }; -Database.prototype.registerChannel = function (name, owner, callback) { - var self = this; +module.exports.registerChannel = function (name, owner, callback) { if(typeof callback !== "function") callback = blackHole; @@ -329,7 +326,7 @@ Database.prototype.registerChannel = function (name, owner, callback) { // Messy, but I can't think of a better async solution atm var query = "SELECT * FROM channels WHERE name=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { if(!err && res.length > 0) { callback("Channel already exists", null); return; @@ -344,7 +341,7 @@ Database.prototype.registerChannel = function (name, owner, callback) { "PRIMARY KEY (`id`))", "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { callback(err, null); return; @@ -358,7 +355,7 @@ Database.prototype.registerChannel = function (name, owner, callback) { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { callback(err, null); return; @@ -373,14 +370,14 @@ Database.prototype.registerChannel = function (name, owner, callback) { "ENGINE = MyISAM ", "CHARACTER SET utf8;"].join(""); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { callback(err, null); return; } query = "INSERT INTO channels VALUES (NULL, ?, ?)"; - self.query(query, [name, owner], function (err, res) { + module.exports.query(query, [name, owner], function (err, res) { callback(err, res); }); }); @@ -389,8 +386,7 @@ Database.prototype.registerChannel = function (name, owner, callback) { }); }; -Database.prototype.loadChannelData = function (chan, callback) { - var self = this; +module.exports.loadChannelData = function (chan, callback) { if(typeof callback !== "function") callback = blackHole; @@ -401,7 +397,7 @@ Database.prototype.loadChannelData = function (chan, callback) { var query = "SELECT * FROM channels WHERE name=?"; - self.query(query, [chan.name], function (err, res) { + module.exports.query(query, [chan.name], function (err, res) { if(err) { callback(err, null); return; @@ -423,7 +419,7 @@ Database.prototype.loadChannelData = function (chan, callback) { // Load bans query = "SELECT * FROM `chan_" + chan.name + "_bans`"; - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if (chan.dead) { callback("channel_dead", null); return; @@ -448,8 +444,7 @@ Database.prototype.loadChannelData = function (chan, callback) { }); }; -Database.prototype.dropChannel = function (name, callback) { - var self = this; +module.exports.dropChannel = function (name, callback) { if(typeof callback !== "function") callback = blackHole; @@ -461,7 +456,7 @@ Database.prototype.dropChannel = function (name, callback) { var query = "DROP TABLE `chan_?_bans`,`chan_?_ranks`,`chan_?_library`" .replace(/\?/g, name); - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { Logger.errlog.log("! Failed to drop channel tables for "+name); callback(err, null); @@ -469,7 +464,7 @@ Database.prototype.dropChannel = function (name, callback) { } query = "DELETE FROM channels WHERE name=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { callback(err, res); if(err) { Logger.errlog.log("! Failed to delete channel "+name); @@ -478,8 +473,7 @@ Database.prototype.dropChannel = function (name, callback) { }); }; -Database.prototype.getChannelRank = function (channame, name, callback) { - var self = this; +module.exports.getChannelRank = function (channame, name, callback) { if(typeof callback !== "function") return; @@ -491,7 +485,7 @@ Database.prototype.getChannelRank = function (channame, name, callback) { var query = "SELECT name, rank FROM `chan_" + channame + "_ranks`" + "WHERE name=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { if(err) { Logger.errlog.log("! Failed to lookup " + channame + " ranks"); callback(err, null); @@ -505,9 +499,8 @@ Database.prototype.getChannelRank = function (channame, name, callback) { }); }; -Database.prototype.listChannelUserRanks = function (channame, names, +module.exports.listChannelUserRanks = function (channame, names, callback) { - var self = this; if(typeof callback !== "function") return; @@ -528,7 +521,7 @@ Database.prototype.listChannelUserRanks = function (channame, names, var query = "SELECT name, rank FROM `chan_" + channame + "_ranks`" + "WHERE name IN " + nlist; - self.query(query, names, function (err, res) { + module.exports.query(query, names, function (err, res) { if(err) { Logger.errlog.log("! Failed to lookup " + channame + " ranks"); callback(err, null); @@ -542,8 +535,7 @@ Database.prototype.listChannelUserRanks = function (channame, names, }); }; -Database.prototype.setChannelRank = function (channame, name, rank, callback) { - var self = this; +module.exports.setChannelRank = function (channame, name, rank, callback) { if(typeof callback !== "function") callback = blackHole; @@ -556,11 +548,10 @@ Database.prototype.setChannelRank = function (channame, name, rank, callback) { "(name, rank) VALUES (?, ?) " + "ON DUPLICATE KEY UPDATE rank=?"; - self.query(query, [name, rank, rank], callback); + module.exports.query(query, [name, rank, rank], callback); }; -Database.prototype.insertChannelRank = function (channame, name, rank, callback) { - var self = this; +module.exports.insertChannelRank = function (channame, name, rank, callback) { if(typeof callback !== "function") callback = blackHole; @@ -573,11 +564,10 @@ Database.prototype.insertChannelRank = function (channame, name, rank, callback) "(name, rank) VALUES (?, ?) " + "ON DUPLICATE KEY UPDATE rank=rank"; - self.query(query, [name, rank], callback); + module.exports.query(query, [name, rank], callback); }; -Database.prototype.listChannelRanks = function (channame, callback) { - var self = this; +module.exports.listChannelRanks = function (channame, callback) { if(typeof callback !== "function") return; @@ -587,11 +577,10 @@ Database.prototype.listChannelRanks = function (channame, callback) { } var query = "SELECT * FROM `chan_" + channame + "_ranks` WHERE 1"; - self.query(query, callback); + module.exports.query(query, callback); }; -Database.prototype.addToLibrary = function (channame, media, callback) { - var self = this; +module.exports.addToLibrary = function (channame, media, callback) { if(typeof callback !== "function") callback = blackHole; @@ -610,11 +599,10 @@ Database.prototype.addToLibrary = function (channame, media, callback) { media.seconds, media.type ]; - self.query(query, params, callback); + module.exports.query(query, params, callback); }; -Database.prototype.removeFromLibrary = function (channame, id, callback) { - var self = this; +module.exports.removeFromLibrary = function (channame, id, callback) { if(typeof callback !== "function") callback = blackHole; @@ -624,11 +612,10 @@ Database.prototype.removeFromLibrary = function (channame, id, callback) { } var query = "DELETE FROM `chan_" + channame + "_library` WHERE id=?"; - self.query(query, [id], callback); + module.exports.query(query, [id], callback); }; -Database.prototype.getLibraryItem = function (channame, id, callback) { - var self = this; +module.exports.getLibraryItem = function (channame, id, callback) { if(typeof callback !== "function") callback = blackHole; @@ -648,7 +635,7 @@ Database.prototype.getLibraryItem = function (channame, id, callback) { var query = "SELECT id, title, seconds, type FROM " + "`chan_" + channame + "_library` WHERE id=?"; - self.query(query, [id], function (err, res) { + module.exports.query(query, [id], function (err, res) { if(err) { callback(err, null); return; @@ -658,8 +645,7 @@ Database.prototype.getLibraryItem = function (channame, id, callback) { }); }; -Database.prototype.searchLibrary = function (channame, term, callback) { - var self = this; +module.exports.searchLibrary = function (channame, term, callback) { if(typeof callback !== "function") return; @@ -671,12 +657,11 @@ Database.prototype.searchLibrary = function (channame, term, callback) { var query = "SELECT id, title, seconds, type FROM " + "`chan_" + channame + "_library` WHERE title LIKE ?"; - self.query(query, ["%" + term + "%"], callback); + module.exports.query(query, ["%" + term + "%"], callback); }; -Database.prototype.addChannelBan = function (channame, ip, name, banBy, +module.exports.addChannelBan = function (channame, ip, name, banBy, callback) { - var self = this; if(typeof callback !== "function") callback = blackHole; @@ -689,11 +674,10 @@ Database.prototype.addChannelBan = function (channame, ip, name, banBy, "(ip, name, banner) VALUES (?, ?, ?) " + "ON DUPLICATE KEY UPDATE ip=ip"; - self.query(query, [ip, name, banBy], callback); + module.exports.query(query, [ip, name, banBy], callback); }; -Database.prototype.clearChannelIPBan = function (channame, ip, callback) { - var self = this; +module.exports.clearChannelIPBan = function (channame, ip, callback) { if(typeof callback !== "function") callback = blackHole; @@ -703,12 +687,11 @@ Database.prototype.clearChannelIPBan = function (channame, ip, callback) { } var query = "DELETE FROM `chan_" + channame + "_bans` WHERE ip=?"; - self.query(query, [ip], callback); + module.exports.query(query, [ip], callback); }; -Database.prototype.clearChannelNameBan = function (channame, name, +module.exports.clearChannelNameBan = function (channame, name, callback) { - var self = this; if(typeof callback !== "function") { callback = blackHole; return; @@ -717,20 +700,19 @@ Database.prototype.clearChannelNameBan = function (channame, name, var query = "DELETE FROM `chan_" + channame + "_bans` WHERE ip='*'" + "AND name=?"; - self.query(query, [name], callback); + module.exports.query(query, [name], callback); }; /* END REGION */ /* REGION Auth */ -Database.prototype.isUsernameTaken = function (name, callback) { - var self = this; +module.exports.isUsernameTaken = function (name, callback) { if(typeof callback !== "function") return; var query = "SELECT id FROM registrations WHERE uname=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { if(err) { callback(err, null); return; @@ -741,8 +723,7 @@ Database.prototype.isUsernameTaken = function (name, callback) { }; var regInProgress = {}; -Database.prototype.registerUser = function (name, pw, callback) { - var self = this; +module.exports.registerUser = function (name, pw, callback) { if(typeof callback !== "function") callback = blackHole; @@ -765,7 +746,7 @@ Database.prototype.registerUser = function (name, pw, callback) { return; } - self.createLoginSession(name, function (err, hash) { + createLoginSession(name, function (err, hash) { if(err) { delete regInProgress[name]; // Don't confuse people into thinking the registration @@ -779,7 +760,7 @@ Database.prototype.registerUser = function (name, pw, callback) { }); }; - self.isUsernameTaken(name, function (err, taken) { + isUsernameTaken(name, function (err, taken) { if(err) { delete regInProgress[name]; callback(err, null); @@ -802,13 +783,12 @@ Database.prototype.registerUser = function (name, pw, callback) { var query = "INSERT INTO registrations VALUES " + "(NULL, ?, ?, 1, '', 0, '', '', '')"; - self.query(query, [name, hash], postRegister); + module.exports.query(query, [name, hash], postRegister); }); }); }; -Database.prototype.userLogin = function (name, pw, session, callback) { - var self = this; +module.exports.userLogin = function (name, pw, session, callback) { if(typeof callback !== "function") callback = blackHole; @@ -823,7 +803,7 @@ Database.prototype.userLogin = function (name, pw, session, callback) { return; } - self.createLoginSession(name, function (err, hash) { + createLoginSession(name, function (err, hash) { if(err) { callback(err, null); return; @@ -835,21 +815,20 @@ Database.prototype.userLogin = function (name, pw, session, callback) { }; if(session) { - self.userLoginSession(name, session, postLogin); + module.exports.userLoginSession(name, session, postLogin); } else if(pw) { - self.userLoginPassword(name, pw, postLogin); + module.exports.userLoginPassword(name, pw, postLogin); } else { callback("Invalid login", null); } }; -Database.prototype.userLoginPassword = function (name, pw, callback) { - var self = this; +module.exports.userLoginPassword = function (name, pw, callback) { if(typeof callback !== "function") callback = blackHole; var query = "SELECT * FROM registrations WHERE uname=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { if(err) { callback(err, null); return; @@ -879,7 +858,7 @@ Database.prototype.userLoginPassword = function (name, pw, callback) { // Replace it bcrypt.hash(pw, 10, function (err, hash) { if(!err) { - self.query("UPDATE registrations SET pw=? "+ + module.exports.query("UPDATE registrations SET pw=? "+ "WHERE uname=?", [hash, name]); } }); @@ -895,15 +874,14 @@ Database.prototype.userLoginPassword = function (name, pw, callback) { }); }; -Database.prototype.userLoginSession = function (name, session, callback) { - var self = this; +module.exports.userLoginSession = function (name, session, callback) { if(typeof callback !== "function") callback = blackHole; var query = "SELECT * FROM registrations WHERE uname=? AND " + "session_hash=?"; - self.query(query, [name, session], function (err, res) { + module.exports.query(query, [name, session], function (err, res) { if(err) { callback(err, null); return; @@ -925,8 +903,7 @@ Database.prototype.userLoginSession = function (name, session, callback) { }); }; -Database.prototype.createLoginSession = function (name, callback) { - var self = this; +module.exports.createLoginSession = function (name, callback) { if(typeof callback !== "function") callback = blackHole; @@ -936,7 +913,7 @@ Database.prototype.createLoginSession = function (name, callback) { var query = "UPDATE registrations SET session_hash=?, expire=? " + "WHERE uname=?"; - self.query(query, [hash, Date.now() + 604800000, name], + module.exports.query(query, [hash, Date.now() + 604800000, name], function (err, res) { if(err) { callback(err, null); @@ -947,8 +924,7 @@ Database.prototype.createLoginSession = function (name, callback) { }); }; -Database.prototype.setUserPassword = function (name, pw, callback) { - var self = this; +module.exports.setUserPassword = function (name, pw, callback) { if(typeof callback !== "function") callback = blackHole; @@ -959,18 +935,17 @@ Database.prototype.setUserPassword = function (name, pw, callback) { } var query = "UPDATE registrations SET pw=? WHERE uname=?"; - self.query(query, [hash, name], callback); + module.exports.query(query, [hash, name], callback); }); }; -Database.prototype.getGlobalRank = function (name, callback) { - var self = this; +module.exports.getGlobalRank = function (name, callback) { if(typeof callback !== "function") return; var query = "SELECT global_rank FROM registrations WHERE uname=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { if(err) { callback(err, null); return; @@ -985,8 +960,7 @@ Database.prototype.getGlobalRank = function (name, callback) { }); }; -Database.prototype.listGlobalRanks = function (names, callback) { - var self = this; +module.exports.listGlobalRanks = function (names, callback) { if(typeof callback !== "function") return; @@ -1001,7 +975,7 @@ Database.prototype.listGlobalRanks = function (names, callback) { var query = "SELECT global_rank FROM registrations WHERE uname IN " + nlist; - self.query(query, names, function (err, res) { + module.exports.query(query, names, function (err, res) { if(err) { callback(err, null); return; @@ -1023,8 +997,7 @@ Database.prototype.listGlobalRanks = function (names, callback) { /* REGION users */ -Database.prototype.searchUser = function (name, callback) { - var self = this; +module.exports.searchUser = function (name, callback) { if(typeof callback !== "function") return; @@ -1034,31 +1007,29 @@ Database.prototype.searchUser = function (name, callback) { "profile_text, email FROM registrations WHERE " + "uname LIKE ?"; - self.query(query, ["%" + name + "%"], callback); + module.exports.query(query, ["%" + name + "%"], callback); }; /* rank */ -Database.prototype.setGlobalRank = function (name, rank, callback) { - var self = this; +module.exports.setGlobalRank = function (name, rank, callback) { if(typeof callback !== "function") callback = blackHole; var query = "UPDATE registrations SET global_rank=? WHERE uname=?"; - self.query(query, [rank, name], callback); + module.exports.query(query, [rank, name], callback); }; /* email and profile */ -Database.prototype.getUserProfile = function (name, callback) { - var self = this; +module.exports.getUserProfile = function (name, callback) { if(typeof callback !== "function") callback = blackHole; var query = "SELECT profile_image, profile_text FROM registrations " + "WHERE uname=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { if(err) { callback(err, null); return; @@ -1073,36 +1044,33 @@ Database.prototype.getUserProfile = function (name, callback) { }); }; -Database.prototype.setUserProfile = function (name, data, callback) { - var self = this; +module.exports.setUserProfile = function (name, data, callback) { if(typeof callback !== "function") callback = blackHole; var query = "UPDATE registrations SET profile_image=?, profile_text=?" + "WHERE uname=?"; - self.query(query, [data.image, data.text, name], callback); + module.exports.query(query, [data.image, data.text, name], callback); }; -Database.prototype.setUserEmail = function (name, email, callback) { - var self = this; +module.exports.setUserEmail = function (name, email, callback) { if(typeof callback !== "function") callback = blackHole; var query = "UPDATE registrations SET email=? WHERE uname=?"; - self.query(query, [email, name], callback); + module.exports.query(query, [email, name], callback); }; /* password recovery */ -Database.prototype.genPasswordReset = function (ip, name, email, callback) { - var self = this; +module.exports.genPasswordReset = function (ip, name, email, callback) { if(typeof callback !== "function") callback = blackHole; var query = "SELECT email FROM registrations WHERE uname=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { if(err) { callback(err, null); return; @@ -1123,7 +1091,7 @@ Database.prototype.genPasswordReset = function (ip, name, email, callback) { query = "INSERT INTO password_reset " + "(ip, name, hash, email, expire) VALUES (?, ?, ?, ?, ?) " + "ON DUPLICATE KEY UPDATE hash=?, expire=?"; - self.query(query, [ip, name, hash, email, expire, hash, expire], + module.exports.query(query, [ip, name, hash, email, expire, hash, expire], function (err, res) { if(err) { callback(err, null); @@ -1135,13 +1103,12 @@ Database.prototype.genPasswordReset = function (ip, name, email, callback) { }); }; -Database.prototype.recoverUserPassword = function (hash, callback) { - var self = this; +module.exports.recoverUserPassword = function (hash, callback) { if(typeof callback !== "function") callback = blackHole; var query = "SELECT * FROM password_reset WHERE hash=?"; - self.query(query, [hash], function (err, res) { + module.exports.query(query, [hash], function (err, res) { if(err) { callback(err, null); return; @@ -1153,7 +1120,7 @@ Database.prototype.recoverUserPassword = function (hash, callback) { } if(Date.now() > res[0].expire) { - self.query("DELETE FROM password_reset WHERE hash=?", [hash]); + module.exports.query("DELETE FROM password_reset WHERE hash=?", [hash]); callback("Link expired. Password resets are valid for 24hr", null); return; @@ -1161,13 +1128,13 @@ Database.prototype.recoverUserPassword = function (hash, callback) { var name = res[0].name; - self.resetUserPassword(res[0].name, function (err, pw) { + resetUserPassword(res[0].name, function (err, pw) { if(err) { callback(err, null); return; } - self.query("DELETE FROM password_reset WHERE hash=?", [hash]); + module.exports.query("DELETE FROM password_reset WHERE hash=?", [hash]); callback(null, { name: name, pw: pw @@ -1176,8 +1143,7 @@ Database.prototype.recoverUserPassword = function (hash, callback) { }); }; -Database.prototype.resetUserPassword = function (name, callback) { - var self = this; +module.exports.resetUserPassword = function (name, callback) { if(typeof callback !== "function") callback = blackHole; @@ -1194,7 +1160,7 @@ Database.prototype.resetUserPassword = function (name, callback) { } var query = "UPDATE registrations SET pw=? WHERE uname=?"; - self.query(query, [data, name], function (err, res) { + module.exports.query(query, [data, name], function (err, res) { if(err) { callback(err, null); return; @@ -1207,24 +1173,22 @@ Database.prototype.resetUserPassword = function (name, callback) { /* user playlists */ -Database.prototype.listUserPlaylists = function (name, callback) { - var self = this; +module.exports.listUserPlaylists = function (name, callback) { if(typeof callback !== "function") return; var query = "SELECT name, count, time FROM user_playlists WHERE user=?"; - self.query(query, [name], callback); + module.exports.query(query, [name], callback); }; -Database.prototype.getUserPlaylist = function (username, plname, callback) { - var self = this; +module.exports.getUserPlaylist = function (username, plname, callback) { if(typeof callback !== "function") return; var query = "SELECT contents FROM user_playlists WHERE " + "user=? AND name=?"; - self.query(query, [username, plname], function (err, res) { + module.exports.query(query, [username, plname], function (err, res) { if(err) { callback(err, null); return; @@ -1246,9 +1210,8 @@ Database.prototype.getUserPlaylist = function (username, plname, callback) { }); }; -Database.prototype.saveUserPlaylist = function (pl, username, plname, +module.exports.saveUserPlaylist = function (pl, username, plname, callback) { - var self = this; if(typeof callback !== "function") callback = blackHole; @@ -1272,34 +1235,31 @@ Database.prototype.saveUserPlaylist = function (pl, username, plname, var params = [username, plname, plText, count, time, plText, count, time]; - self.query(query, params, callback); + module.exports.query(query, params, callback); }; -Database.prototype.deleteUserPlaylist = function (username, plname, +module.exports.deleteUserPlaylist = function (username, plname, callback) { - var self = this; if(typeof callback !== "function") callback = blackHole; var query = "DELETE FROM user_playlists WHERE user=? AND name=?"; - self.query(query, [username, plname], callback); + module.exports.query(query, [username, plname], callback); }; /* user channels */ -Database.prototype.listUserChannels = function (username, callback) { - var self = this; +module.exports.listUserChannels = function (username, callback) { if(typeof callback !== "function") return; var query = "SELECT * FROM channels WHERE owner=? ORDER BY id ASC"; - self.query(query, [username], callback); + module.exports.query(query, [username], callback); }; /* aliases */ -Database.prototype.recordVisit = function (ip, name, callback) { - var self = this; +module.exports.recordVisit = function (ip, name, callback) { if(typeof callback !== "function") callback = blackHole; @@ -1307,20 +1267,18 @@ Database.prototype.recordVisit = function (ip, name, callback) { var query = "DELETE FROM aliases WHERE ip=? AND name=?;" + "INSERT INTO aliases VALUES (NULL, ?, ?, ?)"; - self.query(query, [ip, name, ip, name, time], callback); + module.exports.query(query, [ip, name, ip, name, time], callback); }; -Database.prototype.cleanOldAliases = function (expiration, callback) { - var self = this; +module.exports.cleanOldAliases = function (expiration, callback) { if (typeof callback === "undefined") callback = blackHole; var query = "DELETE FROM aliases WHERE time < ?"; - self.query(query, [Date.now() - expiration], callback); + module.exports.query(query, [Date.now() - expiration], callback); }; -Database.prototype.listAliases = function (ip, callback) { - var self = this; +module.exports.listAliases = function (ip, callback) { if(typeof callback !== "function") return; @@ -1335,7 +1293,7 @@ Database.prototype.listAliases = function (ip, callback) { query += " ORDER BY time DESC LIMIT 5"; - self.query(query, [ip], function (err, res) { + module.exports.query(query, [ip], function (err, res) { var names = null; if(!err) { names = []; @@ -1348,13 +1306,12 @@ Database.prototype.listAliases = function (ip, callback) { }); }; -Database.prototype.listIPsForName = function (name, callback) { - var self = this; +module.exports.listIPsForName = function (name, callback) { if(typeof callback !== "function") return; var query = "SELECT ip FROM aliases WHERE name=?"; - self.query(query, [name], function (err, res) { + module.exports.query(query, [name], function (err, res) { var ips = null; if(!err) { ips = []; @@ -1371,20 +1328,18 @@ Database.prototype.listIPsForName = function (name, callback) { /* REGION action log */ -Database.prototype.recordAction = function (ip, name, action, args, +module.exports.recordAction = function (ip, name, action, args, callback) { - var self = this; if(typeof callback !== "function") callback = blackHole; var query = "INSERT INTO actionlog (ip, name, action, args, time) " + "VALUES (?, ?, ?, ?, ?)"; - self.query(query, [ip, name, action, args, Date.now()], callback); + module.exports.query(query, [ip, name, action, args, Date.now()], callback); }; -Database.prototype.clearActions = function (actions, callback) { - var self = this; +module.exports.clearActions = function (actions, callback) { if(typeof callback !== "function") callback = blackHole; @@ -1395,28 +1350,26 @@ Database.prototype.clearActions = function (actions, callback) { var actionlist = "(" + list.join(",") + ")"; var query = "DELETE FROM actionlog WHERE action IN " + actionlist; - self.query(query, actions, callback); + module.exports.query(query, actions, callback); }; -Database.prototype.clearSingleAction = function (item, callback) { - var self = this; +module.exports.clearSingleAction = function (item, callback) { if(typeof callback !== "function") callback = blackHole; var query = "DELETE FROM actionlog WHERE ip=? AND time=?"; - self.query(query, [item.ip, item.time], callback); + module.exports.query(query, [item.ip, item.time], callback); }; -Database.prototype.recentRegistrationCount = function (ip, callback) { - var self = this; +module.exports.recentRegistrationCount = function (ip, callback) { if(typeof callback !== "function") return; var query = "SELECT * FROM actionlog WHERE ip=? " + "AND action='register-success' AND time > ?"; - self.query(query, [ip, Date.now() - 48 * 3600 * 1000], + module.exports.query(query, [ip, Date.now() - 48 * 3600 * 1000], function (err, res) { if(err) { callback(err, null); @@ -1427,13 +1380,12 @@ Database.prototype.recentRegistrationCount = function (ip, callback) { }); }; -Database.prototype.listActionTypes = function (callback) { - var self = this; +module.exports.listActionTypes = function (callback) { if(typeof callback !== "function") return; var query = "SELECT DISTINCT action FROM actionlog"; - self.query(query, function (err, res) { + module.exports.query(query, function (err, res) { if(err) { callback(err, null); return; @@ -1447,8 +1399,7 @@ Database.prototype.listActionTypes = function (callback) { }); }; -Database.prototype.listActions = function (types, callback) { - var self = this; +module.exports.listActions = function (types, callback) { if(typeof callback !== "function") return; @@ -1458,40 +1409,36 @@ Database.prototype.listActions = function (types, callback) { var actionlist = "(" + list.join(",") + ")"; var query = "SELECT * FROM actionlog WHERE action IN " + actionlist; - self.query(query, types, callback); + module.exports.query(query, types, callback); }; /* END REGION */ /* REGION stats */ -Database.prototype.addStatPoint = function (time, ucount, ccount, mem, +module.exports.addStatPoint = function (time, ucount, ccount, mem, callback) { - var self = this; if(typeof callback !== "function") callback = blackHole; var query = "INSERT INTO stats VALUES (?, ?, ?, ?)"; - self.query(query, [time, ucount, ccount, mem], callback); + module.exports.query(query, [time, ucount, ccount, mem], callback); }; -Database.prototype.pruneStats = function (before, callback) { - var self = this; +module.exports.pruneStats = function (before, callback) { if(typeof callback !== "function") callback = blackHole; var query = "DELETE FROM stats WHERE time < ?"; - self.query(query, [before], callback); + module.exports.query(query, [before], callback); }; -Database.prototype.listStats = function (callback) { - var self = this; +module.exports.listStats = function (callback) { if(typeof callback !== "function") return; var query = "SELECT * FROM stats ORDER BY time ASC"; - self.query(query, callback); + module.exports.query(query, callback); }; /* END REGION */ -module.exports = Database; diff --git a/lib/database/accounts.js b/lib/database/accounts.js index f2551224..25d1c2ba 100644 --- a/lib/database/accounts.js +++ b/lib/database/accounts.js @@ -1,498 +1,497 @@ //var db = require("../database"); var $util = require("../utilities"); var bcrypt = require("bcrypt"); +var db = require("../database"); var registrationLock = {}; var blackHole = function () { }; -module.exports = function (db) { - return { - /** - * Initialize the accounts table - */ - init: function () { - db.query("CREATE TABLE IF NOT EXISTS `users` (" + - "`id` INT NOT NULL AUTO_INCREMENT," + - "`name` VARCHAR(20) NOT NULL," + - "`password` VARCHAR(64) NOT NULL," + - "`global_rank` INT NOT NULL," + - "`email` VARCHAR(255) NOT NULL," + - "`profile` TEXT NOT NULL," + - "`ip` VARCHAR(39) NOT NULL," + - "`time` BIGINT NOT NULL, " + - "PRIMARY KEY(`id`), INDEX(`name`)) " + - "CHARACTER SET utf8"); - }, +module.exports = { + /** + * Initialize the accounts table + */ + init: function () { + db.query("CREATE TABLE IF NOT EXISTS `users` (" + + "`id` INT NOT NULL AUTO_INCREMENT," + + "`name` VARCHAR(20) NOT NULL," + + "`password` VARCHAR(64) NOT NULL," + + "`global_rank` INT NOT NULL," + + "`email` VARCHAR(255) NOT NULL," + + "`profile` TEXT NOT NULL," + + "`ip` VARCHAR(39) NOT NULL," + + "`time` BIGINT NOT NULL, " + + "PRIMARY KEY(`id`), INDEX(`name`)) " + + "CHARACTER SET utf8"); + }, - /** - * Check if a username is taken - */ - isUsernameTaken: function (name, callback) { - db.query("SELECT name FROM `users` WHERE name=?", [name], - function (err, rows) { - if (err) { - callback(err, true); - return; - } - callback(null, rows.length > 0); - }); - }, - - /** - * Search for a user by name - */ - search: function (name, fields, callback) { - /* This bit allows it to accept varargs - Function can be called as (name, callback) or - (name, fields, callback) - */ - if (typeof callback !== "function") { - if (typeof fields === "function") { - callback = fields; - fields = ["name"]; - } else { - return; - } - } - - // Don't allow search to return password hashes - if (fields.indexOf("password") !== -1) { - fields.splice(fields.indexOf("password")); - } - - db.query("SELECT " + fields.join(",") + " FROM `users` WHERE name LIKE ?", - ["%"+name+"%"], - function (err, rows) { - if (err) { - callback(err, true); - return; - } - callback(null, rows); - }); - }, - - /** - * Registers a new user account - */ - register: function (name, pw, email, ip, callback) { - // Start off with a boatload of error checking - if (typeof callback !== "function") { - callback = blackHole; - } - - if (typeof name !== "string" || typeof pw !== "string") { - callback(new Error("You must provide a nonempty username and password"), null); + /** + * Check if a username is taken + */ + isUsernameTaken: function (name, callback) { + db.query("SELECT name FROM `users` WHERE name=?", [name], + function (err, rows) { + if (err) { + callback(err, true); return; } - var lname = name.toLowerCase(); + callback(null, rows.length > 0); + }); + }, - if (registrationLock[lname]) { - callback(new Error("There is already a registration in progress for "+name), - null); + /** + * Search for a user by name + */ + search: function (name, fields, callback) { + /* This bit allows it to accept varargs + Function can be called as (name, callback) or + (name, fields, callback) + */ + if (typeof callback !== "function") { + if (typeof fields === "function") { + callback = fields; + fields = ["name"]; + } else { + return; + } + } + + // Don't allow search to return password hashes + if (fields.indexOf("password") !== -1) { + fields.splice(fields.indexOf("password")); + } + + db.query("SELECT " + fields.join(",") + " FROM `users` WHERE name LIKE ?", + ["%"+name+"%"], + function (err, rows) { + if (err) { + callback(err, true); + return; + } + callback(null, rows); + }); + }, + + /** + * Registers a new user account + */ + register: function (name, pw, email, ip, callback) { + // Start off with a boatload of error checking + if (typeof callback !== "function") { + callback = blackHole; + } + + if (typeof name !== "string" || typeof pw !== "string") { + callback(new Error("You must provide a nonempty username and password"), null); + return; + } + var lname = name.toLowerCase(); + + if (registrationLock[lname]) { + callback(new Error("There is already a registration in progress for "+name), + null); + return; + } + + if (!$util.isValidUserName(name)) { + callback(new Error("Invalid username. Usernames may consist of 1-20 " + + "characters a-z, A-Z, 0-9, -, _, and accented letters."), + null); + return; + } + + if (typeof email !== "string") { + email = ""; + } + + if (typeof ip !== "string") { + ip = ""; + } + + // From this point forward, actual registration happens + // registrationLock prevents concurrent database activity + // on the same user account + registrationLock[lname] = true; + + this.isUsernameTaken(name, function (err, taken) { + if (err) { + delete registrationLock[lname]; + callback(err, null); return; } - if (!$util.isValidUserName(name)) { - callback(new Error("Invalid username. Usernames may consist of 1-20 " + - "characters a-z, A-Z, 0-9, -, _, and accented letters."), - null); + if (taken) { + delete registrationLock[lname]; + callback(new Error("Username is already registered"), null); return; } - if (typeof email !== "string") { - email = ""; - } - - if (typeof ip !== "string") { - ip = ""; - } - - // From this point forward, actual registration happens - // registrationLock prevents concurrent database activity - // on the same user account - registrationLock[lname] = true; - - this.isUsernameTaken(name, function (err, taken) { + bcrypt.hash(pw, 10, function (err, hash) { if (err) { delete registrationLock[lname]; callback(err, null); return; } - if (taken) { + db.query("INSERT INTO `users` " + + "(`name`, `password`, `global_rank`, `email`, `ip`, `time`)" + + " VALUES " + + "(?, ?, ?, ?, ?, ?)", + [name, hash, 1, email, ip, Date.now()], + function (err, res) { delete registrationLock[lname]; - callback(new Error("Username is already registered"), null); - return; - } - - bcrypt.hash(pw, 10, function (err, hash) { - if (err) { - delete registrationLock[lname]; - callback(err, null); - return; - } - - db.query("INSERT INTO `users` " + - "(`name`, `password`, `global_rank`, `email`, `ip`, `time`)" + - " VALUES " + - "(?, ?, ?, ?, ?, ?)", - [name, hash, 1, email, ip, Date.now()], - function (err, res) { - delete registrationLock[lname]; - if (err) { - callback(err, null); - } else { - callback(null, { - name: name, - hash: hash - }); - } - }); - }); - }); - }, - - /** - * Verify a username/password pair - */ - verifyLogin: function (name, pw, callback) { - if (typeof callback !== "function") { - return; - } - - if (typeof name !== "string" || typeof pw !== "string") { - callback(new Error("Invalid username/password combination"), null); - return; - } - - /* Passwords are capped at 100 characters to prevent a potential - denial of service vector through causing the server to hash - ridiculously long strings. - */ - pw = pw.substring(0, 100); - - /* Note: rather than hash the password and then query based on name and - password, I query by name, then use bcrypt.compare() to check that - the hashes match. - */ - - db.query("SELECT name,password,global_rank FROM `users` WHERE name=?", - [name], - function (err, rows) { - if (err) { - callback(err, null); - return; - } - - if (rows.length === 0) { - callback(new Error("User does not exist"), null); - return; - } - - bcrypt.compare(pw, rows[0].password, function (err, match) { if (err) { callback(err, null); - } else if (!match) { - callback(new Error("Invalid username/password combination"), null); } else { callback(null, { - name: rows[0].name, - hash: rows[0].password, - global_rank: rows[0].global_rank + name: name, + hash: hash }); } }); }); - }, + }); + }, - /** - * Verify an auth string of the form name:hash - */ - verifyAuth: function (auth, callback) { - if (typeof callback !== "function") { - return; - } - - if (typeof auth !== "string") { - callback(new Error("Invalid auth string"), null); + /** + * Verify a username/password pair + */ + verifyLogin: function (name, pw, callback) { + if (typeof callback !== "function") { + return; + } + + if (typeof name !== "string" || typeof pw !== "string") { + callback(new Error("Invalid username/password combination"), null); + return; + } + + /* Passwords are capped at 100 characters to prevent a potential + denial of service vector through causing the server to hash + ridiculously long strings. + */ + pw = pw.substring(0, 100); + + /* Note: rather than hash the password and then query based on name and + password, I query by name, then use bcrypt.compare() to check that + the hashes match. + */ + + db.query("SELECT name,password,global_rank FROM `users` WHERE name=?", + [name], + function (err, rows) { + if (err) { + callback(err, null); return; } - var split = auth.split(":"); - if (split.length !== 2) { - callback(new Error("Invalid auth string"), null); + if (rows.length === 0) { + callback(new Error("User does not exist"), null); return; } - var name = split[0]; - var hash = split[1]; - db.query("SELECT name,password,global_rank FROM `users` WHERE " + - "name=? and password=?", [name, hash], - function (err, rows) { + bcrypt.compare(pw, rows[0].password, function (err, match) { if (err) { callback(err, null); - return; - } - - if (rows.length === 0) { - callback(new Error("Auth string does not match an existing user"), null); - return; - } - - callback(null, { - name: rows[0].name, - hash: rows[0].password, - global_rank: rows[0].global_rank - }); - }); - }, - - /** - * Change a user's password - */ - setPassword: function (name, pw, callback) { - if (typeof callback !== "function") { - callback = blackHole; - } - - if (typeof name !== "string" || typeof pw !== "string") { - callback(new Error("Invalid username/password combination"), null); - return; - } - - /* Passwords are capped at 100 characters to prevent a potential - denial of service vector through causing the server to hash - ridiculously long strings. - */ - pw = pw.substring(0, 100); - - bcrypt.hash(pw, 10, function (err, hash) { - if (err) { - callback(err, null); - return; - } - - db.query("UPDATE `users` SET password=? WHERE name=?", - [hash, name], - function (err, result) { - callback(err, err ? null : true); - }); - }); - }, - - /** - * Lookup a user's global rank - */ - getGlobalRank: function (name, callback) { - if (typeof callback !== "function") { - return; - } - - if (typeof name !== "string") { - callback(new Error("Invalid username"), null); - return; - } - - db.query("SELECT global_rank FROM `users` WHERE name=?", [name], - function (err, rows) { - if (err) { - callback(err, null); - } else if (rows.length === 0) { - callback(new Error("User does not exist"), null); + } else if (!match) { + callback(new Error("Invalid username/password combination"), null); } else { - callback(null, rows[0].global_rank); + callback(null, { + name: rows[0].name, + hash: rows[0].password, + global_rank: rows[0].global_rank + }); } }); - }, + }); + }, - /** - * Updates a user's global rank - */ - setGlobalRank: function (name, rank, callback) { - if (typeof callback !== "function") { - callback = blackHole; - } + /** + * Verify an auth string of the form name:hash + */ + verifyAuth: function (auth, callback) { + if (typeof callback !== "function") { + return; + } + + if (typeof auth !== "string") { + callback(new Error("Invalid auth string"), null); + return; + } - if (typeof name !== "string") { - callback(new Error("Invalid username"), null); + var split = auth.split(":"); + if (split.length !== 2) { + callback(new Error("Invalid auth string"), null); + return; + } + + var name = split[0]; + var hash = split[1]; + db.query("SELECT name,password,global_rank FROM `users` WHERE " + + "name=? and password=?", [name, hash], + function (err, rows) { + if (err) { + callback(err, null); return; } - if (typeof rank !== "number") { - callback(new Error("Invalid rank"), null); + if (rows.length === 0) { + callback(new Error("Auth string does not match an existing user"), null); return; } - db.query("UPDATE `users` SET global_rank=? WHERE name=?", [rank, name], + callback(null, { + name: rows[0].name, + hash: rows[0].password, + global_rank: rows[0].global_rank + }); + }); + }, + + /** + * Change a user's password + */ + setPassword: function (name, pw, callback) { + if (typeof callback !== "function") { + callback = blackHole; + } + + if (typeof name !== "string" || typeof pw !== "string") { + callback(new Error("Invalid username/password combination"), null); + return; + } + + /* Passwords are capped at 100 characters to prevent a potential + denial of service vector through causing the server to hash + ridiculously long strings. + */ + pw = pw.substring(0, 100); + + bcrypt.hash(pw, 10, function (err, hash) { + if (err) { + callback(err, null); + return; + } + + db.query("UPDATE `users` SET password=? WHERE name=?", + [hash, name], function (err, result) { callback(err, err ? null : true); }); - }, + }); + }, - /** - * Lookup multiple users' global rank in one query - */ - getGlobalRanks: function (names, callback) { - if (typeof callback !== "function") { - return; + /** + * Lookup a user's global rank + */ + getGlobalRank: function (name, callback) { + if (typeof callback !== "function") { + return; + } + + if (typeof name !== "string") { + callback(new Error("Invalid username"), null); + return; + } + + db.query("SELECT global_rank FROM `users` WHERE name=?", [name], + function (err, rows) { + if (err) { + callback(err, null); + } else if (rows.length === 0) { + callback(new Error("User does not exist"), null); + } else { + callback(null, rows[0].global_rank); } + }); + }, - if (!(names instanceof Array)) { - callback(new Error("Expected array of names, got " + typeof names), null); - return; + /** + * Updates a user's global rank + */ + setGlobalRank: function (name, rank, callback) { + if (typeof callback !== "function") { + callback = blackHole; + } + + if (typeof name !== "string") { + callback(new Error("Invalid username"), null); + return; + } + + if (typeof rank !== "number") { + callback(new Error("Invalid rank"), null); + return; + } + + db.query("UPDATE `users` SET global_rank=? WHERE name=?", [rank, name], + function (err, result) { + callback(err, err ? null : true); + }); + }, + + /** + * Lookup multiple users' global rank in one query + */ + getGlobalRanks: function (names, callback) { + if (typeof callback !== "function") { + return; + } + + if (!(names instanceof Array)) { + callback(new Error("Expected array of names, got " + typeof names), null); + return; + } + + var list = "(" + names.map(function () { return "?";}).join(",") + ")"; + + db.query("SELECT global_rank FROM `users` WHERE name IN " + list, names, + function (err, rows) { + if (err) { + callback(err, null); + } else if (rows.length === 0) { + callback(null, []); + } else { + callback(null, rows.map(function (x) { return x.global_rank; })); } + }); + }, - var list = "(" + names.map(function () { return "?";}).join(",") + ")"; + /** + * Lookup a user's email + */ + getEmail: function (name, callback) { + if (typeof callback !== "function") { + return; + } - db.query("SELECT global_rank FROM `users` WHERE name IN " + list, names, - function (err, rows) { - if (err) { - callback(err, null); - } else if (rows.length === 0) { - callback(null, []); - } else { - callback(null, rows.map(function (x) { return x.global_rank; })); + if (typeof name !== "string") { + callback(new Error("Invalid username"), null); + return; + } + + db.query("SELECT email FROM `users` WHERE name=?", [name], + function (err, rows) { + if (err) { + callback(err, null); + } else if (rows.length === 0) { + callback(new Error("User does not exist"), null); + } else { + callback(null, rows[0].email); + } + }); + }, + + /** + * Updates a user's email + */ + setEmail: function (name, email, callback) { + if (typeof callback !== "function") { + callback = blackHole; + } + + if (typeof name !== "string") { + callback(new Error("Invalid username"), null); + return; + } + + if (typeof email !== "string") { + callback(new Error("Invalid email"), null); + return; + } + + db.query("UPDATE `users` SET email=? WHERE name=?", [email, name], + function (err, result) { + callback(err, err ? null : true); + }); + }, + + /** + * Lookup a user's profile + */ + getProfile: function (name, callback) { + if (typeof callback !== "function") { + return; + } + + if (typeof name !== "string") { + callback(new Error("Invalid username"), null); + return; + } + + db.query("SELECT profile FROM `users` WHERE name=?", [name], + function (err, rows) { + if (err) { + callback(err, null); + } else if (rows.length === 0) { + callback(new Error("User does not exist"), null); + } else { + var userprof = { + image: "", + text: "" + }; + try { + var profile = JSON.parse(rows[0].profile); + userprof.image = profile.image || ""; + userprof.text = profile.text || ""; + callback(null, userprof); + } catch (e) { + callback(e, null); } - }); - }, - - /** - * Lookup a user's email - */ - getEmail: function (name, callback) { - if (typeof callback !== "function") { - return; } + }); + }, - if (typeof name !== "string") { - callback(new Error("Invalid username"), null); - return; - } + /** + * Updates a user's profile + */ + setProfile: function (name, profile, callback) { + if (typeof callback !== "function") { + callback = blackHole; + } - db.query("SELECT email FROM `users` WHERE name=?", [name], - function (err, rows) { - if (err) { - callback(err, null); - } else if (rows.length === 0) { - callback(new Error("User does not exist"), null); - } else { - callback(null, rows[0].email); - } - }); - }, + if (typeof name !== "string") { + callback(new Error("Invalid username"), null); + return; + } - /** - * Updates a user's email - */ - setEmail: function (name, email, callback) { - if (typeof callback !== "function") { - callback = blackHole; - } + if (typeof profile !== "object") { + callback(new Error("Invalid profile"), null); + return; + } - if (typeof name !== "string") { - callback(new Error("Invalid username"), null); - return; - } + // Cast to string to guarantee string type + profile.image += ""; + profile.text += ""; - if (typeof email !== "string") { - callback(new Error("Invalid email"), null); - return; - } + // Limit size + profile.image = profile.image.substring(0, 255); + profile.text = profile.text.substring(0, 255); - db.query("UPDATE `users` SET email=? WHERE name=?", [email, name], - function (err, result) { - callback(err, err ? null : true); - }); - }, + // Stringify the literal to guarantee I only get the keys I want + var profilejson = JSON.stringify({ + image: profile.image, + text: profile.text + }); - /** - * Lookup a user's profile - */ - getProfile: function (name, callback) { - if (typeof callback !== "function") { - return; - } + db.query("UPDATE `users` SET profile=? WHERE name=?", [profilejson, name], + function (err, result) { + callback(err, err ? null : true); + }); + }, - if (typeof name !== "string") { - callback(new Error("Invalid username"), null); - return; - } + generatePasswordReset: function (ip, name, email, callback) { + if (typeof callback !== "function") { + return; + } - db.query("SELECT profile FROM `users` WHERE name=?", [name], - function (err, rows) { - if (err) { - callback(err, null); - } else if (rows.length === 0) { - callback(new Error("User does not exist"), null); - } else { - var userprof = { - image: "", - text: "" - }; - try { - var profile = JSON.parse(rows[0].profile); - userprof.image = profile.image || ""; - userprof.text = profile.text || ""; - callback(null, userprof); - } catch (e) { - callback(e, null); - } - } - }); - }, + callback(new Error("generatePasswordReset is not implemented"), null); + }, - /** - * Updates a user's profile - */ - setProfile: function (name, profile, callback) { - if (typeof callback !== "function") { - callback = blackHole; - } + recoverPassword: function (hash, callback) { + if (typeof callback !== "function") { + return; + } - if (typeof name !== "string") { - callback(new Error("Invalid username"), null); - return; - } - - if (typeof profile !== "object") { - callback(new Error("Invalid profile"), null); - return; - } - - // Cast to string to guarantee string type - profile.image += ""; - profile.text += ""; - - // Limit size - profile.image = profile.image.substring(0, 255); - profile.text = profile.text.substring(0, 255); - - // Stringify the literal to guarantee I only get the keys I want - var profilejson = JSON.stringify({ - image: profile.image, - text: profile.text - }); - - db.query("UPDATE `users` SET profile=? WHERE name=?", [profilejson, name], - function (err, result) { - callback(err, err ? null : true); - }); - }, - - generatePasswordReset: function (ip, name, email, callback) { - if (typeof callback !== "function") { - return; - } - - callback(new Error("generatePasswordReset is not implemented"), null); - }, - - recoverPassword: function (hash, callback) { - if (typeof callback !== "function") { - return; - } - - callback(new Error("recoverPassword is not implemented"), null); - }, - }; + callback(new Error("recoverPassword is not implemented"), null); + }, }; diff --git a/lib/server.js b/lib/server.js index a51be906..bbca30da 100644 --- a/lib/server.js +++ b/lib/server.js @@ -67,13 +67,26 @@ var Server = function (cfg) { // database init ------------------------------------------------------ var Database = require("./database"); - self.db = new Database(self.cfg); + self.db = Database; + self.db.init(self.cfg); // webserver init ----------------------------------------------------- self.httplog = new Logger.Logger(path.join(__dirname, "../httpaccess.log")); self.express = express(); require("./web/webserver").init(self.express); + self.express.get("/old/:channel(*)", function (req, res, next) { + var c = req.params.channel; + if (!$util.isValidChannelName(c)) { + res.redirect("/" + c); + return; + } + + self.logHTTP(req); + res.sendfile("channel.html", { + root: path.join(__dirname, "../www") + }); + }); /* self.express.use(express.urlencoded()); self.express.use(express.json()); diff --git a/www/assets/js/ui.js b/www/assets/js/ui.js index 1226954e..6f341ffe 100644 --- a/www/assets/js/ui.js +++ b/www/assets/js/ui.js @@ -478,7 +478,7 @@ $(window).resize(function() { /* load channel */ var loc = document.location+""; -var m = loc.match(/\/r\/([a-zA-Z0-9-_]+)$/); +var m = loc.match(/\/old\/([a-zA-Z0-9-_]+)$/); if(m) { CHANNEL.name = m[1]; }