Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ User-visible changes in "magic-wormhole-mailbox-server":

* (put release-note here when merging / proposing a PR)
* CI no longer tests Python 3.8 (it is EOL)
* add a ``/v2/`` version that introduces a ``"you"`` key to the ``"welcome"`` message (to reflect the IP address and port back)


## Release 0.5.1 (9-Nov-2024)
Expand Down
47 changes: 44 additions & 3 deletions src/wormhole_mailbox_server/server_websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,56 @@ def __init__(self):
self._mailbox = None
self._mailbox_id = None
self._did_close = False
self._peer_addr_port = None

def onConnect(self, request):
rv = self.factory.server
# Caddy uses capitalized headers like X-Real-IP and X-Real-Port, which
# you see if you forward Caddy to netcat. But the twisted/autobahn
# Request object lowercases everything.
if "x-real-ip" in request.headers:
peer_host = request.headers.get("x-real-ip") # either 1.2.3.4 or 2600:..:1234
peer_port = request.headers.get("x-real-port")
# assume frontends like Caddy don't give us v4-in-v6 addrs
peer_type = "ipv6" if ":" in peer_host else "ipv4"
else:
peer = request.peer
peer_type = peer.split(":", maxsplit=1)[0]
peer_port = peer.rsplit(":", maxsplit=1)[-1]
peer_host = peer[len(peer_type)+1:(-len(peer_port)-1)]
# this gets me [tcp6, ::1, 53276] for a client using ws://localhost:4000/v1
# or ws://[::1]:4000/v1
# and [tcp6, ::ffff:127.0.0.1, 53279] when using ws://127.0.0.1:4000/v1
if peer_type == "tcp6":
peer_type = "ipv6"
if peer_host.startswith("::ffff:"):
peer_host = peer_host.rsplit(":", maxsplit=1)[-1]
peer_type = "ipv4"
else:
peer_type = "ipv4"
self._peer_addr_port = (peer_type, peer_host, int(peer_port))

if rv.get_log_requests():
log.msg(f"ws client connecting: {request.peer}")
v = 4 if peer_type == "ipv4" else 6
log.msg(f"ws client connecting: tcp{v}:{peer_host}:{peer_port}")
self._reactor = self.factory.reactor

def get_you(self):
(peer_type, peer_host, peer_port) = self._peer_addr_port
you = { "port": peer_port }
if peer_type == "ipv4":
you["ipv4"] = peer_host
elif peer_host == "ipv6":
you["ipv6"] = peer_host
return you

def onOpen(self):
rv = self.factory.server
self.send("welcome", welcome=rv.get_welcome())
welcome = rv.get_welcome()
if self.factory.version > 1:
welcome = welcome.copy()
welcome["you"] = self.get_you()
self.send("welcome", welcome=welcome)

def onMessage(self, payload, isBinary):
server_rx = time.time()
Expand Down Expand Up @@ -301,8 +341,9 @@ def onClose(self, wasClean, code, reason):
class WebSocketServerFactory(websocket.WebSocketServerFactory):
protocol = WebSocketServer

def __init__(self, url, server):
def __init__(self, url, server, version):
websocket.WebSocketServerFactory.__init__(self, url)
self.setProtocolOptions(autoPingInterval=60, autoPingTimeout=600)
self.server = server
self.version = version
self.reactor = reactor # for tests to control
1 change: 0 additions & 1 deletion src/wormhole_mailbox_server/test/test_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ def test_log_websocket(self):
expected = "ws client connecting: tcp4:127.0.0.1:%d" % client_port
self.assertEqual(l.mock_calls, [mock.call(expected)])


@inlineCallbacks
def test_no_log_http(self):
yield self._setup_relay(do_listen=True, web_log_requests=False)
Expand Down
9 changes: 6 additions & 3 deletions src/wormhole_mailbox_server/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ def log(self, request):

def make_web_server(server, log_requests, websocket_protocol_options=()):
root = Root()
wsrf = WebSocketServerFactory(None, server)
wsrf.setProtocolOptions(**dict(websocket_protocol_options))
root.putChild(b"v1", WebSocketResource(wsrf))

for version in (1, 2):
wsrf = WebSocketServerFactory(None, server, version=version)
wsrf.setProtocolOptions(**dict(websocket_protocol_options))
path = f"v{version}".encode("utf8")
root.putChild(path, WebSocketResource(wsrf))

site = PrivacyEnhancedSite(root)
site.logRequests = log_requests
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# and then run "tox" from this directory.

[tox]
envlist = {py37,py38,py39,py310,py311,pypy}
envlist = {py310,py311,py312,py313,py314,pypy}
skip_missing_interpreters = True
minversion = 2.4.0

Expand Down