Added reactions, replies, message redacting
All checks were successful
Server Build / publish (push) Successful in 30s
Voice Build / publish (push) Successful in 26s

This commit is contained in:
olcxja 2026-06-12 16:52:30 +02:00
commit 6571f38afa
4 changed files with 117 additions and 2 deletions

View file

@ -653,6 +653,18 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
await Room.Requests.DmMessageSend(id, serializedBody.string2) await Room.Requests.DmMessageSend(id, serializedBody.string2)
, password)); , password));
break; break;
case "dm/message/delete":
await context.Response.WriteAsync(
Encryption.Encryption.EncryptString(
await Room.Requests.DmMessageDelete(id, serializedBody.string2)
, password));
break;
case "dm/message/react":
await context.Response.WriteAsync(
Encryption.Encryption.EncryptString(
await Room.Requests.DmMessageReact(id, serializedBody.string2)
, password));
break;
case "dm/messages/get": case "dm/messages/get":
{ {
Universal3String msgGet = JsonSerializer.Deserialize( Universal3String msgGet = JsonSerializer.Deserialize(

View file

@ -23,6 +23,16 @@ public class Requests
return true; return true;
} }
private static bool IsSafeMsgId(string msgId)
{
if (string.IsNullOrEmpty(msgId)) return false;
if (msgId.Contains("..") || msgId.Contains("/") || msgId.Contains("\\"))
{
return false;
}
return true;
}
private static async Task<bool> IsMemberOfDm(string id, string dmId) private static async Task<bool> IsMemberOfDm(string id, string dmId)
{ {
if (!IsSafeDmId(dmId)) return false; if (!IsSafeDmId(dmId)) return false;
@ -361,13 +371,14 @@ public class Requests
public static async Task<string> DmMessageSend(string id, string body) public static async Task<string> DmMessageSend(string id, string body)
{ {
Universal3String serializedBody = JsonSerializer.Deserialize( Universal4String serializedBody = JsonSerializer.Deserialize(
body, body,
AppJsonSerializerContext.Default.Universal3String AppJsonSerializerContext.Default.Universal4String
); );
string dmId = serializedBody.string1; string dmId = serializedBody.string1;
string content = serializedBody.string2; string content = serializedBody.string2;
string attachment = serializedBody.string3; string attachment = serializedBody.string3;
string responded = serializedBody.string4;
if (!await IsMemberOfDm(id, dmId)) return "error:forbidden"; if (!await IsMemberOfDm(id, dmId)) return "error:forbidden";
@ -387,6 +398,8 @@ public class Requests
msg.attachment = attachment; msg.attachment = attachment;
msg.key = "0"; // Flag for encrypted content msg.key = "0"; // Flag for encrypted content
msg.pervious = ""; msg.pervious = "";
msg.responded = responded ?? "";
msg.reactions = "";
await Fs.WriteFile($"{msgDir}/{nextId}", Encoding.UTF8.GetBytes(JsonSerializer.Serialize(msg, AppJsonSerializerContext.Default.Message))); await Fs.WriteFile($"{msgDir}/{nextId}", Encoding.UTF8.GetBytes(JsonSerializer.Serialize(msg, AppJsonSerializerContext.Default.Message)));
await Fs.WriteFile($"{msgDir}/last", Encoding.UTF8.GetBytes(nextId.ToString())); await Fs.WriteFile($"{msgDir}/last", Encoding.UTF8.GetBytes(nextId.ToString()));
@ -424,4 +437,84 @@ public class Requests
} }
return "success:message.sent"; return "success:message.sent";
} }
public static async Task<string> DmMessageDelete(string id, string body)
{
Universal2String serializedBody = JsonSerializer.Deserialize(
body,
AppJsonSerializerContext.Default.Universal2String
);
string dmId = serializedBody.string1;
string msgId = serializedBody.string2;
if (!IsSafeMsgId(msgId)) return "error:invalid.msg.id";
if (!await IsMemberOfDm(id, dmId)) return "error:forbidden";
string msgPath = $"{ROOMS_DIR}/dms/{DOMAIN}/{dmId}/messages/{msgId}";
if (!Fs.Exists(msgPath)) return "error:message.not.found";
Message msg = JsonSerializer.Deserialize(
Encoding.UTF8.GetString(await Fs.ReadFile(msgPath)),
AppJsonSerializerContext.Default.Message
);
if (msg.author != id) return "error:forbidden";
msg.type = "larp.redacted";
msg.content = "{blah(larp.redacted)}";
msg.attachment = "";
msg.key = "";
await Fs.WriteFile(msgPath, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(msg, AppJsonSerializerContext.Default.Message)));
string[] members = Fs.ReadDirectory($"{ROOMS_DIR}/dms/{DOMAIN}/{dmId}/members");
foreach(string memberWD in members)
{
bool isLocal = Account.Utils.IsUserLocal(memberWD, out string domain);
string memberId = Account.Utils.GetValidIdOrZero(memberWD);
if (isLocal)
{
await Utils.Utils.SendWsMessage(memberId, $"dm_message:{dmId}");
}
}
return "success:message.deleted";
}
public static async Task<string> DmMessageReact(string id, string body)
{
Universal3String serializedBody = JsonSerializer.Deserialize(
body,
AppJsonSerializerContext.Default.Universal3String
);
string dmId = serializedBody.string1;
string msgId = serializedBody.string2;
string reactions = serializedBody.string3;
if (!IsSafeMsgId(msgId)) return "error:invalid.msg.id";
if (!await IsMemberOfDm(id, dmId)) return "error:forbidden";
string msgPath = $"{ROOMS_DIR}/dms/{DOMAIN}/{dmId}/messages/{msgId}";
if (!Fs.Exists(msgPath)) return "error:message.not.found";
Message msg = JsonSerializer.Deserialize(
Encoding.UTF8.GetString(await Fs.ReadFile(msgPath)),
AppJsonSerializerContext.Default.Message
);
msg.reactions = reactions ?? "";
await Fs.WriteFile(msgPath, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(msg, AppJsonSerializerContext.Default.Message)));
string[] members = Fs.ReadDirectory($"{ROOMS_DIR}/dms/{DOMAIN}/{dmId}/members");
foreach(string memberWD in members)
{
bool isLocal = Account.Utils.IsUserLocal(memberWD, out string domain);
string memberId = Account.Utils.GetValidIdOrZero(memberWD);
if (isLocal)
{
await Utils.Utils.SendWsMessage(memberId, $"dm_message:{dmId}");
}
}
return "success:message.reacted";
}
} }

