@havoc-security/scanner 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +22 -0
- package/dist/analyzers/AuthorizationCoverageAnalyzer.d.ts +7 -0
- package/dist/analyzers/AuthorizationCoverageAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/AuthorizationCoverageAnalyzer.js +100 -0
- package/dist/analyzers/AuthorizationCoverageAnalyzer.js.map +1 -0
- package/dist/analyzers/CredentialExposureAnalyzer.d.ts +11 -0
- package/dist/analyzers/CredentialExposureAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/CredentialExposureAnalyzer.js +262 -0
- package/dist/analyzers/CredentialExposureAnalyzer.js.map +1 -0
- package/dist/analyzers/DependencyAuditAnalyzer.d.ts +28 -0
- package/dist/analyzers/DependencyAuditAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/DependencyAuditAnalyzer.js +107 -0
- package/dist/analyzers/DependencyAuditAnalyzer.js.map +1 -0
- package/dist/analyzers/EncryptionAnalyzer.d.ts +7 -0
- package/dist/analyzers/EncryptionAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/EncryptionAnalyzer.js +170 -0
- package/dist/analyzers/EncryptionAnalyzer.js.map +1 -0
- package/dist/analyzers/FileUploadAnalyzer.d.ts +8 -0
- package/dist/analyzers/FileUploadAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/FileUploadAnalyzer.js +193 -0
- package/dist/analyzers/FileUploadAnalyzer.js.map +1 -0
- package/dist/analyzers/IdorAnalyzer.d.ts +7 -0
- package/dist/analyzers/IdorAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/IdorAnalyzer.js +91 -0
- package/dist/analyzers/IdorAnalyzer.js.map +1 -0
- package/dist/analyzers/MassAssignmentAnalyzer.d.ts +7 -0
- package/dist/analyzers/MassAssignmentAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/MassAssignmentAnalyzer.js +90 -0
- package/dist/analyzers/MassAssignmentAnalyzer.js.map +1 -0
- package/dist/analyzers/PrivilegeEscalationAnalyzer.d.ts +7 -0
- package/dist/analyzers/PrivilegeEscalationAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/PrivilegeEscalationAnalyzer.js +217 -0
- package/dist/analyzers/PrivilegeEscalationAnalyzer.js.map +1 -0
- package/dist/analyzers/RateLimitAnalyzer.d.ts +7 -0
- package/dist/analyzers/RateLimitAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/RateLimitAnalyzer.js +151 -0
- package/dist/analyzers/RateLimitAnalyzer.js.map +1 -0
- package/dist/analyzers/SessionSecurityAnalyzer.d.ts +10 -0
- package/dist/analyzers/SessionSecurityAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/SessionSecurityAnalyzer.js +295 -0
- package/dist/analyzers/SessionSecurityAnalyzer.js.map +1 -0
- package/dist/analyzers/SqlInjectionAnalyzer.d.ts +7 -0
- package/dist/analyzers/SqlInjectionAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/SqlInjectionAnalyzer.js +77 -0
- package/dist/analyzers/SqlInjectionAnalyzer.js.map +1 -0
- package/dist/analyzers/XssSurfaceAnalyzer.d.ts +7 -0
- package/dist/analyzers/XssSurfaceAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/XssSurfaceAnalyzer.js +100 -0
- package/dist/analyzers/XssSurfaceAnalyzer.js.map +1 -0
- package/dist/analyzers/index.d.ts +13 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +13 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +139 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/PhpParser.d.ts +56 -0
- package/dist/parsers/PhpParser.d.ts.map +1 -0
- package/dist/parsers/PhpParser.js +193 -0
- package/dist/parsers/PhpParser.js.map +1 -0
- package/dist/parsers/RouteParser.d.ts +87 -0
- package/dist/parsers/RouteParser.d.ts.map +1 -0
- package/dist/parsers/RouteParser.js +327 -0
- package/dist/parsers/RouteParser.js.map +1 -0
- package/dist/rules/index.d.ts +14 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +9 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/types/index.d.ts +137 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +13 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +30 -0
- package/package.json.bak +27 -0
- package/src/analyzers/AuthorizationCoverageAnalyzer.ts +213 -0
- package/src/analyzers/CredentialExposureAnalyzer.ts +312 -0
- package/src/analyzers/DependencyAuditAnalyzer.ts +135 -0
- package/src/analyzers/EncryptionAnalyzer.ts +195 -0
- package/src/analyzers/FileUploadAnalyzer.ts +239 -0
- package/src/analyzers/IdorAnalyzer.ts +118 -0
- package/src/analyzers/InsecureDeserializationAnalyzer.ts +212 -0
- package/src/analyzers/MassAssignmentAnalyzer.ts +105 -0
- package/src/analyzers/OpenRedirectAnalyzer.ts +149 -0
- package/src/analyzers/PrivilegeEscalationAnalyzer.ts +258 -0
- package/src/analyzers/RateLimitAnalyzer.ts +195 -0
- package/src/analyzers/SecurityHeaderAnalyzer.ts +263 -0
- package/src/analyzers/SessionSecurityAnalyzer.ts +342 -0
- package/src/analyzers/SqlInjectionAnalyzer.ts +99 -0
- package/src/analyzers/XssSurfaceAnalyzer.ts +112 -0
- package/src/analyzers/exclusions.ts +87 -0
- package/src/analyzers/index.ts +15 -0
- package/src/index.ts +226 -0
- package/src/parsers/PhpParser.ts +259 -0
- package/src/parsers/RouteParser.ts +384 -0
- package/src/rules/index.ts +16 -0
- package/src/types/index.ts +164 -0
- package/tests/EncryptionAnalyzer.test.ts +137 -0
- package/tests/PrivilegeEscalationAnalyzer.test.ts +141 -0
- package/tests/RateLimitAnalyzer.test.ts +112 -0
- package/tests/analyzers.test.ts +678 -0
- package/tests/auth-coverage-route-aware.test.ts +294 -0
- package/tests/credential-exposure.test.ts +142 -0
- package/tests/file-upload.test.ts +141 -0
- package/tests/fixtures/app/Http/Controllers/AdminController.php +19 -0
- package/tests/fixtures/app/Http/Controllers/PostController.php +49 -0
- package/tests/fixtures/app/Http/Controllers/PublicController.php +17 -0
- package/tests/fixtures/app/Models/Comment.php +11 -0
- package/tests/fixtures/app/Models/OpenModel.php +11 -0
- package/tests/fixtures/app/Models/Post.php +14 -0
- package/tests/fixtures/app/Models/SafeModel.php +10 -0
- package/tests/fixtures/app/Models/User.php +15 -0
- package/tests/fixtures/blade/mail.blade.php +8 -0
- package/tests/fixtures/blade/safe.blade.php +12 -0
- package/tests/fixtures/blade/vulnerable.blade.php +12 -0
- package/tests/fixtures/controllers/AdminController.php +19 -0
- package/tests/fixtures/controllers/PostController.php +49 -0
- package/tests/fixtures/controllers/PublicController.php +17 -0
- package/tests/fixtures/deserialization/safe.php +32 -0
- package/tests/fixtures/deserialization/unsafe.php +60 -0
- package/tests/fixtures/models/Comment.php +11 -0
- package/tests/fixtures/models/OpenModel.php +11 -0
- package/tests/fixtures/models/Post.php +14 -0
- package/tests/fixtures/models/SafeModel.php +10 -0
- package/tests/fixtures/models/User.php +15 -0
- package/tests/fixtures/redirect/safe.php +38 -0
- package/tests/fixtures/redirect/unsafe.php +39 -0
- package/tests/fixtures/routes/api.php +9 -0
- package/tests/fixtures/routes/web.php +18 -0
- package/tests/fixtures/security-headers/app/Http/Middleware/SecurityHeaders.php +24 -0
- package/tests/fixtures/security-headers/app/Providers/AppServiceProvider.php +16 -0
- package/tests/fixtures/sql/safe_queries.php +7 -0
- package/tests/fixtures/sql/vulnerable_queries.php +7 -0
- package/tests/new-analyzers.test.ts +373 -0
- package/tests/route-parser.test.ts +257 -0
- package/tests/scanner.test.ts +82 -0
- package/tests/session-security.test.ts +161 -0
- package/tests/types.test.ts +29 -0
- package/tsconfig.json +9 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
export * from './types/index.js';
|
|
2
|
+
export * from './analyzers/index.js';
|
|
3
|
+
export { PhpParser, PHP_FILE_PATTERNS } from './parsers/PhpParser.js';
|
|
4
|
+
export { rules } from './rules/index.js';
|
|
5
|
+
import { readFile } from 'node:fs/promises';
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { resolve, join } from 'node:path';
|
|
8
|
+
import { glob } from 'glob';
|
|
9
|
+
import { Severity } from './types/index.js';
|
|
10
|
+
import { AuthorizationCoverageAnalyzer } from './analyzers/AuthorizationCoverageAnalyzer.js';
|
|
11
|
+
import { MassAssignmentAnalyzer } from './analyzers/MassAssignmentAnalyzer.js';
|
|
12
|
+
import { XssSurfaceAnalyzer } from './analyzers/XssSurfaceAnalyzer.js';
|
|
13
|
+
import { SqlInjectionAnalyzer } from './analyzers/SqlInjectionAnalyzer.js';
|
|
14
|
+
import { DependencyAuditAnalyzer } from './analyzers/DependencyAuditAnalyzer.js';
|
|
15
|
+
import { IdorAnalyzer } from './analyzers/IdorAnalyzer.js';
|
|
16
|
+
import { CredentialExposureAnalyzer } from './analyzers/CredentialExposureAnalyzer.js';
|
|
17
|
+
import { SessionSecurityAnalyzer } from './analyzers/SessionSecurityAnalyzer.js';
|
|
18
|
+
import { FileUploadAnalyzer } from './analyzers/FileUploadAnalyzer.js';
|
|
19
|
+
import { RateLimitAnalyzer } from './analyzers/RateLimitAnalyzer.js';
|
|
20
|
+
import { EncryptionAnalyzer } from './analyzers/EncryptionAnalyzer.js';
|
|
21
|
+
import { PrivilegeEscalationAnalyzer } from './analyzers/PrivilegeEscalationAnalyzer.js';
|
|
22
|
+
import { PhpParser } from './parsers/PhpParser.js';
|
|
23
|
+
const SEVERITY_PENALTIES = {
|
|
24
|
+
[Severity.Critical]: 25,
|
|
25
|
+
[Severity.High]: 10,
|
|
26
|
+
[Severity.Medium]: 3,
|
|
27
|
+
[Severity.Low]: 1,
|
|
28
|
+
[Severity.Info]: 0,
|
|
29
|
+
};
|
|
30
|
+
const GRADE_THRESHOLDS = [
|
|
31
|
+
{ grade: 'A', maxPenalty: 0 },
|
|
32
|
+
{ grade: 'B', maxPenalty: 10 },
|
|
33
|
+
{ grade: 'C', maxPenalty: 25 },
|
|
34
|
+
{ grade: 'D', maxPenalty: 50 },
|
|
35
|
+
{ grade: 'F', maxPenalty: Infinity },
|
|
36
|
+
];
|
|
37
|
+
export function calculateSecurityGrade(findings) {
|
|
38
|
+
const penalty = findings.reduce((sum, f) => sum + (SEVERITY_PENALTIES[f.severity] ?? 0), 0);
|
|
39
|
+
for (const threshold of GRADE_THRESHOLDS) {
|
|
40
|
+
if (penalty <= threshold.maxPenalty)
|
|
41
|
+
return threshold.grade;
|
|
42
|
+
}
|
|
43
|
+
return 'F';
|
|
44
|
+
}
|
|
45
|
+
// ─── Defaults ─────────────────────────────────────────────────────────────────
|
|
46
|
+
export const DEFAULT_ANALYZERS = [
|
|
47
|
+
new AuthorizationCoverageAnalyzer(),
|
|
48
|
+
new MassAssignmentAnalyzer(),
|
|
49
|
+
new XssSurfaceAnalyzer(),
|
|
50
|
+
new SqlInjectionAnalyzer(),
|
|
51
|
+
new DependencyAuditAnalyzer(),
|
|
52
|
+
new IdorAnalyzer(),
|
|
53
|
+
new CredentialExposureAnalyzer(),
|
|
54
|
+
new SessionSecurityAnalyzer(),
|
|
55
|
+
new FileUploadAnalyzer(),
|
|
56
|
+
new RateLimitAnalyzer(),
|
|
57
|
+
new EncryptionAnalyzer(),
|
|
58
|
+
new PrivilegeEscalationAnalyzer(),
|
|
59
|
+
];
|
|
60
|
+
export const DEFAULT_CONFIG = {
|
|
61
|
+
framework: 'laravel',
|
|
62
|
+
failOn: Severity.High,
|
|
63
|
+
output: 'text',
|
|
64
|
+
};
|
|
65
|
+
const SCANNER_VERSION = '0.2.0';
|
|
66
|
+
const DEFAULT_EXCLUDE_PATTERNS = [
|
|
67
|
+
'vendor/**', 'node_modules/**', 'storage/**',
|
|
68
|
+
'bootstrap/cache/**', 'public/vendor/**', '.git/**',
|
|
69
|
+
];
|
|
70
|
+
async function discoverProjectFiles(projectPath, config, parser) {
|
|
71
|
+
const absPath = resolve(projectPath);
|
|
72
|
+
const excludePatterns = [
|
|
73
|
+
...DEFAULT_EXCLUDE_PATTERNS,
|
|
74
|
+
...(config.exclude ?? []),
|
|
75
|
+
].map((e) => `${absPath}/${e}`);
|
|
76
|
+
const phpFiles = await glob(`${absPath}/**/*.php`, { ignore: excludePatterns, nodir: true });
|
|
77
|
+
const bladeFiles = await glob(`${absPath}/resources/views/**/*.blade.php`, { ignore: excludePatterns, nodir: true });
|
|
78
|
+
const parsedPhp = await Promise.all(phpFiles.map((f) => parser.parseFile(f, absPath)));
|
|
79
|
+
const parsedBlade = await Promise.all(bladeFiles
|
|
80
|
+
.filter((f) => !phpFiles.includes(f))
|
|
81
|
+
.map(async (f) => ({
|
|
82
|
+
path: f.replace(`${absPath}/`, ''),
|
|
83
|
+
content: await readFile(f, 'utf-8').catch(() => ''),
|
|
84
|
+
ast: null,
|
|
85
|
+
})));
|
|
86
|
+
const composerJsonPath = join(absPath, 'composer.json');
|
|
87
|
+
const composerFiles = existsSync(composerJsonPath)
|
|
88
|
+
? [{ path: 'composer.json', content: await readFile(composerJsonPath, 'utf-8').catch(() => ''), ast: null }]
|
|
89
|
+
: [];
|
|
90
|
+
return [...parsedPhp, ...parsedBlade, ...composerFiles];
|
|
91
|
+
}
|
|
92
|
+
function computeCoverage(files) {
|
|
93
|
+
let totalRoutes = 0;
|
|
94
|
+
let coveredRoutes = 0;
|
|
95
|
+
let totalModels = 0;
|
|
96
|
+
let protectedModels = 0;
|
|
97
|
+
for (const file of files) {
|
|
98
|
+
if (file.path.startsWith('routes/') || file.path.startsWith('routes\\')) {
|
|
99
|
+
const routeMatches = file.content.match(/Route::\w+\s*\(/g) ?? [];
|
|
100
|
+
totalRoutes += routeMatches.length;
|
|
101
|
+
const authMatches = file.content.match(/->middleware\s*\(\s*['"]auth/g) ?? [];
|
|
102
|
+
coveredRoutes += authMatches.length;
|
|
103
|
+
}
|
|
104
|
+
if ((file.path.includes('app/Models') || file.path.includes('app\\Models')) && file.path.endsWith('.php')) {
|
|
105
|
+
totalModels++;
|
|
106
|
+
if (/\$fillable\s*=|protected\s+\$guarded\s*=\s*\[(?:[^\]]+)\]/.test(file.content)) {
|
|
107
|
+
protectedModels++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const coveragePercent = totalRoutes > 0 ? Math.round((coveredRoutes / totalRoutes) * 100) : 100;
|
|
112
|
+
return { totalRoutes, coveredRoutes, coveragePercent, totalModels, protectedModels };
|
|
113
|
+
}
|
|
114
|
+
export async function scan(files, config = DEFAULT_CONFIG, analyzers = DEFAULT_ANALYZERS) {
|
|
115
|
+
const startTime = Date.now();
|
|
116
|
+
const allFindings = await Promise.all(analyzers.map((analyzer) => analyzer.analyze(files, config)));
|
|
117
|
+
const findings = allFindings.flat();
|
|
118
|
+
const coverage = computeCoverage(files);
|
|
119
|
+
return {
|
|
120
|
+
findings,
|
|
121
|
+
coverage,
|
|
122
|
+
metadata: {
|
|
123
|
+
scannedAt: new Date().toISOString(),
|
|
124
|
+
framework: config.framework,
|
|
125
|
+
filesScanned: files.length,
|
|
126
|
+
durationMs: Date.now() - startTime,
|
|
127
|
+
scannerVersion: SCANNER_VERSION,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
export async function scanProject(projectPath, config = DEFAULT_CONFIG, analyzers = DEFAULT_ANALYZERS) {
|
|
132
|
+
const parser = new PhpParser();
|
|
133
|
+
const files = await discoverProjectFiles(projectPath, config, parser);
|
|
134
|
+
const configWithRoot = { ...config, projectRoot: resolve(projectPath) };
|
|
135
|
+
const result = await scan(files, configWithRoot, analyzers);
|
|
136
|
+
const grade = calculateSecurityGrade(result.findings);
|
|
137
|
+
return { ...result, grade };
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ParsedFile } from '../types/index.js';
|
|
2
|
+
export interface PhpMethodInfo {
|
|
3
|
+
name: string;
|
|
4
|
+
visibility: 'public' | 'protected' | 'private';
|
|
5
|
+
isStatic: boolean;
|
|
6
|
+
line: number;
|
|
7
|
+
bodyText: string;
|
|
8
|
+
parameters: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface PhpPropertyInfo {
|
|
11
|
+
name: string;
|
|
12
|
+
visibility: 'public' | 'protected' | 'private';
|
|
13
|
+
isStatic: boolean;
|
|
14
|
+
line: number;
|
|
15
|
+
initializer?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface PhpClassInfo {
|
|
18
|
+
name: string;
|
|
19
|
+
isAbstract: boolean;
|
|
20
|
+
isTrait: boolean;
|
|
21
|
+
methods: PhpMethodInfo[];
|
|
22
|
+
properties: PhpPropertyInfo[];
|
|
23
|
+
traitUses: string[];
|
|
24
|
+
importedTraits: string[];
|
|
25
|
+
parent?: string;
|
|
26
|
+
line: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ParsedPhpFile extends ParsedFile {
|
|
29
|
+
classes: PhpClassInfo[];
|
|
30
|
+
useStatements: string[];
|
|
31
|
+
namespace?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare const PHP_FILE_PATTERNS: {
|
|
34
|
+
readonly CONTROLLERS: "app/Http/Controllers/**/*.php";
|
|
35
|
+
readonly MODELS: "app/Models/**/*.php";
|
|
36
|
+
readonly ROUTES_WEB: "routes/web.php";
|
|
37
|
+
readonly ROUTES_API: "routes/api.php";
|
|
38
|
+
readonly ROUTES_ALL: "routes/**/*.php";
|
|
39
|
+
readonly BLADE_TEMPLATES: "resources/views/**/*.blade.php";
|
|
40
|
+
readonly CONFIG: "config/**/*.php";
|
|
41
|
+
readonly ALL_PHP: "**/*.php";
|
|
42
|
+
};
|
|
43
|
+
export declare class PhpParser {
|
|
44
|
+
private engine;
|
|
45
|
+
constructor();
|
|
46
|
+
parseFile(filePath: string, rootDir?: string): Promise<ParsedPhpFile>;
|
|
47
|
+
parseDirectory(dir: string, exclude?: string[]): Promise<ParsedPhpFile[]>;
|
|
48
|
+
parseByPattern(rootDir: string, pattern: string, exclude?: string[]): Promise<ParsedPhpFile[]>;
|
|
49
|
+
parseBladeFiles(rootDir: string): Promise<ParsedFile[]>;
|
|
50
|
+
private extractFromAst;
|
|
51
|
+
private extractClass;
|
|
52
|
+
private extractMethod;
|
|
53
|
+
private extractProperty;
|
|
54
|
+
private stringifyNode;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=PhpParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhpParser.d.ts","sourceRoot":"","sources":["../../src/parsers/PhpParser.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAqB/C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC/C,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC/C,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;CASpB,CAAC;AAkBX,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAyD;;IAYjE,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAarE,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAS7E,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IASlG,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAY7D,OAAO,CAAC,cAAc;IAyBtB,OAAO,CAAC,YAAY;IA6BpB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,aAAa;CAyBtB"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { resolve, relative } from 'node:path';
|
|
4
|
+
import { glob } from 'glob';
|
|
5
|
+
export const PHP_FILE_PATTERNS = {
|
|
6
|
+
CONTROLLERS: 'app/Http/Controllers/**/*.php',
|
|
7
|
+
MODELS: 'app/Models/**/*.php',
|
|
8
|
+
ROUTES_WEB: 'routes/web.php',
|
|
9
|
+
ROUTES_API: 'routes/api.php',
|
|
10
|
+
ROUTES_ALL: 'routes/**/*.php',
|
|
11
|
+
BLADE_TEMPLATES: 'resources/views/**/*.blade.php',
|
|
12
|
+
CONFIG: 'config/**/*.php',
|
|
13
|
+
ALL_PHP: '**/*.php',
|
|
14
|
+
};
|
|
15
|
+
function nodeName(n) {
|
|
16
|
+
if (!n)
|
|
17
|
+
return '';
|
|
18
|
+
if (typeof n === 'string')
|
|
19
|
+
return n;
|
|
20
|
+
if (typeof n === 'object') {
|
|
21
|
+
if (typeof n.name === 'string')
|
|
22
|
+
return n.name;
|
|
23
|
+
if (typeof n.name === 'object')
|
|
24
|
+
return nodeName(n.name);
|
|
25
|
+
}
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
function normalizeVisibility(v) {
|
|
29
|
+
if (v === 'protected')
|
|
30
|
+
return 'protected';
|
|
31
|
+
if (v === 'private')
|
|
32
|
+
return 'private';
|
|
33
|
+
return 'public';
|
|
34
|
+
}
|
|
35
|
+
export class PhpParser {
|
|
36
|
+
engine;
|
|
37
|
+
constructor() {
|
|
38
|
+
const _require = createRequire(import.meta.url);
|
|
39
|
+
const mod = _require('php-parser');
|
|
40
|
+
const Engine = mod.Engine ?? mod.default?.Engine ?? mod;
|
|
41
|
+
this.engine = new Engine({
|
|
42
|
+
parser: { extractDoc: true, suppressErrors: true, php7: true },
|
|
43
|
+
ast: { withPositions: true },
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async parseFile(filePath, rootDir) {
|
|
47
|
+
const content = await readFile(filePath, 'utf-8').catch(() => '');
|
|
48
|
+
const relativePath = rootDir ? relative(rootDir, filePath) : filePath;
|
|
49
|
+
try {
|
|
50
|
+
const ast = this.engine.parseCode(content, filePath);
|
|
51
|
+
const extracted = this.extractFromAst(ast, content);
|
|
52
|
+
return { path: relativePath, content, ast, ...extracted };
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return { path: relativePath, content, ast: null, classes: [], useStatements: [] };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async parseDirectory(dir, exclude = []) {
|
|
59
|
+
const absDir = resolve(dir);
|
|
60
|
+
const files = await glob(`${absDir}/${PHP_FILE_PATTERNS.ALL_PHP}`, {
|
|
61
|
+
ignore: exclude.map((e) => resolve(absDir, e)),
|
|
62
|
+
nodir: true,
|
|
63
|
+
});
|
|
64
|
+
return Promise.all(files.map((f) => this.parseFile(f, absDir)));
|
|
65
|
+
}
|
|
66
|
+
async parseByPattern(rootDir, pattern, exclude = []) {
|
|
67
|
+
const absRoot = resolve(rootDir);
|
|
68
|
+
const files = await glob(`${absRoot}/${pattern}`, {
|
|
69
|
+
ignore: exclude.map((e) => resolve(absRoot, e)),
|
|
70
|
+
nodir: true,
|
|
71
|
+
});
|
|
72
|
+
return Promise.all(files.map((f) => this.parseFile(f, absRoot)));
|
|
73
|
+
}
|
|
74
|
+
async parseBladeFiles(rootDir) {
|
|
75
|
+
const absRoot = resolve(rootDir);
|
|
76
|
+
const files = await glob(`${absRoot}/${PHP_FILE_PATTERNS.BLADE_TEMPLATES}`, { nodir: true });
|
|
77
|
+
return Promise.all(files.map(async (f) => ({
|
|
78
|
+
path: relative(absRoot, f),
|
|
79
|
+
content: await readFile(f, 'utf-8').catch(() => ''),
|
|
80
|
+
ast: null,
|
|
81
|
+
})));
|
|
82
|
+
}
|
|
83
|
+
extractFromAst(ast, source) {
|
|
84
|
+
const classes = [];
|
|
85
|
+
const useStatements = [];
|
|
86
|
+
let namespace;
|
|
87
|
+
const processNodes = (nodes) => {
|
|
88
|
+
for (const node of nodes) {
|
|
89
|
+
if (node.kind === 'namespace') {
|
|
90
|
+
namespace = nodeName(node.name);
|
|
91
|
+
processNodes((node.children ?? []));
|
|
92
|
+
}
|
|
93
|
+
else if (node.kind === 'usegroup') {
|
|
94
|
+
for (const item of (node.items ?? [])) {
|
|
95
|
+
const name = nodeName(item.name);
|
|
96
|
+
if (name)
|
|
97
|
+
useStatements.push(name);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else if (node.kind === 'class' || node.kind === 'trait') {
|
|
101
|
+
classes.push(this.extractClass(node, source));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
processNodes((ast.children ?? []));
|
|
106
|
+
return { classes, useStatements, namespace };
|
|
107
|
+
}
|
|
108
|
+
extractClass(node, source) {
|
|
109
|
+
const name = nodeName(node.name);
|
|
110
|
+
const isAbstract = node.isAbstract ?? false;
|
|
111
|
+
const isTrait = node.kind === 'trait';
|
|
112
|
+
const line = node.loc?.start.line ?? 1;
|
|
113
|
+
const methods = [];
|
|
114
|
+
const properties = [];
|
|
115
|
+
const importedTraits = [];
|
|
116
|
+
const body = (node.body ?? []);
|
|
117
|
+
for (const member of body) {
|
|
118
|
+
if (member.kind === 'method') {
|
|
119
|
+
methods.push(this.extractMethod(member, source));
|
|
120
|
+
}
|
|
121
|
+
else if (member.kind === 'propertystatement') {
|
|
122
|
+
const prop = this.extractProperty(member);
|
|
123
|
+
if (prop)
|
|
124
|
+
properties.push(prop);
|
|
125
|
+
}
|
|
126
|
+
else if (member.kind === 'traituse') {
|
|
127
|
+
for (const trait of (member.traits ?? [])) {
|
|
128
|
+
importedTraits.push(nodeName(trait));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const parentNode = node.extends;
|
|
133
|
+
const parent = parentNode ? nodeName(parentNode.name ?? parentNode) : undefined;
|
|
134
|
+
return { name, isAbstract, isTrait, methods, properties, traitUses: [], importedTraits, parent, line };
|
|
135
|
+
}
|
|
136
|
+
extractMethod(node, source) {
|
|
137
|
+
const name = nodeName(node.name);
|
|
138
|
+
const visibility = normalizeVisibility(node.visibility);
|
|
139
|
+
const isStatic = node.isStatic ?? false;
|
|
140
|
+
const line = node.loc?.start.line ?? 1;
|
|
141
|
+
const bodyNode = node.body;
|
|
142
|
+
let bodyText = '';
|
|
143
|
+
if (bodyNode?.loc) {
|
|
144
|
+
const lines = source.split('\n');
|
|
145
|
+
bodyText = lines.slice(bodyNode.loc.start.line - 1, bodyNode.loc.end.line).join('\n');
|
|
146
|
+
}
|
|
147
|
+
const params = (node.arguments ?? [])
|
|
148
|
+
.map((p) => nodeName(p.name));
|
|
149
|
+
return { name, visibility, isStatic, line, bodyText, parameters: params };
|
|
150
|
+
}
|
|
151
|
+
extractProperty(node) {
|
|
152
|
+
// php-parser uses "properties" for propertystatement children
|
|
153
|
+
const props = (node.properties ?? node.items ?? []);
|
|
154
|
+
if (props.length === 0)
|
|
155
|
+
return null;
|
|
156
|
+
const first = props[0];
|
|
157
|
+
const name = nodeName(first.name);
|
|
158
|
+
if (!name)
|
|
159
|
+
return null;
|
|
160
|
+
const visibility = normalizeVisibility(node.visibility);
|
|
161
|
+
const isStatic = node.isStatic ?? false;
|
|
162
|
+
const line = node.loc?.start.line ?? 1;
|
|
163
|
+
const initializer = first.value != null ? this.stringifyNode(first.value) : undefined;
|
|
164
|
+
return { name, visibility, isStatic, line, initializer };
|
|
165
|
+
}
|
|
166
|
+
stringifyNode(node) {
|
|
167
|
+
if (!node)
|
|
168
|
+
return '';
|
|
169
|
+
switch (node.kind) {
|
|
170
|
+
case 'string': return `"${node.value}"`;
|
|
171
|
+
case 'number': return String(node.value);
|
|
172
|
+
case 'boolean': return String(node.value);
|
|
173
|
+
case 'nullkeyword': return 'null';
|
|
174
|
+
case 'array': {
|
|
175
|
+
const items = (node.items ?? []);
|
|
176
|
+
const parts = items.map((item) => {
|
|
177
|
+
// php-parser wraps array values in "entry" nodes
|
|
178
|
+
const entryVal = item.value ?? item;
|
|
179
|
+
const val = this.stringifyNode(entryVal);
|
|
180
|
+
const entryKey = item.key;
|
|
181
|
+
return entryKey ? `${this.stringifyNode(entryKey)} => ${val}` : val;
|
|
182
|
+
});
|
|
183
|
+
return `[${parts.join(', ')}]`;
|
|
184
|
+
}
|
|
185
|
+
case 'identifier':
|
|
186
|
+
case 'name':
|
|
187
|
+
return nodeName(node);
|
|
188
|
+
default:
|
|
189
|
+
return '';
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=PhpParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhpParser.js","sourceRoot":"","sources":["../../src/parsers/PhpParser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HAVOC Route Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses Laravel route files (routes/web.php, routes/api.php, etc.) to extract
|
|
5
|
+
* route definitions and their associated middleware — including group-inherited
|
|
6
|
+
* middleware. This data is used by the AuthorizationCoverageAnalyzer to eliminate
|
|
7
|
+
* false positives where auth/authorization is handled at the route level.
|
|
8
|
+
*/
|
|
9
|
+
export interface RouteInfo {
|
|
10
|
+
/** HTTP method (GET, POST, PUT, PATCH, DELETE, ANY) or 'resource' */
|
|
11
|
+
method: string;
|
|
12
|
+
/** Route URI */
|
|
13
|
+
uri: string;
|
|
14
|
+
/** Controller class name (short, without namespace) */
|
|
15
|
+
controller: string;
|
|
16
|
+
/** Controller action/method name */
|
|
17
|
+
action: string;
|
|
18
|
+
/** All effective middleware applied to this route (including group inheritance) */
|
|
19
|
+
middleware: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface ParsedRouteFile {
|
|
22
|
+
/** Source file path (relative) */
|
|
23
|
+
path: string;
|
|
24
|
+
/** All extracted route definitions */
|
|
25
|
+
routes: RouteInfo[];
|
|
26
|
+
}
|
|
27
|
+
export declare function isAuthorizationMiddleware(mw: string): boolean;
|
|
28
|
+
export declare function isAuthenticationMiddleware(mw: string): boolean;
|
|
29
|
+
export declare function hasAuthorizationMiddleware(middleware: string[]): boolean;
|
|
30
|
+
export declare function hasAuthenticationMiddleware(middleware: string[]): boolean;
|
|
31
|
+
export declare function isWebhookHandler(bodyText: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Regex-based Laravel route file parser.
|
|
34
|
+
*
|
|
35
|
+
* Handles:
|
|
36
|
+
* - Route::get/post/put/patch/delete/any('uri', ...)
|
|
37
|
+
* - Route::resource('resource', Controller::class)
|
|
38
|
+
* - Route::middleware([...])->group(function () { ... })
|
|
39
|
+
* - Nested groups
|
|
40
|
+
*/
|
|
41
|
+
export declare class RouteParser {
|
|
42
|
+
/**
|
|
43
|
+
* Parse a single route file's content and return extracted routes.
|
|
44
|
+
*/
|
|
45
|
+
parseContent(content: string, filePath?: string): ParsedRouteFile;
|
|
46
|
+
/**
|
|
47
|
+
* Parse a route file from disk.
|
|
48
|
+
*/
|
|
49
|
+
parseFile(filePath: string, rootDir?: string): Promise<ParsedRouteFile>;
|
|
50
|
+
/**
|
|
51
|
+
* Parse all route files in a Laravel project's routes/ directory.
|
|
52
|
+
*/
|
|
53
|
+
parseDirectory(projectRoot: string): Promise<ParsedRouteFile[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Recursively parse a block of PHP route code, tracking inherited middleware.
|
|
56
|
+
*/
|
|
57
|
+
private parseBlock;
|
|
58
|
+
/**
|
|
59
|
+
* Extract the full chained call text starting at a Route:: position.
|
|
60
|
+
* Stops at semicolons not inside brackets/parens.
|
|
61
|
+
*/
|
|
62
|
+
private extractChain;
|
|
63
|
+
/**
|
|
64
|
+
* If the chain is a Route::middleware(...)->group(...), extract the middleware list.
|
|
65
|
+
* Returns null if this is not a group.
|
|
66
|
+
*/
|
|
67
|
+
private extractGroupMiddleware;
|
|
68
|
+
/**
|
|
69
|
+
* Find the closure body of a ->group(function () { ... }) call.
|
|
70
|
+
*/
|
|
71
|
+
private extractGroupBody;
|
|
72
|
+
/**
|
|
73
|
+
* Extract route info from a single Route::method() chain.
|
|
74
|
+
*/
|
|
75
|
+
private extractRoute;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build a lookup map: "ControllerName::action" → RouteInfo[]
|
|
79
|
+
* Used by analyzers for O(1) route lookups.
|
|
80
|
+
*/
|
|
81
|
+
export declare function buildRouteMap(routeFiles: ParsedRouteFile[]): Map<string, RouteInfo[]>;
|
|
82
|
+
/**
|
|
83
|
+
* Get all middleware for a given controller action from the route map.
|
|
84
|
+
* Returns an empty array if the action is not found in any route.
|
|
85
|
+
*/
|
|
86
|
+
export declare function getRouteMiddleware(routeMap: Map<string, RouteInfo[]>, controller: string, action: string): string[];
|
|
87
|
+
//# sourceMappingURL=RouteParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RouteParser.d.ts","sourceRoot":"","sources":["../../src/parsers/RouteParser.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,WAAW,SAAS;IACxB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAmBD,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAExE;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAEzE;AAeD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1D;AAkED;;;;;;;;GAQG;AACH,qBAAa,WAAW;IACtB;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAW,GAAG,eAAe;IAMrE;;OAEG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAM7E;;OAEG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAMrE;;OAEG;IACH,OAAO,CAAC,UAAU;IAgClB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAmCpB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAO9B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;OAEG;IACH,OAAO,CAAC,YAAY;CAoDrB;AAID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAYrF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,EAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,MAAM,EAAE,CAKV"}
|