From b7ce079a261ff442e2537d8045ea8b4398792cb5 Mon Sep 17 00:00:00 2001 From: Aiden Date: Mon, 1 Jun 2026 06:52:56 -0400 Subject: [PATCH] Fixed duplication --- CMakeLists.txt | 1 + src/app/ShaderRuntimeContentController.cpp | 86 ++----------------- src/shader/ShaderManifestParser.cpp | 55 +++---------- src/shader/ShaderUiPath.cpp | 96 ++++++++++++++++++++++ src/shader/ShaderUiPath.h | 14 ++++ 5 files changed, 128 insertions(+), 124 deletions(-) create mode 100644 src/shader/ShaderUiPath.cpp create mode 100644 src/shader/ShaderUiPath.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 489ce6b..9f9916d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,7 @@ set(SHADER_MANIFEST_SOURCES "${SRC_DIR}/shader/ShaderManifestParameters.cpp" "${SRC_DIR}/shader/ShaderManifestParser.cpp" "${SRC_DIR}/shader/ShaderPackageRegistry.cpp" + "${SRC_DIR}/shader/ShaderUiPath.cpp" ) set(VIDEO_MODE_SOURCES diff --git a/src/app/ShaderRuntimeContentController.cpp b/src/app/ShaderRuntimeContentController.cpp index 63772a4..493a7a8 100644 --- a/src/app/ShaderRuntimeContentController.cpp +++ b/src/app/ShaderRuntimeContentController.cpp @@ -2,73 +2,12 @@ #include "../control/RuntimeControlCommand.h" #include "../control/RuntimeStateJson.h" +#include "../shader/ShaderUiPath.h" #include namespace RenderCadenceCompositor { -namespace -{ -bool IsSafeShaderAssetPath(const std::string& assetPath, std::filesystem::path& normalizedPath) -{ - if (assetPath.empty() || assetPath.find('\\') != std::string::npos || - assetPath.find(':') != std::string::npos || assetPath.find('?') != std::string::npos || - assetPath.find('#') != std::string::npos) - return false; - - const std::filesystem::path path(assetPath); - if (path.empty() || path.is_absolute()) - return false; - - bool firstPart = true; - bool startsInUiDirectory = false; - for (const std::filesystem::path& part : path) - { - if (part.empty() || part == "." || part == "..") - return false; - if (firstPart) - { - startsInUiDirectory = part == "ui"; - firstPart = false; - } - } - if (!startsInUiDirectory) - return false; - - normalizedPath = path.lexically_normal(); - if (normalizedPath.empty() || normalizedPath.is_absolute()) - return false; - for (const std::filesystem::path& part : normalizedPath) - { - if (part.empty() || part == "." || part == "..") - return false; - } - return true; -} - -bool IsPathUnderRoot(const std::filesystem::path& root, const std::filesystem::path& path) -{ - std::error_code errorCode; - const std::filesystem::path canonicalRoot = std::filesystem::weakly_canonical(root, errorCode); - if (errorCode) - return false; - - const std::filesystem::path canonicalPath = std::filesystem::weakly_canonical(path, errorCode); - if (errorCode) - return false; - - const std::filesystem::path relative = canonicalPath.lexically_relative(canonicalRoot); - if (relative.empty() || relative.is_absolute()) - return false; - for (const std::filesystem::path& part : relative) - { - if (part == "..") - return false; - } - return true; -} -} - ShaderRuntimeContentController::ShaderRuntimeContentController(RenderLayerPublisher publisher) : mRuntimeLayers(std::move(publisher)) { @@ -145,26 +84,15 @@ bool ShaderRuntimeContentController::ResolveAssetPath( return false; } - std::filesystem::path normalizedPath; - if (!IsSafeShaderAssetPath(assetPath, normalizedPath)) + if (!ShaderUiPath::ResolveAssetPath(shaderPackage->directoryPath, assetPath, resolvedPath)) { - error = "Shader asset path is not safe."; + std::filesystem::path normalizedPath; + if (!ShaderUiPath::NormalizeAssetPath(assetPath, normalizedPath)) + error = "Shader asset path is not safe."; + else + error = "Shader asset was not found."; return false; } - - const std::filesystem::path candidatePath = shaderPackage->directoryPath / normalizedPath; - if (!IsPathUnderRoot(shaderPackage->directoryPath, candidatePath)) - { - error = "Shader asset path escaped the package directory."; - return false; - } - if (!std::filesystem::exists(candidatePath) || !std::filesystem::is_regular_file(candidatePath)) - { - error = "Shader asset was not found."; - return false; - } - - resolvedPath = candidatePath; return true; } } diff --git a/src/shader/ShaderManifestParser.cpp b/src/shader/ShaderManifestParser.cpp index 42376ff..643fce3 100644 --- a/src/shader/ShaderManifestParser.cpp +++ b/src/shader/ShaderManifestParser.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "ShaderManifestParser.h" +#include "ShaderUiPath.h" + #include #include #include @@ -47,46 +49,6 @@ bool ParseTemporalHistorySource(const std::string& sourceName, TemporalHistorySo return false; } -bool IsSafeUiEntryPath(const std::string& entryPath) -{ - if (Trim(entryPath).empty()) - return false; - if (entryPath.find('\\') != std::string::npos || entryPath.find(':') != std::string::npos || - entryPath.find('?') != std::string::npos || entryPath.find('#') != std::string::npos) - return false; - - const std::filesystem::path path(entryPath); - if (path.empty() || path.is_absolute()) - return false; - - bool firstPart = true; - bool startsInUiDirectory = false; - for (const std::filesystem::path& part : path) - { - if (part.empty() || part == "." || part == "..") - return false; - if (firstPart) - { - startsInUiDirectory = part == "ui"; - firstPart = false; - } - } - if (!startsInUiDirectory) - return false; - - const std::filesystem::path normalized = path.lexically_normal(); - if (normalized.empty() || normalized.is_absolute()) - return false; - for (const std::filesystem::path& part : normalized) - { - if (part.empty() || part == "." || part == "..") - return false; - } - - const std::string extension = normalized.extension().string(); - return extension == ".js" || extension == ".mjs"; -} - bool IsValidCustomElementTag(const std::string& tag) { if (tag.empty() || tag.find('-') == std::string::npos || tag.front() == '-' || tag.back() == '-') @@ -450,7 +412,9 @@ bool ParseUiDefinition(const JsonValue& manifestJson, ShaderPackage& shaderPacka error = "Shader UI type must be 'webComponent' in: " + ManifestPathMessage(manifestPath); return false; } - if (!IsSafeUiEntryPath(ui.entryPath)) + std::filesystem::path normalizedEntryPath; + if (!ShaderUiPath::NormalizeAssetPath(ui.entryPath, normalizedEntryPath) || + !ShaderUiPath::IsModulePath(normalizedEntryPath)) { error = "Shader UI entry must be a safe relative .js or .mjs path under ui/ in: " + ManifestPathMessage(manifestPath); return false; @@ -461,14 +425,15 @@ bool ParseUiDefinition(const JsonValue& manifestJson, ShaderPackage& shaderPacka return false; } - const std::filesystem::path entryPath = shaderPackage.directoryPath / std::filesystem::path(ui.entryPath); - if (!std::filesystem::exists(entryPath)) + std::filesystem::path entryPath; + if (!ShaderUiPath::ResolveAssetPath(shaderPackage.directoryPath, ui.entryPath, entryPath)) { - error = "Shader UI entry not found for package " + shaderPackage.id + ": " + entryPath.string(); + error = "Shader UI entry not found for package " + shaderPackage.id + ": " + + (shaderPackage.directoryPath / normalizedEntryPath).string(); return false; } - ui.entryPath = std::filesystem::path(ui.entryPath).lexically_normal().generic_string(); + ui.entryPath = normalizedEntryPath.generic_string(); ui.enabled = true; shaderPackage.ui = ui; return true; diff --git a/src/shader/ShaderUiPath.cpp b/src/shader/ShaderUiPath.cpp new file mode 100644 index 0000000..b634a1d --- /dev/null +++ b/src/shader/ShaderUiPath.cpp @@ -0,0 +1,96 @@ +#include "stdafx.h" +#include "ShaderUiPath.h" + +namespace ShaderUiPath +{ +namespace +{ +bool IsPathUnderRoot(const std::filesystem::path& root, const std::filesystem::path& path) +{ + std::error_code errorCode; + const std::filesystem::path canonicalRoot = std::filesystem::weakly_canonical(root, errorCode); + if (errorCode) + return false; + + const std::filesystem::path canonicalPath = std::filesystem::weakly_canonical(path, errorCode); + if (errorCode) + return false; + + const std::filesystem::path relative = canonicalPath.lexically_relative(canonicalRoot); + if (relative.empty() || relative.is_absolute()) + return false; + for (const std::filesystem::path& part : relative) + { + if (part == "..") + return false; + } + return true; +} +} + +bool NormalizeAssetPath(const std::string& assetPath, std::filesystem::path& normalizedPath) +{ + normalizedPath.clear(); + if (assetPath.empty() || assetPath.find('\\') != std::string::npos || + assetPath.find(':') != std::string::npos || assetPath.find('?') != std::string::npos || + assetPath.find('#') != std::string::npos) + { + return false; + } + + const std::filesystem::path path(assetPath); + if (path.empty() || path.is_absolute()) + return false; + + bool firstPart = true; + bool startsInUiDirectory = false; + for (const std::filesystem::path& part : path) + { + if (part.empty() || part == "." || part == "..") + return false; + if (firstPart) + { + startsInUiDirectory = part == "ui"; + firstPart = false; + } + } + if (!startsInUiDirectory) + return false; + + normalizedPath = path.lexically_normal(); + if (normalizedPath.empty() || normalizedPath.is_absolute()) + return false; + for (const std::filesystem::path& part : normalizedPath) + { + if (part.empty() || part == "." || part == "..") + return false; + } + return true; +} + +bool IsModulePath(const std::filesystem::path& normalizedPath) +{ + const std::string extension = normalizedPath.extension().string(); + return extension == ".js" || extension == ".mjs"; +} + +bool ResolveAssetPath( + const std::filesystem::path& packageRoot, + const std::string& assetPath, + std::filesystem::path& resolvedPath) +{ + resolvedPath.clear(); + std::filesystem::path normalizedPath; + if (!NormalizeAssetPath(assetPath, normalizedPath)) + return false; + + const std::filesystem::path candidatePath = packageRoot / normalizedPath; + if (!IsPathUnderRoot(packageRoot, candidatePath)) + return false; + if (!std::filesystem::exists(candidatePath) || !std::filesystem::is_regular_file(candidatePath)) + return false; + + resolvedPath = candidatePath; + return true; +} +} diff --git a/src/shader/ShaderUiPath.h b/src/shader/ShaderUiPath.h new file mode 100644 index 0000000..049f4a1 --- /dev/null +++ b/src/shader/ShaderUiPath.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +namespace ShaderUiPath +{ +bool NormalizeAssetPath(const std::string& assetPath, std::filesystem::path& normalizedPath); +bool IsModulePath(const std::filesystem::path& normalizedPath); +bool ResolveAssetPath( + const std::filesystem::path& packageRoot, + const std::string& assetPath, + std::filesystem::path& resolvedPath); +}