diff options
author | Rory& <root@rory.gay> | 2024-10-03 20:53:24 +0200 |
---|---|---|
committer | Rory& <root@rory.gay> | 2024-10-03 20:53:24 +0200 |
commit | 1041c0ade1700d1a56e4b2585c6a4e20d7123f81 (patch) | |
tree | e6af21cd725b34517501acd5088fb5805506cf16 | |
parent | Changes (diff) | |
download | MatrixUtils-1041c0ade1700d1a56e4b2585c6a4e20d7123f81.tar.xz |
Small fixes, fix policy list editor
m--------- | LibMatrix | 0 | ||||
-rw-r--r-- | MatrixUtils.Web/Pages/Index.razor | 12 | ||||
-rw-r--r-- | MatrixUtils.Web/Pages/LoginPage.razor | 44 | ||||
-rw-r--r-- | MatrixUtils.Web/Pages/Rooms/PolicyList.razor | 4 | ||||
-rw-r--r-- | MatrixUtils.Web/Pages/Tools/Index.razor | 2 | ||||
-rw-r--r-- | MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor | 27 | ||||
-rw-r--r-- | MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectedRoomsEditor.razor | 143 | ||||
-rw-r--r-- | MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectionsEditor.razor (renamed from MatrixUtils.Web/Pages/Tools/Moderation/DraupnirProtectedRoomsEditor.razor) | 41 | ||||
-rw-r--r-- | MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirWatchedListsEditor.razor | 139 | ||||
-rw-r--r-- | MatrixUtils.Web/Pages/Tools/User/ViewAccountData.razor | 2 |
10 files changed, 389 insertions, 25 deletions
diff --git a/LibMatrix b/LibMatrix -Subproject ba7c369846086133b59af1cee68b2d836589f37 +Subproject 77650d16a9cc66fdfe393320164cd8248cdff38 diff --git a/MatrixUtils.Web/Pages/Index.razor b/MatrixUtils.Web/Pages/Index.razor index b1a52d5..4be91b7 100644 --- a/MatrixUtils.Web/Pages/Index.razor +++ b/MatrixUtils.Web/Pages/Index.razor @@ -168,17 +168,11 @@ Small collection of tools to do not-so-everyday things. } List<string> offlineServers = []; - var sema = new SemaphoreSlim(64, 64); + var sema = new SemaphoreSlim(8, 8); var updateSw = Stopwatch.StartNew(); var tasks = tokens.Select(async token => { await sema.WaitAsync(); - if ((!string.IsNullOrWhiteSpace(token.Proxy) && offlineServers.Contains(token.Proxy)) || offlineServers.Contains(token.Homeserver)) { - _offlineSessions.Add(token); - sema.Release(); - scannedSessions++; - return; - } - + AuthenticatedHomeserverGeneric hs; try { hs = await hsProvider.GetAuthenticatedWithToken(token.Homeserver, token.AccessToken, token.Proxy); @@ -187,7 +181,7 @@ Small collection of tools to do not-so-everyday things. var serverVersionTask = hs.FederationClient?.GetServerVersionAsync(); _sessions.Add(new() { UserInfo = new() { - AvatarUrl = (await profileTask).AvatarUrl ?? "meow", + AvatarUrl = (await profileTask).AvatarUrl, RoomCount = (await joinedRoomsTask).Count, DisplayName = (await profileTask).DisplayName ?? hs.WhoAmI.UserId }, diff --git a/MatrixUtils.Web/Pages/LoginPage.razor b/MatrixUtils.Web/Pages/LoginPage.razor index 6c869ac..d43913c 100644 --- a/MatrixUtils.Web/Pages/LoginPage.razor +++ b/MatrixUtils.Web/Pages/LoginPage.razor @@ -27,6 +27,27 @@ <br/> <br/> + +<h4>Add with access token</h4> +<hr/> + +<span style="display: block;"> + <label>Homeserver:</label> + <FancyTextBox @bind-Value="@newRecordInput.Homeserver"></FancyTextBox> +</span> +<span style="display: block;"> + <label>Access token:</label> + <FancyTextBox @bind-Value="@newRecordInput.Password" IsPassword="true"></FancyTextBox> +</span> +<span style="display: block"> + <label>Proxy (<a href="https://cgit.rory.gay/matrix/MxApiExtensions.git">MxApiExtensions</a> or similar):</label> + <FancyTextBox @bind-Value="@newRecordInput.Proxy"></FancyTextBox> +</span> +<br/> +<LinkButton OnClick="@(() => AddWithAccessToken(newRecordInput))">Add session</LinkButton> +<br/> +<br/> + <h4>Import from TSV</h4> <hr/> <span>Import credentials from a TSV (Tab Separated Values) file</span><br/> @@ -156,4 +177,27 @@ internal Exception? Exception { get; set; } } + private async Task AddWithAccessToken(LoginStruct record) { + try { + var session = await hsProvider.GetAuthenticatedWithToken(record.Homeserver, record.Password, record.Proxy); + if (session == null) { + Console.WriteLine($"Failed to login to {record.Homeserver} as {record.Username}!"); + return; + } + + await RMUStorage.AddToken(new UserAuth() { + UserId = session.WhoAmI.UserId, + AccessToken = session.AccessToken, + Proxy = record.Proxy, + DeviceId = session.WhoAmI.DeviceId + }); + LoggedInSessions = await RMUStorage.GetAllTokens(); + } + catch (Exception e) { + Console.WriteLine($"Failed to login to {record.Homeserver} as {record.Username}!"); + Console.WriteLine(e); + record.Exception = e; + } + } + } \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor index 4dc2adc..d57aa43 100644 --- a/MatrixUtils.Web/Pages/Rooms/PolicyList.razor +++ b/MatrixUtils.Web/Pages/Rooms/PolicyList.razor @@ -214,13 +214,13 @@ else { private string GetPolicyTypeName(Type type) => GetPolicyTypeNameOrNull(type) ?? type.Name; private async Task RemovePolicyAsync(StateEventResponse policyEvent) { - await Room.SendStateEventAsync(policyEvent.Type, policyEvent.StateKey.UrlEncode(), new { }); + await Room.SendStateEventAsync(policyEvent.Type, policyEvent.StateKey, new { }); PolicyEventsByType[policyEvent.MappedType].Remove(policyEvent); await LoadStatesAsync(); } private async Task UpdatePolicyAsync(StateEventResponse policyEvent) { - await Room.SendStateEventAsync(policyEvent.Type, policyEvent.StateKey.UrlEncode(), policyEvent.RawContent); + await Room.SendStateEventAsync(policyEvent.Type, policyEvent.StateKey, policyEvent.RawContent); CurrentlyEditingEvent = null; await LoadStatesAsync(); } diff --git a/MatrixUtils.Web/Pages/Tools/Index.razor b/MatrixUtils.Web/Pages/Tools/Index.razor index e68bb9a..f99e932 100644 --- a/MatrixUtils.Web/Pages/Tools/Index.razor +++ b/MatrixUtils.Web/Pages/Tools/Index.razor @@ -24,7 +24,7 @@ <a href="/Tools/Moderation/UserTrace">Trace user across rooms</a><br/> <a href="/tools/Moderation/MassCMEBan">Mass write policies to Community Moderation Effort</a><br/> <a href="/tools/Moderation/RoomIntersections">Find rooms with common users</a><br/> -<a href="/tools/Moderation/DraupnirProtectedRoomsEditor">Edit Draupnir protected rooms set</a><br/> +<a href="/tools/Moderation/Draupnir/ProtectedRoomsEditor">Draupnir: edit protected rooms set</a><br/> <h4 class="tool-category">Debugging tools</h4> diff --git a/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor index de0bfe7..f2af9b5 100644 --- a/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor +++ b/MatrixUtils.Web/Pages/Tools/Info/PolicyListActivity.razor @@ -5,6 +5,8 @@ @using LibMatrix.EventTypes.Common + +@* <ActivityGraph Data="TestData"/> *@ @if (RoomData.Count == 0) { <p>Loading...</p> @@ -15,10 +17,8 @@ else <h3>@room.Key</h3> @foreach (var year in room.Value.OrderBy(x => x.Key)) { - <h5>@year.Key</h5> - <ActivityGraph Data="@year.Value" GlobalMax="MaxValue" - RLabel="removed" GLabel="new" BLabel="updated policies"> - </ActivityGraph> + <span>@year.Key</span> + <ActivityGraph Data="@year.Value" GlobalMax="MaxValue" RLabel="removed" GLabel="new" BLabel="updated policies"/> } } @@ -42,15 +42,22 @@ else await base.OnInitializedAsync(); Homeserver = (await RMUStorage.GetCurrentSessionOrNavigate())!; if (Homeserver is null) return; - + // //random test data - for (DateOnly i = new DateOnly(2020, 1, 1); i < new DateOnly(2020, 12, 30); i = i.AddDays(Random.Shared.Next(5))) + for (DateOnly i = new DateOnly(2020, 1, 1); i < new DateOnly(2020, 12, 30); i = i.AddDays(2)) { + // TestData[i] = new() + // { + // R = (int)(Random.Shared.NextSingle() * 255), + // G = (int)(Random.Shared.NextSingle() * 255), + // B = (int)(Random.Shared.NextSingle() * 255) + // }; + // rgb based on number of week TestData[i] = new() { - R = (int)(Random.Shared.NextSingle() * 255), - G = (int)(Random.Shared.NextSingle() * 255), - B = (int)(Random.Shared.NextSingle() * 255) + R = i.DayOfYear % 255, + G = i.DayOfYear + 96 % 255, + B = i.DayOfYear + 192 % 255 }; } @@ -109,7 +116,7 @@ else } //use timeline - var timeline = room.GetManyMessagesAsync(limit: int.MaxValue, chunkSize: 5000); + var timeline = room.GetManyMessagesAsync(limit: int.MaxValue, chunkSize: 2000); await foreach (var response in timeline) { Console.WriteLine($"Got {response.State.Count} state, {response.Chunk.Count} timeline"); diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectedRoomsEditor.razor b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectedRoomsEditor.razor new file mode 100644 index 0000000..8745459 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectedRoomsEditor.razor @@ -0,0 +1,143 @@ +@page "/Moderation/DraupnirProtectedRoomsEditor" +@page "/Tools/Moderation/DraupnirProtectedRoomsEditor" +@page "/Tools/Moderation/Draupnir/ProtectedRoomsEditor" +@using System.Text.Json.Serialization +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.RoomTypes +<h3>Edit Draupnir protected rooms</h3> +<hr/> +<p><b>Note:</b> You will need to restart Draupnir after applying changes!</p> +<p>Minor note: This <i>should</i> also work with Mjolnir, but this hasn't been tested, and as such functionality cannot be guaranteed.</p> + +@if (data is not null) { + <div class="row"> + <div class="col-12"> + <details> + <summary>Currently protected room IDs</summary> + <ul> + @foreach (var room in data.Rooms) { + <li>@room</li> + } + </ul> + </details> + <hr/> + <h4>Tickyboxes</h4> + <table class="table"> + <thead> + <tr> + <th></th> @* Checkbox column *@ + <th>Kick?</th> @* PL > kick *@ + <th>Ban?</th> @* PL > ban *@ + <th>ACL?</th> @* PL > m.room.server_acls event *@ + <th>Room ID</th> + <th>Room name</th> + </tr> + </thead> + <tbody> + @foreach (var room in Rooms.OrderBy(x => x.RoomName)) { + <tr> + <td> + <input type="checkbox" @bind="room.IsProtected"/> + </td> + <td>@(room.PowerLevels.Kick <= room.PowerLevels.GetUserPowerLevel(hs.UserId) ? "X" : "")</td> + <td>@(room.PowerLevels.Ban <= room.PowerLevels.GetUserPowerLevel(hs.UserId) ? "X" : "")</td> + <td>@(room.PowerLevels.UserHasStatePermission(hs.UserId, RoomServerACLEventContent.EventId) ? "X" : "")</td> + <td>@room.Room.RoomId</td> + <td>@room.RoomName</td> + </tr> + } + </tbody> + </table> + </div> + </div> +} +<br/> +<LinkButton OnClick="@Apply">Apply</LinkButton> + + +@code { + private DraupnirProtectedRoomsData data { get; set; } = new(); + private List<EditorRoomInfo> Rooms { get; set; } = new(); + private AuthenticatedHomeserverGeneric hs { get; set; } + + protected override async Task OnInitializedAsync() { + hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + data = await hs.GetAccountDataAsync<DraupnirProtectedRoomsData>("org.matrix.mjolnir.protected_rooms"); + StateHasChanged(); + var tasks = (await hs.GetJoinedRooms()).Select(async room => { + var plTask = room.GetPowerLevelsAsync(); + var roomNameTask = room.GetNameOrFallbackAsync(); + var EditorRoomInfo = new EditorRoomInfo { + Room = room, + IsProtected = data.Rooms.Contains(room.RoomId), + RoomName = await roomNameTask, + PowerLevels = await plTask + }; + + Rooms.Add(EditorRoomInfo); + StateHasChanged(); + return Task.CompletedTask; + }).ToList(); + await Task.WhenAll(tasks); + await Task.Delay(500); + + foreach (var protectedRoomId in data.Rooms) { + if (Rooms.Any(x => x.Room.RoomId == protectedRoomId)) continue; + var room = hs.GetRoom(protectedRoomId); + var editorRoomInfo = new EditorRoomInfo { + Room = room, + IsProtected = true + }; + + try { + var pl = await room.GetPowerLevelsAsync(); + editorRoomInfo.PowerLevels = pl; + } + catch (MatrixException e) { + Console.WriteLine($"Failed to get power levels for {room.RoomId}: {e}"); + } + + try { + editorRoomInfo.RoomName = await room.GetNameOrFallbackAsync(); + } + catch (MatrixException e) { + Console.WriteLine($"Failed to get name for {room.RoomId}: {e}"); + } + + try { + var membership = await room.GetStateEventOrNullAsync(hs.UserId); + if (membership is not null) { + editorRoomInfo.RoomName = $"(!! {membership.ContentAs<RoomMemberEventContent>()?.Membership ?? "null"} !!) {editorRoomInfo.RoomName}"; + } + } + catch (MatrixException e) { + Console.WriteLine($"Failed to get membership for {room.RoomId}: {e}"); + } + + Rooms.Add(editorRoomInfo); + } + + StateHasChanged(); + } + + private class DraupnirProtectedRoomsData { + [JsonPropertyName("rooms")] + public List<string> Rooms { get; set; } = new(); + } + + private class EditorRoomInfo { + public GenericRoom Room { get; set; } + public bool IsProtected { get; set; } + public string RoomName { get; set; } + public RoomPowerLevelEventContent PowerLevels { get; set; } + } + + private async Task Apply() { + Console.WriteLine(string.Join('\n', Rooms.Where(x => x.IsProtected).Select(x => x.Room.RoomId))); + data.Rooms = Rooms.Where(x => x.IsProtected).Select(x => x.Room.RoomId).ToList(); + await hs.SetAccountDataAsync("org.matrix.mjolnir.protected_rooms", data); + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/DraupnirProtectedRoomsEditor.razor b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectionsEditor.razor index 805bd40..b722596 100644 --- a/MatrixUtils.Web/Pages/Tools/Moderation/DraupnirProtectedRoomsEditor.razor +++ b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirProtectionsEditor.razor @@ -1,6 +1,6 @@ -@page "/Moderation/DraupnirProtectedRoomsEditor" -@page "/Tools/Moderation/DraupnirProtectedRoomsEditor" +@page "/Tools/Moderation/Draupnir/ProtectionsEditor" @using System.Text.Json.Serialization +@using LibMatrix @using LibMatrix.EventTypes.Spec.State @using LibMatrix.RoomTypes <h3>Edit Draupnir protected rooms</h3> @@ -78,6 +78,43 @@ }).ToList(); await Task.WhenAll(tasks); await Task.Delay(500); + + foreach (var protectedRoomId in data.Rooms) { + if (Rooms.Any(x => x.Room.RoomId == protectedRoomId)) continue; + var room = hs.GetRoom(protectedRoomId); + var editorRoomInfo = new EditorRoomInfo { + Room = room, + IsProtected = true + }; + + try { + var pl = await room.GetPowerLevelsAsync(); + editorRoomInfo.PowerLevels = pl; + } + catch (MatrixException e) { + Console.WriteLine($"Failed to get power levels for {room.RoomId}: {e}"); + } + + try { + editorRoomInfo.RoomName = await room.GetNameOrFallbackAsync(); + } + catch (MatrixException e) { + Console.WriteLine($"Failed to get name for {room.RoomId}: {e}"); + } + + try { + var membership = await room.GetStateEventOrNullAsync(hs.UserId); + if (membership is not null) { + editorRoomInfo.RoomName = $"(!! {membership.ContentAs<RoomMemberEventContent>()?.Membership ?? "null"} !!) {editorRoomInfo.RoomName}"; + } + } + catch (MatrixException e) { + Console.WriteLine($"Failed to get membership for {room.RoomId}: {e}"); + } + + Rooms.Add(editorRoomInfo); + } + StateHasChanged(); } diff --git a/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirWatchedListsEditor.razor b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirWatchedListsEditor.razor new file mode 100644 index 0000000..b2f4026 --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/Moderation/Draupnir/DraupnirWatchedListsEditor.razor @@ -0,0 +1,139 @@ +@page "/Tools/Moderation/Draupnir/WatchedListsEditor" +@using System.Text.Json.Serialization +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.RoomTypes +<h3>Edit Draupnir protected rooms</h3> +<hr/> +<p><b>Note:</b> You will need to restart Draupnir after applying changes!</p> +<p>Minor note: This <i>should</i> also work with Mjolnir, but this hasn't been tested, and as such functionality cannot be guaranteed.</p> + +@if (data is not null) { + <div class="row"> + <div class="col-12"> + <h4>Current rooms</h4> + <ul> + @foreach (var room in data.Rooms) { + <li>@room</li> + } + </ul> + <hr/> + <h4>Tickyboxes</h4> + <table class="table"> + <thead> + <tr> + <th></th> @* Checkbox column *@ + <th>Kick?</th> @* PL > kick *@ + <th>Ban?</th> @* PL > ban *@ + <th>ACL?</th> @* PL > m.room.server_acls event *@ + <th>Room ID</th> + <th>Room name</th> + </tr> + </thead> + <tbody> + @foreach (var room in Rooms.OrderBy(x => x.RoomName)) { + <tr> + <td> + <input type="checkbox" @bind="room.IsProtected"/> + </td> + <td>@(room.PowerLevels.Kick <= room.PowerLevels.GetUserPowerLevel(hs.UserId) ? "X" : "")</td> + <td>@(room.PowerLevels.Ban <= room.PowerLevels.GetUserPowerLevel(hs.UserId) ? "X" : "")</td> + <td>@(room.PowerLevels.UserHasStatePermission(hs.UserId, RoomServerACLEventContent.EventId) ? "X" : "")</td> + <td>@room.Room.RoomId</td> + <td>@room.RoomName</td> + </tr> + } + </tbody> + </table> + </div> + </div> +} +<br/> +<LinkButton OnClick="@Apply">Apply</LinkButton> + + +@code { + private DraupnirProtectedRoomsData data { get; set; } = new(); + private List<EditorRoomInfo> Rooms { get; set; } = new(); + private AuthenticatedHomeserverGeneric hs { get; set; } + + protected override async Task OnInitializedAsync() { + hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + data = await hs.GetAccountDataAsync<DraupnirProtectedRoomsData>("org.matrix.mjolnir.protected_rooms"); + StateHasChanged(); + var tasks = (await hs.GetJoinedRooms()).Select(async room => { + var plTask = room.GetPowerLevelsAsync(); + var roomNameTask = room.GetNameOrFallbackAsync(); + var EditorRoomInfo = new EditorRoomInfo { + Room = room, + IsProtected = data.Rooms.Contains(room.RoomId), + RoomName = await roomNameTask, + PowerLevels = await plTask + }; + + Rooms.Add(EditorRoomInfo); + StateHasChanged(); + return Task.CompletedTask; + }).ToList(); + await Task.WhenAll(tasks); + await Task.Delay(500); + + foreach (var protectedRoomId in data.Rooms) { + if (Rooms.Any(x => x.Room.RoomId == protectedRoomId)) continue; + var room = hs.GetRoom(protectedRoomId); + var editorRoomInfo = new EditorRoomInfo { + Room = room, + IsProtected = true + }; + + try { + var pl = await room.GetPowerLevelsAsync(); + editorRoomInfo.PowerLevels = pl; + } + catch (MatrixException e) { + Console.WriteLine($"Failed to get power levels for {room.RoomId}: {e}"); + } + + try { + editorRoomInfo.RoomName = await room.GetNameOrFallbackAsync(); + } + catch (MatrixException e) { + Console.WriteLine($"Failed to get name for {room.RoomId}: {e}"); + } + + try { + var membership = await room.GetStateEventOrNullAsync(hs.UserId); + if (membership is not null) { + editorRoomInfo.RoomName = $"(!! {membership.ContentAs<RoomMemberEventContent>()?.Membership ?? "null"} !!) {editorRoomInfo.RoomName}"; + } + } + catch (MatrixException e) { + Console.WriteLine($"Failed to get membership for {room.RoomId}: {e}"); + } + + Rooms.Add(editorRoomInfo); + } + + StateHasChanged(); + } + + private class DraupnirProtectedRoomsData { + [JsonPropertyName("rooms")] + public List<string> Rooms { get; set; } = new(); + } + + private class EditorRoomInfo { + public GenericRoom Room { get; set; } + public bool IsProtected { get; set; } + public string RoomName { get; set; } + public RoomPowerLevelEventContent PowerLevels { get; set; } + } + + private async Task Apply() { + Console.WriteLine(string.Join('\n', Rooms.Where(x => x.IsProtected).Select(x => x.Room.RoomId))); + data.Rooms = Rooms.Where(x => x.IsProtected).Select(x => x.Room.RoomId).ToList(); + await hs.SetAccountDataAsync("org.matrix.mjolnir.protected_rooms", data); + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/User/ViewAccountData.razor b/MatrixUtils.Web/Pages/Tools/User/ViewAccountData.razor index d8b02bb..153518e 100644 --- a/MatrixUtils.Web/Pages/Tools/User/ViewAccountData.razor +++ b/MatrixUtils.Web/Pages/Tools/User/ViewAccountData.razor @@ -1,4 +1,4 @@ -@page "/Tools/ViewAccountData" +@page "/Tools/User/ViewAccountData" @using ArcaneLibs.Extensions @using LibMatrix <h3>View account data</h3> |