Work on ACP
This commit is contained in:
parent
d0be588149
commit
1272425205
112
lib/web/acp.js
Normal file
112
lib/web/acp.js
Normal file
|
@ -0,0 +1,112 @@
|
|||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var webserver = require("./webserver");
|
||||
var sendJade = require("./jade").sendJade;
|
||||
var Logger = require("../logger");
|
||||
var db = require("../database");
|
||||
|
||||
function checkAdmin(cb) {
|
||||
return function (req, res) {
|
||||
webserver.logRequest(req);
|
||||
var auth = req.cookies.auth;
|
||||
if (!auth) {
|
||||
res.send(403);
|
||||
return;
|
||||
}
|
||||
db.users.verifyAuth(auth, function (err, user) {
|
||||
if (err) {
|
||||
if (err === "Invalid auth string" ||
|
||||
err === "Auth string does not match an existing user") {
|
||||
res.send(403);
|
||||
} else {
|
||||
res.send(500);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.global_rank < 255) {
|
||||
res.send(403);
|
||||
Logger.eventlog.log("[acp] Attempted GET /acp from non-admin " +
|
||||
user.name + "@" + webserver.ipForRequest(req));
|
||||
return;
|
||||
}
|
||||
|
||||
cb(req, res, user);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a request for the ACP
|
||||
*/
|
||||
function handleAcp(req, res, user) {
|
||||
sendJade(res, "acp", {
|
||||
loginName: user.name,
|
||||
loggedIn: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams the last length bytes of file to the given HTTP response
|
||||
*/
|
||||
function readLog(res, file, length) {
|
||||
fs.stat(file, function (err, data) {
|
||||
if (err) {
|
||||
res.send(500);
|
||||
return;
|
||||
}
|
||||
|
||||
var start = Math.max(0, data.size - length);
|
||||
if (isNaN(start)) {
|
||||
res.send(500);
|
||||
}
|
||||
var end = Math.max(0, data.size - 1);
|
||||
if (isNaN(end)) {
|
||||
res.send(500);
|
||||
}
|
||||
fs.createReadStream(file, { start: start, end: end })
|
||||
.pipe(res);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a request to read the syslog
|
||||
*/
|
||||
function handleReadSyslog(req, res) {
|
||||
readLog(res, path.join(__dirname, "..", "..", "sys.log"), 1048576);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a request to read the error log
|
||||
*/
|
||||
function handleReadErrlog(req, res) {
|
||||
readLog(res, path.join(__dirname, "..", "..", "error.log"), 1048576);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a request to read the http log
|
||||
*/
|
||||
function handleReadHttplog(req, res) {
|
||||
readLog(res, path.join(__dirname, "..", "..", "http.log"), 1048576);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a request to read a channel log
|
||||
*/
|
||||
function handleReadChanlog(req, res) {
|
||||
if (!req.params.name.match(/^[\w-]{1,30}$/)) {
|
||||
res.send(400);
|
||||
return;
|
||||
}
|
||||
readLog(res, path.join(__dirname, "..", "..", "chanlogs", req.params.name + ".log"), 1048576);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: function (app) {
|
||||
app.get("/acp", checkAdmin(handleAcp));
|
||||
app.get("/acp/syslog", checkAdmin(handleReadSyslog));
|
||||
app.get("/acp/errlog", checkAdmin(handleReadErrlog));
|
||||
app.get("/acp/httplog", checkAdmin(handleReadHttplog));
|
||||
app.get("/acp/chanlog/:name", checkAdmin(handleReadChanlog));
|
||||
}
|
||||
};
|
|
@ -153,38 +153,6 @@ function handleIndex(req, res) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a request for the ACP
|
||||
*/
|
||||
function handleAcp(req, res) {
|
||||
logRequest(req);
|
||||
|
||||
var auth = req.cookies.auth || "";
|
||||
db.users.verifyAuth(auth, function (err, user) {
|
||||
if (err) {
|
||||
if (err === "Invalid auth string" ||
|
||||
err === "Auth string does not match an existing user") {
|
||||
res.send(403);
|
||||
} else {
|
||||
res.send(500);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.global_rank < 255) {
|
||||
res.send(403);
|
||||
Logger.eventlog.log("[acp] Attempted GET /acp from non-admin " + user.name +
|
||||
"@" + ipForRequest(req));
|
||||
return;
|
||||
}
|
||||
|
||||
sendJade(res, "acp", {
|
||||
loginName: user.name,
|
||||
loggedIn: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a request for the socket.io information
|
||||
*/
|
||||
|
@ -200,8 +168,7 @@ function handleSocketConfig(req, res) {
|
|||
"',ALLOW_SSL="+Config.get("https.enabled")+";" +
|
||||
(Config.get("https.enabled") ?
|
||||
"if(location.protocol=='https:'||USEROPTS.secure_connection){" +
|
||||
"IO_URL=WEB_URL=SSL_URL;}" : ""));
|
||||
}
|
||||
"IO_URL=WEB_URL=SSL_URL;}" : "")); }
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
|
@ -220,9 +187,12 @@ module.exports = {
|
|||
app.get("/r/:channel", handleChannel);
|
||||
app.get("/", handleIndex);
|
||||
app.get("/sioconfig", handleSocketConfig);
|
||||
app.get("/acp", handleAcp);
|
||||
require("./auth").init(app);
|
||||
require("./account").init(app);
|
||||
require("./acp").init(app);
|
||||
app.all("*", function (req, res, next) {
|
||||
if (isSuspicious(req)) {
|
||||
console.log("isSuspicious");
|
||||
logRequest(req, 403);
|
||||
res.status(403);
|
||||
if (req.header("user-agent").toLowerCase() === "zmeu") {
|
||||
|
@ -238,8 +208,6 @@ module.exports = {
|
|||
next();
|
||||
});
|
||||
app.use(express.static("www"));
|
||||
require("./auth").init(app);
|
||||
require("./account").init(app);
|
||||
},
|
||||
|
||||
logRequest: logRequest,
|
||||
|
|
|
@ -12,6 +12,10 @@ html(lang="en")
|
|||
#nav-collapsible.collapse.navbar-collapse
|
||||
ul.nav.navbar-nav
|
||||
mixin navdefaultlinks("/acp")
|
||||
li#nav-acp-section.dropdown
|
||||
a#nav-acp-dd-toggle.dropdown-toggle(data-toggle="dropdown", href="javascript:void(0)") Menu
|
||||
span.caret
|
||||
ul.dropdown-menu
|
||||
mixin navloginlogout("/acp")
|
||||
section#mainpage
|
||||
.container
|
||||
|
@ -22,6 +26,7 @@ html(lang="en")
|
|||
div.input-group-btn
|
||||
button#acp-syslog-btn.btn.btn-default Syslog
|
||||
button#acp-errlog-btn.btn.btn-default Error log
|
||||
button#acp-httplog-btn.btn.btn-default HTTP log
|
||||
input#acp-chanlog-name.form-control(type="text", placeholder="Channel name")
|
||||
pre#acp-log
|
||||
#acp-announcements.col-md-12(style="display: none")
|
||||
|
@ -40,7 +45,7 @@ html(lang="en")
|
|||
.form-group
|
||||
.col-sm-10.col-sm-offset-2
|
||||
button#acp-announce-submit.btn.btn-primary Announce
|
||||
#acp-global-bans.col-md-12
|
||||
#acp-global-bans.col-md-12(style="display: none")
|
||||
h3 Global Bans
|
||||
table.table.table-striped.table-bordered
|
||||
thead
|
||||
|
@ -62,5 +67,60 @@ html(lang="en")
|
|||
.form-group
|
||||
.col-sm-9.col-sm-offset-3
|
||||
button#acp-gban-submit.btn.btn-danger Add ban
|
||||
#acp-user-lookup.col-md-12(style="display: none")
|
||||
h3 Users
|
||||
.input-group(style="max-width: 25%")
|
||||
input#acp-ulookup-name.form-control(type="text")
|
||||
span.input-group-btn
|
||||
button#acp-ulookup-btn.btn.btn-default Search
|
||||
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
|
||||
#acp-channel-lookup.col-md-12(style="display: none")
|
||||
h3 Channels
|
||||
form.form-inline(action="javascript:void(0)", role="form")
|
||||
.form-group
|
||||
input#acp-clookup-value.form-control(type="text", placeholder="Name")
|
||||
.form-group
|
||||
select#acp-clookup-field.form-control
|
||||
option(value="name") Channel Name
|
||||
option(value="owner") Channel Owner
|
||||
button#acp-clookup-submit.btn.btn-default Search
|
||||
table.table.table-bordered.table-striped(style="margin-top: 20px")
|
||||
thead
|
||||
tr
|
||||
th ID
|
||||
th Name
|
||||
th Owner
|
||||
#acp-loaded-channels.col-md-12(style="display: none")
|
||||
h3 Loaded Channels
|
||||
button#acp-lchannels-refresh.btn.btn-default Refresh
|
||||
table.table.table-bordered.table-striped(style="margin-top: 20px")
|
||||
thead
|
||||
tr
|
||||
th Title
|
||||
th Usercount
|
||||
th Now Playing
|
||||
th Registered
|
||||
th Public
|
||||
th Force Unload
|
||||
#acp-eventlog.col-md-12(style="display: none")
|
||||
h3 Event Log
|
||||
strong Filter event types
|
||||
select#acp-eventlog-filter.form-control(multiple="multiple", style="max-width: 25%")
|
||||
pre#acp-eventlog-text(style="margin-top: 20px")
|
||||
#acp-stats.col-md-12(style="display: none")
|
||||
h3 User Count
|
||||
canvas#stat_users(width="100%", height="400")
|
||||
h3 Channel Count
|
||||
canvas#stat_channels(width="100%", height="400")
|
||||
h3 Memory Usage
|
||||
canvas#stat_mem(width="100%", height="400")
|
||||
|
||||
include footer
|
||||
mixin footer()
|
||||
script(src="/js/acp.js")
|
||||
|
|
|
@ -7,4 +7,7 @@
|
|||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-top: none;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
|
57
www/js/acp.js
Normal file
57
www/js/acp.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
function addMenuItem(target, text) {
|
||||
var ul = $("#nav-acp-section ul");
|
||||
var li = $("<li/>").appendTo(ul);
|
||||
var a = $("<a/>").attr("href", "javascript:void(0)")
|
||||
.text(text)
|
||||
.appendTo(li)
|
||||
.click(function () {
|
||||
$(".col-md-12").hide();
|
||||
$(target).show();
|
||||
});
|
||||
};
|
||||
|
||||
addMenuItem("#acp-logview", "Log Viewer");
|
||||
addMenuItem("#acp-announcements", "Announcements");
|
||||
addMenuItem("#acp-global-bans", "Global Bans");
|
||||
addMenuItem("#acp-user-lookup", "Users");
|
||||
addMenuItem("#acp-channel-lookup", "Channels");
|
||||
addMenuItem("#acp-loaded-channels", "Active Channels");
|
||||
addMenuItem("#acp-eventlog", "Event Log");
|
||||
addMenuItem("#acp-stats", "Stats");
|
||||
|
||||
function readSyslog() {
|
||||
$.ajax(location.protocol + "//" + location.host + "/acp/syslog").done(function (data) {
|
||||
$("#acp-log").text(data);
|
||||
$("#acp-log").scrollTop($("#acp-log").prop("scrollHeight"));
|
||||
});
|
||||
}
|
||||
|
||||
function readErrlog() {
|
||||
$.ajax(location.protocol + "//" + location.host + "/acp/errlog").done(function (data) {
|
||||
$("#acp-log").text(data);
|
||||
$("#acp-log").scrollTop($("#acp-log").prop("scrollHeight"));
|
||||
});
|
||||
}
|
||||
|
||||
function readHttplog() {
|
||||
$.ajax(location.protocol + "//" + location.host + "/acp/httplog").done(function (data) {
|
||||
$("#acp-log").text(data);
|
||||
$("#acp-log").scrollTop($("#acp-log").prop("scrollHeight"));
|
||||
});
|
||||
}
|
||||
|
||||
function readChanlog(name) {
|
||||
$.ajax(location.protocol + "//" + location.host + "/acp/chanlog/" + name).done(function (data) {
|
||||
$("#acp-log").text(data);
|
||||
$("#acp-log").scrollTop($("#acp-log").prop("scrollHeight"));
|
||||
});
|
||||
}
|
||||
|
||||
$("#acp-syslog-btn").click(readSyslog);
|
||||
$("#acp-errlog-btn").click(readErrlog);
|
||||
$("#acp-httplog-btn").click(readHttplog);
|
||||
$("#acp-chanlog-name").keyup(function (ev) {
|
||||
if (ev.keyCode === 13) {
|
||||
readChanlog($("#acp-chanlog-name").val());
|
||||
}
|
||||
});
|
Loading…
Reference in a new issue