2016-06-04 06:07:50 +00:00
|
|
|
from __future__ import print_function, unicode_literals
|
2017-04-04 07:05:28 +00:00
|
|
|
import json, io, re
|
2016-05-22 18:31:00 +00:00
|
|
|
import mock
|
|
|
|
from twisted.trial import unittest
|
|
|
|
from twisted.internet import reactor
|
2017-04-04 07:05:28 +00:00
|
|
|
from twisted.internet.defer import gatherResults, inlineCallbacks
|
2017-04-06 17:44:04 +00:00
|
|
|
from .common import ServerBase, poll_until
|
2017-03-07 11:34:36 +00:00
|
|
|
from .. import wormhole, _rendezvous
|
2017-04-04 07:05:28 +00:00
|
|
|
from ..errors import (WrongPasswordError,
|
2017-03-08 07:45:11 +00:00
|
|
|
KeyFormatError, WormholeClosed, LonelyError,
|
|
|
|
NoKeyError, OnlyOneCodeError)
|
2016-05-22 18:31:00 +00:00
|
|
|
|
2016-06-04 20:16:09 +00:00
|
|
|
APPID = "appid"
|
2016-05-22 18:31:00 +00:00
|
|
|
|
|
|
|
class MockWebSocket:
|
|
|
|
def __init__(self):
|
|
|
|
self._payloads = []
|
|
|
|
def sendMessage(self, payload, is_binary):
|
|
|
|
assert not is_binary
|
|
|
|
self._payloads.append(payload)
|
|
|
|
|
|
|
|
def outbound(self):
|
|
|
|
out = []
|
|
|
|
while self._payloads:
|
|
|
|
p = self._payloads.pop(0)
|
|
|
|
out.append(json.loads(p.decode("utf-8")))
|
|
|
|
return out
|
|
|
|
|
|
|
|
def response(w, **kwargs):
|
|
|
|
payload = json.dumps(kwargs).encode("utf-8")
|
|
|
|
w._ws_dispatch_response(payload)
|
|
|
|
|
|
|
|
class Welcome(unittest.TestCase):
|
2016-05-23 01:40:44 +00:00
|
|
|
def test_tolerate_no_current_version(self):
|
2017-04-03 21:23:03 +00:00
|
|
|
w = wormhole._WelcomeHandler("relay_url")
|
2016-05-22 18:31:00 +00:00
|
|
|
w.handle_welcome({})
|
|
|
|
|
2016-05-23 01:40:44 +00:00
|
|
|
def test_print_motd(self):
|
2017-04-03 21:23:03 +00:00
|
|
|
stderr = io.StringIO()
|
|
|
|
w = wormhole._WelcomeHandler("relay_url", stderr=stderr)
|
|
|
|
w.handle_welcome({"motd": "message of\nthe day"})
|
|
|
|
self.assertEqual(stderr.getvalue(),
|
|
|
|
"Server (at relay_url) says:\n message of\n the day\n")
|
2016-05-29 02:19:22 +00:00
|
|
|
# motd can be displayed multiple times
|
2017-04-03 21:23:03 +00:00
|
|
|
w.handle_welcome({"motd": "second message"})
|
|
|
|
self.assertEqual(stderr.getvalue(),
|
|
|
|
("Server (at relay_url) says:\n message of\n the day\n"
|
|
|
|
"Server (at relay_url) says:\n second message\n"))
|
2016-05-23 01:40:44 +00:00
|
|
|
|
|
|
|
# event orderings to exercise:
|
|
|
|
#
|
|
|
|
# * normal sender: set_code, send_phase1, connected, claimed, learn_msg2,
|
|
|
|
# learn_phase1
|
|
|
|
# * normal receiver (argv[2]=code): set_code, connected, learn_msg1,
|
|
|
|
# learn_phase1, send_phase1,
|
|
|
|
# * normal receiver (readline): connected, input_code
|
|
|
|
# *
|
|
|
|
# * set_code, then connected
|
|
|
|
# * connected, receive_pake, send_phase, set_code
|
|
|
|
|
2017-04-04 07:05:28 +00:00
|
|
|
class Delegate:
|
|
|
|
def __init__(self):
|
|
|
|
self.code = None
|
|
|
|
self.verifier = None
|
|
|
|
self.messages = []
|
|
|
|
self.closed = None
|
|
|
|
def wormhole_got_code(self, code):
|
|
|
|
self.code = code
|
|
|
|
def wormhole_got_verifier(self, verifier):
|
|
|
|
self.verifier = verifier
|
|
|
|
def wormhole_receive(self, data):
|
|
|
|
self.messages.append(data)
|
|
|
|
def wormhole_closed(self, result):
|
|
|
|
self.closed = result
|
|
|
|
|
|
|
|
class Delegated(ServerBase, unittest.TestCase):
|
|
|
|
|
|
|
|
def test_delegated(self):
|
|
|
|
dg = Delegate()
|
|
|
|
w = wormhole.create(APPID, self.relayurl, reactor, delegate=dg)
|
|
|
|
w.close()
|
|
|
|
|
2016-05-23 01:40:44 +00:00
|
|
|
class Wormholes(ServerBase, unittest.TestCase):
|
|
|
|
# integration test, with a real server
|
|
|
|
|
|
|
|
def doBoth(self, d1, d2):
|
|
|
|
return gatherResults([d1, d2], True)
|
|
|
|
|
2017-04-04 07:05:28 +00:00
|
|
|
@inlineCallbacks
|
|
|
|
def test_allocate_default(self):
|
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.allocate_code()
|
|
|
|
code = yield w1.when_code()
|
|
|
|
mo = re.search(r"^\d+-\w+-\w+$", code)
|
|
|
|
self.assert_(mo, code)
|
|
|
|
# w.close() fails because we closed before connecting
|
|
|
|
yield self.assertFailure(w1.close(), LonelyError)
|
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_allocate_more_words(self):
|
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.allocate_code(3)
|
|
|
|
code = yield w1.when_code()
|
|
|
|
mo = re.search(r"^\d+-\w+-\w+-\w+$", code)
|
|
|
|
self.assert_(mo, code)
|
|
|
|
yield self.assertFailure(w1.close(), LonelyError)
|
|
|
|
|
2016-05-23 01:40:44 +00:00
|
|
|
@inlineCallbacks
|
|
|
|
def test_basic(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
2017-04-04 07:05:28 +00:00
|
|
|
#w1.debug_set_trace("W1")
|
2017-03-07 11:34:36 +00:00
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
2017-04-04 07:05:28 +00:00
|
|
|
#w2.debug_set_trace(" W2")
|
2017-03-07 11:34:36 +00:00
|
|
|
w1.allocate_code()
|
|
|
|
code = yield w1.when_code()
|
2016-05-23 01:40:44 +00:00
|
|
|
w2.set_code(code)
|
2017-04-04 07:05:28 +00:00
|
|
|
|
|
|
|
verifier1 = yield w1.when_verified()
|
|
|
|
verifier2 = yield w2.when_verified()
|
|
|
|
self.assertEqual(verifier1, verifier2)
|
|
|
|
|
|
|
|
version1 = yield w1.when_version()
|
|
|
|
version2 = yield w2.when_version()
|
|
|
|
# TODO: add the ability to set app-versions
|
|
|
|
self.assertEqual(version1, {})
|
|
|
|
self.assertEqual(version2, {})
|
|
|
|
|
2016-05-23 01:40:44 +00:00
|
|
|
w1.send(b"data1")
|
|
|
|
w2.send(b"data2")
|
2017-03-07 11:34:36 +00:00
|
|
|
dataX = yield w1.when_received()
|
|
|
|
dataY = yield w2.when_received()
|
2016-05-23 01:40:44 +00:00
|
|
|
self.assertEqual(dataX, b"data2")
|
|
|
|
self.assertEqual(dataY, b"data1")
|
2017-04-04 07:05:28 +00:00
|
|
|
|
|
|
|
version1_again = yield w1.when_version()
|
|
|
|
self.assertEqual(version1, version1_again)
|
|
|
|
|
|
|
|
c1 = yield w1.close()
|
|
|
|
self.assertEqual(c1, "happy")
|
|
|
|
c2 = yield w2.close()
|
|
|
|
self.assertEqual(c2, "happy")
|
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_when_code_early(self):
|
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
d = w1.when_code()
|
|
|
|
w1.set_code("1-abc")
|
|
|
|
code = self.successResultOf(d)
|
|
|
|
self.assertEqual(code, "1-abc")
|
|
|
|
yield self.assertFailure(w1.close(), LonelyError)
|
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_when_code_late(self):
|
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.set_code("1-abc")
|
|
|
|
d = w1.when_code()
|
|
|
|
code = self.successResultOf(d)
|
|
|
|
self.assertEqual(code, "1-abc")
|
|
|
|
yield self.assertFailure(w1.close(), LonelyError)
|
2016-05-23 01:40:44 +00:00
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_same_message(self):
|
|
|
|
# the two sides use random nonces for their messages, so it's ok for
|
|
|
|
# both to try and send the same body: they'll result in distinct
|
|
|
|
# encrypted messages
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.allocate_code()
|
|
|
|
code = yield w1.when_code()
|
2016-05-23 01:40:44 +00:00
|
|
|
w2.set_code(code)
|
2016-05-24 05:53:00 +00:00
|
|
|
w1.send(b"data")
|
|
|
|
w2.send(b"data")
|
2017-03-07 11:34:36 +00:00
|
|
|
dataX = yield w1.when_received()
|
|
|
|
dataY = yield w2.when_received()
|
2016-05-23 01:40:44 +00:00
|
|
|
self.assertEqual(dataX, b"data")
|
|
|
|
self.assertEqual(dataY, b"data")
|
2016-05-24 06:59:49 +00:00
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
2016-05-23 01:40:44 +00:00
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_interleaved(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.allocate_code()
|
|
|
|
code = yield w1.when_code()
|
2016-05-23 01:40:44 +00:00
|
|
|
w2.set_code(code)
|
2016-05-24 05:53:00 +00:00
|
|
|
w1.send(b"data1")
|
2017-03-07 11:34:36 +00:00
|
|
|
dataY = yield w2.when_received()
|
2016-05-23 01:40:44 +00:00
|
|
|
self.assertEqual(dataY, b"data1")
|
2017-03-07 11:34:36 +00:00
|
|
|
d = w1.when_received()
|
2016-05-24 05:53:00 +00:00
|
|
|
w2.send(b"data2")
|
|
|
|
dataX = yield d
|
2016-05-23 01:40:44 +00:00
|
|
|
self.assertEqual(dataX, b"data2")
|
2016-05-24 06:59:49 +00:00
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
2016-05-24 05:53:00 +00:00
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_unidirectional(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.allocate_code()
|
|
|
|
code = yield w1.when_code()
|
2016-05-24 05:53:00 +00:00
|
|
|
w2.set_code(code)
|
|
|
|
w1.send(b"data1")
|
2017-03-07 11:34:36 +00:00
|
|
|
dataY = yield w2.when_received()
|
2016-05-24 05:53:00 +00:00
|
|
|
self.assertEqual(dataY, b"data1")
|
2016-05-24 06:59:49 +00:00
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
2016-05-24 05:53:00 +00:00
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_early(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
2016-05-24 05:53:00 +00:00
|
|
|
w1.send(b"data1")
|
2017-03-07 11:34:36 +00:00
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
d = w2.when_received()
|
2016-06-04 20:16:09 +00:00
|
|
|
w1.set_code("123-abc-def")
|
|
|
|
w2.set_code("123-abc-def")
|
2016-05-24 05:53:00 +00:00
|
|
|
dataY = yield d
|
|
|
|
self.assertEqual(dataY, b"data1")
|
2016-05-24 06:59:49 +00:00
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
2016-05-23 01:40:44 +00:00
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_fixed_code(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
2016-06-04 20:16:09 +00:00
|
|
|
w1.set_code("123-purple-elephant")
|
|
|
|
w2.set_code("123-purple-elephant")
|
2016-05-24 05:53:00 +00:00
|
|
|
w1.send(b"data1"), w2.send(b"data2")
|
2017-03-07 11:34:36 +00:00
|
|
|
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
2016-05-23 01:40:44 +00:00
|
|
|
(dataX, dataY) = dl
|
|
|
|
self.assertEqual(dataX, b"data2")
|
|
|
|
self.assertEqual(dataY, b"data1")
|
2016-05-24 06:59:49 +00:00
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
2016-05-23 01:40:44 +00:00
|
|
|
|
2017-04-06 17:44:04 +00:00
|
|
|
@inlineCallbacks
|
|
|
|
def test_input_code(self):
|
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.set_code("123-purple-elephant")
|
|
|
|
h = w2.input_code()
|
|
|
|
h.choose_nameplate("123")
|
|
|
|
# Pause to allow some messages to get delivered. Specifically we want
|
|
|
|
# to wait until w2 claims the nameplate, opens the mailbox, and
|
|
|
|
# receives the PAKE message, to exercise the PAKE-before-CODE path in
|
|
|
|
# Key.
|
|
|
|
yield poll_until(lambda: w2._boss._K._debug_pake_stashed)
|
|
|
|
h.choose_words("purple-elephant")
|
|
|
|
|
|
|
|
w1.send(b"data1"), w2.send(b"data2")
|
|
|
|
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
|
|
|
(dataX, dataY) = dl
|
|
|
|
self.assertEqual(dataX, b"data2")
|
|
|
|
self.assertEqual(dataY, b"data1")
|
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
|
|
|
|
2016-05-23 01:40:44 +00:00
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_multiple_messages(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
2016-06-04 20:16:09 +00:00
|
|
|
w1.set_code("123-purple-elephant")
|
|
|
|
w2.set_code("123-purple-elephant")
|
2016-05-24 05:53:00 +00:00
|
|
|
w1.send(b"data1"), w2.send(b"data2")
|
|
|
|
w1.send(b"data3"), w2.send(b"data4")
|
2017-03-07 11:34:36 +00:00
|
|
|
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
2016-05-23 01:40:44 +00:00
|
|
|
(dataX, dataY) = dl
|
|
|
|
self.assertEqual(dataX, b"data2")
|
|
|
|
self.assertEqual(dataY, b"data1")
|
2017-03-07 11:34:36 +00:00
|
|
|
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
2016-05-23 01:40:44 +00:00
|
|
|
(dataX, dataY) = dl
|
|
|
|
self.assertEqual(dataX, b"data4")
|
|
|
|
self.assertEqual(dataY, b"data3")
|
2016-05-24 06:59:49 +00:00
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
2016-05-23 01:40:44 +00:00
|
|
|
|
2017-03-07 11:34:36 +00:00
|
|
|
|
|
|
|
@inlineCallbacks
|
|
|
|
def test_closed(self):
|
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.set_code("123-foo")
|
|
|
|
w2.set_code("123-foo")
|
|
|
|
|
|
|
|
# let it connect and become HAPPY
|
|
|
|
yield w1.when_version()
|
|
|
|
yield w2.when_version()
|
|
|
|
|
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
|
|
|
|
|
|
|
# once closed, all Deferred-yielding API calls get an error
|
|
|
|
e = yield self.assertFailure(w1.when_code(), WormholeClosed)
|
|
|
|
self.assertEqual(e.args[0], "happy")
|
|
|
|
yield self.assertFailure(w1.when_verified(), WormholeClosed)
|
|
|
|
yield self.assertFailure(w1.when_version(), WormholeClosed)
|
|
|
|
yield self.assertFailure(w1.when_received(), WormholeClosed)
|
|
|
|
|
|
|
|
|
2016-05-23 01:40:44 +00:00
|
|
|
@inlineCallbacks
|
|
|
|
def test_wrong_password(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.allocate_code()
|
|
|
|
code = yield w1.when_code()
|
2016-05-23 01:40:44 +00:00
|
|
|
w2.set_code(code+"not")
|
2017-04-04 07:05:28 +00:00
|
|
|
code2 = yield w2.when_code()
|
|
|
|
self.assertNotEqual(code, code2)
|
2016-05-24 05:53:00 +00:00
|
|
|
# That's enough to allow both sides to discover the mismatch, but
|
|
|
|
# only after the confirmation message gets through. API calls that
|
|
|
|
# don't wait will appear to work until the mismatched confirmation
|
|
|
|
# message arrives.
|
|
|
|
w1.send(b"should still work")
|
|
|
|
w2.send(b"should still work")
|
|
|
|
|
|
|
|
# API calls that wait (i.e. get) will errback
|
2017-03-07 11:34:36 +00:00
|
|
|
yield self.assertFailure(w2.when_received(), WrongPasswordError)
|
|
|
|
yield self.assertFailure(w1.when_received(), WrongPasswordError)
|
|
|
|
|
|
|
|
yield self.assertFailure(w1.when_verified(), WrongPasswordError)
|
|
|
|
yield self.assertFailure(w1.when_version(), WrongPasswordError)
|
|
|
|
|
|
|
|
yield self.assertFailure(w1.close(), WrongPasswordError)
|
|
|
|
yield self.assertFailure(w2.close(), WrongPasswordError)
|
2016-05-23 01:40:44 +00:00
|
|
|
|
|
|
|
|
2016-06-02 21:07:27 +00:00
|
|
|
@inlineCallbacks
|
|
|
|
def test_wrong_password_with_spaces(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
badcode = "4 oops spaces"
|
2016-06-02 21:21:29 +00:00
|
|
|
with self.assertRaises(KeyFormatError) as ex:
|
2017-03-07 11:34:36 +00:00
|
|
|
w.set_code(badcode)
|
|
|
|
expected_msg = "code (%s) contains spaces." % (badcode,)
|
2016-06-02 21:21:29 +00:00
|
|
|
self.assertEqual(expected_msg, str(ex.exception))
|
2017-03-07 11:34:36 +00:00
|
|
|
yield self.assertFailure(w.close(), LonelyError)
|
2016-06-02 21:07:27 +00:00
|
|
|
|
2016-05-23 01:40:44 +00:00
|
|
|
@inlineCallbacks
|
|
|
|
def test_verifier(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w1.allocate_code()
|
|
|
|
code = yield w1.when_code()
|
2016-05-23 01:40:44 +00:00
|
|
|
w2.set_code(code)
|
2017-03-07 11:34:36 +00:00
|
|
|
v1 = yield w1.when_verified()
|
|
|
|
v2 = yield w2.when_verified()
|
2016-05-23 01:40:44 +00:00
|
|
|
self.failUnlessEqual(type(v1), type(b""))
|
|
|
|
self.failUnlessEqual(v1, v2)
|
2016-05-24 05:53:00 +00:00
|
|
|
w1.send(b"data1")
|
|
|
|
w2.send(b"data2")
|
2017-03-07 11:34:36 +00:00
|
|
|
dataX = yield w1.when_received()
|
|
|
|
dataY = yield w2.when_received()
|
2016-05-23 01:40:44 +00:00
|
|
|
self.assertEqual(dataX, b"data2")
|
|
|
|
self.assertEqual(dataY, b"data1")
|
2016-05-24 06:59:49 +00:00
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
2016-05-23 01:40:44 +00:00
|
|
|
|
2016-05-26 01:27:37 +00:00
|
|
|
@inlineCallbacks
|
|
|
|
def test_versions(self):
|
|
|
|
# there's no API for this yet, but make sure the internals work
|
2017-03-07 11:34:36 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor,
|
|
|
|
versions={"w1": 123})
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor,
|
|
|
|
versions={"w2": 456})
|
|
|
|
w1.allocate_code()
|
|
|
|
code = yield w1.when_code()
|
2016-05-26 01:27:37 +00:00
|
|
|
w2.set_code(code)
|
2017-03-07 11:34:36 +00:00
|
|
|
w1_versions = yield w2.when_version()
|
|
|
|
self.assertEqual(w1_versions, {"w1": 123})
|
|
|
|
w2_versions = yield w1.when_version()
|
|
|
|
self.assertEqual(w2_versions, {"w2": 456})
|
2016-05-26 01:27:37 +00:00
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
|
|
|
|
2016-12-26 20:21:45 +00:00
|
|
|
@inlineCallbacks
|
|
|
|
def test_rx_dedup(self):
|
|
|
|
# Future clients will handle losing/reestablishing the Rendezvous
|
|
|
|
# Server connection by retransmitting messages, which will sometimes
|
|
|
|
# cause duplicate messages. Make sure this client can tolerate them.
|
|
|
|
# The first place this would fail was when the second copy of the
|
|
|
|
# incoming PAKE message was received, which would cause
|
|
|
|
# SPAKE2.finish() to be called a second time, which throws an error
|
|
|
|
# (which, being somewhat unexpected, caused a hang rather than a
|
2017-03-07 11:34:36 +00:00
|
|
|
# clear exception). The Mailbox object is responsible for
|
|
|
|
# deduplication, so we must patch the RendezvousConnector to simulate
|
|
|
|
# duplicated messages.
|
|
|
|
with mock.patch("wormhole._boss.RendezvousConnector", MessageDoubler):
|
2017-03-04 11:44:07 +00:00
|
|
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
|
|
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
2016-12-26 20:21:45 +00:00
|
|
|
w1.set_code("123-purple-elephant")
|
|
|
|
w2.set_code("123-purple-elephant")
|
|
|
|
w1.send(b"data1"), w2.send(b"data2")
|
2017-03-07 11:34:36 +00:00
|
|
|
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
2016-12-26 20:21:45 +00:00
|
|
|
(dataX, dataY) = dl
|
|
|
|
self.assertEqual(dataX, b"data2")
|
|
|
|
self.assertEqual(dataY, b"data1")
|
|
|
|
yield w1.close()
|
|
|
|
yield w2.close()
|
|
|
|
|
2017-03-07 11:34:36 +00:00
|
|
|
class MessageDoubler(_rendezvous.RendezvousConnector):
|
2016-12-26 20:21:45 +00:00
|
|
|
# we could double messages on the sending side, but a future server will
|
|
|
|
# strip those duplicates, so to really exercise the receiver, we must
|
|
|
|
# double them on the inbound side instead
|
|
|
|
#def _msg_send(self, phase, body):
|
|
|
|
# wormhole._Wormhole._msg_send(self, phase, body)
|
|
|
|
# self._ws_send_command("add", phase=phase, body=bytes_to_hexstr(body))
|
2017-03-07 11:34:36 +00:00
|
|
|
def _response_handle_message(self, msg):
|
|
|
|
_rendezvous.RendezvousConnector._response_handle_message(self, msg)
|
|
|
|
_rendezvous.RendezvousConnector._response_handle_message(self, msg)
|
2016-12-26 20:21:45 +00:00
|
|
|
|
2016-05-24 05:53:00 +00:00
|
|
|
class Errors(ServerBase, unittest.TestCase):
|
2016-05-23 01:40:44 +00:00
|
|
|
@inlineCallbacks
|
2017-03-08 07:45:11 +00:00
|
|
|
def test_derive_key_early(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w = wormhole.create(APPID, self.relayurl, reactor)
|
2016-05-24 05:53:00 +00:00
|
|
|
# definitely too early
|
2017-03-08 07:45:11 +00:00
|
|
|
self.assertRaises(NoKeyError, w.derive_key, "purpose", 12)
|
|
|
|
yield self.assertFailure(w.close(), LonelyError)
|
2016-05-24 05:53:00 +00:00
|
|
|
|
2017-03-08 07:45:11 +00:00
|
|
|
@inlineCallbacks
|
|
|
|
def test_multiple_set_code(self):
|
|
|
|
w = wormhole.create(APPID, self.relayurl, reactor)
|
2016-06-04 20:16:09 +00:00
|
|
|
w.set_code("123-purple-elephant")
|
2016-05-24 05:53:00 +00:00
|
|
|
# code can only be set once
|
2017-03-08 07:45:11 +00:00
|
|
|
self.assertRaises(OnlyOneCodeError, w.set_code, "123-nope")
|
|
|
|
yield self.assertFailure(w.close(), LonelyError)
|
2016-05-24 05:53:00 +00:00
|
|
|
|
|
|
|
@inlineCallbacks
|
2017-03-08 07:45:11 +00:00
|
|
|
def test_allocate_and_set_code(self):
|
2017-03-07 11:34:36 +00:00
|
|
|
w = wormhole.create(APPID, self.relayurl, reactor)
|
2017-03-08 07:45:11 +00:00
|
|
|
w.allocate_code()
|
2017-03-07 11:34:36 +00:00
|
|
|
yield w.when_code()
|
2017-03-08 07:45:11 +00:00
|
|
|
self.assertRaises(OnlyOneCodeError, w.set_code, "123-nope")
|
|
|
|
yield self.assertFailure(w.close(), LonelyError)
|