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/send", "dm/message/delete", "dm/message/react", "dm/key/update", "dm/message/pin/toggle",
|
||||||
"dm/message/react/add", "dm/message/react/remove",
|
"dm/message/react/add", "dm/message/react/remove",
|
||||||
"user/storage/public/update", "user/storage/private/update", "dm/read",
|
"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/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",
|
"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",
|
"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;
|
break;
|
||||||
case "group/create":
|
case "group/create":
|
||||||
{
|
{
|
||||||
Universal2String groupCreate = JsonSerializer.Deserialize(
|
Universal3String groupCreate = JsonSerializer.Deserialize(
|
||||||
serializedBody.string2,
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case "group/info":
|
case "group/info":
|
||||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptString(await Room.Groups.GroupInfo(serializedBody.string2), password));
|
await context.Response.WriteAsync(Encryption.Encryption.EncryptString(await Room.Groups.GroupInfo(serializedBody.string2), password));
|
||||||
break;
|
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":
|
case "group/invite":
|
||||||
{
|
{
|
||||||
Universal2String payload = JsonSerializer.Deserialize(
|
Universal2String payload = JsonSerializer.Deserialize(
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ public class Groups
|
||||||
await Fs.WriteFile(groupPath, Encoding.UTF8.GetBytes(JsonSerializer.Serialize(fileGroup, AppJsonSerializerContext.Default.Universal3String)));
|
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();
|
await Room.Requests.createLock.WaitAsync();
|
||||||
try
|
try
|
||||||
|
|
@ -84,6 +84,7 @@ public class Groups
|
||||||
await Fs.WriteFile($"{groupPath}/keys/last", Encoding.UTF8.GetBytes("0"));
|
await Fs.WriteFile($"{groupPath}/keys/last", Encoding.UTF8.GetBytes("0"));
|
||||||
await Fs.WriteFile($"{groupPath}/keys/newrequired", Encoding.UTF8.GetBytes("false"));
|
await Fs.WriteFile($"{groupPath}/keys/newrequired", Encoding.UTF8.GetBytes("false"));
|
||||||
await Fs.WriteFile($"{groupPath}/name", Encoding.UTF8.GetBytes(name));
|
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
|
// body is the key encrypted for the creator
|
||||||
await Fs.WriteFile($"{groupPath}/keys/0/{id};{DOMAIN}", Encoding.UTF8.GetBytes(body));
|
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}";
|
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)
|
public static async Task<string> GroupInfo(string groupId)
|
||||||
{
|
{
|
||||||
string groupPath = GetGroupPath(groupId);
|
string groupPath = GetGroupPath(groupId);
|
||||||
|
|
@ -181,16 +278,23 @@ public class Groups
|
||||||
newRequired = Encoding.UTF8.GetString(await Fs.ReadFile($"{groupPath}/keys/newrequired"));
|
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,
|
string1 = groupId,
|
||||||
string2 = name,
|
string2 = name,
|
||||||
string3 = memberCount,
|
string3 = memberCount,
|
||||||
string4 = lastKeyIndex,
|
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)
|
public static async Task<string> GroupInvite(string id, string groupId, string targetId)
|
||||||
|
|
@ -319,9 +423,16 @@ public class Groups
|
||||||
// Add to members
|
// Add to members
|
||||||
await Fs.WriteFile($"{groupPath}/members/{id};{DOMAIN}", Array.Empty<byte>());
|
await Fs.WriteFile($"{groupPath}/members/{id};{DOMAIN}", Array.Empty<byte>());
|
||||||
|
|
||||||
// Require new key
|
// Require new key if history is not visible
|
||||||
await Fs.WriteFile($"{groupPath}/keys/newrequired", Encoding.UTF8.GetBytes("true"));
|
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();
|
string timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
|
||||||
|
|
||||||
Message joinMsg = new();
|
Message joinMsg = new();
|
||||||
|
|
@ -520,6 +631,42 @@ public class Groups
|
||||||
return "success:storage.entry.updated";
|
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)
|
public static async Task<string> GroupLeave(string userId, string groupId)
|
||||||
{
|
{
|
||||||
string[] parts = groupId.Split(';');
|
string[] parts = groupId.Split(';');
|
||||||
|
|
@ -547,8 +694,16 @@ public class Groups
|
||||||
Fs.DeleteFile(userGroupPath);
|
Fs.DeleteFile(userGroupPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Require new key
|
// Require new key if history is not visible
|
||||||
await Fs.WriteFile($"{groupPath}/keys/newrequired", Encoding.UTF8.GetBytes("true"));
|
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
|
// Add info message
|
||||||
Message msg = new();
|
Message msg = new();
|
||||||
|
|
@ -575,6 +730,13 @@ public class Groups
|
||||||
Room.Requests.createLock.Release();
|
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";
|
return "success";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ using System.Collections.Generic;
|
||||||
[JsonSerializable(typeof(Universal3String))]
|
[JsonSerializable(typeof(Universal3String))]
|
||||||
[JsonSerializable(typeof(Universal4String))]
|
[JsonSerializable(typeof(Universal4String))]
|
||||||
[JsonSerializable(typeof(Universal5String))]
|
[JsonSerializable(typeof(Universal5String))]
|
||||||
|
[JsonSerializable(typeof(Universal6String))]
|
||||||
[JsonSerializable(typeof(ServerInfo))]
|
[JsonSerializable(typeof(ServerInfo))]
|
||||||
[JsonSerializable(typeof(Message))]
|
[JsonSerializable(typeof(Message))]
|
||||||
[JsonSerializable(typeof(Dictionary<string, string>))]
|
[JsonSerializable(typeof(Dictionary<string, string>))]
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,15 @@ public class Universal5String
|
||||||
public string string5 { get; set; }
|
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
|
public class KeyExchangePayload
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue