diff --git a/other/js/auth_plugin_examples.js b/other/js/auth_plugin_examples.js new file mode 100644 index 0000000..945b248 --- /dev/null +++ b/other/js/auth_plugin_examples.js @@ -0,0 +1,90 @@ +/* + * An auth plugin must be a function which returns a function conforing to the + * requirements of the `verifyClients` option on ws.WebSocket.Server. + * + * See: https://github.com/websockets/ws/blob/master/doc/ws.md + * + * If websockify is provided with an --auth-source argument, this will be + * passed to the auth plugin as its first argument. + * + */ + +const querystring = require('querystring'); +const fs = require('fs'); + +function urlTokenMatch(url, token, verbose=false) { + /** + * Parse the url path, extract the `token` querystring value, and check if + * it matches the token argument. If verbose is set to true, log messages + * are enabled. + * + * Args: + * url (string): the path section of the URL + * token (string): the token which the token provided in the URL should + * match + * verbose (boolean): If True, extra console.log messages will be output + */ + let splitUrl = url.split("?") + if (splitUrl.length !== 2) { + if (verbose) { + console.log("Permission denied. No token provided."); + } + return false; + } + let qs = splitUrl[1]; + let qs_parsed = querystring.parse(qs); + let success = (qs_parsed.token === token); + if (verbose) { + if (!success) { + console.log("Permission denied for token: " + qs_parsed.token); + } else { + console.log("Permission granted for token: " + qs_parsed.token); + } + } + return success; +} + +exports.tokenAuth = function tokenAuth(source) { + /** + * Authorisation plugin which validates the token query parameter against + * a token provided as the argument to the `--auth-source` command line + * argument. + */ + return function(info) { + let token = source; + return urlTokenMatch(info.req.url, token, true); + } +} + +exports.tokenAuthEnv = function tokenAuthEnv(source) { + /** + * Authorisation plugin which validates the token query parameter against + * a token which is the value of an environment variable. The name of this + * environment variable is specified as the argument to the command line + * argument `--auth-source` + */ + return function(info) { + let token = process.env[source]; + return urlTokenMatch(info.req.url, token, true); + } +} + +exports.tokenAuthFile = function tokenEnvFile(source) { + /** + * Authorisation plugin which validates the token query parameter against a + * token which is contained in a text file, the path to which is specified + * as the value of the `--auth-source` command line argument + */ + return function(info, cb) { + fs.readFile(source, 'utf8', function(err, data) { + if (err) { + console.log(err); + cb(false); + } else { + let token = data.trim(); + let success = urlTokenMatch(info.req.url, token, true); + cb(success); + } + }); + } +} \ No newline at end of file diff --git a/other/js/websockify.js b/other/js/websockify.js index f617a1f..567482e 100755 --- a/other/js/websockify.js +++ b/other/js/websockify.js @@ -22,6 +22,7 @@ var argv = require('optimist').argv, webServer, wsServer, source_host, source_port, target_host, target_port, + auth_plugin, websocket_server_opts, web_path = null; @@ -140,7 +141,7 @@ try { throw("illegal port"); } } catch(e) { - console.error("websockify.js [--web web_dir] [--cert cert.pem [--key key.pem]] [source_addr:]source_port target_addr:target_port"); + console.error("websockify.js [--web web_dir] [--cert cert.pem [--key key.pem]] [--auth-plugin module.plugin [--auth-source auth_source]] [source_addr:]source_port target_addr:target_port"); process.exit(2); } @@ -161,7 +162,23 @@ if (argv.cert) { console.log(" - Running in unencrypted HTTP (ws://) mode"); webServer = http.createServer(http_request); } + +if (argv["auth-plugin"]) { + let auth_plugin_arg = argv["auth-plugin"].split(".") + let plugin_name = auth_plugin_arg.pop(); + let module_path = auth_plugin_arg.join("."); + + let auth_plugin = require(module_path)[plugin_name]; + let auth_source = argv["auth-source"] || undefined; + websocket_server_opts = { + server: webServer, + verifyClient: auth_plugin(auth_source) + }; +} else { + websocket_server_opts = {server: webServer}; +} + webServer.listen(source_port, function() { - wsServer = new WebSocketServer({server: webServer}); + wsServer = new WebSocketServer(websocket_server_opts); wsServer.on('connection', new_client); });