using System.Text.Json; using ArcaneLibs; using ArcaneLibs.Extensions; using LibMatrix.Helpers; using LibMatrix.RoomTypes; using LibMatrix.Utilities.Bot.Interfaces; using Microsoft.Extensions.Logging; namespace MatrixAntiDmSpam.Core; public class RoomInviteHandler(ILogger logger, AntiDmSpamConfiguration config) : IRoomInviteHandler { public List Invites { get; } = []; public List> OnInviteReceived { get; set; } = []; private GenericRoom? LogRoom { get; set; } public async Task HandleInviteAsync(RoomInviteContext invite) { if (!string.IsNullOrWhiteSpace(config.LogRoom)) LogRoom = invite.Homeserver.GetRoom(config.LogRoom); 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 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); 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() { MessageType = "m.file", Body = invite.RoomId + ".json", FileName = invite.RoomId + ".json", Url = await inviteDataFileUriTask, FileInfo = new() { Size = inviteData.Length, MimeType = "application/json" } }); } } public async Task RejectInvite(RoomInviteContext invite, MessageBuilder reason) { if (LogRoom is not null) _ = LogRoom.SendMessageEventAsync(reason.Build()); try { await invite.Homeserver.GetRoom(invite.RoomId).LeaveAsync(); } 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() ); } Invites.Remove(invite); } }