mirror of https://github.com/calzoneman/sync.git
Continue working on acp
This commit is contained in:
parent
1272425205
commit
ac89c87e29
289
lib/acp.js
289
lib/acp.js
|
@ -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;
|
||||
|
|
14
lib/user.js
14
lib/user.js
|
@ -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 : {};
|
||||
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
172
www/js/acp.js
172
www/js/acp.js
|
@ -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);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue