From 955903511829239c090040823704334cc97373fc Mon Sep 17 00:00:00 2001 From: Xaekai Date: Fri, 15 Jul 2016 22:06:27 -0700 Subject: [PATCH] Add a service socket to enable out of band access to the process commandline --- config.template.yaml | 6 +++++ index.js | 30 ++++++++++++++++++++++++ servcmd.sh.js | 56 ++++++++++++++++++++++++++++++++++++++++++++ src/config.js | 4 ++++ src/servsock.js | 53 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+) create mode 100755 servcmd.sh.js create mode 100644 src/servsock.js diff --git a/config.template.yaml b/config.template.yaml index 269428ad..e88873e1 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -237,3 +237,9 @@ setuid: # concurrent updates), then run `node lib/channel-storage/migrate.js`. channel-storage: type: 'file' + +# Allows for external services to access the system commandline +# Useful for setups where stdin isn't available such as when using PM2 +service-socket: + enabled: false + socket: 'service.sock' diff --git a/index.js b/index.js index 729d6cb4..f82a3176 100644 --- a/index.js +++ b/index.js @@ -45,6 +45,7 @@ process.stdin.on("data", function (data) { } }); +var net = require('net'); function handleLine(line) { if (line === "/reload") { Logger.syslog.log("Reloading config"); @@ -75,5 +76,34 @@ function handleLine(line) { } } else if (line.indexOf("/reload-partitions") === 0) { sv.reloadPartitionMap(); + } else if (line.indexOf("/globalban") === 0) { + var args = line.split(/\s+/); args.shift(); + if (args.length >= 2 && net.isIP(args[0]) !== 0) { + var ip = args.shift(); + var comment = args.join(' '); + require("./lib/database").globalBanIP(ip, comment, function (err, res) { + if (!err) { + Logger.eventlog.log("[acp] " + "SYSTEM" + " global banned " + ip); + } + }) + } + } else if (line.indexOf("/unglobalban") === 0) { + var args = line.split(/\s+/); args.shift(); + if (args.length === 1 && net.isIP(args[0]) !== 0) { + var ip = args.shift(); + require("./lib/database").globalUnbanIP(ip, function (err, res) { + if (!err) { + Logger.eventlog.log("[acp] " + "SYSTEM" + " un-global banned " + ip); + } + }) + } } } + +// Go Go Gadget Service Socket +if (Config.get("service-socket.enabled")) { + Logger.syslog.log("Opening service socket"); + var ServiceSocket = require('./lib/servsock'); + var server = new ServiceSocket; + server.init(handleLine, Config.get("service-socket.socket")); +} diff --git a/servcmd.sh.js b/servcmd.sh.js new file mode 100755 index 00000000..c90d4228 --- /dev/null +++ b/servcmd.sh.js @@ -0,0 +1,56 @@ +#!/usr/bin/env node +/* +** CyTube Service Socket Commandline +*/ + +var Config = require("./lib/config"); +Config.load("config.yaml"); + +if(!Config.get("service-socket.enabled")){ + console.error('The Service Socket is not enabled.'); + process.exit(1); +} + +const SOCKETFILE = Config.get("service-socket.socket"); +var net = require('net'); + +var client = net.createConnection(SOCKETFILE) + .on('connect', () => { + console.log("Connected."); + }) + .on('data', (msg) => { + msg = msg.toString(); + + if(msg === '__disconnect'){ + console.log('Server shutting down.'); + return cleanup(); + } + + // Generic message handler + console.info('Server:', data) + }) + .on('error', (data) => { + console.error('Unable to connect to Service Socket.'); + process.exit(1); + }) + ; + +var inputbuffer = ""; +process.stdin.on("data", (data) => { + inputbuffer += data; + if (inputbuffer.indexOf("\n") !== -1) { + var line = inputbuffer.substring(0, inputbuffer.indexOf("\n")); + inputbuffer = inputbuffer.substring(inputbuffer.indexOf("\n") + 1); + // Let the client escape + if(line === 'exit'){ return cleanup(); } + if(line === 'quit'){ return cleanup(); } + client.write(line); + } +}); + +function cleanup(){ + console.log('\n',"Terminating.",'\n'); + client.end(); + process.exit(0); +} +process.on('SIGINT', cleanup); diff --git a/src/config.js b/src/config.js index 6b24f2ae..e3d0ca82 100644 --- a/src/config.js +++ b/src/config.js @@ -116,6 +116,10 @@ var defaults = { }, "channel-storage": { type: "file" + }, + "service-socket": { + enabled: false, + socket: "service.sock" } }; diff --git a/src/servsock.js b/src/servsock.js new file mode 100644 index 00000000..b368112d --- /dev/null +++ b/src/servsock.js @@ -0,0 +1,53 @@ +var fs = require('fs'); +var net = require('net'); + +export default class ServiceSocket { + + constructor() { + this.connections = {}; + } + + init(handler, socket){ + this.handler = handler; + this.socket = socket; + + fs.stat(this.socket, (err, stats) => { + if (err) { + return this.openServiceSocket(); + } + fs.unlink(this.socket, (err) => { + if(err){ + console.error(err); process.exit(0); + } + return this.openServiceSocket(); + }); + }); + } + + openServiceSocket(){ + this.server = net.createServer((stream) => { + let id = Date.now(); + this.connections[id] = stream; + stream.on('end', () => { + delete this.connections[id]; + }); + stream.on('data', (msg) => { + this.handler(msg.toString()); + }); + }).listen(this.socket); + process.on('exit', this.closeServiceSocket.bind(this)); + } + + closeServiceSocket() { + if(Object.keys(this.connections).length){ + let clients = Object.keys(this.connections); + while(clients.length){ + let client = clients.pop(); + this.connections[client].write('__disconnect'); + this.connections[client].end(); + } + } + this.server.close(); + } + +}