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::{
|
use crate::models::relationships::queries::{
|
||||||
follow_request_accepted,
|
follow_request_accepted,
|
||||||
follow_request_rejected,
|
follow_request_rejected,
|
||||||
follow, unfollow,
|
follow,
|
||||||
|
unfollow,
|
||||||
};
|
};
|
||||||
use crate::models::users::queries::get_user_by_id;
|
use crate::models::users::queries::get_user_by_id;
|
||||||
use super::activity::{Object, Activity, create_activity_accept_follow};
|
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::fetcher::{fetch_avatar_and_banner, fetch_attachment};
|
||||||
use super::vocabulary::*;
|
use super::vocabulary::*;
|
||||||
|
|
||||||
fn parse_actor_id(actor_id: &str) -> Result<String, ValidationError> {
|
fn parse_actor_id(
|
||||||
let url_regexp = Regex::new(r"^https?://.+/users/(?P<username>[0-9a-z_]+)$").unwrap();
|
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)
|
let url_caps = url_regexp.captures(&actor_id)
|
||||||
.ok_or(ValidationError("invalid actor ID"))?;
|
.ok_or(ValidationError("invalid actor ID"))?;
|
||||||
let username = url_caps.name("username")
|
let username = url_caps.name("username")
|
||||||
|
@ -37,8 +46,16 @@ fn parse_actor_id(actor_id: &str) -> Result<String, ValidationError> {
|
||||||
Ok(username)
|
Ok(username)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_object_id(object_id: &str) -> Result<Uuid, ValidationError> {
|
fn parse_object_id(
|
||||||
let url_regexp = Regex::new(r"^https?://.+/objects/(?P<uuid>[0-9a-f-]+)$").unwrap();
|
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)
|
let url_caps = url_regexp.captures(&object_id)
|
||||||
.ok_or(ValidationError("invalid object ID"))?;
|
.ok_or(ValidationError("invalid object ID"))?;
|
||||||
let object_uuid: Uuid = url_caps.name("uuid")
|
let object_uuid: Uuid = url_caps.name("uuid")
|
||||||
|
@ -66,14 +83,13 @@ pub async fn receive_activity(
|
||||||
(ACCEPT, FOLLOW) => {
|
(ACCEPT, FOLLOW) => {
|
||||||
let object: Object = serde_json::from_value(activity.object)
|
let object: Object = serde_json::from_value(activity.object)
|
||||||
.map_err(|_| ValidationError("invalid object"))?;
|
.map_err(|_| ValidationError("invalid object"))?;
|
||||||
// TODO: reject if object ID contains wrong instance URI
|
let follow_request_id = parse_object_id(&config.instance_url(), &object.id)?;
|
||||||
let follow_request_id = parse_object_id(&object.id)?;
|
|
||||||
follow_request_accepted(db_client, &follow_request_id).await?;
|
follow_request_accepted(db_client, &follow_request_id).await?;
|
||||||
},
|
},
|
||||||
(REJECT, FOLLOW) => {
|
(REJECT, FOLLOW) => {
|
||||||
let object: Object = serde_json::from_value(activity.object)
|
let object: Object = serde_json::from_value(activity.object)
|
||||||
.map_err(|_| ValidationError("invalid 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?;
|
follow_request_rejected(db_client, &follow_request_id).await?;
|
||||||
},
|
},
|
||||||
(CREATE, NOTE) => {
|
(CREATE, NOTE) => {
|
||||||
|
@ -118,8 +134,7 @@ pub async fn receive_activity(
|
||||||
.map_err(|_| HttpError::InternalError)?;
|
.map_err(|_| HttpError::InternalError)?;
|
||||||
let target_actor_id = activity.object.as_str()
|
let target_actor_id = activity.object.as_str()
|
||||||
.ok_or(ValidationError("invalid object"))?;
|
.ok_or(ValidationError("invalid object"))?;
|
||||||
// TODO: reject if object ID contains wrong instance URI
|
let target_username = parse_actor_id(&config.instance_url(), &target_actor_id)?;
|
||||||
let target_username = parse_actor_id(&target_actor_id)?;
|
|
||||||
let target_profile = get_profile_by_acct(db_client, &target_username).await?;
|
let target_profile = get_profile_by_acct(db_client, &target_username).await?;
|
||||||
// Create and send 'Accept' activity
|
// Create and send 'Accept' activity
|
||||||
let target_user = get_user_by_id(db_client, &target_profile.id).await?;
|
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 source_profile = get_profile_by_actor_id(db_client, &activity.actor).await?;
|
||||||
let target_actor_id = object.object
|
let target_actor_id = object.object
|
||||||
.ok_or(ValidationError("invalid object"))?;
|
.ok_or(ValidationError("invalid object"))?;
|
||||||
// TODO: reject if actor ID contains wrong instance URI
|
let target_username = parse_actor_id(&config.instance_url(), &target_actor_id)?;
|
||||||
let target_username = parse_actor_id(&target_actor_id)?;
|
|
||||||
let target_profile = get_profile_by_acct(db_client, &target_username).await?;
|
let target_profile = get_profile_by_acct(db_client, &target_username).await?;
|
||||||
unfollow(db_client, &source_profile.id, &target_profile.id).await?;
|
unfollow(db_client, &source_profile.id, &target_profile.id).await?;
|
||||||
},
|
},
|
||||||
|
@ -185,21 +199,29 @@ pub async fn receive_activity(
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
const INSTANCE_URL: &str = "https://example.org";
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_actor_id() {
|
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());
|
assert_eq!(username, "test".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_actor_id_wrong_path() {
|
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");
|
assert_eq!(error.to_string(), "invalid actor ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_actor_id_invalid_username() {
|
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");
|
assert_eq!(error.to_string(), "invalid actor ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,13 +232,14 @@ mod tests {
|
||||||
"https://example.org/objects/{}",
|
"https://example.org/objects/{}",
|
||||||
expected_uuid,
|
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);
|
assert_eq!(object_uuid, expected_uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_object_id_invalid_uuid() {
|
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");
|
assert_eq!(error.to_string(), "invalid object ID");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue