Don't fetch signer when processing Delete(Person) activity

This commit is contained in:
silverpill 2022-05-30 19:51:32 +00:00
parent c89ee4fd7b
commit 8407bbe842
2 changed files with 39 additions and 28 deletions

View file

@ -130,13 +130,14 @@ pub fn parse_property_value<T: DeserializeOwned>(value: &Value) -> Result<Vec<T>
} }
/// Parses object json value and returns its ID as string /// Parses object json value and returns its ID as string
fn get_object_id(object: Value) -> Result<String, ValidationError> { fn get_object_id(object: &Value) -> Result<String, ValidationError> {
let object_id = match object.as_str() { let object_id = match object.as_str() {
Some(object_id) => object_id.to_owned(), Some(object_id) => object_id.to_owned(),
None => { None => {
let object: Object = serde_json::from_value(object) let object_id = object["id"].as_str()
.map_err(|_| ValidationError("invalid object"))?; .ok_or(ValidationError("missing object ID"))?
object.id .to_string();
object_id
}, },
}; };
Ok(object_id) Ok(object_id)
@ -171,11 +172,15 @@ pub async fn receive_activity(
.and_then(|val| val.as_str()) .and_then(|val| val.as_str())
.unwrap_or("Unknown"); .unwrap_or("Unknown");
let signer = match verify_http_signature(config, db_client, request).await { let is_self_delete = if activity_type == DELETE {
let object_id = get_object_id(&activity.object)?;
activity.actor == object_id
} else { false };
// Don't fetch signer if this is Delete(Person) activity
let signer = match verify_http_signature(config, db_client, request, is_self_delete).await {
Ok(signer) => signer, Ok(signer) => signer,
Err(error) => { Err(error) => {
let object_id = get_object_id(activity.object)?; if is_self_delete {
if activity_type == DELETE && activity.actor == object_id {
// Ignore Delete(Person) activities without HTTP signatures // Ignore Delete(Person) activities without HTTP signatures
return Ok(()); return Ok(());
}; };
@ -193,7 +198,7 @@ pub async fn receive_activity(
(ACCEPT, FOLLOW) => { (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 actor_profile = get_profile_by_actor_id(db_client, &activity.actor).await?;
let object_id = get_object_id(activity.object)?; let object_id = get_object_id(&activity.object)?;
let follow_request_id = parse_object_id(&config.instance_url(), &object_id)?; let follow_request_id = parse_object_id(&config.instance_url(), &object_id)?;
let follow_request = get_follow_request_by_id(db_client, &follow_request_id).await?; let follow_request = get_follow_request_by_id(db_client, &follow_request_id).await?;
if follow_request.target_id != actor_profile.id { if follow_request.target_id != actor_profile.id {
@ -205,7 +210,7 @@ pub async fn receive_activity(
(REJECT, 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 actor_profile = get_profile_by_actor_id(db_client, &activity.actor).await?;
let object_id = get_object_id(activity.object)?; let object_id = get_object_id(&activity.object)?;
let follow_request_id = parse_object_id(&config.instance_url(), &object_id)?; let follow_request_id = parse_object_id(&config.instance_url(), &object_id)?;
let follow_request = get_follow_request_by_id(db_client, &follow_request_id).await?; let follow_request = get_follow_request_by_id(db_client, &follow_request_id).await?;
if follow_request.target_id != actor_profile.id { if follow_request.target_id != actor_profile.id {
@ -241,7 +246,7 @@ pub async fn receive_activity(
&config.media_dir(), &config.media_dir(),
&activity.actor, &activity.actor,
).await?; ).await?;
let object_id = get_object_id(activity.object)?; let object_id = get_object_id(&activity.object)?;
let post_id = match parse_object_id(&config.instance_url(), &object_id) { let post_id = match parse_object_id(&config.instance_url(), &object_id) {
Ok(post_id) => post_id, Ok(post_id) => post_id,
Err(_) => { Err(_) => {
@ -263,7 +268,7 @@ pub async fn receive_activity(
// Ignore forwarded Delete() activities // Ignore forwarded Delete() activities
return Ok(()); return Ok(());
}; };
let object_id = get_object_id(activity.object)?; let object_id = get_object_id(&activity.object)?;
if object_id == activity.actor { if object_id == activity.actor {
log::info!("received deletion request for {}", object_id); log::info!("received deletion request for {}", object_id);
// Ignore Delete(Person) // Ignore Delete(Person)
@ -294,7 +299,7 @@ pub async fn receive_activity(
&config.media_dir(), &config.media_dir(),
&activity.actor, &activity.actor,
).await?; ).await?;
let object_id = get_object_id(activity.object)?; let object_id = get_object_id(&activity.object)?;
let post_id = match parse_object_id(&config.instance_url(), &object_id) { let post_id = match parse_object_id(&config.instance_url(), &object_id) {
Ok(post_id) => post_id, Ok(post_id) => post_id,
Err(_) => { Err(_) => {
@ -330,7 +335,7 @@ pub async fn receive_activity(
).await?; ).await?;
let source_actor = source_profile.actor_json let source_actor = source_profile.actor_json
.ok_or(HttpError::InternalError)?; .ok_or(HttpError::InternalError)?;
let target_actor_id = get_object_id(activity.object)?; let target_actor_id = get_object_id(&activity.object)?;
let target_username = parse_actor_id(&config.instance_url(), &target_actor_id)?; let target_username = parse_actor_id(&config.instance_url(), &target_actor_id)?;
let target_user = get_user_by_name(db_client, &target_username).await?; let target_user = get_user_by_name(db_client, &target_username).await?;
match follow(db_client, &source_profile.id, &target_user.profile.id).await { match follow(db_client, &source_profile.id, &target_user.profile.id).await {
@ -371,7 +376,7 @@ pub async fn receive_activity(
(UNDO, _) => { (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 actor_profile = get_profile_by_actor_id(db_client, &activity.actor).await?;
let object_id = get_object_id(activity.object)?; let object_id = get_object_id(&activity.object)?;
match get_reaction_by_activity_id(db_client, &object_id).await { match get_reaction_by_activity_id(db_client, &object_id).await {
Ok(reaction) => { Ok(reaction) => {
// Undo(Like) // Undo(Like)
@ -517,12 +522,12 @@ mod tests {
#[test] #[test]
fn test_get_object_id_from_string() { fn test_get_object_id_from_string() {
let value = json!("test_id"); let value = json!("test_id");
assert_eq!(get_object_id(value).unwrap(), "test_id"); assert_eq!(get_object_id(&value).unwrap(), "test_id");
} }
#[test] #[test]
fn test_get_object_id_from_object() { fn test_get_object_id_from_object() {
let value = json!({"id": "test_id", "type": "Note"}); let value = json!({"id": "test_id", "type": "Note"});
assert_eq!(get_object_id(value).unwrap(), "test_id"); assert_eq!(get_object_id(&value).unwrap(), "test_id");
} }
} }

View file

@ -13,6 +13,7 @@ use crate::activitypub::fetcher::helpers::{
}; };
use crate::config::Config; use crate::config::Config;
use crate::errors::DatabaseError; use crate::errors::DatabaseError;
use crate::models::profiles::queries::get_profile_by_actor_id;
use crate::models::profiles::types::DbActorProfile; use crate::models::profiles::types::DbActorProfile;
use crate::utils::crypto::{deserialize_public_key, verify_signature}; use crate::utils::crypto::{deserialize_public_key, verify_signature};
@ -119,11 +120,12 @@ fn key_id_to_actor_id(key_id: &str) -> Result<String, url::ParseError> {
Ok(actor_id.to_string()) Ok(actor_id.to_string())
} }
/// Verifies HTTP signature and returns signer ID /// Verifies HTTP signature and returns signer
pub async fn verify_http_signature( pub async fn verify_http_signature(
config: &Config, config: &Config,
db_client: &impl GenericClient, db_client: &impl GenericClient,
request: &HttpRequest, request: &HttpRequest,
no_fetch: bool,
) -> Result<DbActorProfile, VerificationError> { ) -> Result<DbActorProfile, VerificationError> {
let signature_data = parse_http_signature( let signature_data = parse_http_signature(
request.method(), request.method(),
@ -132,17 +134,21 @@ pub async fn verify_http_signature(
)?; )?;
let actor_id = key_id_to_actor_id(&signature_data.key_id)?; let actor_id = key_id_to_actor_id(&signature_data.key_id)?;
let actor_profile = match get_or_import_profile_by_actor_id( let actor_profile = if no_fetch {
db_client, get_profile_by_actor_id(db_client, &actor_id).await?
&config.instance(), } else {
&config.media_dir(), match get_or_import_profile_by_actor_id(
&actor_id, db_client,
).await { &config.instance(),
Ok(profile) => profile, &config.media_dir(),
Err(ImportError::DatabaseError(error)) => return Err(error.into()), &actor_id,
Err(other_error) => { ).await {
return Err(VerificationError::ActorError(other_error.to_string())); Ok(profile) => profile,
}, Err(ImportError::DatabaseError(error)) => return Err(error.into()),
Err(other_error) => {
return Err(VerificationError::ActorError(other_error.to_string()));
},
}
}; };
let actor = actor_profile.actor_json.as_ref() let actor = actor_profile.actor_json.as_ref()
.ok_or(VerificationError::ActorError("invalid profile".to_string()))?; .ok_or(VerificationError::ActorError("invalid profile".to_string()))?;