#!/usr/bin/env node process.title = 'proxy'; /** * Module dependencies. */ const args = require('args'); const pkg = require('../package'); args.option( 'port', 'Port number to the proxy server should bind to', 3128, parseInt ) .option( 'authenticate', '"authenticate" command to run when the "Proxy-Authorization" header is sent', '', String ) .option( 'local-address', 'IP address of the network interface to send the outgoing requests through', '', String ); const flags = args.parse(process.argv, { name: pkg.name }); const { port, authenticate } = flags; const http = require('http'); const setup = require('../'); const debug = require('debug')('proxy'); const spawn = require('child_process').spawn; const basicAuthParser = require('basic-auth-parser'); /** * Setup the HTTP "proxy server" instance. */ const proxy = http.createServer(); setup(proxy); /** * Outbound proxy requests will use `agent: false`. */ debug("setting outbound proxy request's `agent` to `false`"); proxy.agent = false; /** * Proxy outgoing request localAddress parameter */ if (flags.localAddress) { proxy.localAddress = flags.localAddress; } /** * Proxy authenticate function. */ if (authenticate) { debug('setting `authenticate()` function for: "%s"', authenticate); proxy.authenticate = function(req, fn) { debug('authenticate(): "%s"', authenticate); // parse the "Proxy-Authorization" header var auth = req.headers['proxy-authorization']; if (!auth) { // optimization: don't invoke the child process if no // "Proxy-Authorization" header was given return fn(null, false); } var parsed = basicAuthParser(auth); debug('parsed "Proxy-Authorization": %j', parsed); // spawn a child process with the user-specified "authenticate" command var i; var env = {}; for (i in process.env) { // inherit parent env variables env[i] = process.env[i]; } // add "auth" related ENV variables for (i in parsed) { env['PROXY_AUTH_' + i.toUpperCase()] = parsed[i]; } var opts = {}; opts.stdio = ['ignore', 1, 2]; opts.env = env; var args = ['-c', authenticate]; // TODO: add Windows support (use `cross-spawn`?) var child = spawn('/bin/sh', args, opts); function onerror(err) { child.removeListener('exit', onexit); fn(err); } function onexit(code, signal) { debug( 'authentication child process "exit" event: %s %s', code, signal ); child.removeListener('error', onerror); fn(null, 0 == code); } child.once('error', onerror); child.once('exit', onexit); }; } /** * Bind to port. */ proxy.listen(port, function() { console.log( 'HTTP(s) proxy server listening on port %d', this.address().port ); });