View file

@ -7,6 +7,7 @@ namespace LarpixServer.Utils.Jsons;
[JsonSerializable(typeof(CaptchaPayloadClient))] [JsonSerializable(typeof(CaptchaPayloadClient))]
[JsonSerializable(typeof(Universal2String))] [JsonSerializable(typeof(Universal2String))]
[JsonSerializable(typeof(Universal3String))] [JsonSerializable(typeof(Universal3String))]
[JsonSerializable(typeof(Universal4String))]
[JsonSerializable(typeof(ServerInfo))] [JsonSerializable(typeof(ServerInfo))]
[JsonSerializable(typeof(Message))] [JsonSerializable(typeof(Message))]
public partial class AppJsonSerializerContext : JsonSerializerContext public partial class AppJsonSerializerContext : JsonSerializerContext

View file

@ -17,6 +17,13 @@ public class Universal3String
public string string2 { get; set; } public string string2 { get; set; }
public string string3 { get; set; } public string string3 { get; set; }
} }
public class Universal4String
{
public string string1 { get; set; }
public string string2 { get; set; }
public string string3 { get; set; }
public string string4 { get; set; }
}
public class KeyExchangePayload public class KeyExchangePayload
@ -51,4 +58,6 @@ public class Message
public string attachment { get; set; } public string attachment { get; set; }
public string timestamp { get; set; } public string timestamp { get; set; }
public string key { get; set; } public string key { get; set; }
public string responded { get; set; }
public string reactions { get; set; }
} }