Reject unsolicited public posts
This commit is contained in:
parent
fc82c83421
commit
8708abd9cd
3 changed files with 57 additions and 2 deletions
|
@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Populate `alsoKnownAs` property on actor object with declared aliases.
|
- Populate `alsoKnownAs` property on actor object with declared aliases.
|
||||||
- Support account migration from Mastodon.
|
- Support account migration from Mastodon.
|
||||||
- Created API endpoint for managing client configurations.
|
- Created API endpoint for managing client configurations.
|
||||||
|
- Reject unsolicited public posts.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -348,6 +348,24 @@ pub async fn get_followers_paginated(
|
||||||
Ok(related_profiles)
|
Ok(related_profiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn has_local_followers(
|
||||||
|
db_client: &impl DatabaseClient,
|
||||||
|
actor_id: &str,
|
||||||
|
) -> Result<bool, DatabaseError> {
|
||||||
|
let maybe_row = db_client.query_opt(
|
||||||
|
"
|
||||||
|
SELECT 1
|
||||||
|
FROM relationship
|
||||||
|
JOIN actor_profile ON (relationship.target_id = actor_profile.id)
|
||||||
|
WHERE
|
||||||
|
actor_profile.actor_id = $1
|
||||||
|
AND relationship_type = $2
|
||||||
|
",
|
||||||
|
&[&actor_id, &RelationshipType::Follow]
|
||||||
|
).await?;
|
||||||
|
Ok(maybe_row.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_following(
|
pub async fn get_following(
|
||||||
db_client: &impl DatabaseClient,
|
db_client: &impl DatabaseClient,
|
||||||
profile_id: &Uuid,
|
profile_id: &Uuid,
|
||||||
|
@ -581,10 +599,14 @@ mod tests {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let source = create_user(db_client, source_data).await.unwrap();
|
let source = create_user(db_client, source_data).await.unwrap();
|
||||||
|
let target_actor_id = "https://example.org/users/1";
|
||||||
let target_data = ProfileCreateData {
|
let target_data = ProfileCreateData {
|
||||||
username: "followed".to_string(),
|
username: "followed".to_string(),
|
||||||
hostname: Some("example.org".to_string()),
|
hostname: Some("example.org".to_string()),
|
||||||
actor_json: Some(DbActor::default()),
|
actor_json: Some(DbActor {
|
||||||
|
id: target_actor_id.to_string(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let target = create_profile(db_client, target_data).await.unwrap();
|
let target = create_profile(db_client, target_data).await.unwrap();
|
||||||
|
@ -604,6 +626,10 @@ mod tests {
|
||||||
assert_eq!(follow_request.request_status, FollowRequestStatus::Accepted);
|
assert_eq!(follow_request.request_status, FollowRequestStatus::Accepted);
|
||||||
let following = get_following(db_client, &source.id).await.unwrap();
|
let following = get_following(db_client, &source.id).await.unwrap();
|
||||||
assert_eq!(following[0].id, target.id);
|
assert_eq!(following[0].id, target.id);
|
||||||
|
let target_has_followers =
|
||||||
|
has_local_followers(db_client, target_actor_id).await.unwrap();
|
||||||
|
assert_eq!(target_has_followers, true);
|
||||||
|
|
||||||
// Unfollow
|
// Unfollow
|
||||||
let follow_request_id = unfollow(db_client, &source.id, &target.id)
|
let follow_request_id = unfollow(db_client, &source.id, &target.id)
|
||||||
.await.unwrap().unwrap();
|
.await.unwrap().unwrap();
|
||||||
|
|
|
@ -19,6 +19,7 @@ use mitra_models::{
|
||||||
types::{Post, PostCreateData, Visibility},
|
types::{Post, PostCreateData, Visibility},
|
||||||
},
|
},
|
||||||
profiles::types::DbActorProfile,
|
profiles::types::DbActorProfile,
|
||||||
|
relationships::queries::has_local_followers,
|
||||||
users::queries::get_user_by_name,
|
users::queries::get_user_by_name,
|
||||||
};
|
};
|
||||||
use mitra_utils::{
|
use mitra_utils::{
|
||||||
|
@ -655,6 +656,26 @@ pub async fn handle_note(
|
||||||
Ok(post)
|
Ok(post)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn is_unsolicited_message(
|
||||||
|
db_client: &impl DatabaseClient,
|
||||||
|
instance_url: &str,
|
||||||
|
object: &Object,
|
||||||
|
) -> Result<bool, HandlerError> {
|
||||||
|
let author_id = get_object_attributed_to(object)?;
|
||||||
|
let author_has_followers =
|
||||||
|
has_local_followers(db_client, &author_id).await?;
|
||||||
|
let audience = get_audience(object)?;
|
||||||
|
let has_local_recipients = audience.iter().any(|actor_id| {
|
||||||
|
parse_local_actor_id(instance_url, actor_id).is_ok()
|
||||||
|
});
|
||||||
|
let result =
|
||||||
|
object.in_reply_to.is_none() &&
|
||||||
|
is_public_object(&audience) &&
|
||||||
|
!has_local_recipients &&
|
||||||
|
!author_has_followers;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle_create(
|
pub async fn handle_create(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
db_client: &mut impl DatabaseClient,
|
db_client: &mut impl DatabaseClient,
|
||||||
|
@ -663,6 +684,13 @@ pub async fn handle_create(
|
||||||
) -> HandlerResult {
|
) -> HandlerResult {
|
||||||
let object: Object = serde_json::from_value(activity["object"].to_owned())
|
let object: Object = serde_json::from_value(activity["object"].to_owned())
|
||||||
.map_err(|_| ValidationError("invalid object"))?;
|
.map_err(|_| ValidationError("invalid object"))?;
|
||||||
|
let instance = config.instance();
|
||||||
|
|
||||||
|
if is_unsolicited_message(db_client, &instance.url(), &object).await? {
|
||||||
|
log::warn!("unsolicited message rejected: {}", object.id);
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
let object_id = object.id.clone();
|
let object_id = object.id.clone();
|
||||||
let object_received = if is_authenticated {
|
let object_received = if is_authenticated {
|
||||||
Some(object)
|
Some(object)
|
||||||
|
@ -673,7 +701,7 @@ pub async fn handle_create(
|
||||||
};
|
};
|
||||||
import_post(
|
import_post(
|
||||||
db_client,
|
db_client,
|
||||||
&config.instance(),
|
&instance,
|
||||||
&MediaStorage::from(config),
|
&MediaStorage::from(config),
|
||||||
object_id,
|
object_id,
|
||||||
object_received,
|
object_received,
|
||||||
|
|
Loading…
Reference in a new issue