Compare commits

...

2 Commits
master ... hash

Author SHA1 Message Date
cake
dd4cb73b9b Change lightfinder permissions for groups 2025-11-18 00:27:25 +01:00
cake
ab9cdeb682 Upped hashing 2025-11-17 19:37:23 +01:00
5 changed files with 34 additions and 19 deletions

View File

@@ -995,11 +995,11 @@ public partial class LightlessHub
return false; return false;
} }
var (isOwner, _) = await TryValidateOwner(dto.GID).ConfigureAwait(false); var (isOwner, _) = await TryValidateGroupModeratorOrOwner(dto.GID).ConfigureAwait(false);
if (!isOwner) if (!isOwner)
{ {
_logger.LogCallWarning(LightlessHubLogger.Args("Unauthorized syncshell broadcast change", "User", UserUID, "GID", dto.GID)); _logger.LogCallWarning(LightlessHubLogger.Args("Unauthorized syncshell broadcast change", "User", UserUID, "GID", dto.GID));
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "You must be the owner of the syncshell to broadcast it."); await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "You must be the owner or moderator of the syncshell to broadcast it.");
return false; return false;
} }

View File

@@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using StackExchange.Redis; using StackExchange.Redis;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;

View File

@@ -21,6 +21,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" /> <PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="Blake3" Version="2.0.0" />
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8"> <PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -1,4 +1,5 @@
using K4os.Compression.LZ4.Legacy; using Blake3;
using K4os.Compression.LZ4.Legacy;
using LightlessSync.API.Dto.Files; using LightlessSync.API.Dto.Files;
using LightlessSync.API.Routes; using LightlessSync.API.Routes;
using LightlessSync.API.SignalR; using LightlessSync.API.SignalR;
@@ -208,11 +209,14 @@ public class ServerFilesController : ControllerBase
[RequestSizeLimit(200 * 1024 * 1024)] [RequestSizeLimit(200 * 1024 * 1024)]
public async Task<IActionResult> UploadFile(string hash, CancellationToken requestAborted) public async Task<IActionResult> UploadFile(string hash, CancellationToken requestAborted)
{ {
using var dbContext = await _lightlessDbContext.CreateDbContextAsync(); await using var dbContext = await _lightlessDbContext.CreateDbContextAsync();
_logger.LogInformation("{user}|{file}: Uploading", LightlessUser, hash); _logger.LogInformation("{user}|{file}: Uploading", LightlessUser, hash);
if (hash.Length == 40)
{
hash = hash.ToUpperInvariant(); hash = hash.ToUpperInvariant();
}
var existingFile = await dbContext.Files.SingleOrDefaultAsync(f => f.Hash == hash); var existingFile = await dbContext.Files.SingleOrDefaultAsync(f => f.Hash == hash);
if (existingFile != null) return Ok(); if (existingFile != null) return Ok();
@@ -263,10 +267,14 @@ public class ServerFilesController : ControllerBase
[RequestSizeLimit(200 * 1024 * 1024)] [RequestSizeLimit(200 * 1024 * 1024)]
public async Task<IActionResult> UploadFileMunged(string hash, CancellationToken requestAborted) public async Task<IActionResult> UploadFileMunged(string hash, CancellationToken requestAborted)
{ {
using var dbContext = await _lightlessDbContext.CreateDbContextAsync(); await using var dbContext = await _lightlessDbContext.CreateDbContextAsync();
_logger.LogInformation("{user}|{file}: Uploading munged", LightlessUser, hash); _logger.LogInformation("{user}|{file}: Uploading munged", LightlessUser, hash);
if (hash.Length == 40)
{
hash = hash.ToUpperInvariant(); hash = hash.ToUpperInvariant();
}
var existingFile = await dbContext.Files.SingleOrDefaultAsync(f => f.Hash == hash); var existingFile = await dbContext.Files.SingleOrDefaultAsync(f => f.Hash == hash);
if (existingFile != null) return Ok(); if (existingFile != null) return Ok();
@@ -319,20 +327,26 @@ public class ServerFilesController : ControllerBase
private async Task StoreData(string hash, LightlessDbContext dbContext, MemoryStream compressedFileStream) private async Task StoreData(string hash, LightlessDbContext dbContext, MemoryStream compressedFileStream)
{ {
var decompressedData = LZ4Wrapper.Unwrap(compressedFileStream.ToArray()); var decompressedData = LZ4Wrapper.Unwrap(compressedFileStream.ToArray());
// reset streams
compressedFileStream.Seek(0, SeekOrigin.Begin); compressedFileStream.Seek(0, SeekOrigin.Begin);
// compute hash to verify bool valid;
var hashString = BitConverter.ToString(SHA1.HashData(decompressedData))
.Replace("-", "", StringComparison.Ordinal).ToUpperInvariant();
if (!string.Equals(hashString, hash, StringComparison.Ordinal))
throw new InvalidOperationException($"{LightlessUser}|{hash}: Hash does not match file, computed: {hashString}, expected: {hash}");
// save file if (hash.Length == 40)
var path = FilePathUtil.GetFilePath(_basePath, hash); {
using var fileStream = new FileStream(path, FileMode.Create); var sha1Hex = Convert.ToHexString(SHA1.HashData(decompressedData));
await compressedFileStream.CopyToAsync(fileStream).ConfigureAwait(false); valid = string.Equals(sha1Hex, hash, StringComparison.OrdinalIgnoreCase);
_logger.LogDebug("{user}|{file}: Uploaded file saved to {path}", LightlessUser, hash, path); }
else
{
var blakeHash = Hasher.Hash(decompressedData);
var blakeHex = Convert.ToHexString(blakeHash.AsSpan());
valid = string.Equals(blakeHex, hash, StringComparison.OrdinalIgnoreCase);
}
if (!valid)
throw new InvalidOperationException(
$"{LightlessUser}|{hash}: Hash does not match file, computed mismatch."
);
// update on db // update on db
await dbContext.Files.AddAsync(new FileCache() await dbContext.Files.AddAsync(new FileCache()

View File

@@ -18,6 +18,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Blake3" Version="2.0.0" />
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8"> <PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>