use affinidi_did_resolver_cache_sdk::config::{DIDCacheConfig, DIDCacheConfigBuilder};
use affinidi_did_resolver_cache_sdk::network_resolvers::HostPolicy;
pub fn allow_private_did_hosts() -> bool {
#[cfg(feature = "client")]
{
crate::http::EndpointPolicy::process_default().allow_private
}
#[cfg(not(feature = "client"))]
{
std::env::var("VTA_ALLOW_PRIVATE_ENDPOINTS")
.map(|v| {
matches!(
v.trim().to_ascii_lowercase().as_str(),
"1" | "true" | "yes" | "on"
)
})
.unwrap_or(false)
}
}
pub fn webvh_host_policy() -> HostPolicy {
if allow_private_did_hosts() {
HostPolicy::AllowPrivate
} else {
HostPolicy::PublicOnly
}
}
pub fn build_did_cache_config(url: Option<&str>) -> DIDCacheConfig {
let mut builder = DIDCacheConfigBuilder::default().with_host_policy(webvh_host_policy());
if let Some(u) = url {
builder = builder.with_network_mode(u);
}
builder.build()
}
pub fn build_did_cache_config_from_env() -> DIDCacheConfig {
let url = std::env::var("PNM_RESOLVER_URL")
.ok()
.filter(|s| !s.is_empty());
build_did_cache_config(url.as_deref())
}
#[cfg(test)]
mod tests {
use super::*;
use affinidi_did_resolver_cache_sdk::DIDCacheClient;
use std::sync::{
Arc,
atomic::{AtomicUsize, Ordering},
};
use std::time::Duration;
async fn counting_listener() -> (u16, Arc<AtomicUsize>) {
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let port = listener.local_addr().unwrap().port();
let accepted = Arc::new(AtomicUsize::new(0));
let counter = accepted.clone();
tokio::spawn(async move {
while let Ok((socket, _)) = listener.accept().await {
counter.fetch_add(1, Ordering::SeqCst);
drop(socket);
}
});
(port, accepted)
}
#[tokio::test]
async fn default_config_refuses_loopback_webvh_did_without_connecting() {
let (port, accepted) = counting_listener().await;
let client = DIDCacheClient::new(build_did_cache_config(None))
.await
.expect("local-mode DID cache client");
for host in [
"localhost",
"LOCALHOST",
"localhost.",
"svc.localhost",
"printer.local",
"metadata.google.internal",
] {
let did = format!("did:webvh:QmScidNotResolvable:{host}%3A{port}");
let result = client.resolve(&did).await;
assert!(result.is_err(), "{did} resolved but should be refused");
let message = result.unwrap_err().to_string();
assert!(
message.contains("BlockedHost"),
"{did} failed for the wrong reason: {message}"
);
}
tokio::time::sleep(Duration::from_millis(100)).await;
assert_eq!(
accepted.load(Ordering::SeqCst),
0,
"a refused did:webvh DID still connected to its host"
);
}
#[test]
fn default_policy_is_public_only() {
assert_eq!(webvh_host_policy(), HostPolicy::PublicOnly);
}
}