11use std:: sync:: { Arc , Mutex } ;
22
3- #[ cfg( feature = "_danger-local-https" ) ]
4- use anyhow:: Result ;
5- #[ cfg( not( feature = "_danger-local-https" ) ) ]
63use anyhow:: { anyhow, Result } ;
74
85use super :: Config ;
96
107#[ derive( Debug , Clone ) ]
118pub struct RelayManager {
129 selected_relay : Option < payjoin:: Url > ,
13- #[ cfg( not( feature = "_danger-local-https" ) ) ]
1410 failed_relays : Vec < payjoin:: Url > ,
1511}
1612
1713impl RelayManager {
18- #[ cfg( feature = "_danger-local-https" ) ]
19- pub fn new ( ) -> Self { RelayManager { selected_relay : None } }
20- #[ cfg( not( feature = "_danger-local-https" ) ) ]
2114 pub fn new ( ) -> Self { RelayManager { selected_relay : None , failed_relays : Vec :: new ( ) } }
2215
23- #[ cfg( not( feature = "_danger-local-https" ) ) ]
2416 pub fn set_selected_relay ( & mut self , relay : payjoin:: Url ) { self . selected_relay = Some ( relay) ; }
2517
2618 pub fn get_selected_relay ( & self ) -> Option < payjoin:: Url > { self . selected_relay . clone ( ) }
2719
28- #[ cfg( not( feature = "_danger-local-https" ) ) ]
2920 pub fn add_failed_relay ( & mut self , relay : payjoin:: Url ) { self . failed_relays . push ( relay) ; }
3021
31- #[ cfg( not( feature = "_danger-local-https" ) ) ]
3222 pub fn get_failed_relays ( & self ) -> Vec < payjoin:: Url > { self . failed_relays . clone ( ) }
3323}
3424
35- pub ( crate ) async fn unwrap_ohttp_keys_or_else_fetch (
36- config : & Config ,
37- relay_manager : Arc < Mutex < RelayManager > > ,
38- ) -> Result < payjoin:: OhttpKeys > {
39- if let Some ( keys) = config. v2 ( ) ?. ohttp_keys . clone ( ) {
40- println ! ( "Using OHTTP Keys from config" ) ;
41- Ok ( keys)
42- } else {
43- println ! ( "Bootstrapping private network transport over Oblivious HTTP" ) ;
44-
45- fetch_keys ( config, relay_manager. clone ( ) )
46- . await
47- . and_then ( |keys| keys. ok_or_else ( || anyhow:: anyhow!( "No OHTTP keys found" ) ) )
48- }
25+ pub ( crate ) struct ValidatedOhttpKeys {
26+ pub ( crate ) ohttp_keys : payjoin:: OhttpKeys ,
27+ pub ( crate ) relay_url : payjoin:: Url ,
4928}
5029
51- #[ cfg( not( feature = "_danger-local-https" ) ) ]
52- async fn fetch_keys (
30+ pub ( crate ) async fn unwrap_ohttp_keys_or_else_fetch (
5331 config : & Config ,
5432 relay_manager : Arc < Mutex < RelayManager > > ,
55- ) -> Result < Option < payjoin:: OhttpKeys > > {
56- use payjoin:: bitcoin:: secp256k1:: rand:: prelude:: SliceRandom ;
57- let payjoin_directory = config. v2 ( ) ?. pj_directory . clone ( ) ;
58- let relays = config. v2 ( ) ?. ohttp_relays . clone ( ) ;
59-
60- loop {
61- let failed_relays =
62- relay_manager. lock ( ) . expect ( "Lock should not be poisoned" ) . get_failed_relays ( ) ;
63-
64- let remaining_relays: Vec < _ > =
65- relays. iter ( ) . filter ( |r| !failed_relays. contains ( r) ) . cloned ( ) . collect ( ) ;
66-
67- if remaining_relays. is_empty ( ) {
68- return Err ( anyhow ! ( "No valid relays available" ) ) ;
69- }
70-
71- let selected_relay =
72- match remaining_relays. choose ( & mut payjoin:: bitcoin:: key:: rand:: thread_rng ( ) ) {
73- Some ( relay) => relay. clone ( ) ,
74- None => return Err ( anyhow ! ( "Failed to select from remaining relays" ) ) ,
75- } ;
76-
77- relay_manager
78- . lock ( )
79- . expect ( "Lock should not be poisoned" )
80- . set_selected_relay ( selected_relay. clone ( ) ) ;
33+ ) -> Result < ValidatedOhttpKeys > {
34+ let config_keys = config. v2 ( ) ?. ohttp_keys . clone ( ) ;
35+ let mut fetched_keys = fetch_ohttp_keys ( config, relay_manager) . await ?;
8136
82- let ohttp_keys = {
83- payjoin:: io:: fetch_ohttp_keys ( selected_relay. clone ( ) , payjoin_directory. clone ( ) ) . await
84- } ;
85-
86- match ohttp_keys {
87- Ok ( keys) => return Ok ( Some ( keys) ) ,
88- Err ( payjoin:: io:: Error :: UnexpectedStatusCode ( e) ) => {
89- return Err ( payjoin:: io:: Error :: UnexpectedStatusCode ( e) . into ( ) ) ;
90- }
91- Err ( e) => {
92- log:: debug!( "Failed to connect to relay: {selected_relay}, {e:?}" ) ;
93- relay_manager
94- . lock ( )
95- . expect ( "Lock should not be poisoned" )
96- . add_failed_relay ( selected_relay) ;
97- }
98- }
37+ if let Some ( keys) = config_keys {
38+ fetched_keys. ohttp_keys = keys;
9939 }
100- }
10140
102- ///Local relays are incapable of acting as proxies so we must opportunistically fetch keys from the config
103- #[ cfg( feature = "_danger-local-https" ) ]
104- async fn fetch_keys (
105- config : & Config ,
106- _relay_manager : Arc < Mutex < RelayManager > > ,
107- ) -> Result < Option < payjoin:: OhttpKeys > > {
108- let keys = config. v2 ( ) ?. ohttp_keys . clone ( ) . expect ( "No OHTTP keys set" ) ;
109-
110- Ok ( Some ( keys) )
41+ Ok ( fetched_keys)
11142}
11243
113- #[ cfg( not( feature = "_danger-local-https" ) ) ]
114- pub ( crate ) async fn validate_relay (
44+ async fn fetch_ohttp_keys (
11545 config : & Config ,
11646 relay_manager : Arc < Mutex < RelayManager > > ,
117- ) -> Result < payjoin :: Url > {
47+ ) -> Result < ValidatedOhttpKeys > {
11848 use payjoin:: bitcoin:: secp256k1:: rand:: prelude:: SliceRandom ;
11949 let payjoin_directory = config. v2 ( ) ?. pj_directory . clone ( ) ;
12050 let relays = config. v2 ( ) ?. ohttp_relays . clone ( ) ;
@@ -141,11 +71,26 @@ pub(crate) async fn validate_relay(
14171 . expect ( "Lock should not be poisoned" )
14272 . set_selected_relay ( selected_relay. clone ( ) ) ;
14373
144- let ohttp_keys =
145- payjoin:: io:: fetch_ohttp_keys ( selected_relay. clone ( ) , payjoin_directory. clone ( ) ) . await ;
74+ let ohttp_keys = {
75+ #[ cfg( feature = "_danger-local-https" ) ]
76+ {
77+ let cert_der = crate :: app:: read_local_cert ( ) ?;
78+ payjoin:: io:: fetch_ohttp_keys_with_cert (
79+ & selected_relay,
80+ & payjoin_directory,
81+ cert_der,
82+ )
83+ . await
84+ }
85+ #[ cfg( not( feature = "_danger-local-https" ) ) ]
86+ {
87+ payjoin:: io:: fetch_ohttp_keys ( & selected_relay, & payjoin_directory) . await
88+ }
89+ } ;
14690
14791 match ohttp_keys {
148- Ok ( _) => return Ok ( selected_relay) ,
92+ Ok ( keys) =>
93+ return Ok ( ValidatedOhttpKeys { ohttp_keys : keys, relay_url : selected_relay } ) ,
14994 Err ( payjoin:: io:: Error :: UnexpectedStatusCode ( e) ) => {
15095 return Err ( payjoin:: io:: Error :: UnexpectedStatusCode ( e) . into ( ) ) ;
15196 }
@@ -159,13 +104,3 @@ pub(crate) async fn validate_relay(
159104 }
160105 }
161106}
162-
163- #[ cfg( feature = "_danger-local-https" ) ]
164- pub ( crate ) async fn validate_relay (
165- config : & Config ,
166- _relay_manager : Arc < Mutex < RelayManager > > ,
167- ) -> Result < payjoin:: Url > {
168- let relay = config. v2 ( ) ?. ohttp_relays . first ( ) . expect ( "no OHTTP relay set" ) . clone ( ) ;
169-
170- Ok ( relay)
171- }
0 commit comments