about summary refs log tree commit diff
path: root/MatrixAntiDmSpam.Core/RoomInviteHandler.cs
blob: 41f4011413d645ed31157ed8a0b934cf0b3c1d0b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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<RoomInviteHandler> logger, AntiDmSpamConfiguration config) : IRoomInviteHandler {
    public List<RoomInviteContext> Invites { get; } = [];

    public List<Func<RoomInviteContext, Task>> 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);
    }
}