feat: v2 rewrite — hexagonal arch, ActivityPub federation, NATS, deployment-ready #1
@@ -1336,13 +1336,52 @@ impl domain::ports::FederationActionPort for ActivityPubService {
|
||||
&self,
|
||||
handle: &str,
|
||||
) -> Result<domain::models::remote_actor::RemoteActor, domain::errors::DomainError> {
|
||||
let data = self.federation_config.to_request_data();
|
||||
use activitypub_federation::fetch::object_id::ObjectId;
|
||||
|
||||
let normalized = handle.trim_start_matches('@');
|
||||
let actor: crate::actors::DbActor = webfinger_resolve_actor(normalized, &data)
|
||||
let at = normalized.rfind('@').ok_or_else(|| {
|
||||
domain::errors::DomainError::InvalidInput("handle must be user@domain".into())
|
||||
})?;
|
||||
let (user, domain_str) = (&normalized[..at], &normalized[at + 1..]);
|
||||
|
||||
// Fetch WebFinger over HTTPS directly — the library's webfinger_resolve_actor
|
||||
// tries HTTP first in debug mode, which fails on servers without HTTP→HTTPS redirect.
|
||||
let wf_url = format!(
|
||||
"https://{}/.well-known/webfinger?resource=acct:{}@{}",
|
||||
domain_str, user, domain_str
|
||||
);
|
||||
let wf: serde_json::Value = reqwest::Client::new()
|
||||
.get(&wf_url)
|
||||
.header("Accept", "application/jrd+json, application/json")
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?;
|
||||
|
||||
let self_href = wf["links"]
|
||||
.as_array()
|
||||
.and_then(|links| {
|
||||
links.iter().find(|l| {
|
||||
l["rel"].as_str() == Some("self")
|
||||
&& l["type"].as_str() == Some("application/activity+json")
|
||||
})
|
||||
})
|
||||
.and_then(|l| l["href"].as_str())
|
||||
.ok_or(domain::errors::DomainError::NotFound)?;
|
||||
|
||||
let self_url = url::Url::parse(self_href)
|
||||
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?;
|
||||
|
||||
let data = self.federation_config.to_request_data();
|
||||
let actor: crate::actors::DbActor = ObjectId::from(self_url)
|
||||
.dereference(&data)
|
||||
.await
|
||||
.map_err(|e: crate::error::Error| {
|
||||
domain::errors::DomainError::ExternalService(e.to_string())
|
||||
})?;
|
||||
|
||||
Ok(domain::models::remote_actor::RemoteActor {
|
||||
url: actor.ap_id.to_string(),
|
||||
handle: actor.username.clone(),
|
||||
|
||||
Reference in New Issue
Block a user