TorProcess.js.html 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>TorProcess.js - Documentation</title>
  6. <script src="scripts/prettify/prettify.js"></script>
  7. <script src="scripts/prettify/lang-css.js"></script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
  13. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  14. </head>
  15. <body>
  16. <input type="checkbox" id="nav-trigger" class="nav-trigger" />
  17. <label for="nav-trigger" class="navicon-button x">
  18. <div class="navicon"></div>
  19. </label>
  20. <label for="nav-trigger" class="overlay"></label>
  21. <nav>
  22. <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ControlServer.html">ControlServer</a><ul class='methods'><li data-type='method'><a href="ControlServer.html#.instance_info">instance_info</a></li><li data-type='method'><a href="ControlServer.html#close">close</a></li><li data-type='method'><a href="ControlServer.html#createDNSServer">createDNSServer</a></li><li data-type='method'><a href="ControlServer.html#createHTTPServer">createHTTPServer</a></li><li data-type='method'><a href="ControlServer.html#createSOCKSServer">createSOCKSServer</a></li><li data-type='method'><a href="ControlServer.html#createTorPool">createTorPool</a></li><li data-type='method'><a href="ControlServer.html#listen">listen</a></li><li data-type='method'><a href="ControlServer.html#listenTcp">listenTcp</a></li><li data-type='method'><a href="ControlServer.html#listenWs">listenWs</a></li></ul></li><li><a href="DNSServer.html">DNSServer</a><ul class='methods'><li data-type='method'><a href="DNSServer.html#listen">listen</a></li></ul></li><li><a href="HTTPServer.html">HTTPServer</a><ul class='methods'><li data-type='method'><a href="HTTPServer.html#listen">listen</a></li></ul></li><li><a href="SOCKSServer.html">SOCKSServer</a><ul class='methods'><li data-type='method'><a href="SOCKSServer.html#listen">listen</a></li></ul></li><li><a href="TorPool.html">TorPool</a><ul class='methods'><li data-type='method'><a href="TorPool.html#add">add</a></li><li data-type='method'><a href="TorPool.html#add_instance_to_group">add_instance_to_group</a></li><li data-type='method'><a href="TorPool.html#add_instance_to_group_at">add_instance_to_group_at</a></li><li data-type='method'><a href="TorPool.html#add_instance_to_group_by_name">add_instance_to_group_by_name</a></li><li data-type='method'><a href="TorPool.html#create">create</a></li><li data-type='method'><a href="TorPool.html#create_instance">create_instance</a></li><li data-type='method'><a href="TorPool.html#exit">exit</a></li><li data-type='method'><a href="TorPool.html#get_config_at">get_config_at</a></li><li data-type='method'><a href="TorPool.html#get_config_by_name">get_config_by_name</a></li><li data-type='method'><a href="TorPool.html#instance_at">instance_at</a></li><li data-type='method'><a href="TorPool.html#instance_by_name">instance_by_name</a></li><li data-type='method'><a href="TorPool.html#instances_by_group">instances_by_group</a></li><li data-type='method'><a href="TorPool.html#new_identites">new_identites</a></li><li data-type='method'><a href="TorPool.html#new_identites_by_group">new_identites_by_group</a></li><li data-type='method'><a href="TorPool.html#new_identity_at">new_identity_at</a></li><li data-type='method'><a href="TorPool.html#new_identity_by_name">new_identity_by_name</a></li><li data-type='method'><a href="TorPool.html#next">next</a></li><li data-type='method'><a href="TorPool.html#next_by_group">next_by_group</a></li><li data-type='method'><a href="TorPool.html#remove">remove</a></li><li data-type='method'><a href="TorPool.html#remove_at">remove_at</a></li><li data-type='method'><a href="TorPool.html#remove_by_name">remove_by_name</a></li><li data-type='method'><a href="TorPool.html#remove_instance_from_group">remove_instance_from_group</a></li><li data-type='method'><a href="TorPool.html#remove_instance_from_group_at">remove_instance_from_group_at</a></li><li data-type='method'><a href="TorPool.html#remove_instance_from_group_by_name">remove_instance_from_group_by_name</a></li><li data-type='method'><a href="TorPool.html#set_config_all">set_config_all</a></li><li data-type='method'><a href="TorPool.html#set_config_at">set_config_at</a></li><li data-type='method'><a href="TorPool.html#set_config_by_group">set_config_by_group</a></li><li data-type='method'><a href="TorPool.html#set_config_by_name">set_config_by_name</a></li><li data-type='method'><a href="TorPool.html#signal_all">signal_all</a></li><li data-type='method'><a href="TorPool.html#signal_at">signal_at</a></li><li data-type='method'><a href="TorPool.html#signal_by_group">signal_by_group</a></li><li data-type='method'><a href="TorPool.html#signal_by_name">signal_by_name</a></li></ul></li><li><a href="TorProcess.html">TorProcess</a><ul class='methods'><li data-type='method'><a href="TorProcess.html#create">create</a></li><li data-type='method'><a href="TorProcess.html#exit">exit</a></li><li data-type='method'><a href="TorProcess.html#get_config">get_config</a></li><li data-type='method'><a href="TorProcess.html#new_identity">new_identity</a></li><li data-type='method'><a href="TorProcess.html#set_config">set_config</a></li><li data-type='method'><a href="TorProcess.html#signal">signal</a></li></ul></li></ul><h3>Modules</h3><ul><li><a href="module-tor-router.html">tor-router</a></li><li><a href="module-tor-router_ControlServer.html">tor-router/ControlServer</a></li><li><a href="module-tor-router_default_config.html">tor-router/default_config</a></li><li><a href="module-tor-router_default_ports.html">tor-router/default_ports</a></li><li><a href="module-tor-router_DNSServer.html">tor-router/DNSServer</a></li><li><a href="module-tor-router_HTTPServer.html">tor-router/HTTPServer</a></li><li><a href="module-tor-router_launch.html">tor-router/launch</a></li><li><a href="module-tor-router_nconf_load_env.html">tor-router/nconf_load_env</a></li><li><a href="module-tor-router_SOCKSServer.html">tor-router/SOCKSServer</a></li><li><a href="module-tor-router_TorPool.html">tor-router/TorPool</a></li><li><a href="module-tor-router_TorProcess.html">tor-router/TorProcess</a></li><li><a href="module-tor-router_winston_silent_logger.html">tor-router/winston_silent_logger</a></li></ul><h3>Events</h3><ul><li><a href="DNSServer.html#event:instance-connection">instance-connection</a></li><li><a href="HTTPServer.html#event:instance-connection">instance-connection</a></li><li><a href="SOCKSServer.html#event:instance-connection">instance-connection</a></li><li><a href="TorPool.html#event:instance_created">instance_created</a></li><li><a href="TorProcess.html#event:control_listen">control_listen</a></li><li><a href="TorProcess.html#event:controller_ready">controller_ready</a></li><li><a href="TorProcess.html#event:dns_listen">dns_listen</a></li><li><a href="TorProcess.html#event:error">error</a></li><li><a href="TorProcess.html#event:process_exit">process_exit</a></li><li><a href="TorProcess.html#event:ready">ready</a></li><li><a href="TorProcess.html#event:socks_listen">socks_listen</a></li></ul><h3>Global</h3><ul><li><a href="global.html#assembleHost">assembleHost</a></li><li><a href="global.html#cleanUp">cleanUp</a></li><li><a href="global.html#env_whitelist">env_whitelist</a></li><li><a href="global.html#logger">logger</a></li><li><a href="global.html#main">main</a></li><li><a href="global.html#nconf">nconf</a></li><li><a href="global.html#REALM">REALM</a></li><li><a href="global.html#setup_nconf_env">setup_nconf_env</a></li><li><a href="global.html#TOR_ROUTER_PROXY_AGENT">TOR_ROUTER_PROXY_AGENT</a></li></ul>
  23. </nav>
  24. <div id="main">
  25. <h1 class="page-title">TorProcess.js</h1>
  26. <section>
  27. <article>
  28. <pre class="prettyprint source linenums"><code>const spawn = require('child_process').spawn;
  29. const fs = require('fs');
  30. const crypto = require('crypto');
  31. const { connect } = require('net');
  32. const os = require('os');
  33. const Promise = require('bluebird');
  34. const _ = require('lodash');
  35. const { EventEmitter } = require('eventemitter3');
  36. const shell = require('shelljs');
  37. const getPort = require('get-port');
  38. const del = require('del');
  39. const temp = require('temp');
  40. const { TorController } = require('@deadcanaries/granax');
  41. const nanoid = require("nanoid");
  42. const winston = require('winston');
  43. Promise.promisifyAll(temp);
  44. Promise.promisifyAll(fs);
  45. temp.track();
  46. /**
  47. * @typedef {Object} InstanceDefinition
  48. * @property {string} [Name] - Name of the instance.
  49. * @property {string[]|string} [Group=[]] - Groups the instance belongs to.
  50. * @property {Object} [Config={}] - Configuration that will be passed to Tor. See {@link https://bit.ly/2QrmI3o|Tor Documentation} for all possible options.
  51. * @property {Number} [Weight] - Weight of the instance for "weighted" load balancing.
  52. */
  53. /**
  54. * Class that represents an individual Tor process.
  55. *
  56. * @extends EventEmitter
  57. */
  58. class TorProcess extends EventEmitter {
  59. /**
  60. * Creates an instance of `TorProcess`
  61. *
  62. * @param {string} tor_path - Path to the Tor executable.
  63. * @param {InstanceDefinition} [definition] - Object containing various options for the instance. See {@link InstanceDefinition} for more info.
  64. * @param {Object} [granax_options] - Object containing options that will be passed to granax.
  65. * @param {Logger} [logger] - A winston logger. If not provided no logging will occur.
  66. */
  67. constructor(tor_path, definition, granax_options, logger) {
  68. super();
  69. this.logger = logger || require('./winston_silent_logger');
  70. definition = definition || {};
  71. definition.Group = definition.Group ? [].concat(definition.Group) : [];
  72. definition.Config = definition.Config || {};
  73. this._definition = definition;
  74. /**
  75. * Path to the Tor executable.
  76. *
  77. * @type {string}
  78. * @public
  79. */
  80. this.tor_path = tor_path;
  81. /**
  82. * Object containing options that will be passed to granax.
  83. *
  84. * @type {Object}
  85. * @public
  86. */
  87. this.granax_options = granax_options;
  88. /**
  89. * The password that will be set for the control protocol.
  90. *
  91. * @type {string}
  92. * @public
  93. */
  94. this.control_password = crypto.randomBytes(128).toString('base64');
  95. this._id = nanoid(12);
  96. this.tor_config.DataDirectory = this.tor_config.DataDirectory || temp.mkdirSync();
  97. }
  98. /**
  99. * Kills the Tor process.
  100. *
  101. * @async
  102. * @returns {Promise}
  103. */
  104. async exit() {
  105. let p = new Promise((resolve, reject) => {
  106. this.once('process_exit', (code) => {
  107. resolve();
  108. });
  109. });
  110. this.process.kill('SIGINT');
  111. await p;
  112. }
  113. /**
  114. * The unique identifier assigned to each instance.
  115. *
  116. * @readonly
  117. * @type {string}
  118. */
  119. get id() { return this._id; }
  120. /**
  121. * Groups the instance are currently in.
  122. *
  123. * @readonly
  124. * @type {string[]}
  125. */
  126. get instance_group() {
  127. return (this.definition &amp;&amp; this.definition.Group);
  128. }
  129. /**
  130. * Either the "Name" property of the definition or the {@link TorProcess#id} property.
  131. *
  132. * @readonly
  133. * @type {string}
  134. */
  135. get instance_name() {
  136. return (this.definition &amp;&amp; this.definition.Name) || this.id;
  137. }
  138. /**
  139. * The definition used to create the instance.
  140. *
  141. * @readonly
  142. * @type {string}
  143. */
  144. get definition() { return this._definition; }
  145. /**
  146. * The configuration passed to Tor. The same value as `definition.Config`.
  147. *
  148. * @readonly
  149. * @type {Object}
  150. */
  151. get tor_config() { return this.definition.Config; }
  152. /**
  153. * Port Tor is bound to for DNS traffic.
  154. *
  155. * @readonly
  156. * @type {number}
  157. */
  158. get dns_port() {
  159. return this._ports.dns_port;
  160. }
  161. /**
  162. * Port Tor is bound to for SOCKS5 traffic.
  163. *
  164. * @readonly
  165. * @type {number}
  166. */
  167. get socks_port() {
  168. return this._ports.socks_port;
  169. }
  170. /**
  171. * Port Tor is bound to for API access.
  172. *
  173. * @readonly
  174. * @type {number}
  175. */
  176. get control_port() {
  177. return this._ports.control_port;
  178. }
  179. /**
  180. * Instance of granax.TorController connected to the Tor process.
  181. *
  182. * @readonly
  183. * @type {TorController}
  184. */
  185. get controller() {
  186. return this._controller;
  187. }
  188. /**
  189. * Property identifiyng whether Tor has started.
  190. *
  191. * @readonly
  192. * @type {boolean}
  193. */
  194. get ready() { return this._ready; }
  195. /* Passthrough to granax */
  196. /**
  197. * Requests a new identity via the control protocol.
  198. *
  199. * @async
  200. */
  201. async new_identity() {
  202. this.logger.info(`[tor-${this.instance_name}]: requested a new identity`);
  203. await this.controller.cleanCircuitsAsync();
  204. }
  205. /**
  206. * Retrieves a configuration value from the instance via the control protocol.
  207. *
  208. * @async
  209. * @throws Will throw an error if not connected to the control protocol.
  210. * @param {string} keyword - The name of the configuration property to retrieve.
  211. *
  212. * @returns {Promise&lt;string[]>}
  213. */
  214. async get_config(keyword) {
  215. if (!this.controller)
  216. throw new Error(`Controller is not connected`);
  217. return await this.controller.getConfigAsync(keyword);
  218. }
  219. /**
  220. * Sets a configuration value for the instance via the control protocol.
  221. *
  222. * @async
  223. * @throws Will throw an error if not connected to the control protocol.
  224. * @param {string} keyword - The name of the configuration property to retrieve.
  225. * @param {any} value - Value to set the property to.
  226. *
  227. * @returns {Promise}
  228. */
  229. async set_config(keyword, value) {
  230. if (!this.controller) {
  231. return new Error(`Controller is not connected`);
  232. }
  233. return await this.controller.setConfigAsync(keyword, value);
  234. }
  235. /**
  236. * Sends a signal via the control tnterface.
  237. *
  238. * @async
  239. * @throws Will throw an error if not connected to the control protocol.
  240. * @param {string} signal - The signal to send.
  241. *
  242. * @returns {Promise}
  243. */
  244. async signal(signal) {
  245. if (!this.controller) {
  246. throw new Error(`Controller is not connected`);
  247. }
  248. return await this.controller.signal(signal);
  249. }
  250. /**
  251. * Creates the Tor process based on the configuration provided. Promise is resolved when the process has been started.
  252. *
  253. * @async
  254. *
  255. * @returns {Promise&lt;ChildProcess>} - The process that has been created.
  256. */
  257. async create() {
  258. this._ports = {};
  259. let dnsPort = this._ports.dns_port = await getPort();
  260. let socksPort = this._ports.socks_port = await getPort();
  261. let controlPort = this._ports.control_port = await getPort();
  262. Object.freeze(this._ports);
  263. let options = {
  264. DNSPort: `127.0.0.1:${dnsPort}`,
  265. SocksPort: `127.0.0.1:${socksPort}`,
  266. ControlPort: `127.0.0.1:${controlPort}`,
  267. HashedControlPassword: shell.exec(`${this.tor_path} --quiet --hash-password "${this.control_password}"`, { async: false, silent: true }).stdout.trim()
  268. };
  269. let config = _.extend(_.cloneDeep(this.tor_config), options);
  270. let text = Object.keys(config).map((key) => `${key} ${config[key]}`).join(os.EOL);
  271. let configFile = await temp.openAsync('tor-router');
  272. let configPath = configFile.path;
  273. await fs.writeFileAsync(configPath, text);
  274. let tor = spawn(this.tor_path, ['-f', configPath], {
  275. stdio: ['ignore', 'pipe', 'pipe'],
  276. detached: false
  277. });
  278. tor.on('close', (async (code) => {
  279. if (this.definition &amp;&amp; !this.definition.Name) {
  280. await del(this.tor_config.DataDirectory, { force: true });
  281. }
  282. /**
  283. * An event that fires when the process has closed.
  284. *
  285. * @event TorProcess#process_exit
  286. * @type {number}
  287. * @param {number} code - The exit code from the process.
  288. */
  289. this.emit('process_exit', code);
  290. }));
  291. tor.stderr.on('data', (data) => {
  292. let error_message = Buffer.from(data).toString('utf8');
  293. this.emit('error', new Error(error_message));
  294. });
  295. this.once('ready', () => {
  296. this._ready = true;
  297. this.logger.info(`[tor-${this.instance_name}]: tor is ready`);
  298. });
  299. this.on('control_listen', (async () => {
  300. try {
  301. let socket = connect(this.control_port);
  302. socket.on('error', ((error) => {
  303. this.logger.error(`[tor-${this.instance_name}]: ${error.stack}`);
  304. this.emit('error', error);
  305. }));
  306. this._controller = new TorController(socket, _.extend({ authOnConnect: false }, this.granax_options));
  307. Promise.promisifyAll(this._controller);
  308. this.controller.on('ready', () => {
  309. this.logger.debug(`[tor-${this.instance_name}]: connected via the tor control protocol`);
  310. this.controller.authenticate(`"${this.control_password}"`, (err) => {
  311. if (err) {
  312. this.logger.error(`[tor-${this.instance_name}]: ${err.stack}`);
  313. this.emit('error', err);
  314. } else {
  315. this.logger.debug(`[tor-${this.instance_name}]: authenticated with tor instance via the control protocol`);
  316. /**
  317. * Is true when the connected via the control protcol
  318. * @type {boolean}
  319. */
  320. this.control_port_connected = true;
  321. /**
  322. * An event that fires when a connection has been established to the control protocol.
  323. *
  324. * @event TorProcess#controller_ready
  325. */
  326. this.emit('controller_ready');
  327. }
  328. });
  329. });
  330. } catch (error) {
  331. this.logger.error(`[tor-${this.instance_name}]: ${err.stack}`);
  332. this.emit('error', err);
  333. }
  334. }));
  335. tor.stdout.on('data', (data) => {
  336. let text = Buffer.from(data).toString('utf8');
  337. let msg = text.indexOf('] ') !== -1 ? text.split('] ').pop() : null;
  338. if (text.indexOf('Bootstrapped 100%: Done') !== -1){
  339. this.bootstrapped = true;
  340. /**
  341. * An event that fires when the Tor process is fully bootstrapped (and ready for traffic).
  342. *
  343. * @event TorProcess#ready
  344. */
  345. this.emit('ready');
  346. }
  347. if (text.indexOf('Opening Control listener on') !== -1) {
  348. this.control_port_listening = true;
  349. /**
  350. * An event that fires when the Tor process has started listening for control interface traffic.
  351. *
  352. * @event TorProcess#control_listen
  353. */
  354. this.emit('control_listen');
  355. }
  356. if (text.indexOf('Opening Socks listener on') !== -1) {
  357. this.socks_port_listening = true;
  358. /**
  359. * An event that fires when the Tor process has started listening for SOCKS5 traffic.
  360. *
  361. * @event TorProcess#socks_listen
  362. */
  363. this.emit('socks_listen');
  364. }
  365. if (text.indexOf('Opening DNS listener on') !== -1) {
  366. this.dns_port_listening = true;
  367. /**
  368. * An event that fires when the Tor process has started listening for DNS traffic.
  369. *
  370. * @event TorProcess#dns_listen
  371. */
  372. this.emit('dns_listen');
  373. }
  374. if (text.indexOf('[err]') !== -1) {
  375. /**
  376. * An event that fires when the Tor process has written an error to stdout, stderr or when an error occurs connecting via the control protocol.
  377. *
  378. * @event TorProcess#error
  379. * @type {Error}
  380. * @returns {Error}
  381. */
  382. this.emit('error', new Error(msg));
  383. this.logger.error(`[tor-${this.instance_name}]: ${msg}`);
  384. }
  385. else if (text.indexOf('[notice]') !== -1) {
  386. this.logger.debug(`[tor-${this.instance_name}]: ${msg}`);
  387. }
  388. else if (text.indexOf('[warn]') !== -1) {
  389. this.logger.warn(`[tor-${this.instance_name}]: ${msg}`);
  390. }
  391. });
  392. this.process = tor;
  393. return tor;
  394. }
  395. };
  396. /**
  397. * Module that contains the {@link TorProcess} class.
  398. * @module tor-router/TorProcess
  399. * @see TorProcess
  400. */
  401. module.exports = TorProcess;</code></pre>
  402. </article>
  403. </section>
  404. </div>
  405. <br class="clear">
  406. <footer>
  407. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Tue Sep 25 2018 12:53:23 GMT-0400 (Eastern Daylight Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
  408. </footer>
  409. <script>prettyPrint();</script>
  410. <script src="scripts/linenumber.js"></script>
  411. </body>
  412. </html>