group settings (TEST)
This commit is contained in:
parent
f7be24e615
commit
97fbbc7b71
4 changed files with 194 additions and 13 deletions
|
|
@ -666,7 +666,7 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
|||
"dm/message/send", "dm/message/delete", "dm/message/react", "dm/key/update", "dm/message/pin/toggle",
|
||||
"dm/message/react/add", "dm/message/react/remove",
|
||||
"user/storage/public/update", "user/storage/private/update", "dm/read",
|
||||
"group/create", "user/group/list", "group/info",
|
||||
"group/create", "user/group/list", "group/info", "group/settings/update",
|
||||
"user/invite/accept", "user/invite/decline", "user/invite/revoke", "user/dm/list", "user/group/list",
|
||||
"user/storage/public/update", "user/storage/private/update", "group/storage/public/update", "group/storage/private/update", "group/storage/private/getentry", "dm/read", "group/read",
|
||||
"dm/message/send", "dm/message/delete", "dm/message/react/add", "dm/message/react/remove", "dm/message/pin/toggle",
|
||||
|
|
@ -806,16 +806,25 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
|||
break;
|
||||
case "group/create":
|
||||
{
|
||||
Universal2String groupCreate = JsonSerializer.Deserialize(
|
||||
Universal3String groupCreate = JsonSerializer.Deserialize(
|
||||
serializedBody.string2,
|
||||
AppJsonSerializerContext.Default.Universal2String
|
||||
AppJsonSerializerContext.Default.Universal3String
|
||||
);
|
||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptString(await Room.Groups.GroupCreate(id, groupCreate.string1, groupCreate.string2), password));
|
||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptString(await Room.Groups.GroupCreate(id, groupCreate.string1, groupCreate.string2, groupCreate.string3), password));
|
||||
break;
|
||||
}
|
||||
case "group/info":
|
||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptString(await Room.Groups.GroupInfo(serializedBody.string2), password));
|
||||
break;
|
||||
case "group/settings/update":
|
||||
{
|
||||
Universal3String req = JsonSerializer.Deserialize(
|
||||
serializedBody.string2,
|
||||
AppJsonSerializerContext.Default.Universal3String
|
||||
);
|
||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptString(await Room.Groups.GroupSettingsUpdate(id, req.string1, req.string2, req.string3), password));
|
||||
break;
|
||||
}
|
||||
case "group/invite":
|
||||
{
|
||||
Universal2String payload = JsonSerializer.Deserialize(
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public class Groups
|
|||
await Fs.WriteFile(groupPath, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(fileGroup, AppJsonSerializerContext.Default.Universal3String)));
|
||||
}
|
||||
|
||||
public static async Task<string> GroupCreate(string id, string name, string body)
|
||||
public static async Task<string> GroupCreate(string id, string name, string body, string historyVisible = "false")
|
||||
{
|
||||
await Room.Requests.createLock.WaitAsync();
|
||||
try
|
||||
|
|
@ -84,6 +84,7 @@ public class Groups
|
|||
await Fs.WriteFile($"{groupPath}/keys/last", Encoding.UTF8.GetBytes("0"));
|
||||
await Fs.WriteFile($"{groupPath}/keys/newrequired", Encoding.UTF8.GetBytes("false"));
|
||||
await Fs.WriteFile($"{groupPath}/name", Encoding.UTF8.GetBytes(name));
|
||||
await Fs.WriteFile($"{groupPath}/history_visible", Encoding.UTF8.GetBytes(historyVisible == "true" ? "true" : "false"));
|
||||
|
||||
// body is the key encrypted for the creator
|
||||
await Fs.WriteFile($"{groupPath}/keys/0/{id};{DOMAIN}", Encoding.UTF8.GetBytes(body));
|
||||
|
|
@ -149,6 +150,102 @@ public class Groups
|
|||
return $"{ROOMS_DIR}/groups/{domain}/{id}";
|
||||
}
|
||||
|
||||
public static async Task<string> GroupSettingsUpdate(string userId, string groupId, string name, string historyVisible)
|
||||
{
|
||||
string groupPath = GetGroupPath(groupId);
|
||||
if (!Fs.Exists(groupPath)) return "error:group.not.found";
|
||||
|
||||
string memberPath = $"{groupPath}/members/{userId};{Utils.Utils.DOMAIN}";
|
||||
if (!Fs.Exists(memberPath)) return "error:not.a.member";
|
||||
|
||||
await Room.Requests.createLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) return "error:invalid.name";
|
||||
await Fs.WriteFile($"{groupPath}/name", Encoding.UTF8.GetBytes(name));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(historyVisible))
|
||||
{
|
||||
bool currentState = false;
|
||||
if (Fs.Exists($"{groupPath}/history_visible"))
|
||||
{
|
||||
currentState = Encoding.UTF8.GetString(await Fs.ReadFile($"{groupPath}/history_visible")) == "true";
|
||||
}
|
||||
|
||||
bool newState = historyVisible == "true";
|
||||
|
||||
if (currentState != newState)
|
||||
{
|
||||
await Fs.WriteFile($"{groupPath}/history_visible", Encoding.UTF8.GetBytes(newState ? "true" : "false"));
|
||||
|
||||
string timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
|
||||
|
||||
Message infoMsg = new();
|
||||
infoMsg.attachment = "";
|
||||
infoMsg.author = userId;
|
||||
infoMsg.timestamp = timestamp;
|
||||
infoMsg.type = "larp.info.history";
|
||||
infoMsg.content = newState ? "{blah(history.visible)}" : "{blah(history.hidden)}";
|
||||
infoMsg.key = "";
|
||||
|
||||
ulong lastMessageId = 0;
|
||||
if (Fs.Exists($"{groupPath}/messages/last"))
|
||||
{
|
||||
lastMessageId = ulong.Parse(Encoding.UTF8.GetString(await Fs.ReadFile($"{groupPath}/messages/last")));
|
||||
}
|
||||
ulong newMessageId = lastMessageId + 1;
|
||||
|
||||
infoMsg.pervious = lastMessageId.ToString();
|
||||
|
||||
await Fs.WriteFile($"{groupPath}/messages/{newMessageId}", Encoding.UTF8.GetBytes(JsonSerializer.Serialize(infoMsg, AppJsonSerializerContext.Default.Message)));
|
||||
await Fs.WriteFile($"{groupPath}/messages/last", Encoding.UTF8.GetBytes(newMessageId.ToString()));
|
||||
|
||||
string[] members = Fs.ReadDirectory($"{groupPath}/members");
|
||||
foreach (string memberWD in members)
|
||||
{
|
||||
string memberStr = Path.GetFileName(memberWD);
|
||||
bool isLocal = Account.Utils.IsUserLocal(memberStr, out string d);
|
||||
string memberId = Account.Utils.GetValidIdOrZero(memberStr);
|
||||
if (isLocal)
|
||||
{
|
||||
if (memberId == userId)
|
||||
{
|
||||
await UpdateUserGroup(memberId, groupId, "true", timestamp);
|
||||
await Utils.Utils.SendWsMessage(memberId, $"group_message:{groupId}:read");
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
SemaphoreSlim userLock = Account.Utils.GetUserLock(memberId);
|
||||
await userLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
await UpdateUserGroup(memberId, groupId, "false", timestamp);
|
||||
}
|
||||
finally
|
||||
{
|
||||
userLock.Release();
|
||||
}
|
||||
await Utils.Utils.SendWsMessage(memberId, $"group_message:{groupId}:unread");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Room.Requests.createLock.Release();
|
||||
}
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
public static async Task<string> GroupInfo(string groupId)
|
||||
{
|
||||
string groupPath = GetGroupPath(groupId);
|
||||
|
|
@ -181,16 +278,23 @@ public class Groups
|
|||
newRequired = Encoding.UTF8.GetString(await Fs.ReadFile($"{groupPath}/keys/newrequired"));
|
||||
}
|
||||
|
||||
var info = new Universal5String
|
||||
string historyVisible = "false";
|
||||
if (Fs.Exists($"{groupPath}/history_visible"))
|
||||
{
|
||||
historyVisible = Encoding.UTF8.GetString(await Fs.ReadFile($"{groupPath}/history_visible"));
|
||||
}
|
||||
|
||||
var info = new Universal6String
|
||||
{
|
||||
string1 = groupId,
|
||||
string2 = name,
|
||||
string3 = memberCount,
|
||||
string4 = lastKeyIndex,
|
||||
string5 = newRequired
|
||||
string5 = newRequired,
|
||||
string6 = historyVisible
|
||||
};
|
||||
|
||||
return JsonSerializer.Serialize(info, AppJsonSerializerContext.Default.Universal5String);
|
||||
return JsonSerializer.Serialize(info, AppJsonSerializerContext.Default.Universal6String);
|
||||
}
|
||||
|
||||
public static async Task<string> GroupInvite(string id, string groupId, string targetId)
|
||||
|
|
@ -319,9 +423,16 @@ public class Groups
|
|||
// Add to members
|
||||
await Fs.WriteFile($"{groupPath}/members/{id};{DOMAIN}", Array.Empty<byte>());
|
||||
|
||||
// Require new key
|
||||
await Fs.WriteFile($"{groupPath}/keys/newrequired", Encoding.UTF8.GetBytes("true"));
|
||||
|
||||
// Require new key if history is not visible
|
||||
bool historyVisible = false;
|
||||
if (Fs.Exists($"{groupPath}/history_visible"))
|
||||
{
|
||||
historyVisible = Encoding.UTF8.GetString(await Fs.ReadFile($"{groupPath}/history_visible")) == "true";
|
||||
}
|
||||
if (!historyVisible)
|
||||
{
|
||||
await Fs.WriteFile($"{groupPath}/keys/newrequired", Encoding.UTF8.GetBytes("true"));
|
||||
}
|
||||
string timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
|
||||
|
||||
Message joinMsg = new();
|
||||
|
|
@ -520,6 +631,42 @@ public class Groups
|
|||
return "success:storage.entry.updated";
|
||||
}
|
||||
|
||||
public static async Task<string> GroupDelete(string groupId)
|
||||
{
|
||||
string[] parts = groupId.Split(';');
|
||||
string id = parts[0];
|
||||
string domain = parts.Length > 1 ? parts[1] : Utils.Utils.DOMAIN;
|
||||
string groupPath = $"{Utils.Utils.ROOMS_DIR}/groups/{domain}/{id}";
|
||||
|
||||
if (!Fs.Exists(groupPath)) return "error:group.not.found";
|
||||
|
||||
await Room.Requests.createLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
string membersDir = $"{groupPath}/members";
|
||||
if (Fs.Exists(membersDir))
|
||||
{
|
||||
string[] memberFiles = Fs.ReadDirectory(membersDir);
|
||||
foreach (string memberFile in memberFiles)
|
||||
{
|
||||
string memberId = memberFile.Split(';')[0];
|
||||
string userGroupPath = $"{Utils.Utils.ACCOUNTS_DATA_DIR}/{memberId}/groups/{id};{domain}";
|
||||
if (Fs.Exists(userGroupPath))
|
||||
{
|
||||
Fs.DeleteFile(userGroupPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
Fs.DeleteDirectory(groupPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Room.Requests.createLock.Release();
|
||||
}
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
public static async Task<string> GroupLeave(string userId, string groupId)
|
||||
{
|
||||
string[] parts = groupId.Split(';');
|
||||
|
|
@ -547,8 +694,16 @@ public class Groups
|
|||
Fs.DeleteFile(userGroupPath);
|
||||
}
|
||||
|
||||
// Require new key
|
||||
await Fs.WriteFile($"{groupPath}/keys/newrequired", Encoding.UTF8.GetBytes("true"));
|
||||
// Require new key if history is not visible
|
||||
bool historyVisible = false;
|
||||
if (Fs.Exists($"{groupPath}/history_visible"))
|
||||
{
|
||||
historyVisible = Encoding.UTF8.GetString(await Fs.ReadFile($"{groupPath}/history_visible")) == "true";
|
||||
}
|
||||
if (!historyVisible)
|
||||
{
|
||||
await Fs.WriteFile($"{groupPath}/keys/newrequired", Encoding.UTF8.GetBytes("true"));
|
||||
}
|
||||
|
||||
// Add info message
|
||||
Message msg = new();
|
||||
|
|
@ -575,6 +730,13 @@ public class Groups
|
|||
Room.Requests.createLock.Release();
|
||||
}
|
||||
|
||||
// If members count == 0, delete group folder and we are done.
|
||||
// Doing it outside the lock since GroupDelete takes the lock again.
|
||||
if (Fs.ReadDirectory($"{groupPath}/members").Length == 0)
|
||||
{
|
||||
await GroupDelete(groupId);
|
||||
}
|
||||
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ using System.Collections.Generic;
|
|||
[JsonSerializable(typeof(Universal3String))]
|
||||
[JsonSerializable(typeof(Universal4String))]
|
||||
[JsonSerializable(typeof(Universal5String))]
|
||||
[JsonSerializable(typeof(Universal6String))]
|
||||
[JsonSerializable(typeof(ServerInfo))]
|
||||
[JsonSerializable(typeof(Message))]
|
||||
[JsonSerializable(typeof(Dictionary<string, string>))]
|
||||
|
|
|
|||
|
|
@ -34,6 +34,15 @@ public class Universal5String
|
|||
public string string5 { get; set; }
|
||||
}
|
||||
|
||||
public class Universal6String
|
||||
{
|
||||
public string string1 { get; set; }
|
||||
public string string2 { get; set; }
|
||||
public string string3 { get; set; }
|
||||
public string string4 { get; set; }
|
||||
public string string5 { get; set; }
|
||||
public string string6 { get; set; }
|
||||
}
|
||||
|
||||
public class KeyExchangePayload
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue