@@ -44,6 +44,11 @@ pub enum WormholeCoreError {
44
44
/// The server sent us an error message
45
45
#[ error( "Received error message from server: {}" , _0) ]
46
46
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 > ) ,
47
52
#[ error(
48
53
"Key confirmation failed. If you didn't mistype the code, \
49
54
this is a sign of an attacker guessing passwords. Please try \
@@ -81,11 +86,16 @@ impl From<std::convert::Infallible> for WormholeCoreError {
81
86
// TODO manually implement Debug again to display some Vec<u8> as string and others as hex
82
87
#[ derive( Debug , derive_more:: Display ) ]
83
88
pub 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
+ ) ]
85
93
ConnectedToServer {
86
94
/// 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 {
89
99
/// Share this with your peer so they can connect
90
100
code : Code ,
91
101
} ,
@@ -126,6 +136,12 @@ pub enum Mood {
126
136
127
137
#[ derive( Debug , derive_more:: Display ) ]
128
138
enum State {
139
+ #[ display( fmt = "" ) ] // TODO
140
+ WaitForWelcome {
141
+ versions : serde_json:: Value ,
142
+ code_provider : CodeProvider ,
143
+ } ,
144
+
129
145
#[ display(
130
146
fmt = "AllocatingNameplate {{ wordlist: <{} words>, side: {}, versions: {} }}" ,
131
147
"wordlist.num_words" ,
@@ -200,39 +216,12 @@ pub async fn run(
200
216
201
217
let mut actions: VecDeque < Event > = VecDeque :: new ( ) ;
202
218
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
+ } ;
235
223
224
+ /* The usual main loop */
236
225
loop {
237
226
let e = match actions. pop_front ( ) {
238
227
Some ( event) => Ok ( event) ,
@@ -269,7 +258,72 @@ pub async fn run(
269
258
use self :: { events:: Event :: * , server_messages:: InboundMessage } ;
270
259
match e {
271
260
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
+ }
273
327
} ,
274
328
FromIO ( InboundMessage :: Claimed { mailbox } ) => {
275
329
match state {
@@ -291,19 +345,7 @@ pub async fn run(
291
345
& code,
292
346
) ) ) ;
293
347
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 ( ) ) ;
307
349
} ,
308
350
State :: Closing { .. } => { /* This may happen. Ignore it. */ } ,
309
351
_ => {
@@ -420,6 +462,13 @@ pub async fn run(
420
462
}
421
463
} ,
422
464
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
+ } ,
423
472
State :: AllocatingNameplate { .. } => {
424
473
state = State :: Closing {
425
474
await_nameplate_release : false ,
0 commit comments