about summary refs log tree commit diff
path: root/MatrixRoomUtils.Web/Pages/PolicyList
diff options
context:
space:
mode:
Diffstat (limited to 'MatrixRoomUtils.Web/Pages/PolicyList')
-rw-r--r--MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor228
-rw-r--r--MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor158
2 files changed, 386 insertions, 0 deletions
diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor
new file mode 100644

index 0000000..5dfb2d6 --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListEditorPage.razor
@@ -0,0 +1,228 @@ +@page "/PolicyListEditor/{RoomId}" +@using System.Text.Json +@using MatrixRoomUtils.Core.Extensions +@using MatrixRoomUtils.Core.StateEventTypes +@inject ILocalStorageService LocalStorage +@inject NavigationManager NavigationManager +<h3>Policy list editor - Editing @RoomId</h3> +<hr/> + +<p> + This policy list contains @PolicyEvents.Count(x => x.type == "m.policy.rule.server") server bans, + @PolicyEvents.Count(x => x.type == "m.policy.rule.room") room bans and + @PolicyEvents.Count(x => x.type == "m.policy.rule.user") user bans. +</p> + + +@if (!PolicyEvents.Any(x => x.type == "m.policy.rule.server")) +{ + <p>No server policies</p> +} +else +{ + <h3>Server policies</h3> + <hr/> + <table class="table table-striped table-hover" style="width: fit-content;"> + <thead> + <tr> + <th scope="col" style="max-width: 50vw;">Server</th> + <th scope="col">Reason</th> + <th scope="col">Expires</th> + <th scope="col">Actions</th> + </tr> + </thead> + <tbody> + @foreach (var policyEvent in PolicyEvents.Where(x => x.type == "m.policy.rule.server" && x.content.Entity != null)) + { + <tr> + <td>Entity: @policyEvent.content.Entity<br/>State: @policyEvent.state_key</td> + <td>@policyEvent.content.Reason</td> + <td> + @policyEvent.content.ExpiryDateTime + </td> + <td> + <button class="btn btn-danger" @* @onclick="async () => await RemovePolicyAsync(policyEvent)" *@>Remove</button> + </td> + </tr> + } + </tbody> + </table> + <details> + <summary>Invalid events</summary> + <table class="table table-striped table-hover" style="width: fit-content;"> + <thead> + <tr> + <th scope="col" style="max-width: 50vw;">State key</th> + <th scope="col">Serialised contents</th> + </tr> + </thead> + <tbody> + @foreach (var policyEvent in PolicyEvents.Where(x => x.type == "m.policy.rule.server" && x.content.Entity == null)) + { + <tr> + <td>@policyEvent.state_key</td> + <td>@policyEvent.content.ToJson(indent: false, ignoreNull: true)</td> + </tr> + } + </tbody> + </table> + </details> +} +@if (!PolicyEvents.Any(x => x.type == "m.policy.rule.room")) +{ + <p>No room policies</p> +} +else +{ + <h3>Room policies</h3> + <hr/> + <table class="table table-striped table-hover" style="width: fit-content;"> + <thead> + <tr> + <th scope="col" style="max-width: 50vw;">Room</th> + <th scope="col">Reason</th> + <th scope="col">Expires</th> + <th scope="col">Actions</th> + </tr> + </thead> + <tbody> + @foreach (var policyEvent in PolicyEvents.Where(x => x.type == "m.policy.rule.room" && x.content.Entity != null)) + { + <tr> + <td>Entity: @policyEvent.content.Entity<br/>State: @policyEvent.state_key</td> + <td>@policyEvent.content.Reason</td> + <td> + @policyEvent.content.ExpiryDateTime + </td> + <td> + <button class="btn btn-danger" @* @onclick="async () => await RemovePolicyAsync(policyEvent)" *@>Remove</button> + </td> + </tr> + } + </tbody> + </table> + <details> + <summary>Invalid events</summary> + <table class="table table-striped table-hover" style="width: fit-content;"> + <thead> + <tr> + <th scope="col" style="max-width: 50vw;">State key</th> + <th scope="col">Serialised contents</th> + </tr> + </thead> + <tbody> + @foreach (var policyEvent in PolicyEvents.Where(x => x.type == "m.policy.rule.room" && x.content.Entity == null)) + { + <tr> + <td>@policyEvent.state_key</td> + <td>@policyEvent.content.ToJson(indent: false, ignoreNull: true)</td> + </tr> + } + </tbody> + </table> + </details> +} +@if (!PolicyEvents.Any(x => x.type == "m.policy.rule.user")) +{ + <p>No user policies</p> +} +else +{ + <h3>User policies</h3> + <hr/> + <table class="table table-striped table-hover" style="width: fit-content;"> + <thead> + <tr> + <th scope="col" style="max-width: 0.2vw; word-wrap: anywhere;">User</th> + <th scope="col">Reason</th> + <th scope="col">Expires</th> + <th scope="col">Actions</th> + </tr> + </thead> + <tbody> + @foreach (var policyEvent in PolicyEvents.Where(x => x.type == "m.policy.rule.user" && x.content.Entity != null)) + { + <tr> + <td style="word-wrap: anywhere;">Entity: @string.Join("", policyEvent.content.Entity.Take(64))<br/>State: @string.Join("", policyEvent.state_key.Take(64))</td> + <td>@policyEvent.content.Reason</td> + <td> + @policyEvent.content.ExpiryDateTime + </td> + <td> + <button class="btn btn-danger" @* @onclick="async () => await RemovePolicyAsync(policyEvent)" *@>Remove</button> + </td> + </tr> + } + </tbody> + </table> + <details> + <summary>Invalid events</summary> + <table class="table table-striped table-hover" style="width: fit-content;"> + <thead> + <tr> + <th scope="col">State key</th> + <th scope="col">Serialised contents</th> + </tr> + </thead> + <tbody> + @foreach (var policyEvent in PolicyEvents.Where(x => x.type == "m.policy.rule.user" && x.content.Entity == null)) + { + <tr> + <td>@policyEvent.state_key</td> + <td>@policyEvent.content.ToJson(indent: false, ignoreNull: true)</td> + </tr> + } + </tbody> + </table> + </details> +} + +<LogView></LogView> + +@code { + //get room list + // - sync withroom list filter + // type = support.feline.msc3784 + //support.feline.policy.lists.msc.v1 + + [Parameter] + public string? RoomId { get; set; } + + public List<StateEvent<PolicyRuleStateEventData>> PolicyEvents { get; set; } = new(); + + protected override async Task OnInitializedAsync() + { + if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + await base.OnInitializedAsync(); + // if(RuntimeCache.AccessToken == null || RuntimeCache.CurrentHomeserver == null) + if (RuntimeCache.CurrentHomeServer == null) + { + NavigationManager.NavigateTo("/Login"); + return; + } + RoomId = RoomId.Replace('~', '.'); + await LoadStatesAsync(); + Console.WriteLine("Policy list editor initialized!"); + } + + private async Task LoadStatesAsync() + { + // using var client = new HttpClient(); + // client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", LocalStorageWrapper.AccessToken); + // var response = await client.GetAsync($"{LocalStorageWrapper.CurrentHomeserver}/_matrix/client/r0/rooms/{RoomId}/state"); + // var content = await response.Content.ReadAsStringAsync(); + // Console.WriteLine(JsonSerializer.Deserialize<object>(content).ToJson()); + // var stateEvents = JsonSerializer.Deserialize<List<StateEvent>>(content); + var room = await RuntimeCache.CurrentHomeServer.GetRoom(RoomId); + var stateEventsQuery = await room.GetStateAsync(""); + if (stateEventsQuery == null) + { + Console.WriteLine("state events query is null!!!"); + } + var stateEvents = stateEventsQuery.Value.Deserialize<List<StateEvent>>(); + PolicyEvents = stateEvents.Where(x => x.type.StartsWith("m.policy.rule")) + .Select(x => JsonSerializer.Deserialize<StateEvent<PolicyRuleStateEventData>>(JsonSerializer.Serialize(x))).ToList(); + StateHasChanged(); + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor new file mode 100644
index 0000000..5656af9 --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/PolicyList/PolicyListRoomList.razor
@@ -0,0 +1,158 @@ +@page "/PolicyListEditor" +@using System.Text.Json +@using MatrixRoomUtils.Core.Extensions +@inject ILocalStorageService LocalStorage +@inject NavigationManager NavigationManager +<h3>Policy list editor - Room list</h3> +<hr/> + +@if (PolicyRoomList.Count == 0) +{ + <p>No policy rooms found.</p> + <p>Loading progress: @checkedRoomCount/@totalRoomCount</p> +} +else +{ + @if (checkedRoomCount != totalRoomCount) + { + <p>Loading progress: @checkedRoomCount/@totalRoomCount</p> + } + foreach (var s in PolicyRoomList) + { + <a href="@(NavigationManager.Uri + "/" + s.RoomId.Replace('.', '~'))">[@s.Shortcode] @s.Name (@s.RoomId)</a> + <br/> + } +} + +<div style="margin-bottom: 4em;"></div> +<LogView></LogView> + +@code { + //get room list + // - sync withroom list filter + // type = support.feline.msc3784 + //support.feline.policy.lists.msc.v1 + + public List<PolicyRoomInfo> PolicyRoomList { get; set; } = new(); + + private int checkedRoomCount { get; set; } = 0; + private int totalRoomCount { get; set; } = 0; + + protected override async Task OnInitializedAsync() + { + if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage); + await base.OnInitializedAsync(); + if (RuntimeCache.CurrentHomeServer == null) + { + NavigationManager.NavigateTo("/Login"); + return; + } + await EnumeratePolicyRooms(); + Console.WriteLine("Policy list editor initialized!"); + } + + private async Task EnumeratePolicyRooms() + { + var xxxrooms = await RuntimeCache.CurrentHomeServer.GetJoinedRooms(); + totalRoomCount = xxxrooms.Count; + StateHasChanged(); + + var xxxsemaphore = new SemaphoreSlim(256); + var xxxtasks = new List<Task<PolicyRoomInfo?>>(); + foreach (var room in xxxrooms) + { + xxxtasks.Add(GetPolicyRoomInfo(room.RoomId, xxxsemaphore)); + } + var xxxresults = await Task.WhenAll(xxxtasks); + PolicyRoomList.AddRange(xxxresults.Where(x => x != null).Select(x => x.Value)); + + Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}"); + return; + /* + using HttpClient wc = new(); + wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", LocalStorageWrapper.AccessToken); + + + + //get room list + //temporary hack until rooms get enumerated... + string[] rooms = { "!fTjMjIzNKEsFlUIiru:neko.dev" }; + var _rooms = await wc.GetAsync($"{LocalStorageWrapper.CurrentHomeserver}/_matrix/client/v3/joined_rooms"); + Console.WriteLine($"Got {_rooms.StatusCode}..."); + if (!_rooms.IsSuccessStatusCode) + { + Console.WriteLine($"Failed to get rooms: {await _rooms.Content.ReadAsStringAsync()}"); + return; + } + var _rooms_o = await _rooms.Content.ReadFromJsonAsync<JsonElement>(); + if (_rooms_o.TryGetProperty("joined_rooms", out JsonElement _rooms_j)) + { + rooms = _rooms_j.EnumerateArray().Select(x => x.GetString()).ToArray(); + } + + totalRoomCount = rooms.Length; + StateHasChanged(); + + var semaphore = new SemaphoreSlim(256); + var tasks = new List<Task<PolicyRoomInfo?>>(); + foreach (string room in rooms) + { + tasks.Add(GetPolicyRoomInfo(room, semaphore)); + } + var results = await Task.WhenAll(tasks); + PolicyRoomList.AddRange(results.Where(x => x != null).Select(x => x.Value)); + + + //print to console + Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}"); + */ + } + + private async Task<PolicyRoomInfo?> GetPolicyRoomInfo(string room, SemaphoreSlim semaphore) + { + try + { + //TODO: refactor!!!!! + await semaphore.WaitAsync(); + PolicyRoomInfo roomInfo = new() + { + RoomId = room + }; + + + // --- // + var r = await RuntimeCache.CurrentHomeServer.GetRoom(room); + var shortcodeState = await r.GetStateAsync("org.matrix.mjolnir.shortcode"); + if(!shortcodeState.HasValue) return null; + roomInfo.Shortcode = shortcodeState.Value.TryGetProperty("shortcode", out JsonElement shortcode) ? shortcode.GetString() : null; + + if (roomInfo.Shortcode != null) + { + roomInfo.Name = await r.GetNameAsync(); + return roomInfo; + } + + return null; + } + finally + + { + checkedRoomCount++; + StateHasChanged(); + semaphore.Release(); + } + } + + public struct PolicyRoomInfo + + { + public + string RoomId { get; set; } + + public + string? Shortcode { get; set; } + + public + string? Name { get; set; } + } + } \ No newline at end of file