tor-commits
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
November 2015
- 20 participants
- 857 discussions
commit d55d7d74122e1f07df608f653541c45a154ce49c
Author: ilv <ilv(a)users.noreply.github.com>
Date: Mon Aug 3 15:02:27 2015 -0300
Debugging improvements
---
gettor/blacklist.py | 85 +++++++++++-------
gettor/core.py | 241 ++++++++++++++++++++++++++++-----------------------
gettor/db.py | 76 ++++++++++------
gettor/utils.py | 19 ++++
4 files changed, 258 insertions(+), 163 deletions(-)
diff --git a/gettor/blacklist.py b/gettor/blacklist.py
index b95d888..a16c764 100644
--- a/gettor/blacklist.py
+++ b/gettor/blacklist.py
@@ -27,6 +27,14 @@ class BlacklistError(Exception):
pass
+class ConfigError(Exception):
+ pass
+
+
+class InternalError(Exception):
+ pass
+
+
class Blacklist(object):
"""Manage blacklisting of users.
@@ -38,6 +46,7 @@ class Blacklist(object):
ConfigurationError: Bad configuration.
BlacklistError: User is blacklisted.
+ InternalError: Something went wrong internally.
"""
@@ -47,44 +56,46 @@ class Blacklist(object):
:param: cfg (string) path of the configuration file.
"""
- # define a set of default values
- DEFAULT_CONFIG_FILE = 'blacklist.cfg'
-
- logging.basicConfig(format='[%(levelname)s] %(asctime)s - %(message)s',
- datefmt="%Y-%m-%d %H:%M:%S")
- log = logging.getLogger(__name__)
+ default_cfg = 'blacklist.cfg'
config = ConfigParser.ConfigParser()
if cfg is None or not os.path.isfile(cfg):
- cfg = DEFAULT_CONFIG_FILE
-
- config.read(cfg)
+ cfg = default_cfg
try:
- dbname = config.get('general', 'db')
- self.db = db.DB(dbname)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'db' from 'general'")
+ with open(cfg) as f:
+ config.readfp(f)
+ except IOError:
+ raise ConfigError("File %s not found!" % cfg)
try:
+ dbname = config.get('general', 'db')
logdir = config.get('log', 'dir')
logfile = os.path.join(logdir, 'blacklist.log')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'log'")
-
- try:
loglevel = config.get('log', 'level')
+ self.db = db.DB(dbname)
+
except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'level' from 'log'")
+ raise ConfigError("%s" % e)
+ except db.Exception as e:
+ raise ConfigError("%s" % e)
- # establish log level and redirect to log file
- log.info('Redirecting logging to %s' % logfile)
+ # logging
+ log = logging.getLogger(__name__)
+
+ logging_format = utils.get_logging_format()
+ date_format = utils.get_date_format()
+ formatter = logging.Formatter(logging_format, date_format)
+
+ log.info('Redirecting BLACKLIST logging to %s' % logfile)
logfileh = logging.FileHandler(logfile, mode='a+')
+ logfileh.setFormatter(formatter)
logfileh.setLevel(logging.getLevelName(loglevel))
log.addHandler(logfileh)
# stop logging on stdout from now on
log.propagate = False
+ self.log = log
def is_blacklisted(self, user, service, max_req, wait_time):
"""Check if a user is blacklisted.
@@ -113,24 +124,40 @@ class Blacklist(object):
if r:
# permanently blacklisted
if r['blocked']:
- self.db.update_user(user, service, r['times']+1, 1)
- raise BlacklistError("Blocked user")
+ try:
+ self.db.update_user(user, service, r['times']+1, 1)
+ raise BlacklistError("Blocked user")
+ except db.DBError as e:
+ raise InternalError("Can't update user (%s)" % str(e))
# don't be greedy
elif r['times'] >= max_req:
- last = datetime.datetime.fromtimestamp(float(
- r['last_request']))
+ last = datetime.datetime.fromtimestamp(
+ float(r['last_request'])
+ )
next = last + datetime.timedelta(minutes=wait_time)
if datetime.datetime.now() < next:
# too many requests from the same user
- self.db.update_user(user, service, r['times']+1, 0)
- raise BlacklistError("Too many requests")
+ try:
+ self.db.update_user(user, service, r['times']+1, 0)
+ raise BlacklistError("Too many requests")
+ except db.DBError as e:
+ raise InternalError("Can't update user (%s)" % str(e))
else:
# fresh user again!
- self.db.update_user(user, service, 1, 0)
+ try:
+ self.db.update_user(user, service, 1, 0)
+ except db.DBError as e:
+ raise InternalError("Can't update user (%s)" % str(e))
else:
# adding up a request for user
- self.db.update_user(user, service, r['times']+1, 0)
+ try:
+ self.db.update_user(user, service, r['times']+1, 0)
+ except db.DBError as e:
+ raise InternalError("Can't update user (%s)" % str(e))
else:
# new request for user
- self.db.add_user(user, service, 0)
+ try:
+ self.db.add_user(user, service, 0)
+ except db.DBError as e:
+ raise InternalError("Can't add new user (%s)" % str(e))
diff --git a/gettor/core.py b/gettor/core.py
index df596a9..219fed2 100644
--- a/gettor/core.py
+++ b/gettor/core.py
@@ -27,11 +27,7 @@ class ConfigError(Exception):
pass
-class UnsupportedOSError(Exception):
- pass
-
-
-class UnsupportedLocaleError(Exception):
+class NotSupportedError(Exception):
pass
@@ -60,8 +56,7 @@ class Core(object):
Exceptions:
- UnsupportedOSError: Request for an unsupported operating system.
- UnsupportedLocaleError: Request for an unsupported locale.
+ UnsupportedOSError: OS and/or locale not supported.
ConfigError: Something's misconfigured.
LinkFormatError: The link added doesn't seem legit.
LinkFileError: Error related to the links file of a provider.
@@ -77,71 +72,56 @@ class Core(object):
or if something goes wrong while reading options from it.
"""
- # define a set of default values
- DEFAULT_CONFIG_FILE = 'core.cfg'
-
- logging.basicConfig(format='[%(levelname)s] %(asctime)s - %(message)s',
- datefmt="%Y-%m-%d %H:%M:%S")
- log = logging.getLogger(__name__)
+ default_cfg = 'core.cfg'
config = ConfigParser.ConfigParser()
if cfg is None or not os.path.isfile(cfg):
- cfg = DEFAULT_CONFIG_FILE
-
- config.read(cfg)
-
- try:
- basedir = config.get('general', 'basedir')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'basedir' from 'general'")
-
- try:
- dbname = config.get('general', 'db')
- dbname = os.path.join(basedir, dbname)
- self.db = db.DB(dbname)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'db' from 'general'")
+ cfg = default_cfg
try:
- self.linksdir = config.get('links', 'dir')
- self.linksdir = os.path.join(basedir, self.linksdir)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'links' from 'dir'")
+ with open(cfg) as f:
+ config.readfp(f)
+ except IOError:
+ raise ConfigError("File %s not found!" % cfg)
try:
self.supported_lc = config.get('links', 'locales')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'locales' from 'links'")
-
- try:
self.supported_os = config.get('links', 'os')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'os' from 'links'")
- try:
- loglevel = config.get('log', 'level')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'level' from 'log'")
-
- try:
+ basedir = config.get('general', 'basedir')
+ self.linksdir = config.get('links', 'dir')
+ self.linksdir = os.path.join(basedir, self.linksdir)
self.i18ndir = config.get('i18n', 'dir')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'i18n'")
- try:
+ loglevel = config.get('log', 'level')
logdir = config.get('log', 'dir')
logfile = os.path.join(logdir, 'core.log')
+
+ dbname = config.get('general', 'db')
+ dbname = os.path.join(basedir, dbname)
+ self.db = db.DB(dbname)
+
except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'log'")
+ raise ConfigError("Configuration error: %s" % str(e))
+ except db.Exception as e:
+ raise InternalError("%s" % e)
- # establish log level and redirect to log file
- log.info('Redirecting logging to %s' % logfile)
+ # logging
+ log = logging.getLogger(__name__)
+
+ logging_format = utils.get_logging_format()
+ date_format = utils.get_date_format()
+ formatter = logging.Formatter(logging_format, date_format)
+
+ log.info('Redirecting CORE logging to %s' % logfile)
logfileh = logging.FileHandler(logfile, mode='a+')
+ logfileh.setFormatter(formatter)
logfileh.setLevel(logging.getLevelName(loglevel))
log.addHandler(logfileh)
# stop logging on stdout from now on
log.propagate = False
+ self.log = log
def _get_msg(self, msgid, lc):
"""Get message identified by msgid in a specific locale.
@@ -153,11 +133,14 @@ class Core(object):
"""
# obtain the content in the proper language
- t = gettext.translation(lc, self.i18ndir, languages=[lc])
- _ = t.ugettext
+ try:
+ t = gettext.translation(lc, self.i18ndir, languages=[lc])
+ _ = t.ugettext
- msgstr = _(msgid)
- return msgstr
+ msgstr = _(msgid)
+ return msgstr
+ except IOError as e:
+ raise ConfigError("%s" % str(e))
def get_links(self, service, os, lc):
"""Get links for OS in locale.
@@ -170,27 +153,33 @@ class Core(object):
:param: os (string) the operating system.
:param: lc (string) tthe locale.
- :raise: UnsupportedOSError if the operating system is not supported.
- :raise: UnsupportedLocaleError if the locale is not supported.
:raise: InternalError if something goes wrong while internally.
:return: (string) the links.
"""
-
+ # english and windows by default
if lc not in self.supported_lc:
- raise UnsupportedLocaleError("Locale %s not supported" % lc)
+ self.log.debug("Request for locale not supported. Default to en")
+ lc = 'en'
if os not in self.supported_os:
- raise UnsupportedOSError("OS %s not supported " % os)
+ self.log.debug("Request for OS not supported. Default to windows")
+ os = 'windows'
# this could change in the future, let's leave it isolated.
- links = self._get_links(os, lc)
+ self.log.debug("Trying to get the links...")
+ try:
+ links = self._get_links(os, lc)
+ self.log.debug("OK")
+ except InternalError as e:
+ self.log.debug("FAILED")
+ raise InternalError("%s" % str(e))
if links is None:
- raise InternalError("Something went wrong internally")
+ self.log.debug("No links found")
+ raise InternalError("No links. Something is wrong.")
- # thanks for stopping by
return links
def _get_links(self, osys, lc):
@@ -230,43 +219,45 @@ class Core(object):
for name in links:
# we're reading files listed on linksdir, so they must exist!
config = ConfigParser.ConfigParser()
- config.read(name)
+ # but just in case they don't
+ try:
+ with open(name) as f:
+ config.readfp(f)
+ except IOError:
+ raise InternalError("File %s not found!" % name)
try:
pname = config.get('provider', 'name')
- except ConfigParser.Error as e:
- raise InternalError("Couldn't get 'name' from 'provider'")
- # checking if current provider pname has links for os in lc
- try:
+ # check if current provider pname has links for os in lc
providers[pname] = config.get(osys, lc)
# avoid showing it all together
providers[pname] = providers[pname].replace(",", "")
providers[pname] = providers[pname].replace("$", "\n\n")
- except ConfigParser.Error as e:
- raise InternalError("Couldn't get %s from %s (%s)" %
- (lc, osys, name))
- # all packages are signed with the same key (Tor Browser developers)
- try:
+ # all packages are signed with same key
+ # (Tor Browser developers)
fingerprint = config.get('key', 'fingerprint')
fingerprint_msg = self._get_msg('fingerprint', lc)
fingerprint_msg = fingerprint_msg % fingerprint
except ConfigParser.Error as e:
- raise InternalError("Couldn't get 'fingerprint' from 'key'")
+ raise InternalError("%s" % str(e))
# create the final links list with all providers
all_links = []
for key in providers.keys():
# get more friendly description of the provider
- provider_desc = self._get_msg('provider_desc', lc)
- provider_desc = provider_desc % key
+ try:
+ provider_desc = self._get_msg('provider_desc', lc)
+ provider_desc = provider_desc % key
- all_links.append(
- "%s\n%s\n\n%s%s\n\n\n" %
- (provider_desc, spt, ''.join(providers[key]), spt)
- )
+ all_links.append(
+ "%s\n%s\n\n%s%s\n\n\n" %
+ (provider_desc, spt, ''.join(providers[key]), spt)
+ )
+ except ConfigError as e:
+ raise InternalError("%s" % str(e))
# add fingerprint after the links
all_links.append(fingerprint_msg)
@@ -310,27 +301,41 @@ class Core(object):
linksfile = os.path.join(self.linksdir, provider.lower() + '.links')
linksfile_backup = ""
+ self.log.debug("Request to create a new links file")
if os.path.isfile(linksfile):
- # backup the old file in case something fails
- linksfile_backup = linksfile + '.backup'
- os.rename(linksfile, linksfile_backup)
-
- try:
- # this creates an empty links file
- content = ConfigParser.RawConfigParser()
- content.add_section('provider')
- content.set('provider', 'name', provider)
- content.add_section('key')
- content.set('key', 'fingerprint', fingerprint)
- content.add_section('linux')
- content.add_section('windows')
- content.add_section('osx')
- with open(linksfile, 'w+') as f:
- content.write(f)
- except Exception as e:
- if linksfile_backup:
- os.rename(linksfile_backup, linksfile)
- raise LinkFileError("Error while creating new links file: %s" % e)
+ self.log.debug("Trying to backup the old one...")
+ try:
+ # backup the old file in case something fails
+ linksfile_backup = linksfile + '.backup'
+ os.rename(linksfile, linksfile_backup)
+ except OSError as e:
+ self.log.debug("FAILED %s" % str(e))
+ raise LinkFileError(
+ "Error while creating new links file: %s" % str(e)
+ )
+
+ self.log.debug("Creating empty links file...")
+ try:
+ # this creates an empty links file
+ content = ConfigParser.RawConfigParser()
+ content.add_section('provider')
+ content.set('provider', 'name', provider)
+ content.add_section('key')
+ content.set('key', 'fingerprint', fingerprint)
+ content.add_section('linux')
+ content.add_section('windows')
+ content.add_section('osx')
+ with open(linksfile, 'w+') as f:
+ content.write(f)
+ except Exception as e:
+ self.log.debug("FAILED: %s" % str(e))
+ # if we passed the last exception, then this shouldn't
+ # be a problem...
+ if linksfile_backup:
+ os.rename(linksfile_backup, linksfile)
+ raise LinkFileError(
+ "Error while creating new links file: %s" % str(e)
+ )
def add_link(self, provider, osys, lc, link):
"""Public method to add a link to a provider's links file.
@@ -344,8 +349,7 @@ class Core(object):
:param: lc (string) the locale.
:param: link (string) link to be added.
- :raise: UnsupportedOSError if the operating system is not supported.
- :raise: UnsupportedLocaleError if the locale is not supported.
+ :raise: NotsupportedError if the OS and/or locale is not supported.
:raise: LinkFileError if there is no links file for the provider.
:raise: LinkFormatError if the link format doesn't seem legit.
:raise: InternalError if the links file doesn't have a section for
@@ -355,33 +359,54 @@ class Core(object):
"""
linksfile = os.path.join(self.linksdir, provider.lower() + '.links')
+ self.log.debug("Request to add a new link")
# don't try to add unsupported stuff
if lc not in self.supported_lc:
- raise UnsupportedLocaleError("Locale %s not supported" % lc)
+ self.log.debug("Request for locale %s not supported" % lc)
+ raise NotSupportedError("Locale %s not supported" % lc)
if osys not in self.supported_os:
- raise UnsupportedOSError("OS %s not supported" % osys)
+ self.log.debug("Request for OS %s not supported" % osys)
+ raise NotSupportedError("OS %s not supported" % osys)
+ self.log.debug("Opening links file...")
if os.path.isfile(linksfile):
content = ConfigParser.RawConfigParser()
- content.readfp(open(linksfile))
+
+ try:
+ with open(linksfile) as f:
+ content.readfp(f)
+ except IOError as e:
+ self.log.debug("FAILED %s" % str(e))
+ raise LinksFileError("File %s not found!" % linksfile)
# check if exists and entry for locale; if not, create it
+ self.log.debug("Trying to add the link...")
try:
links = content.get(osys, lc)
links = "%s,\n%s" % (links, link)
content.set(osys, lc, links)
+ self.log.debug("Link added")
with open(linksfile, 'w') as f:
content.write(f)
except ConfigParser.NoOptionError:
content.set(osys, lc, link)
+ self.log.debug("Link added (with new locale created)")
with open(linksfile, 'w') as f:
content.write(f)
- except ConfigParser.NoSectionError:
+ except ConfigParser.NoSectionError as e:
# this shouldn't happen, but just in case
- raise InternalError("Unknown %s section in links file" % osys)
+ self.log.debug("FAILED (OS not found)")
+ raise InternalError("Unknown section %s" % str(e))
else:
- raise LinkFileError("There is no links file for %s" % provider)
+ self.log.debug("FAILED (links file doesn't seem legit)")
+ raise LinkFileError("No links file for %s" % provider)
def add_request_to_db(self):
"""Add request to database."""
- self.db.add_request()
+ self.log.debug("Trying to add request to database")
+ try:
+ self.db.add_request()
+ self.log.debug("Request added!")
+ except db.DBError as e:
+ self.log.debug("FAILED %s" % str(e))
+ raise InternalError("Couldn't add request to database %s" % str(e))
diff --git a/gettor/db.py b/gettor/db.py
index e5e0acc..0b971af 100644
--- a/gettor/db.py
+++ b/gettor/db.py
@@ -17,6 +17,10 @@ import datetime
"""DB interface for comunicating with sqlite3"""
+class DBError(Exception):
+ pass
+
+
class DB(object):
"""
@@ -27,6 +31,11 @@ class DB(object):
add_user(): add a user to the database (users table).
update_user(): update a user on the database (users table).
+ Exceptions:
+
+ DBError: Something went wrong when trying to connect/interact
+ with the database.
+
"""
def __init__(self, dbname):
@@ -35,8 +44,11 @@ class DB(object):
:param: dbname (string) the path of the database.
"""
- self.con = sqlite3.connect(dbname)
- self.con.row_factory = sqlite3.Row
+ try:
+ self.con = sqlite3.connect(dbname)
+ self.con.row_factory = sqlite3.Row
+ except sqlite3.Error as e:
+ raise DBError("%s" % str(e))
def add_request(self):
"""Add a request to the database.
@@ -44,15 +56,18 @@ class DB(object):
For now we just count the number of requests we have received so far.
"""
- with self.con:
- cur = self.con.cursor()
- cur.execute("SELECT counter FROM requests WHERE id = 1")
- row = cur.fetchone()
- if row:
- cur.execute("UPDATE requests SET counter=? WHERE id=?",
- (row['counter']+1, 1))
- else:
- cur.execute("INSERT INTO requests VALUES(?, ?)", (1, 1))
+ try:
+ with self.con:
+ cur = self.con.cursor()
+ cur.execute("SELECT counter FROM requests WHERE id = 1")
+ row = cur.fetchone()
+ if row:
+ cur.execute("UPDATE requests SET counter=? WHERE id=?",
+ (row['counter']+1, 1))
+ else:
+ cur.execute("INSERT INTO requests VALUES(?, ?)", (1, 1))
+ except sqlite3.Error as e:
+ raise DBError("%s" % str(e))
def get_user(self, user, service):
"""Get user info from the database.
@@ -64,13 +79,16 @@ class DB(object):
(e.g. row['user']).
"""
- with self.con:
- cur = self.con.cursor()
- cur.execute("SELECT * FROM users WHERE id =? AND service =?",
- (user, service))
+ try:
+ with self.con:
+ cur = self.con.cursor()
+ cur.execute("SELECT * FROM users WHERE id =? AND service =?",
+ (user, service))
- row = cur.fetchone()
- return row
+ row = cur.fetchone()
+ return row
+ except sqlite3.Error as e:
+ raise DBError("%s" % str(e))
def add_user(self, user, service, blocked):
"""Add a user to the database.
@@ -83,10 +101,13 @@ class DB(object):
:param: blocked (int) one if user is blocked, zero otherwise.
"""
- with self.con:
- cur = self.con.cursor()
- cur.execute("INSERT INTO users VALUES(?,?,?,?,?)",
- (user, service, 1, blocked, str(time.time())))
+ try:
+ with self.con:
+ cur = self.con.cursor()
+ cur.execute("INSERT INTO users VALUES(?,?,?,?,?)",
+ (user, service, 1, blocked, str(time.time())))
+ except sqlite3.Error as e:
+ raise DBError("%s" % str(e))
def update_user(self, user, service, times, blocked):
"""Update a user on the database.
@@ -99,8 +120,11 @@ class DB(object):
:param: blocked (int) one if user is blocked, zero otherwise.
"""
- with self.con:
- cur = self.con.cursor()
- cur.execute("UPDATE users SET times =?, blocked =?,"
- " last_request =? WHERE id =? AND service =?",
- (times, blocked, str(time.time()), user, service))
+ try:
+ with self.con:
+ cur = self.con.cursor()
+ cur.execute("UPDATE users SET times =?, blocked =?,"
+ " last_request =? WHERE id =? AND service =?",
+ (times, blocked, str(time.time()), user, service))
+ except sqlite3.Error as e:
+ raise DBError("%s" % str(e))
diff --git a/gettor/utils.py b/gettor/utils.py
index cbf01ce..b4ab9c6 100644
--- a/gettor/utils.py
+++ b/gettor/utils.py
@@ -16,6 +16,25 @@ import hashlib
"""Common utilities for GetTor modules."""
+LOGGING_FORMAT = "[%(levelname)s] %(asctime)s - %(message)s"
+DATE_FORMAT = "%Y-%m-%d" # %H:%M:%S
+
+def get_logging_format():
+ """Get the logging format.
+
+ :return: (string) the logging format.
+
+ """
+ return LOGGING_FORMAT
+
+def get_date_format():
+ """Get the date format for logging.
+
+ :return: (string) the date format for logging.
+
+ """
+ return DATE_FORMAT
+
def get_sha256(string):
"""Get sha256 of a string.
1
0
commit 4ed9de8fe5760a60e04298d86bc05780ea7378eb
Author: ilv <ilv(a)users.noreply.github.com>
Date: Mon Aug 3 15:07:34 2015 -0300
Minor changes to drive script
---
upload/bundles2drive.py | 108 ++++++++++++++++++++++++++++-------------------
1 file changed, 65 insertions(+), 43 deletions(-)
diff --git a/upload/bundles2drive.py b/upload/bundles2drive.py
index 8c329bf..9612382 100644
--- a/upload/bundles2drive.py
+++ b/upload/bundles2drive.py
@@ -16,10 +16,11 @@ import re
import os
import gnupg
import hashlib
+import logging
import ConfigParser
import gettor.core
-#import google drive libs
+# import google drive libs
import httplib2
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
@@ -51,7 +52,7 @@ def valid_format(file, osys):
file)
elif(osys == 'osx'):
m = re.search(
- 'TorBrowser-\d\.\d\.\d-osx\d\d_(\w\w)(-\w\w)?\.dmg',
+ 'TorBrowser-\d\.\d\.\d-osx\d\d_(\w\w)(-\w\w)?\.dmg',
file)
if m:
return True
@@ -143,21 +144,21 @@ def upload_files(client, basedir):
for name in os.listdir(basedir):
path = os.path.abspath(os.path.join(basedir, name))
if os.path.isfile(path) and p.match(path)\
- and valid_format(name, 'linux'):
+ and valid_format(name, 'linux'):
files.append(name)
p = re.compile('.*\.exe$')
for name in os.listdir(basedir):
path = os.path.abspath(os.path.join(basedir, name))
if os.path.isfile(path) and p.match(path)\
- and valid_format(name, 'windows'):
+ and valid_format(name, 'windows'):
files.append(name)
p = re.compile('.*\.dmg$')
for name in os.listdir(basedir):
path = os.path.abspath(os.path.join(basedir, name))
if os.path.isfile(path) and p.match(path)\
- and valid_format(name, 'osx'):
+ and valid_format(name, 'osx'):
files.append(name)
# dictionary to store file names and IDs
@@ -173,33 +174,44 @@ def upload_files(client, basedir):
continue
# upload tor browser installer
- file_body = MediaFileUpload(abs_file, resumable=True)
+ file_body = MediaFileUpload(
+ abs_file,
+ mimetype="application/octet-stream",
+ resumable=True
+ )
body = {
- 'title': file
+ 'title': file
}
print "Uploading '%s'..." % file
try:
- file_data = drive_service.files().insert(body=body, media_body=file_body).execute()
+ file_data = drive_service.files().insert(
+ body=body,
+ media_body=file_body
+ ).execute()
except errors.HttpError, e:
print str(e)
# upload signature
asc_body = MediaFileUpload(abs_asc, resumable=True)
asc_head = {
- 'title': "%s.asc" % file
+ 'title': "%s.asc" % file
}
print "Uploading '%s'..." % asc
try:
- asc_data = drive_service.files().insert(body=asc_head, media_body=asc_body).execute()
+ asc_data = drive_service.files().insert(
+ body=asc_head,
+ media_body=asc_body
+ ).execute()
except errors.HttpError, e:
print str(e)
# add filenames and file id to dict
files_dict[file] = file_data['id']
- files_dict[asc] = asc_data['id']
+ files_dict[asc] = asc_data['id']
return files_dict
+
def share_file(service, file_id):
"""Make files public
@@ -207,26 +219,28 @@ def share_file(service, file_id):
link to file.
:param: file_id (string)
-
+
:return: (string) url to shared file
-
+
"""
permission = {
- 'type': "anyone",
- 'role': "reader",
- 'withLink': True
+ 'type': "anyone",
+ 'role': "reader",
+ 'withLink': True
}
-
+
try:
service.permissions().insert(
- fileId=file_id, body=permission).execute()
+ fileId=file_id,
+ body=permission
+ ).execute()
except errors.HttpError, error:
- print('An error occured while sharing: %s' % file_id)
+ print('An error occured while sharing: %s' % file_id)
try:
file = service.files().get(fileId=file_id).execute()
except errors.HttpError, error:
- print('Error occured while fetch public link for file: %s' % file_id)
+ print('Error occured while fetch public link for file: %s' % file_id)
print("Uploaded to %s" % file['webContentLink'])
return file['webContentLink']
@@ -250,29 +264,33 @@ if __name__ == '__main__':
print "Authenticating..."
- flow = OAuth2WebServerFlow(client_id, app_secret, OAUTH_SCOPE,
- redirect_uri=REDIRECT_URI)
+ flow = OAuth2WebServerFlow(
+ client_id,
+ app_secret,
+ OAUTH_SCOPE,
+ redirect_uri=REDIRECT_URI
+ )
# If no valid token found, need to prompt user.
# this should only occur once
if not refresh_token:
- flow.params['access_type'] = 'offline'
- flow.params['approval_prompt'] = 'force'
- authorize_url = flow.step1_get_authorize_url()
- print 'Go to the following link in your browser: ' + authorize_url
- code = raw_input('Enter verification code: ').strip()
- try:
- credentials = flow.step2_exchange(code)
- except FlowExchangeError as e:
- print str(e)
-
- # oauth2 credentials instance must be stored as json string
- config.set('app', 'refresh_token', credentials.to_json())
- with open('drive.cfg', 'wb') as configfile:
+ flow.params['access_type'] = 'offline'
+ flow.params['approval_prompt'] = 'force'
+ authorize_url = flow.step1_get_authorize_url()
+ print 'Go to the following link in your browser: ' + authorize_url
+ code = raw_input('Enter verification code: ').strip()
+ try:
+ credentials = flow.step2_exchange(code)
+ except FlowExchangeError as e:
+ print str(e)
+
+ # oauth2 credentials instance must be stored as json string
+ config.set('app', 'refresh_token', credentials.to_json())
+ with open('drive.cfg', 'wb') as configfile:
config.write(configfile)
else:
- # we already have a valid token
- credentials = Credentials.new_from_json(refresh_token)
+ # we already have a valid token
+ credentials = Credentials.new_from_json(refresh_token)
# authenticate with oauth2
http = httplib2.Http()
@@ -281,7 +299,6 @@ if __name__ == '__main__':
# initialize drive instance
drive_service = build('drive', 'v2', http=http)
-
# import key fingerprint
gpg = gnupg.GPG()
key_data = open(tbb_key).read()
@@ -309,7 +326,7 @@ if __name__ == '__main__':
for file in uploaded_files.keys():
# only run for tor browser installers
if p4.match(file):
- continue
+ continue
asc = "%s.asc" % file
abs_file = os.path.abspath(os.path.join(upload_dir, file))
abs_asc = os.path.abspath(os.path.join(upload_dir, asc))
@@ -317,10 +334,15 @@ if __name__ == '__main__':
sha_file = get_file_sha256(abs_file)
# build links
- link_file = share_file(drive_service,
- uploaded_files[file])
- link_asc = share_file(drive_service,
- uploaded_files["%s.asc" % file])
+ link_file = share_file(
+ drive_service,
+ uploaded_files[file]
+ )
+
+ link_asc = share_file(
+ drive_service,
+ uploaded_files["%s.asc" % file]
+ )
if p1.match(file):
osys, arch, lc = get_bundle_info(file, 'linux')
1
0
[gettor/master] Added direct link to downloads section in http(s) mirrors
by ilv@torproject.org 03 Nov '15
by ilv@torproject.org 03 Nov '15
03 Nov '15
commit 87758bd0ec34a52a995d0e5973ca81ebf61203d6
Author: ilv <ilv(a)users.noreply.github.com>
Date: Thu Aug 27 15:13:44 2015 -0300
Added direct link to downloads section in http(s) mirrors
---
get_mirrors.py | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/get_mirrors.py b/get_mirrors.py
index 9c4b0c4..afa4cc9 100644
--- a/get_mirrors.py
+++ b/get_mirrors.py
@@ -158,6 +158,15 @@ def is_json(my_json):
return True
+def add_tpo_link(url):
+ """Add the download link for Tor Browser."""
+ uri = 'projects/torbrowser.html.en#downloads'
+ if url.endswith('/'):
+ return "%s%s" % (url, uri)
+ else:
+ return "%s/%s" % (url, uri)
+
+
def add_entry(mirrors, columns, elements):
"""Add entry to mirrors list."""
entry = {}
@@ -172,9 +181,15 @@ def add_entry(mirrors, columns, elements):
def add_mirror(file, entry, proto):
"""Add mirror to mirrors list."""
+ # if proto requested is http(s), we add link to download section
+ if PROTOS[proto] == 'http' or PROTOS[proto] == 'https':
+ uri = add_tpo_link(entry[proto])
+ else:
+ uri = entry[proto]
+
file.write(
"%s - by %s (%s)\n" % (
- entry[proto],
+ uri,
entry['orgName'],
entry['subRegion'],
)
1
0
commit e81d9c681ba7998038a1ae626a00949766b498c7
Author: ilv <ilv(a)users.noreply.github.com>
Date: Mon Aug 3 15:05:53 2015 -0300
Send mirrors option
---
get_mirrors.py | 338 ++++++
gettor/smtp.py | 239 ++--
lang/smtp/i18n/en/LC_MESSAGES/en.po | 19 +
mirrors-list.txt | 58 +
smtp.cfg | 3 +-
tor-mirrors | 2187 +++++++++++++++++++++++++++++++++++
tor-mirrors.csv | 116 ++
7 files changed, 2867 insertions(+), 93 deletions(-)
diff --git a/get_mirrors.py b/get_mirrors.py
new file mode 100644
index 0000000..9c4b0c4
--- /dev/null
+++ b/get_mirrors.py
@@ -0,0 +1,338 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of GetTor
+#
+# :authors: Israel Leiva <ilv(a)torproject.org>
+# see also AUTHORS file
+#
+# :license: This is Free Software. See LICENSE for license information.
+
+"""get_mirrors -- Download the list of tpo's mirrors for GetTor."""
+
+import os
+import json
+import codecs
+import logging
+import argparse
+
+
+from OpenSSL import SSL
+from OpenSSL import crypto
+
+from twisted.web import client
+from twisted.python import log
+from twisted.internet import ssl
+from twisted.internet import defer
+from twisted.internet import protocol
+from twisted.internet import reactor
+from twisted.internet.error import TimeoutError
+from twisted.internet.error import DNSLookupError
+from twisted.internet.error import ConnectionRefusedError
+
+from gettor import utils
+
+# Associate each protocol with its column name in tor-mirrors.csv
+PROTOS = {
+ 'https': 'httpsWebsiteMirror',
+ 'http': 'httpWebsiteMirror',
+ 'rsync': 'rsyncWebsiteMirror',
+ 'https-dist': 'httpsDistMirror',
+ 'http-dist': 'httpDistMirror',
+ 'rsync-dist': 'rsyncDistMirror',
+ 'ftp': 'ftpWebsiteMirror',
+ 'onion': 'hiddenServiceMirror',
+}
+
+# Tor Project's website certificate
+# $ openssl s_client -showcerts -connect tpo:443 < /dev/null > tpo.pem
+CERT_TPO = '/path/to/gettor/tpo.pem'
+
+
+# Taken from get-tor-exits (BridgeDB)
+class FileWriter(protocol.Protocol):
+ """Read a downloaded file incrementally and write to file."""
+ def __init__(self, finished, file):
+ """Create a FileWriter.
+
+ .. warning:: We currently only handle the first 2MB of a file. Files
+ over 2MB will be truncated prematurely. *note*: this should be
+ enough for the mirrors file.
+
+ :param finished: A :class:`~twisted.internet.defer.Deferred` which
+ will fire when another portion of the download is complete.
+ """
+ self.finished = finished
+ self.remaining = 1024 * 1024 * 2
+ self.fh = file
+
+ def dataReceived(self, bytes):
+ """Write a portion of the download with ``bytes`` size to disk."""
+ if self.remaining:
+ display = bytes[:self.remaining]
+ self.fh.write(display)
+ self.fh.flush()
+ self.remaining -= len(display)
+
+ def connectionLost(self, reason):
+ """Called when the download is complete."""
+ logging.info('Finished receiving mirrors list: %s'
+ % reason.getErrorMessage())
+ self.finished.callback(None)
+
+
+# Based in tor2web.utils.ssl (Tor2web)
+class HTTPSVerifyingContextFactory(ssl.ClientContextFactory):
+ def __init__(self, cn):
+ self.cn = cn
+ #
+ # From https://docs.python.org/2/library/ssl.html#ssl-security
+ #
+ # "SSL versions 2 and 3 are considered insecure and are therefore
+ # dangerous to use. If you want maximum compatibility between clients
+ # and servers, it is recommended to use PROTOCOL_SSLv23 as the protocol
+ # version and then disable SSLv2 and SSLv3 explicitly"
+ #
+ self.method = SSL.SSLv23_METHOD
+
+ def getContext(self, hostname, port):
+ """Get this connection's OpenSSL context.
+
+ We disable SSLv2 and SSLv3. We also check the certificate received
+ is the one we expect (using the "common name").
+
+ """
+ ctx = self._contextFactory(self.method)
+ ctx.set_options(SSL.OP_NO_SSLv2)
+ ctx.set_options(SSL.OP_NO_SSLv3)
+ ctx.set_verify(
+ SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
+ self.verifyCN
+ )
+
+ return ctx
+
+ def verifyCN(self, connection, x509, errno, depth, preverifyOK):
+ # DEBUG: print "%s == %s ?" % (self.cn, x509.get_subject().commonName)
+
+ # Somehow, if I don't set this to true, the verifyCN doesn't go
+ # down in the chain, I don't know if this is OK
+ verify = True
+ if depth == 0:
+ if self.cn == x509.get_subject().commonName:
+ verify = True
+ else:
+ verify = False
+ return verify
+
+
+# Based in get-tor-exits (BridgeDB)
+def handle(failure):
+ """Handle a **failure**."""
+ if failure.type == ConnectionRefusedError:
+ logging.error("Couldn't download file; connection was refused.")
+ elif failure.type == DNSLookupError:
+ logging.error("Couldn't download file; domain resolution failed.")
+ elif failure.type == TimeoutError:
+ logging.error("Couldn't download file; connection timed out.")
+ else:
+ logging.error("Couldn't download file.")
+
+ print "Couldn't download file. Check the log."
+ os._exit(-1)
+
+
+# Taken from get-tor-exits (BridgeDB)
+def writeToFile(response, filename):
+ """Write requested content to filename."""
+ finished = defer.Deferred()
+ response.deliverBody(FileWriter(finished, filename))
+ return finished
+
+
+def is_json(my_json):
+ """Check if json generated is valid."""
+ try:
+ json_object = json.loads(my_json)
+ except ValueError, e:
+ return False
+ return True
+
+
+def add_entry(mirrors, columns, elements):
+ """Add entry to mirrors list."""
+ entry = {}
+ count = 0
+ for e in elements:
+ e = e.replace("\n", '')
+ entry[columns[count]] = e
+ count = count + 1
+
+ mirrors.append(entry)
+
+
+def add_mirror(file, entry, proto):
+ """Add mirror to mirrors list."""
+ file.write(
+ "%s - by %s (%s)\n" % (
+ entry[proto],
+ entry['orgName'],
+ entry['subRegion'],
+ )
+ )
+
+
+def main():
+ """Script to get the list of tpo's mirrors from tpo and adapt it to
+ be used by GetTor.
+
+ Usage: python2.7 get_mirrors.py [-h] [--proto protocol]
+
+ By default, the protocol is 'https'. Possible values of protcol are:
+
+ http, https, rsync, ftp, onion, http-dist, https-dist, rsync-dist.
+
+ """
+ parser = argparse.ArgumentParser(
+ description="Utility to download tpo's mirrors and make it usable\
+ by GetTor."
+ )
+
+ parser.add_argument(
+ '-p', '--proto',
+ default='https',
+ help='Protocol filter. Possible values: http, https, rsync, ftp, onion\
+ http-dist, https-dist, rsync-dist. Default to https.')
+
+ args = parser.parse_args()
+ p = args.proto
+
+ gettor_path = '/path/to/gettor/'
+ csv_path = os.path.join(gettor_path, 'tor-mirrors.csv')
+ json_path = os.path.join(gettor_path, 'tor-mirrors')
+ mirrors_list = os.path.join(gettor_path, 'mirrors-list.txt')
+
+ # Load tpo certificate and extract common name, we'll later compare this
+ # with the certificate sent by tpo to check we're really taltking to it
+ try:
+ data = open(CERT_TPO).read()
+ x509 = crypto.load_certificate(crypto.FILETYPE_PEM, data)
+ cn_tpo = x509.get_subject().commonName
+ except Exception as e:
+ logging.error("Error with certificate: %s" % str(e))
+ return
+
+ # While we wait the json of mirrors to be implemented in tpo, we need
+ # to download the csv file and transform it to json
+
+ # The code below is based in get-tor-exits script from BridgeDB and
+ # the tor2web.utils.ssl module from Tor2web
+ url = 'https://www.torproject.org/include/tor-mirrors.csv'
+
+ try:
+ fh = open(csv_path, 'w')
+ except IOError as e:
+ logging.error("Could not open %s" % csv_path)
+ return
+
+ logging.info("Requesting %s..." % url)
+
+ # If certificate don't match an exception will be raised
+ # this is my first experience with twisted, maybe I'll learn to handle
+ # this better some time in the future...
+ contextFactory = HTTPSVerifyingContextFactory(cn_tpo)
+ agent = client.Agent(reactor, contextFactory)
+ d = agent.request("GET", url)
+ d.addCallback(writeToFile, fh)
+ d.addErrback(handle)
+ d.addCallbacks(log.msg, log.err)
+
+ if not reactor.running:
+ d.addCallback(lambda ignored: reactor.stop())
+ reactor.run()
+
+ logging.info("File downloaded!")
+
+ # Now transform it to json -- I couldn't find out how to use a
+ # two-character delimiter with the csv package, so I decided to handle
+ # the csv data by hand. We are doing this until #16601 gets deployed.
+ # https://trac.torproject.org/projects/tor/ticket/16601
+
+ # Code below is based in update-mirrors-json.py script from tpo
+
+ # These are the names of each column e.g. adminContact
+ columns = []
+ # List of mirrors to be built
+ mirrors = []
+
+ logging.info("Transforming csv data into json...")
+ logging.info("Getting data from csv")
+ try:
+ with codecs.open(csv_path, "rb", "utf-8") as csvfile:
+ for line in csvfile:
+ elements = line.split(", ")
+ # first entry have the names of the columns
+ if not columns:
+ columns = elements
+ else:
+ add_entry(mirrors, columns, elements)
+ except IOError as e:
+ logging.error("Couldn't read csv file: %s" % str(e))
+ return
+
+ logging.info("Creating json")
+ if is_json(json.dumps(mirrors)):
+ try:
+ with codecs.open(json_path, "w", "utf-8") as jsonfile:
+ # Make pretty json
+ json.dump(
+ mirrors,
+ jsonfile,
+ sort_keys=True,
+ indent=4,
+ separators=(',', ': '),
+ encoding="utf-8",
+ )
+ except IOError as e:
+ logging.error("Couldn't write json: %s" % str(e))
+ return
+ else:
+ logging.error("Invalid json file")
+ return
+
+ # Now make the mirrors list to be used by GetTor
+ logging.info("Reading json")
+ try:
+ mirrors_json = codecs.open(json_path, "rb", "utf-8")
+ mirrors = json.load(mirrors_json)
+ except IOError as e:
+ logging.error("Couldn't open %s" % json_path)
+ return
+
+ logging.info("Creating new list with protocol: %s" % p)
+ try:
+ list = codecs.open(mirrors_list, "w", "utf-8")
+ for entry in mirrors:
+ if args.proto is not 'all':
+ for e in entry:
+ if e == PROTOS[p] and entry[PROTOS[p]]:
+ add_mirror(list, entry, PROTOS[p])
+ else:
+ for k, v in PROTOS:
+ if entry[v]:
+ add_mirror(list, entry, v)
+ logging.info("List created: %s" % mirrors_list)
+ except IOError as e:
+ logging.error("Couldn't open %s" % mirrors_list)
+ return
+
+if __name__ == "__main__":
+ logging_format = utils.get_logging_format()
+ logging.basicConfig(
+ filename='/path/to/gettor/log/get-mirrors.log',
+ format=logging_format,
+ datefmt="%Y-%m-%d %H:%M:%S",
+ level=logging.INFO
+ )
+ logging.info("Started")
+ main()
+ logging.info("Finished")
diff --git a/gettor/smtp.py b/gettor/smtp.py
index 655b5df..4db3ac7 100644
--- a/gettor/smtp.py
+++ b/gettor/smtp.py
@@ -22,7 +22,10 @@ import smtplib
import datetime
import ConfigParser
+from email import Encoders
+from email.MIMEBase import MIMEBase
from email.mime.text import MIMEText
+from email.MIMEMultipart import MIMEMultipart
import core
import utils
@@ -69,74 +72,60 @@ class SMTP(object):
:param: cfg (string) path of the configuration file.
"""
- # define a set of default values
- DEFAULT_CONFIG_FILE = 'smtp.cfg'
-
- logging.basicConfig(format='[%(levelname)s] %(asctime)s - %(message)s',
- datefmt="%Y-%m-%d %H:%M:%S")
- log = logging.getLogger(__name__)
+ default_cfg = 'smtp.cfg'
config = ConfigParser.ConfigParser()
if cfg is None or not os.path.isfile(cfg):
cfg = DEFAULT_CONFIG_FILE
- config.read(cfg)
+ try:
+ with open(cfg) as f:
+ config.readfp(f)
+ except IOError:
+ raise ConfigError("File %s not found!" % cfg)
try:
self.our_domain = config.get('general', 'our_domain')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'our_domain' from 'general'")
+ self.mirrors = config.get('general', 'mirrors')
+ self.i18ndir = config.get('i18n', 'dir')
- try:
- core_cfg = config.get('general', 'core_cfg')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'core_cfg' from 'general'")
+ logdir = config.get('log', 'dir')
+ logfile = os.path.join(logdir, 'smtp.log')
+ loglevel = config.get('log', 'level')
- try:
blacklist_cfg = config.get('blacklist', 'cfg')
self.bl = blacklist.Blacklist(blacklist_cfg)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'cfg' from 'blacklist'")
-
- try:
self.bl_max_req = config.get('blacklist', 'max_requests')
self.bl_max_req = int(self.bl_max_req)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'max_requests' from 'blacklist'")
-
- try:
self.bl_wait_time = config.get('blacklist', 'wait_time')
self.bl_wait_time = int(self.bl_wait_time)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'wait_time' from 'blacklist'")
- try:
- self.i18ndir = config.get('i18n', 'dir')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'i18n'")
+ core_cfg = config.get('general', 'core_cfg')
+ self.core = core.Core(core_cfg)
- try:
- logdir = config.get('log', 'dir')
- logfile = os.path.join(logdir, 'smtp.log')
except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'log'")
+ raise ConfigError("Configuration error: %s" % str(e))
+ except blacklist.ConfigError as e:
+ raise InternalError("Blacklist error: %s" % str(e))
+ except core.ConfigError as e:
+ raise InternalError("Core error: %s" % str(e))
- try:
- loglevel = config.get('log', 'level')
- except ConfigParser.Error as e:
- raise ConfigurationError("Couldn't read 'level' from 'log'")
+ # logging
+ log = logging.getLogger(__name__)
- # use default values
- self.core = core.Core(core_cfg)
+ logging_format = utils.get_logging_format()
+ date_format = utils.get_date_format()
+ formatter = logging.Formatter(logging_format, date_format)
- # establish log level and redirect to log file
- log.info('Redirecting logging to %s' % logfile)
+ log.info('Redirecting SMTP logging to %s' % logfile)
logfileh = logging.FileHandler(logfile, mode='a+')
+ logfileh.setFormatter(formatter)
logfileh.setLevel(logging.getLevelName(loglevel))
log.addHandler(logfileh)
# stop logging on stdout from now on
log.propagate = False
+ self.log = log
def _is_blacklisted(self, addr):
"""Check if a user is blacklisted.
@@ -148,8 +137,9 @@ class SMTP(object):
"""
try:
- self.bl.is_blacklisted(addr, 'SMTP', self.bl_max_req,
- self.bl_wait_time)
+ self.bl.is_blacklisted(
+ addr, 'SMTP', self.bl_max_req, self.bl_wait_time
+ )
return False
except blacklist.BlacklistError as e:
return True
@@ -228,11 +218,14 @@ class SMTP(object):
"""
# obtain the content in the proper language
- t = gettext.translation(lc, self.i18ndir, languages=[lc])
- _ = t.ugettext
+ try:
+ t = gettext.translation(lc, self.i18ndir, languages=[lc])
+ _ = t.ugettext
- msgstr = _(msgid)
- return msgstr
+ msgstr = _(msgid)
+ return msgstr
+ except IOError as e:
+ raise ConfigError("%s" % str(e))
def _parse_email(self, msg, addr):
"""Parse the email received.
@@ -270,17 +263,23 @@ class SMTP(object):
# core knows what OS are supported
supported_os = self.core.get_supported_os()
- # if no OS is found, help request by default
- found_os = False
+ # search for OS or mirrors request
+ # if nothing is found, help by default
+ found_request = False
lines = msg.split(' ')
for word in lines:
- if not found_os:
+ if not found_request:
+ # OS first
for os in supported_os:
if re.match(os, word, re.IGNORECASE):
req['os'] = os
req['type'] = 'links'
- found_os = True
+ found_request = True
break
+ # mirrors
+ if re.match("mirrors?", word, re.IGNORECASE):
+ req['type'] = 'mirrors'
+ found_request = True
else:
break
return req
@@ -298,15 +297,18 @@ class SMTP(object):
:return: (object) the email object.
"""
- email_obj = MIMEText(msg)
+ email_obj = MIMEMultipart()
email_obj.set_charset("utf-8")
email_obj['Subject'] = subject
email_obj['From'] = from_addr
email_obj['To'] = to_addr
+ msg_attach = MIMEText(msg, 'text')
+ email_obj.attach(msg_attach)
+
return email_obj
- def _send_email(self, from_addr, to_addr, subject, msg):
+ def _send_email(self, from_addr, to_addr, subject, msg, attach=None):
"""Send an email.
Take a 'from' and 'to' addresses, a subject and the content, creates
@@ -316,10 +318,27 @@ class SMTP(object):
:param: to_addr (string) the address of the recipient.
:param: subject (string) the subject of the email.
:param: msg (string) the content of the email.
+ :param: attach (string) the path of the mirrors list.
"""
email_obj = self._create_email(from_addr, to_addr, subject, msg)
+ if(attach):
+ # for now, the only email with attachment is the one for mirrors
+ try:
+ part = MIMEBase('application', "octet-stream")
+ part.set_payload(open(attach, "rb").read())
+ Encoders.encode_base64(part)
+
+ part.add_header(
+ 'Content-Disposition',
+ 'attachment; filename="mirrors.txt"'
+ )
+
+ email_obj.attach(part)
+ except IOError as e:
+ raise SendEmailError('Error with mirrors: %s' % str(e))
+
try:
s = smtplib.SMTP("localhost")
s.sendmail(from_addr, to_addr, email_obj.as_string())
@@ -341,17 +360,25 @@ class SMTP(object):
"""
# obtain the content in the proper language and send it
- links_subject = self._get_msg('links_subject', lc)
- links_msg = self._get_msg('links_msg', lc)
- links_msg = links_msg % (os, lc, links)
-
try:
- self._send_email(from_addr, to_addr, links_subject, links_msg)
+ links_subject = self._get_msg('links_subject', lc)
+ links_msg = self._get_msg('links_msg', lc)
+ links_msg = links_msg % (os, lc, links)
+
+ self._send_email(
+ from_addr,
+ to_addr,
+ links_subject,
+ links_msg,
+ None
+ )
+ except ConfigError as e:
+ raise InternalError("Error while getting message %s" % str(e))
except SendEmailError as e:
raise InternalError("Error while sending links message")
- def _send_help(self, lc, from_addr, to_addr):
- """Send help message.
+ def _send_mirrors(self, lc, from_addr, to_addr):
+ """Send mirrors message.
Get the message in the proper language (according to the locale),
replace variables (if any) and send the email.
@@ -362,37 +389,39 @@ class SMTP(object):
"""
# obtain the content in the proper language and send it
- help_subject = self._get_msg('help_subject', lc)
- help_msg = self._get_msg('help_msg', lc)
-
try:
- self._send_email(from_addr, to_addr, help_subject, help_msg)
+ mirrors_subject = self._get_msg('mirrors_subject', lc)
+ mirrors_msg = self._get_msg('mirrors_msg', lc)
+
+ self._send_email(
+ from_addr, to_addr, mirrors_subject, mirrors_msg, self.mirrors
+ )
+ except ConfigError as e:
+ raise InternalError("Error while getting message %s" % str(e))
except SendEmailError as e:
- raise InternalError("Error while sending help message")
+ raise InternalError("Error while sending mirrors message")
- def _send_unsupported_lc(self, lc, os, from_addr, to_addr):
- """Send unsupported locale message.
+ def _send_help(self, lc, from_addr, to_addr):
+ """Send help message.
- Get the message for unsupported locale in english, replace variables
- (if any) and send the email.
+ Get the message in the proper language (according to the locale),
+ replace variables (if any) and send the email.
:param: lc (string) the locale.
- :param: os (string) the operating system.
:param: from_addr (string) the address of the sender.
:param: to_addr (string) the address of the recipient.
"""
-
- # obtain the content in english and send it
- un_lc_subject = self._get_msg('unsupported_lc_subject', 'en')
- un_lc_msg = self._get_msg('unsupported_lc_msg', 'en')
- un_lc_msg = un_lc_msg % lc
-
+ # obtain the content in the proper language and send it
try:
- self._send_email(from_addr, to_addr, un_lc_subject, un_lc_msg)
+ help_subject = self._get_msg('help_subject', lc)
+ help_msg = self._get_msg('help_msg', lc)
+ self._send_email(from_addr, to_addr, help_subject, help_msg, None)
+ except ConfigError as e:
+ raise InternalError("Error while getting message %s" % str(e))
except SendEmailError as e:
- raise InternalError("Error while sending unsupported lc message")
+ raise InternalError("Error while sending help message")
def process_email(self, raw_msg):
"""Process the email received.
@@ -411,6 +440,7 @@ class SMTP(object):
links to the Core module.
"""
+ self.log.debug("Processing email")
parsed_msg = email.message_from_string(raw_msg)
content = self._get_content(parsed_msg)
from_addr = parsed_msg['From']
@@ -423,71 +453,96 @@ class SMTP(object):
# two ways for a request to be bogus: address malformed or
# blacklisted
try:
+ self.log.debug("Normalizing address...")
norm_from_addr = self._get_normalized_address(from_addr)
except AddressError as e:
status = 'malformed'
bogus_request = True
+ self.log.debug("Address is malformed!")
# it might be interesting to know what triggered this
# we are not logging this for now
# logfile = self._log_email('malformed', content)
if norm_from_addr:
+ self.log.debug("Anonymizing address...")
anon_addr = utils.get_sha256(norm_from_addr)
if self._is_blacklisted(anon_addr):
status = 'blacklisted'
bogus_request = True
+ self.log.debug("Address is blacklisted!")
# it might be interesting to know extra info
# we are not logging this for now
# logfile = self._log_email(anon_addr, content)
if not bogus_request:
# try to figure out what the user is asking
+ self.log.debug("Request seems legit; parsing it...")
req = self._parse_email(content, to_addr)
# our address should have the locale requested
our_addr = "gettor+%s@%s" % (req['lc'], self.our_domain)
+ self.log.debug("Replying from %s" % our_addr)
- # two possible options: asking for help or for the links
+ # possible options: help, links, mirrors
if req['type'] == 'help':
+ self.log.debug("Type of request: help")
+ self.log.debug("Trying to send help...")
# make sure we can send emails
try:
self._send_help(req['lc'], our_addr, norm_from_addr)
+ status = 'success'
except SendEmailError as e:
status = 'internal_error'
+ self.log.debug("FAILED: %s" % str(e))
raise InternalError("Something's wrong with the SMTP "
"server: %s" % str(e))
- elif req['type'] == 'links':
+ elif req['type'] == 'mirrors':
+ self.log.debug("Type of request: mirrors")
+ self.log.debug("Trying to send the mirrors...")
+ # make sure we can send emails
try:
- links = self.core.get_links('SMTP', req['os'],
- req['lc'])
-
- except core.UnsupportedLocaleError as e:
- # if we got here, the address of the sender should
- # be valid so we send him/her a message about the
- # unsupported locale
- status = 'unsupported_lc'
- self._send_unsupported_lc(req['lc'], req['os'],
- our_addr, norm_from_addr)
- return
+ self._send_mirrors(req['lc'], our_addr, norm_from_addr)
+ status = 'success'
+ except SendEmailError as e:
+ status = 'internal_error'
+ self.log.debug("FAILED: %s" % str(e))
+ raise SendEmailError("Something's wrong with the SMTP "
+ "server: %s" % str(e))
+ elif req['type'] == 'links':
+ self.log.debug("Type of request: links")
+ self.log.debug("Trying to obtain the links...")
+ try:
+ links = self.core.get_links(
+ 'SMTP', req['os'], req['lc']
+ )
# if core fails, we fail too
except (core.InternalError, core.ConfigurationError) as e:
status = 'core_error'
+ self.log.debug("FAILED: %s" % str(e))
# something went wrong with the core
raise InternalError("Error obtaining the links")
# make sure we can send emails
+ self.log.debug("Trying to send the links...")
try:
self._send_links(links, req['lc'], req['os'], our_addr,
norm_from_addr)
+ status = 'success'
except SendEmailError as e:
status = 'internal_error'
+ self.log.debug("FAILED: %s" % str(e))
raise SendEmailError("Something's wrong with the SMTP "
"server: %s" % str(e))
- status = 'success'
+ self.log.debug("Mail sent!")
finally:
# keep stats
if req:
- self.core.add_request_to_db()
+ self.log.debug("Adding request to database... ")
+ try:
+ self.core.add_request_to_db()
+ self.log.debug("Request added")
+ except InternalError as e:
+ self.log.debug("FAILED: %s" % str(e))
diff --git a/lang/smtp/i18n/en/LC_MESSAGES/en.po b/lang/smtp/i18n/en/LC_MESSAGES/en.po
index 906dbb8..dcb2e35 100644
--- a/lang/smtp/i18n/en/LC_MESSAGES/en.po
+++ b/lang/smtp/i18n/en/LC_MESSAGES/en.po
@@ -4,6 +4,10 @@ domain "en"
msgid "links_subject"
msgstr "[GetTor] Links for your request"
+#: Mirrors subject
+msgid "mirrors_subject"
+msgstr "[GetTor] Mirrors"
+
#: Help subject
msgid "help_subject"
msgstr "[GetTor] Help"
@@ -32,6 +36,21 @@ network, or need to talk to a human, please contact our support team at:\n\
We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
French and Spanish."
+#: Mirrors message
+msgid "mirrors_msg"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+Thank you for your request. Attached to this email you will find\n\
+an updated list of mirrors of Tor Project's website.\n\
+\n\
+Still need help? If you have any questions, trouble connecting to Tor\n\
+network, or need to talk to a human, please contact our support team at:\n\
+\n\
+ help(a)rt.torproject.org\n\
+\n\
+We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
+French and Spanish."
+
#: Help message
msgid "help_msg"
msgstr "Hello there! this is the 'GetTor' robot.\n\
diff --git a/mirrors-list.txt b/mirrors-list.txt
new file mode 100644
index 0000000..311a3a5
--- /dev/null
+++ b/mirrors-list.txt
@@ -0,0 +1,58 @@
+https://tor-mirror.de/ - by tor-mirror.de (Germany)
+https://tor.blingblingsquad.net/ - by [[:bbs:]] (Germany)
+https://tor.li/ - by Tor Supporter (Estonia)
+https://tormirror.tb-itf-tor.de - by TB-ITF (Germany)
+https://tormirror.piratenpartei-bayern.de - by Piratenpartei Bayern (Germany)
+https://tor.hoi-polloi.org/ - by Tor Supporter (Germany)
+https://tor.fodt.it - by FoDT.it (Austria)
+https://tor.zilog.es/ - by Tor Supporter (Spain)
+https://199.175.55.215/ - by Tor Supporter (United States)
+https://2607:8b00:2::6258:5c9/ - by Tor Supporter (United States)
+https://tor.spline.inf.fu-berlin.de/ - by spline (Germany)
+https://fbnaia.homelinux.net/torproject/ - by Tor Supporter (Mexico)
+https://mirror.unicorncloud.org/torproject.org/ - by UnicornCloud.org (Germany)
+https://tor.hackthissite.org/ - by HackThisSite.org (United States)
+https://tor.crazyhaze.de/ - by crazyhaze.de (Germany)
+https://creep.im/tor - by Soviet Anonymous (Russia)
+https://www.torservers.net/mirrors/torproject.org/ - by torservers (Germany)
+https://mirror.torland.me/torproject.org/ - by torland (United Kingdom)
+https://tor.myrl.net/ - by myRL.net (Iceland)
+https://torprojekt.userzap.de - by Userzap (Germany)
+https://tor.stalkr.net/ - by stalkr.net (France)
+https://tor-mirror.cyberguerrilla.org - by cYbergueRrilLa AnonyMous NeXus (Germany)
+https://torproject.gtor.org/ - by Gtor (Germany)
+https://torproject.nexiom.net - by SDL (United States)
+https://mirror.velcommuta.de/tor/ - by Tor Supporter (Germany)
+https://tor.eff.org - by EFF (United States)
+https://tor.void.gr - by Tor Supporter (Greece)
+https://reichster.de/mirrors/torproject.org - by Tor Supporter (Germany)
+https://tor.miglix.eu - by Tor Supporter (Germany)
+https://tor.fr33tux.org - by Tor Supporter (France)
+https://tor.iv.net.pl - by Sebastian M. Bobrecki (Poland)
+https://tor.static.lu - by d0wn.biz (France)
+https://www.moparisthebest.com/tor/ - by moparisthebest.com (Germany)
+https://ayo.tl/tor/ - by Tor Supporter (Iceland)
+https://tor.pajonzeck.de/ - by ITsn (Germany)
+https://tor.ludikovsky.name/ - by Tor Supporter (Austria)
+https://tor.nuclear-weapons.net - by Setec Administrator (Texas)
+https://tor.calyxinstitute.org - by The Calyx Institute (United States)
+https://mirror2.babylon.network/torproject/ - by Babylon Network (The Netherlands)
+https://mirror0.babylon.network/torproject/ - by Babylon Network (France)
+https://mirror1.babylon.network/torproject/ - by Babylon Network (France)
+https://tor.ybti.net/ - by Tor Supporter (Germany)
+https://tor.0x3d.lu/ - by 0x3d.lu (Germany)
+https://www.unicorncloud.org/public/torproject.org/ - by UnicornCloud.org (Favoriten)
+https://108.248.87.242/ - by intfxdx.com (United States)
+https://mirrors.samwhited.net/tor - by SamWhited.com (GA)
+https://www.jessevictors.com/secureMirrors/torproject.org/ - by Department of CS at USU (United States)
+https://mirror.ntzk.de/torproject.org/ - by Netzkonstrukt Berlin (Germany)
+https://www.eprci.com/tor/ - by EPRCI (NH)
+https://tor-mirror.kura.io/ - by KURA IO LIMITED (Netherlands)
+https://www.it-sicherheitschannel.de/ - by PW (Germany)
+https://tor.freedom.press - by Freedom of the Press Foundation (US)
+https://tor.hoovism.com/ - by Matthew Hoover (NJ)
+https://torproject.urown.net/ - by urown.net (Switzerland)
+https://sela.io/mirrors/torproject.org/ - by sela Internet (Germany)
+https://services.justaguy.pw/ - by Justaguy (The Netherlands)
+https://tor.thecthulhu.com/ - by TheCthulhu (The Netherlands)
+https://tor.ccc.de - by CCC (The Netherlands)
diff --git a/smtp.cfg b/smtp.cfg
index 671c090..a7e9f7a 100644
--- a/smtp.cfg
+++ b/smtp.cfg
@@ -1,5 +1,6 @@
[general]
basedir: /path/to/gettor/smtp
+mirrors: /path/to/mirrors
our_domain: torproject.org
core_cfg: /path/to/core.cfg
@@ -13,4 +14,4 @@ dir: /path/to/i18n/
[log]
level: DEBUG
-dir: /path/to/log/
\ No newline at end of file
+dir: /path/to/log/
diff --git a/tor-mirrors b/tor-mirrors
new file mode 100644
index 0000000..5dbd421
--- /dev/null
+++ b/tor-mirrors
@@ -0,0 +1,2187 @@
+[
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.loritsu.com/dist/",
+ "httpWebsiteMirror": "http://tor.loritsu.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.adamas.ai/dist/",
+ "httpWebsiteMirror": "http://torproject.adamas.ai/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "LU",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "LU",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Luxemborg",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torua.reactor-xg.kiev.ua/dist/",
+ "httpWebsiteMirror": "http://torua.reactor-xg.kiev.ua/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "UA",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "UA",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Ukraine",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://37.187.0.127/tormirror/dist/",
+ "httpWebsiteMirror": "http://37.187.0.127/tormirror/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.minibofh.org/dist/",
+ "httpWebsiteMirror": "http://tor.minibofh.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mage.me.uk/dist/",
+ "httpWebsiteMirror": "http://tor.mage.me.uk/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "UK",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "UK",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United Kingdom",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "nsane2307 eml cc",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-mirror.de/dist/",
+ "httpWebsiteMirror": "http://tor-mirror.de/",
+ "httpsDistMirror": "https://tor-mirror.de/dist/",
+ "httpsWebsiteMirror": "https://tor-mirror.de/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "tor-mirror.de",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "citizen428 AT gmail DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.blingblingsquad.net/dist/",
+ "httpWebsiteMirror": "http://tor.blingblingsquad.net/",
+ "httpsDistMirror": "https://tor.blingblingsquad.net/dist/",
+ "httpsWebsiteMirror": "https://tor.blingblingsquad.net/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "[[:bbs:]]",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.nwlinux.us/dist/",
+ "httpWebsiteMirror": "http://torproject.nwlinux.us/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "NW Linux",
+ "region": "US",
+ "rsyncDistMirror": "rsync://nwlinux.us/tor-dist",
+ "rsyncWebsiteMirror": "rsync://nwlinux.us/tor-web",
+ "subRegion": "WA",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "",
+ "httpsDistMirror": "https://www.coevoet.nl/tor/dist/",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "NL",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.taiga-san.net/dist/",
+ "httpWebsiteMirror": "http://tor.taiga-san.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "LazyTiger",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.li/dist/",
+ "httpWebsiteMirror": "http://tor.li/",
+ "httpsDistMirror": "https://tor.li/dist/",
+ "httpsWebsiteMirror": "https://tor.li/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "EE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "EE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Estonia",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.externenpr\u00fcfung-nichtsch\u00fcler.de/dist/",
+ "httpWebsiteMirror": "http://tor.externenpr\u00fcfung-nichtsch\u00fcler.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "mirror-service(a)netcologne.de",
+ "ftpWebsiteMirror": "ftp://mirror.netcologne.de/torproject.org/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.netcologne.de/torproject.org/dist",
+ "httpWebsiteMirror": "http://mirror.netcologne.de/torproject.org",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "NetCologne GmbH",
+ "region": "",
+ "rsyncDistMirror": "rsync://mirror.netcologne.de/torproject.org/dist",
+ "rsyncWebsiteMirror": "rsync://mirror.netcologne.de/torproject.org",
+ "subRegion": "NRW",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "admin AT netgull DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.netgull.com/torproject/",
+ "httpWebsiteMirror": "",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "NetGull",
+ "region": "North America",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "mirrors[at]ip-connect[dot]vn[dot]ua",
+ "ftpWebsiteMirror": "ftp://torproject.ip-connect.vn.ua/mirror/torproject/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.ip-connect.vn.ua/dist",
+ "httpWebsiteMirror": "http://torproject.ip-connect.vn.ua",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "UA",
+ "loadBalanced": "Yes",
+ "orgName": "IP-Connect LLC",
+ "region": "",
+ "rsyncDistMirror": "rsync://torproject.ip-connect.vn.ua/torproject/dist",
+ "rsyncWebsiteMirror": "rsync://torproject.ip-connect.vn.ua/torproject",
+ "subRegion": "VN",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "torsupport AT tb-itf DOT de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tormirror.tb-itf-tor.de/dist/",
+ "httpWebsiteMirror": "http://tormirror.tb-itf-tor.de",
+ "httpsDistMirror": "https://tormirror.tb-itf-tor.de/dist/",
+ "httpsWebsiteMirror": "https://tormirror.tb-itf-tor.de",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "TB-ITF",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "admin at koreswatanabe dottnet",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-relay.koreswatanabe.net/dist/",
+ "httpWebsiteMirror": "http://tor-relay.koreswatanabe.net",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "RO",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "RO",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Romania",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "calebcenter(a)live.com",
+ "ftpWebsiteMirror": "ftp://ftp.calebxu.tk",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.calebxu.tk/dist",
+ "httpWebsiteMirror": "http://tor.calebxu.tk",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "NO",
+ "orgName": "calebxu.tk",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "rsync://calebxu.tk/tor",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "maki(a)maki-chan.de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mirrors.maki-chan.de/dist/",
+ "httpWebsiteMirror": "http://tor.mirrors.maki-chan.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Maki Hoshisawa",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Sat Aug 23 08:09:07 2014"
+ },
+ {
+ "adminContact": "info AT zentrum-der-gesundheit DOT de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.idnr.ws/dist/",
+ "httpWebsiteMirror": "http://tor.idnr.ws/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DK",
+ "loadBalanced": "No",
+ "orgName": "Zentrum der Gesundheit",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Denmark",
+ "updateDate\n": "Tue Sep 2 11:16:00 2014"
+ },
+ {
+ "adminContact": "info /AT enn /DOT lu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://btn6gqzqevlhoryd.onion",
+ "httpDistMirror": "http://torproject.lu/dist/",
+ "httpWebsiteMirror": "http://torproject.lu/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "Frenn vun der Enn A.S.B.L.",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Piratenpartei Bayern",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tormirror.piratenpartei-bayern.de/dist/",
+ "httpWebsiteMirror": "http://tormirror.piratenpartei-bayern.de",
+ "httpsDistMirror": "https://tormirror.piratenpartei-bayern.de/dist/",
+ "httpsWebsiteMirror": "https://tormirror.piratenpartei-bayern.de",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Piratenpartei Bayern",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.hoi-polloi.org/dist/",
+ "httpWebsiteMirror": "http://tor.hoi-polloi.org",
+ "httpsDistMirror": "https://tor.hoi-polloi.org/dist/",
+ "httpsWebsiteMirror": "https://tor.hoi-polloi.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)fodt.it // FoDT.it Webteam",
+ "ftpWebsiteMirror": "ftp://ftp.fodt.it/pub/mirrors/torproject.org/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.fodt.it/dist/",
+ "httpWebsiteMirror": "http://tor.fodt.it",
+ "httpsDistMirror": "https://tor.fodt.it/dist/",
+ "httpsWebsiteMirror": "https://tor.fodt.it",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "FoDT.it",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Mon Aug 25 10:19:07 2014"
+ },
+ {
+ "adminContact": "http://www.multinet.no",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.multinet.no/dist/",
+ "httpWebsiteMirror": "http://tor.multinet.no/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "NO",
+ "loadBalanced": "No",
+ "orgName": "MultiNet AS",
+ "region": "Trondheim",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Trondheim",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "haskell at gmx.es",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.zilog.es/dist/",
+ "httpWebsiteMirror": "http://tor.zilog.es/",
+ "httpsDistMirror": "https://tor.zilog.es/dist/",
+ "httpsWebsiteMirror": "https://tor.zilog.es/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "ES",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Spain",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://199.175.55.215/dist/",
+ "httpWebsiteMirror": "http://199.175.55.215/",
+ "httpsDistMirror": "https://199.175.55.215/dist/",
+ "httpsWebsiteMirror": "https://199.175.55.215/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://2607:8b00:2::6258:5c9/dist/",
+ "httpWebsiteMirror": "http://2607:8b00:2::6258:5c9/",
+ "httpsDistMirror": "https://2607:8b00:2::6258:5c9/dist/",
+ "httpsWebsiteMirror": "https://2607:8b00:2::6258:5c9/",
+ "ipv4": "FALSE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "margus.random at mail.ee",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://cyberside.net.ee/tor/",
+ "httpWebsiteMirror": "http://cyberside.planet.ee/tor/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "EE",
+ "loadBalanced": "No",
+ "orgName": "CyberSIDE",
+ "region": "EE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Estonia",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.torproject.is/dist/",
+ "httpWebsiteMirror": "http://www.torproject.is/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "torproject.is",
+ "region": "IS",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "ftp://ftp.spline.de/pub/tor",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.spline.de/dist/",
+ "httpWebsiteMirror": "http://tor.spline.de/",
+ "httpsDistMirror": "https://tor.spline.inf.fu-berlin.de/dist/",
+ "httpsWebsiteMirror": "https://tor.spline.inf.fu-berlin.de/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "spline",
+ "region": "DE",
+ "rsyncDistMirror": "rsync://ftp.spline.de/tor/dist",
+ "rsyncWebsiteMirror": "rsync://ftp.spline.de/tor",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.me0w.cc/dist/",
+ "httpWebsiteMirror": "http://tor.me0w.cc/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "RO",
+ "loadBalanced": "No",
+ "orgName": "me0w.cc",
+ "region": "RO",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Romania",
+ "updateDate\n": "Thu Jan 1 16:17:56 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.borgmann.tv/dist/",
+ "httpWebsiteMirror": "http://tor.borgmann.tv/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "borgmann.tv",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Sun Jul 12 19:04:44 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.dont-know-me.at/dist/",
+ "httpWebsiteMirror": "http://tor.dont-know-me.at/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "AT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "coralcdn.org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.torproject.org.nyud.net/dist/",
+ "httpWebsiteMirror": "http://www.torproject.org.nyud.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "INT",
+ "loadBalanced": "Yes",
+ "orgName": "CoralCDN",
+ "region": "INT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "International",
+ "updateDate\n": "Thu Jan 8 02:01:06 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.ph3x.at/dist/",
+ "httpWebsiteMirror": "http://torproject.ph3x.at/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "AT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://fbnaia.homelinux.net/torproject/dist/",
+ "httpWebsiteMirror": "http://fbnaia.homelinux.net/torproject/",
+ "httpsDistMirror": "https://fbnaia.homelinux.net/torproject/dist/",
+ "httpsWebsiteMirror": "https://fbnaia.homelinux.net/torproject/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "MX",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "MX",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Mexico",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "webmaster AT askapache DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.askapache.com/dist/",
+ "httpWebsiteMirror": "http://tor.askapache.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "AskApache",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "California",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mirror.chekanov.net/dist/",
+ "httpWebsiteMirror": "http://tor.mirror.chekanov.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "kontakt AT unicorncloud DOT org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.unicorncloud.org/torproject.org/dist",
+ "httpWebsiteMirror": "http://mirror.unicorncloud.org/torproject.org/",
+ "httpsDistMirror": "https://mirror.unicorncloud.org/torproject.org/dist",
+ "httpsWebsiteMirror": "https://mirror.unicorncloud.org/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "UnicornCloud.org",
+ "region": "Falkenstein",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "root AT amorphis DOT eu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.amorphis.eu/dist/",
+ "httpWebsiteMirror": "http://tor.amorphis.eu/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "Amorphis",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "hackthissite.org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.hackthissite.org/tor",
+ "httpWebsiteMirror": "http://tor.hackthissite.org/",
+ "httpsDistMirror": "https://mirror.hackthissite.org/tor",
+ "httpsWebsiteMirror": "https://tor.hackthissite.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "HackThisSite.org",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "paul at coffswifi.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.coffswifi.net/dist",
+ "httpWebsiteMirror": "http://torproject.coffswifi.net",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AU",
+ "loadBalanced": "No",
+ "orgName": "CoffsWiFi",
+ "region": "APNIC",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Australia and New Zealand",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "http://tor.cyberarmy.at/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "cyberarmy",
+ "region": "AT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "hostmaster AT example DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.theonionrouter.com/dist/",
+ "httpWebsiteMirror": "http://www.theonionrouter.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "TheOnionRouter",
+ "region": "Iceland",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.crazyhaze.de/dist/",
+ "httpWebsiteMirror": "http://tor.crazyhaze.de/",
+ "httpsDistMirror": "https://tor.crazyhaze.de/dist/",
+ "httpsWebsiteMirror": "https://tor.crazyhaze.de/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "crazyhaze.de",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Tue Jul 7 13:16:29 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirrors.chaos-darmstadt.de/tor-mirror/dist/",
+ "httpWebsiteMirror": "http://mirrors.chaos-darmstadt.de/tor-mirror/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "chaos darmstadt",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "ftp://creep.im/mirrors/tor",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://creep.im/tor/dist/",
+ "httpWebsiteMirror": "http://creep.im/tor",
+ "httpsDistMirror": "https://creep.im/tor/dist/",
+ "httpsWebsiteMirror": "https://creep.im/tor",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "RU",
+ "loadBalanced": "No",
+ "orgName": "Soviet Anonymous",
+ "region": "RU",
+ "rsyncDistMirror": "rsync://creep.im/tor-dist",
+ "rsyncWebsiteMirror": "rsync://creep.im/tor",
+ "subRegion": "Russia",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://hbpvnydyyjbmhx6b.onion/mirrors/torproject.org/",
+ "httpDistMirror": "http://www.torservers.net/mirrors/torproject.org/dist/",
+ "httpWebsiteMirror": "http://www.torservers.net/mirrors/torproject.org/",
+ "httpsDistMirror": "https://www.torservers.net/mirrors/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://www.torservers.net/mirrors/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "torservers",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.torland.me/torproject.org/dist/",
+ "httpWebsiteMirror": "http://mirror.torland.me/torproject.org/",
+ "httpsDistMirror": "https://mirror.torland.me/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://mirror.torland.me/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "GB",
+ "loadBalanced": "No",
+ "orgName": "torland",
+ "region": "GB",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United Kingdom",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.lightning-bolt.net/dist/",
+ "httpWebsiteMirror": "http://torproject.lightning-bolt.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "CZ",
+ "loadBalanced": "No",
+ "orgName": "Lightning-bolt.net",
+ "region": "CZ",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Czech Republic",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "IceBear",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.myrl.net/dist/",
+ "httpWebsiteMirror": "http://tor.myrl.net/",
+ "httpsDistMirror": "https://tor.myrl.net/dist/",
+ "httpsWebsiteMirror": "https://tor.myrl.net/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "myRL.net",
+ "region": "IS",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "kiro AT userzap DOT de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torprojekt.userzap.de/dist/",
+ "httpWebsiteMirror": "http://torprojekt.userzap.de",
+ "httpsDistMirror": "https://torprojekt.userzap.de/dist/",
+ "httpsWebsiteMirror": "https://torprojekt.userzap.de",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Userzap",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "tor(a)les.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.les.net/dist",
+ "httpWebsiteMirror": "http://tor.les.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "CA",
+ "loadBalanced": "NO",
+ "orgName": "tor(a)les.net",
+ "region": "CA",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Canada",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)stalkr.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.stalkr.net/dist/",
+ "httpWebsiteMirror": "http://tor.stalkr.net/",
+ "httpsDistMirror": "https://tor.stalkr.net/dist/",
+ "httpsWebsiteMirror": "https://tor.stalkr.net/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "NO",
+ "orgName": "stalkr.net",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "doemela[AT]cyberguerrilla[DOT]org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://6dvj6v5imhny3anf.onion",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "",
+ "httpsDistMirror": "https://tor-mirror.cyberguerrilla.org/dist/",
+ "httpsWebsiteMirror": "https://tor-mirror.cyberguerrilla.org",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "cYbergueRrilLa AnonyMous NeXus",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "contact(a)gtor.org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.gtor.org/dist/",
+ "httpWebsiteMirror": "http://torproject.gtor.org/",
+ "httpsDistMirror": "https://torproject.gtor.org/dist/",
+ "httpsWebsiteMirror": "https://torproject.gtor.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Gtor",
+ "region": "DE",
+ "rsyncDistMirror": "rsync://torproject.gtor.org/website-mirror/dist/",
+ "rsyncWebsiteMirror": "rsync://torproject.gtor.org/website-mirror/",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "SDL",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.nexiom.net",
+ "httpWebsiteMirror": "http://torproject.nexiom.net",
+ "httpsDistMirror": "https://torproject.nexiom.net/dist",
+ "httpsWebsiteMirror": "https://torproject.nexiom.net",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "NO",
+ "orgName": "SDL",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.velcommuta.de/tor/dist/",
+ "httpWebsiteMirror": "http://mirror.velcommuta.de/tor/",
+ "httpsDistMirror": "https://mirror.velcommuta.de/tor/dist/",
+ "httpsWebsiteMirror": "https://mirror.velcommuta.de/tor/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "EFF",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "",
+ "httpsDistMirror": "https://tor.eff.org/dist/",
+ "httpsWebsiteMirror": "https://tor.eff.org",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "NO",
+ "orgName": "EFF",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.void.gr/dist/",
+ "httpWebsiteMirror": "http://tor.void.gr",
+ "httpsDistMirror": "https://tor.void.gr/dist/",
+ "httpsWebsiteMirror": "https://tor.void.gr",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "GR",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "GR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Greece",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Ich Eben",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://reichster.de/mirrors/torproject.org/dist/",
+ "httpWebsiteMirror": "http://reichster.de/mirrors/torproject.org/",
+ "httpsDistMirror": "https://reichster.de/mirrors/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://reichster.de/mirrors/torproject.org",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "jlgaddis AT gnu DOT org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor1.evilrouters.net/dist/",
+ "httpWebsiteMirror": "http://tor1.evilrouters.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Evil Routers",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor AT miglix DOT eu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.miglix.eu/dist/",
+ "httpWebsiteMirror": "http://tor.miglix.eu",
+ "httpsDistMirror": "https://tor.miglix.eu/dist/",
+ "httpsWebsiteMirror": "https://tor.miglix.eu",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor TA ninurta TOD name",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ninurta.name/dist/",
+ "httpWebsiteMirror": "http://tor.ninurta.name/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "AT",
+ "loadBalanced": "no",
+ "orgName": "TorNinurtaName",
+ "region": "AT",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Austria",
+ "updateDate\n": "Wed Oct 22 15:02:17 2014"
+ },
+ {
+ "adminContact": "fr33tux <AT> general-changelog-team.fr",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.fr33tux.org/dist/",
+ "httpWebsiteMirror": "http://tor.fr33tux.org",
+ "httpsDistMirror": "https://tor.fr33tux.org/dist/",
+ "httpsWebsiteMirror": "https://tor.fr33tux.org",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "sebastian(at)bobrecki(dot)pl",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.iv.net.pl/dist/",
+ "httpWebsiteMirror": "http://tor.iv.net.pl",
+ "httpsDistMirror": "https://tor.iv.net.pl/dist/",
+ "httpsWebsiteMirror": "https://tor.iv.net.pl",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "PL",
+ "loadBalanced": "No",
+ "orgName": "Sebastian M. Bobrecki",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Poland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor-mirror AT rdns DOT cc",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.static.lu/dist/",
+ "httpWebsiteMirror": "http://tor.static.lu",
+ "httpsDistMirror": "https://tor.static.lu/dist/",
+ "httpsWebsiteMirror": "https://tor.static.lu",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "d0wn.biz",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)moparisthebest.com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.moparisthebest.com/tor/dist/",
+ "httpWebsiteMirror": "http://www.moparisthebest.com/tor/",
+ "httpsDistMirror": "https://www.moparisthebest.com/tor/dist/",
+ "httpsWebsiteMirror": "https://www.moparisthebest.com/tor/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "moparisthebest.com",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Sebastian",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.maxanoo.com/dist/",
+ "httpWebsiteMirror": "http://tor.maxanoo.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "NO",
+ "orgName": "Maxanoo",
+ "region": "Amsterdam",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Sun May 31 15:13:53 2015"
+ },
+ {
+ "adminContact": "rorrim AT ayo DOT tl",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://ayo.tl/tor/dist/",
+ "httpWebsiteMirror": "http://ayo.tl/tor/",
+ "httpsDistMirror": "https://ayo.tl/tor/dist/",
+ "httpsWebsiteMirror": "https://ayo.tl/tor/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "IS",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Iceland",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "stefano.fenoglio AT gmail DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.stefanof.com/dist",
+ "httpWebsiteMirror": "http://tor.stefanof.com",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "IT",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Italy",
+ "updateDate\n": "Sun Jul 12 13:19:35 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ramosresearch.com/dist/",
+ "httpWebsiteMirror": "http://tor.ramosresearch.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Ramos Research",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "Tor Fan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.euve33747.vserver.de/dist",
+ "httpWebsiteMirror": "http://tor.euve33747.vserver.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "s7r[at]sky-ip[d0t]org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://beautiful-mind.sky-ip.org/dist/",
+ "httpWebsiteMirror": "http://beautiful-mind.sky-ip.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "sky-ip.org",
+ "region": "NL",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor#pajonzeck#de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://zgfgvob256pffy62.onion",
+ "httpDistMirror": "http://tor.pajonzeck.de/dist/",
+ "httpWebsiteMirror": "http://tor.pajonzeck.de/",
+ "httpsDistMirror": "https://tor.pajonzeck.de/dist/",
+ "httpsWebsiteMirror": "https://tor.pajonzeck.de/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "ITsn",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://tor.pajonzeck.de/tor/dist",
+ "rsyncWebsiteMirror": "rsync://tor.pajonzeck.de/tor",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "peter AT ludikovsky DOT name",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://54lnbzjo6xlr4f4j.onion/",
+ "httpDistMirror": "http://tor.ludikovsky.name/dist",
+ "httpWebsiteMirror": "http://tor.ludikovsky.name/",
+ "httpsDistMirror": "https://tor.ludikovsky.name/dist",
+ "httpsWebsiteMirror": "https://tor.ludikovsky.name/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://tor.ludikovsky.name/tor-dist",
+ "rsyncWebsiteMirror": "rsync://tor.ludikovsky.name/tor",
+ "subRegion": "Austria",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "admin AT nuclear DASH weapons DOT net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.nuclear-weapons.net/dist",
+ "httpWebsiteMirror": "http://tor.nuclear-weapons.net",
+ "httpsDistMirror": "https://tor.nuclear-weapons.net/dist",
+ "httpsWebsiteMirror": "https://tor.nuclear-weapons.net",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Setec Administrator",
+ "region": "Austin",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Texas",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "0x43DE8191",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.hactar.bz/dist/",
+ "httpWebsiteMirror": "http://torproject.hactar.bz",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "-nick at calyx dot com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://tmdrhl4e4anhsjc5.onion",
+ "httpDistMirror": "http://tor.calyxinstitute.org/dist/",
+ "httpWebsiteMirror": "http://tor.calyxinstitute.org",
+ "httpsDistMirror": "https://tor.calyxinstitute.org/dist/",
+ "httpsWebsiteMirror": "https://tor.calyxinstitute.org",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "The Calyx Institute",
+ "region": "North America",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "opi(a)zeropi.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-mirror.zeropi.net/dist/",
+ "httpWebsiteMirror": "http://tor-mirror.zeropi.net/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Mon Dec 1 12:15:20 2014"
+ },
+ {
+ "adminContact": "noc AT babylon DOT network",
+ "ftpWebsiteMirror": "ftp://mirror2.babylon.network/torproject/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror2.babylon.network/torproject/dist/",
+ "httpWebsiteMirror": "http://mirror2.babylon.network/torproject/",
+ "httpsDistMirror": "https://mirror2.babylon.network/torproject/dist/",
+ "httpsWebsiteMirror": "https://mirror2.babylon.network/torproject/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "Babylon Network",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://mirror2.babylon.network/torproject/dist/",
+ "rsyncWebsiteMirror": "rsync://mirror2.babylon.network/torproject/",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "noc AT babylon DOT network",
+ "ftpWebsiteMirror": "ftp://mirror0.babylon.network/torproject/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror0.babylon.network/torproject/dist/",
+ "httpWebsiteMirror": "http://mirror0.babylon.network/torproject/",
+ "httpsDistMirror": "https://mirror0.babylon.network/torproject/dist/",
+ "httpsWebsiteMirror": "https://mirror0.babylon.network/torproject/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Babylon Network",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://mirror0.babylon.network/torproject/dist/",
+ "rsyncWebsiteMirror": "rsync://mirror0.babylon.network/torproject/",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "noc AT babylon DOT network",
+ "ftpWebsiteMirror": "ftp://mirror1.babylon.network/torproject/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror1.babylon.network/torproject/dist/",
+ "httpWebsiteMirror": "http://mirror1.babylon.network/torproject/",
+ "httpsDistMirror": "https://mirror1.babylon.network/torproject/dist/",
+ "httpsWebsiteMirror": "https://mirror1.babylon.network/torproject/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Babylon Network",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://mirror1.babylon.network/torproject/dist/",
+ "rsyncWebsiteMirror": "rsync://mirror1.babylon.network/torproject/",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "alexander AT dietrich DOT cx",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ybti.net/dist/",
+ "httpWebsiteMirror": "http://tor.ybti.net/",
+ "httpsDistMirror": "https://tor.ybti.net/dist/",
+ "httpsWebsiteMirror": "https://tor.ybti.net/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)0x3d.lu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.0x3d.lu/dist/",
+ "httpWebsiteMirror": "http://tor.0x3d.lu/",
+ "httpsDistMirror": "https://tor.0x3d.lu/dist/",
+ "httpsWebsiteMirror": "https://tor.0x3d.lu/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "0x3d.lu",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "kraai(a)ftbfs.org 0xADCE6065",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ftbfs.org/dist/",
+ "httpWebsiteMirror": "http://tor.ftbfs.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "SE",
+ "loadBalanced": "No",
+ "orgName": "",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Sweden",
+ "updateDate\n": "Fri Oct 24 08:28:32 2014"
+ },
+ {
+ "adminContact": "kontakt(a)unicorncloud.org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://www.unicorncloud.org/public/torproject.org/dist",
+ "httpWebsiteMirror": "http://www.unicorncloud.org/public/torproject.org/",
+ "httpsDistMirror": "https://www.unicorncloud.org/public/torproject.org/dist",
+ "httpsWebsiteMirror": "https://www.unicorncloud.org/public/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "AT",
+ "loadBalanced": "No",
+ "orgName": "UnicornCloud.org",
+ "region": "Wien",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Favoriten",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "James Murphy",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://108.248.87.242/dist/",
+ "httpWebsiteMirror": "http://108.248.87.242/",
+ "httpsDistMirror": "https://108.248.87.242/dist/",
+ "httpsWebsiteMirror": "https://108.248.87.242/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "intfxdx.com",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Sam Whited 4096R/54083AE104EA7AD3 <sam(a)samwhited.com>",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirrors.samwhited.net/tor/dist",
+ "httpWebsiteMirror": "http://mirrors.samwhited.net/tor",
+ "httpsDistMirror": "https://mirrors.samwhited.net/tor/dist",
+ "httpsWebsiteMirror": "https://mirrors.samwhited.net/tor",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "FALSE",
+ "orgName": "SamWhited.com",
+ "region": "United States",
+ "rsyncDistMirror": "rsync://mirrors.samwhited.net/tor-dist",
+ "rsyncWebsiteMirror": "rsync://mirrors.samwhited.net/tor",
+ "subRegion": "GA",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "rohit008 AT e DOT ntu DOT edu DOT sg",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://torproject.ntuoss.com/dist/",
+ "httpWebsiteMirror": "http://torproject.ntuoss.com/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "SG",
+ "loadBalanced": "No",
+ "orgName": "NTUOSS",
+ "region": "Asia",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Singapore",
+ "updateDate\n": "Mon Mar 16 15:53:03 2015"
+ },
+ {
+ "adminContact": "jvictors at jessevictors dot com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-relay.cs.usu.edu/mirrors/torproject.org/dist/",
+ "httpWebsiteMirror": "http://tor-relay.cs.usu.edu/mirrors/torproject.org/",
+ "httpsDistMirror": "https://www.jessevictors.com/secureMirrors/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://www.jessevictors.com/secureMirrors/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Department of CS at USU",
+ "region": "North America",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Jacob Henner",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ventricle.us/dist/",
+ "httpWebsiteMirror": "http://tor.ventricle.us/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "TRUE",
+ "orgName": "Anatomical Networks",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "hostmaster(a)lucidnetworks.net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mirrors.lucidnetworks.net/dist",
+ "httpWebsiteMirror": "http://tor.mirrors.lucidnetworks.net",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Lucid Networks",
+ "region": "US",
+ "rsyncDistMirror": "rsync://tor.mirrors.lucidnetworks.net::tor-dist",
+ "rsyncWebsiteMirror": "rsync://tor.mirrors.lucidnetworks.net::tor",
+ "subRegion": "United States",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "hostmaster(a)vieth-server.de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.mirror-server.de/dist/",
+ "httpWebsiteMirror": "http://tor.mirror-server.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "mirror-server.de",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Tue Jan 20 16:17:52 2015"
+ },
+ {
+ "adminContact": "mirror ntzk de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://mirror.ntzk.de/torproject.org/dist/",
+ "httpWebsiteMirror": "http://mirror.ntzk.de/torproject.org/",
+ "httpsDistMirror": "https://mirror.ntzk.de/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://mirror.ntzk.de/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Netzkonstrukt Berlin",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "mirror(a)xfree.com.ar",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.xfree.com.ar/dist/",
+ "httpWebsiteMirror": "http://tor.xfree.com.ar/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "AR",
+ "loadBalanced": "No",
+ "orgName": "Xfree.com.ar",
+ "region": "South America",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Argentina",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor AT eprci NET",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.eprci.net/dist/",
+ "httpWebsiteMirror": "http://tor.eprci.net/",
+ "httpsDistMirror": "https://www.eprci.com/tor/dist/",
+ "httpsWebsiteMirror": "https://www.eprci.com/tor/",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "EPRCI",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "NH",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tor(a)kura.io",
+ "ftpWebsiteMirror": "ftp://tor-mirror.kura.io",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-mirror.kura.io/dist/",
+ "httpWebsiteMirror": "http://tor-mirror.kura.io/",
+ "httpsDistMirror": "https://tor-mirror.kura.io/dist/",
+ "httpsWebsiteMirror": "https://tor-mirror.kura.io/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "NL",
+ "loadBalanced": "TRUE",
+ "orgName": "KURA IO LIMITED",
+ "region": "Europe",
+ "rsyncDistMirror": "rsync://tor-mirror.kura.io/torproject.org/dist",
+ "rsyncWebsiteMirror": "rsync://tor-mirror.kura.io/torproject.org",
+ "subRegion": "Netherlands",
+ "updateDate\n": "Thu Jan 22 16:27:59 2015"
+ },
+ {
+ "adminContact": "tor-admin AT wardsback DOT org",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://alliumcepa.wardsback.org/dist/",
+ "httpWebsiteMirror": "http://alliumcepa.wardsback.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "wardsback.org",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "PW",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.pw.is/dist/",
+ "httpWebsiteMirror": "http://tor.pw.is/",
+ "httpsDistMirror": "https://www.it-sicherheitschannel.de/dist/",
+ "httpsWebsiteMirror": "https://www.it-sicherheitschannel.de/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "NO",
+ "orgName": "PW",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "kevin(a)freedom.press",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.freedom.press/dist/",
+ "httpWebsiteMirror": "http://tor.freedom.press",
+ "httpsDistMirror": "https://tor.freedom.press/dist/",
+ "httpsWebsiteMirror": "https://tor.freedom.press",
+ "ipv4": "True",
+ "ipv6": "False",
+ "isoCC": "",
+ "loadBalanced": "No",
+ "orgName": "Freedom of the Press Foundation",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "US",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "hsu AT peterdavehellor DOT org",
+ "ftpWebsiteMirror": "ftp://ftp.yzu.edu.tw/torproject.org/",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://ftp.yzu.edu.tw/torproject.org/dist/",
+ "httpWebsiteMirror": "http://ftp.yzu.edu.tw/torproject.org/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "TW",
+ "loadBalanced": "No",
+ "orgName": "Department of CSE. Yuan Ze University",
+ "region": "Asia",
+ "rsyncDistMirror": "rsync://ftp.yzu.edu.tw/pub/torproject.org/dist/",
+ "rsyncWebsiteMirror": "rsync://ftp.yzu.edu.tw/pub/torproject.org/",
+ "subRegion": "Taiwan",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tormirror at sybec.net <mailto:tormirror at sybec.net>",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tormirror.sybec.net:8080/dist/ <http://tormirror.sybec.net:8080/dist/>",
+ "httpWebsiteMirror": "http://tormirror.sybec.net:8080/ <http://tormirror.sybec.net:8080/>",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "FALSE",
+ "orgName": "Sybec Services Ltd.",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": ""
+ },
+ {
+ "adminContact": "tor at tvdw dot eu",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-exit.network/dist",
+ "httpWebsiteMirror": "http://tor-exit.network",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "XX",
+ "loadBalanced": "Yes",
+ "orgName": "TvdW",
+ "region": "XX",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Around the world",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "spiderfly AT protonmail DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://onionphysics.com/dist/",
+ "httpWebsiteMirror": "http://onionphysics.com",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "FR",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "FR",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "France",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "ops at hoovism.com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://bt3ehg7prnlm6tyv.onion/",
+ "httpDistMirror": "http://tor.hoovism.com/dist/",
+ "httpWebsiteMirror": "http://tor.hoovism.com/",
+ "httpsDistMirror": "https://tor.hoovism.com/dist/",
+ "httpsWebsiteMirror": "https://tor.hoovism.com/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "Matthew Hoover",
+ "region": "US",
+ "rsyncDistMirror": "rsync://tor.hoovism.com/tor/dist/",
+ "rsyncWebsiteMirror": "rsync://tor.hoovism.com/tor/",
+ "subRegion": "NJ",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "tormaster AT urown DOT net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://torprowdd64ytmyk.onion",
+ "httpDistMirror": "http://torproject.urown.net/dist/",
+ "httpWebsiteMirror": "http://torproject.urown.net/",
+ "httpsDistMirror": "https://torproject.urown.net/dist/",
+ "httpsWebsiteMirror": "https://torproject.urown.net/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "CH",
+ "loadBalanced": "No",
+ "orgName": "urown.net",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Switzerland",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "Stefan",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://sela.io/mirrors/torproject.org/dist/",
+ "httpWebsiteMirror": "http://sela.io/mirrors/torproject.org/",
+ "httpsDistMirror": "https://sela.io/mirrors/torproject.org/dist/",
+ "httpsWebsiteMirror": "https://sela.io/mirrors/torproject.org/",
+ "ipv4": "TRUE",
+ "ipv6": "TRUE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "sela Internet",
+ "region": "DE",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "justaguy AT justaguy DOT pw",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "http://3qzbcsjhwseov7k4.onion",
+ "httpDistMirror": "http://services.justaguy.pw/dist",
+ "httpWebsiteMirror": "http://services.justaguy.pw/",
+ "httpsDistMirror": "https://services.justaguy.pw/dist",
+ "httpsWebsiteMirror": "https://services.justaguy.pw/",
+ "ipv4": "True",
+ "ipv6": "False",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "Justaguy",
+ "region": "NL",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "thomaswhite AT riseup DOT net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.thecthulhu.com/dist/",
+ "httpWebsiteMirror": "http://tor.thecthulhu.com/",
+ "httpsDistMirror": "https://tor.thecthulhu.com/dist/",
+ "httpsWebsiteMirror": "https://tor.thecthulhu.com/",
+ "ipv4": "True",
+ "ipv6": "False",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "TheCthulhu",
+ "region": "NL",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "rush23 AT gmx DOT net",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor-proxy.euve59946.serverprofi24.de/dist/",
+ "httpWebsiteMirror": "http://tor-proxy.euve59946.serverprofi24.de/",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "DE",
+ "loadBalanced": "No",
+ "orgName": "Tor Supporter",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "Germany",
+ "updateDate\n": "Thu Jun 4 19:06:42 2015"
+ },
+ {
+ "adminContact": "webmaster AT ccc DOT de",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "http://tor.ccc.de/dist/",
+ "httpWebsiteMirror": "http://tor.ccc.de/",
+ "httpsDistMirror": "https://tor.ccc.de/dist/",
+ "httpsWebsiteMirror": "https://tor.ccc.de",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "NL",
+ "loadBalanced": "No",
+ "orgName": "CCC",
+ "region": "Europe",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "The Netherlands",
+ "updateDate\n": "Wed Jul 15 18:49:12 2015"
+ },
+ {
+ "adminContact": "mitchell AT lcsks DOT com",
+ "ftpWebsiteMirror": "",
+ "hiddenServiceMirror": "",
+ "httpDistMirror": "",
+ "httpWebsiteMirror": "http://mirror.lcsks.com",
+ "httpsDistMirror": "",
+ "httpsWebsiteMirror": "",
+ "ipv4": "TRUE",
+ "ipv6": "FALSE",
+ "isoCC": "US",
+ "loadBalanced": "No",
+ "orgName": "CCC",
+ "region": "US",
+ "rsyncDistMirror": "",
+ "rsyncWebsiteMirror": "",
+ "subRegion": "United States",
+ "updateDate\n": ""
+ }
+]
\ No newline at end of file
diff --git a/tor-mirrors.csv b/tor-mirrors.csv
new file mode 100644
index 0000000..5ca8f03
--- /dev/null
+++ b/tor-mirrors.csv
@@ -0,0 +1,116 @@
+adminContact, orgName, isoCC, subRegion, region, ipv4, ipv6, loadBalanced, httpWebsiteMirror, httpsWebsiteMirror, rsyncWebsiteMirror, ftpWebsiteMirror, httpDistMirror, httpsDistMirror, rsyncDistMirror, hiddenServiceMirror, updateDate
+Tor Fan, Tor Supporter, US, United States, US, TRUE, TRUE, No, http://tor.loritsu.com/, , , , http://tor.loritsu.com/dist/, , , ,
+Tor Fan, Tor Supporter, LU, Luxemborg, LU, TRUE, FALSE, No, http://torproject.adamas.ai/, , , , http://torproject.adamas.ai/dist/, , , ,
+Tor Fan, Tor Supporter, UA, Ukraine, UA, TRUE, FALSE, No, http://torua.reactor-xg.kiev.ua/, , , , http://torua.reactor-xg.kiev.ua/dist/, , , ,
+Tor Fan, Tor Supporter, FR, France, FR, TRUE, FALSE, No, http://37.187.0.127/tormirror/, , , , http://37.187.0.127/tormirror/dist/, , , ,
+Tor Fan, Tor Supporter, US, United States, US, TRUE, FALSE, No, http://tor.minibofh.org/, , , , http://tor.minibofh.org/dist/, , , ,
+Tor Fan, Tor Supporter, UK, United Kingdom, UK, TRUE, FALSE, No, http://tor.mage.me.uk/, , , , http://tor.mage.me.uk/dist/, , , ,
+nsane2307 eml cc, tor-mirror.de, DE, Germany, Europe, TRUE, FALSE, No, http://tor-mirror.de/, https://tor-mirror.de/, , , http://tor-mirror.de/dist/, https://tor-mirror.de/dist/, , ,
+citizen428 AT gmail DOT com, [[:bbs:]], DE, Germany, Europe, TRUE, FALSE, No, http://tor.blingblingsquad.net/, https://tor.blingblingsquad.net/, , , http://tor.blingblingsquad.net/dist/, https://tor.blingblingsquad.net/dist/, , ,
+Tor Fan, NW Linux, US, WA, US, TRUE, FALSE, No, http://torproject.nwlinux.us/, , rsync://nwlinux.us/tor-web, , http://torproject.nwlinux.us/dist/, , rsync://nwlinux.us/tor-dist, ,
+Tor Fan, Tor Supporter, NL, The Netherlands, NL, TRUE, FALSE, No, , , , , , https://www.coevoet.nl/tor/dist/, , ,
+Tor Fan, LazyTiger, FR, France, FR, TRUE, FALSE, No, http://tor.taiga-san.net/, , , , http://tor.taiga-san.net/dist/, , , ,
+Tor Fan, Tor Supporter, EE, Estonia, EE, TRUE, FALSE, No, http://tor.li/, https://tor.li/, , , http://tor.li/dist/, https://tor.li/dist/, , ,
+Tor Fan, Tor Supporter, DE, Germany, DE, TRUE, FALSE, NO, http://tor.externenprüfung-nichtschüler.de/, , , , http://tor.externenprüfung-nichtschüler.de/dist/, , , ,
+mirror-service(a)netcologne.de, NetCologne GmbH, DE, NRW, , TRUE, TRUE, No, http://mirror.netcologne.de/torproject.org, , rsync://mirror.netcologne.de/torproject.org, ftp://mirror.netcologne.de/torproject.org/, http://mirror.netcologne.de/torproject.org/dist, , rsync://mirror.netcologne.de/torproject.org/dist, , Wed Jul 15 18:49:12 2015
+admin AT netgull DOT com, NetGull, US, United States, North America, TRUE, TRUE, No, , , , , http://www.netgull.com/torproject/, , , ,
+mirrors[at]ip-connect[dot]vn[dot]ua, IP-Connect LLC, UA, VN, , TRUE, TRUE, Yes, http://torproject.ip-connect.vn.ua, , rsync://torproject.ip-connect.vn.ua/torproject, ftp://torproject.ip-connect.vn.ua/mirror/torproject/, http://torproject.ip-connect.vn.ua/dist, , rsync://torproject.ip-connect.vn.ua/torproject/dist, , Wed Jul 15 18:49:12 2015
+torsupport AT tb-itf DOT de, TB-ITF, DE, Germany, Europe, TRUE, TRUE, No, http://tormirror.tb-itf-tor.de, https://tormirror.tb-itf-tor.de, , , http://tormirror.tb-itf-tor.de/dist/, https://tormirror.tb-itf-tor.de/dist/, , , Wed Jul 15 18:49:12 2015
+admin at koreswatanabe dottnet, Tor Supporter, RO, Romania, RO, TRUE, TRUE, No, http://tor-relay.koreswatanabe.net, , , , http://tor-relay.koreswatanabe.net/dist/, , , ,
+calebcenter(a)live.com, calebxu.tk, US, United States, US, TRUE, FALSE, NO, http://tor.calebxu.tk, , rsync://calebxu.tk/tor, ftp://ftp.calebxu.tk, http://tor.calebxu.tk/dist, , , ,
+maki(a)maki-chan.de, Maki Hoshisawa, DE, Germany, DE, TRUE, FALSE, NO, http://tor.mirrors.maki-chan.de/, , , , http://tor.mirrors.maki-chan.de/dist/, , , , Sat Aug 23 08:09:07 2014
+info AT zentrum-der-gesundheit DOT de, Zentrum der Gesundheit, DK, Denmark, Europe, TRUE, FALSE, No, http://tor.idnr.ws/, , , , http://tor.idnr.ws/dist/, , , , Tue Sep 2 11:16:00 2014
+info /AT enn /DOT lu, Frenn vun der Enn A.S.B.L., IS, Iceland, Europe, TRUE, FALSE, No, http://torproject.lu/, , , , http://torproject.lu/dist/, , , http://btn6gqzqevlhoryd.onion, Wed Jul 15 18:49:12 2015
+Piratenpartei Bayern, Piratenpartei Bayern, DE, Germany, DE, TRUE, FALSE, NO, http://tormirror.piratenpartei-bayern.de, https://tormirror.piratenpartei-bayern.de, , , http://tormirror.piratenpartei-bayern.de/dist/, https://tormirror.piratenpartei-bayern.de/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, DE, Germany, DE, TRUE, TRUE, NO, http://tor.hoi-polloi.org, https://tor.hoi-polloi.org/, , , http://tor.hoi-polloi.org/dist/, https://tor.hoi-polloi.org/dist/, , , Wed Jul 15 18:49:12 2015
+tor(a)fodt.it // FoDT.it Webteam, FoDT.it, AT, Austria, Europe, TRUE, FALSE, No, http://tor.fodt.it, https://tor.fodt.it, , ftp://ftp.fodt.it/pub/mirrors/torproject.org/, http://tor.fodt.it/dist/, https://tor.fodt.it/dist/, , , Mon Aug 25 10:19:07 2014
+http://www.multinet.no, MultiNet AS, NO, Trondheim, Trondheim, TRUE, TRUE, No, http://tor.multinet.no/, , , , http://tor.multinet.no/dist/, , , , Wed Jul 15 18:49:12 2015
+haskell at gmx.es, Tor Supporter, ES, Spain, Europe, TRUE, TRUE, No, http://tor.zilog.es/, https://tor.zilog.es/, , , http://tor.zilog.es/dist/, https://tor.zilog.es/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, US, United States, US, TRUE, FALSE, No, http://199.175.55.215/, https://199.175.55.215/, , , http://199.175.55.215/dist/, https://199.175.55.215/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, US, United States, US, FALSE, TRUE, No, http://2607:8b00:2::6258:5c9/, https://2607:8b00:2::6258:5c9/, , , http://2607:8b00:2::6258:5c9/dist/, https://2607:8b00:2::6258:5c9/dist/, , , Tue Jan 20 16:17:52 2015
+margus.random at mail.ee, CyberSIDE, EE, Estonia, EE, TRUE, FALSE, No, http://cyberside.planet.ee/tor/, , , , http://cyberside.net.ee/tor/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, torproject.is, IS, Iceland, IS, TRUE, FALSE, No, http://www.torproject.is/, , , , http://www.torproject.is/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, spline, DE, Germany, DE, TRUE, FALSE, No, http://tor.spline.de/, https://tor.spline.inf.fu-berlin.de/, rsync://ftp.spline.de/tor, ftp://ftp.spline.de/pub/tor, http://tor.spline.de/dist/, https://tor.spline.inf.fu-berlin.de/dist/, rsync://ftp.spline.de/tor/dist, , Wed Jul 15 18:49:12 2015
+Tor Fan, me0w.cc, RO, Romania, RO, TRUE, FALSE, No, http://tor.me0w.cc/, , , , http://tor.me0w.cc/dist/, , , , Thu Jan 1 16:17:56 2015
+Tor Fan, borgmann.tv, DE, Germany, DE, TRUE, FALSE, No, http://tor.borgmann.tv/, , , , http://tor.borgmann.tv/dist/, , , , Sun Jul 12 19:04:44 2015
+Tor Fan, Tor Supporter, AT, Austria, AT, TRUE, TRUE, No, http://tor.dont-know-me.at/, , , , http://tor.dont-know-me.at/dist/, , , , Tue Jan 20 16:17:52 2015
+coralcdn.org, CoralCDN, INT, International, INT, TRUE, FALSE, Yes, http://www.torproject.org.nyud.net/, , , , http://www.torproject.org.nyud.net/dist/, , , , Thu Jan 8 02:01:06 2015
+Tor Fan, Tor Supporter, AT, Austria, AT, TRUE, FALSE, No, http://torproject.ph3x.at/, , , , http://torproject.ph3x.at/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, MX, Mexico, MX, TRUE, FALSE, No, http://fbnaia.homelinux.net/torproject/, https://fbnaia.homelinux.net/torproject/, , , http://fbnaia.homelinux.net/torproject/dist/, https://fbnaia.homelinux.net/torproject/dist/, , , Wed Jul 15 18:49:12 2015
+webmaster AT askapache DOT com, AskApache, US, California, US, TRUE, FALSE, No, http://tor.askapache.com/, , , , http://tor.askapache.com/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, FR, France, FR, TRUE, FALSE, No, http://tor.mirror.chekanov.net/, , , , http://tor.mirror.chekanov.net/dist/, , , , Mon Mar 16 15:53:03 2015
+kontakt AT unicorncloud DOT org, UnicornCloud.org, DE, Germany, Falkenstein, TRUE, FALSE, No, http://mirror.unicorncloud.org/torproject.org/, https://mirror.unicorncloud.org/torproject.org/, , , http://mirror.unicorncloud.org/torproject.org/dist, https://mirror.unicorncloud.org/torproject.org/dist, , , Wed Jul 15 18:49:12 2015
+root AT amorphis DOT eu, Amorphis, NL, The Netherlands, Europe, TRUE, FALSE, No, http://tor.amorphis.eu/, , , , http://tor.amorphis.eu/dist/, , , , Mon Mar 16 15:53:03 2015
+hackthissite.org, HackThisSite.org, US, United States, US, TRUE, TRUE, No, http://tor.hackthissite.org/, https://tor.hackthissite.org/, , , http://mirror.hackthissite.org/tor, https://mirror.hackthissite.org/tor, , , Wed Jul 15 18:49:12 2015
+paul at coffswifi.net, CoffsWiFi, AU, Australia and New Zealand, APNIC, TRUE, FALSE, No, http://torproject.coffswifi.net, , , , http://torproject.coffswifi.net/dist, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, cyberarmy, AT, Austria, AT, TRUE, FALSE, No, http://tor.cyberarmy.at/, , , , , , , , Wed Jul 15 18:49:12 2015
+hostmaster AT example DOT com, TheOnionRouter, IS, Iceland, Iceland, TRUE, FALSE, No, http://www.theonionrouter.com/, , , , http://www.theonionrouter.com/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, crazyhaze.de, DE, Germany, DE, TRUE, FALSE, No, http://tor.crazyhaze.de/, https://tor.crazyhaze.de/, , , http://tor.crazyhaze.de/dist/, https://tor.crazyhaze.de/dist/, , , Tue Jul 7 13:16:29 2015
+Tor Fan, chaos darmstadt, DE, Germany, Europe, TRUE, FALSE, No, http://mirrors.chaos-darmstadt.de/tor-mirror/, , , , http://mirrors.chaos-darmstadt.de/tor-mirror/dist/, , , , Wed Jul 15 18:49:12 2015
+Tor Fan, Soviet Anonymous, RU, Russia, RU, TRUE, FALSE, No, http://creep.im/tor, https://creep.im/tor, rsync://creep.im/tor, ftp://creep.im/mirrors/tor, http://creep.im/tor/dist/, https://creep.im/tor/dist/, rsync://creep.im/tor-dist, , Wed Jul 15 18:49:12 2015
+Tor Fan, torservers, DE, Germany, DE, TRUE, FALSE, No, http://www.torservers.net/mirrors/torproject.org/, https://www.torservers.net/mirrors/torproject.org/, , , http://www.torservers.net/mirrors/torproject.org/dist/, https://www.torservers.net/mirrors/torproject.org/dist/, , http://hbpvnydyyjbmhx6b.onion/mirrors/torproject.org/, Wed Jul 15 18:49:12 2015
+Tor Fan, torland, GB, United Kingdom, GB, TRUE, FALSE, No, http://mirror.torland.me/torproject.org/, https://mirror.torland.me/torproject.org/, , , http://mirror.torland.me/torproject.org/dist/, https://mirror.torland.me/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Lightning-bolt.net, CZ, Czech Republic, CZ, TRUE, FALSE, No, http://torproject.lightning-bolt.net/, , , , http://torproject.lightning-bolt.net/dist/, , , , Mon Mar 16 15:53:03 2015
+IceBear, myRL.net, IS, Iceland, IS, TRUE, FALSE, No, http://tor.myrl.net/, https://tor.myrl.net/, , , http://tor.myrl.net/dist/, https://tor.myrl.net/dist/, , , Wed Jul 15 18:49:12 2015
+kiro AT userzap DOT de, Userzap, DE, Germany, DE, TRUE, FALSE, No, http://torprojekt.userzap.de, https://torprojekt.userzap.de, , , http://torprojekt.userzap.de/dist/, https://torprojekt.userzap.de/dist/, , , Tue Jan 20 16:17:52 2015
+tor(a)les.net, tor(a)les.net, CA, Canada, CA, TRUE, FALSE, NO, http://tor.les.net/, , , , http://tor.les.net/dist, , , , Wed Jul 15 18:49:12 2015
+tor(a)stalkr.net, stalkr.net, FR, France, FR, TRUE, TRUE, NO, http://tor.stalkr.net/, https://tor.stalkr.net/, , , http://tor.stalkr.net/dist/, https://tor.stalkr.net/dist/, , , Wed Jul 15 18:49:12 2015
+doemela[AT]cyberguerrilla[DOT]org, cYbergueRrilLa AnonyMous NeXus, DE, Germany, DE, TRUE, FALSE, NO, , https://tor-mirror.cyberguerrilla.org, , , , https://tor-mirror.cyberguerrilla.org/dist/, , http://6dvj6v5imhny3anf.onion, Wed Jul 15 18:49:12 2015
+contact(a)gtor.org, Gtor, DE, Germany, DE, TRUE, TRUE, NO, http://torproject.gtor.org/, https://torproject.gtor.org/, rsync://torproject.gtor.org/website-mirror/, , http://torproject.gtor.org/dist/, https://torproject.gtor.org/dist/, rsync://torproject.gtor.org/website-mirror/dist/, , Wed Jul 15 18:49:12 2015
+SDL, SDL, US, United States, US, TRUE, TRUE, NO, http://torproject.nexiom.net, https://torproject.nexiom.net, , , http://torproject.nexiom.net, https://torproject.nexiom.net/dist, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, DE, Germany, DE, TRUE, TRUE, NO, http://mirror.velcommuta.de/tor/, https://mirror.velcommuta.de/tor/, , , http://mirror.velcommuta.de/tor/dist/, https://mirror.velcommuta.de/tor/dist/, , , Wed Jul 15 18:49:12 2015
+EFF, EFF, US, United States, US, TRUE, FALSE, NO, , https://tor.eff.org, , , , https://tor.eff.org/dist/, , , Wed Jul 15 18:49:12 2015
+Tor Fan, Tor Supporter, GR, Greece, GR, TRUE, TRUE, NO, http://tor.void.gr, https://tor.void.gr, , , http://tor.void.gr/dist/, https://tor.void.gr/dist/, , , Wed Jul 15 18:49:12 2015
+Ich Eben, Tor Supporter, DE, Germany, DE, TRUE, TRUE, No, http://reichster.de/mirrors/torproject.org/, https://reichster.de/mirrors/torproject.org, , , http://reichster.de/mirrors/torproject.org/dist/, https://reichster.de/mirrors/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+jlgaddis AT gnu DOT org, Evil Routers, US, United States, US, TRUE, FALSE, No, http://tor1.evilrouters.net/, , , , http://tor1.evilrouters.net/dist/, , , , Wed Jul 15 18:49:12 2015
+tor AT miglix DOT eu, Tor Supporter, DE, Germany, Europe, TRUE, TRUE, NO, http://tor.miglix.eu, https://tor.miglix.eu, , , http://tor.miglix.eu/dist/, https://tor.miglix.eu/dist/, , , Wed Jul 15 18:49:12 2015
+tor TA ninurta TOD name, TorNinurtaName, AT, Austria, AT, TRUE, TRUE, no, http://tor.ninurta.name/, , , , http://tor.ninurta.name/dist/, , , , Wed Oct 22 15:02:17 2014
+fr33tux <AT> general-changelog-team.fr, Tor Supporter, FR, France, FR, TRUE, TRUE, No, http://tor.fr33tux.org, https://tor.fr33tux.org, , , http://tor.fr33tux.org/dist/, https://tor.fr33tux.org/dist/, , , Wed Jul 15 18:49:12 2015
+sebastian(at)bobrecki(dot)pl, Sebastian M. Bobrecki, PL, Poland, Europe, TRUE, FALSE, No, http://tor.iv.net.pl, https://tor.iv.net.pl, , , http://tor.iv.net.pl/dist/, https://tor.iv.net.pl/dist/, , , Wed Jul 15 18:49:12 2015
+tor-mirror AT rdns DOT cc, d0wn.biz, FR, France, Europe, TRUE, FALSE, No, http://tor.static.lu, https://tor.static.lu, , , http://tor.static.lu/dist/, https://tor.static.lu/dist/, , , Wed Jul 15 18:49:12 2015
+tor(a)moparisthebest.com, moparisthebest.com, DE, Germany, Europe, TRUE, TRUE, No, http://www.moparisthebest.com/tor/, https://www.moparisthebest.com/tor/, , , http://www.moparisthebest.com/tor/dist/, https://www.moparisthebest.com/tor/dist/, , , Wed Jul 15 18:49:12 2015
+Sebastian, Maxanoo, NL, The Netherlands, Amsterdam, TRUE, FALSE, NO, http://tor.maxanoo.com/, , , , http://tor.maxanoo.com/dist/, , , , Sun May 31 15:13:53 2015
+rorrim AT ayo DOT tl, Tor Supporter, IS, Iceland, Europe, TRUE, TRUE, No, http://ayo.tl/tor/, https://ayo.tl/tor/, , , http://ayo.tl/tor/dist/, https://ayo.tl/tor/dist/, , , Tue Jan 20 16:17:52 2015
+stefano.fenoglio AT gmail DOT com, Tor Supporter, IT, Italy, Europe, TRUE, FALSE, No, http://tor.stefanof.com, , , , http://tor.stefanof.com/dist, , , , Sun Jul 12 13:19:35 2015
+Tor Fan, Ramos Research, US, United States, US, TRUE, TRUE, No, http://tor.ramosresearch.com/, , , , http://tor.ramosresearch.com/dist/, , , , Mon Mar 16 15:53:03 2015
+Tor Fan, Tor Supporter, DE, Germany, Europe, TRUE, FALSE, No, http://tor.euve33747.vserver.de/, , , , http://tor.euve33747.vserver.de/dist, , , , Wed Jul 15 18:49:12 2015
+s7r[at]sky-ip[d0t]org, sky-ip.org, NL, Netherlands, NL, TRUE, FALSE, No, http://beautiful-mind.sky-ip.org/, , , , http://beautiful-mind.sky-ip.org/dist/, , , , Wed Jul 15 18:49:12 2015
+tor#pajonzeck#de, ITsn, DE, Germany, Europe, TRUE, FALSE, No, http://tor.pajonzeck.de/, https://tor.pajonzeck.de/, rsync://tor.pajonzeck.de/tor, , http://tor.pajonzeck.de/dist/, https://tor.pajonzeck.de/dist/, rsync://tor.pajonzeck.de/tor/dist, http://zgfgvob256pffy62.onion, Wed Jul 15 18:49:12 2015
+peter AT ludikovsky DOT name, Tor Supporter, AT, Austria, Europe, TRUE, TRUE, No, http://tor.ludikovsky.name/, https://tor.ludikovsky.name/, rsync://tor.ludikovsky.name/tor, , http://tor.ludikovsky.name/dist, https://tor.ludikovsky.name/dist, rsync://tor.ludikovsky.name/tor-dist, http://54lnbzjo6xlr4f4j.onion/, Wed Jul 15 18:49:12 2015
+admin AT nuclear DASH weapons DOT net, Setec Administrator, US, Texas, Austin, TRUE, FALSE, No, http://tor.nuclear-weapons.net, https://tor.nuclear-weapons.net, , , http://tor.nuclear-weapons.net/dist, https://tor.nuclear-weapons.net/dist, , , Wed Jul 15 18:49:12 2015
+0x43DE8191, Tor Supporter, DE, Germany, Europe, TRUE, TRUE, No, http://torproject.hactar.bz, , , , http://torproject.hactar.bz/dist/, , , , Wed Jul 15 18:49:12 2015
+-nick at calyx dot com, The Calyx Institute, US, United States, North America, TRUE, FALSE, No, http://tor.calyxinstitute.org, https://tor.calyxinstitute.org, , , http://tor.calyxinstitute.org/dist/, https://tor.calyxinstitute.org/dist/, , http://tmdrhl4e4anhsjc5.onion, Wed Jul 15 18:49:12 2015
+opi(a)zeropi.net, Tor Supporter, FR, France, FR, TRUE, TRUE, No, http://tor-mirror.zeropi.net/, , , , http://tor-mirror.zeropi.net/dist/, , , , Mon Dec 1 12:15:20 2014
+noc AT babylon DOT network, Babylon Network, NL, The Netherlands, Europe, TRUE, TRUE, No, http://mirror2.babylon.network/torproject/, https://mirror2.babylon.network/torproject/, rsync://mirror2.babylon.network/torproject/, ftp://mirror2.babylon.network/torproject/, http://mirror2.babylon.network/torproject/dist/, https://mirror2.babylon.network/torproject/dist/, rsync://mirror2.babylon.network/torproject/dist/, , Wed Jul 15 18:49:12 2015
+noc AT babylon DOT network, Babylon Network, FR, France, Europe, TRUE, TRUE, No, http://mirror0.babylon.network/torproject/, https://mirror0.babylon.network/torproject/, rsync://mirror0.babylon.network/torproject/, ftp://mirror0.babylon.network/torproject/, http://mirror0.babylon.network/torproject/dist/, https://mirror0.babylon.network/torproject/dist/, rsync://mirror0.babylon.network/torproject/dist/, , Wed Jul 15 18:49:12 2015
+noc AT babylon DOT network, Babylon Network, FR, France, Europe, TRUE, TRUE, No, http://mirror1.babylon.network/torproject/, https://mirror1.babylon.network/torproject/, rsync://mirror1.babylon.network/torproject/, ftp://mirror1.babylon.network/torproject/, http://mirror1.babylon.network/torproject/dist/, https://mirror1.babylon.network/torproject/dist/, rsync://mirror1.babylon.network/torproject/dist/, , Wed Jul 15 18:49:12 2015
+alexander AT dietrich DOT cx, Tor Supporter, DE, Germany, Europe, TRUE, TRUE, No, http://tor.ybti.net/, https://tor.ybti.net/, , , http://tor.ybti.net/dist/, https://tor.ybti.net/dist/, , , Wed Jul 15 18:49:12 2015
+tor(a)0x3d.lu, 0x3d.lu, DE, Germany, Europe, TRUE, FALSE, No, http://tor.0x3d.lu/, https://tor.0x3d.lu/, , , http://tor.0x3d.lu/dist/, https://tor.0x3d.lu/dist/, , , Wed Jul 15 18:49:12 2015
+kraai(a)ftbfs.org 0xADCE6065, , SE, Sweden, Europe, TRUE, TRUE, No, http://tor.ftbfs.org/, , , , http://tor.ftbfs.org/dist/, , , , Fri Oct 24 08:28:32 2014
+kontakt(a)unicorncloud.org, UnicornCloud.org, AT, Favoriten, Wien, TRUE, TRUE, No, http://www.unicorncloud.org/public/torproject.org/, https://www.unicorncloud.org/public/torproject.org/, , , http://www.unicorncloud.org/public/torproject.org/dist, https://www.unicorncloud.org/public/torproject.org/dist, , , Mon Mar 16 15:53:03 2015
+James Murphy, intfxdx.com, US, United States, US, TRUE, TRUE, No, http://108.248.87.242/, https://108.248.87.242/, , , http://108.248.87.242/dist/, https://108.248.87.242/dist/, , , Wed Jul 15 18:49:12 2015
+Sam Whited 4096R/54083AE104EA7AD3 <sam(a)samwhited.com>, SamWhited.com, US, GA, United States, TRUE, TRUE, FALSE, http://mirrors.samwhited.net/tor, https://mirrors.samwhited.net/tor, rsync://mirrors.samwhited.net/tor, , http://mirrors.samwhited.net/tor/dist, https://mirrors.samwhited.net/tor/dist, rsync://mirrors.samwhited.net/tor-dist, , Wed Jul 15 18:49:12 2015
+rohit008 AT e DOT ntu DOT edu DOT sg, NTUOSS, SG, Singapore, Asia, TRUE, FALSE, No, http://torproject.ntuoss.com/, , , , http://torproject.ntuoss.com/dist/, , , , Mon Mar 16 15:53:03 2015
+jvictors at jessevictors dot com, Department of CS at USU, US, United States, North America, TRUE, FALSE, No, http://tor-relay.cs.usu.edu/mirrors/torproject.org/, https://www.jessevictors.com/secureMirrors/torproject.org/, , , http://tor-relay.cs.usu.edu/mirrors/torproject.org/dist/, https://www.jessevictors.com/secureMirrors/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+Jacob Henner, Anatomical Networks, US, United States, US, TRUE, TRUE, TRUE, http://tor.ventricle.us/, , , , http://tor.ventricle.us/dist/, , , , Tue Jan 20 16:17:52 2015
+hostmaster(a)lucidnetworks.net, Lucid Networks, US, United States, US, TRUE, FALSE, No, http://tor.mirrors.lucidnetworks.net, , rsync://tor.mirrors.lucidnetworks.net::tor, , http://tor.mirrors.lucidnetworks.net/dist, , rsync://tor.mirrors.lucidnetworks.net::tor-dist, , Wed Jul 15 18:49:12 2015
+hostmaster(a)vieth-server.de, mirror-server.de, DE, Germany, DE, TRUE, TRUE, No, http://tor.mirror-server.de/, , , , http://tor.mirror-server.de/dist/, , , , Tue Jan 20 16:17:52 2015
+mirror ntzk de, Netzkonstrukt Berlin, DE, Germany, Europe, TRUE, FALSE, No, http://mirror.ntzk.de/torproject.org/, https://mirror.ntzk.de/torproject.org/, , , http://mirror.ntzk.de/torproject.org/dist/, https://mirror.ntzk.de/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+mirror(a)xfree.com.ar, Xfree.com.ar, AR, Argentina, South America, TRUE, FALSE, No, http://tor.xfree.com.ar/, , , , http://tor.xfree.com.ar/dist/, , , , Wed Jul 15 18:49:12 2015
+tor AT eprci NET, EPRCI, US, NH, US, TRUE, FALSE, No, http://tor.eprci.net/, https://www.eprci.com/tor/, , , http://tor.eprci.net/dist/, https://www.eprci.com/tor/dist/, , , Wed Jul 15 18:49:12 2015
+tor(a)kura.io, KURA IO LIMITED, NL, Netherlands, Europe, TRUE, TRUE, TRUE, http://tor-mirror.kura.io/, https://tor-mirror.kura.io/, rsync://tor-mirror.kura.io/torproject.org, ftp://tor-mirror.kura.io, http://tor-mirror.kura.io/dist/, https://tor-mirror.kura.io/dist/, rsync://tor-mirror.kura.io/torproject.org/dist, , Thu Jan 22 16:27:59 2015
+tor-admin AT wardsback DOT org, wardsback.org, FR, France, FR, TRUE, FALSE, No, http://alliumcepa.wardsback.org/, , , , http://alliumcepa.wardsback.org/dist/, , , , Wed Jul 15 18:49:12 2015
+PW, PW, DE, Germany, DE, TRUE, TRUE, NO, http://tor.pw.is/, https://www.it-sicherheitschannel.de/, , , http://tor.pw.is/dist/, https://www.it-sicherheitschannel.de/dist/, , , Wed Jul 15 18:49:12 2015
+kevin(a)freedom.press, Freedom of the Press Foundation, , US, US, True, False, No, http://tor.freedom.press, https://tor.freedom.press, , , http://tor.freedom.press/dist/, https://tor.freedom.press/dist/, , ,
+hsu AT peterdavehellor DOT org, Department of CSE. Yuan Ze University, TW, Taiwan, Asia, TRUE, FALSE, No, http://ftp.yzu.edu.tw/torproject.org/, , rsync://ftp.yzu.edu.tw/pub/torproject.org/, ftp://ftp.yzu.edu.tw/torproject.org/, http://ftp.yzu.edu.tw/torproject.org/dist/, , rsync://ftp.yzu.edu.tw/pub/torproject.org/dist/, , Wed Jul 15 18:49:12 2015
+tormirror at sybec.net <mailto:tormirror at sybec.net>, Sybec Services Ltd., DE, Germany, DE, TRUE, FALSE, FALSE, http://tormirror.sybec.net:8080/ <http://tormirror.sybec.net:8080/>, , , , http://tormirror.sybec.net:8080/dist/ <http://tormirror.sybec.net:8080/dist/>, , , ,
+tor at tvdw dot eu, TvdW, XX, Around the world, XX, TRUE, TRUE, Yes, http://tor-exit.network, , , , http://tor-exit.network/dist, , , , Wed Jul 15 18:49:12 2015
+spiderfly AT protonmail DOT com, Tor Supporter, FR, France, FR, TRUE, FALSE, No, http://onionphysics.com, , , , http://onionphysics.com/dist/, , , , Wed Jul 15 18:49:12 2015
+ops at hoovism.com, Matthew Hoover, US, NJ, US, TRUE, TRUE, No, http://tor.hoovism.com/, https://tor.hoovism.com/, rsync://tor.hoovism.com/tor/, , http://tor.hoovism.com/dist/, https://tor.hoovism.com/dist/, rsync://tor.hoovism.com/tor/dist/, http://bt3ehg7prnlm6tyv.onion/, Wed Jul 15 18:49:12 2015
+tormaster AT urown DOT net, urown.net, CH, Switzerland, Europe, TRUE, TRUE, No, http://torproject.urown.net/, https://torproject.urown.net/, , , http://torproject.urown.net/dist/, https://torproject.urown.net/dist/, , http://torprowdd64ytmyk.onion, Wed Jul 15 18:49:12 2015
+Stefan, sela Internet, DE, Germany, DE, TRUE, TRUE, No, http://sela.io/mirrors/torproject.org/, https://sela.io/mirrors/torproject.org/, , , http://sela.io/mirrors/torproject.org/dist/, https://sela.io/mirrors/torproject.org/dist/, , , Wed Jul 15 18:49:12 2015
+justaguy AT justaguy DOT pw, Justaguy, NL, The Netherlands, NL, True, False, No, http://services.justaguy.pw/, https://services.justaguy.pw/, , , http://services.justaguy.pw/dist, https://services.justaguy.pw/dist, , http://3qzbcsjhwseov7k4.onion, Wed Jul 15 18:49:12 2015
+thomaswhite AT riseup DOT net, TheCthulhu, NL, The Netherlands, NL, True, False, No, http://tor.thecthulhu.com/, https://tor.thecthulhu.com/, , , http://tor.thecthulhu.com/dist/, https://tor.thecthulhu.com/dist/, , , Wed Jul 15 18:49:12 2015
+rush23 AT gmx DOT net, Tor Supporter, DE, Germany, Europe, TRUE, FALSE, No, http://tor-proxy.euve59946.serverprofi24.de/, , , , http://tor-proxy.euve59946.serverprofi24.de/dist/, , , , Thu Jun 4 19:06:42 2015
+webmaster AT ccc DOT de, CCC, NL, The Netherlands, Europe, TRUE, FALSE, No, http://tor.ccc.de/, https://tor.ccc.de, , , http://tor.ccc.de/dist/, https://tor.ccc.de/dist/, , , Wed Jul 15 18:49:12 2015
+mitchell AT lcsks DOT com, CCC, US, United States, US, TRUE, FALSE, No, http://mirror.lcsks.com, , , , , , , ,
1
0
commit e35c09f55571c1b1966c263643a38eaeb94c8a9a
Author: ilv <ilv(a)users.noreply.github.com>
Date: Mon Aug 3 15:08:29 2015 -0300
Debugging improvements
---
process_email.py | 41 +++++++++++++++++++++++++++++++++++++++++
smtp_demo.py | 22 ----------------------
2 files changed, 41 insertions(+), 22 deletions(-)
diff --git a/process_email.py b/process_email.py
new file mode 100644
index 0000000..504b5dd
--- /dev/null
+++ b/process_email.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+import logging
+
+import gettor.smtp
+
+def main():
+ logging_level = 'INFO'
+ logging_file = '/path/to/gettor/log/process_email.log'
+ logging_format = '[%(levelname)s] %(asctime)s - %(message)s'
+ date_format = "%Y-%m-%d" # %H:%M:%S
+
+ logging.basicConfig(
+ format=logging_format,
+ datefmt=date_format,
+ filename = logging_file,
+ level = logging_level
+ )
+
+ logging.debug("New email received")
+ logging.debug("Creating new SMTP object")
+
+ try:
+ service = gettor.smtp.SMTP('/path/to/gettor/smtp.cfg')
+ incoming = sys.stdin.read()
+ service.process_email(incoming)
+ logging.debug("Email processed sucessfully")
+ except gettor.smtp.ConfigError as e:
+ logging.error("Configuration error: %s" % str(e))
+ except gettor.smtp.SendEmailError as e:
+ logging.error("SMTP not working: %s" % str(e))
+ except gettor.smtp.InternalError as e:
+ logging.error("Core module not working: %s" % str(e))
+ except Exception as e:
+ # in case something unexpected happens
+ logging.critical("Unexpected error: %s" % str(e))
+
+if __name__ == '__main__':
+ main()
diff --git a/smtp_demo.py b/smtp_demo.py
deleted file mode 100644
index 0ec341e..0000000
--- a/smtp_demo.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-import sys
-
-import gettor.smtp
-
-service = gettor.smtp.SMTP()
-
-# For now we simulate mails reading from stdin
-# In linux test as follows:
-# $ python smtp_demo.py < email.eml
-
-incoming = sys.stdin.read()
-try:
- print "Email received!"
- service.process_email(incoming)
- print "Email sent!"
-except gettor.smtp.ConfigError as e:
- print "Misconfiguration: " + str(e)
-except gettor.smtp.SendEmailError as e:
- print "SMTP not working: " + str(e)
-except gettor.smtp.InternalError as e:
- print "Core module not working: " + str(e)
1
0
commit c745cbd07d09b368b058b208a51c5ae66e8aa736
Author: ilv <ilv(a)users.noreply.github.com>
Date: Thu Aug 27 15:16:08 2015 -0300
Better format for sending the links
---
gettor/core.py | 86 +++++++++++++++++++++++++++++++----
gettor/smtp.py | 19 +++++---
lang/core/i18n/en/en.po | 2 +-
lang/smtp/i18n/en/LC_MESSAGES/en.po | 4 +-
4 files changed, 94 insertions(+), 17 deletions(-)
diff --git a/gettor/core.py b/gettor/core.py
index 219fed2..49fbbb2 100644
--- a/gettor/core.py
+++ b/gettor/core.py
@@ -197,7 +197,18 @@ class Core(object):
# read the links files using ConfigParser
# see the README for more details on the format used
- links = []
+ links_files = []
+
+ links32 = {}
+ links64 = {}
+
+ # for the message to be sent
+ if osys == 'windows':
+ arch = '32/64'
+ elif osys == 'osx':
+ arch = '64'
+ else:
+ arch = '32'
# look for files ending with .links
p = re.compile('.*\.links$')
@@ -205,7 +216,7 @@ class Core(object):
for name in os.listdir(self.linksdir):
path = os.path.abspath(os.path.join(self.linksdir, name))
if os.path.isfile(path) and p.match(path):
- links.append(path)
+ links_files.append(path)
# let's create a dictionary linking each provider with the links
# found for os and lc. This way makes it easy to check if no
@@ -216,7 +227,7 @@ class Core(object):
spt = '=' * 72
# reading links from providers directory
- for name in links:
+ for name in links_files:
# we're reading files listed on linksdir, so they must exist!
config = ConfigParser.ConfigParser()
# but just in case they don't
@@ -231,14 +242,34 @@ class Core(object):
# check if current provider pname has links for os in lc
providers[pname] = config.get(osys, lc)
- # avoid showing it all together
- providers[pname] = providers[pname].replace(",", "")
- providers[pname] = providers[pname].replace("$", "\n\n")
+ except ConfigParser.Error as e:
+ # we should at least have the english locale available
+ self.log.error("Request for %s, returning 'en' instead" % lc)
+ providers[pname] = config.get(osys, 'en')
+ try:
+ #test = providers[pname].split("$")
+ #self.log.debug(test)
+ if osys == 'linux':
+ t32, t64 = [t for t in providers[pname].split(",") if t]
+
+ link, signature, chs32 = [l for l in t32.split("$") if l]
+ links32[link] = signature
+
+ link, signature, chs64 = [l for l in t64.split("$") if l]
+ links64[link] = signature
+
+ else:
+ link, signature, chs32 = [l for l in providers[pname].split("$") if l]
+ links32[link] = signature
+
+ #providers[pname] = providers[pname].replace(",", "")
+ #providers[pname] = providers[pname].replace("$", "\n\n")
# all packages are signed with same key
# (Tor Browser developers)
fingerprint = config.get('key', 'fingerprint')
- fingerprint_msg = self._get_msg('fingerprint', lc)
+ # for now, english messages only
+ fingerprint_msg = self._get_msg('fingerprint', 'en')
fingerprint_msg = fingerprint_msg % fingerprint
except ConfigParser.Error as e:
raise InternalError("%s" % str(e))
@@ -246,10 +277,47 @@ class Core(object):
# create the final links list with all providers
all_links = []
+ msg = "Tor Browser %s-bit:" % arch
+ for link in links32:
+ msg = "%s\n%s" % (msg, link)
+
+ all_links.append(msg)
+
+ if osys == 'linux':
+ msg = "\n\n\nTor Browser 64-bit:"
+ for link in links64:
+ msg = "%s\n%s" % (msg, link)
+
+ all_links.append(msg)
+
+ msg = "\n\n\nTor Browser's signature %s-bit (in the same order):" %\
+ arch
+ for link in links32:
+ msg = "%s\n%s" % (msg, links32[link])
+
+ all_links.append(msg)
+
+ if osys == 'linux':
+ msg = "\n\n\nTor Browser's signature 64-bit:"
+ for link in links64:
+ msg = "%s\n%s" % (msg, links64[link])
+
+ all_links.append(msg)
+
+ msg = "\n\n\nSHA256 of Tor Browser %s-bit (advanced): %s\n" %\
+ (arch, chs32)
+ all_links.append(msg)
+
+ if osys == 'linux':
+ msg = "SHA256 of Tor Browser 64-bit (advanced): %s\n" % chs64
+ all_links.append(msg)
+
+ """
for key in providers.keys():
# get more friendly description of the provider
try:
- provider_desc = self._get_msg('provider_desc', lc)
+ # for now, english messages only
+ provider_desc = self._get_msg('provider_desc', 'en')
provider_desc = provider_desc % key
all_links.append(
@@ -258,6 +326,7 @@ class Core(object):
)
except ConfigError as e:
raise InternalError("%s" % str(e))
+ """
# add fingerprint after the links
all_links.append(fingerprint_msg)
@@ -405,6 +474,7 @@ class Core(object):
"""Add request to database."""
self.log.debug("Trying to add request to database")
try:
+ self.db.connect()
self.db.add_request()
self.log.debug("Request added!")
except db.DBError as e:
diff --git a/gettor/smtp.py b/gettor/smtp.py
index 4db3ac7..34477ef 100644
--- a/gettor/smtp.py
+++ b/gettor/smtp.py
@@ -76,7 +76,7 @@ class SMTP(object):
config = ConfigParser.ConfigParser()
if cfg is None or not os.path.isfile(cfg):
- cfg = DEFAULT_CONFIG_FILE
+ cfg = default_cfg
try:
with open(cfg) as f:
@@ -240,7 +240,12 @@ class SMTP(object):
"""
req = self._parse_text(msg)
lc = self._get_lc(addr)
- req['lc'] = lc
+ supported_lc = self.core.get_supported_lc()
+
+ if lc in supported_lc:
+ req['lc'] = lc
+ else:
+ req['lc'] = 'en'
return req
@@ -361,8 +366,8 @@ class SMTP(object):
"""
# obtain the content in the proper language and send it
try:
- links_subject = self._get_msg('links_subject', lc)
- links_msg = self._get_msg('links_msg', lc)
+ links_subject = self._get_msg('links_subject', 'en')
+ links_msg = self._get_msg('links_msg', 'en')
links_msg = links_msg % (os, lc, links)
self._send_email(
@@ -490,7 +495,7 @@ class SMTP(object):
self.log.debug("Trying to send help...")
# make sure we can send emails
try:
- self._send_help(req['lc'], our_addr, norm_from_addr)
+ self._send_help('en', our_addr, norm_from_addr)
status = 'success'
except SendEmailError as e:
status = 'internal_error'
@@ -503,7 +508,7 @@ class SMTP(object):
self.log.debug("Trying to send the mirrors...")
# make sure we can send emails
try:
- self._send_mirrors(req['lc'], our_addr, norm_from_addr)
+ self._send_mirrors('en', our_addr, norm_from_addr)
status = 'success'
except SendEmailError as e:
status = 'internal_error'
@@ -519,7 +524,7 @@ class SMTP(object):
'SMTP', req['os'], req['lc']
)
# if core fails, we fail too
- except (core.InternalError, core.ConfigurationError) as e:
+ except (core.InternalError, core.ConfigError) as e:
status = 'core_error'
self.log.debug("FAILED: %s" % str(e))
# something went wrong with the core
diff --git a/lang/core/i18n/en/en.po b/lang/core/i18n/en/en.po
index b8d4509..0b28a70 100644
--- a/lang/core/i18n/en/en.po
+++ b/lang/core/i18n/en/en.po
@@ -2,7 +2,7 @@ domain "en"
#: Fingerprint message
msgid "fingerprint"
-msgstr "Fingerprint of the key used to sign Tor Browser:\n%s"
+msgstr "Fingerprint of key used to sign Tor Browser (advanced): %s"
#: Provider description
msgid "provider_desc"
diff --git a/lang/smtp/i18n/en/LC_MESSAGES/en.po b/lang/smtp/i18n/en/LC_MESSAGES/en.po
index dcb2e35..ee6a24e 100644
--- a/lang/smtp/i18n/en/LC_MESSAGES/en.po
+++ b/lang/smtp/i18n/en/LC_MESSAGES/en.po
@@ -28,6 +28,7 @@ Below are the links for your request (Tor Browser for %s, %s package):\n\
\n\
%s\n\
\n\
+===========================================================================\n\
Still need help? If you have any questions, trouble connecting to Tor\n\
network, or need to talk to a human, please contact our support team at:\n\
\n\
@@ -63,7 +64,8 @@ Please reply to this message with one of the options below:\n\
windows\n\
linux\n\
osx\n\
+ mirrors\n\
\n\
-And I will send you the download instructions quickly.\n\
+And I will send you the download/access instructions quickly.\n\
\n\
Tip: Just send a blank reply to this message if you are not sure."
1
0
commit e1fe0b98202d07aaacb14d0dc18bce8080642e67
Author: ilv <ilv(a)users.noreply.github.com>
Date: Thu Aug 27 15:14:55 2015 -0300
Better debugging and error handling
---
gettor/blacklist.py | 65 ++++++++++++++++++++++++---------------------------
gettor/db.py | 7 +++++-
2 files changed, 37 insertions(+), 35 deletions(-)
diff --git a/gettor/blacklist.py b/gettor/blacklist.py
index a16c764..635d9a7 100644
--- a/gettor/blacklist.py
+++ b/gettor/blacklist.py
@@ -120,44 +120,41 @@ class Blacklist(object):
:raise: BlacklistError if the user is blacklisted
"""
- r = self.db.get_user(user, service)
- if r:
- # permanently blacklisted
- if r['blocked']:
- try:
+ try:
+ self.log.info("Trying to get info from user")
+ self.db.connect()
+ r = self.db.get_user(user, service)
+ if r:
+ # permanently blacklisted
+ if r['blocked']:
+ self.log.warning("Request from user permanently blocked")
self.db.update_user(user, service, r['times']+1, 1)
raise BlacklistError("Blocked user")
- except db.DBError as e:
- raise InternalError("Can't update user (%s)" % str(e))
- # don't be greedy
- elif r['times'] >= max_req:
- last = datetime.datetime.fromtimestamp(
- float(r['last_request'])
- )
- next = last + datetime.timedelta(minutes=wait_time)
-
- if datetime.datetime.now() < next:
- # too many requests from the same user
- try:
+ # don't be greedy
+ elif r['times'] >= max_req:
+ last = datetime.datetime.fromtimestamp(
+ float(r['last_request'])
+ )
+ next = last + datetime.timedelta(minutes=wait_time)
+
+ if datetime.datetime.now() < next:
+ self.log.warning("Too many requests from same user")
self.db.update_user(user, service, r['times']+1, 0)
raise BlacklistError("Too many requests")
- except db.DBError as e:
- raise InternalError("Can't update user (%s)" % str(e))
- else:
- # fresh user again!
- try:
+ else:
+ # fresh user again!
+ self.log.info("Updating counter for existing user")
self.db.update_user(user, service, 1, 0)
- except db.DBError as e:
- raise InternalError("Can't update user (%s)" % str(e))
- else:
- # adding up a request for user
- try:
+ else:
+ # adding up a request for user
+ self.log.info("Request from existing user")
self.db.update_user(user, service, r['times']+1, 0)
- except db.DBError as e:
- raise InternalError("Can't update user (%s)" % str(e))
- else:
- # new request for user
- try:
+ else:
+ # new request for user
+ self.log.info("Request from new user")
self.db.add_user(user, service, 0)
- except db.DBError as e:
- raise InternalError("Can't add new user (%s)" % str(e))
+ except db.DBError as e:
+ self.log.error("Something failed!")
+ raise InternalError("Error with database (%s)" % str(e))
+ except BlacklistError as e:
+ raise BlacklistError(e)
diff --git a/gettor/db.py b/gettor/db.py
index 0b971af..7a595a3 100644
--- a/gettor/db.py
+++ b/gettor/db.py
@@ -44,8 +44,13 @@ class DB(object):
:param: dbname (string) the path of the database.
"""
+ self.dbname = dbname
+
+
+ def connect(self):
+ """ """
try:
- self.con = sqlite3.connect(dbname)
+ self.con = sqlite3.connect(self.dbname)
self.con.row_factory = sqlite3.Row
except sqlite3.Error as e:
raise DBError("%s" % str(e))
1
0
[gettor/master] Better debugging, error handling and mirrors option for xmpp
by ilv@torproject.org 03 Nov '15
by ilv@torproject.org 03 Nov '15
03 Nov '15
commit d71e6838bda2a158963228f321d1cb682c5f4297
Author: ilv <ilv(a)users.noreply.github.com>
Date: Thu Aug 27 15:17:21 2015 -0300
Better debugging, error handling and mirrors option for xmpp
---
gettor/xmpp.py | 200 +++++++++++++++++++++--------------
lang/xmpp/i18n/en/LC_MESSAGES/en.po | 72 +++++++++++--
process_chat.py | 22 ++++
xmpp.cfg | 2 +
4 files changed, 207 insertions(+), 89 deletions(-)
diff --git a/gettor/xmpp.py b/gettor/xmpp.py
index e9d2a10..f9b025d 100644
--- a/gettor/xmpp.py
+++ b/gettor/xmpp.py
@@ -5,8 +5,8 @@
# :authors: Israel Leiva <ilv(a)riseup.net>
# see also AUTHORS file
#
-# :copyright: (c) 2008-2014, The Tor Project, Inc.
-# (c) 2014, Israel Leiva
+# :copyright: (c) 2008-2015, The Tor Project, Inc.
+# (c) 2015, Israel Leiva
#
# :license: This is Free Software. See LICENSE for license information.
@@ -20,6 +20,7 @@ import logging
import ConfigParser
from sleekxmpp import ClientXMPP
+from sleekxmpp.xmlstream.stanzabase import JID
from sleekxmpp.exceptions import IqError, IqTimeout
import core
@@ -30,6 +31,14 @@ import blacklist
"""XMPP module for processing requests."""
+class ConfigError(Exception):
+ pass
+
+
+class InternalError(Exception):
+ pass
+
+
class Bot(ClientXMPP):
"""XMPP bot.
@@ -52,10 +61,11 @@ class Bot(ClientXMPP):
self.get_roster()
except IqError as err:
# error getting the roster
- # logging.error(err.iq['error']['condition'])
+ self.xmpp.log.error(err.iq['error']['condition'])
self.disconnect()
except IqTimeout:
# server is taking too long to respond
+ self.xmpp.log.error("Server is taking too long to respond")
self.disconnect()
def message(self, msg):
@@ -65,14 +75,6 @@ class Bot(ClientXMPP):
msg.reply(msg_to_send).send()
-class ConfigError(Exception):
- pass
-
-
-class InternalError(Exception):
- pass
-
-
class XMPP(object):
"""Receive and reply requests by XMPP.
@@ -95,75 +97,63 @@ class XMPP(object):
"""
# define a set of default values
- DEFAULT_CONFIG_FILE = 'xmpp.cfg'
-
- logging.basicConfig(format='[%(levelname)s] %(asctime)s - %(message)s',
- datefmt="%Y-%m-%d %H:%M:%S")
- log = logging.getLogger(__name__)
+ default_cfg = 'xmpp.cfg'
config = ConfigParser.ConfigParser()
if cfg is None or not os.path.isfile(cfg):
- cfg = DEFAULT_CONFIG_FILE
-
- config.read(cfg)
+ cfg = default_cfg
try:
- self.user = config.get('account', 'user')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'user' from 'account'")
+ with open(cfg) as f:
+ config.readfp(f)
+ except IOError:
+ raise ConfigError("File %s not found!" % cfg)
try:
+ self.user = config.get('account', 'user')
self.password = config.get('account', 'password')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'password' from 'account'")
- try:
- self.core_cfg = config.get('general', 'core_cfg')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'core_cfg' from 'general'")
+ self.mirrors = config.get('general', 'mirrors')
+ self.max_words = config.get('general', 'max_words')
+ self.max_words = int(self.max_words)
+ core_cfg = config.get('general', 'core_cfg')
+ self.core = core.Core(core_cfg)
+ self.i18ndir = config.get('i18n', 'dir')
- try:
blacklist_cfg = config.get('blacklist', 'cfg')
- self.bl = blacklist_cfg
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'cfg' from 'blacklist'")
-
- try:
+ self.bl = blacklist.Blacklist(blacklist_cfg)
self.bl_max_req = config.get('blacklist', 'max_requests')
self.bl_max_req = int(self.bl_max_req)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'max_requests' from 'blacklist'")
-
- try:
self.bl_wait_time = config.get('blacklist', 'wait_time')
self.bl_wait_time = int(self.bl_wait_time)
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'wait_time' from 'blacklist'")
-
- try:
- self.i18ndir = config.get('i18n', 'dir')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'i18n'")
- try:
logdir = config.get('log', 'dir')
logfile = os.path.join(logdir, 'xmpp.log')
- except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'dir' from 'log'")
-
- try:
loglevel = config.get('log', 'level')
+
except ConfigParser.Error as e:
- raise ConfigError("Couldn't read 'level' from 'log'")
+ raise ConfigError("Configuration error: %s" % str(e))
+ except blacklist.ConfigError as e:
+ raise InternalError("Blacklist error: %s" % str(e))
+ except core.ConfigError as e:
+ raise InternalError("Core error: %s" % str(e))
+
+ # logging
+ log = logging.getLogger(__name__)
- # establish log level and redirect to log file
- log.info('Redirecting logging to %s' % logfile)
+ logging_format = utils.get_logging_format()
+ date_format = utils.get_date_format()
+ formatter = logging.Formatter(logging_format, date_format)
+
+ log.info('Redirecting XMPP logging to %s' % logfile)
logfileh = logging.FileHandler(logfile, mode='a+')
+ logfileh.setFormatter(formatter)
logfileh.setLevel(logging.getLevelName(loglevel))
log.addHandler(logfileh)
# stop logging on stdout from now on
log.propagate = False
+ self.log = log
def start_bot(self):
"""Start the bot for handling requests.
@@ -171,6 +161,7 @@ class XMPP(object):
Start a new sleekxmpp bot.
"""
+ self.log.info("Starting the bot with account %s" % self.user)
xmpp = Bot(self.user, self.password, self)
xmpp.connect()
xmpp.process(block=True)
@@ -184,11 +175,11 @@ class XMPP(object):
"""
anon_acc = utils.get_sha256(account)
- bl = blacklist.Blacklist(self.bl)
try:
- bl.is_blacklisted(anon_acc, 'XMPP', self.bl_max_req,
- self.bl_wait_time)
+ self.bl.is_blacklisted(
+ anon_acc, 'XMPP', self.bl_max_req, self.bl_wait_time
+ )
return False
except blacklist.BlacklistError as e:
return True
@@ -203,13 +194,17 @@ class XMPP(object):
"""
# obtain the content in the proper language
- t = gettext.translation(lc, self.i18ndir, languages=[lc])
- _ = t.ugettext
+ self.log.debug("Trying to get translated text")
+ try:
+ t = gettext.translation(lc, self.i18ndir, languages=[lc])
+ _ = t.ugettext
- msgstr = _(msgid)
- return msgstr
+ msgstr = _(msgid)
+ return msgstr
+ except IOError as e:
+ raise ConfigError("%s" % str(e))
- def _parse_text(self, msg, core_obj):
+ def _parse_text(self, msg):
"""Parse the text part of a message.
Split the message in words and look for patterns for locale,
@@ -223,20 +218,21 @@ class XMPP(object):
"""
# core knows what OS are supported
- supported_os = core_obj.get_supported_os()
- supported_lc = core_obj.get_supported_lc()
+ supported_os = self.core.get_supported_os()
+ supported_lc = self.core.get_supported_lc()
+ self.log.debug("Parsing text")
# default values
req = {}
req['lc'] = 'en'
req['os'] = None
req['type'] = 'help'
+
found_lc = False
found_os = False
+ found_mirrors = False
# analyze every word
- # request shouldn't be more than 10 words long, so there should
- # be a limit for the amount of words
for word in msg.split(' '):
# look for lc and os
if not found_lc:
@@ -250,6 +246,14 @@ class XMPP(object):
found_os = True
req['os'] = os
req['type'] = 'links'
+ # mirrors
+ if not found_mirrors:
+ if re.match("mirrors?", word, re.IGNORECASE):
+ found_mirrors = True
+ req['type'] = 'mirrors'
+ if (found_lc and found_os) or (found_lc and found_mirrors):
+ break
+
return req
def parse_request(self, account, msg):
@@ -269,36 +273,70 @@ class XMPP(object):
reply = ''
status = ''
req = None
- core_obj = core.Core(self.core_cfg)
+ self.log.debug("Parsing request")
try:
if self._is_blacklisted(str(account)):
+ self.log.info("Request from blacklisted account!")
status = 'blacklisted'
bogus_request = True
+ # first let's find out how many words are in the message
+ # request shouldn't be longer than 3 words, but just in case
+ words = msg.split(' ')
+ if len(words) > self.max_words:
+ bogus_request = True
+ self.log.info("Message way too long")
+ status = 'error'
+ reply = self._get_msg('message_error', 'en')
+
if not bogus_request:
+ self.log.debug("Request seems legit, let's parse it")
# let's try to guess what the user is asking
- req = self._parse_text(str(msg), core_obj)
+ req = self._parse_text(str(msg))
if req['type'] == 'help':
+ self.log.debug("Type of request: help")
status = 'success'
- reply = self._get_msg('help', req['lc'])
- elif req['type'] == 'links':
+ reply = self._get_msg('help', 'en')
+
+ elif req['type'] == 'mirrors':
+ self.log.debug("Type of request: mirrors")
+ status = 'success'
+ reply = self._get_msg('mirrors', 'en')
try:
- links = core_obj.get_links("XMPP", req['os'],
- req['lc'])
- reply = self._get_msg('links', req['lc'])
- reply = reply % (req['os'], req['lc'], links)
-
- status = 'success'
- except (core.ConfigError, core.InternalError) as e:
- # if core failes, send the user an error message, but
- # keep going
- status = 'core_error'
- reply = self._get_msg('internal_error', req['lc'])
+ with open(self.mirrors, "r") as list_mirrors:
+ mirrors = list_mirrors.read()
+ reply = reply % mirrors
+ except IOError as e:
+ reply = self._get_msg('mirrors_unavailable', 'en')
+
+ elif req['type'] == 'links':
+ self.log.debug("Type of request: help")
+ links = self.core.get_links(
+ "XMPP",
+ req['os'],
+ req['lc']
+ )
+ reply = self._get_msg('links', 'en')
+ reply = reply % (req['os'], req['lc'], links)
+
+ status = 'success'
+
+ except (core.ConfigError, core.InternalError) as e:
+ # if core failes, send the user an error message, but keep going
+ self.log.error("Something went wrong internally: %s" % str(e))
+ status = 'core_error'
+ reply = self._get_msg('internal_error', req['lc'])
+
finally:
# keep stats
if req:
- core_obj.add_request_to_db()
+ self.log.debug("Adding request to database... ")
+ self.core.add_request_to_db()
+ if reply:
+ self.log.debug("Everything seems OK. Sending back the reply")
+ else:
+ self.log.debug("Nothing to reply!")
return reply
diff --git a/lang/xmpp/i18n/en/LC_MESSAGES/en.po b/lang/xmpp/i18n/en/LC_MESSAGES/en.po
index d242625..8cc715e 100644
--- a/lang/xmpp/i18n/en/LC_MESSAGES/en.po
+++ b/lang/xmpp/i18n/en/LC_MESSAGES/en.po
@@ -2,21 +2,77 @@ domain "en"
#: Links
msgid "links"
-msgstr "Links %s-%s:\n %s"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+Below are the links for your request (Tor Browser for %s, %s package):\n\
+\n\
+%s\n\
+\n\
+===========================================================================\n\
+Still need help? If you have any questions, trouble connecting to Tor\n\
+network, or need to talk to a human, please contact our support team at:\n\
+\n\
+ help(a)rt.torproject.org\n\
+\n\
+We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
+French and Spanish."
-#: Links
-msgid "links_pt"
-msgstr "Links-PT for %s-%s:\n %s"
+#: Mirrors message
+msgid "mirrors"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+Thank you for your request. Below you will find an updated list of mirrors\n\
+of Tor Project's website.\n\
+\n\
+%s\n\
+\n\
+Still need help? If you have any questions, trouble connecting to Tor\n\
+network, or need to talk to a human, please contact our support team at:\n\
+\n\
+ help(a)rt.torproject.org\n\
+\n\
+We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
+French and Spanish."
#: Help
msgid "help"
-msgstr "*help*"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+Thank you for your request. I am here to help you download the latest\n\
+Tor Browser.\n\
+\n\
+Please reply to this message with one of the options below (where lc stands\n\
+for the locale of the package you want e.g. en):\n\
+\n\
+ windows lc\n\
+ linux lc\n\
+ osx lc\n\
+ mirrors\n\
+\n\
+The currently supported locales are:\n\
+\n\
+ en: English\n\
+\n\
+And I will send you the download/access instructions quickly."
-#: Unsupported locale
-msgid "unsupported_lc"
-msgstr "Unsupported locale"
+#: Mirrors unavailable message
+msgid "mirrors_unavailable"
+msgstr "Hello there! this is the 'GetTor' robot.\n\
+\n\
+I'm sorry, I can't send you mirrors right now, please try again later.\n\
+\n\
+Still need help? If you have any questions, trouble connecting to Tor\n\
+network, or need to talk to a human, please contact our support team at:\n\
+\n\
+ help(a)rt.torproject.org\n\
+\n\
+We are ready to answer your queries in English, Farsi, Chinese, Arabic,\n\
+French and Spanish."
#: Internal error
msgid "internal_error"
msgstr "Internal error"
+#: Internal error
+msgid "message_error"
+msgstr "Message too long."
diff --git a/process_chat.py b/process_chat.py
new file mode 100644
index 0000000..6ad7b59
--- /dev/null
+++ b/process_chat.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+import logging
+
+import gettor.xmpp
+
+def main():
+ try:
+ bot = gettor.xmpp.XMPP()
+ bot.start_bot()
+ except gettor.xmpp.ConfigError as e:
+ print "Configuration error: %s" % str(e)
+ except gettor.xmpp.InternalError as e:
+ print "Core module not working: %s" % str(e)
+ except Exception as e:
+ # in case something unexpected happens
+ print "Unexpected error: %s" % str(e)
+
+if __name__ == '__main__':
+ main()
diff --git a/xmpp.cfg b/xmpp.cfg
index 0b2f547..d81d4df 100644
--- a/xmpp.cfg
+++ b/xmpp.cfg
@@ -5,6 +5,8 @@ password:
[general]
basedir: /path/to/gettor/xmpp/
core_cfg: /path/to/core.cfg
+max_words: 10
+db: /path/to/gettor.db
[blacklist]
cfg: /path/to/blacklist.cfg
1
0
commit 54ebdf8ec2110dd381e66e07349add7ead190dce
Author: ilv <ilv(a)users.noreply.github.com>
Date: Tue Nov 3 16:06:56 2015 -0300
Change related to #17211
---
gettor/xmpp.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gettor/xmpp.py b/gettor/xmpp.py
index f9b025d..a605f50 100644
--- a/gettor/xmpp.py
+++ b/gettor/xmpp.py
@@ -283,7 +283,7 @@ class XMPP(object):
# first let's find out how many words are in the message
# request shouldn't be longer than 3 words, but just in case
- words = msg.split(' ')
+ words = re.split('\s+', msg.strip())
if len(words) > self.max_words:
bogus_request = True
self.log.info("Message way too long")
1
0
commit 540c525cb038ff42684488f4a1b3f4c5078b5b8e
Author: ilv <ilv(a)users.noreply.github.com>
Date: Tue Nov 3 16:06:20 2015 -0300
Minor correction to #17211
---
gettor/smtp.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gettor/smtp.py b/gettor/smtp.py
index 5476189..3697786 100644
--- a/gettor/smtp.py
+++ b/gettor/smtp.py
@@ -271,7 +271,7 @@ class SMTP(object):
# search for OS or mirrors request
# if nothing is found, help by default
found_request = False
- words = re.split('\s+', test.strip())
+ words = re.split('\s+', msg.strip())
for word in words:
if not found_request:
# OS first
1
0