fix: force HTTPS for WebFinger in follow/unfollow — library uses HTTP in debug mode
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user