From 087a077f7db8bf6894137d6988501c5fcb2ec643 Mon Sep 17 00:00:00 2001 From: silverpill Date: Mon, 20 Sep 2021 21:45:33 +0000 Subject: [PATCH] Make actor ID and object ID parsers more strict --- src/activitypub/receiver.rs | 57 ++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/src/activitypub/receiver.rs b/src/activitypub/receiver.rs index f6cd6ca..24b8855 100644 --- a/src/activitypub/receiver.rs +++ b/src/activitypub/receiver.rs @@ -17,7 +17,8 @@ use crate::models::profiles::types::ProfileUpdateData; use crate::models::relationships::queries::{ follow_request_accepted, follow_request_rejected, - follow, unfollow, + follow, + unfollow, }; use crate::models::users::queries::get_user_by_id; use super::activity::{Object, Activity, create_activity_accept_follow}; @@ -26,8 +27,16 @@ use super::deliverer::deliver_activity; use super::fetcher::{fetch_avatar_and_banner, fetch_attachment}; use super::vocabulary::*; -fn parse_actor_id(actor_id: &str) -> Result { - let url_regexp = Regex::new(r"^https?://.+/users/(?P[0-9a-z_]+)$").unwrap(); +fn parse_actor_id( + instance_url: &str, + actor_id: &str, +) -> Result { + let url_regexp_str = format!( + "^{}/users/(?P[0-9a-z_]+)$", + instance_url.replace(".", r"\."), + ); + let url_regexp = Regex::new(&url_regexp_str) + .map_err(|_| ValidationError("error"))?; let url_caps = url_regexp.captures(&actor_id) .ok_or(ValidationError("invalid actor ID"))?; let username = url_caps.name("username") @@ -37,8 +46,16 @@ fn parse_actor_id(actor_id: &str) -> Result { Ok(username) } -fn parse_object_id(object_id: &str) -> Result { - let url_regexp = Regex::new(r"^https?://.+/objects/(?P[0-9a-f-]+)$").unwrap(); +fn parse_object_id( + instance_url: &str, + object_id: &str, +) -> Result { + let url_regexp_str = format!( + "^{}/objects/(?P[0-9a-f-]+)$", + instance_url.replace(".", r"\."), + ); + let url_regexp = Regex::new(&url_regexp_str) + .map_err(|_| ValidationError("error"))?; let url_caps = url_regexp.captures(&object_id) .ok_or(ValidationError("invalid object ID"))?; let object_uuid: Uuid = url_caps.name("uuid") @@ -66,14 +83,13 @@ pub async fn receive_activity( (ACCEPT, FOLLOW) => { let object: Object = serde_json::from_value(activity.object) .map_err(|_| ValidationError("invalid object"))?; - // TODO: reject if object ID contains wrong instance URI - let follow_request_id = parse_object_id(&object.id)?; + let follow_request_id = parse_object_id(&config.instance_url(), &object.id)?; follow_request_accepted(db_client, &follow_request_id).await?; }, (REJECT, FOLLOW) => { let object: Object = serde_json::from_value(activity.object) .map_err(|_| ValidationError("invalid object"))?; - let follow_request_id = parse_object_id(&object.id)?; + let follow_request_id = parse_object_id(&config.instance_url(), &object.id)?; follow_request_rejected(db_client, &follow_request_id).await?; }, (CREATE, NOTE) => { @@ -118,8 +134,7 @@ pub async fn receive_activity( .map_err(|_| HttpError::InternalError)?; let target_actor_id = activity.object.as_str() .ok_or(ValidationError("invalid object"))?; - // TODO: reject if object ID contains wrong instance URI - let target_username = parse_actor_id(&target_actor_id)?; + let target_username = parse_actor_id(&config.instance_url(), &target_actor_id)?; let target_profile = get_profile_by_acct(db_client, &target_username).await?; // Create and send 'Accept' activity let target_user = get_user_by_id(db_client, &target_profile.id).await?; @@ -145,8 +160,7 @@ pub async fn receive_activity( let source_profile = get_profile_by_actor_id(db_client, &activity.actor).await?; let target_actor_id = object.object .ok_or(ValidationError("invalid object"))?; - // TODO: reject if actor ID contains wrong instance URI - let target_username = parse_actor_id(&target_actor_id)?; + let target_username = parse_actor_id(&config.instance_url(), &target_actor_id)?; let target_profile = get_profile_by_acct(db_client, &target_username).await?; unfollow(db_client, &source_profile.id, &target_profile.id).await?; }, @@ -185,21 +199,29 @@ pub async fn receive_activity( mod tests { use super::*; + const INSTANCE_URL: &str = "https://example.org"; + #[test] fn test_parse_actor_id() { - let username = parse_actor_id("https://example.org/users/test").unwrap(); + let username = parse_actor_id(INSTANCE_URL, "https://example.org/users/test").unwrap(); assert_eq!(username, "test".to_string()); } #[test] fn test_parse_actor_id_wrong_path() { - let error = parse_actor_id("https://example.org/user/test").unwrap_err(); + let error = parse_actor_id(INSTANCE_URL, "https://example.org/user/test").unwrap_err(); assert_eq!(error.to_string(), "invalid actor ID"); } #[test] fn test_parse_actor_id_invalid_username() { - let error = parse_actor_id("https://example.org/users/tes-t").unwrap_err(); + let error = parse_actor_id(INSTANCE_URL, "https://example.org/users/tes-t").unwrap_err(); + assert_eq!(error.to_string(), "invalid actor ID"); + } + + #[test] + fn test_parse_actor_id_invalid_instance_url() { + let error = parse_actor_id(INSTANCE_URL, "https://example.gov/users/test").unwrap_err(); assert_eq!(error.to_string(), "invalid actor ID"); } @@ -210,13 +232,14 @@ mod tests { "https://example.org/objects/{}", expected_uuid, ); - let object_uuid = parse_object_id(&object_id).unwrap(); + let object_uuid = parse_object_id(INSTANCE_URL, &object_id).unwrap(); assert_eq!(object_uuid, expected_uuid); } #[test] fn test_parse_object_id_invalid_uuid() { - let error = parse_object_id("https://example.org/objects/1234").unwrap_err(); + let object_id = "https://example.org/objects/1234"; + let error = parse_object_id(INSTANCE_URL, object_id).unwrap_err(); assert_eq!(error.to_string(), "invalid object ID"); } }