clean up wordlist handling
This commit is contained in:
parent
ae95948c17
commit
175fef2ab4
|
@ -7,8 +7,8 @@ digraph {
|
|||
S0A -> S0B [label="connected"]
|
||||
S0B -> S0A [label="lost"]
|
||||
S0B [label="S0B:\nidle\nconnected"]
|
||||
S0A -> S1A [label="allocate" color="orange"]
|
||||
S0B -> P_allocate [label="allocate"]
|
||||
S0A -> S1A [label="allocate(length, wordlist)" color="orange"]
|
||||
S0B -> P_allocate [label="allocate(length, wordlist)"]
|
||||
P_allocate [shape="box" label="RC.tx_allocate" color="orange"]
|
||||
P_allocate -> S1B [color="orange"]
|
||||
{rank=same; S1A P_allocate S1B}
|
||||
|
@ -21,7 +21,7 @@ digraph {
|
|||
S1A -> P_allocate [label="connected" color="orange"]
|
||||
|
||||
S1B -> P_allocated [label="rx_allocated" color="orange"]
|
||||
P_allocated [shape="box" label="C.allocated_nameplate" color="orange"]
|
||||
P_allocated [shape="box" label="choose words\nC.allocated(nameplate,code)" color="orange"]
|
||||
P_allocated -> S2 [color="orange"]
|
||||
|
||||
S2 [label="S2:\ndone" color="orange"]
|
||||
|
|
|
@ -4,36 +4,31 @@ digraph {
|
|||
{rank=same; start S0}
|
||||
start -> S0 [style="invis"]
|
||||
S0 [label="S0:\nidle"]
|
||||
S0 -> P0_got_code [label="set_code"]
|
||||
S0 -> P0_got_code [label="set_code\n(code)"]
|
||||
P0_got_code [shape="box" label="N.set_nameplate"]
|
||||
P0_got_code -> P_done
|
||||
P_done [shape="box" label="K.got_code\nB.got_code"]
|
||||
P_done -> S5
|
||||
S5 [label="S5: known" color="green"]
|
||||
P_done -> S4
|
||||
S4 [label="S4: known" color="green"]
|
||||
|
||||
{rank=same; S1_inputting_nameplate S3_allocating}
|
||||
{rank=same; P0_got_code P1_set_nameplate P3_got_nameplate}
|
||||
S0 -> P_input [label="input_code"]
|
||||
P_input [shape="box" label="I.start"]
|
||||
P_input [shape="box" label="I.start\n(helper)"]
|
||||
P_input -> S1_inputting_nameplate
|
||||
S1_inputting_nameplate [label="S1:\ninputting\nnameplate"]
|
||||
S1_inputting_nameplate -> P1_set_nameplate [label="got_nameplate"]
|
||||
S1_inputting_nameplate -> P1_set_nameplate [label="got_nameplate\n(nameplate)"]
|
||||
P1_set_nameplate [shape="box" label="N.set_nameplate"]
|
||||
P1_set_nameplate -> S2_inputting_words
|
||||
S2_inputting_words [label="S2:\ninputting\nwords"]
|
||||
S2_inputting_words -> P1_got_words [label="finished_input"]
|
||||
P1_got_words [shape="box" label="assemble\ncode"]
|
||||
P1_got_words -> P_done
|
||||
P_done
|
||||
S2_inputting_words -> P_done [label="finished_input\n(code)"]
|
||||
|
||||
S0 -> P_allocate [label="allocate_code"]
|
||||
P_allocate [shape="box" label="A.allocate"]
|
||||
S0 -> P_allocate [label="allocate_code\n(length,\nwordlist)"]
|
||||
P_allocate [shape="box" label="A.allocate\n(length, wordlist)"]
|
||||
P_allocate -> S3_allocating
|
||||
S3_allocating [label="S3:\nallocating"]
|
||||
S3_allocating -> P3_got_nameplate [label="allocated_nameplate"]
|
||||
S3_allocating -> P3_got_nameplate [label="allocated\n(nameplate,\ncode)"]
|
||||
P3_got_nameplate [shape="box" label="N.set_nameplate"]
|
||||
P3_got_nameplate -> P3_generate
|
||||
P3_generate [shape="box" label="append\nrandom words"]
|
||||
P3_generate -> P_done
|
||||
P3_got_nameplate -> P_done
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ digraph {
|
|||
S3 [label="S3: typing\ncode\n(yes wordlist)"]
|
||||
S3 -> S3 [label="got_nameplates"]
|
||||
S3 -> P_done [label="choose_words" color="orange" fontcolor="orange"]
|
||||
P_done [shape="box" label="build code\nC.finished_input"]
|
||||
P_done [shape="box" label="build code\nC.finished_input(code)"]
|
||||
P_done -> S4
|
||||
S4 [label="S4: done" color="green"]
|
||||
S4 -> S4 [label="got_nameplates\ngot_wordlist"]
|
||||
|
|
|
@ -61,6 +61,7 @@ digraph {
|
|||
label="connected\nlost\nrx_claimed\nrx_released"]
|
||||
Mailbox -> Nameplate [style="dashed" label="release"]
|
||||
Nameplate -> Mailbox [style="dashed" label="got_mailbox"]
|
||||
Nameplate -> Input [style="dashed" label="got_wordlist"]
|
||||
|
||||
Mailbox -> Connection [style="dashed" color="red" fontcolor="red"
|
||||
label="tx_open\ntx_add\ntx_close"
|
||||
|
|
|
@ -38,7 +38,7 @@ digraph {
|
|||
|
||||
S2A -> S3A [label="(none)" style="invis"]
|
||||
S2B -> P_open [label="rx_claimed" color="orange" fontcolor="orange"]
|
||||
P_open [shape="box" label="M.got_mailbox" color="orange"]
|
||||
P_open [shape="box" label="I.got_wordlist\nM.got_mailbox" color="orange"]
|
||||
P_open -> S3B [color="orange"]
|
||||
|
||||
subgraph {rank=same; S3A S3B}
|
||||
|
|
|
@ -30,7 +30,7 @@ class Allocator(object):
|
|||
|
||||
# from Code
|
||||
@m.input()
|
||||
def allocate(self): pass
|
||||
def allocate(self, length, wordlist): pass
|
||||
|
||||
# from RendezvousConnector
|
||||
@m.input()
|
||||
|
@ -40,26 +40,37 @@ class Allocator(object):
|
|||
@m.input()
|
||||
def rx_allocated(self, nameplate): pass
|
||||
|
||||
@m.output()
|
||||
def stash(self, length, wordlist):
|
||||
self._length = length
|
||||
self._wordlist = _interfaces.IWordlist(wordlist)
|
||||
@m.output()
|
||||
def stash_and_RC_rx_allocate(self, length, wordlist):
|
||||
self._length = length
|
||||
self._wordlist = _interfaces.IWordlist(wordlist)
|
||||
self._RC.tx_allocate()
|
||||
@m.output()
|
||||
def RC_tx_allocate(self):
|
||||
self._RC.tx_allocate()
|
||||
@m.output()
|
||||
def C_allocated_nameplate(self, nameplate):
|
||||
self._C.allocated_nameplate(nameplate)
|
||||
def build_and_notify(self, nameplate):
|
||||
words = self._wordlist.choose_words(self._length)
|
||||
code = nameplate + "-" + words
|
||||
self._C.allocated(nameplate, code)
|
||||
|
||||
S0A_idle.upon(connected, enter=S0B_idle_connected, outputs=[])
|
||||
S0B_idle_connected.upon(lost, enter=S0A_idle, outputs=[])
|
||||
|
||||
S0A_idle.upon(allocate, enter=S1A_allocating, outputs=[])
|
||||
S0A_idle.upon(allocate, enter=S1A_allocating, outputs=[stash])
|
||||
S0B_idle_connected.upon(allocate, enter=S1B_allocating_connected,
|
||||
outputs=[RC_tx_allocate])
|
||||
outputs=[stash_and_RC_rx_allocate])
|
||||
|
||||
S1A_allocating.upon(connected, enter=S1B_allocating_connected,
|
||||
outputs=[RC_tx_allocate])
|
||||
S1B_allocating_connected.upon(lost, enter=S1A_allocating, outputs=[])
|
||||
|
||||
S1B_allocating_connected.upon(rx_allocated, enter=S2_done,
|
||||
outputs=[C_allocated_nameplate])
|
||||
outputs=[build_and_notify])
|
||||
|
||||
S2_done.upon(connected, enter=S2_done, outputs=[])
|
||||
S2_done.upon(lost, enter=S2_done, outputs=[])
|
||||
|
|
|
@ -19,6 +19,7 @@ from ._allocator import Allocator
|
|||
from ._input import Input
|
||||
from ._code import Code
|
||||
from ._terminator import Terminator
|
||||
from ._wordlist import PGPWordList
|
||||
from .errors import (ServerError, LonelyError, WrongPasswordError,
|
||||
KeyFormatError, OnlyOneCodeError)
|
||||
from .util import bytes_to_dict
|
||||
|
@ -50,13 +51,13 @@ class Boss(object):
|
|||
self._RC = RendezvousConnector(self._url, self._appid, self._side,
|
||||
self._reactor, self._journal,
|
||||
self._tor_manager, self._timing)
|
||||
self._L = Lister()
|
||||
self._L = Lister(self._timing)
|
||||
self._A = Allocator(self._timing)
|
||||
self._I = Input(self._timing)
|
||||
self._C = Code(self._timing)
|
||||
self._T = Terminator()
|
||||
|
||||
self._N.wire(self._M, self._RC, self._T)
|
||||
self._N.wire(self._M, self._I, self._RC, self._T)
|
||||
self._M.wire(self._N, self._RC, self._O, self._T)
|
||||
self._S.wire(self._M)
|
||||
self._O.wire(self._K, self._R)
|
||||
|
@ -129,7 +130,8 @@ class Boss(object):
|
|||
if self._did_start_code:
|
||||
raise OnlyOneCodeError()
|
||||
self._did_start_code = True
|
||||
self._C.allocate_code(code_length)
|
||||
wl = PGPWordList()
|
||||
self._C.allocate_code(code_length, wl)
|
||||
def set_code(self, code):
|
||||
if ' ' in code:
|
||||
raise KeyFormatError("code (%s) contains spaces." % code)
|
||||
|
|
|
@ -1,24 +1,9 @@
|
|||
from __future__ import print_function, absolute_import, unicode_literals
|
||||
import os
|
||||
from zope.interface import implementer
|
||||
from attr import attrs, attrib
|
||||
from attr.validators import provides
|
||||
from automat import MethodicalMachine
|
||||
from . import _interfaces
|
||||
from .wordlist import (byte_to_even_word, byte_to_odd_word,
|
||||
#even_words_lowercase, odd_words_lowercase,
|
||||
)
|
||||
|
||||
def make_code(nameplate, code_length):
|
||||
assert isinstance(nameplate, type("")), type(nameplate)
|
||||
words = []
|
||||
for i in range(code_length):
|
||||
# we start with an "odd word"
|
||||
if i % 2 == 0:
|
||||
words.append(byte_to_odd_word[os.urandom(1)].lower())
|
||||
else:
|
||||
words.append(byte_to_even_word[os.urandom(1)].lower())
|
||||
return "%s-%s" % (nameplate, "-".join(words))
|
||||
|
||||
@attrs
|
||||
@implementer(_interfaces.ICode)
|
||||
|
@ -28,7 +13,7 @@ class Code(object):
|
|||
@m.setTrace()
|
||||
def set_trace(): pass # pragma: no cover
|
||||
|
||||
def wire(self, boss, rendezvous_connector, lister):
|
||||
def wire(self, boss, allocator, nameplate, key, input):
|
||||
self._B = _interfaces.IBoss(boss)
|
||||
self._A = _interfaces.IAllocator(allocator)
|
||||
self._N = _interfaces.INameplate(nameplate)
|
||||
|
@ -36,37 +21,27 @@ class Code(object):
|
|||
self._I = _interfaces.IInput(input)
|
||||
|
||||
@m.state(initial=True)
|
||||
def S0A_unknown(self): pass # pragma: no cover
|
||||
def S0_idle(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S0B_unknown_connected(self): pass # pragma: no cover
|
||||
def S1_inputting_nameplate(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S1A_connecting(self): pass # pragma: no cover
|
||||
def S2_inputting_words(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S1B_allocating(self): pass # pragma: no cover
|
||||
def S3_allocating(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S2_input_nameplate(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S3_input_code_no_wordlist(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S4_input_code_wordlist(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S5_known(self): pass # pragma: no cover
|
||||
def S4_known(self): pass # pragma: no cover
|
||||
|
||||
# from App
|
||||
@m.input()
|
||||
def allocate_code(self, code_length): pass
|
||||
def allocate_code(self, length, wordlist): pass
|
||||
@m.input()
|
||||
def input_code(self, input_helper): pass
|
||||
@m.input()
|
||||
def set_code(self, code): pass
|
||||
|
||||
# from Lister
|
||||
# from Allocator
|
||||
@m.input()
|
||||
def got_nameplates(self, nameplates): pass
|
||||
|
||||
# from Nameplate
|
||||
@m.input()
|
||||
def got_wordlist(self, wordlist): pass
|
||||
def allocated(self, nameplate, code): pass
|
||||
|
||||
# from Input
|
||||
@m.input()
|
||||
|
@ -75,109 +50,38 @@ class Code(object):
|
|||
def finished_input(self, code): pass
|
||||
|
||||
@m.output()
|
||||
def L_refresh_nameplates(self):
|
||||
self._L.refresh_nameplates()
|
||||
@m.output()
|
||||
def start_input_and_L_refresh_nameplates(self, input_helper):
|
||||
self._input_helper = input_helper
|
||||
self._L.refresh_nameplates()
|
||||
@m.output()
|
||||
def stash_code_length_and_RC_tx_allocate(self, code_length):
|
||||
self._code_length = code_length
|
||||
self._RC.tx_allocate()
|
||||
@m.output()
|
||||
def stash_code_length(self, code_length):
|
||||
self._code_length = code_length
|
||||
@m.output()
|
||||
def RC_tx_allocate(self):
|
||||
self._RC.tx_allocate()
|
||||
@m.output()
|
||||
def stash_wordlist(self, wordlist):
|
||||
# TODO
|
||||
pass
|
||||
@m.output()
|
||||
def stash_nameplates(self, nameplates):
|
||||
self._known_nameplates = nameplates
|
||||
pass
|
||||
@m.output()
|
||||
def lookup_wordlist(self):
|
||||
pass
|
||||
@m.output()
|
||||
def do_completion_code(self):
|
||||
pass
|
||||
@m.output()
|
||||
def record_nameplate(self, nameplate):
|
||||
self._nameplate = nameplate
|
||||
@m.output()
|
||||
def N_set_nameplate(self, nameplate):
|
||||
def do_set_code(self, code):
|
||||
nameplate = code.split("-", 2)[0]
|
||||
self._N.set_nameplate(nameplate)
|
||||
self._K.got_code(code)
|
||||
self._B.got_code(code)
|
||||
|
||||
@m.output()
|
||||
def generate_and_B_got_code(self, nameplate):
|
||||
self._code = make_code(nameplate, self._code_length)
|
||||
self._B_got_code()
|
||||
def do_start_input(self, input_helper):
|
||||
self._I.start(input_helper)
|
||||
@m.output()
|
||||
def do_middle_input(self, nameplate):
|
||||
self._N.set_nameplate(nameplate)
|
||||
@m.output()
|
||||
def do_finish_input(self, code):
|
||||
self._K.got_code(code)
|
||||
self._B.got_code(code)
|
||||
|
||||
@m.output()
|
||||
def submit_words_and_B_got_code(self, words):
|
||||
assert self._nameplate
|
||||
self._code = self._nameplate + "-" + words
|
||||
self._B_got_code()
|
||||
|
||||
def do_start_allocate(self, length, wordlist):
|
||||
self._A.allocate(length, wordlist)
|
||||
@m.output()
|
||||
def B_got_code(self, code):
|
||||
self._code = code
|
||||
self._B_got_code()
|
||||
def do_finish_allocate(self, nameplate, code):
|
||||
self._N.set_nameplate(nameplate)
|
||||
self._K.got_code(code)
|
||||
self._B.got_code(code)
|
||||
|
||||
def _B_got_code(self):
|
||||
self._N.set_nameplate(nameplate) XXX
|
||||
self._B.got_code(self._code)
|
||||
|
||||
S0A_unknown.upon(connected, enter=S0B_unknown_connected, outputs=[])
|
||||
S0B_unknown_connected.upon(lost, enter=S0A_unknown, outputs=[])
|
||||
|
||||
S0A_unknown.upon(set_code, enter=S5_known, outputs=[B_got_code])
|
||||
S0B_unknown_connected.upon(set_code, enter=S5_known, outputs=[B_got_code])
|
||||
|
||||
S0A_unknown.upon(allocate_code, enter=S1A_connecting,
|
||||
outputs=[stash_code_length])
|
||||
S0B_unknown_connected.upon(allocate_code, enter=S1B_allocating,
|
||||
outputs=[stash_code_length_and_RC_tx_allocate])
|
||||
S1A_connecting.upon(connected, enter=S1B_allocating,
|
||||
outputs=[RC_tx_allocate])
|
||||
S1B_allocating.upon(lost, enter=S1A_connecting, outputs=[])
|
||||
S1B_allocating.upon(rx_allocated, enter=S5_known,
|
||||
outputs=[generate_and_B_got_code])
|
||||
|
||||
S0A_unknown.upon(input_code, enter=S2_input_nameplate,
|
||||
outputs=[start_input_and_L_refresh_nameplates])
|
||||
S0B_unknown_connected.upon(input_code, enter=S2_input_nameplate,
|
||||
outputs=[start_input_and_L_refresh_nameplates])
|
||||
S2_input_nameplate.upon(update_nameplates, enter=S2_input_nameplate,
|
||||
outputs=[L_refresh_nameplates])
|
||||
S2_input_nameplate.upon(got_nameplates,
|
||||
enter=S2_input_nameplate,
|
||||
outputs=[stash_nameplates])
|
||||
S2_input_nameplate.upon(claim_nameplate, enter=S3_input_code_no_wordlist,
|
||||
outputs=[record_nameplate, N_set_nameplate])
|
||||
S2_input_nameplate.upon(connected, enter=S2_input_nameplate, outputs=[])
|
||||
S2_input_nameplate.upon(lost, enter=S2_input_nameplate, outputs=[])
|
||||
|
||||
S3_input_code_no_wordlist.upon(got_wordlist,
|
||||
enter=S4_input_code_wordlist,
|
||||
outputs=[stash_wordlist])
|
||||
S3_input_code_no_wordlist.upon(submit_words, enter=S5_known,
|
||||
outputs=[submit_words_and_B_got_code])
|
||||
S3_input_code_no_wordlist.upon(connected, enter=S3_input_code_no_wordlist,
|
||||
outputs=[])
|
||||
S3_input_code_no_wordlist.upon(lost, enter=S3_input_code_no_wordlist,
|
||||
outputs=[])
|
||||
|
||||
S4_input_code_wordlist.upon(submit_words, enter=S5_known,
|
||||
outputs=[submit_words_and_B_got_code])
|
||||
S4_input_code_wordlist.upon(connected, enter=S4_input_code_wordlist,
|
||||
outputs=[])
|
||||
S4_input_code_wordlist.upon(lost, enter=S4_input_code_wordlist,
|
||||
outputs=[])
|
||||
|
||||
S5_known.upon(connected, enter=S5_known, outputs=[])
|
||||
S5_known.upon(lost, enter=S5_known, outputs=[])
|
||||
S0_idle.upon(set_code, enter=S4_known, outputs=[do_set_code])
|
||||
S0_idle.upon(input_code, enter=S1_inputting_nameplate,
|
||||
outputs=[do_start_input])
|
||||
S1_inputting_nameplate.upon(got_nameplate, enter=S2_inputting_words,
|
||||
outputs=[do_middle_input])
|
||||
S2_inputting_words.upon(finished_input, enter=S4_known,
|
||||
outputs=[do_finish_input])
|
||||
S0_idle.upon(allocate_code, enter=S3_allocating, outputs=[do_start_allocate])
|
||||
S3_allocating.upon(allocated, enter=S4_known, outputs=[do_finish_allocate])
|
||||
|
|
|
@ -16,7 +16,6 @@ class Input(object):
|
|||
def __attrs_post_init__(self):
|
||||
self._nameplate = None
|
||||
self._wordlist = None
|
||||
self._claimed_waiter = None
|
||||
|
||||
def wire(self, code, lister):
|
||||
self._C = _interfaces.ICode(code)
|
||||
|
@ -25,23 +24,23 @@ class Input(object):
|
|||
@m.state(initial=True)
|
||||
def S0_idle(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S1_nameplate(self): pass # pragma: no cover
|
||||
def S1_typing_nameplate(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S2_code_no_wordlist(self): pass # pragma: no cover
|
||||
def S2_typing_code_no_wordlist(self): pass # pragma: no cover
|
||||
@m.state()
|
||||
def S3_code_yes_wordlist(self): pass # pragma: no cover
|
||||
def S3_typing_code_yes_wordlist(self): pass # pragma: no cover
|
||||
@m.state(terminal=True)
|
||||
def S4_done(self): pass # pragma: no cover
|
||||
|
||||
# from Code
|
||||
@m.input()
|
||||
def start(self): pass
|
||||
def start(self, input_helper): pass
|
||||
|
||||
# from Lister
|
||||
@m.input()
|
||||
def got_nameplates(self, nameplates): pass
|
||||
|
||||
# from Nameplate??
|
||||
# from Nameplate
|
||||
@m.input()
|
||||
def got_wordlist(self, wordlist): pass
|
||||
|
||||
|
@ -49,58 +48,62 @@ class Input(object):
|
|||
@m.input()
|
||||
def refresh_nameplates(self): pass
|
||||
@m.input()
|
||||
def _choose_nameplate(self, nameplate): pass
|
||||
def choose_nameplate(self, nameplate): pass
|
||||
@m.input()
|
||||
def choose_words(self, words): pass
|
||||
|
||||
@m.output()
|
||||
def L_refresh_nameplates(self):
|
||||
self._L.refresh_nameplates()
|
||||
@m.output()
|
||||
def start_and_L_refresh_nameplates(self, input_helper):
|
||||
def do_start(self, input_helper):
|
||||
self._input_helper = input_helper
|
||||
self._L.refresh_nameplates()
|
||||
@m.output()
|
||||
def stash_wordlist_and_notify(self, wordlist):
|
||||
self._wordlist = wordlist
|
||||
if self._claimed_waiter:
|
||||
self._claimed_waiter.callback(None)
|
||||
del self._claimed_waiter
|
||||
def do_refresh(self):
|
||||
self._L.refresh_nameplates()
|
||||
@m.output()
|
||||
def stash_nameplate(self, nameplate):
|
||||
def do_nameplate(self, nameplate):
|
||||
self._nameplate = nameplate
|
||||
@m.output()
|
||||
def C_got_nameplate(self, nameplate):
|
||||
self._C.got_nameplate(nameplate)
|
||||
@m.output()
|
||||
def do_wordlist(self, wordlist):
|
||||
self._wordlist = wordlist
|
||||
|
||||
@m.output()
|
||||
def finished(self, words):
|
||||
def do_words(self, words):
|
||||
code = self._nameplate + "-" + words
|
||||
self._C.finished_input(code)
|
||||
|
||||
S0_idle.upon(start, enter=S1_nameplate, outputs=[L_refresh_nameplates])
|
||||
S1_nameplate.upon(refresh_nameplates, enter=S1_nameplate,
|
||||
outputs=[L_refresh_nameplates])
|
||||
S1_nameplate.upon(_choose_nameplate, enter=S2_code_no_wordlist,
|
||||
outputs=[stash_nameplate, C_got_nameplate])
|
||||
S2_code_no_wordlist.upon(got_wordlist, enter=S3_code_yes_wordlist,
|
||||
outputs=[stash_wordlist_and_notify])
|
||||
S2_code_no_wordlist.upon(choose_words, enter=S4_done, outputs=[finished])
|
||||
S3_code_yes_wordlist.upon(choose_words, enter=S4_done, outputs=[finished])
|
||||
S0_idle.upon(start, enter=S1_typing_nameplate, outputs=[do_start])
|
||||
S1_typing_nameplate.upon(refresh_nameplates, enter=S1_typing_nameplate,
|
||||
outputs=[do_refresh])
|
||||
S1_typing_nameplate.upon(choose_nameplate, enter=S2_typing_code_no_wordlist,
|
||||
outputs=[do_nameplate])
|
||||
S2_typing_code_no_wordlist.upon(got_wordlist,
|
||||
enter=S3_typing_code_yes_wordlist,
|
||||
outputs=[do_wordlist])
|
||||
S2_typing_code_no_wordlist.upon(choose_words, enter=S4_done,
|
||||
outputs=[do_words])
|
||||
S2_typing_code_no_wordlist.upon(got_nameplates,
|
||||
enter=S2_typing_code_no_wordlist, outputs=[])
|
||||
S3_typing_code_yes_wordlist.upon(choose_words, enter=S4_done,
|
||||
outputs=[do_words])
|
||||
S3_typing_code_yes_wordlist.upon(got_nameplates,
|
||||
enter=S3_typing_code_yes_wordlist,
|
||||
outputs=[])
|
||||
S4_done.upon(got_nameplates, enter=S4_done, outputs=[])
|
||||
S4_done.upon(got_wordlist, enter=S4_done, outputs=[])
|
||||
|
||||
# methods for the CodeInputHelper to use
|
||||
#refresh_nameplates/_choose_nameplate/choose_words: @m.input methods
|
||||
|
||||
def get_nameplate_completions(self, prefix):
|
||||
lp = len(prefix)
|
||||
completions = []
|
||||
for nameplate in self._nameplates
|
||||
pass
|
||||
def choose_nameplate(self, nameplate):
|
||||
if self._claimed_waiter is not None:
|
||||
raise X
|
||||
d = self._claimed_waiter = defer.Deferred()
|
||||
self._choose_nameplate(nameplate)
|
||||
for nameplate in self._nameplates:
|
||||
if nameplate.startswith(prefix):
|
||||
completions.append(nameplate[lp:])
|
||||
return completions
|
||||
|
||||
def get_word_completions(self, prefix):
|
||||
pass
|
||||
|
||||
if self._wordlist:
|
||||
return self._wordlist.get_completions(prefix)
|
||||
return []
|
||||
|
|
|
@ -33,6 +33,13 @@ class ITiming(Interface):
|
|||
pass
|
||||
class ITorManager(Interface):
|
||||
pass
|
||||
class IWordlist(Interface):
|
||||
def choose_words(length):
|
||||
"""Randomly select LENGTH words, join them with hyphens, return the
|
||||
result."""
|
||||
def get_completions(prefix):
|
||||
"""Return a list of all suffixes that could complete the given
|
||||
prefix."""
|
||||
|
||||
class IJournal(Interface): # TODO: this needs to be public
|
||||
pass
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
from __future__ import print_function, absolute_import, unicode_literals
|
||||
from zope.interface import implementer
|
||||
from attr import attrib
|
||||
from attr.validators import provides
|
||||
from automat import MethodicalMachine
|
||||
from . import _interfaces
|
||||
|
||||
@implementer(_interfaces.ILister)
|
||||
class Lister(object):
|
||||
_timing = attrib(validator=provides(_interfaces.ITiming))
|
||||
m = MethodicalMachine()
|
||||
@m.setTrace()
|
||||
def set_trace(): pass # pragma: no cover
|
||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import print_function, absolute_import, unicode_literals
|
|||
from zope.interface import implementer
|
||||
from automat import MethodicalMachine
|
||||
from . import _interfaces
|
||||
from ._wordlist import PGPWordList
|
||||
|
||||
@implementer(_interfaces.INameplate)
|
||||
class Nameplate(object):
|
||||
|
@ -12,8 +13,9 @@ class Nameplate(object):
|
|||
def __init__(self):
|
||||
self._nameplate = None
|
||||
|
||||
def wire(self, mailbox, rendezvous_connector, terminator):
|
||||
def wire(self, mailbox, input, rendezvous_connector, terminator):
|
||||
self._M = _interfaces.IMailbox(mailbox)
|
||||
self._I = _interfaces.IInput(input)
|
||||
self._RC = _interfaces.IRendezvousConnector(rendezvous_connector)
|
||||
self._T = _interfaces.ITerminator(terminator)
|
||||
|
||||
|
@ -96,6 +98,11 @@ class Nameplate(object):
|
|||
# when invoked via M.connected(), we must use the stored nameplate
|
||||
self._RC.tx_claim(self._nameplate)
|
||||
@m.output()
|
||||
def I_got_wordlist(self, mailbox):
|
||||
# TODO select wordlist based on nameplate properties, in rx_claimed
|
||||
wordlist = PGPWordList()
|
||||
self._I.got_wordlist(wordlist)
|
||||
@m.output()
|
||||
def M_got_mailbox(self, mailbox):
|
||||
self._M.got_mailbox(mailbox)
|
||||
@m.output()
|
||||
|
@ -120,7 +127,7 @@ class Nameplate(object):
|
|||
S2A.upon(connected, enter=S2B, outputs=[RC_tx_claim])
|
||||
S2A.upon(close, enter=S4A, outputs=[])
|
||||
S2B.upon(lost, enter=S2A, outputs=[])
|
||||
S2B.upon(rx_claimed, enter=S3B, outputs=[M_got_mailbox])
|
||||
S2B.upon(rx_claimed, enter=S3B, outputs=[I_got_wordlist, M_got_mailbox])
|
||||
S2B.upon(close, enter=S4B, outputs=[RC_tx_release])
|
||||
|
||||
S3A.upon(connected, enter=S3B, outputs=[])
|
||||
|
|
182
src/wormhole/_wordlist.py
Normal file
182
src/wormhole/_wordlist.py
Normal file
|
@ -0,0 +1,182 @@
|
|||
from __future__ import unicode_literals
|
||||
import os
|
||||
|
||||
# The PGP Word List, which maps bytes to phonetically-distinct words. There
|
||||
# are two lists, even and odd, and encodings should alternate between then to
|
||||
# detect dropped words. https://en.wikipedia.org/wiki/PGP_Words
|
||||
|
||||
# Thanks to Warren Guy for transcribing them:
|
||||
# https://github.com/warrenguy/javascript-pgp-word-list
|
||||
|
||||
from binascii import unhexlify
|
||||
|
||||
raw_words = {
|
||||
'00': ['aardvark', 'adroitness'], '01': ['absurd', 'adviser'],
|
||||
'02': ['accrue', 'aftermath'], '03': ['acme', 'aggregate'],
|
||||
'04': ['adrift', 'alkali'], '05': ['adult', 'almighty'],
|
||||
'06': ['afflict', 'amulet'], '07': ['ahead', 'amusement'],
|
||||
'08': ['aimless', 'antenna'], '09': ['Algol', 'applicant'],
|
||||
'0A': ['allow', 'Apollo'], '0B': ['alone', 'armistice'],
|
||||
'0C': ['ammo', 'article'], '0D': ['ancient', 'asteroid'],
|
||||
'0E': ['apple', 'Atlantic'], '0F': ['artist', 'atmosphere'],
|
||||
'10': ['assume', 'autopsy'], '11': ['Athens', 'Babylon'],
|
||||
'12': ['atlas', 'backwater'], '13': ['Aztec', 'barbecue'],
|
||||
'14': ['baboon', 'belowground'], '15': ['backfield', 'bifocals'],
|
||||
'16': ['backward', 'bodyguard'], '17': ['banjo', 'bookseller'],
|
||||
'18': ['beaming', 'borderline'], '19': ['bedlamp', 'bottomless'],
|
||||
'1A': ['beehive', 'Bradbury'], '1B': ['beeswax', 'bravado'],
|
||||
'1C': ['befriend', 'Brazilian'], '1D': ['Belfast', 'breakaway'],
|
||||
'1E': ['berserk', 'Burlington'], '1F': ['billiard', 'businessman'],
|
||||
'20': ['bison', 'butterfat'], '21': ['blackjack', 'Camelot'],
|
||||
'22': ['blockade', 'candidate'], '23': ['blowtorch', 'cannonball'],
|
||||
'24': ['bluebird', 'Capricorn'], '25': ['bombast', 'caravan'],
|
||||
'26': ['bookshelf', 'caretaker'], '27': ['brackish', 'celebrate'],
|
||||
'28': ['breadline', 'cellulose'], '29': ['breakup', 'certify'],
|
||||
'2A': ['brickyard', 'chambermaid'], '2B': ['briefcase', 'Cherokee'],
|
||||
'2C': ['Burbank', 'Chicago'], '2D': ['button', 'clergyman'],
|
||||
'2E': ['buzzard', 'coherence'], '2F': ['cement', 'combustion'],
|
||||
'30': ['chairlift', 'commando'], '31': ['chatter', 'company'],
|
||||
'32': ['checkup', 'component'], '33': ['chisel', 'concurrent'],
|
||||
'34': ['choking', 'confidence'], '35': ['chopper', 'conformist'],
|
||||
'36': ['Christmas', 'congregate'], '37': ['clamshell', 'consensus'],
|
||||
'38': ['classic', 'consulting'], '39': ['classroom', 'corporate'],
|
||||
'3A': ['cleanup', 'corrosion'], '3B': ['clockwork', 'councilman'],
|
||||
'3C': ['cobra', 'crossover'], '3D': ['commence', 'crucifix'],
|
||||
'3E': ['concert', 'cumbersome'], '3F': ['cowbell', 'customer'],
|
||||
'40': ['crackdown', 'Dakota'], '41': ['cranky', 'decadence'],
|
||||
'42': ['crowfoot', 'December'], '43': ['crucial', 'decimal'],
|
||||
'44': ['crumpled', 'designing'], '45': ['crusade', 'detector'],
|
||||
'46': ['cubic', 'detergent'], '47': ['dashboard', 'determine'],
|
||||
'48': ['deadbolt', 'dictator'], '49': ['deckhand', 'dinosaur'],
|
||||
'4A': ['dogsled', 'direction'], '4B': ['dragnet', 'disable'],
|
||||
'4C': ['drainage', 'disbelief'], '4D': ['dreadful', 'disruptive'],
|
||||
'4E': ['drifter', 'distortion'], '4F': ['dropper', 'document'],
|
||||
'50': ['drumbeat', 'embezzle'], '51': ['drunken', 'enchanting'],
|
||||
'52': ['Dupont', 'enrollment'], '53': ['dwelling', 'enterprise'],
|
||||
'54': ['eating', 'equation'], '55': ['edict', 'equipment'],
|
||||
'56': ['egghead', 'escapade'], '57': ['eightball', 'Eskimo'],
|
||||
'58': ['endorse', 'everyday'], '59': ['endow', 'examine'],
|
||||
'5A': ['enlist', 'existence'], '5B': ['erase', 'exodus'],
|
||||
'5C': ['escape', 'fascinate'], '5D': ['exceed', 'filament'],
|
||||
'5E': ['eyeglass', 'finicky'], '5F': ['eyetooth', 'forever'],
|
||||
'60': ['facial', 'fortitude'], '61': ['fallout', 'frequency'],
|
||||
'62': ['flagpole', 'gadgetry'], '63': ['flatfoot', 'Galveston'],
|
||||
'64': ['flytrap', 'getaway'], '65': ['fracture', 'glossary'],
|
||||
'66': ['framework', 'gossamer'], '67': ['freedom', 'graduate'],
|
||||
'68': ['frighten', 'gravity'], '69': ['gazelle', 'guitarist'],
|
||||
'6A': ['Geiger', 'hamburger'], '6B': ['glitter', 'Hamilton'],
|
||||
'6C': ['glucose', 'handiwork'], '6D': ['goggles', 'hazardous'],
|
||||
'6E': ['goldfish', 'headwaters'], '6F': ['gremlin', 'hemisphere'],
|
||||
'70': ['guidance', 'hesitate'], '71': ['hamlet', 'hideaway'],
|
||||
'72': ['highchair', 'holiness'], '73': ['hockey', 'hurricane'],
|
||||
'74': ['indoors', 'hydraulic'], '75': ['indulge', 'impartial'],
|
||||
'76': ['inverse', 'impetus'], '77': ['involve', 'inception'],
|
||||
'78': ['island', 'indigo'], '79': ['jawbone', 'inertia'],
|
||||
'7A': ['keyboard', 'infancy'], '7B': ['kickoff', 'inferno'],
|
||||
'7C': ['kiwi', 'informant'], '7D': ['klaxon', 'insincere'],
|
||||
'7E': ['locale', 'insurgent'], '7F': ['lockup', 'integrate'],
|
||||
'80': ['merit', 'intention'], '81': ['minnow', 'inventive'],
|
||||
'82': ['miser', 'Istanbul'], '83': ['Mohawk', 'Jamaica'],
|
||||
'84': ['mural', 'Jupiter'], '85': ['music', 'leprosy'],
|
||||
'86': ['necklace', 'letterhead'], '87': ['Neptune', 'liberty'],
|
||||
'88': ['newborn', 'maritime'], '89': ['nightbird', 'matchmaker'],
|
||||
'8A': ['Oakland', 'maverick'], '8B': ['obtuse', 'Medusa'],
|
||||
'8C': ['offload', 'megaton'], '8D': ['optic', 'microscope'],
|
||||
'8E': ['orca', 'microwave'], '8F': ['payday', 'midsummer'],
|
||||
'90': ['peachy', 'millionaire'], '91': ['pheasant', 'miracle'],
|
||||
'92': ['physique', 'misnomer'], '93': ['playhouse', 'molasses'],
|
||||
'94': ['Pluto', 'molecule'], '95': ['preclude', 'Montana'],
|
||||
'96': ['prefer', 'monument'], '97': ['preshrunk', 'mosquito'],
|
||||
'98': ['printer', 'narrative'], '99': ['prowler', 'nebula'],
|
||||
'9A': ['pupil', 'newsletter'], '9B': ['puppy', 'Norwegian'],
|
||||
'9C': ['python', 'October'], '9D': ['quadrant', 'Ohio'],
|
||||
'9E': ['quiver', 'onlooker'], '9F': ['quota', 'opulent'],
|
||||
'A0': ['ragtime', 'Orlando'], 'A1': ['ratchet', 'outfielder'],
|
||||
'A2': ['rebirth', 'Pacific'], 'A3': ['reform', 'pandemic'],
|
||||
'A4': ['regain', 'Pandora'], 'A5': ['reindeer', 'paperweight'],
|
||||
'A6': ['rematch', 'paragon'], 'A7': ['repay', 'paragraph'],
|
||||
'A8': ['retouch', 'paramount'], 'A9': ['revenge', 'passenger'],
|
||||
'AA': ['reward', 'pedigree'], 'AB': ['rhythm', 'Pegasus'],
|
||||
'AC': ['ribcage', 'penetrate'], 'AD': ['ringbolt', 'perceptive'],
|
||||
'AE': ['robust', 'performance'], 'AF': ['rocker', 'pharmacy'],
|
||||
'B0': ['ruffled', 'phonetic'], 'B1': ['sailboat', 'photograph'],
|
||||
'B2': ['sawdust', 'pioneer'], 'B3': ['scallion', 'pocketful'],
|
||||
'B4': ['scenic', 'politeness'], 'B5': ['scorecard', 'positive'],
|
||||
'B6': ['Scotland', 'potato'], 'B7': ['seabird', 'processor'],
|
||||
'B8': ['select', 'provincial'], 'B9': ['sentence', 'proximate'],
|
||||
'BA': ['shadow', 'puberty'], 'BB': ['shamrock', 'publisher'],
|
||||
'BC': ['showgirl', 'pyramid'], 'BD': ['skullcap', 'quantity'],
|
||||
'BE': ['skydive', 'racketeer'], 'BF': ['slingshot', 'rebellion'],
|
||||
'C0': ['slowdown', 'recipe'], 'C1': ['snapline', 'recover'],
|
||||
'C2': ['snapshot', 'repellent'], 'C3': ['snowcap', 'replica'],
|
||||
'C4': ['snowslide', 'reproduce'], 'C5': ['solo', 'resistor'],
|
||||
'C6': ['southward', 'responsive'], 'C7': ['soybean', 'retraction'],
|
||||
'C8': ['spaniel', 'retrieval'], 'C9': ['spearhead', 'retrospect'],
|
||||
'CA': ['spellbind', 'revenue'], 'CB': ['spheroid', 'revival'],
|
||||
'CC': ['spigot', 'revolver'], 'CD': ['spindle', 'sandalwood'],
|
||||
'CE': ['spyglass', 'sardonic'], 'CF': ['stagehand', 'Saturday'],
|
||||
'D0': ['stagnate', 'savagery'], 'D1': ['stairway', 'scavenger'],
|
||||
'D2': ['standard', 'sensation'], 'D3': ['stapler', 'sociable'],
|
||||
'D4': ['steamship', 'souvenir'], 'D5': ['sterling', 'specialist'],
|
||||
'D6': ['stockman', 'speculate'], 'D7': ['stopwatch', 'stethoscope'],
|
||||
'D8': ['stormy', 'stupendous'], 'D9': ['sugar', 'supportive'],
|
||||
'DA': ['surmount', 'surrender'], 'DB': ['suspense', 'suspicious'],
|
||||
'DC': ['sweatband', 'sympathy'], 'DD': ['swelter', 'tambourine'],
|
||||
'DE': ['tactics', 'telephone'], 'DF': ['talon', 'therapist'],
|
||||
'E0': ['tapeworm', 'tobacco'], 'E1': ['tempest', 'tolerance'],
|
||||
'E2': ['tiger', 'tomorrow'], 'E3': ['tissue', 'torpedo'],
|
||||
'E4': ['tonic', 'tradition'], 'E5': ['topmost', 'travesty'],
|
||||
'E6': ['tracker', 'trombonist'], 'E7': ['transit', 'truncated'],
|
||||
'E8': ['trauma', 'typewriter'], 'E9': ['treadmill', 'ultimate'],
|
||||
'EA': ['Trojan', 'undaunted'], 'EB': ['trouble', 'underfoot'],
|
||||
'EC': ['tumor', 'unicorn'], 'ED': ['tunnel', 'unify'],
|
||||
'EE': ['tycoon', 'universe'], 'EF': ['uncut', 'unravel'],
|
||||
'F0': ['unearth', 'upcoming'], 'F1': ['unwind', 'vacancy'],
|
||||
'F2': ['uproot', 'vagabond'], 'F3': ['upset', 'vertigo'],
|
||||
'F4': ['upshot', 'Virginia'], 'F5': ['vapor', 'visitor'],
|
||||
'F6': ['village', 'vocalist'], 'F7': ['virus', 'voyager'],
|
||||
'F8': ['Vulcan', 'warranty'], 'F9': ['waffle', 'Waterloo'],
|
||||
'FA': ['wallet', 'whimsical'], 'FB': ['watchword', 'Wichita'],
|
||||
'FC': ['wayside', 'Wilmington'], 'FD': ['willow', 'Wyoming'],
|
||||
'FE': ['woodlark', 'yesteryear'], 'FF': ['Zulu', 'Yucatan']
|
||||
};
|
||||
|
||||
byte_to_even_word = dict([(unhexlify(k.encode("ascii")), both_words[0])
|
||||
for k,both_words
|
||||
in raw_words.items()])
|
||||
|
||||
byte_to_odd_word = dict([(unhexlify(k.encode("ascii")), both_words[1])
|
||||
for k,both_words
|
||||
in raw_words.items()])
|
||||
|
||||
even_words_lowercase, odd_words_lowercase = set(), set()
|
||||
|
||||
for k,both_words in raw_words.items():
|
||||
even_word, odd_word = both_words
|
||||
even_words_lowercase.add(even_word.lower())
|
||||
odd_words_lowercase.add(odd_word.lower())
|
||||
|
||||
class PGPWordList(object):
|
||||
def get_completions(self, prefix):
|
||||
# start with the odd words
|
||||
if prefix.count("-") % 2 == 0:
|
||||
words = odd_words_lowercase
|
||||
else:
|
||||
words = even_words_lowercase
|
||||
last_partial_word = prefix.split("-")[-1]
|
||||
lp = len(last_partial_word)
|
||||
completions = []
|
||||
for word in words:
|
||||
if word.startswith(prefix):
|
||||
completions.append(word[lp:])
|
||||
return completions
|
||||
|
||||
def choose_words(self, length):
|
||||
words = []
|
||||
for i in range(length):
|
||||
# we start with an "odd word"
|
||||
if i % 2 == 0:
|
||||
words.append(byte_to_odd_word[os.urandom(1)].lower())
|
||||
else:
|
||||
words.append(byte_to_even_word[os.urandom(1)].lower())
|
||||
return "-".join(words)
|
Loading…
Reference in New Issue
Block a user