From 9a1fe154dbe7c5be6dd87c75d08abf4f637315c8 Mon Sep 17 00:00:00 2001 From: Felix Ableitner Date: Wed, 10 Nov 2021 14:17:56 +0100 Subject: [PATCH] Remove header guard for activitypub routes --- crates/apub/src/http/routes.rs | 98 +++++++++++++++++----------------- crates/routes/src/webfinger.rs | 12 ++--- 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/crates/apub/src/http/routes.rs b/crates/apub/src/http/routes.rs index 5dfbc238..eb9a5595 100644 --- a/crates/apub/src/http/routes.rs +++ b/crates/apub/src/http/routes.rs @@ -12,63 +12,65 @@ use crate::http::{ post::get_apub_post, shared_inbox, }; -use actix_web::*; +use actix_web::{dev::RequestHead, guard::Guard, http::Method, *}; use http_signature_normalization_actix::digest::middleware::VerifyDigest; -use lemmy_apub_lib::APUB_JSON_CONTENT_TYPE; use lemmy_utils::settings::structs::Settings; use sha2::{Digest, Sha256}; -static APUB_JSON_CONTENT_TYPE_LONG: &str = - "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""; - pub fn config(cfg: &mut web::ServiceConfig, settings: &Settings) { if settings.federation.enabled { println!("federation enabled, host is {}", settings.hostname); - let digest_verifier = VerifyDigest::new(Sha256::new()); - - let header_guard_accept = guard::Any(guard::Header("Accept", APUB_JSON_CONTENT_TYPE)) - .or(guard::Header("Accept", APUB_JSON_CONTENT_TYPE_LONG)); - let header_guard_content_type = - guard::Any(guard::Header("Content-Type", APUB_JSON_CONTENT_TYPE)) - .or(guard::Header("Content-Type", APUB_JSON_CONTENT_TYPE_LONG)); cfg - .service( - web::scope("") - .guard(header_guard_accept) - .route( - "/c/{community_name}", - web::get().to(get_apub_community_http), - ) - .route( - "/c/{community_name}/followers", - web::get().to(get_apub_community_followers), - ) - .route( - "/c/{community_name}/outbox", - web::get().to(get_apub_community_outbox), - ) - .route( - "/c/{community_name}/moderators", - web::get().to(get_apub_community_moderators), - ) - .route("/u/{user_name}", web::get().to(get_apub_person_http)) - .route( - "/u/{user_name}/outbox", - web::get().to(get_apub_person_outbox), - ) - .route("/post/{post_id}", web::get().to(get_apub_post)) - .route("/comment/{comment_id}", web::get().to(get_apub_comment)) - .route("/activities/{type_}/{id}", web::get().to(get_activity)), + .route( + "/c/{community_name}", + web::get().to(get_apub_community_http), + ) + .route( + "/c/{community_name}/followers", + web::get().to(get_apub_community_followers), + ) + .route( + "/c/{community_name}/outbox", + web::get().to(get_apub_community_outbox), + ) + .route( + "/c/{community_name}/moderators", + web::get().to(get_apub_community_moderators), + ) + .route("/u/{user_name}", web::get().to(get_apub_person_http)) + .route( + "/u/{user_name}/outbox", + web::get().to(get_apub_person_outbox), ) - // Inboxes dont work with the header guard for some reason. - .service( - web::scope("") - .wrap(digest_verifier) - .guard(header_guard_content_type) - .route("/c/{community_name}/inbox", web::post().to(community_inbox)) - .route("/u/{user_name}/inbox", web::post().to(person_inbox)) - .route("/inbox", web::post().to(shared_inbox)), - ); + .route("/post/{post_id}", web::get().to(get_apub_post)) + .route("/comment/{comment_id}", web::get().to(get_apub_comment)) + .route("/activities/{type_}/{id}", web::get().to(get_activity)); + + cfg.service( + web::scope("") + .wrap(VerifyDigest::new(Sha256::new())) + .guard(InboxRequestGuard) + .route("/c/{community_name}/inbox", web::post().to(community_inbox)) + .route("/u/{user_name}/inbox", web::post().to(person_inbox)) + .route("/inbox", web::post().to(shared_inbox)), + ); + } +} + +/// Without this, things like webfinger or RSS feeds stop working, as all requests seem to get +/// routed into the inbox service (because it covers the root path). So we filter out anything that +/// definitely can't be an inbox request (based on Accept header and request method). +struct InboxRequestGuard; + +impl Guard for InboxRequestGuard { + fn check(&self, request: &RequestHead) -> bool { + if request.method != Method::POST { + return false; + } + if let Some(val) = request.headers.get("Content-Type") { + return val.to_str().unwrap().starts_with("application/"); + } + false } } diff --git a/crates/routes/src/webfinger.rs b/crates/routes/src/webfinger.rs index ef0afd99..21e25c7f 100644 --- a/crates/routes/src/webfinger.rs +++ b/crates/routes/src/webfinger.rs @@ -1,9 +1,9 @@ -use actix_web::{error::ErrorBadRequest, web::Query, *}; +use actix_web::{web, web::Query, HttpResponse}; use anyhow::anyhow; use lemmy_api_common::blocking; use lemmy_apub_lib::webfinger::{WebfingerLink, WebfingerResponse}; use lemmy_db_schema::source::{community::Community, person::Person}; -use lemmy_utils::{settings::structs::Settings, LemmyError}; +use lemmy_utils::{settings::structs::Settings, ApiError, LemmyError}; use lemmy_websocket::LemmyContext; use serde::Deserialize; @@ -30,7 +30,7 @@ pub fn config(cfg: &mut web::ServiceConfig, settings: &Settings) { async fn get_webfinger_response( info: Query, context: web::Data, -) -> Result { +) -> Result { let community_regex_parsed = context .settings() .webfinger_community_regex() @@ -52,7 +52,7 @@ async fn get_webfinger_response( Community::read_from_name(conn, &community_name) }) .await? - .map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))? + .map_err(|e| ApiError::err("not_found", e))? .actor_id } else if let Some(person_name) = username_regex_parsed { let person_name = person_name.as_str().to_owned(); @@ -61,10 +61,10 @@ async fn get_webfinger_response( Person::find_by_name(conn, &person_name) }) .await? - .map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))? + .map_err(|e| ApiError::err("not_found", e))? .actor_id } else { - return Err(ErrorBadRequest(LemmyError::from(anyhow!("not_found")))); + return Err(LemmyError::from(anyhow!("not_found"))); }; let json = WebfingerResponse { -- 2.44.1