62 lines
1.9 KiB
C#
62 lines
1.9 KiB
C#
using Femto.Modules.Media.Data;
|
|
|
|
namespace Femto.Modules.Media.Infrastructure;
|
|
|
|
internal class FilesystemStorageProvider : IStorageProvider
|
|
{
|
|
private readonly string _storageRoot;
|
|
|
|
public FilesystemStorageProvider(string storageRoot)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(storageRoot))
|
|
throw new ArgumentException(
|
|
"Storage root cannot be null or empty.",
|
|
nameof(storageRoot)
|
|
);
|
|
|
|
this._storageRoot = Path.GetFullPath(storageRoot);
|
|
|
|
if (!Directory.Exists(this._storageRoot))
|
|
{
|
|
Directory.CreateDirectory(this._storageRoot);
|
|
}
|
|
}
|
|
|
|
public async Task SaveBlob(string id, Stream data)
|
|
{
|
|
string filePath = this.GetSafeFilePath(id);
|
|
|
|
// Ensure the directory exists
|
|
Directory.CreateDirectory(Path.GetDirectoryName(filePath)!);
|
|
|
|
await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
|
|
await data.CopyToAsync(fileStream);
|
|
}
|
|
|
|
public async Task<Stream> LoadBlob(string id)
|
|
{
|
|
string filePath = this.GetSafeFilePath(id);
|
|
|
|
if (!File.Exists(filePath))
|
|
throw new FileNotFoundException("The blob with the specified ID was not found.", id);
|
|
|
|
Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
|
|
|
return fileStream;
|
|
}
|
|
|
|
private string GetSafeFilePath(string id)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(id))
|
|
throw new ArgumentException("Blob ID cannot be null or empty.", nameof(id));
|
|
|
|
// Sanitize and validate the path
|
|
string combinedPath = Path.Combine(this._storageRoot, id);
|
|
string fullPath = Path.GetFullPath(combinedPath);
|
|
|
|
if (!fullPath.StartsWith(this._storageRoot, StringComparison.Ordinal))
|
|
throw new UnauthorizedAccessException("Access to the path is denied.");
|
|
|
|
return fullPath;
|
|
}
|
|
}
|