🐛 Fix file management of the site
This commit is contained in:
@@ -23,11 +23,18 @@ public class PublicationSiteManager(
|
|||||||
|
|
||||||
private string GetFullPath(Guid siteId, string relativePath)
|
private string GetFullPath(Guid siteId, string relativePath)
|
||||||
{
|
{
|
||||||
var fullPath = Path.Combine(_basePath, siteId.ToString(), relativePath);
|
// Treat paths starting with separator as relative to site root
|
||||||
var siteDirPath = Path.Combine(_basePath, siteId.ToString());
|
relativePath = relativePath.TrimStart('/', '\\');
|
||||||
return !Path.GetRelativePath(siteDirPath, fullPath).StartsWith('.')
|
string fullPath = Path.Combine(_basePath, siteId.ToString(), relativePath);
|
||||||
? throw new ArgumentException("Invalid path")
|
string normalizedPath = Path.GetFullPath(fullPath);
|
||||||
: fullPath;
|
string siteDirFull = Path.Combine(_basePath, siteId.ToString());
|
||||||
|
string normalizedSiteDir = Path.GetFullPath(siteDirFull);
|
||||||
|
if (!normalizedPath.StartsWith(normalizedSiteDir + Path.DirectorySeparatorChar) &&
|
||||||
|
!normalizedPath.Equals(normalizedSiteDir))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Path escapes site directory");
|
||||||
|
}
|
||||||
|
return normalizedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EnsureSiteDirectory(Guid siteId)
|
private async Task EnsureSiteDirectory(Guid siteId)
|
||||||
@@ -43,11 +50,11 @@ public class PublicationSiteManager(
|
|||||||
public async Task<List<FileEntry>> ListFiles(Guid siteId, string relativePath = "")
|
public async Task<List<FileEntry>> ListFiles(Guid siteId, string relativePath = "")
|
||||||
{
|
{
|
||||||
await EnsureSiteDirectory(siteId);
|
await EnsureSiteDirectory(siteId);
|
||||||
var dir = Path.Combine(_basePath, siteId.ToString(), relativePath);
|
var targetDir = GetFullPath(siteId, relativePath);
|
||||||
if (!Directory.Exists(dir))
|
if (!Directory.Exists(targetDir))
|
||||||
throw new DirectoryNotFoundException("Directory not found");
|
throw new DirectoryNotFoundException("Directory not found");
|
||||||
|
|
||||||
var entries = (from file in Directory.GetFiles(dir)
|
var entries = (from file in Directory.GetFiles(targetDir)
|
||||||
let fileInfo = new FileInfo(file)
|
let fileInfo = new FileInfo(file)
|
||||||
select new FileEntry
|
select new FileEntry
|
||||||
{
|
{
|
||||||
@@ -55,7 +62,7 @@ public class PublicationSiteManager(
|
|||||||
RelativePath = Path.GetRelativePath(Path.Combine(_basePath, siteId.ToString()), file),
|
RelativePath = Path.GetRelativePath(Path.Combine(_basePath, siteId.ToString()), file),
|
||||||
Size = fileInfo.Length, Modified = fileInfo.LastWriteTimeUtc
|
Size = fileInfo.Length, Modified = fileInfo.LastWriteTimeUtc
|
||||||
}).ToList();
|
}).ToList();
|
||||||
entries.AddRange(from subDir in Directory.GetDirectories(dir)
|
entries.AddRange(from subDir in Directory.GetDirectories(targetDir)
|
||||||
let dirInfo = new DirectoryInfo(subDir)
|
let dirInfo = new DirectoryInfo(subDir)
|
||||||
select new FileEntry
|
select new FileEntry
|
||||||
{
|
{
|
||||||
@@ -108,10 +115,9 @@ public class PublicationSiteManager(
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetFullPathForDownload(Guid siteId, string relativePath)
|
public string GetValidatedFullPath(Guid siteId, string relativePath)
|
||||||
{
|
{
|
||||||
// Internal method to get path without throwing if not exists
|
return GetFullPath(siteId, relativePath);
|
||||||
return Path.Combine(_basePath, siteId.ToString(), relativePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateFile(Guid siteId, string relativePath, string newContent)
|
public async Task UpdateFile(Guid siteId, string relativePath, string newContent)
|
||||||
@@ -130,4 +136,4 @@ public class PublicationSiteManager(
|
|||||||
else if (Directory.Exists(fullPath))
|
else if (Directory.Exists(fullPath))
|
||||||
Directory.Delete(fullPath, true);
|
Directory.Delete(fullPath, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,16 @@ public class SiteManagerController(
|
|||||||
var check = await CheckAccess(siteId);
|
var check = await CheckAccess(siteId);
|
||||||
if (check != null) return check;
|
if (check != null) return check;
|
||||||
|
|
||||||
var fullPath = fileManager.GetFullPathForDownload(siteId, relativePath);
|
string fullPath;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fullPath = fileManager.GetValidatedFullPath(siteId, relativePath);
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
return BadRequest("Invalid path");
|
||||||
|
}
|
||||||
|
|
||||||
if (!System.IO.File.Exists(fullPath))
|
if (!System.IO.File.Exists(fullPath))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
@@ -137,23 +146,27 @@ public class SiteManagerController(
|
|||||||
const long maxFileSize = 1048576; // 1MB
|
const long maxFileSize = 1048576; // 1MB
|
||||||
const long maxTotalSize = 26214400; // 25MB
|
const long maxTotalSize = 26214400; // 25MB
|
||||||
|
|
||||||
var fullPath = fileManager.GetFullPathForDownload(siteId, relativePath);
|
|
||||||
long oldSize = 0;
|
|
||||||
if (System.IO.File.Exists(fullPath))
|
|
||||||
oldSize = new FileInfo(fullPath).Length;
|
|
||||||
|
|
||||||
if (request.NewContent.Length > maxFileSize)
|
if (request.NewContent.Length > maxFileSize)
|
||||||
return BadRequest("New content exceeds 1MB limit");
|
return BadRequest("New content exceeds 1MB limit");
|
||||||
|
|
||||||
var currentTotal = await fileManager.GetTotalSiteSize(siteId);
|
long oldSize = 0;
|
||||||
if (currentTotal - oldSize + request.NewContent.Length > maxTotalSize)
|
|
||||||
return BadRequest("Site total size would exceed 25MB limit");
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var fullPath = fileManager.GetValidatedFullPath(siteId, relativePath);
|
||||||
|
if (System.IO.File.Exists(fullPath))
|
||||||
|
oldSize = new FileInfo(fullPath).Length;
|
||||||
|
|
||||||
|
var currentTotal = await fileManager.GetTotalSiteSize(siteId);
|
||||||
|
if (currentTotal - oldSize + request.NewContent.Length > maxTotalSize)
|
||||||
|
return BadRequest("Site total size would exceed 25MB limit");
|
||||||
|
|
||||||
await fileManager.UpdateFile(siteId, relativePath, request.NewContent);
|
await fileManager.UpdateFile(siteId, relativePath, request.NewContent);
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
return BadRequest("Invalid path");
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return BadRequest(ex.Message);
|
return BadRequest(ex.Message);
|
||||||
|
|||||||
Reference in New Issue
Block a user