make more things work

This commit is contained in:
meejah 2019-03-21 01:37:47 -06:00
parent 38ed6a094a
commit 816ceb12cb
4 changed files with 101 additions and 69 deletions

View File

@ -1,3 +1,5 @@
import json
from autobahn.twisted.resource import WebSocketResource
from autobahn.twisted.websocket import WebSocketServerFactory
from autobahn.twisted.websocket import WebSocketServerProtocol
@ -6,6 +8,8 @@ from autobahn.websocket.types import ConnectionDeny
from twisted.web import resource, server
from twisted.python.failure import Failure
import eliot
from allmydata.util.hashutil import timing_safe_compare
from .common import humanize_failure
@ -16,45 +20,55 @@ class TokenAuthenticatedWebSocketServerProtocol(WebSocketServerProtocol):
def onConnect(self, req):
if 'authorization' in req.headers:
token = req.headers['authorization'].encode('ascii')
if timing_safe_compare(token, self.factory.tahoe_client.get_auth_token()):
print("we're here, it's fine")
# we don't care what WebSocket sub-protocol is
# negotiated, nor do we need to send headers to the
# client, so we ask Autobahn to just allow this
# connectino with the defaults. We could return a
# (headers, protocol) pair here instead if required.
return None
auth = req.headers['authorization'].encode('ascii').split(' ', 1)
if len(auth) == 2:
tag, token = auth
if tag == "tahoe-lafs":
if timing_safe_compare(token, self.factory.tahoe_client.get_auth_token()):
# we don't care what WebSocket sub-protocol is
# negotiated, nor do we need to send headers to the
# client, so we ask Autobahn to just allow this
# connection with the defaults. We could return a
# (headers, protocol) pair here instead if required.
return None
# everything else -- i.e. no Authorization header, or it's
# wrong -- means we deny the websocket connection
raise ConnectionDeny(
code=406,
code=ConnectionDeny.NOT_ACCEPTABLE,
reason=u"Invalid or missing token"
)
def _received_eliot_log(self, message):
# probably want a try/except around here? what do we do if
# transmission fails or anything else bad?
self.sendMessage(json.dumps(message))
class LogStreamingWebSocket(resource.Resource):
def onOpen(self):
# self.factory.tahoe_client.add_log_streaming_client(self)
# hmm, instead of something like ^ maybe we just add eliot
# stuff ourselves...
eliot.add_destination(self._received_eliot_log)
def onClose(self, wasClean, code, reason):
#self.factory.tahoe_client.remove_log_streaming_client(self)
try:
eliot.remove_destination(self._received_eliot_log)
except ValueError:
pass
def create_log_streaming_resource(client, websocket_url):
"""
Create a new resource that accepts WebSocket connections if they
include a correct `Authorization: tahoe-lafs <api_auth_token>`
header (where `api_auth_token` matches the private configuration
value).
"""
def __init__(self, client):
self._client = client
self._factory = WebSocketServerFactory(u"ws://127.0.0.1:6301/logs_v1")
self._factory.tahoe_client = client
self._factory.protocol = TokenAuthenticatedWebSocketServerProtocol
self._ws_resource = WebSocketResource(self._factory)
def render(self, req):
print(req)
print(dir(req.headers))
print(req.headers.keys())
return self._ws_resource.render(req)
def create_log_streaming_resource(client):
return LogStreamingWebSocket(client)
factory = WebSocketServerFactory(websocket_url)
factory.tahoe_client = client
factory.protocol = TokenAuthenticatedWebSocketServerProtocol
return WebSocketResource(factory)
def _create_log_streaming_resource(client):

View File

