1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

Improve Aphlict server

Summary:
  - Move to port 22280 by default.
  - Warn when running as non-root.
  - Allow subscription and publish/admin ports to be configured.
  - Allow server to drop root after binding to 843.
  - Allow log path to be configured.
  - Add /status/ admin URI which shows server status.
  - Return HTTP 400 Bad Request for other requests, instead of hanging.
  - Minor formatting cleanup.

Test Plan:
Ran without root:

  $ node aphlict_server.js

...got a good error message. Ran with --user:

  $ sudo node aphlict_server.js --user=epriestley

...verified server dropped permissions. Ran with --port / --admin. Hit /status/ with GET, got status. Hit other URLs with GET, got 400.

Reviewers: allenjohnashton, ddfisher, keebuhm

Reviewed By: ddfisher

CC: aran

Differential Revision: https://secure.phabricator.com/D2737
This commit is contained in:
epriestley 2012-06-14 06:12:54 -07:00
parent 9a4243b4b3
commit 86040227b0
5 changed files with 91 additions and 13 deletions

View file

@ -737,7 +737,7 @@ celerity_register_resource_map(array(
), ),
'javelin-aphlict' => 'javelin-aphlict' =>
array( array(
'uri' => '/res/50cae715/rsrc/js/application/aphlict/Aphlict.js', 'uri' => '/res/c0b9e53f/rsrc/js/application/aphlict/Aphlict.js',
'type' => 'js', 'type' => 'js',
'requires' => 'requires' =>
array( array(

View file

@ -39,7 +39,7 @@ final class PhabricatorAphlictTestPageController
array( array(
'id' => $object_id, 'id' => $object_id,
'server' => '127.0.0.1', 'server' => '127.0.0.1',
'port' => 2600, 'port' => 22280,
)); ));
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(

View file

@ -397,7 +397,7 @@ final class PhabricatorStandardPageView extends AphrontPageView {
array( array(
'id' => $aphlict_object_id, 'id' => $aphlict_object_id,
'server' => $server_domain, 'server' => $server_domain,
'port' => 2600, 'port' => 22280,
'pageObjects' => $this->pageObjects, 'pageObjects' => $this->pageObjects,
)); ));

View file

@ -1,3 +1,49 @@
/**
* Notification server. Launch with:
*
* sudo node aphlict_server.js --user=aphlict
*
* You can also specify `port`, `admin` and `log`.
*/
var config = parse_command_line_arguments(process.argv);
function parse_command_line_arguments(argv) {
var config = {
port : 22280,
admin : 22281,
user : null,
log: '/var/log/aphlict.log'
};
for (var ii = 2; ii < argv.length; ii++) {
var arg = argv[ii];
var matches = arg.match(/^--([^=]+)=(.*)$/);
if (!matches) {
throw new Error("Unknown argument '"+arg+"'!");
}
if (!(matches[1] in config)) {
throw new Error("Unknown argument '"+matches[1]+"'!");
}
config[matches[1]] = matches[2];
}
config.port = parseInt(config.port, 10);
config.admin = parseInt(config.admin, 10);
return config;
}
if (process.getuid() != 0) {
console.log(
"ERROR: "+
"This server must be run as root because it needs to bind to privileged "+
"port 843 to start a Flash policy server. It will downgrade to run as a "+
"less-privileged user after binding if you pass a user in the command "+
"line arguments with '--user=alincoln'.");
process.exit(1);
}
var net = require('net'); var net = require('net');
var http = require('http'); var http = require('http');
var url = require('url'); var url = require('url');
@ -5,7 +51,7 @@ var querystring = require('querystring');
var fs = require('fs'); var fs = require('fs');
// set up log file // set up log file
logfile = fs.createWriteStream('/var/log/aphlict.log', var logfile = fs.createWriteStream(config.log,
{ flags: 'a', { flags: 'a',
encoding: null, encoding: null,
mode: 0666 }); mode: 0666 });
@ -23,7 +69,7 @@ function getFlashPolicy() {
'<!DOCTYPE cross-domain-policy SYSTEM ' + '<!DOCTYPE cross-domain-policy SYSTEM ' +
'"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">', '"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">',
'<cross-domain-policy>', '<cross-domain-policy>',
'<allow-access-from domain="*" to-ports="2600"/>', '<allow-access-from domain="*" to-ports="'+config.port+'"/>',
'</cross-domain-policy>' '</cross-domain-policy>'
].join('\n'); ].join('\n');
} }
@ -97,16 +143,20 @@ var send_server = net.createServer(function(socket) {
}); });
socket.on('error', function (e) { socket.on('error', function (e) {
console.log('Uncaught error in send server: ' + e); log('Uncaught error in send server: ' + e);
}); });
}).listen(2600); }).listen(config.port);
var messages_out = 0;
var messages_in = 0;
var start_time = new Date().getTime();
var receive_server = http.createServer(function(request, response) { var receive_server = http.createServer(function(request, response) {
response.writeHead(200, {'Content-Type' : 'text/plain'}); response.writeHead(200, {'Content-Type' : 'text/plain'});
if (request.method == 'POST') { // Only pay attention to POST requests // Publishing a notification.
if (request.method == 'POST') {
var body = ''; var body = '';
request.on('data', function (data) { request.on('data', function (data) {
@ -114,18 +164,40 @@ var receive_server = http.createServer(function(request, response) {
}); });
request.on('end', function () { request.on('end', function () {
++messages_in;
var data = querystring.parse(body); var data = querystring.parse(body);
log('notification: ' + JSON.stringify(data)); log('notification: ' + JSON.stringify(data));
broadcast(data); broadcast(data);
response.end(); response.end();
}); });
} else if (request.url == '/status/') {
request.on('end', function() {
var status = {
'uptime': (new Date().getTime() - start_time),
'clients.active': current_connections,
'clients.total': generate_id.current_id || 0,
'messages.in': messages_in,
'messages.out': messages_out,
'log': config.log
};
response.write(JSON.stringify(status));
response.end();
});
} else {
response.statusCode = 400;
response.write('400 Bad Request');
response.end();
} }
}).listen(22281, '127.0.0.1');
}).listen(config.admin, '127.0.0.1');
function broadcast(data) { function broadcast(data) {
for (var client_id in clients) { for (var client_id in clients) {
try { try {
write_json(clients[client_id], data); write_json(clients[client_id], data);
++messages_out;
log('wrote to client ' + client_id); log('wrote to client ' + client_id);
} catch (error) { } catch (error) {
delete clients[client_id]; delete clients[client_id];
@ -135,3 +207,9 @@ function broadcast(data) {
} }
} }
// If we're configured to drop permissions, get rid of them now that we've
// bound to the ports we need and opened logfiles.
if (config.user) {
process.setuid(config.user);
}

View file

@ -7,7 +7,7 @@
/** /**
* Simple JS API for the Flash Aphlict client. Example usage: * Simple JS API for the Flash Aphlict client. Example usage:
* *
* var aphlict = new JX.Aphlict('aphlict_swf', '127.0.0.1', 2600) * var aphlict = new JX.Aphlict('aphlict_swf', '127.0.0.1', 22280)
* .setHandler(function(type, message) { * .setHandler(function(type, message) {
* JX.log("Got " + type + " event!") * JX.log("Got " + type + " event!")
* }) * })