change API (wormhole.create), start on serialization

This commit is contained in:
Brian Warner 2017-03-03 23:19:48 +01:00
parent b7b8df17be
commit c499fce9f5
4 changed files with 56 additions and 39 deletions

View File

@ -80,6 +80,9 @@ class Boss(object):
old_state, input, new_state))
names[machine].set_trace(tracer)
def serialize(self):
raise NotImplemented
# and these are the state-machine transition functions, which don't take
# args
@m.state(initial=True)

View File

@ -5,7 +5,7 @@ from humanize import naturalsize
from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.python import log
from ..wormhole import wormhole
from .. import wormhole
from ..transit import TransitReceiver
from ..errors import TransferError, WormholeClosedError, NoTorError
from ..util import (dict_to_bytes, bytes_to_dict, bytes_to_hexstr,
@ -61,8 +61,10 @@ class TwistedReceiver:
# with the user handing off the wormhole code
yield self._tor_manager.start()
w = wormhole(self.args.appid or APPID, self.args.relay_url,
self._reactor, self._tor_manager, timing=self.args.timing)
w = wormhole.create(self.args.appid or APPID, self.args.relay_url,
self._reactor,
tor_manager=self._tor_manager,
timing=self.args.timing)
# I wanted to do this instead:
#
# try:
@ -80,13 +82,12 @@ class TwistedReceiver:
@inlineCallbacks
def _go(self, w):
yield self._handle_code(w)
yield w.establish_key()
def on_slow_connection():
print(u"Key established, waiting for confirmation...",
file=self.args.stderr)
notify = self._reactor.callLater(VERIFY_TIMER, on_slow_connection)
try:
verifier = yield w.verify()
verifier = yield w.when_verifier()
finally:
if not notify.called:
notify.cancel()
@ -127,7 +128,7 @@ class TwistedReceiver:
@inlineCallbacks
def _get_data(self, w):
# this may raise WrongPasswordError
them_bytes = yield w.get()
them_bytes = yield w.when_received()
them_d = bytes_to_dict(them_bytes)
if "error" in them_d:
raise TransferError(them_d["error"])
@ -142,7 +143,7 @@ class TwistedReceiver:
if code:
w.set_code(code)
else:
yield w.input_code("Enter receive wormhole code: ",
yield w.input_code("Enter receive wormhole code: ", # TODO
self.args.code_length)
def _show_verifier(self, verifier):

View File

@ -7,7 +7,7 @@ from twisted.protocols import basic
from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks, returnValue
from ..errors import TransferError, WormholeClosedError, NoTorError
from ..wormhole import wormhole
from .. import wormhole
from ..transit import TransitSender
from ..util import dict_to_bytes, bytes_to_dict, bytes_to_hexstr
@ -52,9 +52,10 @@ class Sender:
# with the user handing off the wormhole code
yield self._tor_manager.start()
w = wormhole(self._args.appid or APPID, self._args.relay_url,
self._reactor, self._tor_manager,
timing=self._timing)
w = wormhole.create(self._args.appid or APPID, self._args.relay_url,
self._reactor,
tor_manager=self._tor_manager,
timing=self._timing)
d = self._go(w)
d.addBoth(w.close) # must wait for ack from close()
yield d
@ -83,25 +84,25 @@ class Sender:
if args.code:
w.set_code(args.code)
code = args.code
else:
code = yield w.get_code(args.code_length)
w.allocate_code(args.code_length)
code = yield w.when_code()
if not args.zeromode:
print(u"Wormhole code is: %s" % code, file=args.stderr)
# flush stderr so the code is displayed immediately
args.stderr.flush()
print(u"", file=args.stderr)
yield w.establish_key()
def on_slow_connection():
print(u"Key established, waiting for confirmation...",
file=args.stderr)
notify = self._reactor.callLater(VERIFY_TIMER, on_slow_connection)
# TODO: don't stall on w.verify() unless they want it
# TODO: maybe don't stall on verifier unless they want it
try:
verifier_bytes = yield w.verify() # this may raise WrongPasswordError
# this may raise WrongPasswordError
verifier_bytes = yield w.when_verifier()
finally:
if not notify.called:
notify.cancel()
@ -146,12 +147,13 @@ class Sender:
while True:
try:
them_d_bytes = yield w.get()
them_d_bytes = yield w.when_received()
except WormholeClosedError:
if done:
returnValue(None)
raise TransferError("unexpected close")
# TODO: get() fired, so now it's safe to use w.derive_key()
# TODO: when_received() fired, so now it's safe to use
# w.derive_key()
them_d = bytes_to_dict(them_d_bytes)
#print("GOT", them_d)
recognized = False

View File

@ -51,6 +51,12 @@ class _DelegatedWormhole(object):
def set_code(self, code):
self._boss.set_code(code)
def serialize(self):
s = {"serialized_wormhole_version": 1,
"boss": self._boss.serialize(),
}
return s
def send(self, plaintext):
self._boss.send(plaintext)
def close(self):
@ -116,6 +122,7 @@ class _DeferredWormhole(object):
def set_code(self, code):
self._boss.set_code(code)
# no .serialize in Deferred-mode
def send(self, plaintext):
self._boss.send(plaintext)
def close(self):
@ -165,11 +172,8 @@ class _DeferredWormhole(object):
for d in self._closed_observers:
d.callback(close_result)
def _wormhole(appid, relay_url, reactor, delegate=None,
tor_manager=None, timing=None,
journal=None,
stderr=sys.stderr,
):
def create(appid, relay_url, reactor, delegate=None, journal=None,
tor_manager=None, timing=None, stderr=sys.stderr):
timing = timing or DebugTiming()
side = bytes_to_hexstr(os.urandom(5))
journal = journal or ImmediateJournal()
@ -179,23 +183,30 @@ def _wormhole(appid, relay_url, reactor, delegate=None,
w = _DeferredWormhole()
b = Boss(w, side, relay_url, appid, reactor, journal, timing)
w._set_boss(b)
# force allocate for now
b.start()
return w
def delegated_wormhole(appid, relay_url, reactor, delegate,
tor_manager=None, timing=None,
journal=None,
stderr=sys.stderr,
):
assert delegate
return _wormhole(appid, relay_url, reactor, delegate,
tor_manager, timing, journal, stderr)
def from_serialized(serialized, reactor, delegate,
journal=None, tor_manager=None,
timing=None, stderr=sys.stderr):
assert serialized["serialized_wormhole_version"] == 1
timing = timing or DebugTiming()
w = _DelegatedWormhole(delegate)
# now unpack state machines, including the SPAKE2 in Key
b = Boss.from_serialized(w, serialized["boss"], reactor, journal, timing)
w._set_boss(b)
b.start() # ??
raise NotImplemented
# should the new Wormhole call got_code? only if it wasn't called before.
# after creating the wormhole object, app must call exactly one of:
# set_code(code), generate_code(), helper=type_code(), and then (if they need
# to know the code) wait for delegate.got_code() or d=w.when_code()
# the helper for type_code() can be asked for completions:
# d=helper.get_completions(text_so_far), which will fire with a list of
# strings that could usefully be appended to text_so_far.
# wormhole.type_code_readline(w) is a wrapper that knows how to use
# w.type_code() to drive rlcompleter
def deferred_wormhole(appid, relay_url, reactor,
tor_manager=None, timing=None,
journal=None,
stderr=sys.stderr,
):
return _wormhole(appid, relay_url, reactor, None,
tor_manager, timing, journal, stderr)