@ -1,6 +1,7 @@
import time, os, json
from twisted.web import http
from twisted.internet import endpoints
from nevow import rend, url, tags as T
from nevow.inevow import IRequest
from nevow.static import File as nevow_File # TODO: merge with static.File?
@ -150,7 +151,7 @@ class Root(MultiFormatPage):
"no": "Disconnected",
}
def __init__(self, client, clock=None, now_fn=None):
def __init__(self, client, clock=None, now_fn=None, webport=None):
rend.Page.__init__(self, client)
self.client = client
# If set, clock is a twisted.internet.task.Clock that the tests
@ -170,7 +171,13 @@ class Root(MultiFormatPage):
self.child_magic_folder = magic_folder.MagicFolderWebApi(client)
# handler for "/logs_v1" URIs
self.child_logs_v1 = create_log_streaming_resource(client)
# note, webport can be a bare port or a Twisted endpoint-string
if webport.startswith("tcp:"):
port = webport.split(':')[1]
else:
port = webport
websocket_url = u"ws://127.0.0.1:{}/logs_v1".format(port)
self.child_logs_v1 = create_log_streaming_resource(client, websocket_url)
self.child_file = FileHandler(client)
self.child_named = FileHandler(client)

View File

@ -161,7 +161,11 @@ class WebishServer(service.MultiService):
# twisted.internet.task.Clock that is provided by the unit tests
# so that they can test features that involve the passage of
# time in a deterministic manner.
self.root = root.Root(client, clock, now_fn)
# beware, 'webport' can be a Twisted endpoint-string sometimes
# it seems
print("webport {}".format(webport))
self.root = root.Root(client, clock, now_fn, webport=webport)
self.buildServer(webport, nodeurl_path, staticdir)
if self.root.child_operations:
self.site.remember(self.root.child_operations, IOpHandleTable)

View File

@ -1,56 +1,63 @@
from __future__ import print_function
import json
import sys
from twisted.internet.task import react
from twisted.internet.defer import inlineCallbacks, Deferred
from autobahn.twisted.websocket import (
WebSocketClientProtocol,
WebSocketClientFactory,
)
from autobahn.twisted.websocket import WebSocketClientProtocol, \
WebSocketClientFactory
class MyClientProtocol(WebSocketClientProtocol):
def onConnect(self, response):
print("Server connected: {0}".format(response.peer))
class TahoeLogProtocol(WebSocketClientProtocol):
"""
"""
def onOpen(self):
print("WebSocket connection open.")
def hello():
self.sendMessage(u"Hello, world!".encode('utf8'))
self.sendMessage(b"\x00\x01\x03\x04", isBinary=True)
self.factory.reactor.callLater(1, hello)
# start sending messages every second ..
hello()
pass#print("connected")
def onMessage(self, payload, isBinary):
if isBinary:
print("Binary message received: {0} bytes".format(len(payload)))
if False:
log_data = json.loads(payload.decode('utf8'))
print("eliot message:")
for k, v in log_data.items():
print(" {}: {}".format(k, v))
else:
print("Text message received: {0}".format(payload.decode('utf8')))
print(payload)
sys.stdout.flush()
def onClose(self, wasClean, code, reason):
print("WebSocket connection closed: {0}".format(reason))
def onClose(self, *args):
print("bye", args)
if __name__ == '__main__':
@inlineCallbacks
def main(reactor):
import sys
from twisted.python import log
from twisted.internet import reactor
log.startLogging(sys.stdout)
with open("alice/private/api_auth_token", "r") as f:
with open("testgrid/alice/private/api_auth_token", "r") as f:
#with open("alice/private/api_auth_token", "r") as f:
token = f.read().strip()
factory = WebSocketClientFactory(
url=u"ws://127.0.0.1:6301/logs_v1",
url=u"ws://127.0.0.1:8890/logs_v1",
headers={
"Authorization": token,
"Authorization": "tahoe-lafs {}".format(token),
}
)
factory.protocol = MyClientProtocol
factory.protocol = TahoeLogProtocol
port = yield reactor.connectTCP("127.0.0.1", 8890, factory)
if False:
print("port {}".format(port))
print(dir(port))
print(port.getDestination())
print(port.transport)
print(dir(port.transport))
print(port.transport.protocol)
# can we like 'listen' for this connection/etc to die?
yield Deferred()
reactor.connectTCP("127.0.0.1", 6301, factory)
reactor.run()
if __name__ == '__main__':
react(main)