add attachments
This commit is contained in:
parent
c523d40342
commit
91f8dd0db5
4 changed files with 149 additions and 3 deletions
|
|
@ -863,6 +863,87 @@ public static async Task Auth(HttpContext context, Func<Task> next, IQueryCollec
|
|||
userLock.Release();
|
||||
}
|
||||
}
|
||||
public static async Task UploadDmAttachmentStaging(HttpContext context, Func<Task> next, IQueryCollection query)
|
||||
{
|
||||
if (!query.TryGetValue("id", out var idQuery)) return;
|
||||
if (!context.Request.Headers.TryGetValue("secret", out var secret)) return;
|
||||
|
||||
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
||||
string password = await Utils.GetPassword(id);
|
||||
string secretStr = await Utils.NonceDecryptBody(id, password, secret, false);
|
||||
string auth = await Utils.Auth(id, secretStr, password);
|
||||
|
||||
if (auth != Utils.LOGIN_SUCCESS)
|
||||
{
|
||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptString(auth, secretStr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsActionRateLimited(id))
|
||||
{
|
||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptString("error:rate.limit", password));
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] fileBytes = await LarpixServer.Utils.Utils.LoadBodyBytes(context.Request.Body, 50 * 1024 * 1024); // 50MB limit for attachments
|
||||
if (fileBytes == null || fileBytes.Length == 0)
|
||||
{
|
||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptString("error:empty.body", password));
|
||||
return;
|
||||
}
|
||||
|
||||
string stagingId = Guid.NewGuid().ToString();
|
||||
string stagingDir = $"{LarpixServer.Utils.Utils.ROOMS_DIR}/dms_staging";
|
||||
string filePath = $"{stagingDir}/{stagingId}";
|
||||
|
||||
await Fs.WriteFile(filePath, fileBytes);
|
||||
|
||||
// Fire and forget 10 min timer to delete
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMinutes(10));
|
||||
if (Fs.Exists(filePath))
|
||||
{
|
||||
Fs.DeleteFile(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptString($"success:{stagingId}", password));
|
||||
}
|
||||
|
||||
public static async Task GetDmAttachment(HttpContext context, Func<Task> next, IQueryCollection query)
|
||||
{
|
||||
if (!query.TryGetValue("id", out var idQuery)) return;
|
||||
if (!query.TryGetValue("dm", out var dmQuery)) return;
|
||||
if (!query.TryGetValue("msg", out var msgQuery)) return;
|
||||
if (!query.TryGetValue("att", out var attQuery)) return;
|
||||
if (!context.Request.Headers.TryGetValue("secret", out var secret)) return;
|
||||
|
||||
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
||||
string password = await Utils.GetPassword(id);
|
||||
string secretStr = await Utils.NonceDecryptBody(id, password, secret, false);
|
||||
string auth = await Utils.Auth(id, secretStr, password);
|
||||
|
||||
if (auth != Utils.LOGIN_SUCCESS) return; // Don't leak info
|
||||
|
||||
string dmId = dmQuery.ToString();
|
||||
string msgId = msgQuery.ToString();
|
||||
string attId = attQuery.ToString();
|
||||
|
||||
// Check if user is in DM
|
||||
if (!await Room.Requests.IsMemberOfDm(id, dmId)) return;
|
||||
|
||||
string filePath = $"{LarpixServer.Utils.Utils.ROOMS_DIR}/dms/{LarpixServer.Utils.Utils.DOMAIN}/{dmId}/attachments/{msgId}/{attId}";
|
||||
if (!Fs.Exists(filePath))
|
||||
{
|
||||
context.Response.StatusCode = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] fileBytes = await Fs.ReadFile(filePath);
|
||||
context.Response.ContentType = "application/octet-stream";
|
||||
await context.Response.Body.WriteAsync(fileBytes, 0, fileBytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public class CreateHolder
|
||||
|
|
|
|||
|
|
@ -24,6 +24,30 @@ public class Program
|
|||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
string stagingDir = $"{LarpixServer.Utils.Utils.ROOMS_DIR}/dms_staging";
|
||||
if (Directory.Exists(stagingDir))
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(stagingDir))
|
||||
{
|
||||
var fileInfo = new FileInfo(file);
|
||||
var age = DateTime.UtcNow - fileInfo.LastWriteTimeUtc;
|
||||
var remaining = TimeSpan.FromMinutes(10) - age;
|
||||
if (remaining <= TimeSpan.Zero)
|
||||
{
|
||||
Fs.DeleteFile(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(remaining);
|
||||
if (Fs.Exists(file)) Fs.DeleteFile(file);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.UseWebSockets();
|
||||
|
||||
app.Use(async (HttpContext context, Func<Task> next) =>
|
||||
|
|
@ -191,6 +215,12 @@ public class Program
|
|||
case "/_larpix/upload":
|
||||
await Account.Requests.Upload(context, next, query);
|
||||
return;
|
||||
case "/_larpix/dm/attachment/staging":
|
||||
await Account.Requests.UploadDmAttachmentStaging(context, next, query);
|
||||
return;
|
||||
case "/_larpix/dm/attachment/get":
|
||||
await Account.Requests.GetDmAttachment(context, next, query);
|
||||
return;
|
||||
case "/_larpix/federation":
|
||||
await Federation.Receiver.FederationRequest(context, next, query, reader);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public class Requests
|
|||
return true;
|
||||
}
|
||||
|
||||
private static async Task<bool> IsMemberOfDm(string id, string dmId)
|
||||
public static async Task<bool> IsMemberOfDm(string id, string dmId)
|
||||
{
|
||||
if (!IsSafeDmId(dmId)) return false;
|
||||
string memberPath = $"{ROOMS_DIR}/dms/{DOMAIN}/{dmId}/members/{id};{DOMAIN}";
|
||||
|
|
@ -401,6 +401,41 @@ public class Requests
|
|||
msg.responded = responded ?? "";
|
||||
msg.reactions = "";
|
||||
|
||||
if (!string.IsNullOrEmpty(msg.attachment) && msg.attachment != "[]")
|
||||
{
|
||||
try
|
||||
{
|
||||
var attachmentsNode = System.Text.Json.Nodes.JsonNode.Parse(msg.attachment);
|
||||
if (attachmentsNode is System.Text.Json.Nodes.JsonArray arr)
|
||||
{
|
||||
string attDir = $"{ROOMS_DIR}/dms/{DOMAIN}/{dmId}/attachments/{nextId}";
|
||||
if (!Directory.Exists(attDir)) Directory.CreateDirectory(attDir);
|
||||
|
||||
for (int i = 0; i < arr.Count; i++)
|
||||
{
|
||||
var attObj = arr[i] as System.Text.Json.Nodes.JsonObject;
|
||||
if (attObj != null && attObj.ContainsKey("staging_id"))
|
||||
{
|
||||
string stagingId = attObj["staging_id"].ToString();
|
||||
string stagingPath = $"{ROOMS_DIR}/dms_staging/{stagingId}";
|
||||
if (Fs.Exists(stagingPath))
|
||||
{
|
||||
string attId = attObj["id"].ToString();
|
||||
string destPath = $"{attDir}/{attId}";
|
||||
System.IO.File.Move(stagingPath, destPath);
|
||||
}
|
||||
attObj.Remove("staging_id"); // Clean it up before saving
|
||||
}
|
||||
}
|
||||
msg.attachment = attachmentsNode.ToJsonString();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error processing attachments: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
await Fs.WriteFile($"{msgDir}/{nextId}", Encoding.UTF8.GetBytes(JsonSerializer.Serialize(msg, AppJsonSerializerContext.Default.Message)));
|
||||
await Fs.WriteFile($"{msgDir}/last", Encoding.UTF8.GetBytes(nextId.ToString()));
|
||||
|
||||
|
|
|
|||
|
|
@ -315,9 +315,9 @@ public class Utils
|
|||
Directory.CreateDirectory(ROOMS_DIR);
|
||||
}
|
||||
if (!Directory.Exists(ROOMS_DIR + "/dms"))
|
||||
{
|
||||
Directory.CreateDirectory(ROOMS_DIR + "/dms");
|
||||
}
|
||||
if (!Directory.Exists(ROOMS_DIR + "/dms_staging"))
|
||||
Directory.CreateDirectory(ROOMS_DIR + "/dms_staging");
|
||||
if (!Directory.Exists(ROOMS_DIR + "/groups"))
|
||||
{
|
||||
Directory.CreateDirectory(ROOMS_DIR + "/groups");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue