about summary refs log tree commit diff
path: root/MatrixAntiDmSpam/InviteHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MatrixAntiDmSpam/InviteHandler.cs')
-rw-r--r--MatrixAntiDmSpam/InviteHandler.cs140
1 files changed, 59 insertions, 81 deletions
diff --git a/MatrixAntiDmSpam/InviteHandler.cs b/MatrixAntiDmSpam/InviteHandler.cs

index 2a5d17b..26a88c7 100644 --- a/MatrixAntiDmSpam/InviteHandler.cs +++ b/MatrixAntiDmSpam/InviteHandler.cs
@@ -1,113 +1,91 @@ using System.Text.Json; using ArcaneLibs; using ArcaneLibs.Extensions; -using LibMatrix.EventTypes.Spec.State.RoomInfo; using LibMatrix.Helpers; -using LibMatrix.Utilities.Bot.Services; +using LibMatrix.RoomTypes; +using LibMatrix.Utilities.Bot.Interfaces; namespace MatrixAntiDmSpam; -public class InviteHandler(ILogger<InviteHandler> logger, AntiDmSpamConfiguration config, InviteStore inviteStore) : InviteHandlerHostedService.IInviteHandler { - public async Task HandleInviteAsync(InviteHandlerHostedService.InviteEventArgs invite) { - // logger.LogInformation("Received invite to room {}", invite.RoomId); - await LogInvite(invite); - await inviteStore.AddInviteAsync(invite); - } +public class RoomInviteHandler(ILogger<RoomInviteHandler> logger, AntiDmSpamConfiguration config) : IRoomInviteHandler { + public List<RoomInviteContext> Invites { get; } = []; - private async Task LogInvite(InviteHandlerHostedService.InviteEventArgs invite) { - if (string.IsNullOrWhiteSpace(config.LogRoom)) return; - var logRoom = invite.Homeserver.GetRoom(config.LogRoom); - var inviterName = await GetInviterNameAsync(invite); - string roomName = await GetRoomNameAsync(invite); + public List<Func<RoomInviteContext, Task>> OnInviteReceived { get; set; } = []; - logger.LogInformation("Inviter: {}, Room: {}", inviterName, roomName); + private GenericRoom? LogRoom { get; set; } - var message = new MessageBuilder() - .WithBody("Received invite to ").WithMention(invite.RoomId, roomName).WithBody(" from ").WithMention(invite.MemberEvent.Sender!, inviterName) - .Build(); + public async Task HandleInviteAsync(RoomInviteContext invite) { + if (!string.IsNullOrWhiteSpace(config.LogRoom)) + LogRoom = invite.Homeserver.GetRoom(config.LogRoom); - // TODO: can we filter this somehow to stay within event size limits? - // var serialisedInviteData = JsonNode.Parse(invite.InviteData.ToJson(ignoreNull: true)); - // message.AdditionalData!["gay.rory.invite_logger.invite_data"] = serialisedInviteData!; + Invites.Add(invite); + await LogInvite(invite); + foreach (var handler in OnInviteReceived) { + try { + await handler.Invoke(invite); + } + catch (Exception e) { + if (!string.IsNullOrWhiteSpace(config.LogRoom)) { + var logRoom = invite.Homeserver.GetRoom(config.LogRoom); + await logRoom.SendMessageEventAsync( + new MessageBuilder() + .WithBody($"Failed to execute invite handler {handler}...").WithNewline() + .WithCollapsibleSection("Stack trace", msb => msb.WithCodeBlock(e.ToString(), "cs")) + .Build() + ); + } + } + } + } + private async Task LogInvite(RoomInviteContext invite) { + logger.LogInformation("Received invite to {} from {}", invite.RoomId, invite.MemberEvent.Sender); + + if (LogRoom is null) return; var inviteData = invite.InviteData.ToJsonUtf8Bytes(ignoreNull: true); - var inviteDataFileUri = await invite.Homeserver.UploadFile(invite.RoomId + ".json", inviteData, "application/json"); - logger.LogInformation("Uploaded invite data ({}) to {}", Util.BytesToString(inviteData.Length), inviteDataFileUri); - // Dictionary<string, JsonElement> - message.AdditionalData!["gay.rory.invite_logger.invite_data_uri"] = JsonDocument.Parse($"\"{inviteDataFileUri}\"").RootElement; + var inviterNameTask = invite.TryGetInviterNameAsync(); + var roomNameTask = invite.TryGetRoomNameAsync(); + var inviteDataFileUriTask = invite.Homeserver.UploadFile(invite.RoomId + ".json", inviteData, "application/json"); + logger.LogInformation("Uploaded invite data ({}) to {}", Util.BytesToString(inviteData.Length), await inviteDataFileUriTask); + + await Task.WhenAll(inviterNameTask, roomNameTask, inviteDataFileUriTask); - await logRoom.SendMessageEventAsync(message); + var message = new MessageBuilder() + .WithBody("Received invite to ").WithMention(invite.RoomId, await roomNameTask).WithBody(" from ").WithMention(invite.MemberEvent.Sender!, await inviterNameTask) + .Build(); + + message.AdditionalData!["gay.rory.invite_logger.invite_data_uri"] = JsonDocument.Parse($"\"{await inviteDataFileUriTask}\"").RootElement; + + await LogRoom.SendMessageEventAsync(message); if (config.LogInviteDataAsFile) { - await logRoom.SendMessageEventAsync(new() { + await LogRoom.SendMessageEventAsync(new() { MessageType = "m.file", Body = invite.RoomId + ".json", FileName = invite.RoomId + ".json", - Url = inviteDataFileUri, + Url = await inviteDataFileUriTask, FileInfo = new() { Size = inviteData.Length, MimeType = "application/json" } }); } } - private async Task<string> GetInviterNameAsync(InviteHandlerHostedService.InviteEventArgs invite) { - var name = invite.InviteData.InviteState?.Events? - .FirstOrDefault(evt => evt is { Type: RoomMemberEventContent.EventId } && evt.StateKey == invite.MemberEvent.Sender)? - .ContentAs<RoomMemberEventContent>()?.DisplayName; - - if (!string.IsNullOrWhiteSpace(name)) - return name; - - try { - await invite.Homeserver.GetProfileAsync(invite.MemberEvent.Sender!); - } - catch { - //ignored - } - - return invite.MemberEvent.Sender!; - } - - private async Task<string> GetRoomNameAsync(InviteHandlerHostedService.InviteEventArgs invite) { - // try get room name from invite state - var name = invite.InviteData.InviteState?.Events? - .FirstOrDefault(evt => evt is { Type: RoomNameEventContent.EventId, StateKey: "" })? - .ContentAs<RoomNameEventContent>()?.Name; - - if (!string.IsNullOrWhiteSpace(name)) - return name; - - // try get room alias - var alias = invite.InviteData.InviteState?.Events? - .FirstOrDefault(evt => evt is { Type: RoomCanonicalAliasEventContent.EventId, StateKey: "" })? - .ContentAs<RoomCanonicalAliasEventContent>()?.Alias; - - if (!string.IsNullOrWhiteSpace(alias)) - return alias; - - // try get room name via public previews - try { -#pragma warning disable CS0618 // Type or member is obsolete - name = await invite.Homeserver.GetRoom(invite.RoomId).GetNameOrFallbackAsync(); -#pragma warning restore CS0618 // Type or member is obsolete - if (name != invite.RoomId && !string.IsNullOrWhiteSpace(name)) - return name; - } - catch { - //ignored - } + public async Task RejectInvite(RoomInviteContext invite, MessageBuilder reason) { + if (LogRoom is not null) + _ = LogRoom.SendMessageEventAsync(reason.Build()); - // fallback to room alias via public previews try { - alias = (await invite.Homeserver.GetRoom(invite.RoomId).GetCanonicalAliasAsync())?.Alias; - if (!string.IsNullOrWhiteSpace(alias)) - return alias; + await invite.Homeserver.GetRoom(invite.RoomId).LeaveAsync(); } - catch { - //ignored + catch (Exception e) { + if (LogRoom is not null) + await LogRoom.SendMessageEventAsync( + new MessageBuilder().WithColoredBody("#FF8800", $"Failed to leave {invite.RoomId}:").WithNewline() + .WithCodeBlock(e.ToString(), "cs") + .Build() + ); } - // fall back to room ID - return invite.RoomId; + Invites.Remove(invite); } } \ No newline at end of file