feat: Send intentional mentions in report messages

This commit is contained in:
nexy7574 2025-07-01 15:42:38 +01:00
parent 97e5cc4e2d
commit 59912709aa
No known key found for this signature in database
GPG key ID: 0FA334385D0B689F

View file

@ -1,4 +1,7 @@
use std::time::Duration; use std::{
ops::{Mul, Sub},
time::Duration,
};
use axum::extract::State; use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::InsecureClientIp;
@ -6,19 +9,35 @@ use conduwuit::{Err, Error, Result, debug_info, info, matrix::pdu::PduEvent, uti
use conduwuit_service::Services; use conduwuit_service::Services;
use rand::Rng; use rand::Rng;
use ruma::{ use ruma::{
EventId, RoomId, UserId, EventId, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId,
api::client::{ api::client::{
error::ErrorKind, error::ErrorKind,
report_user, report_user,
room::{report_content, report_room}, room::{report_content, report_room},
}, },
events::room::message, events::{
Mentions,
room::{
message,
message::{RoomMessageEvent, RoomMessageEventContent},
},
},
int, int,
}; };
use tokio::time::sleep; use tokio::time::sleep;
use crate::Ruma; use crate::Ruma;
struct Report {
sender: OwnedUserId,
room_id: Option<OwnedRoomId>,
event_id: Option<OwnedEventId>,
user_id: Option<OwnedUserId>,
report_type: String,
reason: Option<String>,
score: Option<ruma::Int>,
}
/// # `POST /_matrix/client/v3/rooms/{roomId}/report` /// # `POST /_matrix/client/v3/rooms/{roomId}/report`
/// ///
/// Reports an abusive room to homeserver admins /// Reports an abusive room to homeserver admins
@ -56,18 +75,17 @@ pub(crate) async fn report_room_route(
body.reason.as_deref().unwrap_or("") body.reason.as_deref().unwrap_or("")
); );
// send admin room message that we received the report with an @room ping for let report = Report {
// urgency sender: sender_user.to_owned(),
services room_id: Some(body.room_id.to_owned()),
.admin event_id: None,
.send_message(message::RoomMessageEventContent::text_markdown(format!( user_id: None,
"@room Room report received from {} -\n\nRoom ID: {}\n\nReport Reason: {}", report_type: "room".to_string(),
sender_user.to_owned(), reason: body.reason.clone(),
body.room_id, score: None,
body.reason.as_deref().unwrap_or("") };
)))
.await services.admin.send_message(build_report(report)).await.ok();
.ok();
Ok(report_room::v3::Response {}) Ok(report_room::v3::Response {})
} }
@ -108,23 +126,16 @@ pub(crate) async fn report_event_route(
body.event_id, body.event_id,
body.reason.as_deref().unwrap_or("") body.reason.as_deref().unwrap_or("")
); );
let report = Report {
// send admin room message that we received the report with an @room ping for sender: sender_user.to_owned(),
// urgency room_id: Some(body.room_id.to_owned()),
services event_id: Some(body.event_id.to_owned()),
.admin user_id: None,
.send_message(message::RoomMessageEventContent::text_markdown(format!( report_type: "event".to_string(),
"@room Event report received from {} -\n\nEvent ID: {}\nRoom ID: {}\nSent By: \ reason: body.reason.clone(),
{}\n\nReport Score: {}\nReport Reason: {}", score: body.score,
sender_user.to_owned(), };
pdu.event_id, services.admin.send_message(build_report(report)).await.ok();
pdu.room_id,
pdu.sender,
body.score.unwrap_or_else(|| ruma::Int::from(0)),
body.reason.as_deref().unwrap_or("")
)))
.await
.ok();
Ok(report_content::v3::Response {}) Ok(report_content::v3::Response {})
} }
@ -152,24 +163,23 @@ pub(crate) async fn report_user_route(
return Ok(report_user::v3::Response {}); return Ok(report_user::v3::Response {});
} }
let report = Report {
sender: sender_user.to_owned(),
room_id: None,
event_id: None,
user_id: Some(body.user_id.to_owned()),
report_type: "user".to_string(),
reason: body.reason.clone(),
score: None,
};
info!( info!(
"Received room report from {sender_user} for user {} with reason: \"{}\"", "Received room report from {sender_user} for user {} with reason: \"{}\"",
body.user_id, body.user_id,
body.reason.as_deref().unwrap_or("") body.reason.as_deref().unwrap_or("")
); );
// send admin room message that we received the report with an @room ping for services.admin.send_message(build_report(report)).await.ok();
// urgency
services
.admin
.send_message(message::RoomMessageEventContent::text_markdown(format!(
"@room User report received from {} -\n\nUser ID: {}\n\nReport Reason: {}",
sender_user.to_owned(),
body.user_id,
body.reason.as_deref().unwrap_or("")
)))
.await
.ok();
Ok(report_user::v3::Response {}) Ok(report_user::v3::Response {})
} }
@ -231,6 +241,33 @@ async fn is_event_report_valid(
Ok(()) Ok(())
} }
/// Builds a report message to be sent to the admin room.
fn build_report(report: Report) -> RoomMessageEventContent {
let mut text =
format!("@room New {} report received from {}:\n\n", report.report_type, report.sender);
if report.user_id.is_some() {
text.push_str(&format!("- Reported User ID: `{}`\n", report.user_id.unwrap()));
}
if report.room_id.is_some() {
text.push_str(&format!("- Reported Room ID: `{}`\n", report.room_id.unwrap()));
}
if report.event_id.is_some() {
text.push_str(&format!("- Reported Event ID: `{}`\n", report.event_id.unwrap()));
}
if let Some(score) = report.score {
if score < int!(0) {
score.mul(int!(-1)); // invert the score to make it N/100
// unsure why the spec says -100 to 0, but 0 to 100 is more human.
}
text.push_str(&format!("- User-supplied offensiveness score: {}%\n", -score));
}
if let Some(reason) = report.reason {
text.push_str(&format!("- Report Reason: {}\n", reason));
}
RoomMessageEventContent::text_markdown(text).add_mentions(Mentions::with_room_mention());
}
/// even though this is kinda security by obscurity, let's still make a small /// even though this is kinda security by obscurity, let's still make a small
/// random delay sending a response per spec suggestion regarding /// random delay sending a response per spec suggestion regarding
/// enumerating for potential events existing in our server. /// enumerating for potential events existing in our server.