@fortressjs/cli 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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/index.js");
@@ -0,0 +1 @@
1
+ export declare function runAudit(): void;
package/dist/index.js ADDED
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runAudit = runAudit;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const scanner_1 = require("./scanner");
10
+ // ANSI Terminal Colors
11
+ const C = {
12
+ reset: "\x1b[0m",
13
+ bold: "\x1b[1m",
14
+ dim: "\x1b[2m",
15
+ red: "\x1b[31m",
16
+ green: "\x1b[32m",
17
+ yellow: "\x1b[33m",
18
+ cyan: "\x1b[36m"
19
+ };
20
+ function getFilesRecursively(dir, fileList = []) {
21
+ if (!fs_1.default.existsSync(dir))
22
+ return fileList;
23
+ const files = fs_1.default.readdirSync(dir);
24
+ for (const file of files) {
25
+ const filePath = path_1.default.join(dir, file);
26
+ const stat = fs_1.default.statSync(filePath);
27
+ // Skip node_modules, build directories, hidden files, and coverage files
28
+ if (file === "node_modules" ||
29
+ file === "dist" ||
30
+ file === "build" ||
31
+ file === "coverage" ||
32
+ file.startsWith(".")) {
33
+ continue;
34
+ }
35
+ if (stat.isDirectory()) {
36
+ getFilesRecursively(filePath, fileList);
37
+ }
38
+ else if (filePath.endsWith(".ts") || filePath.endsWith(".js")) {
39
+ // Exclude definition files and config files
40
+ if (!filePath.endsWith(".d.ts") && !filePath.includes("config.js")) {
41
+ fileList.push(filePath);
42
+ }
43
+ }
44
+ }
45
+ return fileList;
46
+ }
47
+ function runAudit() {
48
+ console.log(`\n${C.bold}${C.cyan}🛡️ FortressJS Security Audit CLI${C.reset}`);
49
+ console.log(`${C.dim}=========================================${C.reset}\n`);
50
+ const cwd = process.cwd();
51
+ const files = getFilesRecursively(cwd);
52
+ if (files.length === 0) {
53
+ console.log(`${C.yellow}No JavaScript or TypeScript files found to scan in: ${cwd}${C.reset}`);
54
+ return;
55
+ }
56
+ console.log(`${C.dim}Scanning ${files.length} file(s)...${C.reset}`);
57
+ const scanner = new scanner_1.RegexScanner();
58
+ // Aggregate results across all files in the project
59
+ const aggregated = {
60
+ hasCSP: false,
61
+ hasRateLimiting: false,
62
+ hasRequestSizeLimiting: false,
63
+ hasLogger: false,
64
+ hasThreatDetection: false,
65
+ hasHTTPS: false
66
+ };
67
+ for (const file of files) {
68
+ try {
69
+ const content = fs_1.default.readFileSync(file, "utf8");
70
+ const result = scanner.scan(content);
71
+ if (result.hasCSP)
72
+ aggregated.hasCSP = true;
73
+ if (result.hasRateLimiting)
74
+ aggregated.hasRateLimiting = true;
75
+ if (result.hasRequestSizeLimiting)
76
+ aggregated.hasRequestSizeLimiting = true;
77
+ if (result.hasLogger)
78
+ aggregated.hasLogger = true;
79
+ if (result.hasThreatDetection)
80
+ aggregated.hasThreatDetection = true;
81
+ if (result.hasHTTPS)
82
+ aggregated.hasHTTPS = true;
83
+ }
84
+ catch (e) {
85
+ console.error(`${C.red}Error reading file ${file}: ${e.message}${C.reset}`);
86
+ }
87
+ }
88
+ // Calculate score
89
+ let score = 100;
90
+ const missing = [];
91
+ const recommendations = [];
92
+ if (!aggregated.hasCSP) {
93
+ score -= 15;
94
+ missing.push("Content Security Policy (CSP)");
95
+ recommendations.push("Add fortress.headers() to configure secure CSP and other headers");
96
+ }
97
+ if (!aggregated.hasRateLimiting) {
98
+ score -= 20;
99
+ missing.push("Rate Limiting");
100
+ recommendations.push("Add fortress.rateLimit() to prevent DDoS and Brute Force attacks");
101
+ }
102
+ if (!aggregated.hasRequestSizeLimiting) {
103
+ score -= 15;
104
+ missing.push("Request Size Limiting");
105
+ recommendations.push("Add fortress.requestLimit() to restrict payload sizes");
106
+ }
107
+ if (!aggregated.hasLogger) {
108
+ score -= 15;
109
+ missing.push("Security Logger");
110
+ recommendations.push("Add fortress.logger() to record requests in event store");
111
+ }
112
+ if (!aggregated.hasThreatDetection) {
113
+ score -= 20;
114
+ missing.push("Threat Intelligence Engine");
115
+ recommendations.push("Add fortress.threatDetector() to intercept automated scans and brute force");
116
+ }
117
+ if (!aggregated.hasHTTPS) {
118
+ score -= 15;
119
+ missing.push("HTTPS Enforcement / HSTS");
120
+ recommendations.push("Configure fortress.headers({ strictTransportSecurity: ... }) for HSTS");
121
+ }
122
+ score = Math.max(0, score);
123
+ // Pick color based on score
124
+ let scoreColor = C.red;
125
+ if (score >= 90)
126
+ scoreColor = C.green;
127
+ else if (score >= 70)
128
+ scoreColor = C.yellow;
129
+ console.log(`${C.bold}Security Score: ${scoreColor}${score}/100${C.reset}\n`);
130
+ if (missing.length === 0) {
131
+ console.log(`${C.bold}${C.green}🎉 Congratulations! Perfect score. Your application follows core FortressJS security best practices.${C.reset}\n`);
132
+ return;
133
+ }
134
+ console.log(`${C.bold}${C.red}Missing Protections:${C.reset}`);
135
+ for (const item of missing) {
136
+ console.log(` ${C.red}✗${C.reset} ${item}`);
137
+ }
138
+ console.log(`\n${C.bold}${C.yellow}Recommendations:${C.reset}`);
139
+ for (const rec of recommendations) {
140
+ console.log(` ${C.cyan}•${C.reset} ${rec}`);
141
+ }
142
+ console.log("");
143
+ }
144
+ // CLI entry point
145
+ const args = process.argv.slice(2);
146
+ if (args[0] === "audit") {
147
+ runAudit();
148
+ }
149
+ else {
150
+ console.log(`\n${C.bold}FortressJS CLI${C.reset}`);
151
+ console.log(`${C.dim}Usage: npx fortress audit${C.reset}\n`);
152
+ }
@@ -0,0 +1,20 @@
1
+ export interface ScanResult {
2
+ hasCSP: boolean;
3
+ hasRateLimiting: boolean;
4
+ hasRequestSizeLimiting: boolean;
5
+ hasLogger: boolean;
6
+ hasThreatDetection: boolean;
7
+ hasHTTPS: boolean;
8
+ }
9
+ export interface AuditScanner {
10
+ name: string;
11
+ scan(fileContent: string): ScanResult;
12
+ }
13
+ export declare class RegexScanner implements AuditScanner {
14
+ name: string;
15
+ scan(fileContent: string): ScanResult;
16
+ }
17
+ export declare class ASTScanner implements AuditScanner {
18
+ name: string;
19
+ scan(fileContent: string): ScanResult;
20
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ASTScanner = exports.RegexScanner = void 0;
4
+ // Concrete implementation of Regex-based scanner for MVP
5
+ class RegexScanner {
6
+ name = "RegexScanner";
7
+ scan(fileContent) {
8
+ const hasCSP = /fortress\.headers|helmet|Content-Security-Policy/i.test(fileContent);
9
+ const hasRateLimiting = /fortress\.rateLimit|express-rate-limit/i.test(fileContent);
10
+ const hasRequestSizeLimiting = /fortress\.requestLimit|limit\s*:\s*['"]\d+m?k?b['"]/i.test(fileContent);
11
+ const hasLogger = /fortress\.logger|morgan|winston/i.test(fileContent);
12
+ const hasThreatDetection = /fortress\.threatDetector/i.test(fileContent);
13
+ const hasHTTPS = /trust proxy|Strict-Transport-Security|https/i.test(fileContent);
14
+ return {
15
+ hasCSP,
16
+ hasRateLimiting,
17
+ hasRequestSizeLimiting,
18
+ hasLogger,
19
+ hasThreatDetection,
20
+ hasHTTPS
21
+ };
22
+ }
23
+ }
24
+ exports.RegexScanner = RegexScanner;
25
+ // Future AST-based scanner abstraction skeleton
26
+ class ASTScanner {
27
+ name = "ASTScanner (Future)";
28
+ scan(fileContent) {
29
+ // In v2, this scanner will parse the TypeScript/JavaScript code into an AST
30
+ // (using e.g., @babel/parser, typescript or acorn) and perform structural analysis
31
+ // to identify secure middleware configurations accurately without false positives.
32
+ throw new Error("AST Scanning is not implemented yet. Using RegexScanner as fallback.");
33
+ }
34
+ }
35
+ exports.ASTScanner = ASTScanner;
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@fortressjs/cli",
3
+ "version": "0.1.0",
4
+ "description": "Security auditing CLI for FortressJS and Express applications",
5
+ "license": "MIT",
6
+ "author": "Davanesh Saminathan",
7
+ "homepage": "https://github.com/davanesh/fortressjs",
8
+ "bugs": {
9
+ "url": "https://github.com/davanesh/fortressjs/issues"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/davanesh/fortressjs.git"
14
+ },
15
+ "keywords": [
16
+ "security",
17
+ "cli",
18
+ "audit",
19
+ "express",
20
+ "nodejs",
21
+ "middleware",
22
+ "api-security",
23
+ "fortressjs"
24
+ ],
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "bin": {
29
+ "fortress": "./bin/fortress.js"
30
+ },
31
+ "main": "dist/index.js",
32
+ "types": "dist/index.d.ts",
33
+ "files": [
34
+ "dist",
35
+ "bin"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsc"
39
+ },
40
+ "dependencies": {
41
+ "@fortressjs/core": "0.1.0"
42
+ },
43
+ "devDependencies": {
44
+ "typescript": "^5.0.0"
45
+ }
46
+ }