Normalize the allow private IPs flag application

This commit is contained in:
Johanna Larsson
2026-08-28 12:36:47 +00:00
committed by Tangled
parent 093484388f
commit 228c1bbbf5
6 changed files with 33 additions and 25 deletions
+3 -1
View File
@@ -72,6 +72,7 @@ pub struct ClientMetadataCache {
cache: Arc<dyn Cache>,
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<ClientMetadata, OAuthError> {
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(),
));
+10 -7
View File
@@ -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<dyn Cache>) -> 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<serde_json::Value, DidResolutionError> {
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<String, DidResolutionError> {
fn build_did_web_url(
did: &Did,
policy: tranquil_types::ReachPolicy,
) -> Result<String, DidResolutionError> {
let host = did
.strip_prefix("did:web:")
.ok_or(DidResolutionError::InvalidDidWeb)?;
@@ -254,7 +257,7 @@ fn build_did_web_url(did: &Did) -> Result<String, DidResolutionError> {
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)),
}
+6 -8
View File
@@ -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<dyn Cache>) -> Self {
pub fn new(cache: Arc<dyn Cache>, 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 }
+3 -4
View File
@@ -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))
+4 -5
View File
@@ -225,13 +225,12 @@ struct CacheBound {
impl CacheBound {
fn new(cache: &Arc<dyn Cache>, 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,
+7
View File
@@ -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 {