Don't fetch signer when processing Delete(Person) activity
This commit is contained in:
parent
c89ee4fd7b
commit
8407bbe842
2 changed files with 39 additions and 28 deletions
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()))?;
|
||||||
|
|
Loading…
Reference in a new issue