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 std::sync::Arc;
|
||||||
|
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
activity_sending::SendActivityTask,
|
activity_sending::SendActivityTask, fetch::object_id::ObjectId, protocol::context::WithContext,
|
||||||
fetch::{object_id::ObjectId, webfinger::webfinger_resolve_actor},
|
|
||||||
protocol::context::WithContext,
|
|
||||||
traits::Actor,
|
traits::Actor,
|
||||||
};
|
};
|
||||||
use axum::{Router, routing::get, routing::post};
|
use axum::{Router, routing::get, routing::post};
|
||||||
@@ -342,6 +340,48 @@ impl ActivityPubService {
|
|||||||
Ok(())
|
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<()> {
|
pub async fn follow(&self, local_user_id: uuid::Uuid, handle: &str) -> anyhow::Result<()> {
|
||||||
let data = self.federation_config.to_request_data();
|
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;
|
return self.follow_local(local_user_id, parts[0], &data).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
let remote_actor: DbActor = webfinger_resolve_actor(handle, &data)
|
let remote_actor: DbActor = Self::webfinger_https(handle, &data).await?;
|
||||||
.await
|
|
||||||
.map_err(|e| anyhow::anyhow!("{e}"))?;
|
|
||||||
|
|
||||||
let local_actor = get_local_actor(local_user_id, &data)
|
let local_actor = get_local_actor(local_user_id, &data)
|
||||||
.await
|
.await
|
||||||
@@ -1424,9 +1462,9 @@ impl domain::ports::FederationActionPort for ActivityPubService {
|
|||||||
handle: &str,
|
handle: &str,
|
||||||
) -> Result<(), domain::errors::DomainError> {
|
) -> Result<(), domain::errors::DomainError> {
|
||||||
let data = self.federation_config.to_request_data();
|
let data = self.federation_config.to_request_data();
|
||||||
let remote_actor: DbActor = webfinger_resolve_actor(handle, &data).await.map_err(|e| {
|
let remote_actor: DbActor = Self::webfinger_https(handle, &data)
|
||||||
domain::errors::DomainError::ExternalService(anyhow::anyhow!("{e}").to_string())
|
.await
|
||||||
})?;
|
.map_err(|e| domain::errors::DomainError::ExternalService(e.to_string()))?;
|
||||||
let actor_url = remote_actor.ap_id.to_string();
|
let actor_url = remote_actor.ap_id.to_string();
|
||||||
self.unfollow(local_user_id.as_uuid(), &actor_url)
|
self.unfollow(local_user_id.as_uuid(), &actor_url)
|
||||||
.await
|
.await
|
||||||
|
|||||||
Reference in New Issue
Block a user