UNPKG

sicua

Version:

A tool for analyzing project structure and dependencies

297 lines (296 loc) 10.7 kB
"use strict"; /** * Security context analysis utilities for vulnerability detection */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SecurityContext = void 0; const path = __importStar(require("path")); class SecurityContext { /** * Determine the context of a file for security analysis */ static analyzeFileContext(filePath, content) { const fileType = this.determineFileType(filePath, content); const riskContexts = this.identifyRiskContexts(content, fileType); const handlesSensitiveData = this.detectsSensitiveDataHandling(content); const isClientSide = this.isClientSideFile(filePath, fileType); const hasNetworkAccess = this.detectsNetworkAccess(content); const authLibraries = this.extractAuthLibraries(content); const envVariables = this.extractEnvironmentVariables(content); return { fileType, riskContexts, handlesSensitiveData, isClientSide, hasNetworkAccess, authLibraries, envVariables, }; } /** * Determine the type of file based on path and content */ static determineFileType(filePath, content) { const normalizedPath = path.normalize(filePath).replace(/\\/g, "/"); const fileName = path.basename(filePath); // API routes if (normalizedPath.includes("/api/") || normalizedPath.includes("/pages/api/")) { return "api-route"; } // Middleware if (fileName === "middleware.ts" || fileName === "middleware.js" || normalizedPath.includes("/middleware/")) { return "middleware"; } // Configuration files if (this.isConfigFile(fileName)) { return "config"; } // Environment files if (fileName.startsWith(".env")) { return "environment"; } // Test files if (this.isTestFile(filePath)) { return "test"; } // React components if (this.isReactComponent(content, filePath)) { return "component"; } // Utility files if (normalizedPath.includes("/utils/") || normalizedPath.includes("/lib/") || normalizedPath.includes("/helpers/")) { return "utility"; } return "unknown"; } /** * Identify security risk contexts for the file */ static identifyRiskContexts(content, fileType) { const contexts = []; // Authentication patterns if (this.hasAuthPatterns(content)) { contexts.push("authentication"); } // Authorization patterns if (this.hasAuthorizationPatterns(content)) { contexts.push("authorization"); } // Data processing patterns if (this.hasDataProcessingPatterns(content)) { contexts.push("data-processing"); } // External communication patterns if (this.hasExternalCommunicationPatterns(content)) { contexts.push("external-communication"); } // Configuration management if (fileType === "config" || this.hasConfigPatterns(content)) { contexts.push("configuration"); } // Client vs server side if (this.hasClientSidePatterns(content)) { contexts.push("client-side"); } if (this.hasServerSidePatterns(content)) { contexts.push("server-side"); } return contexts.length > 0 ? contexts : ["none"]; } /** * Check if content suggests sensitive data handling */ static detectsSensitiveDataHandling(content) { // TODO: MOVE TO CONSTANTS const sensitivePatterns = [ /password/i, /secret/i, /token/i, /api[_-]?key/i, /private[_-]?key/i, /credit[_-]?card/i, /ssn/i, /social[_-]?security/i, /personal[_-]?data/i, /pii/i, /encrypt/i, /decrypt/i, /hash/i, /bcrypt/i, /jwt/i, ]; return sensitivePatterns.some((pattern) => pattern.test(content)); } /** * Determine if file is client-side accessible */ static isClientSideFile(filePath, fileType) { const normalizedPath = path.normalize(filePath).replace(/\\/g, "/"); // Client-side file locations if (normalizedPath.includes("/components/") || normalizedPath.includes("/pages/") || normalizedPath.includes("/app/") || normalizedPath.includes("/src/") || normalizedPath.includes("/public/")) { return true; } // File types that are typically client-side if (fileType === "component") { return true; } // Server-side only locations if (normalizedPath.includes("/api/") || normalizedPath.includes("/server/") || fileType === "middleware" || fileType === "config") { return false; } return true; // Default to client-side for unknown files } /** * Check if content indicates network access */ static detectsNetworkAccess(content) { // TODO: MOVE TO CONSTANTS const networkPatterns = [ /fetch\s*\(/, /axios\./, /http\./, /https\./, /XMLHttpRequest/, /websocket/i, /socket\.io/, /request\s*\(/, /got\s*\(/, /superagent/, /node-fetch/, ]; return networkPatterns.some((pattern) => pattern.test(content)); } /** * Extract authentication libraries used */ static extractAuthLibraries(content) { const authLibraries = []; // TODO: MOVE TO CONSTANTS const authPatterns = [ { pattern: /next-auth/i, name: "next-auth" }, { pattern: /\@auth0/i, name: "auth0" }, { pattern: /clerk/i, name: "clerk" }, { pattern: /passport/i, name: "passport" }, { pattern: /jsonwebtoken/i, name: "jsonwebtoken" }, { pattern: /jwt-decode/i, name: "jwt-decode" }, { pattern: /bcrypt/i, name: "bcrypt" }, { pattern: /argon2/i, name: "argon2" }, { pattern: /scrypt/i, name: "scrypt" }, { pattern: /firebase.*auth/i, name: "firebase-auth" }, { pattern: /supabase.*auth/i, name: "supabase-auth" }, ]; for (const { pattern, name } of authPatterns) { if (pattern.test(content)) { authLibraries.push(name); } } return authLibraries; } /** * Extract environment variables accessed in the file */ static extractEnvironmentVariables(content) { const envVars = []; const envPattern = /process\.env\.(\w+)/g; let match; while ((match = envPattern.exec(content)) !== null) { if (!envVars.includes(match[1])) { envVars.push(match[1]); } } return envVars; } /** * Helper methods for pattern detection */ static isConfigFile(fileName) { // TODO: MOVE TO CONSTANTS const configFiles = [ "next.config.js", "next.config.ts", "tailwind.config.js", "tailwind.config.ts", "webpack.config.js", "webpack.config.ts", "vite.config.js", "vite.config.ts", "tsconfig.json", "package.json", ".eslintrc.js", ".eslintrc.json", "babel.config.js", "jest.config.js", ]; return configFiles.includes(fileName); } static isTestFile(filePath) { return (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filePath) || filePath.includes("__tests__") || filePath.includes("/test/") || filePath.includes("/tests/")); } static isReactComponent(content, filePath) { const hasReactImport = /import\s+.*React.*from\s+['"]react['"]/.test(content) || /from\s+['"]react['"]/.test(content); const hasJSX = /<[A-Z]/.test(content) || /jsx/i.test(content); const isComponentFile = /\.(tsx|jsx)$/.test(filePath); return (hasReactImport && hasJSX) || isComponentFile; } static hasAuthPatterns(content) { return /login|logout|signin|signout|authenticate|session|cookie|token|jwt/i.test(content); } static hasAuthorizationPatterns(content) { return /authorize|permission|role|access|acl|rbac|guard|protect/i.test(content); } static hasDataProcessingPatterns(content) { return /JSON\.parse|JSON\.stringify|serialize|deserialize|validate|sanitize|transform/i.test(content); } static hasExternalCommunicationPatterns(content) { return /fetch|axios|http|api|request|webhook|graphql|rest/i.test(content); } static hasConfigPatterns(content) { return /config|settings|environment|env|dotenv/i.test(content); } static hasClientSidePatterns(content) { return /window\.|document\.|localStorage|sessionStorage|location\.|navigator\./i.test(content); } static hasServerSidePatterns(content) { return /process\.|require\(|import.*node:|fs\.|path\.|os\./i.test(content); } } exports.SecurityContext = SecurityContext;