@@ -44,6 +44,11 @@ pub enum WormholeCoreError {
4444 /// The server sent us an error message
4545 #[ error( "Received error message from server: {}" , _0) ]
4646 Server ( Box < str > ) ,
47+ #[ error(
48+ "Server wants one of {:?} for permissions, but we don't suppport any of these" ,
49+ _0
50+ ) ]
51+ Login ( Vec < String > ) ,
4752 #[ error(
4853 "Key confirmation failed. If you didn't mistype the code, \
4954 this is a sign of an attacker guessing passwords. Please try \
@@ -81,11 +86,16 @@ impl From<std::convert::Infallible> for WormholeCoreError {
8186// TODO manually implement Debug again to display some Vec<u8> as string and others as hex
8287#[ derive( Debug , derive_more:: Display ) ]
8388pub enum APIEvent {
84- #[ display( fmt = "ConnectedToServer {{ welcome: {}, code: {} }}" , welcome, code) ]
89+ #[ display(
90+ fmt = "ConnectedToServer {{ motd: {} }}" ,
91+ r#"motd.as_deref().unwrap_or("<none>")"#
92+ ) ]
8593 ConnectedToServer {
8694 /// A little welcome message from the server (message of the day and such)
87- // TODO we can actually provide more structure than a "value", see the protocol
88- welcome : serde_json:: Value ,
95+ motd : Option < String > ,
96+ } ,
97+ #[ display( fmt = "GotCode {{ code: {} }}" , code) ]
98+ GotCode {
8999 /// Share this with your peer so they can connect
90100 code : Code ,
91101 } ,
@@ -126,6 +136,12 @@ pub enum Mood {
126136
127137#[ derive( Debug , derive_more:: Display ) ]
128138enum State {
139+ #[ display( fmt = "" ) ] // TODO
140+ WaitForWelcome {
141+ versions : serde_json:: Value ,
142+ code_provider : CodeProvider ,
143+ } ,
144+
129145 #[ display(
130146 fmt = "AllocatingNameplate {{ wordlist: <{} words>, side: {}, versions: {} }}" ,
131147 "wordlist.num_words" ,
@@ -200,39 +216,12 @@ pub async fn run(
200216
201217 let mut actions: VecDeque < Event > = VecDeque :: new ( ) ;
202218
203- /* Bootstrapping code */
204- let mut state;
205- actions. push_back ( OutboundMessage :: bind ( appid. clone ( ) , side. clone ( ) ) . into ( ) ) ;
206- /* A mini state machine to track that messaage. It's okay for now, but modularize if it starts growing. */
207- let mut welcome_message = None ;
208-
209- match code_provider {
210- CodeProvider :: AllocateCode ( num_words) => {
211- // TODO: provide choice of wordlists
212- let wordlist = Arc :: new ( wordlist:: default_wordlist ( num_words) ) ;
213- actions. push_back ( OutboundMessage :: Allocate . into ( ) ) ;
214-
215- state = State :: AllocatingNameplate {
216- wordlist,
217- side : side. clone ( ) ,
218- versions,
219- } ;
220- } ,
221- CodeProvider :: SetCode ( code) => {
222- let code_string = code. to_string ( ) ;
223- let nc: Vec < & str > = code_string. splitn ( 2 , '-' ) . collect ( ) ;
224- let nameplate = Nameplate :: new ( nc[ 0 ] ) ;
225- actions. push_back ( OutboundMessage :: claim ( nameplate. clone ( ) ) . into ( ) ) ;
226-
227- state = State :: ClaimingNameplate {
228- nameplate,
229- code : Code ( code) ,
230- side : side. clone ( ) ,
231- versions,
232- } ;
233- } ,
234- }
219+ let mut state = State :: WaitForWelcome {
220+ versions,
221+ code_provider,
222+ } ;
235223
224+ /* The usual main loop */
236225 loop {
237226 let e = match actions. pop_front ( ) {
238227 Some ( event) => Ok ( event) ,
@@ -269,7 +258,72 @@ pub async fn run(
269258 use self :: { events:: Event :: * , server_messages:: InboundMessage } ;
270259 match e {
271260 FromIO ( InboundMessage :: Welcome { welcome } ) => {
272- welcome_message = Some ( welcome) ;
261+ match state {
262+ State :: WaitForWelcome {
263+ versions,
264+ code_provider,
265+ } => {
266+ use server_messages:: { PermissionRequired , SubmitPermission } ;
267+
268+ actions
269+ . push_back ( APIEvent :: ConnectedToServer { motd : welcome. motd } . into ( ) ) ;
270+
271+ match welcome. permission_required {
272+ Some ( PermissionRequired {
273+ hashcash : Some ( hashcash) ,
274+ ..
275+ } ) => {
276+ let token = hashcash:: Token :: new ( hashcash. resource , hashcash. bits ) ;
277+ actions. push_back (
278+ OutboundMessage :: SubmitPermission ( SubmitPermission :: Hashcash {
279+ stamp : token. to_string ( ) ,
280+ } )
281+ . into ( ) ,
282+ )
283+ } ,
284+ Some ( PermissionRequired { none : true , .. } ) => ( ) ,
285+ Some ( PermissionRequired { other, .. } ) => {
286+ /* We can't actually log in :/ */
287+ actions. push_back ( Event :: ShutDown ( Err ( WormholeCoreError :: Login (
288+ // TODO use `into_keys` once stable and remove the `cloned`
289+ other. keys ( ) . cloned ( ) . collect ( ) ,
290+ ) ) ) ) ;
291+ } ,
292+ None => ( ) ,
293+ }
294+
295+ actions
296+ . push_back ( OutboundMessage :: bind ( appid. clone ( ) , side. clone ( ) ) . into ( ) ) ;
297+
298+ match code_provider {
299+ CodeProvider :: AllocateCode ( num_words) => {
300+ // TODO: provide choice of wordlists
301+ let wordlist = Arc :: new ( wordlist:: default_wordlist ( num_words) ) ;
302+ actions. push_back ( OutboundMessage :: Allocate . into ( ) ) ;
303+
304+ state = State :: AllocatingNameplate {
305+ wordlist,
306+ side : side. clone ( ) ,
307+ versions,
308+ } ;
309+ } ,
310+ CodeProvider :: SetCode ( code) => {
311+ let code_string = code. to_string ( ) ;
312+ let nc: Vec < & str > = code_string. splitn ( 2 , '-' ) . collect ( ) ;
313+ let nameplate = Nameplate :: new ( nc[ 0 ] ) ;
314+ actions. push_back ( OutboundMessage :: claim ( nameplate. clone ( ) ) . into ( ) ) ;
315+
316+ state = State :: ClaimingNameplate {
317+ nameplate,
318+ code : Code ( code) ,
319+ side : side. clone ( ) ,
320+ versions,
321+ } ;
322+ } ,
323+ }
324+ } ,
325+ _ => unreachable ! ( ) ,
326+ }
273327 } ,
274328 FromIO ( InboundMessage :: Claimed { mailbox } ) => {
275329 match state {
@@ -291,19 +345,7 @@ pub async fn run(
291345 & code,
292346 ) ) ) ;
293347
294- actions. push_back (
295- APIEvent :: ConnectedToServer {
296- /* TODO Is the welcome message mandatory or optional? */
297- welcome : welcome_message
298- . take ( )
299- . ok_or_else ( || {
300- anyhow:: format_err!( "Didn't get a welcome message" )
301- } )
302- . unwrap ( ) ,
303- code,
304- }
305- . into ( ) ,
306- ) ;
348+ actions. push_back ( APIEvent :: GotCode { code } . into ( ) ) ;
307349 } ,
308350 State :: Closing { .. } => { /* This may happen. Ignore it. */ } ,
309351 _ => {
@@ -420,6 +462,13 @@ pub async fn run(
420462 }
421463 } ,
422464 ShutDown ( result) => match state {
465+ State :: WaitForWelcome { .. } => {
466+ state = State :: Closing {
467+ await_nameplate_release : false ,
468+ await_mailbox_close : false ,
469+ result,
470+ } ;
471+ } ,
423472 State :: AllocatingNameplate { .. } => {
424473 state = State :: Closing {
425474 await_nameplate_release : false ,
0 commit comments