mirror of https://github.com/calzoneman/sync.git
Do a bit of intermediate database work
This commit is contained in:
parent
b889f7b4c8
commit
cfd1b0618d
371
lib/database.js
371
lib/database.js
File diff suppressed because it is too large
Load Diff
|
@ -1,498 +1,497 @@
|
||||||
//var db = require("../database");
|
//var db = require("../database");
|
||||||
var $util = require("../utilities");
|
var $util = require("../utilities");
|
||||||
var bcrypt = require("bcrypt");
|
var bcrypt = require("bcrypt");
|
||||||
|
var db = require("../database");
|
||||||
|
|
||||||
var registrationLock = {};
|
var registrationLock = {};
|
||||||
var blackHole = function () { };
|
var blackHole = function () { };
|
||||||
|
|
||||||
module.exports = function (db) {
|
module.exports = {
|
||||||
return {
|
/**
|
||||||
/**
|
* Initialize the accounts table
|
||||||
* Initialize the accounts table
|
*/
|
||||||
*/
|
init: function () {
|
||||||
init: function () {
|
db.query("CREATE TABLE IF NOT EXISTS `users` (" +
|
||||||
db.query("CREATE TABLE IF NOT EXISTS `users` (" +
|
"`id` INT NOT NULL AUTO_INCREMENT," +
|
||||||
"`id` INT NOT NULL AUTO_INCREMENT," +
|
"`name` VARCHAR(20) NOT NULL," +
|
||||||
"`name` VARCHAR(20) NOT NULL," +
|
"`password` VARCHAR(64) NOT NULL," +
|
||||||
"`password` VARCHAR(64) NOT NULL," +
|
"`global_rank` INT NOT NULL," +
|
||||||
"`global_rank` INT NOT NULL," +
|
"`email` VARCHAR(255) NOT NULL," +
|
||||||
"`email` VARCHAR(255) NOT NULL," +
|
"`profile` TEXT NOT NULL," +
|
||||||
"`profile` TEXT NOT NULL," +
|
"`ip` VARCHAR(39) NOT NULL," +
|
||||||
"`ip` VARCHAR(39) NOT NULL," +
|
"`time` BIGINT NOT NULL, " +
|
||||||
"`time` BIGINT NOT NULL, " +
|
"PRIMARY KEY(`id`), INDEX(`name`)) " +
|
||||||
"PRIMARY KEY(`id`), INDEX(`name`)) " +
|
"CHARACTER SET utf8");
|
||||||
"CHARACTER SET utf8");
|
},
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a username is taken
|
* Check if a username is taken
|
||||||
*/
|
*/
|
||||||
isUsernameTaken: function (name, callback) {
|
isUsernameTaken: function (name, callback) {
|
||||||
db.query("SELECT name FROM `users` WHERE name=?", [name],
|
db.query("SELECT name FROM `users` WHERE name=?", [name],
|
||||||
function (err, rows) {
|
function (err, rows) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err, true);
|
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);
|
|
||||||
return;
|
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),
|
* Search for a user by name
|
||||||
null);
|
*/
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$util.isValidUserName(name)) {
|
if (taken) {
|
||||||
callback(new Error("Invalid username. Usernames may consist of 1-20 " +
|
delete registrationLock[lname];
|
||||||
"characters a-z, A-Z, 0-9, -, _, and accented letters."),
|
callback(new Error("Username is already registered"), null);
|
||||||
null);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof email !== "string") {
|
bcrypt.hash(pw, 10, function (err, hash) {
|
||||||
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) {
|
if (err) {
|
||||||
delete registrationLock[lname];
|
delete registrationLock[lname];
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
return;
|
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];
|
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) {
|
if (err) {
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
} else if (!match) {
|
|
||||||
callback(new Error("Invalid username/password combination"), null);
|
|
||||||
} else {
|
} else {
|
||||||
callback(null, {
|
callback(null, {
|
||||||
name: rows[0].name,
|
name: name,
|
||||||
hash: rows[0].password,
|
hash: hash
|
||||||
global_rank: rows[0].global_rank
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify an auth string of the form name:hash
|
* Verify a username/password pair
|
||||||
*/
|
*/
|
||||||
verifyAuth: function (auth, callback) {
|
verifyLogin: function (name, pw, callback) {
|
||||||
if (typeof callback !== "function") {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof auth !== "string") {
|
if (rows.length === 0) {
|
||||||
callback(new Error("Invalid auth string"), null);
|
callback(new Error("User does not exist"), null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var split = auth.split(":");
|
bcrypt.compare(pw, rows[0].password, function (err, match) {
|
||||||
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) {
|
if (err) {
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
return;
|
} else if (!match) {
|
||||||
}
|
callback(new Error("Invalid username/password combination"), null);
|
||||||
|
|
||||||
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 {
|
} 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
|
* Verify an auth string of the form name:hash
|
||||||
*/
|
*/
|
||||||
setGlobalRank: function (name, rank, callback) {
|
verifyAuth: function (auth, callback) {
|
||||||
if (typeof callback !== "function") {
|
if (typeof callback !== "function") {
|
||||||
callback = blackHole;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof name !== "string") {
|
if (typeof auth !== "string") {
|
||||||
callback(new Error("Invalid username"), null);
|
callback(new Error("Invalid auth string"), null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof rank !== "number") {
|
if (rows.length === 0) {
|
||||||
callback(new Error("Invalid rank"), null);
|
callback(new Error("Auth string does not match an existing user"), null);
|
||||||
return;
|
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) {
|
function (err, result) {
|
||||||
callback(err, err ? null : true);
|
callback(err, err ? null : true);
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup multiple users' global rank in one query
|
* Lookup a user's global rank
|
||||||
*/
|
*/
|
||||||
getGlobalRanks: function (names, callback) {
|
getGlobalRank: function (name, callback) {
|
||||||
if (typeof callback !== "function") {
|
if (typeof callback !== "function") {
|
||||||
return;
|
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);
|
* Updates a user's global rank
|
||||||
return;
|
*/
|
||||||
|
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,
|
if (typeof name !== "string") {
|
||||||
function (err, rows) {
|
callback(new Error("Invalid username"), null);
|
||||||
if (err) {
|
return;
|
||||||
callback(err, null);
|
}
|
||||||
} else if (rows.length === 0) {
|
|
||||||
callback(null, []);
|
db.query("SELECT email FROM `users` WHERE name=?", [name],
|
||||||
} else {
|
function (err, rows) {
|
||||||
callback(null, rows.map(function (x) { return x.global_rank; }));
|
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);
|
* Updates a user's profile
|
||||||
return;
|
*/
|
||||||
}
|
setProfile: function (name, profile, callback) {
|
||||||
|
if (typeof callback !== "function") {
|
||||||
|
callback = blackHole;
|
||||||
|
}
|
||||||
|
|
||||||
db.query("SELECT email FROM `users` WHERE name=?", [name],
|
if (typeof name !== "string") {
|
||||||
function (err, rows) {
|
callback(new Error("Invalid username"), null);
|
||||||
if (err) {
|
return;
|
||||||
callback(err, null);
|
}
|
||||||
} else if (rows.length === 0) {
|
|
||||||
callback(new Error("User does not exist"), null);
|
|
||||||
} else {
|
|
||||||
callback(null, rows[0].email);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
if (typeof profile !== "object") {
|
||||||
* Updates a user's email
|
callback(new Error("Invalid profile"), null);
|
||||||
*/
|
return;
|
||||||
setEmail: function (name, email, callback) {
|
}
|
||||||
if (typeof callback !== "function") {
|
|
||||||
callback = blackHole;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof name !== "string") {
|
// Cast to string to guarantee string type
|
||||||
callback(new Error("Invalid username"), null);
|
profile.image += "";
|
||||||
return;
|
profile.text += "";
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof email !== "string") {
|
// Limit size
|
||||||
callback(new Error("Invalid email"), null);
|
profile.image = profile.image.substring(0, 255);
|
||||||
return;
|
profile.text = profile.text.substring(0, 255);
|
||||||
}
|
|
||||||
|
|
||||||
db.query("UPDATE `users` SET email=? WHERE name=?", [email, name],
|
// Stringify the literal to guarantee I only get the keys I want
|
||||||
function (err, result) {
|
var profilejson = JSON.stringify({
|
||||||
callback(err, err ? null : true);
|
image: profile.image,
|
||||||
});
|
text: profile.text
|
||||||
},
|
});
|
||||||
|
|
||||||
/**
|
db.query("UPDATE `users` SET profile=? WHERE name=?", [profilejson, name],
|
||||||
* Lookup a user's profile
|
function (err, result) {
|
||||||
*/
|
callback(err, err ? null : true);
|
||||||
getProfile: function (name, callback) {
|
});
|
||||||
if (typeof callback !== "function") {
|
},
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof name !== "string") {
|
generatePasswordReset: function (ip, name, email, callback) {
|
||||||
callback(new Error("Invalid username"), null);
|
if (typeof callback !== "function") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
db.query("SELECT profile FROM `users` WHERE name=?", [name],
|
callback(new Error("generatePasswordReset is not implemented"), null);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
recoverPassword: function (hash, callback) {
|
||||||
* Updates a user's profile
|
if (typeof callback !== "function") {
|
||||||
*/
|
return;
|
||||||
setProfile: function (name, profile, callback) {
|
}
|
||||||
if (typeof callback !== "function") {
|
|
||||||
callback = blackHole;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof name !== "string") {
|
callback(new Error("recoverPassword is not implemented"), null);
|
||||||
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);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -67,13 +67,26 @@ var Server = function (cfg) {
|
||||||
|
|
||||||
// database init ------------------------------------------------------
|
// database init ------------------------------------------------------
|
||||||
var Database = require("./database");
|
var Database = require("./database");
|
||||||
self.db = new Database(self.cfg);
|
self.db = Database;
|
||||||
|
self.db.init(self.cfg);
|
||||||
|
|
||||||
// webserver init -----------------------------------------------------
|
// webserver init -----------------------------------------------------
|
||||||
self.httplog = new Logger.Logger(path.join(__dirname,
|
self.httplog = new Logger.Logger(path.join(__dirname,
|
||||||
"../httpaccess.log"));
|
"../httpaccess.log"));
|
||||||
self.express = express();
|
self.express = express();
|
||||||
require("./web/webserver").init(self.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.urlencoded());
|
||||||
self.express.use(express.json());
|
self.express.use(express.json());
|
||||||
|
|
|
@ -478,7 +478,7 @@ $(window).resize(function() {
|
||||||
/* load channel */
|
/* load channel */
|
||||||
|
|
||||||
var loc = document.location+"";
|
var loc = document.location+"";
|
||||||
var m = loc.match(/\/r\/([a-zA-Z0-9-_]+)$/);
|
var m = loc.match(/\/old\/([a-zA-Z0-9-_]+)$/);
|
||||||
if(m) {
|
if(m) {
|
||||||
CHANNEL.name = m[1];
|
CHANNEL.name = m[1];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue