|
@@ -195,24 +195,36 @@ class BatcaveHttpRequestHandler(BaseHTTPRequestHandler):
|
|
|
|
|
|
self.__send_headers()
|
|
|
|
|
|
- self.wfile.write('<!DOCTYPE html><html><head><title>BATCAVE</title></head>\n')
|
|
|
- self.wfile.write('<body>\n')
|
|
|
- self.wfile.write('<H1 title="Batman/Alfred Transmission Collection, Aggregation & Value Engine">BATCAVE</H1>\n')
|
|
|
-
|
|
|
- self.wfile.write('<p>Dies ist ein interner Hintergrund-Dienst. Er wird nur von anderen Diensten\n')
|
|
|
- self.wfile.write('angesprochen und sollte aus einer Mehrzahl von Gründen nicht öffentlich\n')
|
|
|
- self.wfile.write('zugänglich sein.</p>\n')
|
|
|
-
|
|
|
- self.wfile.write('<H2>API</H2>\n')
|
|
|
- self.wfile.write('<p>Grundsätzlich ist das Antwort-Format JSON und alle Daten sind Live-Daten (kein Cache) die ggf. etwas Bearbeitungs-Zeit erfordern.</p>')
|
|
|
- self.wfile.write('<dl>\n')
|
|
|
- self.wfile.write('<dt>GET <a href="/nodes.json">nodes.json</a></dt><dd>zur Verwendung mit ffmap (MACs anonymisiert)</dd>\n')
|
|
|
- self.wfile.write('<dt>GET /node/<id>.json</dt><dd><u>alle</u> vorhandenen Information zu dem gewünschten Knoten</dd>\n')
|
|
|
- self.wfile.write('<dt>GET /providers?format=json</dt><dd>Liste der Provider</dd>\n')
|
|
|
- self.wfile.write('<dt>GET <a href="/status">/status</a></dt><dd>Status der BATCAVE inkl. Zahl der Nodes+Clients (JSON)</dd>\n')
|
|
|
- self.wfile.write('<dt>GET /status/<id></dt><dd>Status des Knotens</dd>\n')
|
|
|
- self.wfile.write('</dl>\n')
|
|
|
- self.wfile.write('</body></html>')
|
|
|
+ index_page = '''<!DOCTYPE html>
|
|
|
+<html><head><title>BATCAVE</title></head>
|
|
|
+<body>
|
|
|
+<H1 title="Batman/Alfred Transmission Collection, Aggregation & Value Engine">
|
|
|
+BATCAVE
|
|
|
+</H1>
|
|
|
+
|
|
|
+<p>Dies ist ein interner Hintergrund-Dienst. Er wird nur von anderen Diensten
|
|
|
+angesprochen und sollte aus einer Mehrzahl von Gründen nicht
|
|
|
+öffentlich zugänglich sein.</p>
|
|
|
+
|
|
|
+<H2>API</H2>
|
|
|
+<p>
|
|
|
+ Grundsätzlich ist das Antwort-Format JSON und alle Daten sind
|
|
|
+ Live-Daten (kein Cache) die ggf. etwas Bearbeitungs-Zeit erfordern.
|
|
|
+</p>
|
|
|
+<dl>
|
|
|
+ <dt>GET <a href="/nodes.json">nodes.json</a></dt>
|
|
|
+ <dd>zur Verwendung mit ffmap (MACs anonymisiert)</dd>
|
|
|
+ <dt>GET /node/<id>.json</dt>
|
|
|
+ <dd>alle Daten zu dem gewünschten Knoten</dd>
|
|
|
+ <dt>GET /providers?format=json</dt>
|
|
|
+ <dd>Liste der Provider</dd>
|
|
|
+ <dt>GET <a href="/status">/status</a></dt>
|
|
|
+ <dd>Status der BATCAVE inkl. Zahl der Nodes+Clients (JSON)</dd>
|
|
|
+ <dt>GET /status/<id></dt>
|
|
|
+ <dd>Status des Knotens</dd>
|
|
|
+</dl>
|
|
|
+</body></html>'''
|
|
|
+ self.wfile.write(index_page)
|
|
|
|
|
|
def __respond_list(self, query):
|
|
|
"""List stored data."""
|
|
@@ -381,25 +393,32 @@ class BatcaveHttpRequestHandler(BaseHTTPRequestHandler):
|
|
|
|
|
|
def __respond_vpnlist(self):
|
|
|
self.__send_headers()
|
|
|
- self.wfile.write('<!DOCTYPE html>\n')
|
|
|
- self.wfile.write('<html><head><title>BATCAVE - VPN LIST</title></head>\n')
|
|
|
- self.wfile.write('<body>\n')
|
|
|
- self.wfile.write('<style type="text/css">\n')
|
|
|
- self.wfile.write('table { border: 2px solid #999; border-collapse: collapse; }\n')
|
|
|
- self.wfile.write('th, td { border: 1px solid #CCC; }\n')
|
|
|
- self.wfile.write('table tbody tr.online { background-color: #CFC; }\n')
|
|
|
- self.wfile.write('table tbody tr.offline { background-color: #FCC; }\n')
|
|
|
- self.wfile.write('</style>\n')
|
|
|
- self.wfile.write('<table>\n')
|
|
|
+
|
|
|
+ self.wfile.write('''<!DOCTYPE html>
|
|
|
+<html><head><title>BATCAVE - VPN LIST</title></head>
|
|
|
+<body>
|
|
|
+<style type="text/css">
|
|
|
+table { border: 2px solid #999; border-collapse: collapse; }
|
|
|
+th, td { border: 1px solid #CCC; }
|
|
|
+table tbody tr.online { background-color: #CFC; }
|
|
|
+table tbody tr.offline { background-color: #FCC; }
|
|
|
+</style>
|
|
|
+<table>''')
|
|
|
|
|
|
gateways = self.server.storage.get_vpn_gateways()
|
|
|
+ gws_header = '<th>' + '</th><th>'.join(gateways) + '</th>'
|
|
|
+
|
|
|
self.wfile.write('<thead>\n')
|
|
|
- self.wfile.write('<tr><th rowspan="2">names (key)</th><th colspan="' + str(len(gateways)) + '">active</th><th colspan="' + str(len(gateways)) + '">last</th></tr>\n')
|
|
|
- self.wfile.write('<tr><th>' + '</th><th>'.join(gateways) + '</th><th>' + '</th><th>'.join(gateways) + '</th></tr>\n')
|
|
|
+ self.wfile.write('<tr><th rowspan="2">names (key)</th>')
|
|
|
+ self.wfile.write('<th colspan="' + str(len(gateways)) + '">active</th>')
|
|
|
+ self.wfile.write('<th colspan="' + str(len(gateways)) + '">last</th>')
|
|
|
+ self.wfile.write('</tr>\n')
|
|
|
+ self.wfile.write('<tr>' + gws_header + gws_header + '</tr>\n')
|
|
|
self.wfile.write('</thead>\n')
|
|
|
|
|
|
for item in self.server.storage.get_vpn_connections():
|
|
|
- self.wfile.write('<tr class="{0}">'.format('online' if item['online'] else 'offline'))
|
|
|
+ row_class = 'online' if item['online'] else 'offline'
|
|
|
+ self.wfile.write('<tr class="{0}">'.format(row_class))
|
|
|
self.wfile.write('<td title="{0}">{1}</td>'.format(
|
|
|
item['key'],
|
|
|
' / '.join(item['names']) if len(item['names']) > 0 else '?',
|
|
@@ -408,7 +427,8 @@ class BatcaveHttpRequestHandler(BaseHTTPRequestHandler):
|
|
|
for conntype in ['active', 'last']:
|
|
|
for gateway in gateways:
|
|
|
remote = ''
|
|
|
- if conntype in item['remote'] and gateway in item['remote'][conntype]:
|
|
|
+ if conntype in item['remote'] and \
|
|
|
+ gateway in item['remote'][conntype]:
|
|
|
remote = item['remote'][conntype][gateway]
|
|
|
if isinstance(remote, dict):
|
|
|
remote = remote['name']
|
|
@@ -464,7 +484,8 @@ class BatcaveHttpRequestHandler(BaseHTTPRequestHandler):
|
|
|
|
|
|
elif len(item_isps) > 1:
|
|
|
self.logger.warn(
|
|
|
- 'VPN key \'%s\' has %d active IPs which resolved to %d ISPs: \'%s\'',
|
|
|
+ 'VPN key \'%s\' has %d active IPs ' +
|
|
|
+ 'which resolved to %d ISPs: \'%s\'',
|
|
|
item['key'],
|
|
|
len(remotes),
|
|
|
len(item_isps),
|
|
@@ -502,12 +523,15 @@ class BatcaveHttpRequestHandler(BaseHTTPRequestHandler):
|
|
|
elif outputformat == 'html':
|
|
|
self.__send_headers()
|
|
|
|
|
|
- self.wfile.write('<!DOCTYPE html><html>\n')
|
|
|
- self.wfile.write('<head><title>BATCAVE - PROVIDERS</title></head>\n')
|
|
|
- self.wfile.write('<body>\n')
|
|
|
- self.wfile.write('<table border="2">\n')
|
|
|
- self.wfile.write('<thead><tr><th>Count</th><th>Percentage</th><th>Name</th><th>Blocks</th></tr></thead>\n')
|
|
|
- self.wfile.write('<tbody>\n')
|
|
|
+ self.wfile.write('''<!DOCTYPE html>
|
|
|
+<html>
|
|
|
+<head><title>BATCAVE - PROVIDERS</title></head>
|
|
|
+<body>
|
|
|
+<table border="2">
|
|
|
+<thead>
|
|
|
+ <tr><th>Count</th><th>Percentage</th><th>Name</th><th>Blocks</th></tr>
|
|
|
+</thead>
|
|
|
+<tbody>\n''')
|
|
|
|
|
|
for isp in sorted(isps, key=lambda x: isps[x], reverse=True):
|
|
|
self.wfile.write('<tr><td>{0}</td><td>{1:.1f}%</td><td>{2}</td><td>{3}</td></tr>\n'.format(
|