109 lines
3.3 KiB
Python
109 lines
3.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
# vi:si:et:sw=4:sts=4:ts=4
|
|
|
|
import json
|
|
import ssl
|
|
|
|
from tornado.httpserver import HTTPServer
|
|
from tornado.ioloop import PeriodicCallback
|
|
import tornado.web
|
|
|
|
from .proxy import ProxyHandler
|
|
from .utils import get_public_ipv6, valid
|
|
from . import directory
|
|
from . import settings
|
|
from . import state
|
|
|
|
import logging
|
|
logger = logging.getLogger('nodeserver')
|
|
|
|
|
|
class NodeHandler(ProxyHandler):
|
|
|
|
def validate_request(self):
|
|
if 'From' in self.request.headers:
|
|
del self.request.headers['From']
|
|
sig = self.request.headers.get('X-Ed25519-Signature')
|
|
key = self.request.headers.get('X-Ed25519-Key')
|
|
if sig or key:
|
|
try:
|
|
is_valid = valid(key, self.request.body, sig)
|
|
except:
|
|
is_valid = False
|
|
if is_valid:
|
|
self.request.headers['From'] = key
|
|
return is_valid
|
|
return True
|
|
|
|
@tornado.web.asynchronous
|
|
def _handle_response(self, response):
|
|
# sign json responses from local services
|
|
if not response.error and \
|
|
response.headers.get('Content-Type') == 'application/json':
|
|
if response.body:
|
|
response.data = response.body.read()
|
|
response.body = None
|
|
sig = settings.sk.sign(response.data, encoding=settings.ENCODING).decode()
|
|
response.headers['X-Ed25519-Key'] = settings.USER_ID
|
|
response.headers['X-Ed25519-Signature'] = sig
|
|
return ProxyHandler._handle_response(self, response)
|
|
|
|
def remote_url(self):
|
|
if not self.validate_request():
|
|
url = None
|
|
self.set_status(403)
|
|
self.write(json.dumps({'status': 'Invalid Signature'}))
|
|
self.finish()
|
|
return None
|
|
try:
|
|
service, uri = self.request.uri[1:].split('/', 1)
|
|
except:
|
|
logger.debug('Invalid Request %s', self.request.uri)
|
|
return None
|
|
if service in settings.services:
|
|
url = settings.services[service] + uri
|
|
else:
|
|
url = None
|
|
self.set_status(404)
|
|
self.write(json.dumps({'status': 'unknown app'}))
|
|
self.finish()
|
|
return url
|
|
|
|
class StaticHandler(tornado.web.RequestHandler):
|
|
|
|
def get(self):
|
|
self.write('')
|
|
self.finish()
|
|
|
|
def publish_node():
|
|
update_online()
|
|
state._online = PeriodicCallback(update_online, 60000)
|
|
state._online.start()
|
|
|
|
def update_online():
|
|
host = get_public_ipv6()
|
|
if not host:
|
|
state.online = False
|
|
else:
|
|
if host != state.host:
|
|
state.host = host
|
|
online = directory.put(settings.sk, {
|
|
'host': host,
|
|
'port': settings.server['node_port'],
|
|
'cert': settings.server['cert']
|
|
})
|
|
state.online = online
|
|
|
|
def start():
|
|
application = tornado.web.Application([
|
|
(r"/", StaticHandler),
|
|
(r".*", NodeHandler),
|
|
], gzip=True)
|
|
http_server = HTTPServer(application, ssl_options={
|
|
"certfile": settings.tls_cert_path,
|
|
"keyfile": settings.tls_key_path,
|
|
"ssl_version": ssl.PROTOCOL_TLSv1_2
|
|
})
|
|
http_server.listen(settings.server['node_port'], settings.server['node_address'])
|
|
state.main.add_callback(publish_node)
|
|
return http_server
|