From 89f5b200a8128180504716cb829b9270a61dbe8b Mon Sep 17 00:00:00 2001 From: alemi Date: Sun, 23 Jun 2024 03:55:03 +0200 Subject: [PATCH] feat: added hmac validated proxy route --- Cargo.lock | 3 +++ upub/core/src/config.rs | 3 +++ upub/routes/Cargo.toml | 5 +++- upub/routes/src/activitypub/application.rs | 29 +++++++++++++++++++++- upub/routes/src/activitypub/mod.rs | 1 + 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a2326e2..600c36dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4864,7 +4864,9 @@ version = "0.2.0" dependencies = [ "apb", "axum", + "base64 0.22.1", "chrono", + "hmac", "httpsign", "jrd", "mastodon-async-entities", @@ -4874,6 +4876,7 @@ dependencies = [ "sea-orm", "serde", "serde_json", + "sha2", "sha256", "thiserror", "time", diff --git a/upub/core/src/config.rs b/upub/core/src/config.rs index 49dbb6bb..640c49e8 100644 --- a/upub/core/src/config.rs +++ b/upub/core/src/config.rs @@ -68,6 +68,9 @@ pub struct SecurityConfig { #[serde(default)] pub allow_public_debugger: bool, + #[serde_inline_default("changeme".to_string())] + pub proxy_secret: String, + #[serde_inline_default(true)] pub show_reply_ids: bool, diff --git a/upub/routes/Cargo.toml b/upub/routes/Cargo.toml index 978525fd..fc100481 100644 --- a/upub/routes/Cargo.toml +++ b/upub/routes/Cargo.toml @@ -13,7 +13,10 @@ readme = "README.md" [dependencies] thiserror = "1" rand = "0.8" -sha256 = "1.5" +sha2 = "0.10" +sha256 = "1.5" # TODO ughhh +hmac = "0.12" +base64 = "0.22" chrono = { version = "0.4", features = ["serde"] } serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/upub/routes/src/activitypub/application.rs b/upub/routes/src/activitypub/application.rs index 0c90a2af..115c193d 100644 --- a/upub/routes/src/activitypub/application.rs +++ b/upub/routes/src/activitypub/application.rs @@ -1,9 +1,11 @@ use apb::{LD, ActorMut, BaseMut, ObjectMut, PublicKeyMut}; use axum::{extract::{Path, Query, State}, http::HeaderMap, response::{IntoResponse, Redirect, Response}, Form}; +use hmac::{Hmac, Mac}; use reqwest::Method; +use base64::{engine::general_purpose::URL_SAFE, Engine as _}; use upub::{traits::Fetcher, Context}; -use crate::{builders::JsonLD, AuthIdentity, Identity}; +use crate::{builders::JsonLD, ApiError, AuthIdentity, Identity}; pub async fn view( @@ -74,6 +76,31 @@ pub async fn proxy_form( proxy(ctx, query, auth).await } +pub async fn proxy_hmac( + State(ctx): State, + AuthIdentity(auth): AuthIdentity, + Path(hmac): Path, + Path(uri): Path, +) -> crate::ApiResult { + let bytes = URL_SAFE.decode(hmac).map_err(|_| ApiError::bad_request())?; + let uri = + std::str::from_utf8( + &URL_SAFE.decode(uri).map_err(|_| ApiError::bad_request())? + ) + .map_err(|_| ApiError::bad_request())? + .to_string(); + + type HmacSha256 = Hmac; + let mut mac = HmacSha256::new_from_slice(ctx.cfg().security.proxy_secret.as_bytes()) + .map_err(|_| ApiError::internal_server_error())?; + + mac.update(uri.as_bytes()); + mac.verify_slice(&bytes) + .map_err(|_| ApiError::forbidden())?; + + proxy(ctx, uri, auth).await +} + async fn proxy(ctx: Context, query: String, auth: Identity) -> crate::ApiResult { // only local users can request fetches if !ctx.cfg().security.allow_public_debugger && !auth.is_local() { diff --git a/upub/routes/src/activitypub/mod.rs b/upub/routes/src/activitypub/mod.rs index 61786da8..f04d3a2e 100644 --- a/upub/routes/src/activitypub/mod.rs +++ b/upub/routes/src/activitypub/mod.rs @@ -25,6 +25,7 @@ impl ActivityPubRouter for Router { .route("/proxy", post(ap::application::proxy_form)) .route("/proxy", get(ap::application::proxy_get)) .route("/proxy/:uri", get(ap::application::proxy_path)) + .route("/proxy/:hmac/:uri", get(ap::application::proxy_hmac)) .route("/inbox", post(ap::inbox::post)) .route("/inbox", get(ap::inbox::get)) .route("/inbox/page", get(ap::inbox::page))