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)) old_state, input, new_state))
names[machine].set_trace(tracer) names[machine].set_trace(tracer)
def serialize(self):
raise NotImplemented
# and these are the state-machine transition functions, which don't take # and these are the state-machine transition functions, which don't take
# args # args
@m.state(initial=True) @m.state(initial=True)

View File

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

View File

@ -7,7 +7,7 @@ from twisted.protocols import basic
from twisted.internet import reactor from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks, returnValue from twisted.internet.defer import inlineCallbacks, returnValue
from ..errors import TransferError, WormholeClosedError, NoTorError from ..errors import TransferError, WormholeClosedError, NoTorError
from ..wormhole import wormhole from .. import wormhole
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
@ -52,9 +52,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()
w = wormhole(self._args.appid or APPID, self._args.relay_url, w = wormhole.create(self._args.appid or APPID, self._args.relay_url,
self._reactor, self._tor_manager, self._reactor,
timing=self._timing) tor_manager=self._tor_manager,
timing=self._timing)
d = self._go(w) d = self._go(w)
d.addBoth(w.close) # must wait for ack from close() d.addBoth(w.close) # must wait for ack from close()
yield d yield d
@ -83,25 +84,25 @@ class Sender:
if args.code: if args.code:
w.set_code(args.code) w.set_code(args.code)
code = args.code
else: else:
code = yield w.get_code(args.code_length) w.allocate_code(args.code_length)
code = yield w.when_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)
yield w.establish_key()
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)
notify = self._reactor.callLater(VERIFY_TIMER, on_slow_connection) 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: try:
verifier_bytes = yield w.verify() # this may raise WrongPasswordError # this may raise WrongPasswordError
verifier_bytes = yield w.when_verifier()
finally: finally:
if not notify.called: if not notify.called:
notify.cancel() notify.cancel()
@ -146,12 +147,13 @@ class Sender:
while True: while True:
try: try:
them_d_bytes = yield w.get() them_d_bytes = yield w.when_received()
except WormholeClosedError: except WormholeClosedError:
if done: if done:
returnValue(None) returnValue(None)
raise TransferError("unexpected close") 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) them_d = bytes_to_dict(them_d_bytes)
#print("GOT", them_d) #print("GOT", them_d)
recognized = False recognized = False

View File

@ -51,6 +51,12 @@ class _DelegatedWormhole(object):
def set_code(self, code): def set_code(self, code):
self._boss.set_code(code) self._boss.set_code(code)
def serialize(self):
s = {"serialized_wormhole_version": 1,
"boss": self._boss.serialize(),
}
return s
def send(self, plaintext): def send(self, plaintext):
self._boss.send(plaintext) self._boss.send(plaintext)
def close(self): def close(self):
@ -116,6 +122,7 @@ class _DeferredWormhole(object):
def set_code(self, code): def set_code(self, code):
self._boss.set_code(code) self._boss.set_code(code)
# no .serialize in Deferred-mode
def send(self, plaintext): def send(self, plaintext):
self._boss.send(plaintext) self._boss.send(plaintext)
def close(self): def close(self):
@ -165,11 +172,8 @@ class _DeferredWormhole(object):
for d in self._closed_observers: for d in self._closed_observers:
d.callback(close_result) d.callback(close_result)
def _wormhole(appid, relay_url, reactor, delegate=None, def create(appid, relay_url, reactor, delegate=None, journal=None,
tor_manager=None, timing=None, tor_manager=None, timing=None, stderr=sys.stderr):
journal=None,
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()
@ -179,23 +183,30 @@ def _wormhole(appid, relay_url, reactor, delegate=None,
w = _DeferredWormhole() w = _DeferredWormhole()
b = Boss(w, side, relay_url, appid, reactor, journal, timing) b = Boss(w, side, relay_url, appid, reactor, journal, timing)
w._set_boss(b) w._set_boss(b)
# force allocate for now
b.start() b.start()
return w return w
def delegated_wormhole(appid, relay_url, reactor, delegate, def from_serialized(serialized, reactor, delegate,
tor_manager=None, timing=None, journal=None, tor_manager=None,
journal=None, timing=None, stderr=sys.stderr):
stderr=sys.stderr, assert serialized["serialized_wormhole_version"] == 1
): timing = timing or DebugTiming()
assert delegate w = _DelegatedWormhole(delegate)
return _wormhole(appid, relay_url, reactor, delegate, # now unpack state machines, including the SPAKE2 in Key
tor_manager, timing, journal, stderr) 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)