diff options
Diffstat (limited to 'allium')
-rwxr-xr-x | allium/allium.py | 88 | ||||
-rw-r--r-- | allium/lib/relays.py | 270 | ||||
-rw-r--r-- | allium/templates/relay-info.html | 414 | ||||
-rw-r--r-- | allium/templates/relay-list.html | 314 |
4 files changed, 560 insertions, 526 deletions
diff --git a/allium/allium.py b/allium/allium.py index 533eb66..05258db 100755 --- a/allium/allium.py +++ b/allium/allium.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 -''' +""" File: allium.py (executable) Generate complete set of relay HTML pages and copy static files to the output_dir Default output directory: ./www -''' +""" import argparse import os @@ -17,18 +17,28 @@ from lib.relays import Relays ABS_PATH = os.path.dirname(os.path.abspath(__file__)) -if __name__ == '__main__': - desc = 'allium: generate static tor relay metrics and statistics' +if __name__ == "__main__": + desc = "allium: generate static tor relay metrics and statistics" parser = argparse.ArgumentParser(description=desc) - parser.add_argument('--out', dest='output_dir', type=str, - default="./www", - help='directory to store rendered files (default "./www")', - required=False) - parser.add_argument('--onionoo-url', dest='onionoo_url', type=str, - default="https://onionoo.torproject.org/details", - help='onionoo HTTP URL (default '\ - '"https://onionoo.torproject.org/details")', - required=False) + parser.add_argument( + "--out", + dest="output_dir", + type=str, + default="./www", + help='directory to store rendered files (default "./www")', + required=False, + ) + parser.add_argument( + "--onionoo-url", + dest="onionoo_url", + type=str, + default="https://onionoo.torproject.org/details", + help=( + "onionoo HTTP URL (default " + '"https://onionoo.torproject.org/details")' + ), + required=False, + ) args = parser.parse_args() # object containing onionoo data and processing routines @@ -40,40 +50,44 @@ if __name__ == '__main__': # index and "all" HTML relay sets; index set limited to 500 relays RELAY_SET.write_misc( - template = 'index.html', - path = 'index.html', - path_prefix = './', - is_index = True, - ) - RELAY_SET.write_misc( - template = 'all.html', - path = 'misc/all.html' + template="index.html", + path="index.html", + path_prefix="./", + is_index=True, ) + RELAY_SET.write_misc(template="all.html", path="misc/all.html") # miscellaneous page filename suffixes and sorted-by keys misc_pages = { - 'by-bandwidth': '1.bandwidth', - 'by-exit-count': '1.exit_count,1.bandwidth', - 'by-middle-count': '1.middle_count,1.bandwidth', - 'by-first-seen': '1.first_seen,1.bandwidth' + "by-bandwidth": "1.bandwidth", + "by-exit-count": "1.exit_count,1.bandwidth", + "by-middle-count": "1.middle_count,1.bandwidth", + "by-first-seen": "1.first_seen,1.bandwidth", } # miscellaneous-sorted (per misc_pages k/v) HTML pages for k, v in misc_pages.items(): RELAY_SET.write_misc( - template = 'misc-families.html', - path = 'misc/families-{}.html'.format(k), - sorted_by = v + template="misc-families.html", + path="misc/families-{}.html".format(k), + sorted_by=v, ) RELAY_SET.write_misc( - template = 'misc-networks.html', - path = 'misc/networks-{}.html'.format(k), - sorted_by = v + template="misc-networks.html", + path="misc/networks-{}.html".format(k), + sorted_by=v, ) # onionoo keys used to generate pages by unique value; e.g. AS43350 - keys = ['as', 'contact', 'country', 'family', 'flag', 'platform', - 'first_seen'] + keys = [ + "as", + "contact", + "country", + "family", + "flag", + "platform", + "first_seen", + ] for k in keys: RELAY_SET.write_pages_by_key(k) @@ -82,6 +96,8 @@ if __name__ == '__main__': RELAY_SET.write_relay_info() # copy static directory and its contents if it doesn't exist - if not os.path.exists(os.path.join(args.output_dir, 'static')): - copytree(os.path.join(ABS_PATH, 'static'), - os.path.join(args.output_dir, 'static')) + if not os.path.exists(os.path.join(args.output_dir, "static")): + copytree( + os.path.join(ABS_PATH, "static"), + os.path.join(args.output_dir, "static"), + ) diff --git a/allium/lib/relays.py b/allium/lib/relays.py index 7be77f5..664175e 100644 --- a/allium/lib/relays.py +++ b/allium/lib/relays.py @@ -1,9 +1,9 @@ -''' +""" File: relays.py Relays class object consisting of relays (list of dict) and onionoo fetch timestamp -''' +""" import hashlib import json @@ -16,13 +16,16 @@ from shutil import rmtree from jinja2 import Environment, FileSystemLoader ABS_PATH = os.path.dirname(os.path.abspath(__file__)) -ENV = Environment(loader=FileSystemLoader(os.path.join(ABS_PATH, '../templates')), - trim_blocks=True, lstrip_blocks=True) +ENV = Environment( + loader=FileSystemLoader(os.path.join(ABS_PATH, "../templates")), + trim_blocks=True, + lstrip_blocks=True, +) + + +class Relays: + """Relay class consisting of processing routines and onionoo data""" -class Relays(): - ''' - Relay class consisting of processing routines and onionoo data - ''' def __init__(self, output_dir, onionoo_url): self.output_dir = output_dir self.onionoo_url = onionoo_url @@ -39,12 +42,12 @@ class Relays(): self._categorize() def _fetch_onionoo_details(self): - ''' + """ Make request to onionoo to retrieve details document, return JSON response - ''' + """ if os.path.isfile(self.ts_file): - with open(self.ts_file, 'r') as ts_file: + with open(self.ts_file, "r") as ts_file: prev_timestamp = ts_file.read() headers = {"If-Modified-Since": prev_timestamp} conn = urllib.request.Request(self.onionoo_url, headers=headers) @@ -58,24 +61,26 @@ class Relays(): print("no onionoo update since last run, dying peacefully...") sys.exit(1) else: - raise(err) + raise (err) - return json.loads(api_response.decode('utf-8')) + return json.loads(api_response.decode("utf-8")) def _trim_platform(self): - ''' + """ Trim platform to retain base operating system without version number or unnecessary classification which could affect sorting e.g. "Tor 0.3.4.9 on Linux" -> "Linux" - ''' - for relay in self.json['relays']: - if relay.get('platform'): - relay['platform'] = relay['platform'].split(' on ', 1)[1].split(' ')[0] - relay['platform'] = relay['platform'].split('/')[-1] # GNU/* + """ + for relay in self.json["relays"]: + if relay.get("platform"): + relay["platform"] = ( + relay["platform"].split(" on ", 1)[1].split(" ")[0] + ) + relay["platform"] = relay["platform"].split("/")[-1] # GNU/* def _fix_missing_observed_bandwidth(self): - ''' + """ Set the observed_bandwidth parameter value for any relay missing the parameter to 0; the observed_bandwidth parameter is (apparently) optional, I hadn't run into an instance of it missing until 2019-10-03 @@ -84,43 +89,45 @@ class Relays(): found." --https://metrics.torproject.org/onionoo.html#details_relay_observed_bandwidth - ''' - for idx, relay in enumerate(self.json['relays']): - if not relay.get('observed_bandwidth'): - self.json['relays'][idx]['observed_bandwidth'] = 0 + """ + for idx, relay in enumerate(self.json["relays"]): + if not relay.get("observed_bandwidth"): + self.json["relays"][idx]["observed_bandwidth"] = 0 def _add_hashed_contact(self): - ''' + """ Adds a hashed contact key/value for every relay - ''' - for idx, relay in enumerate(self.json['relays']): - c = relay.get('contact', '').encode('utf-8') - self.json['relays'][idx]['contact_md5'] = hashlib.md5(c).hexdigest() + """ + for idx, relay in enumerate(self.json["relays"]): + c = relay.get("contact", "").encode("utf-8") + self.json["relays"][idx]["contact_md5"] = hashlib.md5(c).hexdigest() def _sort_by_bandwidth(self): - ''' + """ Sort full JSON list by highest observed_bandwidth, retain this order during subsequent sorting (country, AS, etc) - ''' - self.json['relays'].sort(key=lambda x: x['observed_bandwidth'], - reverse=True) + """ + self.json["relays"].sort( + key=lambda x: x["observed_bandwidth"], reverse=True + ) def _write_timestamp(self): - ''' + """ Store encoded timestamp in a file to retain time of last request, passed to onionoo via If-Modified-Since header during fetch() if exists - ''' + """ timestamp = time.time() - f_timestamp = time.strftime('%a, %d %b %Y %H:%M:%S GMT', - time.gmtime(timestamp)) + f_timestamp = time.strftime( + "%a, %d %b %Y %H:%M:%S GMT", time.gmtime(timestamp) + ) if self.json is not None: - with open(self.ts_file, 'w', encoding='utf8') as ts_file: + with open(self.ts_file, "w", encoding="utf8") as ts_file: ts_file.write(f_timestamp) return f_timestamp def _sort(self, relay, idx, k, v): - ''' + """ Populate self.sorted dictionary with values from :relay: Args: @@ -128,81 +135,90 @@ class Relays(): idx: index at which the relay can be found in self.json['relays'] k: the name of the key to use in self.sorted v: the name of the subkey to use in self.sorted[k] - ''' - if not v or not re.match(r'^[A-Za-z0-9_-]+$', v): + """ + if not v or not re.match(r"^[A-Za-z0-9_-]+$", v): return - if not k in self.json['sorted']: - self.json['sorted'][k] = dict() + if not k in self.json["sorted"]: + self.json["sorted"][k] = dict() - if not v in self.json['sorted'][k]: - self.json['sorted'][k][v] = { - 'relays': list(), - 'bandwidth': 0, - 'exit_count': 0, - 'middle_count': 0 + if not v in self.json["sorted"][k]: + self.json["sorted"][k][v] = { + "relays": list(), + "bandwidth": 0, + "exit_count": 0, + "middle_count": 0, } - bw = relay['observed_bandwidth'] - self.json['sorted'][k][v]['relays'].append(idx) - self.json['sorted'][k][v]['bandwidth'] += bw + bw = relay["observed_bandwidth"] + self.json["sorted"][k][v]["relays"].append(idx) + self.json["sorted"][k][v]["bandwidth"] += bw - if 'Exit' in relay['flags']: - self.json['sorted'][k][v]['exit_count'] += 1 + if "Exit" in relay["flags"]: + self.json["sorted"][k][v]["exit_count"] += 1 else: - self.json['sorted'][k][v]['middle_count'] += 1 + self.json["sorted"][k][v]["middle_count"] += 1 - if k == 'as': - self.json['sorted'][k][v]['country'] = relay.get('country') - self.json['sorted'][k][v]['country_name'] = relay.get('country') - self.json['sorted'][k][v]['as_name'] = relay.get('as_name') + if k == "as": + self.json["sorted"][k][v]["country"] = relay.get("country") + self.json["sorted"][k][v]["country_name"] = relay.get("country") + self.json["sorted"][k][v]["as_name"] = relay.get("as_name") - if k == 'family': - self.json['sorted'][k][v]['contact'] = relay.get('contact') - self.json['sorted'][k][v]['contact_md5'] = relay.get('contact_md5') + if k == "family": + self.json["sorted"][k][v]["contact"] = relay.get("contact") + self.json["sorted"][k][v]["contact_md5"] = relay.get("contact_md5") # update the first_seen parameter to always contain the oldest # relay's first_seen date - if not self.json['sorted'][k][v].get('first_seen'): - self.json['sorted'][k][v]['first_seen'] = relay['first_seen'] - elif self.json['sorted'][k][v]['first_seen'] > relay['first_seen']: - self.json['sorted'][k][v]['first_seen'] = relay['first_seen'] + if not self.json["sorted"][k][v].get("first_seen"): + self.json["sorted"][k][v]["first_seen"] = relay["first_seen"] + elif self.json["sorted"][k][v]["first_seen"] > relay["first_seen"]: + self.json["sorted"][k][v]["first_seen"] = relay["first_seen"] def _categorize(self): - ''' + """ Iterate over self.json['relays'] set and call self._sort() against discovered relays with attributes we use to generate static sets - ''' - self.json['sorted'] = dict() + """ + self.json["sorted"] = dict() - for idx, relay in enumerate(self.json['relays']): - keys = ['as', 'country', 'platform'] + for idx, relay in enumerate(self.json["relays"]): + keys = ["as", "country", "platform"] for key in keys: self._sort(relay, idx, key, relay.get(key)) - for flag in relay['flags']: - self._sort(relay, idx, 'flag', flag) + for flag in relay["flags"]: + self._sort(relay, idx, "flag", flag) - for member in relay['effective_family']: - if not len(relay['effective_family']) > 1: + for member in relay["effective_family"]: + if not len(relay["effective_family"]) > 1: continue - self._sort(relay, idx, 'family', member) + self._sort(relay, idx, "family", member) - self._sort(relay, idx, 'first_seen', relay['first_seen'].split(' ')[0]) + self._sort( + relay, idx, "first_seen", relay["first_seen"].split(" ")[0] + ) - c_str = relay.get('contact', '').encode('utf-8') + c_str = relay.get("contact", "").encode("utf-8") c_hash = hashlib.md5(c_str).hexdigest() - self._sort(relay, idx, 'contact', c_hash) + self._sort(relay, idx, "contact", c_hash) def create_output_dir(self): - ''' + """ Ensure self.output_dir exists (required for write functions) - ''' - os.makedirs(self.output_dir,exist_ok=True) - - def write_misc(self, template, path, path_prefix='../', sorted_by=None, - reverse=True, is_index=False): - ''' + """ + os.makedirs(self.output_dir, exist_ok=True) + + def write_misc( + self, + template, + path, + path_prefix="../", + sorted_by=None, + reverse=True, + is_index=False, + ): + """ Render and write unsorted HTML listings to disk Args: @@ -212,30 +228,30 @@ class Relays(): sorted_by: key to sort by, used in family and networks pages reverse: passed to sort() function in family and networks pages is_index: whether document is main index listing, limits list to 500 - ''' + """ template = ENV.get_template(template) - self.json['relay_subset'] = self.json['relays'] + self.json["relay_subset"] = self.json["relays"] template_render = template.render( - relays = self, - sorted_by = sorted_by, - reverse = reverse, - is_index = is_index, - path_prefix = path_prefix + relays=self, + sorted_by=sorted_by, + reverse=reverse, + is_index=is_index, + path_prefix=path_prefix, ) output = os.path.join(self.output_dir, path) os.makedirs(os.path.dirname(output), exist_ok=True) - with open(output, 'w', encoding='utf8') as html: + with open(output, "w", encoding="utf8") as html: html.write(template_render) def write_pages_by_key(self, k): - ''' + """ Render and write sorted HTML relay listings to disk Args: k: onionoo key to sort by (as, country, platform...) - ''' - template = ENV.get_template(k + '.html') + """ + template = ENV.get_template(k + ".html") output_path = os.path.join(self.output_dir, k) # the "royal the" must be gramatically recognized @@ -257,61 +273,63 @@ class Relays(): "Philippines", "Seychelles", "Sudan", - "Ukraine" + "Ukraine", ] if os.path.exists(output_path): rmtree(output_path) - for v in self.json['sorted'][k]: - i = self.json['sorted'][k][v] + for v in self.json["sorted"][k]: + i = self.json["sorted"][k][v] members = [] - for m_relay in i['relays']: - members.append(self.json['relays'][m_relay]) - if k == 'flag': + for m_relay in i["relays"]: + members.append(self.json["relays"][m_relay]) + if k == "flag": dir_path = os.path.join(output_path, v.lower()) else: dir_path = os.path.join(output_path, v) os.makedirs(dir_path) - self.json['relay_subset'] = members + self.json["relay_subset"] = members rendered = template.render( - relays = self, - bandwidth = round(i['bandwidth'] / 1000000, 2), - exit_count = i['exit_count'], - middle_count = i['middle_count'], - is_index = False, - path_prefix = '../../', - key = k, - value = v, - sp_countries = the_prefixed + relays=self, + bandwidth=round(i["bandwidth"] / 1000000, 2), + exit_count=i["exit_count"], + middle_count=i["middle_count"], + is_index=False, + path_prefix="../../", + key=k, + value=v, + sp_countries=the_prefixed, ) - with open(os.path.join(dir_path, 'index.html'), 'w', - encoding='utf8') as html: + with open( + os.path.join(dir_path, "index.html"), "w", encoding="utf8" + ) as html: html.write(rendered) def write_relay_info(self): - ''' + """ Render and write per-relay HTML info documents to disk - ''' - relay_list = self.json['relays'] - template = ENV.get_template('relay-info.html') - output_path = os.path.join(self.output_dir, 'relay') + """ + relay_list = self.json["relays"] + template = ENV.get_template("relay-info.html") + output_path = os.path.join(self.output_dir, "relay") if os.path.exists(output_path): rmtree(output_path) os.makedirs(output_path) for relay in relay_list: - if not relay['fingerprint'].isalnum(): + if not relay["fingerprint"].isalnum(): continue rendered = template.render( - relay = relay, - path_prefix = '../', - relays = self + relay=relay, path_prefix="../", relays=self ) - with open(os.path.join(output_path, '%s.html' % relay['fingerprint']), - 'w', encoding='utf8') as html: + with open( + os.path.join(output_path, "%s.html" % relay["fingerprint"]), + "w", + encoding="utf8", + ) as html: html.write(rendered) diff --git a/allium/templates/relay-info.html b/allium/templates/relay-info.html index c494a53..d8ee3be 100644 --- a/allium/templates/relay-info.html +++ b/allium/templates/relay-info.html @@ -1,129 +1,129 @@ {% extends "skeleton.html" -%} {% block title -%} - Tor Relays :: {{ relay['nickname'] }} + Tor Relays :: {{ relay['nickname'] }} {% endblock -%} {% block body -%} - <div id="content"> - <h2> - <a href="{{ path_prefix }}">Home</a> :: Relay "{{ relay['nickname'] }}" - </h2> - <div class="row"> - <div class="col-md-6"> - <dl> - <dt> - Nickname - </dt> - <dd> - {{ relay['nickname']|escape }} - </dd> - <dt> - OR Address - </dt> - <dd> - <pre class="pre-scrollable">{% for address in relay['or_addresses'] -%} +<div id="content"> +<h2> +<a href="{{ path_prefix }}">Home</a> :: Relay "{{ relay['nickname'] }}" +</h2> +<div class="row"> +<div class="col-md-6"> +<dl> +<dt> +Nickname +</dt> +<dd> +{{ relay['nickname']|escape }} +</dd> +<dt> +OR Address +</dt> +<dd> +<pre class="pre-scrollable">{% for address in relay['or_addresses'] -%} {{ address }} {% endfor -%} </pre> - </dd> - <dt> - Contact - </dt> - {% if relay['contact'] -%} - <dd> - <a href="{{ path_prefix }}contact/{{ relay['contact_md5'] }}">{{ - relay['contact']|escape }}</a> - </dd> - {% else -%} - <dd> - <a href="{{ path_prefix }}contact/{{ relay['contact_md5'] }}">none</a> - </dd> - {% endif -%} - <dt> - Dir Address - </dt> - {% if relay['dir_address'] -%} - <dd> - <a href="http://{{ relay['dir_address']|escape }}">{{ - relay['dir_address']|escape }}</a> - </dd> - {% else -%} - <dd> - none - </dd> - {% endif -%} - <dt> - Exit Address - </dt> - {% if relay['exit_address'] -%} - <dd> - {{ relay['exit_address']|escape }} - </dd> - {% else -%} - <dd> - none - </dd> - {% endif -%} - <dt> - Observed Bandwidth - </dt> - {% if relay['observed_bandwidth'] > 1000000 -%} - {% set obs_bandwidth = '%s %s'|format((relay['observed_bandwidth'] - / 1000000)|round(2, 'common'), 'MB/s') -%} - {% else -%} - {% set obs_bandwidth = '%s %s'|format((relay['observed_bandwidth'] - / 1000)|round(2, 'common'), 'KB/s') -%} - {% endif -%} - <dd> - {{ obs_bandwidth }} - </dd> - <dt> - IPv4 Exit Policy Summary - </dt> - <dd> - {% if relay['exit_policy_summary'] -%} - {%- set v4_summary = relay['exit_policy_summary'].items() -%} - <pre class="pre-scrollable">{% for k, v in v4_summary -%} +</dd> +<dt> +Contact +</dt> +{% if relay['contact'] -%} +<dd> +<a href="{{ path_prefix }}contact/{{ relay['contact_md5'] }}/">{{ +relay['contact']|escape }}</a> +</dd> +{% else -%} +<dd> +<a href="{{ path_prefix }}contact/{{ relay['contact_md5'] }}">none</a> +</dd> +{% endif -%} +<dt> +Dir Address +</dt> +{% if relay['dir_address'] -%} +<dd> +<a href="http://{{ relay['dir_address']|escape }}">{{ +relay['dir_address']|escape }}</a> +</dd> +{% else -%} +<dd> +none +</dd> +{% endif -%} +<dt> +Exit Address +</dt> +{% if relay['exit_address'] -%} +<dd> +{{ relay['exit_address']|escape }} +</dd> +{% else -%} +<dd> +none +</dd> +{% endif -%} +<dt> +Observed Bandwidth +</dt> +{% if relay['observed_bandwidth'] > 1000000 -%} +{% set obs_bandwidth = '%s %s'|format((relay['observed_bandwidth'] +/ 1000000)|round(2, 'common'), 'MB/s') -%} +{% else -%} +{% set obs_bandwidth = '%s %s'|format((relay['observed_bandwidth'] +/ 1000)|round(2, 'common'), 'KB/s') -%} +{% endif -%} +<dd> +{{ obs_bandwidth }} +</dd> +<dt> +IPv4 Exit Policy Summary +</dt> +<dd> +{% if relay['exit_policy_summary'] -%} +{%- set v4_summary = relay['exit_policy_summary'].items() -%} +<pre class="pre-scrollable">{% for k, v in v4_summary -%} {{ k|escape }}: {{ '\n ' + v|join('\n ')|escape }} {% endfor -%} </pre> - {% else -%} - <pre>none</pre> - {% endif -%} - </dd> - <dt> - IPv6 Exit Policy Summary - </dt> - <dd> - {% if relay['exit_policy_v6_summary'] -%} - {%- set v6_summary = relay['exit_policy_v6_summary'].items() -%} - <pre class="pre-scrollable">{% for k, v in v6_summary -%} +{% else -%} +<pre>none</pre> +{% endif -%} +</dd> +<dt> +IPv6 Exit Policy Summary +</dt> +<dd> +{% if relay['exit_policy_v6_summary'] -%} +{%- set v6_summary = relay['exit_policy_v6_summary'].items() -%} +<pre class="pre-scrollable">{% for k, v in v6_summary -%} {{ k|escape }}: {{ '\n ' + v|join('\n ')|escape }} {% endfor -%} </pre> - {% else -%} - <pre>none</pre> - {% endif -%} - </dd> - <dt> - Exit Policy - </dt> - <dd> - <pre class="pre-scrollable">{% for policy in relay['exit_policy'] -%} +{% else -%} +<pre>none</pre> +{% endif -%} +</dd> +<dt> +Exit Policy +</dt> +<dd> +<pre class="pre-scrollable">{% for policy in relay['exit_policy'] -%} {{ policy|escape }} {% endfor -%} </pre> - </dd> - {% if relay['effective_family']|length > 1 -%} - <dt> - Effective Family Members (<a href="{{ path_prefix }}family/{{ relay['fingerprint']|escape }}">view</a>) - </dt> - {% else -%} - <dt> - Effective Family Members - </dt> - {% endif -%} - <dd> - <pre class="pre-scrollable">{% for e_relay in relay['effective_family'] -%} +</dd> +{% if relay['effective_family']|length > 1 -%} +<dt> +Effective Family Members (<a href="{{ path_prefix }}family/{{ relay['fingerprint']|escape }}/">view</a>) +</dt> +{% else -%} +<dt> +Effective Family Members +</dt> +{% endif -%} +<dd> +<pre class="pre-scrollable">{% for e_relay in relay['effective_family'] -%} {% if relay['effective_family']|length > 1 -%} <a href="{{ e_relay|escape }}.html">{{ e_relay|escape }}</a> {% else -%} @@ -131,13 +131,13 @@ {% endif -%} {% endfor -%} </pre> - </dd> - <dt> - Alleged Family Members - </dt> - <dd> - {% if relay['alleged_family'] -%} - <pre class="pre-scrollable">{% for a_relay in relay['alleged_family'] -%} +</dd> +<dt> +Alleged Family Members +</dt> +<dd> +{% if relay['alleged_family'] -%} +<pre class="pre-scrollable">{% for a_relay in relay['alleged_family'] -%} {% if relay['alleged_family']|length > 1 -%} <a href="{{ a_relay|escape }}.html">{{ a_relay|escape }}</a> {% else -%} @@ -158,95 +158,95 @@ Fingerprint </dt> <dd> <pre>{{ relay['fingerprint']|escape }}</pre> - </dd> - <dt> - Flags - </dt> - <dd> - {% for flag in relay['flags'] -%} - {% if flag != 'StaleDesc' -%} - <a href="{{ path_prefix }}flag/{{ flag.lower()|escape }}"> - <img src="{{ path_prefix }}static/images/flags/{{ flag.lower()|escape }}.png" - title="{{ flag|escape }}" - alt="{{ flag|escape }}"> - </a> {{ flag|escape }} - {% endif -%} - {% endfor -%} - </dd> - <dt> - Host Name - </dt> - <dd> - {% if relay['verified_host_names'] -%} - <pre class="verified-hostname" title="verified hostname">{{ +</dd> +<dt> +Flags +</dt> +<dd> +{% for flag in relay['flags'] -%} +{% if flag != 'StaleDesc' -%} +<a href="{{ path_prefix }}flag/{{ flag.lower()|escape }}/"> +<img src="{{ path_prefix }}static/images/flags/{{ flag.lower()|escape }}.png" +title="{{ flag|escape }}" +alt="{{ flag|escape }}"> +</a> {{ flag|escape }} +{% endif -%} +{% endfor -%} +</dd> +<dt> +Host Name +</dt> +<dd> +{% if relay['verified_host_names'] -%} +<pre class="verified-hostname" title="verified hostname">{{ relay['verified_host_names']|join('\n')|escape }}</pre> - {% elif relay['unverified_host_names'] -%} - <pre class="unverified-hostname" title="unverified hostname">{{ +{% elif relay['unverified_host_names'] -%} +<pre class="unverified-hostname" title="unverified hostname">{{ relay['unverified_host_names']|join('\n')|escape }}</pre> - {% else -%} - <pre>none</pre> - {% endif -%} - <dt> - Country - </dt> - <dd> - {% if relay['country'] -%} - <a href="{{ path_prefix }}country/{{ relay['country']|escape }}/"> - <img src="{{ path_prefix }}static/images/cc/{{ relay['country']|escape }}.png" - title="{{ relay['country_name']|escape }}" - alt="{{ relay['country_name']|escape }}"> - </a> {{ relay['country_name']|escape }} - {% else -%} - unknown - {% endif -%} - </dd> - <dt> - AS Number - </dt> - <dd> - {% if relay['as'] -%} - <a href='{{ path_prefix }}as/{{ relay['as']|escape }}'>{{ relay['as']|escape - }}</a> - {% else -%} - unknown - {% endif -%} - <dt> - AS Name - </dt> - <dd> - {% if relay['as_name'] -%} - {{ relay['as_name']|escape }} (<a href='https://bgp.tools/{{ relay['as']|escape }}'>BGP</a>) - {% else -%} - unknown - {% endif -%} - <dt> - First Seen - </dt> - <dd> - <a href="{{ path_prefix }}first_seen/{{ relay['first_seen'].split(' ', 1)[0]|escape }}">{{ relay['first_seen']|escape }}</a> - </dd> - <dt> - Last Restarted - </dt> - <dd> - {{ relay['last_restarted']|escape }} - </dd> - <dt> - Consensus Weight - </dt> - <dd> - {{ relay['consensus_weight_fraction']|escape }} ({{ - relay['consensus_weight']|escape }}) - </dd> - <dt> - Platform - </dt> - <dd> - <a href='{{ path_prefix }}platform/{{ relay['platform']|escape }}'>{{ - relay['platform'] }}</a> - </dd> - </dl> - </div> - </div> - </div> - {% endblock -%} +{% else -%} +<pre>none</pre> +{% endif -%} +<dt> +Country +</dt> +<dd> +{% if relay['country'] -%} +<a href="{{ path_prefix }}country/{{ relay['country']|escape }}/"> +<img src="{{ path_prefix }}static/images/cc/{{ relay['country']|escape }}.png" +title="{{ relay['country_name']|escape }}" +alt="{{ relay['country_name']|escape }}"> +</a> {{ relay['country_name']|escape }} +{% else -%} +unknown +{% endif -%} +</dd> +<dt> +AS Number +</dt> +<dd> +{% if relay['as'] -%} +<a href='{{ path_prefix }}as/{{ relay['as']|escape }}/'>{{ relay['as']|escape +}}</a> +{% else -%} +unknown +{% endif -%} +<dt> +AS Name +</dt> +<dd> +{% if relay['as_name'] -%} +{{ relay['as_name']|escape }} (<a href='https://bgp.tools/{{ relay['as']|escape }}'>BGP</a>) +{% else -%} +unknown +{% endif -%} +<dt> +First Seen +</dt> +<dd> +<a href="{{ path_prefix }}first_seen/{{ relay['first_seen'].split(' ', 1)[0]|escape }}/">{{ relay['first_seen']|escape }}</a> +</dd> +<dt> +Last Restarted +</dt> +<dd> +{{ relay['last_restarted']|escape }} +</dd> +<dt> +Consensus Weight +</dt> +<dd> +{{ relay['consensus_weight_fraction']|escape }} ({{ +relay['consensus_weight']|escape }}) +</dd> +<dt> +Platform +</dt> +<dd> +<a href='{{ path_prefix }}platform/{{ relay['platform']|escape }}/'>{{ +relay['platform'] }}</a> +</dd> +</dl> +</div> +</div> +</div> +{% endblock -%} diff --git a/allium/templates/relay-list.html b/allium/templates/relay-list.html index 6c25cef..cc992c1 100644 --- a/allium/templates/relay-list.html +++ b/allium/templates/relay-list.html @@ -3,160 +3,160 @@ Tor Relays {% endblock -%} {% block body -%} - <h2> - {% block header -%} - {% endblock -%} - </h2> - <p> - {% block description -%} - {% endblock -%} - </p> - <table class="table table-condensed"> - <tr> - <th></th> - <th>Nickname</th> - <th>Contact</th> - <th>Bandwidth</th> - <th class="visible-md visible-lg">IP Address</th> - <th>AS Number</th> - <th>AS Name</th> - <th>Country</th> - <th>Platform</th> - <th class="visible-md visible-lg">Flags</th> - <th class="visible-md visible-lg">First Seen</th> - </tr> - <tbody> - {% if is_index -%} - {% set relay_list = relays.json['relay_subset'][:500] -%} - {% else -%} - {% set relay_list = relays.json['relay_subset'] -%} - {% endif -%} - {% for relay in relay_list -%} - <tr> - {% if relay['observed_bandwidth'] > 1000000 -%} - {% set obs_bandwidth = '%s %s'|format((relay['observed_bandwidth'] - / 1000000)|round(2, 'common'), 'MB/s') -%} - {% else -%} - {% set obs_bandwidth = '%s %s'|format((relay['observed_bandwidth'] / 1000)| - round(2, 'common'), 'KB/s') -%} - {% endif -%} - {% if relay['running'] -%} - <td> - <span class="circle circle-online" title="This relay is online"></span> - </td> - {% else -%} - <td> - <span class="circle circle-offline" title="This relay is offline"></span> - </td> - {% endif -%} - {% if relay['effective_family']|length > 1 -%} - <td title="{{ relay['nickname']|escape }}"> - <a href="{{ path_prefix }}relay/{{ relay['fingerprint']|escape }}.html">{{ relay['nickname']|truncate(8)|escape - }}</a> (<a href="{{ path_prefix }}family/{{ relay['fingerprint']|escape }}/">{{ - relay['effective_family']| length }}</a>) - </td> - {% else -%} - <td title="{{ relay['nickname']|escape }}"> - <a href="{{ path_prefix }}relay/{{ relay['fingerprint']|escape }}.html">{{ relay['nickname']|truncate(10)|escape - }}</a> - </td> - {% endif -%} - {% if key != 'contact' -%} - {% if relay['contact'] -%} - <td> - <code><a href="{{ path_prefix }}contact/{{ relay['contact_md5'] }}/" - title="{{ relay['contact']|escape }}">{{ relay['contact_md5'][0:8] - }}</a></code> - </td> - {% else -%} - <td title="none"> - <code>none</code> - </td> - {% endif -%} - {% else -%} - <td title="{{ relay['contact']|escape }}"> - <code>{{ relay['contact_md5'][0:8] - }}</code> - </td> - {% endif -%} - <td>{{ obs_bandwidth }}</td> - <td class="visible-md visible-lg"> - <a href="https://bgp.tools/prefix/{{ relay['or_addresses'][0].split(':', 1)[0]|escape }}">{{ - relay['or_addresses'][0].split(':', 1)[0]|escape }}</a> - </td> - {% if relay['as'] -%} - {% if key != 'as' -%} - <td> - <a href="{{ path_prefix }}as/{{ relay['as']|escape }}/">{{ - relay['as']|escape }}</a> - </td> - {% else -%} - <td>{{ relay['as']|escape }}</td> - {% endif -%} - {% else -%} - <td>Unknown</td> - {% endif -%} - {% if relay['as_name'] -%} - <td> - <a href="https://bgp.tools/{{ relay['as']|escape }}" - title="{{ relay['as_name']|escape }}">{{ - relay['as_name']|escape|truncate(length=20) }}</a> - </td> - {% else -%} - <td>Unknown</td> - {% endif -%} - {% if relay['country'] -%} - {% if key != 'country' -%} - <td> - <a href="{{ path_prefix }}country/{{ relay['country']|escape }}/"> - <img src="{{ path_prefix }}static/images/cc/{{ relay['country']|escape }}.png" - title="{{ relay['country_name']|escape }}" - alt="{{ relay['country_name']|escape }}"> - </a> - </td> - {% else -%} - <td> - <img src="{{ path_prefix }}static/images/cc/{{ relay['country']|escape }}.png" - title="{{ relay['country_name']|escape }}" - alt="{{ relay['country_name']|escape }}"> - </td> - {% endif -%} - {% else -%} - <td>X</td> - {% endif -%} - {% if key != 'platform' -%} - <td> - <a href="{{ path_prefix }}platform/{{ relay['platform']|escape }}/">{{ - relay['platform']|truncate(length=10)|escape }}</a> - </td> - {% else -%} - <td>{{ relay['platform']|truncate(length=10)|escape }}</td> - {% endif -%} - <td class="visible-md visible-lg"> - {% for flag in relay['flags'] -%} - {% if flag != 'StaleDesc' -%} - <a href="{{ path_prefix }}flag/{{ flag.lower()|escape }}"> - <img src="{{ path_prefix }}static/images/flags/{{ flag.lower()|escape }}.png" - title="{{ flag|escape }}" - alt="{{ flag|escape }}"> - </a> - {% endif -%} - {% endfor - -%} - </td> - {% if key != 'first_seen' -%} - <td class="visible-md visible-lg"> - <a href="{{ path_prefix }}first_seen/{{ relay['first_seen'].split(' ', 1)[0]|escape }}">{{ - relay['first_seen'].split(' ', 1)[0]|escape }}</a> - </td> - {% else -%} - <td class="visible-md visible-lg"> - {{ relay['first_seen'].split(' ', 1)[0]|escape - }} - </td> - {% endif -%} - </tr> - {% endfor -%} - </tbody> - </table> - {% endblock -%} +<h2> +{% block header -%} +{% endblock -%} +</h2> +<p> +{% block description -%} +{% endblock -%} +</p> +<table class="table table-condensed"> +<tr> + <th></th> + <th>Nickname</th> + <th>Contact</th> + <th>Bandwidth</th> + <th class="visible-md visible-lg">IP Address</th> + <th>AS Number</th> + <th>AS Name</th> + <th>Country</th> + <th>Platform</th> + <th class="visible-md visible-lg">Flags</th> + <th class="visible-md visible-lg">First Seen</th> +</tr> +<tbody> + {% if is_index -%} + {% set relay_list = relays.json['relay_subset'][:500] -%} + {% else -%} + {% set relay_list = relays.json['relay_subset'] -%} + {% endif -%} + {% for relay in relay_list -%} + <tr> + {% if relay['observed_bandwidth'] > 1000000 -%} + {% set obs_bandwidth = '%s %s'|format((relay['observed_bandwidth'] + / 1000000)|round(2, 'common'), 'MB/s') -%} + {% else -%} + {% set obs_bandwidth = '%s %s'|format((relay['observed_bandwidth'] / 1000)| + round(2, 'common'), 'KB/s') -%} + {% endif -%} + {% if relay['running'] -%} + <td> + <span class="circle circle-online" title="This relay is online"></span> + </td> + {% else -%} + <td> + <span class="circle circle-offline" title="This relay is offline"></span> + </td> + {% endif -%} + {% if relay['effective_family']|length > 1 -%} + <td title="{{ relay['nickname']|escape }}"> + <a href="{{ path_prefix }}relay/{{ relay['fingerprint']|escape }}.html">{{ relay['nickname']|truncate(8)|escape + }}</a> (<a href="{{ path_prefix }}family/{{ relay['fingerprint']|escape }}/">{{ + relay['effective_family']| length }}</a>) + </td> + {% else -%} + <td title="{{ relay['nickname']|escape }}"> + <a href="{{ path_prefix }}relay/{{ relay['fingerprint']|escape }}.html">{{ relay['nickname']|truncate(10)|escape + }}</a> + </td> + {% endif -%} + {% if key != 'contact' -%} + {% if relay['contact'] -%} + <td> + <code><a href="{{ path_prefix }}contact/{{ relay['contact_md5'] }}/" +title="{{ relay['contact']|escape }}">{{ relay['contact_md5'][0:8] + }}</a></code> + </td> + {% else -%} + <td title="none"> + <code>none</code> + </td> + {% endif -%} + {% else -%} + <td title="{{ relay['contact']|escape }}"> + <code>{{ relay['contact_md5'][0:8] + }}</code> + </td> + {% endif -%} + <td>{{ obs_bandwidth }}</td> + <td class="visible-md visible-lg"> + <a href="https://bgp.tools/prefix/{{ relay['or_addresses'][0].split(':', 1)[0]|escape }}">{{ + relay['or_addresses'][0].split(':', 1)[0]|escape }}</a> + </td> + {% if relay['as'] -%} + {% if key != 'as' -%} + <td> + <a href="{{ path_prefix }}as/{{ relay['as']|escape }}/">{{ + relay['as']|escape }}</a> + </td> + {% else -%} + <td>{{ relay['as']|escape }}</td> + {% endif -%} + {% else -%} + <td>Unknown</td> + {% endif -%} + {% if relay['as_name'] -%} + <td> + <a href="https://bgp.tools/{{ relay['as']|escape }}" + title="{{ relay['as_name']|escape }}">{{ + relay['as_name']|escape|truncate(length=20) }}</a> + </td> + {% else -%} + <td>Unknown</td> + {% endif -%} + {% if relay['country'] -%} + {% if key != 'country' -%} + <td> + <a href="{{ path_prefix }}country/{{ relay['country']|escape }}/"> + <img src="{{ path_prefix }}static/images/cc/{{ relay['country']|escape }}.png" + title="{{ relay['country_name']|escape }}" + alt="{{ relay['country_name']|escape }}"> + </a> + </td> + {% else -%} + <td> + <img src="{{ path_prefix }}static/images/cc/{{ relay['country']|escape }}.png" + title="{{ relay['country_name']|escape }}" + alt="{{ relay['country_name']|escape }}"> + </td> + {% endif -%} + {% else -%} + <td>X</td> + {% endif -%} + {% if key != 'platform' -%} + <td> + <a href="{{ path_prefix }}platform/{{ relay['platform']|escape }}/">{{ + relay['platform']|truncate(length=10)|escape }}</a> + </td> + {% else -%} + <td>{{ relay['platform']|truncate(length=10)|escape }}</td> + {% endif -%} + <td class="visible-md visible-lg"> + {% for flag in relay['flags'] -%} + {% if flag != 'StaleDesc' -%} + <a href="{{ path_prefix }}flag/{{ flag.lower()|escape }}/"> + <img src="{{ path_prefix }}static/images/flags/{{ flag.lower()|escape }}.png" + title="{{ flag|escape }}" + alt="{{ flag|escape }}"> + </a> + {% endif -%} + {% endfor + -%} + </td> + {% if key != 'first_seen' -%} + <td class="visible-md visible-lg"> + <a href="{{ path_prefix }}first_seen/{{ relay['first_seen'].split(' ', 1)[0]|escape }}/">{{ + relay['first_seen'].split(' ', 1)[0]|escape }}</a> + </td> + {% else -%} + <td class="visible-md visible-lg"> + {{ relay['first_seen'].split(' ', 1)[0]|escape + }} + </td> + {% endif -%} + </tr> + {% endfor -%} + </tbody> +</table> +{% endblock -%} |