sicua
Version:
A tool for analyzing project structure and dependencies
297 lines (296 loc) • 10.7 kB
JavaScript
;
/**
* 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;