diff --git a/DysonNetwork.Zone/Publication/PublicationSiteManager.cs b/DysonNetwork.Zone/Publication/PublicationSiteManager.cs index 2d52130..aec41c7 100644 --- a/DysonNetwork.Zone/Publication/PublicationSiteManager.cs +++ b/DysonNetwork.Zone/Publication/PublicationSiteManager.cs @@ -23,11 +23,18 @@ public class PublicationSiteManager( private string GetFullPath(Guid siteId, string relativePath) { - var fullPath = Path.Combine(_basePath, siteId.ToString(), relativePath); - var siteDirPath = Path.Combine(_basePath, siteId.ToString()); - return !Path.GetRelativePath(siteDirPath, fullPath).StartsWith('.') - ? throw new ArgumentException("Invalid path") - : fullPath; + // Treat paths starting with separator as relative to site root + relativePath = relativePath.TrimStart('/', '\\'); + string fullPath = Path.Combine(_basePath, siteId.ToString(), relativePath); + string normalizedPath = Path.GetFullPath(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) @@ -43,11 +50,11 @@ public class PublicationSiteManager( public async Task> ListFiles(Guid siteId, string relativePath = "") { await EnsureSiteDirectory(siteId); - var dir = Path.Combine(_basePath, siteId.ToString(), relativePath); - if (!Directory.Exists(dir)) + var targetDir = GetFullPath(siteId, relativePath); + if (!Directory.Exists(targetDir)) 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) select new FileEntry { @@ -55,7 +62,7 @@ public class PublicationSiteManager( RelativePath = Path.GetRelativePath(Path.Combine(_basePath, siteId.ToString()), file), Size = fileInfo.Length, Modified = fileInfo.LastWriteTimeUtc }).ToList(); - entries.AddRange(from subDir in Directory.GetDirectories(dir) + entries.AddRange(from subDir in Directory.GetDirectories(targetDir) let dirInfo = new DirectoryInfo(subDir) select new FileEntry { @@ -108,10 +115,9 @@ public class PublicationSiteManager( 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 Path.Combine(_basePath, siteId.ToString(), relativePath); + return GetFullPath(siteId, relativePath); } public async Task UpdateFile(Guid siteId, string relativePath, string newContent) @@ -130,4 +136,4 @@ public class PublicationSiteManager( else if (Directory.Exists(fullPath)) Directory.Delete(fullPath, true); } -} \ No newline at end of file +} diff --git a/DysonNetwork.Zone/Publication/SiteManagerController.cs b/DysonNetwork.Zone/Publication/SiteManagerController.cs index f2a9f7c..a2583e6 100644 --- a/DysonNetwork.Zone/Publication/SiteManagerController.cs +++ b/DysonNetwork.Zone/Publication/SiteManagerController.cs @@ -111,7 +111,16 @@ public class SiteManagerController( var check = await CheckAccess(siteId); 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)) return NotFound(); @@ -137,23 +146,27 @@ public class SiteManagerController( const long maxFileSize = 1048576; // 1MB 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) return BadRequest("New content exceeds 1MB limit"); - var currentTotal = await fileManager.GetTotalSiteSize(siteId); - if (currentTotal - oldSize + request.NewContent.Length > maxTotalSize) - return BadRequest("Site total size would exceed 25MB limit"); - + long oldSize = 0; 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); return Ok(); } + catch (ArgumentException) + { + return BadRequest("Invalid path"); + } catch (Exception ex) { return BadRequest(ex.Message);