Move HTTP signature verification to receive_activity() function
This commit is contained in:
parent
bf27903ee9
commit
0727b739ed
6 changed files with 34 additions and 39 deletions
|
@ -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
|
||||
|
|
|
@ -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"))?;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<String, VerificationError> {
|
||||
) -> Result<DbActorProfile, VerificationError> {
|
||||
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)]
|
||||
|
|
|
@ -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,
|
||||
)?;
|
||||
|
|
|
@ -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,
|
||||
)?;
|
||||
|
|
Loading…
Reference in a new issue