Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions web/Areas/CMS/Data/CMS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,31 @@ public bool CheckFilePermission(CMSFile file)

if (_rapsContext! != null && currentUser != null)
{
if (file.AllowPublicAccess ||
(file.FileToPermissions.Count == 0 && UserHelper.HasPermission(_rapsContext, currentUser, "SVMSecure")) ||
(file.FileToPermissions.Count > 0 && file.FileToPermissions.Any(fp => UserHelper.GetAllPermissions(_rapsContext, currentUser).Any(p => string.Compare(fp.Permission, p.Permission, true) == 0))) ||
(file.FileToPeople.Count > 0 && file.FileToPeople.Any(fp => fp.IamId == currentUser.IamId)))
// Each access path returns early so later (more expensive) checks are
// skipped once access is granted, preserving the original short-circuit.
if (file.AllowPublicAccess)
{
return true;
}
// No explicit permissions: any authenticated SVMSecure user may access.
if (file.FileToPermissions.Count == 0 && UserHelper.HasPermission(_rapsContext, currentUser, "SVMSecure"))
{
return true;
}
// Explicit permissions: the user must hold a matching one. Resolve the user's
// permissions once into a set rather than re-querying for each file permission.
if (file.FileToPermissions.Count > 0)
{
var userPermissions = UserHelper.GetAllPermissions(_rapsContext, currentUser)
.Select(p => p.Permission)
.ToHashSet(StringComparer.OrdinalIgnoreCase);
if (file.FileToPermissions.Any(fp => userPermissions.Contains(fp.Permission)))
{
return true;
}
}
// Explicit people: the user must be listed.
if (file.FileToPeople.Count > 0 && file.FileToPeople.Any(fp => fp.IamId == currentUser.IamId))
{
return true;
}
Expand Down
18 changes: 13 additions & 5 deletions web/ViteProxyHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,12 @@ public static HttpRequestMessage CreateProxyRequest(HttpContext context, string
var requestMessage = new HttpRequestMessage(new HttpMethod(context.Request.Method), targetUrl);

// Only copy request body for methods that typically support it
var method = context.Request.Method.ToUpperInvariant();
if (method != "GET" && method != "HEAD"
&& ((context.Request.ContentLength.HasValue && context.Request.ContentLength > 0) ||
(!context.Request.ContentLength.HasValue && context.Request.Body.CanRead)))
var requestMethod = context.Request.Method;
bool methodSupportsBody = !string.Equals(requestMethod, "GET", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(requestMethod, "HEAD", StringComparison.OrdinalIgnoreCase);
bool hasReadableBody = (context.Request.ContentLength.HasValue && context.Request.ContentLength > 0)
|| (!context.Request.ContentLength.HasValue && context.Request.Body.CanRead);
if (methodSupportsBody && hasReadableBody)
{
requestMessage.Content = new StreamContent(context.Request.Body);

Expand Down Expand Up @@ -348,10 +350,16 @@ public static async Task HandleProxyError(HttpContext context, Exception ex, ILo
var physicalPath = Path.Join(context.RequestServices.GetRequiredService<IWebHostEnvironment>().WebRootPath,
staticPath.TrimStart('/').Replace('/', Path.DirectorySeparatorChar));

// Prevent directory traversal: ensure the resolved physical path is within WebRootPath
// Prevent directory traversal: ensure the resolved physical path is within WebRootPath.
// A trailing separator makes the StartsWith check respect the directory boundary so a
// sibling like "wwwroot-secret" cannot satisfy the prefix check against "wwwroot".
var webRoot = context.RequestServices.GetRequiredService<IWebHostEnvironment>().WebRootPath;
var resolvedPhysical = Path.GetFullPath(physicalPath);
var resolvedWebRoot = Path.GetFullPath(webRoot);
if (!Path.EndsInDirectorySeparator(resolvedWebRoot))
{
resolvedWebRoot += Path.DirectorySeparatorChar;
}

if (!resolvedPhysical.StartsWith(resolvedWebRoot, StringComparison.OrdinalIgnoreCase))
{
Expand Down
Loading