diff --git a/src/activitypub/inbox/create.rs b/src/activitypub/inbox/create.rs index 551baf7..3d76d79 100644 --- a/src/activitypub/inbox/create.rs +++ b/src/activitypub/inbox/create.rs @@ -14,8 +14,8 @@ pub fn get_note_visibility( let maybe_followers = author.actor_json.as_ref() .and_then(|actor| actor.followers.as_ref()); if let Some(followers) = maybe_followers { - if primary_audience.contains(&followers) || - secondary_audience.contains(&followers) { + if primary_audience.contains(followers) || + secondary_audience.contains(followers) { Visibility::Followers } else { Visibility::Direct diff --git a/src/activitypub/receiver.rs b/src/activitypub/receiver.rs index 0a41094..9cdb821 100644 --- a/src/activitypub/receiver.rs +++ b/src/activitypub/receiver.rs @@ -1,13 +1,14 @@ use std::collections::HashMap; +use actix_web::HttpRequest; use regex::Regex; use serde_json::Value; use tokio_postgres::GenericClient; use uuid::Uuid; use crate::config::Config; -use crate::database::{Pool, get_database_client}; use crate::errors::{ConversionError, DatabaseError, HttpError, ValidationError}; +use crate::http_signatures::verify::verify_http_signature; use crate::models::attachments::queries::create_attachment; use crate::models::posts::mentions::mention_to_address; use crate::models::posts::queries::{ @@ -427,20 +428,26 @@ fn require_actor_signature(actor_id: &str, signer_id: &str) pub async fn receive_activity( config: &Config, - db_pool: &Pool, - signer_id: &str, + db_client: &mut impl GenericClient, + request: &HttpRequest, activity_raw: &Value, ) -> Result<(), HttpError> { + let signer = verify_http_signature(config, db_client, request).await.map_err(|err| { + log::warn!("invalid signature: {}", err); + HttpError::AuthError("invalid signature") + })?; + let signer_id = signer.actor_id(&config.instance_url()); + log::debug!("activity signed by {}", signer_id); + let activity: Activity = serde_json::from_value(activity_raw.clone()) .map_err(|_| ValidationError("invalid activity"))?; let activity_type = activity.activity_type; let maybe_object_type = activity.object.get("type") .and_then(|val| val.as_str()) .unwrap_or("Unknown"); - let db_client = &mut **get_database_client(db_pool).await?; let object_type = match (activity_type.as_str(), maybe_object_type) { (ACCEPT, FOLLOW) => { - require_actor_signature(&activity.actor, signer_id)?; + require_actor_signature(&activity.actor, &signer_id)?; let actor_profile = get_profile_by_actor_id(db_client, &activity.actor).await?; let object_id = get_object_id(activity.object)?; let follow_request_id = parse_object_id(&config.instance_url(), &object_id)?; @@ -452,7 +459,7 @@ pub async fn receive_activity( FOLLOW }, (REJECT, FOLLOW) => { - require_actor_signature(&activity.actor, signer_id)?; + require_actor_signature(&activity.actor, &signer_id)?; let actor_profile = get_profile_by_actor_id(db_client, &activity.actor).await?; let object_id = get_object_id(activity.object)?; let follow_request_id = parse_object_id(&config.instance_url(), &object_id)?; @@ -477,7 +484,7 @@ pub async fn receive_activity( NOTE }, (ANNOUNCE, _) => { - require_actor_signature(&activity.actor, signer_id)?; + require_actor_signature(&activity.actor, &signer_id)?; let repost_object_id = activity.id; match get_post_by_object_id(db_client, &repost_object_id).await { Ok(_) => return Ok(()), // Ignore if repost already exists @@ -508,7 +515,7 @@ pub async fn receive_activity( NOTE }, (DELETE, _) => { - require_actor_signature(&activity.actor, signer_id)?; + require_actor_signature(&activity.actor, &signer_id)?; let object_id = get_object_id(activity.object)?; if object_id == activity.actor { log::info!("received deletion request for {}", object_id); @@ -533,7 +540,7 @@ pub async fn receive_activity( NOTE }, (LIKE, _) | (EMOJI_REACT, _) => { - require_actor_signature(&activity.actor, signer_id)?; + require_actor_signature(&activity.actor, &signer_id)?; let author = get_or_import_profile_by_actor_id( db_client, &config.instance(), @@ -567,7 +574,7 @@ pub async fn receive_activity( NOTE }, (FOLLOW, _) => { - require_actor_signature(&activity.actor, signer_id)?; + require_actor_signature(&activity.actor, &signer_id)?; let source_profile = get_or_import_profile_by_actor_id( db_client, &config.instance(), @@ -598,7 +605,7 @@ pub async fn receive_activity( PERSON }, (UNDO, FOLLOW) => { - require_actor_signature(&activity.actor, signer_id)?; + require_actor_signature(&activity.actor, &signer_id)?; let object: Object = serde_json::from_value(activity.object) .map_err(|_| ValidationError("invalid object"))?; let source_profile = get_profile_by_actor_id(db_client, &activity.actor).await?; @@ -610,7 +617,7 @@ pub async fn receive_activity( FOLLOW }, (UNDO, _) => { - require_actor_signature(&activity.actor, signer_id)?; + require_actor_signature(&activity.actor, &signer_id)?; let actor_profile = get_profile_by_actor_id(db_client, &activity.actor).await?; let object_id = get_object_id(activity.object)?; match get_reaction_by_activity_id(db_client, &object_id).await { @@ -649,7 +656,7 @@ pub async fn receive_activity( } }, (UPDATE, PERSON) => { - require_actor_signature(&activity.actor, signer_id)?; + require_actor_signature(&activity.actor, &signer_id)?; let actor_value = activity.object.clone(); let actor: Actor = serde_json::from_value(activity.object) .map_err(|_| ValidationError("invalid actor data"))?; diff --git a/src/activitypub/views.rs b/src/activitypub/views.rs index e8fe0c8..631bcb4 100644 --- a/src/activitypub/views.rs +++ b/src/activitypub/views.rs @@ -10,7 +10,6 @@ use crate::config::Config; use crate::database::{Pool, get_database_client}; use crate::errors::HttpError; use crate::frontend::{get_post_page_url, get_profile_page_url}; -use crate::http_signatures::verify::verify_http_signature; use crate::models::posts::queries::{get_posts_by_author, get_thread}; use crate::models::users::queries::get_user_by_name; use super::activity::{create_note, create_activity_note}; @@ -113,18 +112,8 @@ async fn inbox( } else { log::info!("received in {}: {}", request.uri().path(), activity_type); }; - let signature_verified = verify_http_signature(&config, &db_pool, &request).await; - let signer_id = match signature_verified { - Ok(signer_id) => { - log::debug!("activity signed by {}", signer_id); - signer_id - }, - Err(err) => { - log::warn!("invalid signature: {}", err); - return Err(HttpError::AuthError("invalid signature")); - }, - }; - receive_activity(&config, &db_pool, &signer_id, &activity).await + let db_client = &mut **get_database_client(&db_pool).await?; + receive_activity(&config, db_client, &request, &activity).await .map_err(|err| { log::warn!("failed to process activity ({}): {}", err, activity); err diff --git a/src/http_signatures/verify.rs b/src/http_signatures/verify.rs index 5534c71..e83e8cf 100644 --- a/src/http_signatures/verify.rs +++ b/src/http_signatures/verify.rs @@ -5,14 +5,15 @@ use actix_web::{ http::{HeaderMap, Method, Uri}, }; use regex::Regex; +use tokio_postgres::GenericClient; use crate::activitypub::fetcher::helpers::{ get_or_import_profile_by_actor_id, ImportError, }; use crate::config::Config; -use crate::database::{Pool, get_database_client}; use crate::errors::DatabaseError; +use crate::models::profiles::types::DbActorProfile; use crate::utils::crypto::{deserialize_public_key, verify_signature}; #[derive(thiserror::Error, Debug)] @@ -42,7 +43,7 @@ pub enum VerificationError { InvalidSignature, } -pub struct SignatureData { +struct SignatureData { pub actor_id: String, pub message: String, // reconstructed message pub signature: String, // base64-encoded signature @@ -115,16 +116,15 @@ fn parse_http_signature( /// Verifies HTTP signature and returns signer ID pub async fn verify_http_signature( config: &Config, - db_pool: &Pool, + db_client: &impl GenericClient, request: &HttpRequest, -) -> Result { +) -> Result { let signature_data = parse_http_signature( request.method(), request.uri(), request.headers(), )?; - let db_client = &**get_database_client(db_pool).await?; let actor_profile = match get_or_import_profile_by_actor_id( db_client, &config.instance(), @@ -149,8 +149,7 @@ pub async fn verify_http_signature( if !is_valid_signature { return Err(VerificationError::InvalidSignature); }; - let signer_id = actor_profile.actor_id(&config.instance_url()); - Ok(signer_id) + Ok(actor_profile) } #[cfg(test)] diff --git a/src/mastodon_api/accounts/views.rs b/src/mastodon_api/accounts/views.rs index a27973f..44858f5 100644 --- a/src/mastodon_api/accounts/views.rs +++ b/src/mastodon_api/accounts/views.rs @@ -87,8 +87,8 @@ pub async fn create_account( let signature = account_data.signature.as_ref() .ok_or(ValidationError("signature is required"))?; let wallet_address = verify_eip4361_signature( - &message, - &signature, + message, + signature, &config.instance().host(), &config.login_message, )?; diff --git a/src/mastodon_api/oauth/views.rs b/src/mastodon_api/oauth/views.rs index f494449..34b2668 100644 --- a/src/mastodon_api/oauth/views.rs +++ b/src/mastodon_api/oauth/views.rs @@ -44,8 +44,8 @@ async fn token_view( let signature = request_data.signature.as_ref() .ok_or(ValidationError("signature is required"))?; let wallet_address = verify_eip4361_signature( - &message, - &signature, + message, + signature, &config.instance().host(), &config.login_message, )?;