diff --git a/crates/tranquil-oauth/src/client.rs b/crates/tranquil-oauth/src/client.rs index 34b3c76..ea08202 100644 --- a/crates/tranquil-oauth/src/client.rs +++ b/crates/tranquil-oauth/src/client.rs @@ -72,6 +72,7 @@ pub struct ClientMetadataCache { cache: Arc, http_client: Client, cache_ttl: Duration, + fetch_policy: ReachPolicy, } impl ClientMetadataCache { @@ -98,6 +99,7 @@ impl ClientMetadataCache { .expect("failed to build client metadata HTTP client") }, cache_ttl, + fetch_policy, } } @@ -249,7 +251,7 @@ impl ClientMetadataCache { async fn fetch_metadata(&self, client_id: &ClientId) -> Result { let url = reqwest::Url::parse(client_id) .map_err(|_| OAuthError::InvalidClient("client_id must be a URL".to_string()))?; - if !url_reach_permits(&url, ReachPolicy::DEBUG_LOOPBACK) { + if !url_reach_permits(&url, self.fetch_policy) { return Err(OAuthError::InvalidClient( "client_id must be an https URL inside the allowed host reach".to_string(), )); diff --git a/crates/tranquil-pds/src/did.rs b/crates/tranquil-pds/src/did.rs index a7e055d..16912e4 100644 --- a/crates/tranquil-pds/src/did.rs +++ b/crates/tranquil-pds/src/did.rs @@ -61,16 +61,15 @@ pub struct DidResolver { client: Client, cache_ttl: Duration, plc_directory_url: String, + fetch_policy: tranquil_types::ReachPolicy, } impl DidResolver { pub fn new(cache: Arc) -> Self { let cfg = tranquil_config::get(); - let fetch_policy = match cfg.server.allow_private_fetch { - true => tranquil_types::ReachPolicy::AllowPrivate, - false => tranquil_types::ReachPolicy::DEBUG_LOOPBACK, - }; + let fetch_policy = + tranquil_types::ReachPolicy::from_private_fetch(cfg.server.allow_private_fetch); let client = Client::builder() .timeout(Duration::from_secs(10)) .connect_timeout(Duration::from_secs(5)) @@ -87,6 +86,7 @@ impl DidResolver { client, cache_ttl: Duration::from_secs(cfg.plc.did_cache_ttl_secs), plc_directory_url: cfg.plc.directory_url.clone(), + fetch_policy, } } @@ -155,7 +155,7 @@ impl DidResolver { &self, did: &Did, ) -> Result { - let url = build_did_web_url(did)?; + let url = build_did_web_url(did, self.fetch_policy)?; debug!("Resolving did:web {} via {}", did, url); @@ -214,7 +214,10 @@ impl DidResolver { } } -fn build_did_web_url(did: &Did) -> Result { +fn build_did_web_url( + did: &Did, + policy: tranquil_types::ReachPolicy, +) -> Result { let host = did .strip_prefix("did:web:") .ok_or(DidResolutionError::InvalidDidWeb)?; @@ -254,7 +257,7 @@ fn build_did_web_url(did: &Did) -> Result { if tranquil_types::url_reach(&url) == Some(tranquil_types::HostReach::Loopback) { let _ = url.set_scheme("http"); } - match tranquil_types::url_reach_permits(&url, tranquil_types::ReachPolicy::DEBUG_LOOPBACK) { + match tranquil_types::url_reach_permits(&url, policy) { true => Ok(url.to_string()), false => Err(DidResolutionError::DidWebHostRejected(host)), } diff --git a/crates/tranquil-pds/src/oauth/client.rs b/crates/tranquil-pds/src/oauth/client.rs index fc65eb7..4c7b510 100644 --- a/crates/tranquil-pds/src/oauth/client.rs +++ b/crates/tranquil-pds/src/oauth/client.rs @@ -10,7 +10,9 @@ use tranquil_oauth::{ AuthorizationServerMetadata, ClientMetadata, compute_es256_jkt, compute_pkce_challenge, create_dpop_proof, }; -use tranquil_types::{AuthorizationCode, ClientId, CrossPdsState, Did, Issuer, PdsUrl}; +use tranquil_types::{ + AuthorizationCode, ClientId, CrossPdsState, Did, Issuer, PdsUrl, ReachPolicy, +}; use crate::cache::Cache; @@ -68,16 +70,12 @@ pub struct CrossPdsOAuthClient { } impl CrossPdsOAuthClient { - pub fn new(cache: Arc) -> Self { + pub fn new(cache: Arc, fetch_policy: ReachPolicy) -> Self { let http = Client::builder() .timeout(Duration::from_secs(15)) .connect_timeout(Duration::from_secs(5)) - .redirect(tranquil_types::redirect_policy( - tranquil_types::ReachPolicy::GlobalOnly, - )) - .dns_resolver(tranquil_types::dns_guard( - tranquil_types::ReachPolicy::GlobalOnly, - )) + .redirect(tranquil_types::redirect_policy(fetch_policy)) + .dns_resolver(tranquil_types::dns_guard(fetch_policy)) .build() .expect("failed to build cross-PDS OAuth HTTP client"); Self { http, cache } diff --git a/crates/tranquil-pds/src/plc/mod.rs b/crates/tranquil-pds/src/plc/mod.rs index a529016..5ff09f1 100644 --- a/crates/tranquil-pds/src/plc/mod.rs +++ b/crates/tranquil-pds/src/plc/mod.rs @@ -187,10 +187,9 @@ impl PlcClient { }); let timeout_secs = cfg.map_or(10, |c| c.plc.timeout_secs); let connect_timeout_secs = cfg.map_or(5, |c| c.plc.connect_timeout_secs); - let fetch_policy = match cfg.map_or(false, |c| c.server.allow_private_fetch) { - true => tranquil_types::ReachPolicy::AllowPrivate, - false => tranquil_types::ReachPolicy::DEBUG_LOOPBACK, - }; + let fetch_policy = tranquil_types::ReachPolicy::from_private_fetch( + cfg.map_or(false, |c| c.server.allow_private_fetch), + ); let client = Client::builder() .timeout(Duration::from_secs(timeout_secs)) .connect_timeout(Duration::from_secs(connect_timeout_secs)) diff --git a/crates/tranquil-pds/src/state.rs b/crates/tranquil-pds/src/state.rs index 3139a51..c83c889 100644 --- a/crates/tranquil-pds/src/state.rs +++ b/crates/tranquil-pds/src/state.rs @@ -225,13 +225,12 @@ struct CacheBound { impl CacheBound { fn new(cache: &Arc, sso_config: &'static SsoConfig) -> Self { tranquil_lexicon::LexiconRegistry::global().set_shared_cache(cache.clone()); - let fetch_policy = match tranquil_config::get().server.allow_private_fetch { - true => tranquil_types::ReachPolicy::AllowPrivate, - false => tranquil_types::ReachPolicy::DEBUG_LOOPBACK, - }; + let fetch_policy = tranquil_types::ReachPolicy::from_private_fetch( + tranquil_config::get().server.allow_private_fetch, + ); Self { did_resolver: Arc::new(DidResolver::new(cache.clone())), - cross_pds_oauth: Arc::new(CrossPdsOAuthClient::new(cache.clone())), + cross_pds_oauth: Arc::new(CrossPdsOAuthClient::new(cache.clone(), fetch_policy)), client_metadata_cache: ClientMetadataCache::new( cache.clone(), CLIENT_METADATA_TTL, diff --git a/crates/tranquil-types/src/lib.rs b/crates/tranquil-types/src/lib.rs index 14b676c..c9866e1 100644 --- a/crates/tranquil-types/src/lib.rs +++ b/crates/tranquil-types/src/lib.rs @@ -1115,6 +1115,13 @@ impl ReachPolicy { pub const DEBUG_LOOPBACK: ReachPolicy = ReachPolicy::AllowLoopback; #[cfg(not(debug_assertions))] pub const DEBUG_LOOPBACK: ReachPolicy = ReachPolicy::GlobalOnly; + + pub fn from_private_fetch(allow_private: bool) -> ReachPolicy { + match allow_private { + true => ReachPolicy::AllowPrivate, + false => ReachPolicy::DEBUG_LOOPBACK, + } + } } pub trait UrlKind {