feat: 添加跨平台运行时、资产系统和UI适配功能 (#256)
* feat(platform-common): 添加WASM加载器和环境检测API * feat(rapier2d): 新增Rapier2D WASM绑定包 * feat(physics-rapier2d): 添加跨平台WASM加载器 * feat(asset-system): 添加运行时资产目录和bundle格式 * feat(asset-system-editor): 新增编辑器资产管理包 * feat(editor-core): 添加构建系统和模块管理 * feat(editor-app): 重构浏览器预览使用import maps * feat(platform-web): 添加BrowserRuntime和资产读取 * feat(engine): 添加材质系统和着色器管理 * feat(material): 新增材质系统和着色器编辑器 * feat(tilemap): 增强tilemap编辑器和动画系统 * feat(modules): 添加module.json配置 * feat(core): 添加module.json和类型定义更新 * chore: 更新依赖和构建配置 * refactor(plugins): 更新插件模板使用ModuleManifest * chore: 添加第三方依赖库 * chore: 移除BehaviourTree-ai和ecs-astar子模块 * docs: 更新README和文档主题样式 * fix: 修复Rust文档测试和添加rapier2d WASM绑定 * fix(tilemap-editor): 修复画布高DPI屏幕分辨率适配问题 * feat(ui): 添加UI屏幕适配系统(CanvasScaler/SafeArea) * fix(ecs-engine-bindgen): 添加缺失的ecs-framework-math依赖 * fix: 添加缺失的包依赖修复CI构建 * fix: 修复CodeQL检测到的代码问题 * fix: 修复构建错误和缺失依赖 * fix: 修复类型检查错误 * fix(material-system): 修复tsconfig配置支持TypeScript项目引用 * fix(editor-core): 修复Rollup构建配置添加tauri external * fix: 修复CodeQL检测到的代码问题 * fix: 修复CodeQL检测到的代码问题
This commit is contained in:
@@ -6,29 +6,77 @@
|
||||
* 验证并清理资产路径以确保安全
|
||||
*/
|
||||
|
||||
/**
|
||||
* Path validation options.
|
||||
* 路径验证选项。
|
||||
*/
|
||||
export interface PathValidationOptions {
|
||||
/** Allow absolute paths (for editor environment). | 允许绝对路径(用于编辑器环境)。 */
|
||||
allowAbsolutePaths?: boolean;
|
||||
/** Allow URLs (http://, https://, asset://). | 允许 URL。 */
|
||||
allowUrls?: boolean;
|
||||
}
|
||||
|
||||
export class PathValidator {
|
||||
// Dangerous path patterns
|
||||
private static readonly DANGEROUS_PATTERNS = [
|
||||
// Dangerous path patterns (without absolute path checks)
|
||||
private static readonly DANGEROUS_PATTERNS_STRICT = [
|
||||
/\.\.[/\\]/g, // Path traversal attempts (..)
|
||||
/^[/\\]/, // Absolute paths on Unix
|
||||
/^[a-zA-Z]:[/\\]/, // Absolute paths on Windows
|
||||
/[<>:"|?*]/, // Invalid characters for Windows paths
|
||||
/\0/, // Null bytes
|
||||
/%00/, // URL encoded null bytes
|
||||
/\.\.%2[fF]/ // URL encoded path traversal
|
||||
];
|
||||
|
||||
// Valid path characters (alphanumeric, dash, underscore, dot, slash)
|
||||
// Dangerous path patterns (allowing absolute paths)
|
||||
private static readonly DANGEROUS_PATTERNS_RELAXED = [
|
||||
/\.\.[/\\]/g, // Path traversal attempts (..)
|
||||
/\0/, // Null bytes
|
||||
/%00/, // URL encoded null bytes
|
||||
/\.\.%2[fF]/ // URL encoded path traversal
|
||||
];
|
||||
|
||||
// Valid path characters for relative paths (alphanumeric, dash, underscore, dot, slash)
|
||||
private static readonly VALID_PATH_REGEX = /^[a-zA-Z0-9\-_./\\@]+$/;
|
||||
|
||||
// Valid path characters for absolute paths (includes colon for Windows drives)
|
||||
private static readonly VALID_ABSOLUTE_PATH_REGEX = /^[a-zA-Z0-9\-_./\\@:]+$/;
|
||||
|
||||
// URL pattern
|
||||
private static readonly URL_REGEX = /^(https?|asset|blob|data):\/\//;
|
||||
|
||||
// Maximum path length
|
||||
private static readonly MAX_PATH_LENGTH = 260;
|
||||
private static readonly MAX_PATH_LENGTH = 1024;
|
||||
|
||||
/** Global options for path validation. | 路径验证的全局选项。 */
|
||||
private static _globalOptions: PathValidationOptions = {
|
||||
allowAbsolutePaths: false,
|
||||
allowUrls: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Set global validation options.
|
||||
* 设置全局验证选项。
|
||||
*/
|
||||
static setGlobalOptions(options: PathValidationOptions): void {
|
||||
this._globalOptions = { ...this._globalOptions, ...options };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current global options.
|
||||
* 获取当前全局选项。
|
||||
*/
|
||||
static getGlobalOptions(): PathValidationOptions {
|
||||
return { ...this._globalOptions };
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate if a path is safe
|
||||
* 验证路径是否安全
|
||||
*/
|
||||
static validate(path: string): { valid: boolean; reason?: string } {
|
||||
static validate(path: string, options?: PathValidationOptions): { valid: boolean; reason?: string } {
|
||||
const opts = { ...this._globalOptions, ...options };
|
||||
|
||||
// Check for null/undefined/empty
|
||||
if (!path || typeof path !== 'string') {
|
||||
return { valid: false, reason: 'Path is empty or invalid' };
|
||||
@@ -39,15 +87,29 @@ export class PathValidator {
|
||||
return { valid: false, reason: `Path exceeds maximum length of ${this.MAX_PATH_LENGTH} characters` };
|
||||
}
|
||||
|
||||
// Allow URLs if enabled
|
||||
if (opts.allowUrls && this.URL_REGEX.test(path)) {
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
// Choose patterns based on options
|
||||
const patterns = opts.allowAbsolutePaths
|
||||
? this.DANGEROUS_PATTERNS_RELAXED
|
||||
: this.DANGEROUS_PATTERNS_STRICT;
|
||||
|
||||
// Check for dangerous patterns
|
||||
for (const pattern of this.DANGEROUS_PATTERNS) {
|
||||
for (const pattern of patterns) {
|
||||
if (pattern.test(path)) {
|
||||
return { valid: false, reason: 'Path contains dangerous pattern' };
|
||||
}
|
||||
}
|
||||
|
||||
// Check for valid characters
|
||||
if (!this.VALID_PATH_REGEX.test(path)) {
|
||||
const validCharsRegex = opts.allowAbsolutePaths
|
||||
? this.VALID_ABSOLUTE_PATH_REGEX
|
||||
: this.VALID_PATH_REGEX;
|
||||
|
||||
if (!validCharsRegex.test(path)) {
|
||||
return { valid: false, reason: 'Path contains invalid characters' };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user