diff --git a/LibMatrix.EventTypes/Common/Msc2545EmoteRoomsAccountDataEventContent.cs b/LibMatrix.EventTypes/Common/Msc2545EmoteRoomsAccountDataEventContent.cs
new file mode 100644
index 0000000..4fd5c29
--- /dev/null
+++ b/LibMatrix.EventTypes/Common/Msc2545EmoteRoomsAccountDataEventContent.cs
@@ -0,0 +1,31 @@
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.EventTypes.Spec;
+
+[MatrixEvent(EventName = EventId)]
+public class Msc2545EmoteRoomsAccountDataEventContent : EventContent {
+ public const string EventId = "im.ponies.emote_rooms";
+
+ [JsonPropertyName("rooms")]
+ public Dictionary<string, Dictionary<string, EnabledEmotePackEntry>> Rooms { get; set; } = new();
+
+ // Dummy type to provide easy access to the by-spec empty content
+ public class EnabledEmotePackEntry {
+ [JsonExtensionData]
+ public Dictionary<string, object>? AdditionalData { get; set; } = [];
+
+ public T? GetAdditionalData<T>(string key) where T : class {
+ if (AdditionalData == null || !AdditionalData.TryGetValue(key, out var value))
+ return null;
+
+ if (value is T tValue)
+ return tValue;
+ if (value is JsonElement jsonElement)
+ return jsonElement.Deserialize<T>();
+
+ throw new InvalidCastException($"Value for key '{key}' ({value.GetType()}) cannot be cast to type '{typeof(T)}'. Cannot continue.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/LibMatrix.EventTypes/EventContent.cs b/LibMatrix.EventTypes/EventContent.cs
index 07f56e2..7a9f0aa 100644
--- a/LibMatrix.EventTypes/EventContent.cs
+++ b/LibMatrix.EventTypes/EventContent.cs
@@ -1,3 +1,5 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Net.Http.Json;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
@@ -5,6 +7,7 @@ using System.Text.Json.Serialization;
namespace LibMatrix.EventTypes;
+[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "These get instantiated via reflection")]
public abstract class EventContent {
[JsonExtensionData]
public Dictionary<string, object>? AdditionalData { get; set; } = [];
@@ -15,6 +18,7 @@ public abstract class EventContent {
foreach (var attr in type.GetCustomAttributes<MatrixEventAttribute>(true)) {
eventTypes.Add(attr.EventName);
}
+
return eventTypes;
}
}
@@ -53,7 +57,7 @@ public abstract class TimelineEventContent : EventContent {
// used for reactions
[JsonPropertyName("key")]
public string? Key { get; set; }
-
+
[JsonExtensionData]
public Dictionary<string, object>? AdditionalData { get; set; } = [];
diff --git a/LibMatrix.EventTypes/LibMatrix.EventTypes.csproj b/LibMatrix.EventTypes/LibMatrix.EventTypes.csproj
index 0924aba..e633aef 100644
--- a/LibMatrix.EventTypes/LibMatrix.EventTypes.csproj
+++ b/LibMatrix.EventTypes/LibMatrix.EventTypes.csproj
@@ -1,14 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>net9.0</TargetFramework>
+ <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
+ <PackageId>RoryLibMatrix.EventTypes</PackageId>
+ <PackageLicenseExpression>AGPL-3.0-only</PackageLicenseExpression>
+ <PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="ArcaneLibs" Version="1.0.0-preview.20250419-174711" Condition="'$(Configuration)' == 'Release'" />
- <ProjectReference Include="..\ArcaneLibs\ArcaneLibs\ArcaneLibs.csproj" Condition="'$(Configuration)' == 'Debug'"/>
+ <None Include="../README.md" Pack="true" PackagePath="\"/>
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\ArcaneLibs\ArcaneLibs\ArcaneLibs.csproj" Condition="'$(ContinuousIntegrationBuild)'!='true'"/>
+ <PackageReference Include="ArcaneLibs" Version="1.0.0-preview.2025*" Condition="'$(ContinuousIntegrationBuild)'=='true'"/>
</ItemGroup>
</Project>
diff --git a/LibMatrix.EventTypes/Spec/RoomMessageEventContent.cs b/LibMatrix.EventTypes/Spec/RoomMessageEventContent.cs
index d1cf8be..ccb5d42 100644
--- a/LibMatrix.EventTypes/Spec/RoomMessageEventContent.cs
+++ b/LibMatrix.EventTypes/Spec/RoomMessageEventContent.cs
@@ -11,6 +11,9 @@ public class RoomMessageEventContent : TimelineEventContent {
Body = body ?? "";
}
+ // TODO: https://spec.matrix.org/v1.16/client-server-api/#mimage
+ // TODO: add `file` for e2ee files
+
[JsonPropertyName("body")]
public string Body { get; set; }
@@ -53,7 +56,7 @@ public class RoomMessageEventContent : TimelineEventContent {
public class MentionsStruct {
[JsonPropertyName("user_ids")]
public List<string>? Users { get; set; }
-
+
[JsonPropertyName("room")]
public bool? Room { get; set; }
}
@@ -68,10 +71,33 @@ public class RoomMessageEventContent : TimelineEventContent {
[JsonPropertyName("thumbnail_url")]
public string? ThumbnailUrl { get; set; }
+ [JsonPropertyName("thumbnail_info")]
+ public ThumbnailInfoStruct? ThumbnailInfo { get; set; }
+
[JsonPropertyName("w")]
public int? Width { get; set; }
[JsonPropertyName("h")]
public int? Height { get; set; }
+
+ /// <summary>
+ /// Duration of the audio/video in milliseconds, if applicable
+ /// </summary>
+ [JsonPropertyName("duration")]
+ public long? Duration { get; set; }
+
+ public class ThumbnailInfoStruct {
+ [JsonPropertyName("w")]
+ public int? Width { get; set; }
+
+ [JsonPropertyName("h")]
+ public int? Height { get; set; }
+
+ [JsonPropertyName("mimetype")]
+ public string? MimeType { get; set; }
+
+ [JsonPropertyName("size")]
+ public long? Size { get; set; }
+ }
}
}
\ No newline at end of file
diff --git a/LibMatrix.EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs b/LibMatrix.EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs
index d75b19f..36c94ae 100644
--- a/LibMatrix.EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs
+++ b/LibMatrix.EventTypes/Spec/State/Policy/PolicyRuleStateEventContent.cs
@@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Security.Cryptography;
+using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using ArcaneLibs.Attributes;
@@ -87,20 +88,16 @@ public abstract class PolicyRuleEventContent : EventContent {
public PolicyHash? Hashes { get; set; }
public string GetDraupnir2StateKey() => Convert.ToBase64String(SHA256.HashData($"{Entity}{Recommendation}".AsBytes().ToArray()));
-
- public Regex? GetEntityRegex() => Entity is null ? null : new(Entity.Replace(".", "\\.").Replace("*", ".*").Replace("?", "."));
-
- public bool IsGlobRule() =>
- !string.IsNullOrWhiteSpace(Entity)
- && (Entity.Contains('*') || Entity.Contains('?'));
+ public Regex? GetEntityRegex() => Entity is null ? null : new(Entity.Replace(".", "\\.").Replace("*", ".*").Replace("?", "."), RegexOptions.Compiled);
+ public bool IsGlobRule() => !string.IsNullOrWhiteSpace(Entity) && (Entity.Contains('*') || Entity.Contains('?'));
+ public bool IsHashedRule() => string.IsNullOrWhiteSpace(Entity) && Hashes is not null;
public bool EntityMatches(string entity) {
if (string.IsNullOrWhiteSpace(entity)) return false;
if (!string.IsNullOrWhiteSpace(Entity)) {
// Check if entity is equal regardless of glob check
- var match = Entity == entity
- || (IsGlobRule() && GetEntityRegex()!.IsMatch(entity));
+ var match = Entity == entity || (IsGlobRule() && GetEntityRegex()!.IsMatch(entity));
if (match) return match;
}
@@ -124,6 +121,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,12 +147,18 @@ 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 {
[JsonPropertyName("sha256")]
public string? Sha256 { get; set; }
+
+ [JsonExtensionData]
+ public Dictionary<string, object>? AdditionalProperties { get; set; }
}
// public class PolicySchemaDefinition {
diff --git a/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomCreateEventContent.cs b/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomCreateEventContent.cs
index 37b831a..3dd033b 100644
--- a/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomCreateEventContent.cs
+++ b/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomCreateEventContent.cs
@@ -1,5 +1,7 @@
using System.Diagnostics.CodeAnalysis;
+using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
+using ArcaneLibs.Extensions;
namespace LibMatrix.EventTypes.Spec.State.RoomInfo;
@@ -12,9 +14,14 @@ public class RoomCreateEventContent : EventContent {
[JsonPropertyName("room_version")]
public string? RoomVersion { get; set; }
+ // missing in room version 11+
[JsonPropertyName("creator")]
public string? Creator { get; set; }
+ // v12+
+ [JsonPropertyName("additional_creators")]
+ public List<string>? AdditionalCreators { get; set; }
+
[JsonPropertyName("m.federate")]
public bool? Federate { get; set; }
diff --git a/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomHistoryVisibilityEventContent.cs b/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomHistoryVisibilityEventContent.cs
index 8edf4a7..3b3ba34 100644
--- a/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomHistoryVisibilityEventContent.cs
+++ b/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomHistoryVisibilityEventContent.cs
@@ -13,5 +13,6 @@ public class RoomHistoryVisibilityEventContent : EventContent {
public const string WorldReadable = "world_readable";
public const string Invited = "invited";
public const string Shared = "shared";
+ public const string Joined = "joined";
}
}
\ No newline at end of file
diff --git a/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomMemberEventContent.cs b/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomMemberEventContent.cs
index b034425..287754a 100644
--- a/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomMemberEventContent.cs
+++ b/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomMemberEventContent.cs
@@ -1,3 +1,5 @@
+using System.Text.Json;
+using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace LibMatrix.EventTypes.Spec.State.RoomInfo;
@@ -26,7 +28,29 @@ public class RoomMemberEventContent : EventContent {
[JsonPropertyName("join_authorised_via_users_server")]
public string? JoinAuthorisedViaUsersServer { get; set; }
-
+
+ [JsonPropertyName("third_party_invite")]
+ public ThirdPartyMemberInvite? ThirdPartyInvite { get; set; }
+
+ public class ThirdPartyMemberInvite {
+ [JsonPropertyName("display_name")]
+ public required string DisplayName { get; set; }
+
+ [JsonPropertyName("signed")]
+ public required SignedThirdPartyInvite Signed { get; set; }
+
+ public class SignedThirdPartyInvite {
+ [JsonPropertyName("mxid")]
+ public required string Mxid { get; set; }
+
+ [JsonPropertyName("signatures")]
+ public required Dictionary<string, Dictionary<string, string>> Signatures { get; set; }
+
+ [JsonPropertyName("token")]
+ public required string Token { get; set; }
+ }
+ }
+
public static class MembershipTypes {
public const string Invite = "invite";
public const string Join = "join";
diff --git a/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomServerACLEventContent.cs b/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomServerACLEventContent.cs
index c492250..c7ad491 100644
--- a/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomServerACLEventContent.cs
+++ b/LibMatrix.EventTypes/Spec/State/RoomInfo/RoomServerACLEventContent.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
+using System.Text.RegularExpressions;
namespace LibMatrix.EventTypes.Spec.State.RoomInfo;
@@ -14,4 +15,10 @@ public class RoomServerAclEventContent : EventContent {
[JsonPropertyName("allow_ip_literals")]
public bool AllowIpLiterals { get; set; } // = false;
+
+ [JsonIgnore]
+ public List<Regex>? AllowRegexes => Allow?.ConvertAll(pattern => new Regex(pattern.Replace(".", "\\.").Replace("*", ".*").Replace("?", "."), RegexOptions.Compiled)) ?? [];
+
+ [JsonIgnore]
+ public List<Regex>? DenyRegexes => Deny?.ConvertAll(pattern => new Regex(pattern.Replace(".", "\\.").Replace("*", ".*").Replace("?", "."), RegexOptions.Compiled)) ?? [];
}
\ No newline at end of file
diff --git a/LibMatrix.EventTypes/deps.json b/LibMatrix.EventTypes/deps.json
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/LibMatrix.EventTypes/deps.json
|