about summary refs log tree commit diff
diff options
context:
space:
mode:
m---------ArcaneLibs0
-rw-r--r--LibMatrix.EventTypes/LibMatrix.EventTypes.csproj2
-rw-r--r--LibMatrix.EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs18
-rw-r--r--LibMatrix.Federation/LibMatrix.Federation.csproj2
-rw-r--r--LibMatrix/Helpers/RoomBuilder.cs2
-rw-r--r--LibMatrix/Helpers/RoomUpgradeBuilder.cs180
-rw-r--r--LibMatrix/LibMatrix.csproj4
-rw-r--r--LibMatrix/RoomTypes/GenericRoom.cs5
-rw-r--r--Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj2
-rw-r--r--Utilities/LibMatrix.DevTestBot/LibMatrix.DevTestBot.csproj4
-rw-r--r--Utilities/LibMatrix.E2eeTestKit/LibMatrix.E2eeTestKit.csproj4
-rw-r--r--Utilities/LibMatrix.FederationTest/LibMatrix.FederationTest.csproj2
-rw-r--r--Utilities/LibMatrix.TestDataGenerator/LibMatrix.TestDataGenerator.csproj2
-rw-r--r--Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj6
14 files changed, 177 insertions, 56 deletions
diff --git a/ArcaneLibs b/ArcaneLibs
-Subproject d3f0ba9cb7ec36ab2f9574fd563c467b61512b9
+Subproject 5099e9feeade98f562723e102bd58887aa2c125
diff --git a/LibMatrix.EventTypes/LibMatrix.EventTypes.csproj b/LibMatrix.EventTypes/LibMatrix.EventTypes.csproj

