var mysql = require("mysql-libmysqlclient"); var Logger = require("./logger"); var Media = require("./media").Media; var db = false; var SERVER = ""; var USER = ""; var DATABASE = ""; var PASSWORD = ""; var CONFIG = {}; function setup(cfg) { SERVER = cfg.MYSQL_SERVER; USER = cfg.MYSQL_USER; DATABASE = cfg.MYSQL_DB; PASSWORD = cfg.MYSQL_PASSWORD; CONFIG = cfg; } function getConnection() { if(db && db.connectedSync()) { return db; } db = mysql.createConnectionSync(); db.connectSync(SERVER, USER, PASSWORD, DATABASE); if(!db.connectedSync()) { //Logger.errlog.log("DB connection failed"); return false; } if(CONFIG.DEBUG) { db._querySync = db.querySync; db.querySync = function(q) { Logger.syslog.log("DEBUG: " + q); return this._querySync(q); } } return db; } function createQuery(template, args) { var last = -1; while(template.indexOf("?", last) >= 0) { var idx = template.indexOf("?", last); var arg = args.shift(); if(typeof arg == "string") { arg = arg.replace(/([\'])/g, "\\$1"); if(idx == 0 || template[idx-1] != "`") { arg = "'" + arg + "'"; } } if(arg === null || arg === undefined) { arg = "NULL"; } var first = template.substring(0, idx); template = first + template.substring(idx).replace("?", arg); last = idx + (arg+"").length; } return template; } function init() { var db = getConnection(); if(!db) { return false; } // Create channel table var query = ["CREATE TABLE IF NOT EXISTS `channels` (", "`id` INT NOT NULL AUTO_INCREMENT,", "`name` VARCHAR(255) NOT NULL,", "PRIMARY KEY(`id`))", "ENGINE = MyISAM;"].join(""); var results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to create channels table"); } // Create registration table query = ["CREATE TABLE IF NOT EXISTS `registrations` (", "`id` INT NOT NULL AUTO_INCREMENT,", "`uname` VARCHAR(20) NOT NULL,", "`pw` VARCHAR(64) NOT NULL,", "`global_rank` INT NOT NULL,", "`session_hash` VARCHAR(64) NOT NULL,", "`expire` BIGINT NOT NULL,", "`profile_image` VARCHAR(255) NOT NULL,", "`profile_text` TEXT NOT NULL,", "PRIMARY KEY (`id`))", "ENGINE = MyISAM;"].join(""); results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to create registrations table"); } // Create global bans table query = ["CREATE TABLE IF NOT EXISTS `global_bans` (", "`ip` VARCHAR(15) NOT NULL,", "`note` VARCHAR(255) NOT NULL,", "PRIMARY KEY (`ip`))", "ENGINE = MyISAM;"].join(""); results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to create global ban table"); } refreshGlobalBans(); } /* REGION Global Bans */ function checkGlobalBan(ip) { const re = /(\d+)\.(\d+)\.(\d+)\.(\d+)/; var s16 = ip.replace(re, "$1.$2"); var s24 = ip.replace(re, "$1.$2.$3"); return (ip in global_bans || s16 in global_bans || s24 in global_bans); } function refreshGlobalBans() { var db = getConnection(); if(!db) { return; } var query = "SELECT * FROM `global_bans` WHERE 1"; var results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to load global bans"); } else { var rows = results.fetchAllSync(); global_bans = {}; for(var i = 0; i < rows.length; i++) { global_bans[rows[i].ip] = rows[i].note; } } } function globalBanIP(ip, reason) { var db = getConnection(); if(!db) { return; } var query = createQuery( "INSERT INTO `global_bans` VALUES (?, ?)", [ip, reason] ); return db.querySync(query); } function globalUnbanIP(ip) { var db = getConnection(); if(!db) { return; } var query = createQuery( "DELETE FROM `global_bans` WHERE ip=?", [ip] ); return db.querySync(query); } /* REGION Channel Registration/Loading */ function registerChannel(name) { var db = getConnection(); if(!db) { return false; } // Library table var query = ["CREATE TABLE `?` (", "`id` VARCHAR(255) NOT NULL,", "`title` VARCHAR(255) NOT NULL,", "`seconds` INT NOT NULL,", "`type` VARCHAR(2) NOT NULL,", "PRIMARY KEY (`id`))", "ENGINE = MyISAM;"].join(""); query = createQuery(query, ["chan_" + name + "_library"]); var results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to create table: chan_"+name+"_library"); return false; } // Rank table query = ["CREATE TABLE `?` (", "`name` VARCHAR(32) NOT NULL,", "`rank` INT NOT NULL,", "UNIQUE (`name`))", "ENGINE = MyISAM;"].join(""); query = createQuery(query, ["chan_" + name + "_ranks"]); results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to create table: chan_"+name+"_ranks"); return false; } // Ban table query = ["CREATE TABLE `?` (", "`ip` VARCHAR(15) NOT NULL,", "`name` VARCHAR(32) NOT NULL,", "`banner` VARCHAR(32) NOT NULL,", "PRIMARY KEY (`ip`))", "ENGINE = MyISAM;"].join(""); query = createQuery(query, ["chan_" + name + "_bans"]); results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to create table: chan_"+name+"_bans"); return false; } // Insert into channel table query = createQuery( "INSERT INTO `channels` VALUES (NULL, ?)", [name] ); results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to insert into channel table: " + name); return false; } return true; } function loadChannel(chan) { var db = getConnection(); if(!db) { return; } var query = createQuery( "SELECT * FROM `channels` WHERE name=?", [chan.name] ); var results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to query channel table"); } else { var rows = results.fetchAllSync(); if(rows.length == 0) { // Unregistered Logger.syslog.log("Channel " + chan.name + " is unregistered"); return; } // Database is case insensitive else if(rows[0].name != chan.name) { chan.name = rows[0].name; } chan.registered = true; } // Load channel library query = createQuery( "SELECT * FROM `?`", ["chan_" + chan.name + "_library"] ); results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to load channel library: " + chan.name); } else { var rows = results.fetchAllSync(); for(var i = 0; i < rows.length; i++) { var r = rows[i]; var m = new Media(r.id, r.title, r.seconds, r.type); chan.library[r.id] = m; } } // Load channel bans query = createQuery( "SELECT * FROM `?`", ["chan_" + chan.name + "_bans"] ); results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to load channel bans: " + chan.name); } else { var rows = results.fetchAllSync(); for(var i = 0; i < rows.length; i++) { var r = rows[i]; if(r.ip == "*") { chan.nameban[r.name] = r.banner; } else { chan.ipbans[r.ip] = [r.name, r.banner]; } } } chan.logger.log("*** Loaded channel from database"); Logger.syslog.log("Loaded channel " + chan.name + " from database"); } function deleteChannel(name) { if(!/[a-zA-Z0-9-_]+/.test(name)) { return false; } var db = getConnection(); if(!db) { return false; } var query = "DROP TABLE `chan_?_bans`, `chan_?_ranks`, `chan_?_library`" .replace(/\?/g, name); var results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to delete channel tables for " + name); return false; } query = createQuery( "DELETE FROM `channels` WHERE name=?", [name] ); results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to delete row from channel table: " + name); return false; } return true; } /* REGION Channel data */ function getChannelRank(chan, name) { var db = getConnection(); if(!db) { return 0; } var query; if(typeof name == "object") { var n = "(?"; for(var i = 1; i < name.length; i++) { n += ",?"; } n += ")" name.unshift("chan_" + chan + "_ranks"); query = createQuery( "SELECT * FROM `?` WHERE name IN " + n, name ); } else { query = createQuery( "SELECT * FROM `?` WHERE name=?", ["chan_"+chan+"_ranks", name] ); } var results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to lookup chan_"+chan+"_ranks"); return 0; } var rows = results.fetchAllSync(); if(typeof name == "object") { var ranks = []; for(var i = 0; i < rows.length; i++) { ranks.push(rows[i].rank); } while(ranks.length < rows.length) { ranks.push(0); } return ranks; } if(rows.length == 0) { return 0; } return rows[0].rank; } function setChannelRank(chan, name, rank) { var db = getConnection(); if(!db) { return false; } var query = createQuery( ["INSERT INTO `?` ", "(`name`, `rank`) ", "VALUES ", "(?, ?) ", "ON DUPLICATE KEY UPDATE ", "`rank`=?"].join(""), ["chan_"+chan+"_ranks", name, rank, rank] ); return db.querySync(query); } function listChannelRanks(chan) { var db = getConnection(); if(!db) { return []; } var query = createQuery( "SELECT * FROM `?` WHERE 1", ["chan_"+chan+"_ranks"] ); var results = db.querySync(query); if(!results) { Logger.errlog.log("! Failed to list ranks: " + chan); return []; } return results.fetchAllSync(); } function addToLibrary(chan, media) { var db = getConnection(); if(!db) { return false; } var query = createQuery( ["INSERT INTO `?` ", "(`id`, `title`, `seconds`, `type`) ", "VALUES ", "(?, ?, ?, ?)"].join(""), ["chan_"+chan+"_library", media.id, media.title, media.seconds, media.type] ); return db.querySync(query); } function removeFromLibrary(chan, id) { var db = getConnection(); if(!db) { return false; } var query = createQuery( "DELETE FROM `?` WHERE id=?", ["chan_"+chan+"_library", id] ); return db.querySync(query); } function channelBan(chan, ip, name, banby) { var db = getConnection(); if(!db) { return false; } var query = createQuery( ["INSERT INTO `?` ", "(`ip`, `name`, `banner`) ", "VALUES ", "(?, ?, ?)"].join(""), ["chan_"+chan+"_bans", ip, name, banby] ); return db.querySync(query); } function channelUnbanIP(chan, ip) { var db = getConnection(); if(!db) { return false; } var query = createQuery( "DELETE FROM `?` WHERE `ip`=?", ["chan_"+chan+"_bans", ip] ); return db.querySync(query); } function channelUnbanName(chan, name) { var db = getConnection(); if(!db) { return false; } var query = createQuery( "DELETE FROM `?` WHERE `ip`='*' AND `name`=?", ["chan_"+chan+"_bans", name] ); return db.querySync(query); } /* REGION Users */ function setProfile(name, data) { var db = getConnection(); if(!db) { return false; } var query = createQuery( ["UPDATE `registrations` SET ", "`profile_image`=?,", "`profile_text`=? ", "WHERE uname=?"].join(""), [data.image, data.text, name] ); return db.querySync(query); } exports.setup = setup; exports.getConnection = getConnection; exports.createQuery = createQuery; exports.init = init; exports.checkGlobalBan = checkGlobalBan; exports.refreshGlobalBans = refreshGlobalBans; exports.globalBanIP = globalBanIP; exports.globalUnbanIP = globalUnbanIP; exports.registerChannel = registerChannel; exports.loadChannel = loadChannel; exports.deleteChannel = deleteChannel; exports.getChannelRank = getChannelRank; exports.setChannelRank = setChannelRank; exports.listChannelRanks = listChannelRanks; exports.addToLibrary = addToLibrary; exports.removeFromLibrary = removeFromLibrary; exports.channelBan = channelBan; exports.channelUnbanIP = channelUnbanIP; exports.channelUnbanName = channelUnbanName; exports.setProfile = setProfile;