@@ -31,7 +31,7 @@ const SPEND_KEY_CHILD_ID: ChildId = ChildId(0);
3131/// Child ID used to derive the blinding key from a service plan's DerivableSecret
3232const BLINDING_KEY_CHILD_ID : ChildId = ChildId ( 1 ) ;
3333
34- #[ derive( Debug , Serialize , Deserialize , Clone , Default ) ]
34+ #[ derive( Debug , Serialize , Deserialize , Clone , Default , PartialEq , Eq ) ]
3535pub struct TokenStorage {
3636 // (service_id, plan_id): number of times used
3737 pub map : HashMap < ServicePlanIndex , u32 > ,
@@ -64,21 +64,52 @@ impl TokenStorage {
6464 }
6565}
6666
67- #[ derive( Debug , Serialize , Deserialize , Clone , Default , Eq , PartialEq , Hash ) ]
67+ #[ derive( Debug , Clone , Default , Eq , PartialEq , Hash ) ]
6868pub struct ServicePlanIndex {
6969 pub service_id : u32 ,
7070 pub plan_id : u32 ,
7171}
7272
73- #[ derive( Debug , Serialize , Deserialize , Clone ) ]
73+ impl Serialize for ServicePlanIndex {
74+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
75+ where
76+ S : serde:: Serializer ,
77+ {
78+ let string = format ! ( "{}-{}" , self . service_id, self . plan_id) ;
79+ serializer. serialize_str ( & string)
80+ }
81+ }
82+
83+ impl < ' a > Deserialize < ' a > for ServicePlanIndex {
84+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
85+ where
86+ D : serde:: Deserializer < ' a > ,
87+ {
88+ let uri = String :: deserialize ( deserializer) ?;
89+
90+ let parts: Vec < & str > = uri. split ( '-' ) . collect ( ) ;
91+ if parts. len ( ) != 2 {
92+ return Err ( serde:: de:: Error :: custom ( "Invalid ServicePlanIndex" ) ) ;
93+ }
94+
95+ let service_id = parts[ 0 ] . parse :: < u32 > ( ) . map_err ( serde:: de:: Error :: custom) ?;
96+ let plan_id = parts[ 1 ] . parse :: < u32 > ( ) . map_err ( serde:: de:: Error :: custom) ?;
97+ Ok ( ServicePlanIndex {
98+ service_id,
99+ plan_id,
100+ } )
101+ }
102+ }
103+
104+ #[ derive( Debug , Serialize , Deserialize , Clone , PartialEq , Eq ) ]
74105pub struct UnsignedToken {
75106 pub counter : u32 ,
76107 pub service_id : u32 ,
77108 pub plan_id : u32 ,
78109 pub blinded_message : BlindedMessage ,
79110}
80111
81- #[ derive( Debug , Serialize , Deserialize , Clone ) ]
112+ #[ derive( Debug , Serialize , Deserialize , Clone , PartialEq , Eq ) ]
82113pub struct SignedToken {
83114 pub counter : u32 ,
84115 pub service_id : u32 ,
@@ -219,7 +250,11 @@ impl<S: MutinyStorage> BlindAuthClient<S> {
219250 // Maybe have an "issued" tokens call so we can see if we're caught up with the server?
220251 self . storage
221252 . insert_token_storage ( token_storage_guard. clone ( ) )
222- . await ?;
253+ . await
254+ . map_err ( |e| {
255+ log_error ! ( self . logger, "could not save token storage: {e:?}" ) ;
256+ e
257+ } ) ?;
223258
224259 Ok ( signed_token)
225260 }
@@ -370,3 +405,46 @@ fn create_blind_auth_secret(
370405 BLINDAUTH_CLIENT_NONCE ,
371406 ) )
372407}
408+
409+ #[ cfg( test) ]
410+ mod test {
411+ use crate :: blindauth:: { ServicePlanIndex , SignedToken , TokenStorage } ;
412+ use tbs:: { BlindedMessage , BlindedSignature } ;
413+
414+ #[ test]
415+ fn test_token_storage_serialization ( ) {
416+ let mut map = std:: collections:: HashMap :: new ( ) ;
417+ map. insert (
418+ ServicePlanIndex {
419+ service_id : 1 ,
420+ plan_id : 1 ,
421+ } ,
422+ 1 ,
423+ ) ;
424+
425+ let token = SignedToken {
426+ counter : 1 ,
427+ service_id : 1 ,
428+ plan_id : 1 ,
429+ blinded_message : BlindedMessage ( Default :: default ( ) ) ,
430+ blind_sig : BlindedSignature ( Default :: default ( ) ) ,
431+ spent : false ,
432+ } ;
433+
434+ let storage = TokenStorage {
435+ map,
436+ tokens : vec ! [ token] ,
437+ version : 0 ,
438+ } ;
439+
440+ let serialized = serde_json:: to_string ( & storage) . unwrap ( ) ;
441+ let deserialized: TokenStorage = serde_json:: from_str ( & serialized) . unwrap ( ) ;
442+
443+ assert_eq ! ( storage, deserialized) ;
444+
445+ // test backwards compatibility
446+ let string = "{\" map\" :{\" 1-1\" :1},\" tokens\" :[{\" counter\" :1,\" service_id\" :1,\" plan_id\" :1,\" blinded_message\" :\" c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\" ,\" blind_sig\" :\" c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\" ,\" spent\" :false}],\" version\" :0}" ;
447+ let deserialized: TokenStorage = serde_json:: from_str ( string) . unwrap ( ) ;
448+ assert_eq ! ( storage, deserialized) ;
449+ }
450+ }
0 commit comments