index 682b91b..a2b22b5 100644 --- a/LibMatrix.EventTypes/LibMatrix.EventTypes.csproj +++ b/LibMatrix.EventTypes/LibMatrix.EventTypes.csproj
@@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="ArcaneLibs" Version="1.0.0-preview.20250630-114950" Condition="'$(Configuration)' == 'Release'" /> + <PackageReference Include="ArcaneLibs" Version="1.0.0-preview.20250806-011111" Condition="'$(Configuration)' == 'Release'" /> <ProjectReference Include="..\ArcaneLibs\ArcaneLibs\ArcaneLibs.csproj" Condition="'$(Configuration)' == 'Debug'"/> </ItemGroup> diff --git a/LibMatrix.EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs b/LibMatrix.EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs
index d75b19f..24b8f90 100644 --- a/LibMatrix.EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs +++ b/LibMatrix.EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs
@@ -124,6 +124,19 @@ public abstract class PolicyRuleEventContent : EventContent { return Recommendation; } + + public string? GetSpecRecommendation() { + if (Recommendation is "m.ban" or "org.matrix.mjolnir.ban") + return PolicyRecommendationTypes.Ban; + + if (Recommendation is "m.mute" or "support.feline.policy.recommendation_mute") + return PolicyRecommendationTypes.Mute; + + if (Recommendation is "m.takedown" or "org.matrix.msc4204.takedown") + return PolicyRecommendationTypes.Takedown; + + return Recommendation; + } } public static class PolicyRecommendationTypes { @@ -137,7 +150,10 @@ public static class PolicyRecommendationTypes { /// </summary> public static string Mute = "support.feline.policy.recommendation_mute"; //stable prefix: m.mute, msc pending - public static string Takedown = "m.takedown"; //unstable prefix: org.matrix.msc4204.takedown + /// <summary> + /// Take down the user with all means available + /// </summary> + public static string Takedown = "org.matrix.msc4204.takedown"; //stable prefix: m.takedown, msc pending } public class PolicyHash { diff --git a/LibMatrix.Federation/LibMatrix.Federation.csproj b/LibMatrix.Federation/LibMatrix.Federation.csproj
index 78086bb..af09d85 100644 --- a/LibMatrix.Federation/LibMatrix.Federation.csproj +++ b/LibMatrix.Federation/LibMatrix.Federation.csproj
@@ -12,7 +12,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" /> + <PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" /> <PackageReference Include="Microsoft.Extensions.Primitives" Version="10.0.0-preview.5.25277.114" /> </ItemGroup> diff --git a/LibMatrix/Helpers/RoomBuilder.cs b/LibMatrix/Helpers/RoomBuilder.cs
index 8843a21..2d8d730 100644 --- a/LibMatrix/Helpers/RoomBuilder.cs +++ b/LibMatrix/Helpers/RoomBuilder.cs
@@ -86,7 +86,7 @@ public class RoomBuilder { public Dictionary<string, object> AdditionalCreationContent { get; set; } = new(); public List<string> AdditionalCreators { get; set; } = new(); - public async Task<GenericRoom> Create(AuthenticatedHomeserverGeneric homeserver) { + public virtual async Task<GenericRoom> Create(AuthenticatedHomeserverGeneric homeserver) { var crq = new CreateRoomRequest() { PowerLevelContentOverride = new() { EventsDefault = 1000000, diff --git a/LibMatrix/Helpers/RoomUpgradeBuilder.cs b/LibMatrix/Helpers/RoomUpgradeBuilder.cs
index cbc7876..64ec364 100644 --- a/LibMatrix/Helpers/RoomUpgradeBuilder.cs +++ b/LibMatrix/Helpers/RoomUpgradeBuilder.cs
@@ -1,71 +1,155 @@ +using System.Diagnostics; using System.Text.Json.Serialization; +using ArcaneLibs; using LibMatrix.EventTypes.Spec; +using LibMatrix.EventTypes.Spec.State.Policy; using LibMatrix.EventTypes.Spec.State.RoomInfo; +using LibMatrix.Homeservers; using LibMatrix.RoomTypes; namespace LibMatrix.Helpers; -public class RoomUpgradeBuilder(GenericRoom oldRoom) : RoomBuilder { - public GenericRoom OldRoom { get; } = oldRoom; +public class RoomUpgradeBuilder : RoomBuilder { public RoomUpgradeOptions UpgradeOptions { get; set; } = new(); + public string OldRoomId { get; set; } = string.Empty; + public bool CanUpgrade { get; private set; } + public Dictionary<string, object> AdditionalTombstoneContent { get; set; } = new(); + + public async Task ImportAsync(GenericRoom OldRoom) { + var sw = Stopwatch.StartNew(); + var total = 0; + + var basePolicyTypes = ClassCollector<PolicyRuleEventContent>.ResolveFromAllAccessibleAssemblies().ToList(); + Console.WriteLine($"Found {basePolicyTypes.Count} policy types in {sw.ElapsedMilliseconds}ms"); + CanUpgrade = ( + (await OldRoom.GetPowerLevelsAsync())?.UserHasStatePermission(OldRoom.Homeserver.UserId, RoomTombstoneEventContent.EventId) + ?? (await OldRoom.GetRoomCreatorsAsync()).Contains(OldRoom.Homeserver.UserId) + ) + || (OldRoom.IsV12PlusRoomId && (await OldRoom.GetRoomCreatorsAsync()).Contains(OldRoom.Homeserver.UserId)); + + await foreach (var srcEvt in OldRoom.GetFullStateAsync()) { + total++; + if (srcEvt is null) continue; + var evt = srcEvt; + + if (UpgradeOptions.UpgradeUnstableValues) { + evt = UpgradeUnstableValues(evt); + } - public async Task ImportAsync() { - await foreach (var evt in OldRoom.GetFullStateAsync()) { - if (evt is null) continue; if (evt.StateKey == "") { - if (evt.TypedContent is RoomCreateEventContent createEvt) + if (evt.Type == RoomCreateEventContent.EventId) foreach (var (key, value) in evt.RawContent) { if (key == "version") continue; if (key == "type") Type = value!.GetValue<string>(); else AdditionalCreationContent[key] = value; } - else if (evt.TypedContent is RoomNameEventContent name) - Name = name; - else if (evt.TypedContent is RoomTopicEventContent topic) - Topic = topic; - else if (evt.TypedContent is RoomAvatarEventContent avatar) - Avatar = avatar; - else if (evt.TypedContent is RoomCanonicalAliasEventContent alias) { - CanonicalAlias = alias; - AliasLocalPart = alias.Alias?.Split(':',2).FirstOrDefault()?[1..] ?? string.Empty; + else if (evt.Type == RoomNameEventContent.EventId) + Name = evt.ContentAs<RoomNameEventContent>()!; + else if (evt.Type == RoomTopicEventContent.EventId) + Topic = evt.ContentAs<RoomTopicEventContent>()!; + else if (evt.Type == RoomAvatarEventContent.EventId) + Avatar = evt.ContentAs<RoomAvatarEventContent>()!; + else if (evt.Type == RoomCanonicalAliasEventContent.EventId) { + CanonicalAlias = evt.ContentAs<RoomCanonicalAliasEventContent>()!; + AliasLocalPart = CanonicalAlias.Alias?.Split(':', 2).FirstOrDefault()?[1..] ?? string.Empty; } - else if (evt.TypedContent is RoomJoinRulesEventContent joinRules) - JoinRules = joinRules; - else if (evt.TypedContent is RoomHistoryVisibilityEventContent historyVisibility) - HistoryVisibility = historyVisibility; - else if (evt.TypedContent is RoomGuestAccessEventContent guestAccess) - GuestAccess = guestAccess; - else if (evt.TypedContent is RoomServerAclEventContent serverAcls) - ServerAcls = serverAcls; - else if (evt.TypedContent is RoomPowerLevelEventContent powerLevels) { - if (UpgradeOptions.InvitePowerlevelUsers && powerLevels.Users != null) - foreach (var (userId, level) in powerLevels.Users) - if (level > powerLevels.UsersDefault) + else if (evt.Type == RoomJoinRulesEventContent.EventId) + JoinRules = evt.ContentAs<RoomJoinRulesEventContent>()!; + else if (evt.Type == RoomHistoryVisibilityEventContent.EventId) + HistoryVisibility = evt.ContentAs<RoomHistoryVisibilityEventContent>()!; + else if (evt.Type == RoomGuestAccessEventContent.EventId) + GuestAccess = evt.ContentAs<RoomGuestAccessEventContent>()!; + else if (evt.Type == RoomServerAclEventContent.EventId) + ServerAcls = evt.ContentAs<RoomServerAclEventContent>()!; + else if (evt.Type == RoomPowerLevelEventContent.EventId) { + PowerLevels = evt.ContentAs<RoomPowerLevelEventContent>()!; + if (UpgradeOptions.InvitePowerlevelUsers && PowerLevels.Users != null) + foreach (var (userId, level) in PowerLevels.Users) + if (level > PowerLevels.UsersDefault) Invites.Add(userId, "Room upgrade (had a power level)"); - - PowerLevels = powerLevels; } - else if (evt.TypedContent is RoomEncryptionEventContent encryption) - Encryption = encryption; - else if (evt.TypedContent is RoomPinnedEventContent) ; // Discard as you can't cross reference pinned events - else InitialState.Add(evt); + else if (evt.Type == RoomEncryptionEventContent.EventId) + Encryption = evt.ContentAs<RoomEncryptionEventContent>(); + else if (evt.Type == RoomPinnedEventContent.EventId) ; // Discard as you can't cross reference pinned events + else + InitialState.Add(new() { + Type = evt.Type, + StateKey = evt.StateKey, + RawContent = evt.RawContent + }); } else if (evt.Type == RoomMemberEventContent.EventId) { - if (UpgradeOptions.InviteMembers && evt.TypedContent is RoomMemberEventContent { Membership: "join" or "invite" }) - if (!Invites.ContainsKey(evt.StateKey)) - Invites.Add(evt.StateKey, "Room upgrade"); - else if (UpgradeOptions.MigrateBans && evt.TypedContent is RoomMemberEventContent { Membership: "ban" } bannedMember) - Bans.Add(evt.StateKey, bannedMember.Reason); + if (UpgradeOptions.InviteMembers && evt.TypedContent is RoomMemberEventContent { Membership: "join" or "invite" } invitedMember) { + Invites.TryAdd(evt.StateKey!, invitedMember.Reason ?? "Room upgrade"); + } + else if (UpgradeOptions.MigrateBans && evt.TypedContent is RoomMemberEventContent { Membership: "ban" } bannedMember) + Bans.TryAdd(evt.StateKey!, bannedMember.Reason); } - else InitialState.Add(evt); + else if (!UpgradeOptions.MigrateEmptyStateEvents && evt.RawContent.Count == 0) { } // skip empty state events + else if (basePolicyTypes.Contains(evt.MappedType)) ImportPolicyEventAsync(evt); + else + InitialState.Add(new() { + Type = evt.Type, + StateKey = evt.StateKey, + RawContent = evt.RawContent + }); + } + + Console.WriteLine($"Imported {total} state events from old room {OldRoom.RoomId} in {sw.ElapsedMilliseconds}ms"); + } + + private StateEventResponse UpgradeUnstableValues(StateEventResponse evt) { + + return evt; + } + + private void ImportPolicyEventAsync(StateEventResponse evt) { + var msc4321Options = UpgradeOptions.Msc4321PolicyListUpgradeOptions; + if (msc4321Options is { Enable: true, UpgradeType: Msc4321PolicyListUpgradeOptions.Msc4321PolicyListUpgradeType.Transition }) + return; // this upgrade type doesnt copy policies + if (msc4321Options.Enable) { + evt.RawContent["org.matrix.msc4321.original_sender"] = evt.Sender; + evt.RawContent["org.matrix.msc4321.original_timestamp"] = evt.OriginServerTs; + evt.RawContent["org.matrix.msc4321.original_event_id"] = evt.EventId; } + InitialState.Add(new() { + Type = evt.Type, + StateKey = evt.StateKey, + RawContent = evt.RawContent + }); + } + + public override async Task<GenericRoom> Create(AuthenticatedHomeserverGeneric homeserver) { + var room = await base.Create(homeserver); + if (CanUpgrade || UpgradeOptions.ForceUpgrade) { + if (UpgradeOptions.RoomUpgradeNotice != null) { + var noticeContent = await UpgradeOptions.RoomUpgradeNotice(room); + await room.SendMessageEventAsync(noticeContent); + } + + var tombstoneContent = new RoomTombstoneEventContent { + Body = "This room has been upgraded to a new version.", + ReplacementRoom = room.RoomId + }; + + tombstoneContent.AdditionalData ??= []; + foreach (var (key, value) in AdditionalTombstoneContent) + tombstoneContent.AdditionalData[key] = value; + + await room.SendStateEventAsync(RoomTombstoneEventContent.EventId, tombstoneContent); + } + return room; } public class RoomUpgradeOptions { public bool InviteMembers { get; set; } public bool InvitePowerlevelUsers { get; set; } public bool MigrateBans { get; set; } + public bool MigrateEmptyStateEvents { get; set; } + public bool UpgradeUnstableValues { get; set; } + public bool ForceUpgrade { get; set; } + public Msc4321PolicyListUpgradeOptions Msc4321PolicyListUpgradeOptions { get; set; } = new(); [JsonIgnore] public Func<GenericRoom, Task<RoomMessageEventContent>> RoomUpgradeNotice { get; set; } = async newRoom => new MessageBuilder() @@ -78,4 +162,22 @@ public class RoomUpgradeBuilder(GenericRoom oldRoom) : RoomBuilder { .WithMention(newRoom.RoomId, await newRoom.GetNameOrFallbackAsync(), vias: (await newRoom.GetHomeserversInRoom()).ToArray(), useLinkInPlainText: true) .Build(); } + + public class Msc4321PolicyListUpgradeOptions { + public bool Enable { get; set; } = true; + public Msc4321PolicyListUpgradeType UpgradeType { get; set; } = Msc4321PolicyListUpgradeType.Move; + + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum Msc4321PolicyListUpgradeType { + /// <summary> + /// Copy policies, unwatch old list + /// </summary> + Move, + + /// <summary> + /// Don't copy policies + /// </summary> + Transition + } + } } \ No newline at end of file diff --git a/LibMatrix/LibMatrix.csproj b/LibMatrix/LibMatrix.csproj
index 7fceb6f..c1049b5 100644 --- a/LibMatrix/LibMatrix.csproj +++ b/LibMatrix/LibMatrix.csproj
@@ -12,8 +12,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.7" /> - <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.7" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.8" /> + <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.8" /> <ProjectReference Include="..\LibMatrix.EventTypes\LibMatrix.EventTypes.csproj"/> </ItemGroup> diff --git a/LibMatrix/RoomTypes/GenericRoom.cs b/LibMatrix/RoomTypes/GenericRoom.cs
index 7fc942e..7d21d68 100644 --- a/LibMatrix/RoomTypes/GenericRoom.cs +++ b/LibMatrix/RoomTypes/GenericRoom.cs
@@ -656,7 +656,10 @@ public class GenericRoom { public SpaceRoom AsSpace() => new SpaceRoom(Homeserver, RoomId); public PolicyRoom AsPolicyRoom() => new PolicyRoom(Homeserver, RoomId); - private bool IsV12PlusRoomId => !RoomId.Contains(':'); + /// <summary> + /// Unsafe: does not actually check if the room is v12, it just checks the room ID format as an estimation. + /// </summary> + public bool IsV12PlusRoomId => !RoomId.Contains(':'); /// <summary> /// Gets the list of room creators for this room. diff --git a/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj b/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj
index 8e4299b..92da98f 100644 --- a/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj +++ b/Utilities/LibMatrix.DebugDataValidationApi/LibMatrix.DebugDataValidationApi.csproj
@@ -9,7 +9,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.7" /> + <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.8" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" /> </ItemGroup> diff --git a/Utilities/LibMatrix.DevTestBot/LibMatrix.DevTestBot.csproj b/Utilities/LibMatrix.DevTestBot/LibMatrix.DevTestBot.csproj
index 8b9aa6d..8a0107b 100644 --- a/Utilities/LibMatrix.DevTestBot/LibMatrix.DevTestBot.csproj +++ b/Utilities/LibMatrix.DevTestBot/LibMatrix.DevTestBot.csproj
@@ -18,14 +18,14 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="ArcaneLibs.StringNormalisation" Version="1.0.0-preview.20250630-114950" Condition="'$(Configuration)' == 'Release'" /> + <PackageReference Include="ArcaneLibs.StringNormalisation" Version="1.0.0-preview.20250806-011111" Condition="'$(Configuration)' == 'Release'" /> <ProjectReference Include="..\..\ArcaneLibs\ArcaneLibs.StringNormalisation\ArcaneLibs.StringNormalisation.csproj" Condition="'$(Configuration)' == 'Debug'"/> <ProjectReference Include="..\..\LibMatrix\LibMatrix.csproj"/> <ProjectReference Include="..\LibMatrix.Utilities.Bot\LibMatrix.Utilities.Bot.csproj" /> </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" /> + <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" /> </ItemGroup> <ItemGroup> diff --git a/Utilities/LibMatrix.E2eeTestKit/LibMatrix.E2eeTestKit.csproj b/Utilities/LibMatrix.E2eeTestKit/LibMatrix.E2eeTestKit.csproj
index eea3d2f..0da4c48 100644 --- a/Utilities/LibMatrix.E2eeTestKit/LibMatrix.E2eeTestKit.csproj +++ b/Utilities/LibMatrix.E2eeTestKit/LibMatrix.E2eeTestKit.csproj
@@ -8,8 +8,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.7" /> - <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.7" PrivateAssets="all" /> + <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.8" /> + <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.8" PrivateAssets="all" /> </ItemGroup> <ItemGroup> diff --git a/Utilities/LibMatrix.FederationTest/LibMatrix.FederationTest.csproj b/Utilities/LibMatrix.FederationTest/LibMatrix.FederationTest.csproj
index aa5647c..954a437 100644 --- a/Utilities/LibMatrix.FederationTest/LibMatrix.FederationTest.csproj +++ b/Utilities/LibMatrix.FederationTest/LibMatrix.FederationTest.csproj
@@ -8,7 +8,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.7" /> + <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.8" /> </ItemGroup> <ItemGroup> diff --git a/Utilities/LibMatrix.TestDataGenerator/LibMatrix.TestDataGenerator.csproj b/Utilities/LibMatrix.TestDataGenerator/LibMatrix.TestDataGenerator.csproj
index abb3169..93de8ab 100644 --- a/Utilities/LibMatrix.TestDataGenerator/LibMatrix.TestDataGenerator.csproj +++ b/Utilities/LibMatrix.TestDataGenerator/LibMatrix.TestDataGenerator.csproj
@@ -17,7 +17,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" /> + <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" /> </ItemGroup> <ItemGroup> <Content Include="appsettings*.json"> diff --git a/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj b/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj
index 1c7d4fc..615808d 100644 --- a/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj +++ b/Utilities/LibMatrix.Utilities.Bot/LibMatrix.Utilities.Bot.csproj
@@ -12,9 +12,9 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.7" /> - <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" /> - <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.7" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.8" /> + <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" /> + <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.8" /> </ItemGroup>