Move HTTP signature verification to receive_activity() function

This commit is contained in:
silverpill 2022-02-23 23:07:51 +00:00
parent bf27903ee9
commit 0727b739ed
6 changed files with 34 additions and 39 deletions

View file

@ -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

View file

@ -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"))?;

View file

@ -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

View file

@ -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)]

View file

@ -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,
)?;

View file

@ -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,
)?;