Make actor ID and object ID parsers more strict
This commit is contained in:
parent
602e4ec229
commit
087a077f7d
1 changed files with 40 additions and 17 deletions
|
@ -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<String, ValidationError> {
|
||||
let url_regexp = Regex::new(r"^https?://.+/users/(?P<username>[0-9a-z_]+)$").unwrap();
|
||||
fn parse_actor_id(
|
||||
instance_url: &str,
|
||||
actor_id: &str,
|
||||
) -> Result<String, ValidationError> {
|
||||
let url_regexp_str = format!(
|
||||
"^{}/users/(?P<username>[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<String, ValidationError> {
|
|||
Ok(username)
|
||||
}
|
||||
|
||||
fn parse_object_id(object_id: &str) -> Result<Uuid, ValidationError> {
|
||||
let url_regexp = Regex::new(r"^https?://.+/objects/(?P<uuid>[0-9a-f-]+)$").unwrap();
|
||||
fn parse_object_id(
|
||||
instance_url: &str,
|
||||
object_id: &str,
|
||||
) -> Result<Uuid, ValidationError> {
|
||||
let url_regexp_str = format!(
|
||||
"^{}/objects/(?P<uuid>[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");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue