UNPKG

@flamesshield/rules-engine

Version:

Independent rules engine for security analysis of Firebase

117 lines 4.55 kB
/** * PathDiscovery - Utility class for discovering and managing paths from project information * * Extracted from RuleValidator for better code organization and reusability. * Handles discovery of available paths, type mapping, and deprecated path identification. */ export class PathDiscovery { /** * Discovers all available paths, their types, and deprecated paths from project information */ static discoverAll(projectInfo) { const availablePaths = new Set(); const typeMap = new Map(); const deprecatedPaths = PathDiscovery.getDeprecatedPaths(projectInfo); // Add paths from project structure PathDiscovery.addPathsFromObject('', projectInfo, availablePaths, typeMap); return { availablePaths, typeMap, deprecatedPaths }; } /** * Discovers only available paths from project structure */ static discoverPaths(projectInfo) { const availablePaths = new Set(); const typeMap = new Map(); PathDiscovery.addPathsFromObject('', projectInfo, availablePaths, typeMap); return availablePaths; } /** * Gets type information for all discovered paths */ static getPathTypeMap(projectInfo) { const availablePaths = new Set(); const typeMap = new Map(); PathDiscovery.addPathsFromObject('', projectInfo, availablePaths, typeMap); return typeMap; } /** * Identifies deprecated direct access paths */ static getDeprecatedPaths(projectInfo) { const deprecatedPaths = new Set(); // These are direct access properties that should use computed paths instead const deprecatedDirectPaths = [ 'total_apps', 'total_services', 'unenforced_services', 'enforcement_coverage_ratio', 'apps_without_attestation_providers', 'auth_service_unenforced', 'functions_service_unenforced', 'dataconnect_service_unenforced', 'ailogic_service_unenforced', 'google_identity_ios_service_unenforced', 'maps_js_service_unenforced', 'places_api_service_unenforced' ]; for (const path of deprecatedDirectPaths) { if (projectInfo.hasOwnProperty(path)) { deprecatedPaths.add(path); } } return deprecatedPaths; } /** * Recursively adds paths from an object to the available paths set */ static addPathsFromObject(prefix, obj, paths, typeMap, depth = 0) { // Prevent infinite recursion if (depth > 10 || !obj || typeof obj !== 'object') { return; } for (const key in obj) { if (obj.hasOwnProperty(key)) { const fullPath = prefix ? `${prefix}.${key}` : key; const value = obj[key]; paths.add(fullPath); typeMap.set(fullPath, typeof value); // Recursively add nested paths for objects if (value && typeof value === 'object' && !Array.isArray(value)) { PathDiscovery.addPathsFromObject(fullPath, value, paths, typeMap, depth + 1); } } } } /** * Extracts path references from a condition string * Excludes string literals, numbers, and common operators/keywords */ static extractPathsFromCondition(condition) { // Enhanced regex to extract paths, excluding string literals and numbers const pathRegex = /\b([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)\b/g; // Remove string literals first to avoid false positives const conditionWithoutStrings = condition.replace(/"[^"]*"|'[^']*'/g, ''); const matches = conditionWithoutStrings.match(pathRegex) || []; // Filter out operators, literals, and common comparison keywords const skipKeywords = [ 'and', 'or', 'not', 'true', 'false', 'null', 'eq', 'ne', 'gt', 'lt', 'gte', 'lte' ]; return matches.filter(match => { // Skip operators, literals, and common comparison keywords if (skipKeywords.includes(match.toLowerCase())) { return false; } // Skip numeric patterns if (/^\d+(\.\d+)?$/.test(match)) { return false; } return true; }); } } //# sourceMappingURL=path-discovery.js.map