aboutsummaryrefslogtreecommitdiff
path: root/allium
diff options
context:
space:
mode:
Diffstat (limited to 'allium')
-rwxr-xr-xallium/allium.py88
-rw-r--r--allium/lib/relays.py270
-rw-r--r--allium/templates/relay-info.html414
-rw-r--r--allium/templates/relay-list.html314
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 -%}