Continue working on acp

This commit is contained in:
calzoneman 2014-01-29 21:50:45 -06:00
parent 1272425205
commit ac89c87e29
6 changed files with 351 additions and 171 deletions

View File

@ -11,169 +11,140 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
var Logger = require("./logger");
var Server = require("./server");
var ActionLog = require("./actionlog");
var db = require("./database");
module.exports = {
init: function (user) {
function handleAnnounce(user, data) {
var sv = Server.getServer();
var db = sv.db;
ActionLog.record(user.ip, user.name, "acp-init");
user.socket.on("acp-announce", function(data) {
ActionLog.record(user.ip, user.name, "acp-announce", data);
sv.announcement = data;
sv.io.sockets.emit("announcement", data);
if (sv.cfg["enable-ssl"])
sv.ioSecure.sockets.emit("announcement", data);
});
user.socket.on("acp-announce-clear", function() {
ActionLog.record(user.ip, user.name, "acp-announce-clear");
sv.announcement = null;
});
user.socket.on("acp-global-ban", function(data) {
ActionLog.record(user.ip, user.name, "acp-global-ban", data.ip);
db.setGlobalIPBan(data.ip, data.note, function (err, res) {
db.listGlobalIPBans(function (err, res) {
res = res || [];
user.socket.emit("acp-global-banlist", res);
});
});
});
user.socket.on("acp-global-unban", function(ip) {
ActionLog.record(user.ip, user.name, "acp-global-unban", ip);
db.clearGlobalIPBan(ip, function (err, res) {
db.listGlobalIPBans(function (err, res) {
res = res || [];
user.socket.emit("acp-global-banlist", res);
});
});
});
db.listGlobalIPBans(function (err, res) {
res = res || [];
user.socket.emit("acp-global-banlist", res);
});
user.socket.on("acp-lookup-user", function(name) {
db.users.search(name, ["name", "email", "global_rank"], function (err, res) {
res = res || [];
user.socket.emit("acp-userdata", res);
});
});
user.socket.on("acp-lookup-channel", function (data) {
db.searchChannel(data.field, data.value, function (e, res) {
res = res || [];
user.socket.emit("acp-channeldata", res);
});
});
user.socket.on("acp-reset-password", function(data) {
db.users.getGlobalRank(data.name, function (err, rank) {
if(err || rank >= user.global_rank)
return;
db.genPasswordReset(user.ip, data.name, data.email,
function (err, hash) {
var pkt = {
success: !err
sv.announcement = {
title: data.title,
text: data.content,
from: user.name
};
if(err) {
pkt.error = err;
} else {
pkt.hash = hash;
}
user.socket.emit("acp-reset-password", pkt);
ActionLog.record(user.ip, user.name,
"acp-reset-password", data.name);
});
});
});
user.socket.on("acp-set-rank", function(data) {
if(data.rank < 1 || data.rank >= user.global_rank)
return;
db.users.getGlobalRank(data.name, function (err, rank) {
if(err || rank >= user.global_rank)
return;
db.users.setGlobalRank(data.name, data.rank,
function (err, res) {
ActionLog.record(user.ip, user.name, "acp-set-rank",
data);
if(!err)
user.socket.emit("acp-set-rank", data);
});
});
});
user.socket.on("acp-list-loaded", function() {
var chans = [];
var all = sv.channels;
for(var c in all) {
var chan = all[c];
chans.push({
name: chan.name,
title: chan.opts.pagetitle,
usercount: chan.users.length,
mediatitle: chan.playlist.current ? chan.playlist.current.media.title : "-",
is_public: chan.opts.show_public,
registered: chan.registered
});
}
user.socket.emit("acp-list-loaded", chans);
});
user.socket.on("acp-channel-unload", function(data) {
if(sv.isChannelLoaded(data.name)) {
var c = sv.getChannel(data.name);
if(!c)
return;
ActionLog.record(user.ip, user.name, "acp-channel-unload");
c.initialized = data.save;
// copy the list of users to prevent concurrent
// modification
var users = Array.prototype.slice.call(c.users);
users.forEach(function (u) {
c.kick(u, "Channel shutting down");
});
// At this point c should be unloaded
// if it's still loaded, kill it
if(sv.isChannelLoaded(data.name))
sv.unloadChannel(sv.getChannel(data.name));
}
});
user.socket.on("acp-actionlog-list", function () {
ActionLog.listActionTypes(function (err, types) {
if(!err)
user.socket.emit("acp-actionlog-list", types);
});
});
user.socket.on("acp-actionlog-clear", function(data) {
ActionLog.clear(data);
ActionLog.record(user.ip, user.name, "acp-actionlog-clear", data);
});
user.socket.on("acp-actionlog-clear-one", function(data) {
ActionLog.clearOne(data);
ActionLog.record(user.ip, user.name, "acp-actionlog-clear-one", data);
});
user.socket.on("acp-view-stats", function () {
db.listStats(function (err, res) {
if(!err)
user.socket.emit("acp-view-stats", res);
});
});
sv.io.sockets.emit("announcement", sv.announcement);
if (sv.ioSecure) {
sv.ioSecure.sockets.emit("announcement", sv.announcement);
}
}
function handleAnnounceClear(user) {
Server.getServer().announcement = null;
}
function handleGlobalBan(user, data) {
db.globalBanIP(data.ip, data.note, function (err, res) {
if (err) {
user.socket.emit("errMessage", {
msg: err
});
return;
}
db.listGlobalBans(function (err, bans) {
if (err) {
user.socket.emit("errMessage", {
msg: err
});
return;
}
var flat = [];
for (var ip in bans) {
flat.push({
ip: ip,
note: bans[ip].reason
});
}
user.socket.emit("acp-gbanlist", flat);
});
});
}
function handleGlobalBanDelete(user, data) {
db.globalUnbanIP(data.ip, function (err, res) {
if (err) {
user.socket.emit("errMessage", {
msg: err
});
return;
}
db.listGlobalBans(function (err, bans) {
if (err) {
user.socket.emit("errMessage", {
msg: err
});
return;
}
var flat = [];
for (var ip in bans) {
flat.push({
ip: ip,
note: bans[ip].reason
});
}
user.socket.emit("acp-gbanlist", flat);
});
});
}
function handleListUsers(user, data) {
var name = data.name;
if (typeof name !== "string") {
name = "";
}
var fields = ["id", "name", "global_rank", "email", "ip", "time"];
db.users.search(name, fields, function (err, users) {
if (err) {
user.socket.emit("errMessage", {
msg: err
});
return;
}
user.socket.emit("acp-list-users", users);
});
}
function handleSetRank(user, data) {
}
function handleResetPassword(user, data) {
}
function init(user) {
var s = user.socket;
s.on("acp-announce", handleAnnounce.bind(this, user));
s.on("acp-announce-clear", handleAnnounceClear.bind(this, user));
s.on("acp-gban", handleGlobalBan.bind(this, user));
s.on("acp-gban-delete", handleGlobalBanDelete.bind(this, user));
s.on("acp-list-users", handleListUsers.bind(this, user));
s.on("acp-set-rank", handleSetRank.bind(this, user));
s.on("acp-reset-password", handleResetPassword(this, user));
db.listGlobalBans(function (err, bans) {
if (err) {
user.socket.emit("errMessage", {
msg: err
});
return;
}
var flat = [];
for (var ip in bans) {
flat.push({
ip: ip,
note: bans[ip].reason
});
}
user.socket.emit("acp-gbanlist", flat);
});
Logger.eventlog.log("[acp] Initialized ACP for " + user.name + "@" + user.ip);
}
module.exports.init = init;

View File

@ -5,6 +5,7 @@ var MakeEmitter = require("./emitter");
var db = require("./database");
var InfoGetter = require("./get-info");
var Config = require("./config");
var ACP = require("./acp");
function User(socket) {
var self = this;
@ -36,6 +37,19 @@ function User(socket) {
self.initChannelCallbacks();
});
self.socket.once("initACP", function () {
self.whenLoggedIn(function () {
if (self.global_rank >= 255) {
ACP.init(self);
} else {
self.kick("Attempted initACP from non privileged user. This incident " +
"will be reported.");
Logger.eventlog.log("[acp] Attempted initACP from socket client " +
self.name + "@" + self.ip);
}
});
});
self.socket.on("login", function (data) {
data = (typeof data === "object") ? data : {};

View File

@ -4,6 +4,7 @@ var webserver = require("./webserver");
var sendJade = require("./jade").sendJade;
var Logger = require("../logger");
var db = require("../database");
var Config = require("../config");
function checkAdmin(cb) {
return function (req, res) {
@ -40,9 +41,18 @@ function checkAdmin(cb) {
* Handles a request for the ACP
*/
function handleAcp(req, res, user) {
var sio;
if (req.secure) {
sio = Config.get("https.domain") + ":" + Config.get("https.port");
} else {
sio = Config.get("http.domain") + ":" + Config.get("io.port");
}
sio += "/socket.io/socket.io.js";
sendJade(res, "acp", {
loginName: user.name,
loggedIn: true
loggedIn: true,
sioSource: sio
});
}

View File

@ -116,13 +116,19 @@ function handleChannel(req, res) {
loginName = req.cookies.auth.split(":")[0];
}
var iourl = "";
var sio;
if (req.secure) {
sio = Config.get("https.domain") + ":" + Config.get("https.port");
} else {
sio = Config.get("http.domain") + ":" + Config.get("io.port");
}
sio += "/socket.io/socket.io.js";
sendJade(res, "channel", {
channelName: req.params.channel,
loggedIn: loginName !== false,
loginName: loginName,
sioSource: Config.get("http.domain") + ":" + Config.get("io.port") +
"/socket.io/socket.io.js"
sioSource: sio
});
}

View File

@ -32,7 +32,7 @@ html(lang="en")
#acp-announcements.col-md-12(style="display: none")
h3 Announcements
h3 New Announcement
.col-md-6
div(style="max-width: 50%")
form.form-horizontal(action="javascript:void(0)", role="form")
.form-group
label.control-label.col-sm-2(for="acp-announce-title") Title
@ -54,7 +54,7 @@ html(lang="en")
th IP Address
th Note
h3 New Global Ban
.col-md-6
div(style="max-width: 50%")
form.form-horizontal(action="javascript:void(0)", role="form")
.form-group
label.control-label.col-sm-3(for="acp-gban-ip") IP Address
@ -76,10 +76,11 @@ html(lang="en")
table.table.table-bordered.table-striped(style="margin-top: 20px")
thead
tr
th#acp-ulookup-id ID
th#acp-ulookup-name Name
th#acp-ulookup-rank Rank
th#acp-ulookup-email Email
th#acp-users-id ID
th#acp-users-name Name
th#acp-users-rank Rank
th#acp-users-email Email
th Actions
#acp-channel-lookup.col-md-12(style="display: none")
h3 Channels
form.form-inline(action="javascript:void(0)", role="form")
@ -123,4 +124,10 @@ html(lang="en")
include footer
mixin footer()
script(type="text/javascript").
var USEROPTS = { secure_connection: true };
script(src=sioSource)
script(src="/sioconfig")
script(src="/assets/js/util.js")
script(src="/assets/js/paginator.js")
script(src="/js/acp.js")

View File

@ -1,3 +1,18 @@
(function () {
var opts = {};
if (location.protocol === "https:") {
opts.secure = true;
}
window.socket = io.connect(IO_URL, opts);
window.socket.on("connect", function () {
window.socket.emit("initACP");
});
window.socket.on("errMessage", function (data) {
alert(data.msg);
});
})();
function addMenuItem(target, text) {
var ul = $("#nav-acp-section ul");
var li = $("<li/>").appendTo(ul);
@ -19,6 +34,7 @@ addMenuItem("#acp-loaded-channels", "Active Channels");
addMenuItem("#acp-eventlog", "Event Log");
addMenuItem("#acp-stats", "Stats");
/* Log Viewer */
function readSyslog() {
$.ajax(location.protocol + "//" + location.host + "/acp/syslog").done(function (data) {
$("#acp-log").text(data);
@ -55,3 +71,159 @@ $("#acp-chanlog-name").keyup(function (ev) {
readChanlog($("#acp-chanlog-name").val());
}
});
/* Announcements */
$("#acp-announce-submit").click(function () {
socket.emit("acp-announce", {
title: $("#acp-announce-title").val(),
content: $("#acp-announce-content").val()
});
});
socket.on("announcement", function (data) {
$("#acp-announcements").find(".announcement").remove();
var al = makeAlert(data.title, data.text)
.removeClass("col-md-12")
.addClass("announcement")
.insertAfter($("#acp-announcements h3")[0]);
al.find(".close").click(function () {
socket.emit("acp-announce-clear");
});
$("#acp-announce-title").val(data.title);
$("#acp-announce-content").val(data.text);
});
/* Global bans */
$("#acp-gban-submit").click(function () {
socket.emit("acp-gban", {
ip: $("#acp-gban-ip").val(),
note: $("#acp-gban-note").val()
});
});
socket.on("acp-gbanlist", function (bans) {
var tbl = $("#acp-global-bans table");
tbl.find("tbody").remove();
bans.forEach(function (b) {
var tr = $("<tr/>").appendTo(tbl);
var td = $("<td/>").appendTo(tr);
var del = $("<button/>").addClass("btn btn-xs btn-danger")
.html("<span class='glyphicon glyphicon-trash'></span>")
.click(function () {
socket.emit("acp-gban-delete", b);
})
.appendTo(td);
td = $("<td/>").appendTo(tr).html("<code>" + b.ip + "</code>");
td = $("<td/>").appendTo(tr).text(b.note);
});
});
/* User listing */
(function () {
var doSearch = function () {
if ($("#acp-ulookup-name").val().trim() === "") {
if (!confirm("You are about to list the entire users table. " +
"This table might be very large and take a long " +
"time to query. Continue?")) {
return;
}
}
socket.emit("acp-list-users", {
name: $("#acp-ulookup-name").val()
});
};
$("#acp-ulookup-btn").click(doSearch);
$("#acp-ulookup-name").keyup(function (ev) {
if (ev.keyCode === 13) {
doSearch();
}
});
})();
socket.on("acp-list-users", function (users) {
var tbl = $("#acp-user-lookup table");
tbl.data("entries", users);
var p = tbl.data("paginator");
if (p) {
p.paginator.remove();
}
var opts = {
preLoadPage: function () {
tbl.find("tbody").remove();
},
generator: function (u, page, index) {
var tr = $("<tr/>").appendTo(tbl);
tr.attr("title", u.name + " joined on " + new Date(u.time) + " from " + u.ip);
$("<td/>").text(u.id).appendTo(tr);
$("<td/>").text(u.name).appendTo(tr);
var rank = $("<td/>").text(u.global_rank).appendTo(tr);
$("<td/>").text(u.email).appendTo(tr);
var reset = $("<td/>").appendTo(tr);
// Rank editor
rank.click(function () {
if (rank.find(".rank-edit").length > 0) {
return;
}
var old = rank.text();
rank.text("");
var editor = $("<input/>").addClass("rank-edit form-control")
.attr("type", "text")
.attr("placeholder", old)
.appendTo(rank)
.focus();
var save = function () {
var newrank = editor.val();
if (newrank.trim() === "") {
newrank = old;
}
rank.text(old);
if (newrank === old) {
return;
}
socket.emit("acp-set-rank", {
name: u.uname,
rank: parseInt(newrank)
});
};
editor.blur(save);
editor.keydown(function (ev) {
if (ev.keyCode === 13) {
save();
}
});
});
// Password reset
$("<button/>").addClass("btn btn-xs btn-danger")
.text("Reset password")
.click(function () {
if (!confirm("Really reset password for " + u.name + "?")) {
return;
}
socket.emit("acp-reset-password", {
name: u.uname,
email: u.email
});
}).appendTo(reset);
}
};
p = Paginate(users, opts);
p.paginator.insertBefore(tbl);
tbl.data("paginator", p);
});