Remove header guard for activitypub routes
authorFelix Ableitner <me@nutomic.com>
Wed, 10 Nov 2021 13:17:56 +0000 (14:17 +0100)
committerFelix Ableitner <me@nutomic.com>
Wed, 10 Nov 2021 14:08:33 +0000 (15:08 +0100)
crates/apub/src/http/routes.rs
crates/routes/src/webfinger.rs

index 5dfbc238281dd016062d08f553378b6766f51982..eb9a5595c90529ae97a7c6fffe6a271b0677dd1d 100644 (file)
@@ -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
   }
 }
index ef0afd9903c56418d939b3801c695ab6f1d3d844..21e25c7f2b039880dc2281a7952a23b8d5fff550 100644 (file)
@@ -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<Params>,
   context: web::Data<LemmyContext>,
-) -> Result<HttpResponse, Error> {
+) -> Result<HttpResponse, LemmyError> {
   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 {