diff --git a/docs/boss.dot b/docs/boss.dot index 8b34fc3..bff04d3 100644 --- a/docs/boss.dot +++ b/docs/boss.dot @@ -54,7 +54,7 @@ digraph { {rank=same; Other S_closed} Other [shape="box" style="dashed" - label="send -> S.send\ngot_verifier -> A.got_verifier\nallocate -> C.allocate\ninput -> C.input\nset_code -> C.set_code" + label="rx_welcome -> process\nsend -> S.send\ngot_verifier -> A.got_verifier\nallocate -> C.allocate\ninput -> C.input\nset_code -> C.set_code" ] diff --git a/src/wormhole/_boss.py b/src/wormhole/_boss.py index 6065bfc..7ba8978 100644 --- a/src/wormhole/_boss.py +++ b/src/wormhole/_boss.py @@ -1,3 +1,4 @@ +from __future__ import print_function, absolute_import, unicode_literals from zope.interface import implementer from attr import attrs, attrib from attr.validators import provides, instance_of @@ -29,7 +30,7 @@ class Boss(object): self._M = Mailbox(self._side) self._S = Send(self._side, self._timing) self._O = Order(self._side, self._timing) - self._K = Key(self._timing) + self._K = Key(self._appid, self._timing) self._R = Receive(self._side, self._timing) self._RC = RendezvousConnector(self._url, self._appid, self._side, self._reactor, self._journal, @@ -92,6 +93,10 @@ class Boss(object): @m.input() def close(self): pass + # from RendezvousConnector + @m.input() + def rx_welcome(self, welcome): pass + # from Code (provoked by input/allocate/set_code) @m.input() def got_code(self, code): pass @@ -121,6 +126,10 @@ class Boss(object): def closed(self): pass + @m.output() + def process_welcome(self, welcome): + pass # TODO: ignored for now + @m.output() def do_got_code(self, code): nameplate = code.split("-")[0] @@ -167,18 +176,22 @@ class Boss(object): S0_empty.upon(close, enter=S3_closing, outputs=[close_lonely]) S0_empty.upon(send, enter=S0_empty, outputs=[S_send]) + S0_empty.upon(rx_welcome, enter=S0_empty, outputs=[process_welcome]) S0_empty.upon(got_code, enter=S1_lonely, outputs=[do_got_code]) + S1_lonely.upon(rx_welcome, enter=S1_lonely, outputs=[process_welcome]) S1_lonely.upon(happy, enter=S2_happy, outputs=[]) S1_lonely.upon(scared, enter=S3_closing, outputs=[close_scared]) S1_lonely.upon(close, enter=S3_closing, outputs=[close_lonely]) S1_lonely.upon(send, enter=S1_lonely, outputs=[S_send]) S1_lonely.upon(got_verifier, enter=S1_lonely, outputs=[W_got_verifier]) + S2_happy.upon(rx_welcome, enter=S2_happy, outputs=[process_welcome]) S2_happy.upon(got_phase, enter=S2_happy, outputs=[W_received]) S2_happy.upon(got_version, enter=S2_happy, outputs=[process_version]) S2_happy.upon(scared, enter=S3_closing, outputs=[close_scared]) S2_happy.upon(close, enter=S3_closing, outputs=[close_happy]) S2_happy.upon(send, enter=S2_happy, outputs=[S_send]) + S3_closing.upon(rx_welcome, enter=S3_closing, outputs=[]) S3_closing.upon(got_phase, enter=S3_closing, outputs=[]) S3_closing.upon(got_version, enter=S3_closing, outputs=[]) S3_closing.upon(happy, enter=S3_closing, outputs=[]) @@ -187,6 +200,7 @@ class Boss(object): S3_closing.upon(send, enter=S3_closing, outputs=[]) S3_closing.upon(closed, enter=S4_closed, outputs=[W_closed]) + S4_closed.upon(rx_welcome, enter=S4_closed, outputs=[]) S4_closed.upon(got_phase, enter=S4_closed, outputs=[]) S4_closed.upon(got_version, enter=S4_closed, outputs=[]) S4_closed.upon(happy, enter=S4_closed, outputs=[]) diff --git a/src/wormhole/_code.py b/src/wormhole/_code.py index 067ace2..7f4a248 100644 --- a/src/wormhole/_code.py +++ b/src/wormhole/_code.py @@ -1,3 +1,4 @@ +from __future__ import print_function, absolute_import, unicode_literals import os from zope.interface import implementer from attr import attrs, attrib @@ -127,5 +128,14 @@ class Code(object): outputs=[stash_nameplates]) S2_typing_nameplate.upon(hyphen, enter=S3_typing_code, outputs=[lookup_wordlist]) + # TODO: need a proper pair of connected/lost states around S2 + S2_typing_nameplate.upon(connected, enter=S2_typing_nameplate, outputs=[]) + S2_typing_nameplate.upon(lost, enter=S2_typing_nameplate, outputs=[]) + S3_typing_code.upon(tab, enter=S3_typing_code, outputs=[do_completion_code]) S3_typing_code.upon(RETURN, enter=S4_known, outputs=[B_got_code]) + S3_typing_code.upon(connected, enter=S3_typing_code, outputs=[]) + S3_typing_code.upon(lost, enter=S3_typing_code, outputs=[]) + + S4_known.upon(connected, enter=S4_known, outputs=[]) + S4_known.upon(lost, enter=S4_known, outputs=[]) diff --git a/src/wormhole/_key.py b/src/wormhole/_key.py index edbcda7..3472871 100644 --- a/src/wormhole/_key.py +++ b/src/wormhole/_key.py @@ -1,7 +1,8 @@ +from __future__ import print_function, absolute_import, unicode_literals from hashlib import sha256 from zope.interface import implementer from attr import attrs, attrib -from attr.validators import provides +from attr.validators import provides, instance_of from spake2 import SPAKE2_Symmetric from hkdf import Hkdf from nacl.secret import SecretBox @@ -53,6 +54,7 @@ def encrypt_data(key, plaintext): @attrs @implementer(_interfaces.IKey) class Key(object): + _appid = attrib(validator=instance_of(type(u""))) _timing = attrib(validator=provides(_interfaces.ITiming)) m = MethodicalMachine() diff --git a/src/wormhole/_mailbox.py b/src/wormhole/_mailbox.py index 1aec665..5d9642f 100644 --- a/src/wormhole/_mailbox.py +++ b/src/wormhole/_mailbox.py @@ -1,3 +1,4 @@ +from __future__ import print_function, absolute_import, unicode_literals from zope.interface import implementer from attr import attrs, attrib from attr.validators import instance_of @@ -10,7 +11,7 @@ class Mailbox(object): _side = attrib(validator=instance_of(type(u""))) m = MethodicalMachine() - def __init__(self): + def __attrs_post_init__(self): self._mood = None self._nameplate = None self._mailbox = None @@ -129,7 +130,7 @@ class Mailbox(object): @m.output() def record_nameplate_and_RC_tx_claim(self, nameplate): self._nameplate = nameplate - self._RX.tx_claim(self._nameplate) + self._RC.tx_claim(self._nameplate) @m.output() def RC_tx_claim(self): # when invoked via M.connected(), we must use the stored nameplate @@ -278,5 +279,19 @@ class Mailbox(object): ScB.upon(rx_closed, enter=SsB, outputs=[RC_stop]) ScA.upon(connected, enter=ScB, outputs=[RC_tx_close]) + SsB.upon(lost, enter=SsB, outputs=[]) SsB.upon(stopped, enter=Ss, outputs=[W_closed]) + SrcB.upon(rx_claimed, enter=SrcB, outputs=[]) + SrcB.upon(rx_message_theirs, enter=SrcB, outputs=[]) + SrcB.upon(rx_message_ours, enter=SrcB, outputs=[]) + SrB.upon(rx_claimed, enter=SrB, outputs=[]) + SrB.upon(rx_message_theirs, enter=SrB, outputs=[]) + SrB.upon(rx_message_ours, enter=SrB, outputs=[]) + ScB.upon(rx_claimed, enter=ScB, outputs=[]) + ScB.upon(rx_message_theirs, enter=ScB, outputs=[]) + ScB.upon(rx_message_ours, enter=ScB, outputs=[]) + SsB.upon(rx_claimed, enter=SsB, outputs=[]) + SsB.upon(rx_message_theirs, enter=SsB, outputs=[]) + SsB.upon(rx_message_ours, enter=SsB, outputs=[]) + diff --git a/src/wormhole/_nameplate.py b/src/wormhole/_nameplate.py index 719f354..ee9631c 100644 --- a/src/wormhole/_nameplate.py +++ b/src/wormhole/_nameplate.py @@ -1,3 +1,4 @@ +from __future__ import print_function, absolute_import, unicode_literals from zope.interface import implementer from automat import MethodicalMachine from . import _interfaces @@ -5,8 +6,7 @@ from . import _interfaces @implementer(_interfaces.INameplateLister) class NameplateListing(object): m = MethodicalMachine() - def __init__(self): - pass + def wire(self, rendezvous_connector, code): self._RC = _interfaces.IRendezvousConnector(rendezvous_connector) self._C = _interfaces.ICode(code) diff --git a/src/wormhole/_order.py b/src/wormhole/_order.py index 73934e8..e16f2b6 100644 --- a/src/wormhole/_order.py +++ b/src/wormhole/_order.py @@ -1,3 +1,4 @@ +from __future__ import print_function, absolute_import, unicode_literals from zope.interface import implementer from attr import attrs, attrib from attr.validators import provides, instance_of @@ -11,7 +12,7 @@ class Order(object): _timing = attrib(validator=provides(_interfaces.ITiming)) m = MethodicalMachine() - def __init__(self): + def __attrs_post_init__(self): self._key = None self._queue = [] def wire(self, key, receive): diff --git a/src/wormhole/_receive.py b/src/wormhole/_receive.py index 8fec9a8..47a3c12 100644 --- a/src/wormhole/_receive.py +++ b/src/wormhole/_receive.py @@ -1,3 +1,4 @@ +from __future__ import print_function, absolute_import, unicode_literals from zope.interface import implementer from attr import attrs, attrib from attr.validators import provides, instance_of @@ -12,7 +13,7 @@ class Receive(object): _timing = attrib(validator=provides(_interfaces.ITiming)) m = MethodicalMachine() - def __init__(self): + def __attrs_post_init__(self): self._key = None def wire(self, boss, key, send): diff --git a/src/wormhole/_rendezvous.py b/src/wormhole/_rendezvous.py index 769cb25..c65dc68 100644 --- a/src/wormhole/_rendezvous.py +++ b/src/wormhole/_rendezvous.py @@ -1,3 +1,4 @@ +from __future__ import print_function, absolute_import, unicode_literals import os from six.moves.urllib_parse import urlparse from attr import attrs, attrib @@ -27,7 +28,12 @@ class WSClient(websocket.WebSocketClientProtocol): def onMessage(self, payload, isBinary): #print("onMessage") assert not isBinary - self._RC.ws_message(payload) + try: + self._RC.ws_message(payload) + except: + print("LOGGING") + log.err() + raise def onClose(self, wasClean, code, reason): #print("onClose") @@ -60,6 +66,7 @@ class RendezvousConnector(object): _reactor = attrib() _journal = attrib(validator=provides(_interfaces.IJournal)) _timing = attrib(validator=provides(_interfaces.ITiming)) + DEBUG = False def __attrs_post_init__(self): self._ws = None diff --git a/src/wormhole/_send.py b/src/wormhole/_send.py index 3d6b1e1..355a267 100644 --- a/src/wormhole/_send.py +++ b/src/wormhole/_send.py @@ -1,14 +1,18 @@ +from __future__ import print_function, absolute_import, unicode_literals +from attr import attrs, attrib +from attr.validators import provides, instance_of from zope.interface import implementer from automat import MethodicalMachine from . import _interfaces from ._key import derive_phase_key, encrypt_data +@attrs @implementer(_interfaces.ISend) class Send(object): + _side = attrib(validator=instance_of(type(u""))) + _timing = attrib(validator=provides(_interfaces.ITiming)) m = MethodicalMachine() - def __init__(self, side, timing): - self._side = side - self._timing = timing + def wire(self, mailbox): self._M = _interfaces.IMailbox(mailbox) diff --git a/src/wormhole/test/test_wormhole_new.py b/src/wormhole/test/test_wormhole_new.py index 821001b..9710ae7 100644 --- a/src/wormhole/test/test_wormhole_new.py +++ b/src/wormhole/test/test_wormhole_new.py @@ -1,6 +1,7 @@ from __future__ import print_function, unicode_literals from twisted.trial import unittest from twisted.internet import reactor +from twisted.internet.defer import inlineCallbacks from .common import ServerBase from .. import wormhole @@ -26,3 +27,11 @@ class New(ServerBase, unittest.TestCase): dg = Delegate() w = wormhole.delegated_wormhole(APPID, self.relayurl, reactor, dg) w.close() + + @inlineCallbacks + def test_allocate(self): + w = wormhole.deferred_wormhole(APPID, self.relayurl, reactor) + code = yield w.when_code() + print("code:", code) + yield w.close() + test_allocate.timeout = 2