better account deletion, add keys to password change,add updating user storage
This commit is contained in:
parent
6571f38afa
commit
499de238cb
5 changed files with 168 additions and 28 deletions
|
|
@ -44,7 +44,10 @@ public class BackgroundDelete : BackgroundService
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string username = await Account.Utils.NameFromId(id);
|
string username = await Account.Utils.NameFromId(id);
|
||||||
Fs.DeleteFile($"{LarpixServer.Utils.Utils.ACCOUNTS_NAME_DIR}/{username.ToLower()}");
|
if (!string.IsNullOrEmpty(username))
|
||||||
|
{
|
||||||
|
Fs.DeleteFile($"{LarpixServer.Utils.Utils.ACCOUNTS_NAME_DIR}/{username.ToLower()}");
|
||||||
|
}
|
||||||
Fs.DeleteDirectory(account);
|
Fs.DeleteDirectory(account);
|
||||||
Fs.WriteFile($"{LarpixServer.Utils.Utils.ACCOUNTS_FREEID_DIR}/{id}", []);
|
Fs.WriteFile($"{LarpixServer.Utils.Utils.ACCOUNTS_FREEID_DIR}/{id}", []);
|
||||||
Console.WriteLine($"Deleted {id} ({username})");
|
Console.WriteLine($"Deleted {id} ({username})");
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,7 @@ public class Requests
|
||||||
userLock.Release();
|
userLock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
await context.Response.WriteAsync(
|
await context.Response.WriteAsync("success:account.deleted.scheduled");
|
||||||
"ok|Your account will be deleted in one month|Please make sure you are logged out on all devices. Logging back into your account during this period will stop the deletion process");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task Create(HttpContext context, Func<Task> next, IQueryCollection query,
|
public static async Task Create(HttpContext context, Func<Task> next, IQueryCollection query,
|
||||||
|
|
@ -232,33 +231,32 @@ public class Requests
|
||||||
|
|
||||||
ulong id = ulong.Parse(await Fs.ReadFile($"{ACCOUNTS_DIR}/last"));
|
ulong id = ulong.Parse(await Fs.ReadFile($"{ACCOUNTS_DIR}/last"));
|
||||||
id++;
|
id++;
|
||||||
var freeid = Path.GetFileName(Directory.EnumerateFiles(ACCOUNTS_FREEID_DIR).FirstOrDefault());
|
if (id == ulong.MaxValue)
|
||||||
if (freeid != null)
|
|
||||||
{
|
{
|
||||||
id = ulong.Parse(freeid);
|
await context.Response.WriteAsync("error:accounts.slots.full");
|
||||||
Fs.DeleteFile($"{ACCOUNTS_FREEID_DIR}/{freeid}");
|
return;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (id == ulong.MaxValue)
|
|
||||||
{
|
|
||||||
await context.Response.WriteAsync(
|
|
||||||
"error:accounts.slots.full");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Fs.WriteFile($"{ACCOUNTS_DIR}/last", Encoding.UTF8.GetBytes(id.ToString()));
|
|
||||||
}
|
}
|
||||||
|
await Fs.WriteFile($"{ACCOUNTS_DIR}/last", Encoding.UTF8.GetBytes(id.ToString()));
|
||||||
|
|
||||||
SemaphoreSlim userLock = Utils.GetUserLock(id.ToString());
|
SemaphoreSlim userLock = Utils.GetUserLock(id.ToString());
|
||||||
await userLock.WaitAsync();
|
await userLock.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Fs.WriteFile($"{ACCOUNTS_NAME_DIR}/{lowerName}", Encoding.UTF8.GetBytes(id.ToString()));
|
await Fs.WriteFile($"{ACCOUNTS_NAME_DIR}/{lowerName}", Encoding.UTF8.GetBytes(id.ToString()));
|
||||||
await Fs.WriteFile($"{ACCOUNTS_DATA_DIR}/{id.ToString()}/username",
|
|
||||||
Encoding.UTF8.GetBytes(entry.name));
|
try
|
||||||
await Fs.WriteFile($"{ACCOUNTS_DATA_DIR}/{id.ToString()}/secret",
|
{
|
||||||
Encoding.UTF8.GetBytes(entry.pass));
|
await Fs.WriteFile($"{ACCOUNTS_DATA_DIR}/{id.ToString()}/username",
|
||||||
|
Encoding.UTF8.GetBytes(entry.name));
|
||||||
|
await Fs.WriteFile($"{ACCOUNTS_DATA_DIR}/{id.ToString()}/secret",
|
||||||
|
Encoding.UTF8.GetBytes(entry.pass));
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Fs.DeleteFile($"{ACCOUNTS_NAME_DIR}/{lowerName}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
createHolder.TryRemove(serialized.idKey, out _);
|
createHolder.TryRemove(serialized.idKey, out _);
|
||||||
await Utils.UpdateLastLogin(id.ToString());
|
await Utils.UpdateLastLogin(id.ToString());
|
||||||
}
|
}
|
||||||
|
|
@ -408,7 +406,7 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
||||||
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
||||||
string body = await LoadBody(bodyReader);
|
string body = await LoadBody(bodyReader);
|
||||||
string password = await Utils.GetPassword(id);
|
string password = await Utils.GetPassword(id);
|
||||||
string newPass = await Utils.NonceDecryptBody(id, password, body, false);
|
string bodyDecrypted = await Utils.NonceDecryptBody(id, password, body, false);
|
||||||
secret = await Utils.NonceDecryptBody(id, password, secret);
|
secret = await Utils.NonceDecryptBody(id, password, secret);
|
||||||
|
|
||||||
string auth = await Utils.Auth(id, password, secret);
|
string auth = await Utils.Auth(id, password, secret);
|
||||||
|
|
@ -419,6 +417,20 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string newPass = bodyDecrypted;
|
||||||
|
string newKeysBody = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Universal2String parsedBody = JsonSerializer.Deserialize(bodyDecrypted, AppJsonSerializerContext.Default.Universal2String);
|
||||||
|
if (parsedBody != null && !string.IsNullOrWhiteSpace(parsedBody.string1) && !string.IsNullOrWhiteSpace(parsedBody.string2))
|
||||||
|
{
|
||||||
|
newPass = parsedBody.string1;
|
||||||
|
newKeysBody = parsedBody.string2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
SemaphoreSlim userLock = Utils.GetUserLock(id);
|
SemaphoreSlim userLock = Utils.GetUserLock(id);
|
||||||
await userLock.WaitAsync();
|
await userLock.WaitAsync();
|
||||||
try
|
try
|
||||||
|
|
@ -429,7 +441,30 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Utils.SetPassword(id, newPass);
|
string oldKeys = null;
|
||||||
|
if (newKeysBody != null)
|
||||||
|
{
|
||||||
|
oldKeys = await Utils.GetUserKeys(id);
|
||||||
|
string keyUpdateResult = await UpdateUserKeys(id, newKeysBody);
|
||||||
|
if (keyUpdateResult.StartsWith("error:"))
|
||||||
|
{
|
||||||
|
await context.Response.WriteAsync(keyUpdateResult);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Utils.SetPassword(id, newPass);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
if (newKeysBody != null && oldKeys != null)
|
||||||
|
{
|
||||||
|
await Utils.UpdateUserKeys(id, oldKeys);
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
@ -620,6 +655,30 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
||||||
await Utils.GetUserKeys(id)
|
await Utils.GetUserKeys(id)
|
||||||
, password));
|
, password));
|
||||||
break;
|
break;
|
||||||
|
case "user/storage/public/update":
|
||||||
|
{
|
||||||
|
Universal2String storageUpdate = JsonSerializer.Deserialize(
|
||||||
|
serializedBody.string2,
|
||||||
|
AppJsonSerializerContext.Default.Universal2String
|
||||||
|
);
|
||||||
|
await context.Response.WriteAsync(
|
||||||
|
Encryption.Encryption.EncryptString(
|
||||||
|
await Utils.UpdateUserPublicStorageEntry(id, storageUpdate.string1, storageUpdate.string2)
|
||||||
|
, password));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "user/storage/private/update":
|
||||||
|
{
|
||||||
|
Universal2String storageUpdate = JsonSerializer.Deserialize(
|
||||||
|
serializedBody.string2,
|
||||||
|
AppJsonSerializerContext.Default.Universal2String
|
||||||
|
);
|
||||||
|
await context.Response.WriteAsync(
|
||||||
|
Encryption.Encryption.EncryptString(
|
||||||
|
await Utils.UpdateUserPrivateStorageEntry(id, storageUpdate.string1, storageUpdate.string2)
|
||||||
|
, password));
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "user/dm/list":
|
case "user/dm/list":
|
||||||
await context.Response.WriteAsync(
|
await context.Response.WriteAsync(
|
||||||
Encryption.Encryption.EncryptString(
|
Encryption.Encryption.EncryptString(
|
||||||
|
|
|
||||||
|
|
@ -304,6 +304,72 @@ public class Utils
|
||||||
return await Fs.ReadFile(path);
|
return await Fs.ReadFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<string> UpdateUserPublicStorageEntry(string id, string entry, string contentBase64)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(entry) || entry.Contains("..") || entry.Contains("/") || entry.Contains("\\"))
|
||||||
|
{
|
||||||
|
return "error:invalid.entry.name";
|
||||||
|
}
|
||||||
|
byte[] contentBytes;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
contentBytes = Convert.FromBase64String(contentBase64);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
contentBytes = Encoding.UTF8.GetBytes(contentBase64);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentBytes.Length > PUBLIC_STORAGE_LIMIT)
|
||||||
|
{
|
||||||
|
return "error:storage.limit.exceeded";
|
||||||
|
}
|
||||||
|
|
||||||
|
string path = $"{ACCOUNTS_DATA_DIR}/{id}/storage/public/{entry}";
|
||||||
|
await Fs.WriteFile(path, contentBytes);
|
||||||
|
return "success:storage.entry.updated";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<byte[]> GetUserPrivateStorageEntry(string id, string entry)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(entry) || entry.Contains("..") || entry.Contains("/") || entry.Contains("\\"))
|
||||||
|
{
|
||||||
|
return new byte[] {};
|
||||||
|
}
|
||||||
|
string path = $"{ACCOUNTS_DATA_DIR}/{id}/storage/private/{entry}";
|
||||||
|
if (!Fs.Exists(path))
|
||||||
|
{
|
||||||
|
return new byte[] {};
|
||||||
|
}
|
||||||
|
return await Fs.ReadFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<string> UpdateUserPrivateStorageEntry(string id, string entry, string contentBase64)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(entry) || entry.Contains("..") || entry.Contains("/") || entry.Contains("\\"))
|
||||||
|
{
|
||||||
|
return "error:invalid.entry.name";
|
||||||
|
}
|
||||||
|
byte[] contentBytes;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
contentBytes = Convert.FromBase64String(contentBase64);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
contentBytes = Encoding.UTF8.GetBytes(contentBase64);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentBytes.Length > PRIVATE_STORAGE_LIMIT)
|
||||||
|
{
|
||||||
|
return "error:storage.limit.exceeded";
|
||||||
|
}
|
||||||
|
|
||||||
|
string path = $"{ACCOUNTS_DATA_DIR}/{id}/storage/private/{entry}";
|
||||||
|
await Fs.WriteFile(path, contentBytes);
|
||||||
|
return "success:storage.entry.updated";
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task UpdateUserDm(string id, string dmId, string isRead = "false", string timestamp = "")
|
public static async Task UpdateUserDm(string id, string dmId, string isRead = "false", string timestamp = "")
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -394,7 +460,19 @@ public class Utils
|
||||||
|
|
||||||
Fs.MoveFile($"{ACCOUNTS_NAME_DIR}/{lowerOldName}", $"{ACCOUNTS_NAME_DIR}/{lowerNewName}");
|
Fs.MoveFile($"{ACCOUNTS_NAME_DIR}/{lowerOldName}", $"{ACCOUNTS_NAME_DIR}/{lowerNewName}");
|
||||||
}
|
}
|
||||||
await Fs.WriteFile($"{ACCOUNTS_DATA_DIR}/{id}/username", Encoding.UTF8.GetBytes(newName));
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Fs.WriteFile($"{ACCOUNTS_DATA_DIR}/{id}/username", Encoding.UTF8.GetBytes(newName));
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
if (lowerNewName != lowerOldName)
|
||||||
|
{
|
||||||
|
Fs.MoveFile($"{ACCOUNTS_NAME_DIR}/{lowerNewName}", $"{ACCOUNTS_NAME_DIR}/{lowerOldName}");
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
return "success:username.changed";
|
return "success:username.changed";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -396,7 +396,7 @@ public class Requests
|
||||||
msg.type = "larp.text";
|
msg.type = "larp.text";
|
||||||
msg.content = content;
|
msg.content = content;
|
||||||
msg.attachment = attachment;
|
msg.attachment = attachment;
|
||||||
msg.key = "0"; // Flag for encrypted content
|
msg.key = "0"; //empty = no encryption, value = encryption key index
|
||||||
msg.pervious = "";
|
msg.pervious = "";
|
||||||
msg.responded = responded ?? "";
|
msg.responded = responded ?? "";
|
||||||
msg.reactions = "";
|
msg.reactions = "";
|
||||||
|
|
@ -435,7 +435,7 @@ public class Requests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "success:message.sent";
|
return $"success:{nextId}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string> DmMessageDelete(string id, string body)
|
public static async Task<string> DmMessageDelete(string id, string body)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ public class Utils
|
||||||
public static int DIR_CACHE_SIZE = 800000;
|
public static int DIR_CACHE_SIZE = 800000;
|
||||||
public static int LOCK_SIZE = 1000000;
|
public static int LOCK_SIZE = 1000000;
|
||||||
|
|
||||||
public static int MAX_BODY_SIZE = 524288; //0.5mb
|
public static int MAX_BODY_SIZE = 20971520; //20mb //2621440; //2.5mb
|
||||||
|
|
||||||
public static int PRIVATE_STORAGE_LIMIT = 5242880;
|
public static int PRIVATE_STORAGE_LIMIT = 5242880;
|
||||||
public static int PUBLIC_STORAGE_LIMIT = 10485760;
|
public static int PUBLIC_STORAGE_LIMIT = 10485760;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue