From 68922365d52e09bf5a1d4cef1c238665d33570da Mon Sep 17 00:00:00 2001 From: Mattias Erming Date: Sat, 16 Aug 2014 09:15:17 -0700 Subject: [PATCH] Check permissions for cli commands --- client/js/chat.js | 1020 ++++++++++++++++++++++----------------------- index.js | 37 +- package.json | 2 +- 3 files changed, 544 insertions(+), 515 deletions(-) diff --git a/client/js/chat.js b/client/js/chat.js index 098f3e0..58556a1 100644 --- a/client/js/chat.js +++ b/client/js/chat.js @@ -1,510 +1,510 @@ -$(function() { - var socket = io(); - var commands = [ - "/close", - "/connect", - "/deop", - "/devoice", - "/disconnect", - "/invite", - "/join", - "/kick", - "/leave", - "/mode", - "/msg", - "/nick", - "/notice", - "/op", - "/part", - "/query", - "/quit", - "/raw", - "/say", - "/send", - "/server", - "/slap", - "/topic", - "/voice", - "/whois" - ]; - - var sidebar = $("#sidebar"); - var chat = $("#chat"); - - var pop = new Audio(); - pop.src = "/audio/pop.ogg"; - - $("#play").on("click", function() { pop.play(); }); - $("#footer .icon").tooltip(); - - var favico = new Favico({ - animation: "none" - }); - - var tpl = []; - function render(name, data) { - tpl[name] = tpl[name] || Handlebars.compile($("#templates ." + name).html()); - return tpl[name](data); - } - - Handlebars.registerHelper( - "partial", function(id) { - return new Handlebars.SafeString(render(id, this)); - } - ); - - socket.on("error", function(e) { - console.log(e); - }); - - socket.on("auth", function(data) { - var body = $("body"); - var login = $("#sign-in"); - if (body.hasClass("signed-out")) { - var error = login.find(".error"); - error.show().closest("form").one("submit", function() { - error.hide(); - }); - } - body.addClass("signed-out"); - login.find("input[name='user']").val($.cookie("user") || ""); - sidebar.find(".sign-in") - .click() - .end() - .find(".networks") - .html("") - .next() - .show(); - }); - - socket.on("init", function(data) { - if (data.networks.length === 0) { - $("#footer").find(".connect").trigger("click"); - return; - } - - sidebar.find(".networks").html( - render("networks", { - networks: data.networks - }) - ); - - var channels = $.map(data.networks, function(n) { - return n.channels; - }); - chat.html( - render("chat", { - channels: channels - }) - ); - - sidebar.find(".empty").hide(); - $("body").removeClass("signed-out"); - - var id = $.cookie("target"); - var target = sidebar.find("[data-target='" + id + "']").trigger("click"); - if (target.length === 0) { - var first = sidebar.find(".chan") - .eq(0) - .trigger("click"); - if (first.length === 0) { - $("#footer").find(".connect").trigger("click"); - } - } - }); - - socket.on("join", function(data) { - var id = data.network; - var network = sidebar.find("#network-" + id); - network.append( - render("channels", { - channels: [data.chan] - }) - ); - chat.append( - render("chat", { - channels: [data.chan] - }) - ); - sidebar.find(".chan") - .last() - .trigger("click"); - }); - - socket.on("msg", function(data) { - var target = data.chan; - if (data.msg.type == "error") { - target = chat.find(".active").data("id"); - } - target = "#chan-" + target; - chat.find(target) - .find(".messages") - .append(render("messages", {messages: [data.msg]})) - .trigger("msg", [ - target, - data.msg - ]); - }); - - socket.on("showMore", function(data) { - var target = data.chan; - chat.find("#chan-" + target) - .find(".show-more") - .remove() - .end() - .find(".messages") - .prepend(render("messages", {messages: data.messages})) - .end(); - }); - - socket.on("network", function(data) { - sidebar.find(".empty").hide(); - sidebar.find(".networks").append( - render("networks", { - networks: [data.network] - }) - ); - chat.append( - render("chat", { - channels: data.network.channels - }) - ); - sidebar.find(".chan") - .last() - .trigger("click"); - $("#connect") - .find(".btn") - .prop("disabled", false) - .end() - .find("input") - .each(function() { - var self = $(this); - self.val(self.data("default")); - }); - }); - - socket.on("nick", function(data) { - console.log(data); - }); - - socket.on("part", function(data) { - var id = data.chan; - sidebar.find("[data-target=#chan-" + id + "]") - .remove() - .end() - .find(".chan") - .eq(0) - .trigger("click"); - }); - - socket.on("quit", function(data) { - var id = data.network; - sidebar.find("#network-" + id) - .remove() - .end(); - var chan = sidebar.find(".chan") - .eq(0) - .trigger("click"); - if (chan.length === 0) { - sidebar.find(".empty").show(); - } - }); - - socket.on("users", function(data) { - chat.find("#chan-" + data.chan) - .find(".users") - .html(render("users", data)); - }); - - $("#connect") - .find("input") - .each(function() { - var self = $(this); - self.data("default", self.val()); - }); - - $.cookie.json = true; - - var settings = $("#settings"); - var options = $.extend({notification: true}, $.cookie("settings")); - - for (var i in options) { - if (options[i]) { - settings.find("input[name=" + i + "]").prop("checked", true); - } - } - - settings.on("change", "input", function() { - var self = $(this); - options[self.attr("name")] = self.prop("checked"); - $.cookie("settings", options); - }).find("input") - .eq(0) - .trigger("change"); - - var viewport = $("#viewport"); - - viewport.on("click", ".lt, .rt", function(e) { - var self = $(this); - viewport.toggleClass(self.attr("class")); - if (viewport.is(".lt, .rt")) { - e.stopPropagation(); - chat.find(".chat").one("click", function() { - viewport.removeClass("lt rt"); - }); - } - }); - - var input = $("#input") - .history() - .tab(complete, {hint: false}); - - var form = $("#form").on("submit", function(e) { - e.preventDefault(); - var text = input.val(); - input.val(""); - socket.emit("input", { - target: chat.data("id"), - text: text - }); - }); - - var top = 1; - sidebar.on("click", "button", function() { - var self = $(this); - var target = self.data("target"); - if (!target) { - return; - } - - if (self.hasClass("chan")) { - $.cookie("target", target); - } - chat.data( - "id", - self.data("id") - ); - - sidebar.find(".active").removeClass("active"); - self.addClass("active") - .find(".badge") - .removeClass("highlight") - .empty(); - - if (sidebar.find(".highlight").length == 0) { - favico.badge(""); - } - - viewport.removeClass(); - - $("#windows .active").removeClass("active"); - var chan = $(target) - .addClass("active") - .trigger("show") - .css("z-index", top++) - .find(".chat") - .sticky() - .end(); - - if (chan.hasClass("chan")) { - input.focus(); - } - }); - - sidebar.on("click", "#sign-out", function() { - location.reload(); - }); - - sidebar.on("click", ".close", function() { - var cmd = "/close"; - var chan = $(this).closest(".chan"); - if (chan.hasClass("lobby")) { - cmd = "/quit"; - var server = chan - .clone() - .remove("span") - .text() - .trim(); - if (!confirm("Disconnect from " + server + "?")) { - return false; - } - } - socket.emit("input", { - target: chan.data("id"), - text: cmd - }); - chan.css({ - transition: "none", - opacity: .4 - }); - return false; - }); - - chat.on("input", ".search", function() { - var value = $(this).val(); - var names = $(this).closest(".users").find(".names"); - names.find("button").each(function() { - var btn = $(this); - var name = btn.text().toLowerCase().replace(/[+%@~]/, ""); - if (name.indexOf(value) === 0) { - btn.show(); - } else { - btn.hide(); - } - }); - }); - - chat.on("click", ".user", function() { - var user = $(this).html().trim().replace(/[+%@~]/, ""); - if (user.indexOf("#") !== -1) { - return; - } - var text = "/whois " + user; - socket.emit("input", { - target: chat.data("id"), - text: text - }); - }); - - chat.on("msg", ".messages", function(e, target, msg) { - var btn = sidebar.find(".chan[data-target=" + target + "]:not(.active)"); - var query = btn.hasClass("query"); - var type = msg.type; - var highlight = type.contains("highlight"); - if (highlight || query) { - pop.play(); - if (document.hidden || !$(target).hasClass("active")) { - favico.badge("!"); - } - } - - if (btn.length === 0) { - return; - } - - var ignore = [ - "join", - "part", - "quit", - "nick" - ]; - if ($.inArray(type, ignore) !== -1){ - return; - } - - var badge = btn.find(".badge"); - if (badge.length !== 0) { - var i = (parseInt(badge.html()) || 0) + 1; - badge.html(i); - if (highlight || query) { - badge.addClass("highlight"); - } - } - }); - - chat.on("click", ".show-more", function() { - var self = $(this); - var id = self.data("id"); - var count = self.next(".messages").children().length; - socket.emit("showMore", { - target: id, - count: count - }); - }); - - var windows = $("#windows"); - var forms = $("#sign-in, #connect"); - - windows.on("show", "#sign-in", function() { - var self = $(this); - var inputs = self.find("input"); - inputs.each(function() { - var self = $(this); - if (self.val() === "") { - self.focus(); - return false; - } - }) - }); - - windows.on("click", ".input", function() { - $(this).select(); - }); - - forms.on("submit", "form", function(e) { - e.preventDefault() - var event = "auth"; - var form = $(this); - if (form.closest(".window").attr("id") == "connect") { - event = "conn"; - form.find(".btn") - .attr("disabled", true) - .end(); - } - var values = {}; - $.each(form.serializeArray(), function(i, obj) { - if (obj.value !== "") { - values[obj.name] = obj.value; - } - }); - if (values.user) { - $.cookie("user", values.user); - } - socket.emit( - event, values - ); - }); - - Mousetrap.bind([ - "command+up", - "command+down", - "ctrl+up", - "ctrl+down" - ], function(e, keys) { - var channels = sidebar.find(".chan"); - var index = channels.index(channels.filter(".active")); - - var direction = keys.split("+").pop(); - switch (direction) { - case "up": - var i = Math.max(0, index - 1); - channels.eq(i).click(); - break; - - case "down": - var i = Math.min(channels.length, index + 1); - channels.eq(i).click(); - break; - } - }); - - function complete(word) { - var words = commands.slice(); - var users = chat.find(".active") - .find(".names") - .children() - .each(function() { - words.push($(this).text().replace(/[+%@~]/, "")); - }); - var channels = sidebar.find(".channel") - .each(function() { - var chan = $(this).clone().remove("span").text().trim(); - words.push(chan); - }); - return $.grep( - words, - function(w) { - return !w.toLowerCase().indexOf(word.toLowerCase()); - } - ); - } - - document.addEventListener( - "visibilitychange", - function() { - if (sidebar.find(".highlight").length == 0) { - favico.badge(""); - } - } - ); -}); +$(function() { + var socket = io(); + var commands = [ + "/close", + "/connect", + "/deop", + "/devoice", + "/disconnect", + "/invite", + "/join", + "/kick", + "/leave", + "/mode", + "/msg", + "/nick", + "/notice", + "/op", + "/part", + "/query", + "/quit", + "/raw", + "/say", + "/send", + "/server", + "/slap", + "/topic", + "/voice", + "/whois" + ]; + + var sidebar = $("#sidebar"); + var chat = $("#chat"); + + var pop = new Audio(); + pop.src = "/audio/pop.ogg"; + + $("#play").on("click", function() { pop.play(); }); + $("#footer .icon").tooltip(); + + var favico = new Favico({ + animation: "none" + }); + + var tpl = []; + function render(name, data) { + tpl[name] = tpl[name] || Handlebars.compile($("#templates ." + name).html()); + return tpl[name](data); + } + + Handlebars.registerHelper( + "partial", function(id) { + return new Handlebars.SafeString(render(id, this)); + } + ); + + socket.on("error", function(e) { + console.log(e); + }); + + socket.on("auth", function(data) { + var body = $("body"); + var login = $("#sign-in"); + if (body.hasClass("signed-out")) { + var error = login.find(".error"); + error.show().closest("form").one("submit", function() { + error.hide(); + }); + } + body.addClass("signed-out"); + login.find("input[name='user']").val($.cookie("user") || ""); + sidebar.find(".sign-in") + .click() + .end() + .find(".networks") + .html("") + .next() + .show(); + }); + + socket.on("init", function(data) { + if (data.networks.length === 0) { + $("#footer").find(".connect").trigger("click"); + return; + } + + sidebar.find(".networks").html( + render("networks", { + networks: data.networks + }) + ); + + var channels = $.map(data.networks, function(n) { + return n.channels; + }); + chat.html( + render("chat", { + channels: channels + }) + ); + + sidebar.find(".empty").hide(); + $("body").removeClass("signed-out"); + + var id = $.cookie("target"); + var target = sidebar.find("[data-target='" + id + "']").trigger("click"); + if (target.length === 0) { + var first = sidebar.find(".chan") + .eq(0) + .trigger("click"); + if (first.length === 0) { + $("#footer").find(".connect").trigger("click"); + } + } + }); + + socket.on("join", function(data) { + var id = data.network; + var network = sidebar.find("#network-" + id); + network.append( + render("channels", { + channels: [data.chan] + }) + ); + chat.append( + render("chat", { + channels: [data.chan] + }) + ); + sidebar.find(".chan") + .last() + .trigger("click"); + }); + + socket.on("msg", function(data) { + var target = data.chan; + if (data.msg.type == "error") { + target = chat.find(".active").data("id"); + } + target = "#chan-" + target; + chat.find(target) + .find(".messages") + .append(render("messages", {messages: [data.msg]})) + .trigger("msg", [ + target, + data.msg + ]); + }); + + socket.on("showMore", function(data) { + var target = data.chan; + chat.find("#chan-" + target) + .find(".show-more") + .remove() + .end() + .find(".messages") + .prepend(render("messages", {messages: data.messages})) + .end(); + }); + + socket.on("network", function(data) { + sidebar.find(".empty").hide(); + sidebar.find(".networks").append( + render("networks", { + networks: [data.network] + }) + ); + chat.append( + render("chat", { + channels: data.network.channels + }) + ); + sidebar.find(".chan") + .last() + .trigger("click"); + $("#connect") + .find(".btn") + .prop("disabled", false) + .end() + .find("input") + .each(function() { + var self = $(this); + self.val(self.data("default")); + }); + }); + + socket.on("nick", function(data) { + console.log(data); + }); + + socket.on("part", function(data) { + var id = data.chan; + sidebar.find("[data-target=#chan-" + id + "]") + .remove() + .end() + .find(".chan") + .eq(0) + .trigger("click"); + }); + + socket.on("quit", function(data) { + var id = data.network; + sidebar.find("#network-" + id) + .remove() + .end(); + var chan = sidebar.find(".chan") + .eq(0) + .trigger("click"); + if (chan.length === 0) { + sidebar.find(".empty").show(); + } + }); + + socket.on("users", function(data) { + chat.find("#chan-" + data.chan) + .find(".users") + .html(render("users", data)); + }); + + $("#connect") + .find("input") + .each(function() { + var self = $(this); + self.data("default", self.val()); + }); + + $.cookie.json = true; + + var settings = $("#settings"); + var options = $.extend({notification: true}, $.cookie("settings")); + + for (var i in options) { + if (options[i]) { + settings.find("input[name=" + i + "]").prop("checked", true); + } + } + + settings.on("change", "input", function() { + var self = $(this); + options[self.attr("name")] = self.prop("checked"); + $.cookie("settings", options); + }).find("input") + .eq(0) + .trigger("change"); + + var viewport = $("#viewport"); + + viewport.on("click", ".lt, .rt", function(e) { + var self = $(this); + viewport.toggleClass(self.attr("class")); + if (viewport.is(".lt, .rt")) { + e.stopPropagation(); + chat.find(".chat").one("click", function() { + viewport.removeClass("lt rt"); + }); + } + }); + + var input = $("#input") + .history() + .tab(complete, {hint: false}); + + var form = $("#form").on("submit", function(e) { + e.preventDefault(); + var text = input.val(); + input.val(""); + socket.emit("input", { + target: chat.data("id"), + text: text + }); + }); + + var top = 1; + sidebar.on("click", "button", function() { + var self = $(this); + var target = self.data("target"); + if (!target) { + return; + } + + if (self.hasClass("chan")) { + $.cookie("target", target); + } + chat.data( + "id", + self.data("id") + ); + + sidebar.find(".active").removeClass("active"); + self.addClass("active") + .find(".badge") + .removeClass("highlight") + .empty(); + + if (sidebar.find(".highlight").length == 0) { + favico.badge(""); + } + + viewport.removeClass(); + + $("#windows .active").removeClass("active"); + var chan = $(target) + .addClass("active") + .trigger("show") + .css("z-index", top++) + .find(".chat") + .sticky() + .end(); + + if (screen.width > 768 && chan.hasClass("chan")) { + input.focus(); + } + }); + + sidebar.on("click", "#sign-out", function() { + location.reload(); + }); + + sidebar.on("click", ".close", function() { + var cmd = "/close"; + var chan = $(this).closest(".chan"); + if (chan.hasClass("lobby")) { + cmd = "/quit"; + var server = chan + .clone() + .remove("span") + .text() + .trim(); + if (!confirm("Disconnect from " + server + "?")) { + return false; + } + } + socket.emit("input", { + target: chan.data("id"), + text: cmd + }); + chan.css({ + transition: "none", + opacity: .4 + }); + return false; + }); + + chat.on("input", ".search", function() { + var value = $(this).val(); + var names = $(this).closest(".users").find(".names"); + names.find("button").each(function() { + var btn = $(this); + var name = btn.text().toLowerCase().replace(/[+%@~]/, ""); + if (name.indexOf(value) === 0) { + btn.show(); + } else { + btn.hide(); + } + }); + }); + + chat.on("click", ".user", function() { + var user = $(this).html().trim().replace(/[+%@~]/, ""); + if (user.indexOf("#") !== -1) { + return; + } + var text = "/whois " + user; + socket.emit("input", { + target: chat.data("id"), + text: text + }); + }); + + chat.on("msg", ".messages", function(e, target, msg) { + var btn = sidebar.find(".chan[data-target=" + target + "]:not(.active)"); + var query = btn.hasClass("query"); + var type = msg.type; + var highlight = type.contains("highlight"); + if (highlight || query) { + pop.play(); + if (document.hidden || !$(target).hasClass("active")) { + favico.badge("!"); + } + } + + if (btn.length === 0) { + return; + } + + var ignore = [ + "join", + "part", + "quit", + "nick" + ]; + if ($.inArray(type, ignore) !== -1){ + return; + } + + var badge = btn.find(".badge"); + if (badge.length !== 0) { + var i = (parseInt(badge.html()) || 0) + 1; + badge.html(i); + if (highlight || query) { + badge.addClass("highlight"); + } + } + }); + + chat.on("click", ".show-more", function() { + var self = $(this); + var id = self.data("id"); + var count = self.next(".messages").children().length; + socket.emit("showMore", { + target: id, + count: count + }); + }); + + var windows = $("#windows"); + var forms = $("#sign-in, #connect"); + + windows.on("show", "#sign-in", function() { + var self = $(this); + var inputs = self.find("input"); + inputs.each(function() { + var self = $(this); + if (self.val() === "") { + self.focus(); + return false; + } + }) + }); + + windows.on("click", ".input", function() { + $(this).select(); + }); + + forms.on("submit", "form", function(e) { + e.preventDefault() + var event = "auth"; + var form = $(this); + if (form.closest(".window").attr("id") == "connect") { + event = "conn"; + form.find(".btn") + .attr("disabled", true) + .end(); + } + var values = {}; + $.each(form.serializeArray(), function(i, obj) { + if (obj.value !== "") { + values[obj.name] = obj.value; + } + }); + if (values.user) { + $.cookie("user", values.user); + } + socket.emit( + event, values + ); + }); + + Mousetrap.bind([ + "command+up", + "command+down", + "ctrl+up", + "ctrl+down" + ], function(e, keys) { + var channels = sidebar.find(".chan"); + var index = channels.index(channels.filter(".active")); + + var direction = keys.split("+").pop(); + switch (direction) { + case "up": + var i = Math.max(0, index - 1); + channels.eq(i).click(); + break; + + case "down": + var i = Math.min(channels.length, index + 1); + channels.eq(i).click(); + break; + } + }); + + function complete(word) { + var words = commands.slice(); + var users = chat.find(".active") + .find(".names") + .children() + .each(function() { + words.push($(this).text().replace(/[+%@~]/, "")); + }); + var channels = sidebar.find(".channel") + .each(function() { + var chan = $(this).clone().remove("span").text().trim(); + words.push(chan); + }); + return $.grep( + words, + function(w) { + return !w.toLowerCase().indexOf(word.toLowerCase()); + } + ); + } + + document.addEventListener( + "visibilitychange", + function() { + if (sidebar.find(".highlight").length == 0) { + favico.badge(""); + } + } + ); +}); diff --git a/index.js b/index.js index 978b093..f681cca 100755 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ var config = require("./config.json"); var ClientManager= new require("./src/clientManager"); var program = require("commander"); var shout = require("./src/server.js"); +var fs = require("fs"); program .option("-p, --port ") @@ -31,22 +32,36 @@ program .description("List all existing users") .action(function() { var users = new ClientManager().getUsers(); - console.log(""); if (!users.length) { + console.log(""); console.log("No users found!"); + console.log(""); } else { + console.log(""); console.log("Users:"); for (var i = 0; i < users.length; i++) { console.log((i + 1) + ": " + users[i]); } + console.log(""); } - console.log(""); }); program .command("add-user ") .description("Add a new user") .action(function(name) { + try { + var path = __dirname + "/users"; + var test = path + "/.test"; + fs.mkdirSync(test); + fs.rmdirSync(test); + } catch (e) { + console.log(""); + console.log("You have no permissions to write to " + path); + console.log("Try running the command as sudo."); + console.log(""); + return; + } var manager = new ClientManager(); var users = manager.getUsers(); if (users.indexOf(name) !== -1) { @@ -75,15 +90,29 @@ program .command("remove-user ") .description("Remove an existing user") .action(function(name) { + try { + var path = __dirname + "/users"; + var test = path + "/.test"; + fs.mkdirSync(test); + fs.rmdirSync(test); + } catch (e) { + console.log(""); + console.log("You have no permissions to delete from " + path); + console.log("Try running the command as sudo."); + console.log(""); + return; + } var manager = new ClientManager(); var success = manager.removeUser(name); - console.log(""); if (success) { + console.log(""); console.log("Removed '" + name + "'."); + console.log(""); } else { + console.log(""); console.log("User '" + name + "' doesn't exist."); + console.log(""); } - console.log(""); }); program.parse(process.argv) diff --git a/package.json b/package.json index 58b5e91..efeda45 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "shout", "description": "A web IRC client", - "version": "0.9.9", + "version": "0.9.10", "author": "Mattias Erming", "preferGlobal": true, "bin": {