switch to new API
This renames all the existing API methods, to use a consistent "d=get_XYZ()" (for Deferred mode) or "dg.wormhole_got_XYZ()" (for Delegated mode). It updates cmd_send/cmd_receive/cmd_ssh to use the new API. Since we now have get_welcome(), apps handle the Welcome message with a Deferred callback instead of registering a "welcome handler". This lets us make sure we've finished printing any server message-of-the-day or "you should update your client" message to stdout before using stdio to ask for the wormhole code. (Previously, the code-input prompt was overwritten by the server message, and it was ugly). refs #145. This approach adds an extra roundtrip to the receiver, but we can fix that (see #145 for details). Because of that change, the server-is-being-slow message is printed at a slightly different time, so those tests needed some extra work to exercise it properly.
This commit is contained in:
parent
2312f2ccce
commit
7955a36bfd
|
@ -33,7 +33,6 @@ class Boss(object):
|
||||||
_url = attrib(validator=instance_of(type(u"")))
|
_url = attrib(validator=instance_of(type(u"")))
|
||||||
_appid = attrib(validator=instance_of(type(u"")))
|
_appid = attrib(validator=instance_of(type(u"")))
|
||||||
_versions = attrib(validator=instance_of(dict))
|
_versions = attrib(validator=instance_of(dict))
|
||||||
_welcome_handler = attrib() # TODO: validator: callable
|
|
||||||
_reactor = attrib()
|
_reactor = attrib()
|
||||||
_journal = attrib(validator=provides(_interfaces.IJournal))
|
_journal = attrib(validator=provides(_interfaces.IJournal))
|
||||||
_tor_manager = attrib() # TODO: ITorManager or None
|
_tor_manager = attrib() # TODO: ITorManager or None
|
||||||
|
@ -185,11 +184,11 @@ class Boss(object):
|
||||||
raise WelcomeError(welcome["error"])
|
raise WelcomeError(welcome["error"])
|
||||||
# TODO: it'd be nice to not call the handler when we're in
|
# TODO: it'd be nice to not call the handler when we're in
|
||||||
# S3_closing or S4_closed states. I tried to implement this with
|
# S3_closing or S4_closed states. I tried to implement this with
|
||||||
# rx_Welcome as an @input, but in the error case I'd be
|
# rx_welcome as an @input, but in the error case I'd be
|
||||||
# delivering a new input (rx_error or something) while in the
|
# delivering a new input (rx_error or something) while in the
|
||||||
# middle of processing the rx_welcome input, and I wasn't sure
|
# middle of processing the rx_welcome input, and I wasn't sure
|
||||||
# Automat would handle that correctly.
|
# Automat would handle that correctly.
|
||||||
self._welcome_handler(welcome) # can raise WelcomeError too
|
self._W.got_welcome(welcome) # TODO: let this raise WelcomeError?
|
||||||
except WelcomeError as welcome_error:
|
except WelcomeError as welcome_error:
|
||||||
self.rx_unwelcome(welcome_error)
|
self.rx_unwelcome(welcome_error)
|
||||||
@m.input()
|
@m.input()
|
||||||
|
@ -244,7 +243,7 @@ class Boss(object):
|
||||||
self._their_versions = bytes_to_dict(plaintext)
|
self._their_versions = bytes_to_dict(plaintext)
|
||||||
# but this part is app-to-app
|
# but this part is app-to-app
|
||||||
app_versions = self._their_versions.get("app_versions", {})
|
app_versions = self._their_versions.get("app_versions", {})
|
||||||
self._W.got_version(app_versions)
|
self._W.got_versions(app_versions)
|
||||||
|
|
||||||
@m.output()
|
@m.output()
|
||||||
def S_send(self, plaintext):
|
def S_send(self, plaintext):
|
||||||
|
|
|
@ -10,7 +10,7 @@ from ..transit import TransitReceiver
|
||||||
from ..errors import TransferError, WormholeClosedError, NoTorError
|
from ..errors import TransferError, WormholeClosedError, NoTorError
|
||||||
from ..util import (dict_to_bytes, bytes_to_dict, bytes_to_hexstr,
|
from ..util import (dict_to_bytes, bytes_to_dict, bytes_to_hexstr,
|
||||||
estimate_free_space)
|
estimate_free_space)
|
||||||
from .welcome import CLIWelcomeHandler
|
from .welcome import handle_welcome
|
||||||
|
|
||||||
APPID = u"lothar.com/wormhole/text-or-file-xfer"
|
APPID = u"lothar.com/wormhole/text-or-file-xfer"
|
||||||
|
|
||||||
|
@ -68,13 +68,10 @@ class Receiver:
|
||||||
# with the user handing off the wormhole code
|
# with the user handing off the wormhole code
|
||||||
yield self._tor_manager.start()
|
yield self._tor_manager.start()
|
||||||
|
|
||||||
wh = CLIWelcomeHandler(self.args.relay_url, __version__,
|
|
||||||
self.args.stderr)
|
|
||||||
w = create(self.args.appid or APPID, self.args.relay_url,
|
w = create(self.args.appid or APPID, self.args.relay_url,
|
||||||
self._reactor,
|
self._reactor,
|
||||||
tor_manager=self._tor_manager,
|
tor_manager=self._tor_manager,
|
||||||
timing=self.args.timing,
|
timing=self.args.timing)
|
||||||
welcome_handler=wh.handle_welcome)
|
|
||||||
self._w = w # so tests can wait on events too
|
self._w = w # so tests can wait on events too
|
||||||
|
|
||||||
# I wanted to do this instead:
|
# I wanted to do this instead:
|
||||||
|
@ -112,6 +109,10 @@ class Receiver:
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def _go(self, w):
|
def _go(self, w):
|
||||||
|
welcome = yield w.get_welcome()
|
||||||
|
handle_welcome(welcome, self.args.relay_url, __version__,
|
||||||
|
self.args.stderr)
|
||||||
|
|
||||||
yield self._handle_code(w)
|
yield self._handle_code(w)
|
||||||
|
|
||||||
def on_slow_key():
|
def on_slow_key():
|
||||||
|
@ -125,7 +126,7 @@ class Receiver:
|
||||||
# of that possibility, it's probably not appropriate to give up
|
# of that possibility, it's probably not appropriate to give up
|
||||||
# automatically after some timeout. The user can express their
|
# automatically after some timeout. The user can express their
|
||||||
# impatience by quitting the program with control-C.
|
# impatience by quitting the program with control-C.
|
||||||
yield w.when_key()
|
yield w.get_unverified_key()
|
||||||
finally:
|
finally:
|
||||||
if not notify.called:
|
if not notify.called:
|
||||||
notify.cancel()
|
notify.cancel()
|
||||||
|
@ -147,7 +148,7 @@ class Receiver:
|
||||||
|
|
||||||
# It would be reasonable to give up after waiting here for too
|
# It would be reasonable to give up after waiting here for too
|
||||||
# long.
|
# long.
|
||||||
verifier_bytes = yield w.when_verified()
|
verifier_bytes = yield w.get_verifier()
|
||||||
finally:
|
finally:
|
||||||
if not notify.called:
|
if not notify.called:
|
||||||
notify.cancel()
|
notify.cancel()
|
||||||
|
@ -183,12 +184,12 @@ class Receiver:
|
||||||
|
|
||||||
def _send_data(self, data, w):
|
def _send_data(self, data, w):
|
||||||
data_bytes = dict_to_bytes(data)
|
data_bytes = dict_to_bytes(data)
|
||||||
w.send(data_bytes)
|
w.send_message(data_bytes)
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def _get_data(self, w):
|
def _get_data(self, w):
|
||||||
# this may raise WrongPasswordError
|
# this may raise WrongPasswordError
|
||||||
them_bytes = yield w.when_received()
|
them_bytes = yield w.get_message()
|
||||||
them_d = bytes_to_dict(them_bytes)
|
them_d = bytes_to_dict(them_bytes)
|
||||||
if "error" in them_d:
|
if "error" in them_d:
|
||||||
raise TransferError(them_d["error"])
|
raise TransferError(them_d["error"])
|
||||||
|
@ -210,7 +211,7 @@ class Receiver:
|
||||||
if not used_completion:
|
if not used_completion:
|
||||||
print(" (note: you can use <Tab> to complete words)",
|
print(" (note: you can use <Tab> to complete words)",
|
||||||
file=self.args.stderr)
|
file=self.args.stderr)
|
||||||
yield w.when_code()
|
yield w.get_code()
|
||||||
|
|
||||||
def _show_verifier(self, verifier_bytes):
|
def _show_verifier(self, verifier_bytes):
|
||||||
verifier_hex = bytes_to_hexstr(verifier_bytes)
|
verifier_hex = bytes_to_hexstr(verifier_bytes)
|
||||||
|
|
|
@ -10,7 +10,7 @@ from ..errors import TransferError, WormholeClosedError, NoTorError
|
||||||
from wormhole import create, __version__
|
from wormhole import create, __version__
|
||||||
from ..transit import TransitSender
|
from ..transit import TransitSender
|
||||||
from ..util import dict_to_bytes, bytes_to_dict, bytes_to_hexstr
|
from ..util import dict_to_bytes, bytes_to_dict, bytes_to_hexstr
|
||||||
from .welcome import CLIWelcomeHandler
|
from .welcome import handle_welcome
|
||||||
|
|
||||||
APPID = u"lothar.com/wormhole/text-or-file-xfer"
|
APPID = u"lothar.com/wormhole/text-or-file-xfer"
|
||||||
VERIFY_TIMER = 1
|
VERIFY_TIMER = 1
|
||||||
|
@ -53,13 +53,10 @@ class Sender:
|
||||||
# with the user handing off the wormhole code
|
# with the user handing off the wormhole code
|
||||||
yield self._tor_manager.start()
|
yield self._tor_manager.start()
|
||||||
|
|
||||||
wh = CLIWelcomeHandler(self._args.relay_url, __version__,
|
|
||||||
self._args.stderr)
|
|
||||||
w = create(self._args.appid or APPID, self._args.relay_url,
|
w = create(self._args.appid or APPID, self._args.relay_url,
|
||||||
self._reactor,
|
self._reactor,
|
||||||
tor_manager=self._tor_manager,
|
tor_manager=self._tor_manager,
|
||||||
timing=self._timing,
|
timing=self._timing)
|
||||||
welcome_handler=wh.handle_welcome)
|
|
||||||
d = self._go(w)
|
d = self._go(w)
|
||||||
|
|
||||||
# if we succeed, we should close and return the w.close results
|
# if we succeed, we should close and return the w.close results
|
||||||
|
@ -85,10 +82,14 @@ class Sender:
|
||||||
|
|
||||||
def _send_data(self, data, w):
|
def _send_data(self, data, w):
|
||||||
data_bytes = dict_to_bytes(data)
|
data_bytes = dict_to_bytes(data)
|
||||||
w.send(data_bytes)
|
w.send_message(data_bytes)
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def _go(self, w):
|
def _go(self, w):
|
||||||
|
welcome = yield w.get_welcome()
|
||||||
|
handle_welcome(welcome, self._args.relay_url, __version__,
|
||||||
|
self._args.stderr)
|
||||||
|
|
||||||
# TODO: run the blocking zip-the-directory IO in a thread, let the
|
# TODO: run the blocking zip-the-directory IO in a thread, let the
|
||||||
# wormhole exchange happen in parallel
|
# wormhole exchange happen in parallel
|
||||||
offer, self._fd_to_send = self._build_offer()
|
offer, self._fd_to_send = self._build_offer()
|
||||||
|
@ -110,21 +111,21 @@ class Sender:
|
||||||
else:
|
else:
|
||||||
w.allocate_code(args.code_length)
|
w.allocate_code(args.code_length)
|
||||||
|
|
||||||
code = yield w.when_code()
|
code = yield w.get_code()
|
||||||
if not args.zeromode:
|
if not args.zeromode:
|
||||||
print(u"Wormhole code is: %s" % code, file=args.stderr)
|
print(u"Wormhole code is: %s" % code, file=args.stderr)
|
||||||
# flush stderr so the code is displayed immediately
|
# flush stderr so the code is displayed immediately
|
||||||
args.stderr.flush()
|
args.stderr.flush()
|
||||||
print(u"", file=args.stderr)
|
print(u"", file=args.stderr)
|
||||||
|
|
||||||
# We don't print a "waiting" message for when_key() here, even though
|
# We don't print a "waiting" message for get_unverified_key() here,
|
||||||
# we do that in cmd_receive.py, because it's not at all surprising to
|
# even though we do that in cmd_receive.py, because it's not at all
|
||||||
# we waiting here for a long time. We'll sit in when_key() until the
|
# surprising to we waiting here for a long time. We'll sit in
|
||||||
# receiver has typed in the code and their PAKE message makes it to
|
# get_unverified_key() until the receiver has typed in the code and
|
||||||
# us.
|
# their PAKE message makes it to us.
|
||||||
yield w.when_key()
|
yield w.get_unverified_key()
|
||||||
|
|
||||||
# TODO: don't stall on w.verify() unless they want it
|
# TODO: don't stall on w.get_verifier() unless they want it
|
||||||
def on_slow_connection():
|
def on_slow_connection():
|
||||||
print(u"Key established, waiting for confirmation...",
|
print(u"Key established, waiting for confirmation...",
|
||||||
file=args.stderr)
|
file=args.stderr)
|
||||||
|
@ -132,13 +133,13 @@ class Sender:
|
||||||
try:
|
try:
|
||||||
# The usual sender-chooses-code sequence means the receiver's
|
# The usual sender-chooses-code sequence means the receiver's
|
||||||
# PAKE should be followed immediately by their VERSION, so
|
# PAKE should be followed immediately by their VERSION, so
|
||||||
# w.when_verified() should fire right away. However if we're
|
# w.get_verifier() should fire right away. However if we're
|
||||||
# using the offline-codes sequence, and the receiver typed in
|
# using the offline-codes sequence, and the receiver typed in
|
||||||
# their code first, and then they went offline, we might be
|
# their code first, and then they went offline, we might be
|
||||||
# sitting here for a while, so printing the "waiting" message
|
# sitting here for a while, so printing the "waiting" message
|
||||||
# seems like a good idea. It might even be appropriate to give up
|
# seems like a good idea. It might even be appropriate to give up
|
||||||
# after a while.
|
# after a while.
|
||||||
verifier_bytes = yield w.when_verified() # might WrongPasswordError
|
verifier_bytes = yield w.get_verifier() # might WrongPasswordError
|
||||||
finally:
|
finally:
|
||||||
if not notify.called:
|
if not notify.called:
|
||||||
notify.cancel()
|
notify.cancel()
|
||||||
|
@ -162,7 +163,7 @@ class Sender:
|
||||||
}
|
}
|
||||||
self._send_data({u"transit": sender_transit}, w)
|
self._send_data({u"transit": sender_transit}, w)
|
||||||
|
|
||||||
# TODO: move this down below w.get()
|
# TODO: move this down below w.get_message()
|
||||||
transit_key = w.derive_key(APPID+"/transit-key",
|
transit_key = w.derive_key(APPID+"/transit-key",
|
||||||
ts.TRANSIT_KEY_LENGTH)
|
ts.TRANSIT_KEY_LENGTH)
|
||||||
ts.set_transit_key(transit_key)
|
ts.set_transit_key(transit_key)
|
||||||
|
@ -174,13 +175,13 @@ class Sender:
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
them_d_bytes = yield w.when_received()
|
them_d_bytes = yield w.get_message()
|
||||||
except WormholeClosedError:
|
except WormholeClosedError:
|
||||||
if done:
|
if done:
|
||||||
returnValue(None)
|
returnValue(None)
|
||||||
raise TransferError("unexpected close")
|
raise TransferError("unexpected close")
|
||||||
# TODO: when_received() fired, so now it's safe to use
|
# TODO: get_message() fired, so get_verifier must have fired, so
|
||||||
# w.derive_key()
|
# now it's safe to use w.derive_key()
|
||||||
them_d = bytes_to_dict(them_d_bytes)
|
them_d = bytes_to_dict(them_d_bytes)
|
||||||
#print("GOT", them_d)
|
#print("GOT", them_d)
|
||||||
recognized = False
|
recognized = False
|
||||||
|
@ -209,7 +210,7 @@ class Sender:
|
||||||
if ok.lower() == "no":
|
if ok.lower() == "no":
|
||||||
err = "sender rejected verification check, abandoned transfer"
|
err = "sender rejected verification check, abandoned transfer"
|
||||||
reject_data = dict_to_bytes({"error": err})
|
reject_data = dict_to_bytes({"error": err})
|
||||||
w.send(reject_data)
|
w.send_message(reject_data)
|
||||||
raise TransferError(err)
|
raise TransferError(err)
|
||||||
|
|
||||||
def _handle_transit(self, receiver_transit):
|
def _handle_transit(self, receiver_transit):
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
from __future__ import print_function, absolute_import, unicode_literals
|
from __future__ import print_function, absolute_import, unicode_literals
|
||||||
import sys
|
|
||||||
from ..wormhole import _WelcomeHandler
|
|
||||||
|
|
||||||
class CLIWelcomeHandler(_WelcomeHandler):
|
def handle_welcome(welcome, relay_url, my_version, stderr):
|
||||||
def __init__(self, url, cli_version, stderr=sys.stderr):
|
if "motd" in welcome:
|
||||||
_WelcomeHandler.__init__(self, url, stderr)
|
motd_lines = welcome["motd"].splitlines()
|
||||||
self._current_version = cli_version
|
motd_formatted = "\n ".join(motd_lines)
|
||||||
self._version_warning_displayed = False
|
print("Server (at %s) says:\n %s" % (relay_url, motd_formatted),
|
||||||
|
file=stderr)
|
||||||
def handle_welcome(self, welcome):
|
|
||||||
# Only warn if we're running a release version (e.g. 0.0.6, not
|
|
||||||
# 0.0.6+DISTANCE.gHASH). Only warn once.
|
|
||||||
if ("current_cli_version" in welcome
|
|
||||||
and "+" not in self._current_version
|
|
||||||
and not self._version_warning_displayed
|
|
||||||
and welcome["current_cli_version"] != self._current_version):
|
|
||||||
print("Warning: errors may occur unless both sides are running the same version", file=self.stderr)
|
|
||||||
print("Server claims %s is current, but ours is %s"
|
|
||||||
% (welcome["current_cli_version"], self._current_version),
|
|
||||||
file=self.stderr)
|
|
||||||
self._version_warning_displayed = True
|
|
||||||
_WelcomeHandler.handle_welcome(self, welcome)
|
|
||||||
|
|
||||||
|
# Only warn if we're running a release version (e.g. 0.0.6, not
|
||||||
|
# 0.0.6+DISTANCE.gHASH). Only warn once.
|
||||||
|
if ("current_cli_version" in welcome
|
||||||
|
and "+" not in my_version
|
||||||
|
and welcome["current_cli_version"] != my_version):
|
||||||
|
print("Warning: errors may occur unless both sides are running the same version", file=stderr)
|
||||||
|
print("Server claims %s is current, but ours is %s"
|
||||||
|
% (welcome["current_cli_version"], my_version),
|
||||||
|
file=stderr)
|
||||||
|
|
|
@ -433,9 +433,16 @@ class PregeneratedCode(ServerBase, ScriptsBase, unittest.TestCase):
|
||||||
receive_d = cmd_receive.receive(recv_cfg)
|
receive_d = cmd_receive.receive(recv_cfg)
|
||||||
else:
|
else:
|
||||||
KEY_TIMER = 0 if mode == "slow-sender-text" else 1.0
|
KEY_TIMER = 0 if mode == "slow-sender-text" else 1.0
|
||||||
|
rxw = []
|
||||||
with mock.patch.object(cmd_receive, "KEY_TIMER", KEY_TIMER):
|
with mock.patch.object(cmd_receive, "KEY_TIMER", KEY_TIMER):
|
||||||
send_d = cmd_send.send(send_cfg)
|
send_d = cmd_send.send(send_cfg)
|
||||||
receive_d = cmd_receive.receive(recv_cfg)
|
receive_d = cmd_receive.receive(recv_cfg,
|
||||||
|
_debug_stash_wormhole=rxw)
|
||||||
|
# we need to keep KEY_TIMER patched until the receiver
|
||||||
|
# gets far enough to start the timer, which happens after
|
||||||
|
# the code is set
|
||||||
|
if mode == "slow-sender-text":
|
||||||
|
yield rxw[0].get_unverified_key()
|
||||||
|
|
||||||
# The sender might fail, leaving the receiver hanging, or vice
|
# The sender might fail, leaving the receiver hanging, or vice
|
||||||
# versa. Make sure we don't wait on one side exclusively
|
# versa. Make sure we don't wait on one side exclusively
|
||||||
|
@ -832,26 +839,26 @@ class NotWelcome(ServerBase, unittest.TestCase):
|
||||||
|
|
||||||
class Cleanup(ServerBase, unittest.TestCase):
|
class Cleanup(ServerBase, unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def make_config(self):
|
||||||
d = super(Cleanup, self).setUp()
|
cfg = config("send")
|
||||||
self.cfg = cfg = config("send")
|
|
||||||
# common options for all tests in this suite
|
# common options for all tests in this suite
|
||||||
cfg.hide_progress = True
|
cfg.hide_progress = True
|
||||||
cfg.relay_url = self.relayurl
|
cfg.relay_url = self.relayurl
|
||||||
cfg.transit_helper = ""
|
cfg.transit_helper = ""
|
||||||
cfg.stdout = io.StringIO()
|
cfg.stdout = io.StringIO()
|
||||||
cfg.stderr = io.StringIO()
|
cfg.stderr = io.StringIO()
|
||||||
return d
|
return cfg
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
@mock.patch('sys.stdout')
|
@mock.patch('sys.stdout')
|
||||||
def test_text(self, stdout):
|
def test_text(self, stdout):
|
||||||
# the rendezvous channel should be deleted after success
|
# the rendezvous channel should be deleted after success
|
||||||
self.cfg.text = "hello"
|
cfg = self.make_config()
|
||||||
self.cfg.code = "1-abc"
|
cfg.text = "hello"
|
||||||
|
cfg.code = "1-abc"
|
||||||
|
|
||||||
send_d = cmd_send.send(self.cfg)
|
send_d = cmd_send.send(cfg)
|
||||||
receive_d = cmd_receive.receive(self.cfg)
|
receive_d = cmd_receive.receive(cfg)
|
||||||
|
|
||||||
yield send_d
|
yield send_d
|
||||||
yield receive_d
|
yield receive_d
|
||||||
|
@ -863,12 +870,14 @@ class Cleanup(ServerBase, unittest.TestCase):
|
||||||
def test_text_wrong_password(self):
|
def test_text_wrong_password(self):
|
||||||
# if the password was wrong, the rendezvous channel should still be
|
# if the password was wrong, the rendezvous channel should still be
|
||||||
# deleted
|
# deleted
|
||||||
self.cfg.text = "secret message"
|
send_cfg = self.make_config()
|
||||||
self.cfg.code = "1-abc"
|
send_cfg.text = "secret message"
|
||||||
send_d = cmd_send.send(self.cfg)
|
send_cfg.code = "1-abc"
|
||||||
|
send_d = cmd_send.send(send_cfg)
|
||||||
|
|
||||||
self.cfg.code = "1-WRONG"
|
rx_cfg = self.make_config()
|
||||||
receive_d = cmd_receive.receive(self.cfg)
|
rx_cfg.code = "1-WRONG"
|
||||||
|
receive_d = cmd_receive.receive(rx_cfg)
|
||||||
|
|
||||||
# both sides should be capable of detecting the mismatch
|
# both sides should be capable of detecting the mismatch
|
||||||
yield self.assertFailure(send_d, WrongPasswordError)
|
yield self.assertFailure(send_d, WrongPasswordError)
|
||||||
|
@ -951,12 +960,9 @@ class AppID(ServerBase, unittest.TestCase):
|
||||||
self.assertEqual(used[0]["app_id"], u"appid2")
|
self.assertEqual(used[0]["app_id"], u"appid2")
|
||||||
|
|
||||||
class Welcome(unittest.TestCase):
|
class Welcome(unittest.TestCase):
|
||||||
def do(self, welcome_message, my_version="2.0", twice=False):
|
def do(self, welcome_message, my_version="2.0"):
|
||||||
stderr = io.StringIO()
|
stderr = io.StringIO()
|
||||||
h = welcome.CLIWelcomeHandler("url", my_version, stderr)
|
welcome.handle_welcome(welcome_message, "url", my_version, stderr)
|
||||||
h.handle_welcome(welcome_message)
|
|
||||||
if twice:
|
|
||||||
h.handle_welcome(welcome_message)
|
|
||||||
return stderr.getvalue()
|
return stderr.getvalue()
|
||||||
|
|
||||||
def test_empty(self):
|
def test_empty(self):
|
||||||
|
@ -973,15 +979,6 @@ class Welcome(unittest.TestCase):
|
||||||
"Server claims 3.0 is current, but ours is 2.0\n")
|
"Server claims 3.0 is current, but ours is 2.0\n")
|
||||||
self.assertEqual(stderr, expected)
|
self.assertEqual(stderr, expected)
|
||||||
|
|
||||||
def test_version_old_twice(self):
|
|
||||||
stderr = self.do({"current_cli_version": "3.0"}, twice=True)
|
|
||||||
# the handler should only emit the version warning once, even if we
|
|
||||||
# get multiple Welcome messages (which could happen if we lose the
|
|
||||||
# connection and then reconnect)
|
|
||||||
expected = ("Warning: errors may occur unless both sides are running the same version\n" +
|
|
||||||
"Server claims 3.0 is current, but ours is 2.0\n")
|
|
||||||
self.assertEqual(stderr, expected)
|
|
||||||
|
|
||||||
def test_version_unreleased(self):
|
def test_version_unreleased(self):
|
||||||
stderr = self.do({"current_cli_version": "3.0"},
|
stderr = self.do({"current_cli_version": "3.0"},
|
||||||
my_version="2.5+middle.something")
|
my_version="2.5+middle.something")
|
||||||
|
|
|
@ -1152,15 +1152,15 @@ class Boss(unittest.TestCase):
|
||||||
def build(self):
|
def build(self):
|
||||||
events = []
|
events = []
|
||||||
wormhole = Dummy("w", events, None,
|
wormhole = Dummy("w", events, None,
|
||||||
"got_code", "got_key", "got_verifier", "got_version",
|
"got_welcome",
|
||||||
|
"got_code", "got_key", "got_verifier", "got_versions",
|
||||||
"received", "closed")
|
"received", "closed")
|
||||||
self._welcome_handler = mock.Mock()
|
|
||||||
versions = {"app": "version1"}
|
versions = {"app": "version1"}
|
||||||
reactor = None
|
reactor = None
|
||||||
journal = ImmediateJournal()
|
journal = ImmediateJournal()
|
||||||
tor_manager = None
|
tor_manager = None
|
||||||
b = MockBoss(wormhole, "side", "url", "appid", versions,
|
b = MockBoss(wormhole, "side", "url", "appid", versions,
|
||||||
self._welcome_handler, reactor, journal, tor_manager,
|
reactor, journal, tor_manager,
|
||||||
timing.DebugTiming())
|
timing.DebugTiming())
|
||||||
b._T = Dummy("t", events, ITerminator, "close")
|
b._T = Dummy("t", events, ITerminator, "close")
|
||||||
b._S = Dummy("s", events, ISend, "send")
|
b._S = Dummy("s", events, ISend, "send")
|
||||||
|
@ -1179,8 +1179,11 @@ class Boss(unittest.TestCase):
|
||||||
self.assertEqual(events, [("w.got_code", "1-code")])
|
self.assertEqual(events, [("w.got_code", "1-code")])
|
||||||
events[:] = []
|
events[:] = []
|
||||||
|
|
||||||
b.rx_welcome("welcome")
|
welcome = {"howdy": "how are ya"}
|
||||||
self.assertEqual(self._welcome_handler.mock_calls, [mock.call("welcome")])
|
b.rx_welcome(welcome)
|
||||||
|
self.assertEqual(events, [("w.got_welcome", welcome),
|
||||||
|
])
|
||||||
|
events[:] = []
|
||||||
|
|
||||||
# pretend a peer message was correctly decrypted
|
# pretend a peer message was correctly decrypted
|
||||||
b.got_key(b"key")
|
b.got_key(b"key")
|
||||||
|
@ -1190,7 +1193,7 @@ class Boss(unittest.TestCase):
|
||||||
b.got_message("0", b"msg1")
|
b.got_message("0", b"msg1")
|
||||||
self.assertEqual(events, [("w.got_key", b"key"),
|
self.assertEqual(events, [("w.got_key", b"key"),
|
||||||
("w.got_verifier", b"verifier"),
|
("w.got_verifier", b"verifier"),
|
||||||
("w.got_version", {}),
|
("w.got_versions", {}),
|
||||||
("w.received", b"msg1"),
|
("w.received", b"msg1"),
|
||||||
])
|
])
|
||||||
events[:] = []
|
events[:] = []
|
||||||
|
@ -1206,6 +1209,12 @@ class Boss(unittest.TestCase):
|
||||||
b.closed()
|
b.closed()
|
||||||
self.assertEqual(events, [("w.closed", "happy")])
|
self.assertEqual(events, [("w.closed", "happy")])
|
||||||
|
|
||||||
|
def test_unwelcome(self):
|
||||||
|
b, events = self.build()
|
||||||
|
unwelcome = {"error": "go away"}
|
||||||
|
b.rx_welcome(unwelcome)
|
||||||
|
self.assertEqual(events, [("t.close", "unwelcome")])
|
||||||
|
|
||||||
def test_lonely(self):
|
def test_lonely(self):
|
||||||
b, events = self.build()
|
b, events = self.build()
|
||||||
b.set_code("1-code")
|
b.set_code("1-code")
|
||||||
|
|
|
@ -12,23 +12,6 @@ from ..errors import (WrongPasswordError,
|
||||||
|
|
||||||
APPID = "appid"
|
APPID = "appid"
|
||||||
|
|
||||||
class Welcome(unittest.TestCase):
|
|
||||||
def test_tolerate_no_current_version(self):
|
|
||||||
w = wormhole._WelcomeHandler("relay_url")
|
|
||||||
w.handle_welcome({})
|
|
||||||
|
|
||||||
def test_print_motd(self):
|
|
||||||
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")
|
|
||||||
# motd can be displayed multiple times
|
|
||||||
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"))
|
|
||||||
|
|
||||||
# event orderings to exercise:
|
# event orderings to exercise:
|
||||||
#
|
#
|
||||||
# * normal sender: set_code, send_phase1, connected, claimed, learn_msg2,
|
# * normal sender: set_code, send_phase1, connected, claimed, learn_msg2,
|
||||||
|
@ -42,21 +25,24 @@ class Welcome(unittest.TestCase):
|
||||||
|
|
||||||
class Delegate:
|
class Delegate:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.welcome = None
|
||||||
self.code = None
|
self.code = None
|
||||||
self.key = None
|
self.key = None
|
||||||
self.verifier = None
|
self.verifier = None
|
||||||
self.version = None
|
self.versions = None
|
||||||
self.messages = []
|
self.messages = []
|
||||||
self.closed = None
|
self.closed = None
|
||||||
def wormhole_code(self, code):
|
def wormhole_got_welcome(self, welcome):
|
||||||
|
self.welcome = welcome
|
||||||
|
def wormhole_got_code(self, code):
|
||||||
self.code = code
|
self.code = code
|
||||||
def wormhole_key(self, key):
|
def wormhole_got_unverified_key(self, key):
|
||||||
self.key = key
|
self.key = key
|
||||||
def wormhole_verified(self, verifier):
|
def wormhole_got_verifier(self, verifier):
|
||||||
self.verifier = verifier
|
self.verifier = verifier
|
||||||
def wormhole_version(self, version):
|
def wormhole_got_versions(self, versions):
|
||||||
self.version = version
|
self.versions = versions
|
||||||
def wormhole_received(self, data):
|
def wormhole_got_message(self, data):
|
||||||
self.messages.append(data)
|
self.messages.append(data)
|
||||||
def wormhole_closed(self, result):
|
def wormhole_closed(self, result):
|
||||||
self.closed = result
|
self.closed = result
|
||||||
|
@ -76,12 +62,12 @@ class Delegated(ServerBase, unittest.TestCase):
|
||||||
w2.set_code(dg.code)
|
w2.set_code(dg.code)
|
||||||
yield poll_until(lambda: dg.key is not None)
|
yield poll_until(lambda: dg.key is not None)
|
||||||
yield poll_until(lambda: dg.verifier is not None)
|
yield poll_until(lambda: dg.verifier is not None)
|
||||||
yield poll_until(lambda: dg.version is not None)
|
yield poll_until(lambda: dg.versions is not None)
|
||||||
|
|
||||||
w1.send(b"ping")
|
w1.send_message(b"ping")
|
||||||
got = yield w2.when_received()
|
got = yield w2.get_message()
|
||||||
self.assertEqual(got, b"ping")
|
self.assertEqual(got, b"ping")
|
||||||
w2.send(b"pong")
|
w2.send_message(b"pong")
|
||||||
yield poll_until(lambda: dg.messages)
|
yield poll_until(lambda: dg.messages)
|
||||||
self.assertEqual(dg.messages[0], b"pong")
|
self.assertEqual(dg.messages[0], b"pong")
|
||||||
|
|
||||||
|
@ -124,7 +110,7 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
def test_allocate_default(self):
|
def test_allocate_default(self):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.allocate_code()
|
w1.allocate_code()
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
mo = re.search(r"^\d+-\w+-\w+$", code)
|
mo = re.search(r"^\d+-\w+-\w+$", code)
|
||||||
self.assert_(mo, code)
|
self.assert_(mo, code)
|
||||||
# w.close() fails because we closed before connecting
|
# w.close() fails because we closed before connecting
|
||||||
|
@ -134,7 +120,7 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
def test_allocate_more_words(self):
|
def test_allocate_more_words(self):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.allocate_code(3)
|
w1.allocate_code(3)
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
mo = re.search(r"^\d+-\w+-\w+-\w+$", code)
|
mo = re.search(r"^\d+-\w+-\w+-\w+$", code)
|
||||||
self.assert_(mo, code)
|
self.assert_(mo, code)
|
||||||
yield self.assertFailure(w1.close(), LonelyError)
|
yield self.assertFailure(w1.close(), LonelyError)
|
||||||
|
@ -149,11 +135,11 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
#w2.debug_set_trace(" W2")
|
#w2.debug_set_trace(" W2")
|
||||||
w1.allocate_code()
|
w1.allocate_code()
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
w2.set_code(code)
|
w2.set_code(code)
|
||||||
|
|
||||||
yield w1.when_key()
|
yield w1.get_unverified_key()
|
||||||
yield w2.when_key()
|
yield w2.get_unverified_key()
|
||||||
|
|
||||||
key1 = w1.derive_key("purpose", 16)
|
key1 = w1.derive_key("purpose", 16)
|
||||||
self.assertEqual(len(key1), 16)
|
self.assertEqual(len(key1), 16)
|
||||||
|
@ -163,29 +149,29 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
w1.derive_key(12345, 16)
|
w1.derive_key(12345, 16)
|
||||||
|
|
||||||
verifier1 = yield w1.when_verified()
|
verifier1 = yield w1.get_verifier()
|
||||||
verifier2 = yield w2.when_verified()
|
verifier2 = yield w2.get_verifier()
|
||||||
self.assertEqual(verifier1, verifier2)
|
self.assertEqual(verifier1, verifier2)
|
||||||
|
|
||||||
self.successResultOf(w1.when_key())
|
self.successResultOf(w1.get_unverified_key())
|
||||||
self.successResultOf(w2.when_key())
|
self.successResultOf(w2.get_unverified_key())
|
||||||
|
|
||||||
version1 = yield w1.when_version()
|
versions1 = yield w1.get_versions()
|
||||||
version2 = yield w2.when_version()
|
versions2 = yield w2.get_versions()
|
||||||
# app-versions are exercised properly in test_versions, this just
|
# app-versions are exercised properly in test_versions, this just
|
||||||
# tests the defaults
|
# tests the defaults
|
||||||
self.assertEqual(version1, {})
|
self.assertEqual(versions1, {})
|
||||||
self.assertEqual(version2, {})
|
self.assertEqual(versions2, {})
|
||||||
|
|
||||||
w1.send(b"data1")
|
w1.send_message(b"data1")
|
||||||
w2.send(b"data2")
|
w2.send_message(b"data2")
|
||||||
dataX = yield w1.when_received()
|
dataX = yield w1.get_message()
|
||||||
dataY = yield w2.when_received()
|
dataY = yield w2.get_message()
|
||||||
self.assertEqual(dataX, b"data2")
|
self.assertEqual(dataX, b"data2")
|
||||||
self.assertEqual(dataY, b"data1")
|
self.assertEqual(dataY, b"data1")
|
||||||
|
|
||||||
version1_again = yield w1.when_version()
|
versions1_again = yield w1.get_versions()
|
||||||
self.assertEqual(version1, version1_again)
|
self.assertEqual(versions1, versions1_again)
|
||||||
|
|
||||||
c1 = yield w1.close()
|
c1 = yield w1.close()
|
||||||
self.assertEqual(c1, "happy")
|
self.assertEqual(c1, "happy")
|
||||||
|
@ -193,19 +179,19 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
self.assertEqual(c2, "happy")
|
self.assertEqual(c2, "happy")
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def test_when_code_early(self):
|
def test_get_code_early(self):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
d = w1.when_code()
|
d = w1.get_code()
|
||||||
w1.set_code("1-abc")
|
w1.set_code("1-abc")
|
||||||
code = self.successResultOf(d)
|
code = self.successResultOf(d)
|
||||||
self.assertEqual(code, "1-abc")
|
self.assertEqual(code, "1-abc")
|
||||||
yield self.assertFailure(w1.close(), LonelyError)
|
yield self.assertFailure(w1.close(), LonelyError)
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def test_when_code_late(self):
|
def test_get_code_late(self):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.set_code("1-abc")
|
w1.set_code("1-abc")
|
||||||
d = w1.when_code()
|
d = w1.get_code()
|
||||||
code = self.successResultOf(d)
|
code = self.successResultOf(d)
|
||||||
self.assertEqual(code, "1-abc")
|
self.assertEqual(code, "1-abc")
|
||||||
yield self.assertFailure(w1.close(), LonelyError)
|
yield self.assertFailure(w1.close(), LonelyError)
|
||||||
|
@ -218,12 +204,12 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.allocate_code()
|
w1.allocate_code()
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
w2.set_code(code)
|
w2.set_code(code)
|
||||||
w1.send(b"data")
|
w1.send_message(b"data")
|
||||||
w2.send(b"data")
|
w2.send_message(b"data")
|
||||||
dataX = yield w1.when_received()
|
dataX = yield w1.get_message()
|
||||||
dataY = yield w2.when_received()
|
dataY = yield w2.get_message()
|
||||||
self.assertEqual(dataX, b"data")
|
self.assertEqual(dataX, b"data")
|
||||||
self.assertEqual(dataY, b"data")
|
self.assertEqual(dataY, b"data")
|
||||||
yield w1.close()
|
yield w1.close()
|
||||||
|
@ -234,13 +220,13 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.allocate_code()
|
w1.allocate_code()
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
w2.set_code(code)
|
w2.set_code(code)
|
||||||
w1.send(b"data1")
|
w1.send_message(b"data1")
|
||||||
dataY = yield w2.when_received()
|
dataY = yield w2.get_message()
|
||||||
self.assertEqual(dataY, b"data1")
|
self.assertEqual(dataY, b"data1")
|
||||||
d = w1.when_received()
|
d = w1.get_message()
|
||||||
w2.send(b"data2")
|
w2.send_message(b"data2")
|
||||||
dataX = yield d
|
dataX = yield d
|
||||||
self.assertEqual(dataX, b"data2")
|
self.assertEqual(dataX, b"data2")
|
||||||
yield w1.close()
|
yield w1.close()
|
||||||
|
@ -251,10 +237,10 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.allocate_code()
|
w1.allocate_code()
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
w2.set_code(code)
|
w2.set_code(code)
|
||||||
w1.send(b"data1")
|
w1.send_message(b"data1")
|
||||||
dataY = yield w2.when_received()
|
dataY = yield w2.get_message()
|
||||||
self.assertEqual(dataY, b"data1")
|
self.assertEqual(dataY, b"data1")
|
||||||
yield w1.close()
|
yield w1.close()
|
||||||
yield w2.close()
|
yield w2.close()
|
||||||
|
@ -262,9 +248,9 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def test_early(self):
|
def test_early(self):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.send(b"data1")
|
w1.send_message(b"data1")
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
d = w2.when_received()
|
d = w2.get_message()
|
||||||
w1.set_code("123-abc-def")
|
w1.set_code("123-abc-def")
|
||||||
w2.set_code("123-abc-def")
|
w2.set_code("123-abc-def")
|
||||||
dataY = yield d
|
dataY = yield d
|
||||||
|
@ -278,8 +264,8 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.set_code("123-purple-elephant")
|
w1.set_code("123-purple-elephant")
|
||||||
w2.set_code("123-purple-elephant")
|
w2.set_code("123-purple-elephant")
|
||||||
w1.send(b"data1"), w2.send(b"data2")
|
w1.send_message(b"data1"), w2.send_message(b"data2")
|
||||||
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
dl = yield self.doBoth(w1.get_message(), w2.get_message())
|
||||||
(dataX, dataY) = dl
|
(dataX, dataY) = dl
|
||||||
self.assertEqual(dataX, b"data2")
|
self.assertEqual(dataX, b"data2")
|
||||||
self.assertEqual(dataY, b"data1")
|
self.assertEqual(dataY, b"data1")
|
||||||
|
@ -300,8 +286,8 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
yield poll_until(lambda: w2._boss._K._debug_pake_stashed)
|
yield poll_until(lambda: w2._boss._K._debug_pake_stashed)
|
||||||
h.choose_words("purple-elephant")
|
h.choose_words("purple-elephant")
|
||||||
|
|
||||||
w1.send(b"data1"), w2.send(b"data2")
|
w1.send_message(b"data1"), w2.send_message(b"data2")
|
||||||
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
dl = yield self.doBoth(w1.get_message(), w2.get_message())
|
||||||
(dataX, dataY) = dl
|
(dataX, dataY) = dl
|
||||||
self.assertEqual(dataX, b"data2")
|
self.assertEqual(dataX, b"data2")
|
||||||
self.assertEqual(dataY, b"data1")
|
self.assertEqual(dataY, b"data1")
|
||||||
|
@ -315,13 +301,13 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.set_code("123-purple-elephant")
|
w1.set_code("123-purple-elephant")
|
||||||
w2.set_code("123-purple-elephant")
|
w2.set_code("123-purple-elephant")
|
||||||
w1.send(b"data1"), w2.send(b"data2")
|
w1.send_message(b"data1"), w2.send_message(b"data2")
|
||||||
w1.send(b"data3"), w2.send(b"data4")
|
w1.send_message(b"data3"), w2.send_message(b"data4")
|
||||||
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
dl = yield self.doBoth(w1.get_message(), w2.get_message())
|
||||||
(dataX, dataY) = dl
|
(dataX, dataY) = dl
|
||||||
self.assertEqual(dataX, b"data2")
|
self.assertEqual(dataX, b"data2")
|
||||||
self.assertEqual(dataY, b"data1")
|
self.assertEqual(dataY, b"data1")
|
||||||
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
dl = yield self.doBoth(w1.get_message(), w2.get_message())
|
||||||
(dataX, dataY) = dl
|
(dataX, dataY) = dl
|
||||||
self.assertEqual(dataX, b"data4")
|
self.assertEqual(dataX, b"data4")
|
||||||
self.assertEqual(dataY, b"data3")
|
self.assertEqual(dataY, b"data3")
|
||||||
|
@ -337,19 +323,19 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w2.set_code("123-foo")
|
w2.set_code("123-foo")
|
||||||
|
|
||||||
# let it connect and become HAPPY
|
# let it connect and become HAPPY
|
||||||
yield w1.when_version()
|
yield w1.get_versions()
|
||||||
yield w2.when_version()
|
yield w2.get_versions()
|
||||||
|
|
||||||
yield w1.close()
|
yield w1.close()
|
||||||
yield w2.close()
|
yield w2.close()
|
||||||
|
|
||||||
# once closed, all Deferred-yielding API calls get an immediate error
|
# once closed, all Deferred-yielding API calls get an immediate error
|
||||||
f = self.failureResultOf(w1.when_code(), WormholeClosed)
|
f = self.failureResultOf(w1.get_code(), WormholeClosed)
|
||||||
self.assertEqual(f.value.args[0], "happy")
|
self.assertEqual(f.value.args[0], "happy")
|
||||||
self.failureResultOf(w1.when_key(), WormholeClosed)
|
self.failureResultOf(w1.get_unverified_key(), WormholeClosed)
|
||||||
self.failureResultOf(w1.when_verified(), WormholeClosed)
|
self.failureResultOf(w1.get_verifier(), WormholeClosed)
|
||||||
self.failureResultOf(w1.when_version(), WormholeClosed)
|
self.failureResultOf(w1.get_versions(), WormholeClosed)
|
||||||
self.failureResultOf(w1.when_received(), WormholeClosed)
|
self.failureResultOf(w1.get_message(), WormholeClosed)
|
||||||
|
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
|
@ -357,20 +343,20 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.allocate_code()
|
w1.allocate_code()
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
w2.set_code(code+"not")
|
w2.set_code(code+"not")
|
||||||
code2 = yield w2.when_code()
|
code2 = yield w2.get_code()
|
||||||
self.assertNotEqual(code, code2)
|
self.assertNotEqual(code, code2)
|
||||||
# That's enough to allow both sides to discover the mismatch, but
|
# That's enough to allow both sides to discover the mismatch, but
|
||||||
# only after the confirmation message gets through. API calls that
|
# only after the confirmation message gets through. API calls that
|
||||||
# don't wait will appear to work until the mismatched confirmation
|
# don't wait will appear to work until the mismatched confirmation
|
||||||
# message arrives.
|
# message arrives.
|
||||||
w1.send(b"should still work")
|
w1.send_message(b"should still work")
|
||||||
w2.send(b"should still work")
|
w2.send_message(b"should still work")
|
||||||
|
|
||||||
key2 = yield w2.when_key() # should work
|
key2 = yield w2.get_unverified_key() # should work
|
||||||
# w2 has just received w1.PAKE, and is about to send w2.VERSION
|
# w2 has just received w1.PAKE, and is about to send w2.VERSION
|
||||||
key1 = yield w1.when_key() # should work
|
key1 = yield w1.get_unverified_key() # should work
|
||||||
# w1 has just received w2.PAKE, and is about to send w1.VERSION, and
|
# w1 has just received w2.PAKE, and is about to send w1.VERSION, and
|
||||||
# then will receive w2.VERSION. When it sees w2.VERSION, it will
|
# then will receive w2.VERSION. When it sees w2.VERSION, it will
|
||||||
# learn about the WrongPasswordError.
|
# learn about the WrongPasswordError.
|
||||||
|
@ -378,54 +364,54 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
|
|
||||||
# API calls that wait (i.e. get) will errback. We collect all these
|
# API calls that wait (i.e. get) will errback. We collect all these
|
||||||
# Deferreds early to exercise the wait-then-fail path
|
# Deferreds early to exercise the wait-then-fail path
|
||||||
d1_verified = w1.when_verified()
|
d1_verified = w1.get_verifier()
|
||||||
d1_version = w1.when_version()
|
d1_versions = w1.get_versions()
|
||||||
d1_received = w1.when_received()
|
d1_received = w1.get_message()
|
||||||
d2_verified = w2.when_verified()
|
d2_verified = w2.get_verifier()
|
||||||
d2_version = w2.when_version()
|
d2_versions = w2.get_versions()
|
||||||
d2_received = w2.when_received()
|
d2_received = w2.get_message()
|
||||||
|
|
||||||
# wait for each side to notice the failure
|
# wait for each side to notice the failure
|
||||||
yield self.assertFailure(w1.when_verified(), WrongPasswordError)
|
yield self.assertFailure(w1.get_verifier(), WrongPasswordError)
|
||||||
yield self.assertFailure(w2.when_verified(), WrongPasswordError)
|
yield self.assertFailure(w2.get_verifier(), WrongPasswordError)
|
||||||
# and then wait for the rest of the loops to fire. if we had+used
|
# and then wait for the rest of the loops to fire. if we had+used
|
||||||
# eventual-send, this wouldn't be a problem
|
# eventual-send, this wouldn't be a problem
|
||||||
yield pause_one_tick()
|
yield pause_one_tick()
|
||||||
|
|
||||||
# now all the rest should have fired already
|
# now all the rest should have fired already
|
||||||
self.failureResultOf(d1_verified, WrongPasswordError)
|
self.failureResultOf(d1_verified, WrongPasswordError)
|
||||||
self.failureResultOf(d1_version, WrongPasswordError)
|
self.failureResultOf(d1_versions, WrongPasswordError)
|
||||||
self.failureResultOf(d1_received, WrongPasswordError)
|
self.failureResultOf(d1_received, WrongPasswordError)
|
||||||
self.failureResultOf(d2_verified, WrongPasswordError)
|
self.failureResultOf(d2_verified, WrongPasswordError)
|
||||||
self.failureResultOf(d2_version, WrongPasswordError)
|
self.failureResultOf(d2_versions, WrongPasswordError)
|
||||||
self.failureResultOf(d2_received, WrongPasswordError)
|
self.failureResultOf(d2_received, WrongPasswordError)
|
||||||
|
|
||||||
# and at this point, with the failure safely noticed by both sides,
|
# and at this point, with the failure safely noticed by both sides,
|
||||||
# new when_key() calls should signal the failure, even before we
|
# new get_unverified_key() calls should signal the failure, even
|
||||||
# close
|
# before we close
|
||||||
|
|
||||||
# any new calls in the error state should immediately fail
|
# any new calls in the error state should immediately fail
|
||||||
self.failureResultOf(w1.when_key(), WrongPasswordError)
|
self.failureResultOf(w1.get_unverified_key(), WrongPasswordError)
|
||||||
self.failureResultOf(w1.when_verified(), WrongPasswordError)
|
self.failureResultOf(w1.get_verifier(), WrongPasswordError)
|
||||||
self.failureResultOf(w1.when_version(), WrongPasswordError)
|
self.failureResultOf(w1.get_versions(), WrongPasswordError)
|
||||||
self.failureResultOf(w1.when_received(), WrongPasswordError)
|
self.failureResultOf(w1.get_message(), WrongPasswordError)
|
||||||
self.failureResultOf(w2.when_key(), WrongPasswordError)
|
self.failureResultOf(w2.get_unverified_key(), WrongPasswordError)
|
||||||
self.failureResultOf(w2.when_verified(), WrongPasswordError)
|
self.failureResultOf(w2.get_verifier(), WrongPasswordError)
|
||||||
self.failureResultOf(w2.when_version(), WrongPasswordError)
|
self.failureResultOf(w2.get_versions(), WrongPasswordError)
|
||||||
self.failureResultOf(w2.when_received(), WrongPasswordError)
|
self.failureResultOf(w2.get_message(), WrongPasswordError)
|
||||||
|
|
||||||
yield self.assertFailure(w1.close(), WrongPasswordError)
|
yield self.assertFailure(w1.close(), WrongPasswordError)
|
||||||
yield self.assertFailure(w2.close(), WrongPasswordError)
|
yield self.assertFailure(w2.close(), WrongPasswordError)
|
||||||
|
|
||||||
# API calls should still get the error, not WormholeClosed
|
# API calls should still get the error, not WormholeClosed
|
||||||
self.failureResultOf(w1.when_key(), WrongPasswordError)
|
self.failureResultOf(w1.get_unverified_key(), WrongPasswordError)
|
||||||
self.failureResultOf(w1.when_verified(), WrongPasswordError)
|
self.failureResultOf(w1.get_verifier(), WrongPasswordError)
|
||||||
self.failureResultOf(w1.when_version(), WrongPasswordError)
|
self.failureResultOf(w1.get_versions(), WrongPasswordError)
|
||||||
self.failureResultOf(w1.when_received(), WrongPasswordError)
|
self.failureResultOf(w1.get_message(), WrongPasswordError)
|
||||||
self.failureResultOf(w2.when_key(), WrongPasswordError)
|
self.failureResultOf(w2.get_unverified_key(), WrongPasswordError)
|
||||||
self.failureResultOf(w2.when_verified(), WrongPasswordError)
|
self.failureResultOf(w2.get_verifier(), WrongPasswordError)
|
||||||
self.failureResultOf(w2.when_version(), WrongPasswordError)
|
self.failureResultOf(w2.get_versions(), WrongPasswordError)
|
||||||
self.failureResultOf(w2.when_received(), WrongPasswordError)
|
self.failureResultOf(w2.get_message(), WrongPasswordError)
|
||||||
|
|
||||||
@inlineCallbacks
|
@inlineCallbacks
|
||||||
def test_wrong_password_with_spaces(self):
|
def test_wrong_password_with_spaces(self):
|
||||||
|
@ -442,21 +428,21 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
w1 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.allocate_code()
|
w1.allocate_code()
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
w2.set_code(code)
|
w2.set_code(code)
|
||||||
v1 = yield w1.when_verified() # early
|
v1 = yield w1.get_verifier() # early
|
||||||
v2 = yield w2.when_verified()
|
v2 = yield w2.get_verifier()
|
||||||
self.failUnlessEqual(type(v1), type(b""))
|
self.failUnlessEqual(type(v1), type(b""))
|
||||||
self.failUnlessEqual(v1, v2)
|
self.failUnlessEqual(v1, v2)
|
||||||
w1.send(b"data1")
|
w1.send_message(b"data1")
|
||||||
w2.send(b"data2")
|
w2.send_message(b"data2")
|
||||||
dataX = yield w1.when_received()
|
dataX = yield w1.get_message()
|
||||||
dataY = yield w2.when_received()
|
dataY = yield w2.get_message()
|
||||||
self.assertEqual(dataX, b"data2")
|
self.assertEqual(dataX, b"data2")
|
||||||
self.assertEqual(dataY, b"data1")
|
self.assertEqual(dataY, b"data1")
|
||||||
|
|
||||||
# calling when_verified() this late should fire right away
|
# calling get_verifier() this late should fire right away
|
||||||
v1_late = self.successResultOf(w2.when_verified())
|
v1_late = self.successResultOf(w2.get_verifier())
|
||||||
self.assertEqual(v1_late, v1)
|
self.assertEqual(v1_late, v1)
|
||||||
|
|
||||||
yield w1.close()
|
yield w1.close()
|
||||||
|
@ -470,11 +456,11 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor,
|
w2 = wormhole.create(APPID, self.relayurl, reactor,
|
||||||
versions={"w2": 456})
|
versions={"w2": 456})
|
||||||
w1.allocate_code()
|
w1.allocate_code()
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
w2.set_code(code)
|
w2.set_code(code)
|
||||||
w1_versions = yield w2.when_version()
|
w1_versions = yield w2.get_versions()
|
||||||
self.assertEqual(w1_versions, {"w1": 123})
|
self.assertEqual(w1_versions, {"w1": 123})
|
||||||
w2_versions = yield w1.when_version()
|
w2_versions = yield w1.get_versions()
|
||||||
self.assertEqual(w2_versions, {"w2": 456})
|
self.assertEqual(w2_versions, {"w2": 456})
|
||||||
yield w1.close()
|
yield w1.close()
|
||||||
yield w2.close()
|
yield w2.close()
|
||||||
|
@ -496,8 +482,8 @@ class Wormholes(ServerBase, unittest.TestCase):
|
||||||
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
w2 = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w1.set_code("123-purple-elephant")
|
w1.set_code("123-purple-elephant")
|
||||||
w2.set_code("123-purple-elephant")
|
w2.set_code("123-purple-elephant")
|
||||||
w1.send(b"data1"), w2.send(b"data2")
|
w1.send_message(b"data1"), w2.send_message(b"data2")
|
||||||
dl = yield self.doBoth(w1.when_received(), w2.when_received())
|
dl = yield self.doBoth(w1.get_message(), w2.get_message())
|
||||||
(dataX, dataY) = dl
|
(dataX, dataY) = dl
|
||||||
self.assertEqual(dataX, b"data2")
|
self.assertEqual(dataX, b"data2")
|
||||||
self.assertEqual(dataY, b"data1")
|
self.assertEqual(dataY, b"data1")
|
||||||
|
@ -537,7 +523,7 @@ class Errors(ServerBase, unittest.TestCase):
|
||||||
def test_allocate_and_set_code(self):
|
def test_allocate_and_set_code(self):
|
||||||
w = wormhole.create(APPID, self.relayurl, reactor)
|
w = wormhole.create(APPID, self.relayurl, reactor)
|
||||||
w.allocate_code()
|
w.allocate_code()
|
||||||
yield w.when_code()
|
yield w.get_code()
|
||||||
with self.assertRaises(OnlyOneCodeError):
|
with self.assertRaises(OnlyOneCodeError):
|
||||||
w.set_code("123-nope")
|
w.set_code("123-nope")
|
||||||
yield self.assertFailure(w.close(), LonelyError)
|
yield self.assertFailure(w.close(), LonelyError)
|
||||||
|
@ -550,8 +536,8 @@ class Reconnection(ServerBase, unittest.TestCase):
|
||||||
w1._boss._RC._debug_record_inbound_f = w1_in.append
|
w1._boss._RC._debug_record_inbound_f = w1_in.append
|
||||||
#w1.debug_set_trace("W1")
|
#w1.debug_set_trace("W1")
|
||||||
w1.allocate_code()
|
w1.allocate_code()
|
||||||
code = yield w1.when_code()
|
code = yield w1.get_code()
|
||||||
w1.send(b"data1") # will be queued until wormhole is established
|
w1.send_message(b"data1") # queued until wormhole is established
|
||||||
|
|
||||||
# now wait until we've deposited all our messages on the server
|
# now wait until we've deposited all our messages on the server
|
||||||
def seen_our_pake():
|
def seen_our_pake():
|
||||||
|
@ -577,11 +563,11 @@ class Reconnection(ServerBase, unittest.TestCase):
|
||||||
#w2.debug_set_trace(" W2")
|
#w2.debug_set_trace(" W2")
|
||||||
w2.set_code(code)
|
w2.set_code(code)
|
||||||
|
|
||||||
dataY = yield w2.when_received()
|
dataY = yield w2.get_message()
|
||||||
self.assertEqual(dataY, b"data1")
|
self.assertEqual(dataY, b"data1")
|
||||||
|
|
||||||
w2.send(b"data2")
|
w2.send_message(b"data2")
|
||||||
dataX = yield w1.when_received()
|
dataX = yield w1.get_message()
|
||||||
self.assertEqual(dataX, b"data2")
|
self.assertEqual(dataX, b"data2")
|
||||||
|
|
||||||
c1 = yield w1.close()
|
c1 = yield w1.close()
|
||||||
|
|
|
@ -15,18 +15,18 @@ from .util import to_bytes
|
||||||
|
|
||||||
# We can provide different APIs to different apps:
|
# We can provide different APIs to different apps:
|
||||||
# * Deferreds
|
# * Deferreds
|
||||||
# w.when_code().addCallback(print_code)
|
# w.get_code().addCallback(print_code)
|
||||||
# w.send(data)
|
# w.send_message(data)
|
||||||
# w.when_received().addCallback(got_data)
|
# w.get_message().addCallback(got_data)
|
||||||
# w.close().addCallback(closed)
|
# w.close().addCallback(closed)
|
||||||
|
|
||||||
# * delegate callbacks (better for journaled environments)
|
# * delegate callbacks (better for journaled environments)
|
||||||
# w = wormhole(delegate=app)
|
# w = wormhole(delegate=app)
|
||||||
# w.send(data)
|
# w.send_message(data)
|
||||||
# app.wormhole_got_code(code)
|
# app.wormhole_got_code(code)
|
||||||
# app.wormhole_got_verifier(verifier)
|
# app.wormhole_got_verifier(verifier)
|
||||||
# app.wormhole_got_version(versions)
|
# app.wormhole_got_versions(versions)
|
||||||
# app.wormhole_receive(data)
|
# app.wormhole_got_message(data)
|
||||||
# w.close()
|
# w.close()
|
||||||
# app.wormhole_closed()
|
# app.wormhole_closed()
|
||||||
#
|
#
|
||||||
|
@ -34,18 +34,6 @@ from .util import to_bytes
|
||||||
# wormhole(delegate=app, delegate_prefix="wormhole_",
|
# wormhole(delegate=app, delegate_prefix="wormhole_",
|
||||||
# delegate_args=(args, kwargs))
|
# delegate_args=(args, kwargs))
|
||||||
|
|
||||||
class _WelcomeHandler:
|
|
||||||
def __init__(self, url, stderr=sys.stderr):
|
|
||||||
self.relay_url = url
|
|
||||||
self.stderr = stderr
|
|
||||||
|
|
||||||
def handle_welcome(self, welcome):
|
|
||||||
if "motd" in welcome:
|
|
||||||
motd_lines = welcome["motd"].splitlines()
|
|
||||||
motd_formatted = "\n ".join(motd_lines)
|
|
||||||
print("Server (at %s) says:\n %s" %
|
|
||||||
(self.relay_url, motd_formatted), file=self.stderr)
|
|
||||||
|
|
||||||
@attrs
|
@attrs
|
||||||
@implementer(IWormhole)
|
@implementer(IWormhole)
|
||||||
class _DelegatedWormhole(object):
|
class _DelegatedWormhole(object):
|
||||||
|
@ -72,7 +60,7 @@ class _DelegatedWormhole(object):
|
||||||
## }
|
## }
|
||||||
## return s
|
## return s
|
||||||
|
|
||||||
def send(self, plaintext):
|
def send_message(self, plaintext):
|
||||||
self._boss.send(plaintext)
|
self._boss.send(plaintext)
|
||||||
|
|
||||||
def derive_key(self, purpose, length):
|
def derive_key(self, purpose, length):
|
||||||
|
@ -94,23 +82,27 @@ class _DelegatedWormhole(object):
|
||||||
self._boss._set_trace(client_name, which, file)
|
self._boss._set_trace(client_name, which, file)
|
||||||
|
|
||||||
# from below
|
# from below
|
||||||
|
def got_welcome(self, welcome):
|
||||||
|
self._delegate.wormhole_got_welcome(welcome)
|
||||||
def got_code(self, code):
|
def got_code(self, code):
|
||||||
self._delegate.wormhole_code(code)
|
self._delegate.wormhole_got_code(code)
|
||||||
def got_key(self, key):
|
def got_key(self, key):
|
||||||
self._delegate.wormhole_key(key)
|
self._delegate.wormhole_got_unverified_key(key)
|
||||||
self._key = key # for derive_key()
|
self._key = key # for derive_key()
|
||||||
def got_verifier(self, verifier):
|
def got_verifier(self, verifier):
|
||||||
self._delegate.wormhole_verified(verifier)
|
self._delegate.wormhole_got_verifier(verifier)
|
||||||
def got_version(self, versions):
|
def got_versions(self, versions):
|
||||||
self._delegate.wormhole_version(versions)
|
self._delegate.wormhole_got_versions(versions)
|
||||||
def received(self, plaintext):
|
def received(self, plaintext):
|
||||||
self._delegate.wormhole_received(plaintext)
|
self._delegate.wormhole_got_message(plaintext)
|
||||||
def closed(self, result):
|
def closed(self, result):
|
||||||
self._delegate.wormhole_closed(result)
|
self._delegate.wormhole_closed(result)
|
||||||
|
|
||||||
@implementer(IWormhole)
|
@implementer(IWormhole)
|
||||||
class _DeferredWormhole(object):
|
class _DeferredWormhole(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self._welcome = None
|
||||||
|
self._welcome_observers = []
|
||||||
self._code = None
|
self._code = None
|
||||||
self._code_observers = []
|
self._code_observers = []
|
||||||
self._key = None
|
self._key = None
|
||||||
|
@ -129,7 +121,7 @@ class _DeferredWormhole(object):
|
||||||
self._boss = boss
|
self._boss = boss
|
||||||
|
|
||||||
# from above
|
# from above
|
||||||
def when_code(self):
|
def get_code(self):
|
||||||
# TODO: consider throwing error unless one of allocate/set/input_code
|
# TODO: consider throwing error unless one of allocate/set/input_code
|
||||||
# was called first. It's legit to grab the Deferred before triggering
|
# was called first. It's legit to grab the Deferred before triggering
|
||||||
# the process that will cause it to fire, but forbidding that
|
# the process that will cause it to fire, but forbidding that
|
||||||
|
@ -143,7 +135,16 @@ class _DeferredWormhole(object):
|
||||||
self._code_observers.append(d)
|
self._code_observers.append(d)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def when_key(self):
|
def get_welcome(self):
|
||||||
|
if self._observer_result is not None:
|
||||||
|
return defer.fail(self._observer_result)
|
||||||
|
if self._welcome is not None:
|
||||||
|
return defer.succeed(self._welcome)
|
||||||
|
d = defer.Deferred()
|
||||||
|
self._welcome_observers.append(d)
|
||||||
|
return d
|
||||||
|
|
||||||
|
def get_unverified_key(self):
|
||||||
if self._observer_result is not None:
|
if self._observer_result is not None:
|
||||||
return defer.fail(self._observer_result)
|
return defer.fail(self._observer_result)
|
||||||
if self._key is not None:
|
if self._key is not None:
|
||||||
|
@ -152,7 +153,7 @@ class _DeferredWormhole(object):
|
||||||
self._key_observers.append(d)
|
self._key_observers.append(d)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def when_verified(self):
|
def get_verifier(self):
|
||||||
if self._observer_result is not None:
|
if self._observer_result is not None:
|
||||||
return defer.fail(self._observer_result)
|
return defer.fail(self._observer_result)
|
||||||
if self._verifier is not None:
|
if self._verifier is not None:
|
||||||
|
@ -161,7 +162,7 @@ class _DeferredWormhole(object):
|
||||||
self._verifier_observers.append(d)
|
self._verifier_observers.append(d)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def when_version(self):
|
def get_versions(self):
|
||||||
if self._observer_result is not None:
|
if self._observer_result is not None:
|
||||||
return defer.fail(self._observer_result)
|
return defer.fail(self._observer_result)
|
||||||
if self._versions is not None:
|
if self._versions is not None:
|
||||||
|
@ -170,7 +171,7 @@ class _DeferredWormhole(object):
|
||||||
self._version_observers.append(d)
|
self._version_observers.append(d)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def when_received(self):
|
def get_message(self):
|
||||||
if self._observer_result is not None:
|
if self._observer_result is not None:
|
||||||
return defer.fail(self._observer_result)
|
return defer.fail(self._observer_result)
|
||||||
if self._received_data:
|
if self._received_data:
|
||||||
|
@ -187,7 +188,8 @@ class _DeferredWormhole(object):
|
||||||
self._boss.set_code(code)
|
self._boss.set_code(code)
|
||||||
|
|
||||||
# no .serialize in Deferred-mode
|
# no .serialize in Deferred-mode
|
||||||
def send(self, plaintext):
|
|
||||||
|
def send_message(self, plaintext):
|
||||||
self._boss.send(plaintext)
|
self._boss.send(plaintext)
|
||||||
|
|
||||||
def derive_key(self, purpose, length):
|
def derive_key(self, purpose, length):
|
||||||
|
@ -217,6 +219,11 @@ class _DeferredWormhole(object):
|
||||||
self._boss._set_trace(client_name, which, file)
|
self._boss._set_trace(client_name, which, file)
|
||||||
|
|
||||||
# from below
|
# from below
|
||||||
|
def got_welcome(self, welcome):
|
||||||
|
self._welcome = welcome
|
||||||
|
for d in self._welcome_observers:
|
||||||
|
d.callback(welcome)
|
||||||
|
self._welcome_observers[:] = []
|
||||||
def got_code(self, code):
|
def got_code(self, code):
|
||||||
self._code = code
|
self._code = code
|
||||||
for d in self._code_observers:
|
for d in self._code_observers:
|
||||||
|
@ -227,12 +234,13 @@ class _DeferredWormhole(object):
|
||||||
for d in self._key_observers:
|
for d in self._key_observers:
|
||||||
d.callback(key)
|
d.callback(key)
|
||||||
self._key_observers[:] = []
|
self._key_observers[:] = []
|
||||||
|
|
||||||
def got_verifier(self, verifier):
|
def got_verifier(self, verifier):
|
||||||
self._verifier = verifier
|
self._verifier = verifier
|
||||||
for d in self._verifier_observers:
|
for d in self._verifier_observers:
|
||||||
d.callback(verifier)
|
d.callback(verifier)
|
||||||
self._verifier_observers[:] = []
|
self._verifier_observers[:] = []
|
||||||
def got_version(self, versions):
|
def got_versions(self, versions):
|
||||||
self._versions = versions
|
self._versions = versions
|
||||||
for d in self._version_observers:
|
for d in self._version_observers:
|
||||||
d.callback(versions)
|
d.callback(versions)
|
||||||
|
@ -245,7 +253,7 @@ class _DeferredWormhole(object):
|
||||||
self._received_data.append(plaintext)
|
self._received_data.append(plaintext)
|
||||||
|
|
||||||
def closed(self, result):
|
def closed(self, result):
|
||||||
#print("closed", result, type(result))
|
#print("closed", result, type(result), file=sys.stderr)
|
||||||
if isinstance(result, Exception):
|
if isinstance(result, Exception):
|
||||||
self._observer_result = self._closed_result = failure.Failure(result)
|
self._observer_result = self._closed_result = failure.Failure(result)
|
||||||
else:
|
else:
|
||||||
|
@ -253,6 +261,8 @@ class _DeferredWormhole(object):
|
||||||
self._observer_result = WormholeClosed(result)
|
self._observer_result = WormholeClosed(result)
|
||||||
# but w.close() only gets error if we're unhappy
|
# but w.close() only gets error if we're unhappy
|
||||||
self._closed_result = result
|
self._closed_result = result
|
||||||
|
for d in self._welcome_observers:
|
||||||
|
d.errback(self._observer_result)
|
||||||
for d in self._code_observers:
|
for d in self._code_observers:
|
||||||
d.errback(self._observer_result)
|
d.errback(self._observer_result)
|
||||||
for d in self._key_observers:
|
for d in self._key_observers:
|
||||||
|
@ -270,13 +280,11 @@ class _DeferredWormhole(object):
|
||||||
def create(appid, relay_url, reactor, # use keyword args for everything else
|
def create(appid, relay_url, reactor, # use keyword args for everything else
|
||||||
versions={},
|
versions={},
|
||||||
delegate=None, journal=None, tor_manager=None,
|
delegate=None, journal=None, tor_manager=None,
|
||||||
timing=None, welcome_handler=None,
|
timing=None,
|
||||||
stderr=sys.stderr):
|
stderr=sys.stderr):
|
||||||
timing = timing or DebugTiming()
|
timing = timing or DebugTiming()
|
||||||
side = bytes_to_hexstr(os.urandom(5))
|
side = bytes_to_hexstr(os.urandom(5))
|
||||||
journal = journal or ImmediateJournal()
|
journal = journal or ImmediateJournal()
|
||||||
if not welcome_handler:
|
|
||||||
welcome_handler = _WelcomeHandler(relay_url).handle_welcome
|
|
||||||
if delegate:
|
if delegate:
|
||||||
w = _DelegatedWormhole(delegate)
|
w = _DelegatedWormhole(delegate)
|
||||||
else:
|
else:
|
||||||
|
@ -284,8 +292,7 @@ def create(appid, relay_url, reactor, # use keyword args for everything else
|
||||||
wormhole_versions = {} # will be used to indicate Wormhole capabilities
|
wormhole_versions = {} # will be used to indicate Wormhole capabilities
|
||||||
wormhole_versions["app_versions"] = versions # app-specific capabilities
|
wormhole_versions["app_versions"] = versions # app-specific capabilities
|
||||||
b = Boss(w, side, relay_url, appid, wormhole_versions,
|
b = Boss(w, side, relay_url, appid, wormhole_versions,
|
||||||
welcome_handler, reactor, journal,
|
reactor, journal, tor_manager, timing)
|
||||||
tor_manager, timing)
|
|
||||||
w._set_boss(b)
|
w._set_boss(b)
|
||||||
b.start()
|
b.start()
|
||||||
return w
|
return w
|
||||||
|
|
|
@ -41,14 +41,14 @@ def receive(reactor, appid, relay_url, code,
|
||||||
wh = wormhole.create(appid, relay_url, reactor, tor_manager=tm)
|
wh = wormhole.create(appid, relay_url, reactor, tor_manager=tm)
|
||||||
if code is None:
|
if code is None:
|
||||||
wh.allocate_code()
|
wh.allocate_code()
|
||||||
code = yield wh.when_code()
|
code = yield wh.get_code()
|
||||||
else:
|
else:
|
||||||
wh.set_code(code)
|
wh.set_code(code)
|
||||||
# we'll call this no matter what, even if you passed in a code --
|
# we'll call this no matter what, even if you passed in a code --
|
||||||
# maybe it should be only in the 'if' block above?
|
# maybe it should be only in the 'if' block above?
|
||||||
if on_code:
|
if on_code:
|
||||||
on_code(code)
|
on_code(code)
|
||||||
data = yield wh.when_received()
|
data = yield wh.get_message()
|
||||||
data = json.loads(data.decode("utf-8"))
|
data = json.loads(data.decode("utf-8"))
|
||||||
offer = data.get('offer', None)
|
offer = data.get('offer', None)
|
||||||
if not offer:
|
if not offer:
|
||||||
|
@ -58,7 +58,8 @@ def receive(reactor, appid, relay_url, code,
|
||||||
msg = None
|
msg = None
|
||||||
if 'message' in offer:
|
if 'message' in offer:
|
||||||
msg = offer['message']
|
msg = offer['message']
|
||||||
wh.send(json.dumps({"answer": {"message_ack": "ok"}}).encode("utf-8"))
|
wh.send_message(json.dumps({"answer":
|
||||||
|
{"message_ack": "ok"}}).encode("utf-8"))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
|
@ -104,20 +105,20 @@ def send(reactor, appid, relay_url, data, code,
|
||||||
wh = wormhole.create(appid, relay_url, reactor, tor_manager=tm)
|
wh = wormhole.create(appid, relay_url, reactor, tor_manager=tm)
|
||||||
if code is None:
|
if code is None:
|
||||||
wh.allocate_code()
|
wh.allocate_code()
|
||||||
code = yield wh.when_code()
|
code = yield wh.get_code()
|
||||||
else:
|
else:
|
||||||
wh.set_code(code)
|
wh.set_code(code)
|
||||||
if on_code:
|
if on_code:
|
||||||
on_code(code)
|
on_code(code)
|
||||||
|
|
||||||
wh.send(
|
wh.send_message(
|
||||||
json.dumps({
|
json.dumps({
|
||||||
"offer": {
|
"offer": {
|
||||||
"message": data
|
"message": data
|
||||||
}
|
}
|
||||||
}).encode("utf-8")
|
}).encode("utf-8")
|
||||||
)
|
)
|
||||||
data = yield wh.when_received()
|
data = yield wh.get_message()
|
||||||
data = json.loads(data.decode("utf-8"))
|
data = json.loads(data.decode("utf-8"))
|
||||||
answer = data.get('answer', None)
|
answer = data.get('answer', None)
|
||||||
yield wh.close()
|
yield wh.close()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user