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.
|
||||
- Support account migration from Mastodon.
|
||||
- Created API endpoint for managing client configurations.
|
||||
- Reject unsolicited public posts.
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -348,6 +348,24 @@ pub async fn get_followers_paginated(
|
|||
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(
|
||||
db_client: &impl DatabaseClient,
|
||||
profile_id: &Uuid,
|
||||
|
@ -581,10 +599,14 @@ mod tests {
|
|||
..Default::default()
|
||||
};
|
||||
let source = create_user(db_client, source_data).await.unwrap();
|
||||
let target_actor_id = "https://example.org/users/1";
|
||||
let target_data = ProfileCreateData {
|
||||
username: "followed".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()
|
||||
};
|
||||
let target = create_profile(db_client, target_data).await.unwrap();
|
||||
|
@ -604,6 +626,10 @@ mod tests {
|
|||
assert_eq!(follow_request.request_status, FollowRequestStatus::Accepted);
|
||||
let following = get_following(db_client, &source.id).await.unwrap();
|
||||
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
|
||||
let follow_request_id = unfollow(db_client, &source.id, &target.id)
|
||||
.await.unwrap().unwrap();
|
||||
|
|
|
@ -19,6 +19,7 @@ use mitra_models::{
|
|||
types::{Post, PostCreateData, Visibility},
|
||||
},
|
||||
profiles::types::DbActorProfile,
|
||||
relationships::queries::has_local_followers,
|
||||
users::queries::get_user_by_name,
|
||||
};
|
||||
use mitra_utils::{
|
||||
|
@ -655,6 +656,26 @@ pub async fn handle_note(
|
|||
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(
|
||||
config: &Config,
|
||||
db_client: &mut impl DatabaseClient,
|
||||
|
@ -663,6 +684,13 @@ pub async fn handle_create(
|
|||
) -> HandlerResult {
|
||||
let object: Object = serde_json::from_value(activity["object"].to_owned())
|
||||
.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_received = if is_authenticated {
|
||||
Some(object)
|
||||
|
@ -673,7 +701,7 @@ pub async fn handle_create(
|
|||
};
|
||||
import_post(
|
||||
db_client,
|
||||
&config.instance(),
|
||||
&instance,
|
||||
&MediaStorage::from(config),
|
||||
object_id,
|
||||
object_received,
|
||||
|
|
Loading…
Reference in a new issue