@@ -42,7 +42,7 @@ mod blind_signature;
4242#[ cfg( feature = "nostr" ) ]
4343mod nostr_backup;
4444#[ cfg( all( feature = "tor" , not( target_arch = "wasm32" ) ) ) ]
45- pub use mint_connector:: TorHttpClient ;
45+ pub use mint_connector:: { TorAuthHttpClient , TorHttpClient } ;
4646mod balance;
4747mod builder;
4848mod issue;
@@ -130,6 +130,7 @@ pub struct Wallet {
130130 /// The targeted amount of proofs to have at each size
131131 pub target_proof_count : usize ,
132132 auth_wallet : Arc < TokioRwLock < Option < AuthWallet > > > ,
133+ auth_connector : Option < Arc < dyn AuthMintConnector + Send + Sync > > ,
133134 #[ cfg( feature = "npubcash" ) ]
134135 npubcash_client : Arc < TokioRwLock < Option < Arc < cdk_npubcash:: NpubCashClient > > > > ,
135136 seed : [ u8 ; 64 ] ,
@@ -434,14 +435,24 @@ impl Wallet {
434435 None => {
435436 tracing:: info!( "Mint has auth enabled; creating auth wallet" ) ;
436437
437- let new_auth_wallet = AuthWallet :: new (
438- self . mint_url . clone ( ) ,
439- None ,
440- self . localstore . clone ( ) ,
441- self . metadata_cache . clone ( ) ,
442- protected_endpoints,
443- oidc_client,
444- ) ;
438+ let new_auth_wallet = match self . auth_connector . as_ref ( ) {
439+ Some ( auth_connector) => AuthWallet :: new_with_client (
440+ self . mint_url . clone ( ) ,
441+ self . localstore . clone ( ) ,
442+ self . metadata_cache . clone ( ) ,
443+ protected_endpoints,
444+ oidc_client,
445+ auth_connector. clone ( ) ,
446+ ) ,
447+ None => AuthWallet :: new (
448+ self . mint_url . clone ( ) ,
449+ None ,
450+ self . localstore . clone ( ) ,
451+ self . metadata_cache . clone ( ) ,
452+ protected_endpoints,
453+ oidc_client,
454+ ) ,
455+ } ;
445456 * auth_wallet = Some ( new_auth_wallet. clone ( ) ) ;
446457
447458 self . client
@@ -993,10 +1004,106 @@ impl Drop for Wallet {
9931004
9941005#[ cfg( test) ]
9951006mod tests {
1007+ use std:: sync:: Mutex ;
1008+
1009+ use async_trait:: async_trait;
1010+ use bitcoin:: bip32:: DerivationPath ;
1011+ use bitcoin:: secp256k1:: Secp256k1 ;
1012+ use cdk_common:: nut02:: KeySetVersion ;
1013+ use cdk_common:: nuts:: { KeySet , KeySetInfo , KeysetResponse , MintKeySet } ;
1014+
9961015 use super :: * ;
997- use crate :: nuts:: { BlindSignature , BlindedMessage , PreMint , PreMintSecrets } ;
1016+ use crate :: nuts:: { AuthToken , BlindSignature , BlindedMessage , PreMint , PreMintSecrets } ;
9981017 use crate :: secret:: Secret ;
9991018
1019+ fn build_test_auth_keyset ( seed_byte : u8 ) -> KeySet {
1020+ let secp = Secp256k1 :: new ( ) ;
1021+ let seed = [ seed_byte; 32 ] ;
1022+ let path = DerivationPath :: from_str ( "m/0'" ) . expect ( "valid derivation path" ) ;
1023+ let mint_keyset = MintKeySet :: generate_from_seed (
1024+ & secp,
1025+ & seed,
1026+ & [ 1 , 2 ] ,
1027+ CurrencyUnit :: Auth ,
1028+ path,
1029+ 0 ,
1030+ None ,
1031+ KeySetVersion :: Version00 ,
1032+ ) ;
1033+
1034+ KeySet {
1035+ id : mint_keyset. id ,
1036+ unit : mint_keyset. unit . clone ( ) ,
1037+ active : None ,
1038+ keys : mint_keyset. keys . into ( ) ,
1039+ input_fee_ppk : mint_keyset. input_fee_ppk ,
1040+ final_expiry : mint_keyset. final_expiry ,
1041+ }
1042+ }
1043+
1044+ #[ derive( Debug ) ]
1045+ struct CountingAuthConnector {
1046+ keyset : KeySet ,
1047+ keysets_calls : Arc < Mutex < usize > > ,
1048+ keyset_calls : Arc < Mutex < usize > > ,
1049+ }
1050+
1051+ impl CountingAuthConnector {
1052+ fn new ( keyset : KeySet ) -> Self {
1053+ Self {
1054+ keyset,
1055+ keysets_calls : Arc :: new ( Mutex :: new ( 0 ) ) ,
1056+ keyset_calls : Arc :: new ( Mutex :: new ( 0 ) ) ,
1057+ }
1058+ }
1059+ }
1060+
1061+ #[ async_trait]
1062+ impl AuthMintConnector for CountingAuthConnector {
1063+ async fn get_auth_token ( & self ) -> Result < AuthToken , Error > {
1064+ Ok ( AuthToken :: ClearAuth ( "dummy" . to_string ( ) ) )
1065+ }
1066+
1067+ async fn set_auth_token ( & self , _: AuthToken ) -> Result < ( ) , Error > {
1068+ Ok ( ( ) )
1069+ }
1070+
1071+ async fn get_mint_info ( & self ) -> Result < MintInfo , Error > {
1072+ Ok ( MintInfo :: default ( ) )
1073+ }
1074+
1075+ async fn get_mint_blind_auth_keyset ( & self , keyset_id : Id ) -> Result < KeySet , Error > {
1076+ * self . keyset_calls . lock ( ) . expect ( "lock" ) += 1 ;
1077+ if keyset_id == self . keyset . id {
1078+ Ok ( self . keyset . clone ( ) )
1079+ } else {
1080+ Err ( Error :: UnknownKeySet )
1081+ }
1082+ }
1083+
1084+ async fn get_mint_blind_auth_keysets ( & self ) -> Result < KeysetResponse , Error > {
1085+ * self . keysets_calls . lock ( ) . expect ( "lock" ) += 1 ;
1086+ Ok ( KeysetResponse {
1087+ keysets : vec ! [ KeySetInfo {
1088+ id: self . keyset. id,
1089+ unit: CurrencyUnit :: Auth ,
1090+ active: true ,
1091+ input_fee_ppk: self . keyset. input_fee_ppk,
1092+ final_expiry: self . keyset. final_expiry,
1093+ } ] ,
1094+ } )
1095+ }
1096+
1097+ async fn post_mint_blind_auth (
1098+ & self ,
1099+ _: crate :: nuts:: nut22:: MintAuthRequest ,
1100+ ) -> Result < crate :: nuts:: MintResponse , Error > {
1101+ Err ( Error :: Custom (
1102+ "post_mint_blind_auth is not used in this test" . to_string ( ) ,
1103+ ) )
1104+ }
1105+ }
1106+
10001107 /// Test that restore signature matching works correctly when response is in order
10011108 #[ test]
10021109 fn test_restore_signature_matching_in_order ( ) {
@@ -1332,4 +1439,41 @@ mod tests {
13321439 result
13331440 ) ;
13341441 }
1442+
1443+ #[ tokio:: test]
1444+ async fn fetch_mint_info_uses_configured_auth_connector_for_auth_settings ( ) {
1445+ use crate :: wallet:: test_utils:: {
1446+ create_test_db, test_mint_info, test_mint_url, MockMintConnector ,
1447+ } ;
1448+
1449+ let db = create_test_db ( ) . await ;
1450+ let mock_client = Arc :: new ( MockMintConnector :: new ( ) ) ;
1451+ let mut mint_info = test_mint_info ( ) ;
1452+ mint_info. time = None ;
1453+ mint_info. nuts . nut22 = Some ( crate :: nuts:: BlindAuthSettings :: new ( 10 , Vec :: new ( ) ) ) ;
1454+ mock_client. set_mint_info_response ( Ok ( mint_info) ) ;
1455+
1456+ let auth_connector = Arc :: new ( CountingAuthConnector :: new ( build_test_auth_keyset ( 1 ) ) ) ;
1457+ let keysets_calls = auth_connector. keysets_calls . clone ( ) ;
1458+ let keyset_calls = auth_connector. keyset_calls . clone ( ) ;
1459+
1460+ let wallet = WalletBuilder :: new ( )
1461+ . mint_url ( test_mint_url ( ) )
1462+ . unit ( CurrencyUnit :: Sat )
1463+ . localstore ( db)
1464+ . seed ( [ 0u8 ; 64 ] )
1465+ . shared_client ( mock_client)
1466+ . auth_connector ( auth_connector)
1467+ . build ( )
1468+ . expect ( "wallet should build" ) ;
1469+
1470+ wallet
1471+ . fetch_mint_info ( )
1472+ . await
1473+ . expect ( "mint info should load and auth keysets should refresh from mock connector" ) ;
1474+
1475+ assert ! ( wallet. auth_wallet. read( ) . await . is_some( ) ) ;
1476+ assert_eq ! ( * keysets_calls. lock( ) . expect( "lock" ) , 1 ) ;
1477+ assert_eq ! ( * keyset_calls. lock( ) . expect( "lock" ) , 1 ) ;
1478+ }
13351479}
0 commit comments