about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-05-24 21:10:25 +0200
committerRory& <root@rory.gay>2025-05-24 21:10:25 +0200
commit6af08dc225887a32bcbb3421cc4122132fa3ce3d (patch)
treef5a56fd21fc56a1ee4dbd446bb004554930186f8
parentLog config on startupg (diff)
downloadMatrixAntiDmSpam-6af08dc225887a32bcbb3421cc4122132fa3ce3d.tar.xz
Implement automatic reporting
-rw-r--r--MatrixAntiDmSpam.Core/ReportManager.cs84
1 files changed, 80 insertions, 4 deletions
diff --git a/MatrixAntiDmSpam.Core/ReportManager.cs b/MatrixAntiDmSpam.Core/ReportManager.cs

index 46f0666..b52ecb7 100644 --- a/MatrixAntiDmSpam.Core/ReportManager.cs +++ b/MatrixAntiDmSpam.Core/ReportManager.cs
@@ -1,3 +1,6 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; +using ArcaneLibs.Extensions; using LibMatrix; using LibMatrix.Helpers; using LibMatrix.Homeservers; @@ -17,15 +20,88 @@ public class ReportManager( public async Task StartAsync(CancellationToken cancellationToken) { if (config.ReportBlockedInvites) { - inviteManager.OnInviteRejected.Add(ReportRejectedInvite); + inviteManager.OnBeforeInviteRejected.Add(ReportRejectedInvite); } } public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; private async Task ReportRejectedInvite(RoomInviteContext invite, StateEventResponse policyEvent) { - logger.LogInformation("ReportRejectedInvite not implemented"); - var msgTask = _logRoom?.SendMessageEventAsync(new MessageBuilder().WithBody("meow").Build()); - if (msgTask is not null) await msgTask; + logger.LogInformation("Reporting rejected invite to {}", homeserver.ServerName); + + var reportContent = "MatrixAntiDmSpam[fmt=v1] | " + new ReportContent { + Reason = "Invite rejected due to matching policy", + RoomName = await invite.TryGetRoomNameAsync(), + Inviter = await invite.TryGetInviterNameAsync(), + InviteEvent = invite.MemberEvent, + PolicyEvent = policyEvent, + RoomId = invite.RoomId, + }.ToJson(); + + logger.LogError(reportContent); + + try { + await homeserver.ReportRoomEventAsync(invite.RoomId, invite.MemberEvent.EventId!, reportContent, score: 50); + var successMessage = new MessageBuilder() + .WithColoredBody("#00FF00", $"Successfully reported {invite.MemberEvent.EventId} to {homeserver.ServerName}!") + .Build(); + + if (_logRoom != null) + await _logRoom.SendMessageEventAsync(successMessage); + } + catch { + // ignored, we're not expecting this to work on spec compliant homeservers + } + + try { + await homeserver.ReportRoomAsync(invite.RoomId, reportContent); + var successMessage = new MessageBuilder() + .WithColoredBody("#00FF00", $"Successfully reported {invite.RoomId} to {homeserver.ServerName}!") + .Build(); + + if (_logRoom != null) + await _logRoom.SendMessageEventAsync(successMessage); + } + catch (Exception e) { + logger.LogError("Failed to report room {roomId}: {exception}", invite.RoomId, e); + } + + try { + await homeserver.ReportUserAsync(invite.MemberEvent.Sender!, reportContent); + var successMessage = new MessageBuilder() + .WithColoredBody("#00FF00", $"Successfully reported {invite.MemberEvent.Sender} to {homeserver.ServerName}!") + .Build(); + + if (_logRoom != null) + await _logRoom.SendMessageEventAsync(successMessage); + } + catch (Exception e) { + logger.LogError("Failed to report user {userId}: {exception}", invite.MemberEvent.Sender, e); + } + } + + [SuppressMessage("ReSharper", "UnusedMember.Local", Justification = "Used for JSON serialization")] + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local", Justification = "Used for JSON serialization")] + private class ReportContent { + [JsonPropertyName("report_id")] + public Guid ReportId { get; set; } = Guid.NewGuid(); + + [JsonPropertyName("room_id")] + public required string RoomId { get; set; } + + [JsonPropertyName("reason")] + public required string Reason { get; set; } + + [JsonPropertyName("inviter")] + public required string Inviter { get; set; } + + [JsonPropertyName("room_name")] + public required string RoomName { get; set; } + + [JsonPropertyName("invite_event")] + public required StateEventResponse InviteEvent { get; set; } + + [JsonPropertyName("policy_event")] + public required StateEventResponse PolicyEvent { get; set; } } } \ No newline at end of file