From a96f7976d8f8b28225d4acb4a76e2ffbe03ca0f8 Mon Sep 17 00:00:00 2001 From: Calvin Montgomery Date: Sat, 17 Jun 2017 10:12:15 -0700 Subject: [PATCH] Change Tor exit list Use the endpoint suggested in #688 to avoid unnecessarilly banning relays. --- package.json | 2 +- src/tor.js | 138 +++++++++++++++++++++++++-------------------------- 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index e0bf0113..cf932513 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "Calvin Montgomery", "name": "CyTube", "description": "Online media synchronizer and chat", - "version": "3.38.2", + "version": "3.38.3", "repository": { "url": "http://github.com/calzoneman/sync" }, diff --git a/src/tor.js b/src/tor.js index d6c78d28..996f86ed 100644 --- a/src/tor.js +++ b/src/tor.js @@ -1,87 +1,87 @@ -var https = require("https"); -var path = require("path"); -var fs = require("fs"); -var domain = require("domain"); +import https from 'https'; +import path from 'path'; +import fs from 'fs'; import { LoggerFactory } from '@calzoneman/jsli'; +import Promise from 'bluebird'; -const LOGGER = LoggerFactory.getLogger('tor'); +Promise.promisifyAll(fs); -function retrieveIPs(cb) { - var options = { - host: "www.dan.me.uk", - port: 443, - path: "/torlist/", - method: "GET" - }; +const LOGGER = LoggerFactory.getLogger('torlist'); +const TOR_EXIT_LIST_URL = 'https://check.torproject.org/exit-addresses'; +const TOR_EXIT_LIST_FILE = path.join(__dirname, '..', 'tor-exit-list.json'); +const ONE_DAY = 24 * 3600 * 1000; +const TOR_EXIT_IPS = new Set(); - var finish = function (status, data) { - if (status !== 200) { - cb(new Error("Failed to retrieve Tor IP list (HTTP " + status + ")"), null); - return; +function loadTorList() { + return fs.statAsync(TOR_EXIT_LIST_FILE).then(stats => { + if (new Date() - stats.mtime > ONE_DAY) { + LOGGER.info('Tor exit node list is older than 24h, re-downloading from %s', + TOR_EXIT_LIST_URL); + return loadTorListFromWebsite(); + } else { + return loadTorListFromFile(); + } + }).catch(error => { + if (error.code === 'ENOENT') { + LOGGER.info('File %s not found, downloading from %s', + TOR_EXIT_LIST_FILE, + TOR_EXIT_LIST_URL); + return loadTorListFromWebsite(); + } else { + throw error; } - - var ips = data.split("\n"); - cb(false, ips); - }; - - var d = domain.create(); - d.on("error", function (err) { - if (err.stack) - LOGGER.error(err.stack); - else - LOGGER.error(err); - }); - - d.run(function () { - var req = https.request(options, function (res) { - var buffer = ""; - res.setEncoding("utf-8"); - res.on("data", function (data) { buffer += data; }); - res.on("end", function () { finish(res.statusCode, buffer); }); - }); - - req.end(); }); } -function getTorIPs(cb) { - retrieveIPs(function (err, ips) { - if (!err) { - cb(false, ips); - const destination = path.join(__dirname, "..", "torlist"); - fs.writeFile(destination, - ips.join("\n"), - error => { - if (error) { - LOGGER.error("Failed to write to %s: %s", destination, error); - } - }); - return; - } - - fs.readFile(path.join(__dirname, "..", "torlist"), function (err, data) { - if (err) { - cb(err, null); +function loadTorListFromWebsite() { + return new Promise((resolve, reject) => { + https.get(TOR_EXIT_LIST_URL, res => { + if (res.statusCode !== 200) { + reject(new Error(`${res.statusCode} ${res.statusMessage}`)); return; } - data = (""+data).split("\n"); - cb(false, data); - }); + let buffer = ''; + res.on('data', data => buffer += data); + res.on('end', () => { + const exitNodes = buffer.split('\n').filter(line => { + return /^ExitAddress/.test(line); + }).map(line => { + return line.split(' ')[1]; + }); + + fs.writeFileAsync(TOR_EXIT_LIST_FILE, JSON.stringify(exitNodes)) + .then(() => { + LOGGER.info('Saved %s', TOR_EXIT_LIST_FILE); + }).catch(error => { + LOGGER.error('Unable to save %s: %s', + TOR_EXIT_LIST_FILE, + error.message); + }); + resolve(exitNodes); + }); + }).on('error', error => { + reject(error); + }) }); } -var _ipList = []; -getTorIPs(function (err, ips) { - if (err) { - LOGGER.error(err); - return; - } +function loadTorListFromFile() { + LOGGER.info('Loading Tor exit list from %s', TOR_EXIT_LIST_FILE); + return fs.readFileAsync(TOR_EXIT_LIST_FILE).then(contents => { + return JSON.parse(String(contents)); + }); +} - LOGGER.info("Loaded Tor IP list"); - _ipList = ips; +loadTorList().then(exits => { + TOR_EXIT_IPS.clear(); + exits.forEach(exit => { + TOR_EXIT_IPS.add(exit); + }); +}).catch(error => { + LOGGER.error('Unable to load Tor exit list: %s', error.stack); }); -exports.isTorExit = function (ip) { - return _ipList.indexOf(ip) >= 0; +export function isTorExit(ip) { + return TOR_EXIT_IPS.has(ip); };