fix: force HTTPS for WebFinger in follow/unfollow — library uses HTTP in debug mode

This commit is contained in:
2026-05-15 03:03:51 +02:00
parent f7350847c5
commit b5427cab7d

View File

@@ -1,9 +1,7 @@
use std::sync::Arc;
use activitypub_federation::{
activity_sending::SendActivityTask,
fetch::{object_id::ObjectId, webfinger::webfinger_resolve_actor},
protocol::context::WithContext,
activity_sending::SendActivityTask, fetch::object_id::ObjectId, protocol::context::WithContext,
traits::Actor,
};
use axum::{Router, routing::get, routing::post};
@@ -342,6 +340,48 @@ impl ActivityPubService {
Ok(())
}
/// Resolve a `@user@domain` handle to a `DbActor` over HTTPS directly.
/// The library's `webfinger_resolve_actor` tries HTTP first in debug mode, which breaks
/// on servers that don't redirect HTTP → HTTPS.
async fn webfinger_https(
handle: &str,
data: &activitypub_federation::config::Data<FederationData>,
) -> anyhow::Result<DbActor> {
let normalized = handle.trim_start_matches('@');
let at = normalized
.rfind('@')
.ok_or_else(|| anyhow::anyhow!("handle must be user@domain"))?;
let (user, domain_str) = (&normalized[..at], &normalized[at + 1..]);
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?
.json()
.await?;
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_else(|| anyhow::anyhow!("no self link in WebFinger response"))?
.to_owned();
let self_url = url::Url::parse(&self_href)?;
let actor: DbActor = ObjectId::from(self_url)
.dereference(data)
.await
.map_err(|e| anyhow::anyhow!("{e}"))?;
Ok(actor)
}
pub async fn follow(&self, local_user_id: uuid::Uuid, handle: &str) -> anyhow::Result<()> {
let data = self.federation_config.to_request_data();
@@ -351,9 +391,7 @@ impl ActivityPubService {
return self.follow_local(local_user_id, parts[0], &data).await;
}
let remote_actor: DbActor = webfinger_resolve_actor(handle, &data)
.await
.map_err(|e| anyhow::anyhow!("{e}"))?;
let remote_actor: DbActor = Self::webfinger_https(handle, &data).await?;
let local_actor = get_local_actor(local_user_id, &data)
.await
@@ -1424,9 +1462,9 @@ impl domain::ports::FederationActionPort for ActivityPubService {
handle: &str,
) -> Result<(), domain::errors::DomainError> {
let data = self.federation_config.to_request_data();
let remote_actor: DbActor = webfinger_resolve_actor(handle, &data).await.map_err(|e| {
domain::errors::DomainError::ExternalService(anyhow::anyhow!("{e}").to_string())
})?;
let remote_actor: DbActor = Self::webfinger_https(handle, &data)
.await
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?;
let actor_url = remote_actor.ap_id.to_string();
self.unfollow(local_user_id.as_uuid(), &actor_url)
.await