z-shield 0.1.1 → 0.1.2
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/README.md +123 -6
- package/dist/block-manager.d.ts +134 -0
- package/dist/block-manager.d.ts.map +1 -0
- package/dist/block-manager.js +425 -0
- package/dist/block-manager.js.map +1 -0
- package/dist/cli.d.ts +141 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +784 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +148 -0
- package/dist/config.js.map +1 -0
- package/dist/detector.d.ts +56 -0
- package/dist/detector.d.ts.map +1 -0
- package/dist/detector.js +81 -0
- package/dist/detector.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +120 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +141 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +347 -0
- package/dist/logger.js.map +1 -0
- package/dist/middleware.d.ts +68 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +272 -0
- package/dist/middleware.js.map +1 -0
- package/dist/next.d.ts +73 -0
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +486 -0
- package/dist/next.js.map +1 -0
- package/dist/rate-limiter.d.ts +75 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +153 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/types.d.ts +199 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/next.d.ts +1 -0
- package/next.js +2 -0
- package/package.json +34 -5
- package/src/block-manager.js +0 -326
- package/src/cli.js +0 -764
- package/src/config.js +0 -165
- package/src/detector.js +0 -88
- package/src/index.js +0 -97
- package/src/logger.js +0 -280
- package/src/middleware.js +0 -288
- package/src/rate-limiter.js +0 -186
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport net from 'node:net';\nimport { stripAnsi, sanitizeString, sanitizeRoute } from './logger';\nimport { parseDuration, isValidIp, normalizeIp } from './block-manager';\n\nexport interface ParsedCliArgs {\n command: string;\n args: string[];\n options: Record<string, string | boolean>;\n}\n\nexport type ColorFormatter = (str: string | number | undefined | null) => string;\n\nexport interface ColorMap {\n bold: ColorFormatter;\n dim: ColorFormatter;\n italic: ColorFormatter;\n underline: ColorFormatter;\n inverse: ColorFormatter;\n red: ColorFormatter;\n green: ColorFormatter;\n yellow: ColorFormatter;\n blue: ColorFormatter;\n magenta: ColorFormatter;\n cyan: ColorFormatter;\n white: ColorFormatter;\n gray: ColorFormatter;\n enabled: boolean;\n hasColors: boolean;\n}\n\nexport interface CliOutput {\n log: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n isTTY?: boolean;\n}\n\nexport interface LogReadResult {\n events: Record<string, unknown>[];\n totalLines: number;\n malformedCount: number;\n fileExists: boolean;\n}\n\nexport interface StatusResult {\n fileExists: boolean;\n totalEvents: number;\n malformedCount?: number;\n typeCounts?: Record<string, number>;\n actionCounts?: Record<string, number>;\n topIps?: Array<{ ip: string; count: number }>;\n topRoutes?: Array<{ route: string; count: number }>;\n}\n\n/**\n * Parses raw command-line arguments into a structured command object.\n *\n * @param argv - Array of CLI arguments (typically process.argv.slice(2))\n * @returns Structured CLI command, positional args, and parsed options\n */\nexport function parseCliArgs(argv: string[] = []): ParsedCliArgs {\n let command = 'help';\n const args: string[] = [];\n const options: Record<string, string | boolean> = {};\n\n let i = 0;\n // If first non-flag argument exists, it's the command\n while (i < argv.length) {\n const token = argv[i];\n if (!token) {\n i += 1;\n continue;\n }\n if (token.startsWith('--') || token.startsWith('-')) {\n const cleanKey = token.replace(/^-+/, '');\n const nextToken = argv[i + 1];\n // Check if next token is value\n if (nextToken !== undefined && !nextToken.startsWith('-')) {\n options[cleanKey] = nextToken;\n i += 2;\n } else {\n options[cleanKey] = true;\n i += 1;\n }\n } else {\n if (command === 'help') {\n command = token.toLowerCase();\n } else {\n args.push(token);\n }\n i += 1;\n }\n }\n\n if (options.help || options.h) {\n command = 'help';\n }\n\n return { command, args, options };\n}\n\n/**\n * Resolves the target JSON Lines log file path based on CLI options or defaults.\n *\n * @param options - Parsed CLI options\n * @returns Absolute path to events.jsonl\n */\nexport function resolveLogPath(options: Record<string, unknown> = {}): string {\n const logDirOption = (options['log-dir'] || options.logDir) as string | undefined;\n const envLogDir = process.env.Z_SHIELD_LOG_DIR;\n const filenameOption = (options['log-file'] || options.logFile) as string | undefined;\n\n // Precedence:\n // 1. Explicit CLI option: --log-dir / --logDir\n // 2. Environment variable: Z_SHIELD_LOG_DIR (if non-empty)\n // 3. Default: .z-shield-logs in current working directory\n let targetDir: string;\n if (typeof logDirOption === 'string' && logDirOption.trim().length > 0) {\n targetDir = logDirOption.trim();\n } else if (typeof envLogDir === 'string' && envLogDir.trim().length > 0) {\n targetDir = envLogDir.trim();\n } else {\n targetDir = path.join(process.cwd(), '.z-shield-logs');\n }\n\n const logDir = path.resolve(targetDir);\n let filename = 'events.jsonl';\n if (typeof filenameOption === 'string' && filenameOption.trim().length > 0) {\n const candidate = filenameOption.trim();\n if (\n !/^[a-zA-Z0-9._-]+$/.test(candidate) ||\n candidate.includes('..') ||\n candidate.includes('/') ||\n candidate.includes('\\\\')\n ) {\n throw new Error('[Z-Shield CLI] \"--log-file\" must be a safe filename without path traversal characters.');\n }\n filename = candidate;\n }\n\n return path.join(logDir, filename);\n}\n\n/**\n * Creates an ANSI color styling helper object.\n * When enabled is false, all styling methods act as plain passthroughs.\n *\n * @param enabled - Whether color styling is active\n * @returns Color styling map\n */\nexport function createColors(enabled: boolean = true): ColorMap {\n if (!enabled) {\n const pass: ColorFormatter = (str) => String(str ?? '');\n return {\n bold: pass,\n dim: pass,\n italic: pass,\n underline: pass,\n inverse: pass,\n red: pass,\n green: pass,\n yellow: pass,\n blue: pass,\n magenta: pass,\n cyan: pass,\n white: pass,\n gray: pass,\n enabled: false,\n hasColors: false\n };\n }\n\n const wrap = (open: number, close: number): ColorFormatter =>\n (str) => `\\x1b[${open}m${str ?? ''}\\x1b[${close}m`;\n\n return {\n bold: wrap(1, 22),\n dim: wrap(2, 22),\n italic: wrap(3, 23),\n underline: wrap(4, 24),\n inverse: wrap(7, 27),\n red: wrap(31, 39),\n green: wrap(32, 39),\n yellow: wrap(33, 39),\n blue: wrap(34, 39),\n magenta: wrap(35, 39),\n cyan: wrap(36, 39),\n white: wrap(37, 39),\n gray: wrap(90, 39),\n enabled: true,\n hasColors: true\n };\n}\n\n/**\n * Determines whether terminal colors should be enabled based on\n * explicit options, environment variables, and TTY capabilities.\n *\n * Respects the standard NO_COLOR specification (https://no-color.org).\n *\n * @param options - Parsed CLI options\n * @param output - Output destination (console or mock stream)\n * @returns True if colors should be enabled\n */\nexport function resolveColorSupport(\n options: Record<string, unknown> = {},\n output: CliOutput | Console | null = null\n): boolean {\n // 1. Explicit CLI flags\n if (\n options['no-color'] ||\n options.noColor ||\n options.color === false ||\n options.colors === false ||\n options.color === 'false' ||\n options.colors === 'false'\n ) {\n return false;\n }\n if (\n options.color === true ||\n options.colors === true ||\n options.color === 'true' ||\n options.colors === 'true' ||\n options.color === ''\n ) {\n return true;\n }\n\n // 2. NO_COLOR standard (https://no-color.org)\n if (process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== '') {\n return false;\n }\n\n // 3. Node.js NODE_DISABLE_COLORS\n if (process.env.NODE_DISABLE_COLORS === '1') {\n return false;\n }\n\n // 4. FORCE_COLOR override\n if (process.env.FORCE_COLOR !== undefined) {\n return process.env.FORCE_COLOR !== '0';\n }\n\n // 5. If output is a custom test mock or stream without TTY, disable colors by default\n if (output && output !== console) {\n return Boolean((output as CliOutput).isTTY);\n }\n\n // 6. Interactive terminal check\n return Boolean(process.stdout && process.stdout.isTTY);\n}\n\n/**\n * Formats a single security event record into a clean, sanitized terminal line.\n * Strips all ANSI escapes and control characters from untrusted log fields before formatting.\n *\n * @param event - Security event object\n * @param options - Options object or boolean for color\n * @returns Sanitized output line\n */\nexport function formatLogEvent(\n event: Record<string, unknown> | null | undefined,\n options: Record<string, unknown> | boolean = {}\n): string {\n if (!event || typeof event !== 'object') {\n return '[Malformed Event]';\n }\n\n let useColors = false;\n if (typeof options === 'boolean') {\n useColors = options;\n } else if (options && typeof options === 'object') {\n if (typeof options.colors === 'boolean') {\n useColors = options.colors;\n } else if (typeof options.color === 'boolean') {\n useColors = options.color;\n } else if (options.colors === 'true' || options.color === 'true') {\n useColors = true;\n } else if (options.colors === 'false' || options.color === 'false' || options['no-color']) {\n useColors = false;\n }\n }\n const c = createColors(useColors);\n\n // Sanitize untrusted log values first to prevent terminal injection\n const timestamp = sanitizeString(event.timestamp || 'UNKNOWN-TIME', 30);\n const severity = sanitizeString((event.severity || 'INFO'), 10).toUpperCase();\n const type = sanitizeString(event.type || 'unknown', 20);\n const rawAction = String(event.action || 'unknown').toUpperCase();\n const normalizedAction = rawAction === 'WARN' ? 'WARNED'\n : rawAction === 'BLOCK' ? 'BLOCKED'\n : rawAction === 'ALLOW' ? 'ALLOWED'\n : rawAction;\n const action = sanitizeString(normalizedAction, 10);\n const ip = sanitizeString(event.ip || 'unknown', 45);\n const method = sanitizeString(event.method || 'GET', 10).toUpperCase();\n const route = sanitizeString(event.route || '/', 100);\n const reason = sanitizeString(event.reason || 'No details', 150);\n\n if (!useColors) {\n return `[${timestamp}] [${severity}] [${action}] ${method} ${route} | IP: ${ip} | ${type}: ${reason}`;\n }\n\n // Action badge with semantic color\n let styledAction: string;\n switch (action) {\n case 'BLOCKED': styledAction = c.bold(c.red(`[${action}]`)); break;\n case 'WARNED': styledAction = c.bold(c.yellow(`[${action}]`)); break;\n case 'ALLOWED': styledAction = c.bold(c.green(`[${action}]`)); break;\n case 'UNBLOCKED': styledAction = c.bold(c.cyan(`[${action}]`)); break;\n case 'REQUESTED': styledAction = c.bold(c.blue(`[${action}]`)); break;\n default: styledAction = c.bold(`[${action}]`); break;\n }\n\n // Severity badge with semantic color\n let styledSeverity: string;\n switch (severity) {\n case 'CRITICAL': styledSeverity = c.bold(c.red(`[${severity}]`)); break;\n case 'WARNING': styledSeverity = c.bold(c.yellow(`[${severity}]`)); break;\n case 'INFO': styledSeverity = c.bold(c.green(`[${severity}]`)); break;\n default: styledSeverity = c.bold(`[${severity}]`); break;\n }\n\n const styledTimestamp = c.gray(`[${timestamp}]`);\n const styledMethod = c.bold(method);\n const styledRoute = c.cyan(route);\n const styledIp = c.bold(ip);\n const styledType = c.yellow(type);\n\n return `${styledTimestamp} ${styledSeverity} ${styledAction} ${styledMethod} ${styledRoute} | IP: ${styledIp} | ${styledType}: ${reason}`;\n}\n\n/**\n * Reads and parses the last N records from the JSON Lines file.\n * Handles missing files and skips malformed records gracefully.\n *\n * @param logFilePath - Path to log file\n * @param limit - Max number of events to return\n * @returns Extracted events and counts\n */\nexport function readLogs(logFilePath: string, limit: number = 20): LogReadResult {\n if (!fs.existsSync(logFilePath)) {\n return { events: [], totalLines: 0, malformedCount: 0, fileExists: false };\n }\n\n const rawContent = fs.readFileSync(logFilePath, 'utf8');\n const rawLines = rawContent.split('\\n').filter(line => line.trim().length > 0);\n\n let malformedCount = 0;\n const parsedEvents: Record<string, unknown>[] = [];\n\n for (const line of rawLines) {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n parsedEvents.push(parsed);\n } catch {\n malformedCount++;\n }\n }\n\n const selected = parsedEvents.slice(-limit);\n\n return {\n events: selected,\n totalLines: rawLines.length,\n malformedCount,\n fileExists: true\n };\n}\n\n/**\n * Sanitizes untrusted IP address values from logs for safe status aggregation and output.\n * Strips ANSI escapes, truncates at newlines/control characters, and extracts valid IP addresses.\n *\n * @param rawIp - Untrusted IP candidate from logs\n * @returns Normalized IP address or 'unknown'\n */\nexport function sanitizeIp(rawIp: unknown): string {\n if (!rawIp || typeof rawIp !== 'string') return 'unknown';\n const trimmed = rawIp.trim();\n if (trimmed.length === 0) return 'unknown';\n\n if (net.isIP(trimmed) !== 0) {\n return normalizeIp(trimmed);\n }\n\n const stripped = stripAnsi(trimmed);\n if (net.isIP(stripped) !== 0) {\n return normalizeIp(stripped);\n }\n\n const beforeEscape = (trimmed.split(/[\\x1b\\r\\n\\x00-\\x1f\\x7f]/)[0] ?? '').trim();\n if (beforeEscape.length > 0 && net.isIP(beforeEscape) !== 0) {\n return normalizeIp(beforeEscape);\n }\n\n const ipv4Match = stripped.match(/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/);\n if (ipv4Match && ipv4Match[0] && net.isIP(ipv4Match[0]) === 4) {\n return normalizeIp(ipv4Match[0]);\n }\n\n const ipv6Candidates = stripped.match(/[0-9a-fA-F:]+/g);\n if (ipv6Candidates) {\n for (const cand of ipv6Candidates) {\n if (net.isIP(cand) === 6) {\n return normalizeIp(cand);\n }\n }\n }\n\n return 'unknown';\n}\n\n/**\n * Sanitizes untrusted event type strings from logs.\n *\n * @param rawType - Untrusted event type string\n * @param maxLength - Maximum permitted length\n * @returns Clean event type string\n */\nexport function sanitizeType(rawType: unknown, maxLength: number = 30): string {\n if (!rawType || typeof rawType !== 'string') return 'unknown';\n let clean = rawType.split(/[\\r\\n\\x1b]/)[0] ?? '';\n clean = stripAnsi(clean);\n clean = clean.replace(/[\\x00-\\x1f\\x7f]/g, ' ').trim();\n clean = clean.replace(/\\s+/g, ' ');\n return clean.slice(0, maxLength) || 'unknown';\n}\n\n/**\n * Sanitizes untrusted action strings from logs.\n *\n * @param rawAction - Untrusted action string\n * @param maxLength - Maximum permitted length\n * @returns Clean action string\n */\nexport function sanitizeAction(rawAction: unknown, maxLength: number = 20): string {\n if (!rawAction || typeof rawAction !== 'string') return 'unknown';\n let clean = rawAction.split(/[\\r\\n\\x1b]/)[0] ?? '';\n clean = stripAnsi(clean);\n clean = clean.replace(/[\\x00-\\x1f\\x7f]/g, '').trim().toLowerCase();\n if (clean === 'warn') clean = 'warned';\n else if (clean === 'block') clean = 'blocked';\n else if (clean === 'allow') clean = 'allowed';\n return clean.slice(0, maxLength) || 'unknown';\n}\n\n/**\n * Computes security summary statistics from the log file.\n *\n * @param logFilePath - Path to log file\n * @returns Summary metrics\n */\nexport function calculateStatus(logFilePath: string): StatusResult {\n if (!fs.existsSync(logFilePath)) {\n return { fileExists: false, totalEvents: 0 };\n }\n\n const { events: allEvents, malformedCount } = readLogs(logFilePath, 100000);\n\n const ipCounts = Object.create(null) as Record<string, number>;\n const routeCounts = Object.create(null) as Record<string, number>;\n const typeCounts = Object.create(null) as Record<string, number>;\n const actionCounts = Object.create(null) as Record<string, number>;\n\n for (const event of allEvents) {\n const ip = sanitizeIp(event.ip);\n const route = sanitizeRoute(event.route);\n const type = sanitizeType(event.type);\n const action = sanitizeAction(event.action);\n\n ipCounts[ip] = (ipCounts[ip] || 0) + 1;\n routeCounts[route] = (routeCounts[route] || 0) + 1;\n typeCounts[type] = (typeCounts[type] || 0) + 1;\n actionCounts[action] = (actionCounts[action] || 0) + 1;\n }\n\n // Sort top offenders\n const topIps = Object.entries(ipCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 5)\n .map(([ip, count]) => ({ ip, count }));\n\n const topRoutes = Object.entries(routeCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 5)\n .map(([route, count]) => ({ route, count }));\n\n return {\n fileExists: true,\n totalEvents: allEvents.length,\n malformedCount,\n typeCounts,\n actionCounts,\n topIps,\n topRoutes\n };\n}\n\n/**\n * Main command runner. Returns an exit code (0 for success, 1 for error).\n *\n * @param argv - Arguments array\n * @param output - Output destination (console or mock object)\n * @returns Exit code\n */\nexport async function runCommand(\n argv: string[] = process.argv.slice(2),\n output: CliOutput | Console = console\n): Promise<number> {\n const { command, args, options } = parseCliArgs(argv);\n const logFilePath = resolveLogPath(options);\n const useColors = resolveColorSupport(options, output);\n const c = createColors(useColors);\n\n switch (command) {\n case 'status': {\n output.log(c.cyan('\\n\\n===================================================='));\n output.log(c.bold(c.cyan('🛡️ Z-Shield Security Status')));\n output.log(c.cyan('===================================================='));\n output.log(`${c.bold('Log File:')} ${c.gray(logFilePath)}`);\n\n const status = calculateStatus(logFilePath);\n\n if (!status.fileExists) {\n output.log(`${c.bold('Status:')} ${c.yellow('No log file found yet.')}`);\n output.log(`\\n${c.bold('Checked Location:')} ${c.gray(logFilePath)}`);\n output.log(c.dim('ℹ Start your Express or Next.js server to begin logging security events.'));\n output.log(c.dim(' If your application stores logs in a custom directory, specify it with:'));\n output.log(c.dim(' • CLI flag: z-shield status --log-dir <path>'));\n output.log(c.dim(' • Environment variable: Z_SHIELD_LOG_DIR=<path> z-shield status'));\n output.log(c.cyan('====================================================\\n'));\n return 0;\n }\n\n output.log(`${c.bold('Total Events Recorded:')} ${c.bold(c.cyan(status.totalEvents))}`);\n if (status.malformedCount && status.malformedCount > 0) {\n output.log(`${c.bold(c.yellow('⚠️ Malformed Lines Skipped:'))} ${c.yellow(status.malformedCount)}`);\n }\n\n output.log(`\\n${c.bold('Actions Breakdown:')}`);\n if (status.actionCounts) {\n for (const [action, count] of Object.entries(status.actionCounts)) {\n const cleanAction = sanitizeAction(action);\n const upper = cleanAction.toUpperCase();\n let styledAction = upper;\n if (upper === 'BLOCKED') styledAction = c.bold(c.red(upper));\n else if (upper === 'WARNED') styledAction = c.bold(c.yellow(upper));\n else if (upper === 'ALLOWED') styledAction = c.bold(c.green(upper));\n else if (upper === 'UNBLOCKED') styledAction = c.bold(c.cyan(upper));\n else if (upper === 'REQUESTED') styledAction = c.bold(c.blue(upper));\n output.log(` - ${styledAction}: ${c.bold(count)}`);\n }\n }\n\n output.log(`\\n${c.bold('Event Types:')}`);\n if (status.typeCounts) {\n for (const [type, count] of Object.entries(status.typeCounts)) {\n const cleanType = sanitizeType(type);\n output.log(` - ${c.yellow(cleanType)}: ${c.bold(count)}`);\n }\n }\n\n if (status.topIps && status.topIps.length > 0) {\n output.log(`\\n${c.bold('Top Offending IPs:')}`);\n for (const item of status.topIps) {\n const cleanIp = sanitizeIp(item.ip);\n output.log(` - ${c.cyan(cleanIp)}: ${c.bold(item.count)} events`);\n }\n }\n\n if (status.topRoutes && status.topRoutes.length > 0) {\n output.log(`\\n${c.bold('Top Targeted Routes:')}`);\n for (const item of status.topRoutes) {\n const cleanRoute = sanitizeRoute(item.route);\n output.log(` - ${c.underline(cleanRoute)}: ${c.bold(item.count)} events`);\n }\n }\n\n output.log(`\\n${c.dim('ℹ Process-Local Architecture Notice:')}`);\n output.log(c.dim('Statistics reflect historical events recorded in the local log file.'));\n output.log(c.dim('Active in-memory counters and temporary blocks reside in server RAM'));\n output.log(c.dim('and are managed inside the running Express process.'));\n\n output.log(c.cyan('===================================================='));\n return 0;\n }\n\n case 'logs': {\n let limit = 20;\n if (options.limit) {\n const parsed = parseInt(String(options.limit), 10);\n if (isNaN(parsed) || parsed <= 0) {\n output.error(c.bold(c.red('[ERROR] --limit must be a positive integer.')));\n return 1;\n }\n limit = parsed;\n }\n\n const { events, totalLines, malformedCount, fileExists } = readLogs(logFilePath, limit);\n\n output.log(c.cyan('\\n\\n===================================================='));\n output.log(c.bold(c.cyan(`🛡️ Z-Shield Security Logs (Showing last ${events.length} of ${totalLines} events)`)));\n output.log(`${c.bold('Source:')} ${c.gray(logFilePath)}`);\n output.log(c.cyan('===================================================='));\n\n if (!fileExists || events.length === 0) {\n if (!fileExists) {\n output.log(c.yellow(`ℹ No log file found at: ${logFilePath}`));\n output.log(c.dim(' Ensure your Express or Next.js server has started and recorded events.'));\n output.log(c.dim(' If your logs are stored in a custom directory, specify it with:'));\n output.log(c.dim(' • CLI flag: z-shield logs --log-dir <path>'));\n output.log(c.dim(' • Environment variable: Z_SHIELD_LOG_DIR=<path> z-shield logs'));\n } else {\n output.log(c.dim('ℹ No security events found in log file.'));\n }\n output.log(c.cyan('===================================================='));\n return 0;\n }\n\n for (const event of events) {\n output.log(formatLogEvent(event, { colors: useColors }));\n }\n\n if (malformedCount > 0) {\n output.log(`\\n${c.yellow(`⚠️ Notice: Skipped ${malformedCount} unparseable or corrupted lines.`)}`);\n }\n\n output.log(c.cyan('===================================================='));\n return 0;\n }\n\n case 'monitor': {\n output.log(c.cyan('\\n\\n===================================================='));\n output.log(c.bold(c.cyan('🛡️ Z-Shield Live Security Event Monitor')));\n output.log(`${c.bold('Watching:')} ${c.gray(logFilePath)}`);\n output.log(c.dim('Press Ctrl+C to exit.'));\n output.log(c.cyan('===================================================='));\n\n let currentSize = 0;\n if (fs.existsSync(logFilePath)) {\n currentSize = fs.statSync(logFilePath).size;\n // Show recent events for immediate context\n const { events } = readLogs(logFilePath, 5);\n if (events.length > 0) {\n output.log(c.dim('--- Recent Events ---'));\n for (const ev of events) {\n output.log(formatLogEvent(ev, { colors: useColors }));\n }\n output.log(c.dim('--- Live Stream Active ---'));\n }\n } else {\n output.log(c.yellow(`ℹ Waiting for log file to be created at: ${logFilePath}`));\n output.log(c.dim(' Tip: You can specify a custom directory with --log-dir <path> or Z_SHIELD_LOG_DIR=<path>.'));\n }\n\n // Live watcher polling function state\n let isReading = false;\n let partialLine = '';\n\n const checkNewLines = () => {\n if (!fs.existsSync(logFilePath) || isReading) {\n return;\n }\n try {\n const stats = fs.statSync(logFilePath);\n if (stats.size > currentSize) {\n isReading = true;\n const readStart = currentSize;\n const readEnd = stats.size;\n currentSize = readEnd;\n\n const stream = fs.createReadStream(logFilePath, {\n start: readStart,\n end: readEnd,\n encoding: 'utf8'\n });\n\n stream.on('data', chunk => {\n partialLine += chunk;\n const lines = partialLine.split('\\n');\n partialLine = lines.pop() ?? ''; // keep last partial line\n for (const line of lines) {\n if (line.trim().length > 0) {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n output.log(formatLogEvent(parsed, { colors: useColors }));\n } catch {\n output.log(c.yellow('[⚠️ Corrupted log record]'));\n }\n }\n }\n });\n\n stream.on('end', () => {\n isReading = false;\n });\n\n stream.on('error', () => {\n isReading = false;\n });\n } else if (stats.size < currentSize) {\n // File was rotated or truncated!\n currentSize = 0;\n partialLine = '';\n }\n } catch {\n isReading = false;\n }\n };\n\n // Poll every 300ms for responsive terminal updates\n const interval = setInterval(checkNewLines, 300);\n\n // Clean exit on SIGINT (Ctrl+C)\n return new Promise<number>((resolve) => {\n const cleanup = () => {\n clearInterval(interval);\n output.log(`\\n${c.cyan('👋 Exiting Z-Shield live monitor.')}`);\n resolve(0);\n };\n\n process.once('SIGINT', cleanup);\n process.once('SIGTERM', cleanup);\n });\n }\n\n case 'block': {\n const ip = args[0];\n if (!ip) {\n output.error(c.bold(c.red('[ERROR] Missing IP address. Usage: npx z-shield block <ip> [--duration 10m] [--reason <text>]')));\n return 1;\n }\n\n if (!isValidIp(ip)) {\n output.error(c.bold(c.red(`[ERROR] Invalid IP address \"${ip}\". Must be a valid IPv4 or IPv6 address.`)));\n return 1;\n }\n\n const durationRaw = (options.duration as string) || '15m';\n let durationMs: number;\n try {\n durationMs = parseDuration(durationRaw);\n } catch (err) {\n output.error(c.bold(c.red(`[ERROR] ${(err as Error).message}`)));\n return 1;\n }\n\n const reason = (options.reason as string) || 'Manual block requested via CLI';\n\n output.log(c.cyan('\\n\\n===================================================='));\n output.log(c.bold(c.cyan('🛡️ Z-Shield CLI: Block Request')));\n output.log(c.cyan('===================================================='));\n output.log(`${c.bold('Target IP:')} ${c.bold(c.cyan(ip))}`);\n output.log(`${c.bold('Duration:')} ${c.yellow(durationRaw)} (${durationMs.toLocaleString()}ms)`);\n output.log(`${c.bold('Reason:')} ${reason}`);\n output.log(`\\n${c.bold(c.yellow('ℹ Process-Local Architecture Notice:'))}`);\n output.log(c.dim('Z-Shield manages active temporary blocks in server memory (RAM).'));\n output.log(c.dim('Because this CLI runs in an independent Node.js process, it cannot'));\n output.log(c.dim(\"directly modify the running Express server's memory heap without an\"));\n output.log(c.dim('external IPC socket or database (which Z-Shield intentionally avoids).'));\n output.log(`\\n${c.bold('To block this IP in your running Express application:')}`);\n output.log(c.green(` shield.block('${ip}', '${durationRaw}', '${reason}');`));\n\n // Record an audit log event\n try {\n fs.mkdirSync(path.dirname(logFilePath), { recursive: true });\n const auditEvent = {\n timestamp: new Date().toISOString(),\n appName: 'cli',\n type: 'cli_block_requested',\n severity: 'info',\n ip,\n method: 'CLI',\n route: '/cli/block',\n reason: `Requested duration: ${durationRaw} | Reason: ${reason}`,\n action: 'requested'\n };\n fs.appendFileSync(logFilePath, JSON.stringify(auditEvent) + '\\n');\n output.log(`\\n${c.green('✔')} Audit entry recorded in: ${c.gray(logFilePath)}`);\n } catch {\n // Safe fallback\n }\n\n output.log(c.cyan('===================================================='));\n return 0;\n }\n\n case 'unblock': {\n const ip = args[0];\n if (!ip) {\n output.error(c.bold(c.red('[ERROR] Missing IP address. Usage: npx z-shield unblock <ip>')));\n return 1;\n }\n\n if (!isValidIp(ip)) {\n output.error(c.bold(c.red(`[ERROR] Invalid IP address \"${ip}\". Must be a valid IPv4 or IPv6 address.`)));\n return 1;\n }\n\n output.log(c.cyan('\\n\\n===================================================='));\n output.log(c.bold(c.cyan('🛡️ Z-Shield CLI: Unblock Request')));\n output.log(c.cyan('===================================================='));\n output.log(`${c.bold('Target IP:')} ${c.bold(c.cyan(ip))}`);\n output.log(`\\n${c.bold(c.yellow('ℹ Process-Local Architecture Notice:'))}`);\n output.log(c.dim('Z-Shield manages active temporary blocks in server memory (RAM).'));\n output.log(`\\n${c.bold('To unblock this IP in your running Express application:')}`);\n output.log(c.green(` shield.unblock('${ip}');`));\n\n // Record an audit log event\n try {\n fs.mkdirSync(path.dirname(logFilePath), { recursive: true });\n const auditEvent = {\n timestamp: new Date().toISOString(),\n appName: 'cli',\n type: 'cli_unblock_requested',\n severity: 'info',\n ip,\n method: 'CLI',\n route: '/cli/unblock',\n reason: 'Manual unblock requested via CLI',\n action: 'requested'\n };\n fs.appendFileSync(logFilePath, JSON.stringify(auditEvent) + '\\n');\n output.log(`\\n${c.green('✔')} Audit entry recorded in: ${c.gray(logFilePath)}`);\n } catch {\n // Safe fallback\n }\n\n output.log(c.cyan('===================================================='));\n return 0;\n }\n\n case 'help':\n default: {\n output.log(c.cyan('\\n\\n===================================================='));\n output.log(c.bold(c.cyan('🛡️ Z-Shield CLI — API Abuse Detection & Protection')));\n output.log(c.cyan('===================================================='));\n output.log(c.bold('Usage:'));\n output.log(` ${c.bold('npx z-shield')} ${c.cyan('<command>')} [options]`);\n output.log(`\\n${c.bold('Commands:')}`);\n output.log(` ${c.bold('npx z-shield status')} Show security overview and top offender IPs`);\n output.log(` ${c.bold('npx z-shield logs')} [--limit 50] Display recent security event logs`);\n output.log(` ${c.bold('npx z-shield monitor')} Stream security events in real time`);\n output.log(` ${c.bold('npx z-shield block')} <ip> Instructions & audit for blocking an IP`);\n output.log(` ${c.bold('npx z-shield unblock')} <ip> Instructions & audit for unblocking an IP`);\n output.log(`\\n${c.bold('Options:')}`);\n output.log(` ${c.yellow('--limit')} <number> Number of log entries to display (default: 20)`);\n output.log(` ${c.yellow('--duration')} <time> Block duration (e.g. 10m, 1h, 30s)`);\n output.log(` ${c.yellow('--reason')} <text> Reason for manual block`);\n output.log(` ${c.yellow('--log-dir')} <path> Path to log directory (default: .z-shield-logs)`);\n output.log(` ${c.yellow('--color')} Force enable colored terminal output`);\n output.log(` ${c.yellow('--no-color')} Disable colored terminal output`);\n output.log(` ${c.yellow('--help, -h')} Display this help message`);\n output.log(`\\n${c.bold('Environment Variables:')}`);\n output.log(` ${c.yellow('Z_SHIELD_LOG_DIR')} Default log directory path when --log-dir is omitted`);\n output.log(c.cyan('===================================================='));\n return command === 'help' ? 0 : 1;\n }\n }\n}\n\n// Execute directly if run from CLI\nif (require.main === module) {\n runCommand(process.argv.slice(2)).then(code => {\n if (code !== 0) {\n process.exit(code);\n }\n });\n}\n"]}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ZShieldConfig, ZShieldOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Default configuration values for Z-Shield.
|
|
4
|
+
* Designed with conservative, safe defaults.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_CONFIG: ZShieldConfig;
|
|
7
|
+
/**
|
|
8
|
+
* Validates user-provided options and merges them with defaults.
|
|
9
|
+
* Throws clear, helpful errors if an invalid option is passed.
|
|
10
|
+
*
|
|
11
|
+
* @param userConfig - Custom configuration provided by the developer
|
|
12
|
+
* @returns Validated and frozen configuration object
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveConfig(userConfig?: ZShieldOptions | ZShieldConfig): ZShieldConfig;
|
|
15
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE7D;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,aAkD5B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,UAAU,GAAE,cAAc,GAAG,aAAkB,GAAG,aAAa,CAiH5F"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
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.DEFAULT_CONFIG = void 0;
|
|
7
|
+
exports.resolveConfig = resolveConfig;
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const block_manager_1 = require("./block-manager");
|
|
10
|
+
/**
|
|
11
|
+
* Default configuration values for Z-Shield.
|
|
12
|
+
* Designed with conservative, safe defaults.
|
|
13
|
+
*/
|
|
14
|
+
exports.DEFAULT_CONFIG = {
|
|
15
|
+
// Unique identifier for the host application (useful when multiple apps share a server)
|
|
16
|
+
appName: 'default-app',
|
|
17
|
+
// Mode: 'monitor' (detect and log only) or 'protect' (enforce 429 and temporary blocks)
|
|
18
|
+
mode: 'monitor',
|
|
19
|
+
// Time window for tracking requests in milliseconds (default: 60,000ms = 1 minute)
|
|
20
|
+
windowMs: 60 * 1000,
|
|
21
|
+
// Maximum allowed requests from a single IP within the windowMs
|
|
22
|
+
maxRequests: 100,
|
|
23
|
+
// Directory where JSONL security event logs will be stored
|
|
24
|
+
logDir: node_path_1.default.resolve(process.cwd(), '.z-shield-logs'),
|
|
25
|
+
// Whether to trust reverse-proxy IP headers (e.g., X-Forwarded-For)
|
|
26
|
+
// CRITICAL: Must be false by default to prevent client IP spoofing attacks
|
|
27
|
+
trustProxy: false,
|
|
28
|
+
// Array of route prefixes that bypass abuse tracking (e.g. internal health checks)
|
|
29
|
+
excludeRoutes: ['/health', '/favicon.ico'],
|
|
30
|
+
// Maximum number of distinct client IPs to track in memory simultaneously
|
|
31
|
+
// Protects against Memory Exhaustion DoS attacks
|
|
32
|
+
maxTrackedIps: 10000,
|
|
33
|
+
// Duration in milliseconds for temporary IP blocks (default: 15 minutes)
|
|
34
|
+
blockDurationMs: 15 * 60 * 1000,
|
|
35
|
+
// Maximum number of blocked IPs to keep in memory simultaneously
|
|
36
|
+
maxBlockedIps: 5000,
|
|
37
|
+
// Whether exceeding rate limit in protect mode automatically triggers a temporary block
|
|
38
|
+
autoBlock: false,
|
|
39
|
+
// Filename for the active JSON Lines log file
|
|
40
|
+
logFilename: 'events.jsonl',
|
|
41
|
+
// Maximum size in bytes before rotating the log file (default: 5MB)
|
|
42
|
+
maxLogSizeBytes: 5 * 1024 * 1024,
|
|
43
|
+
// Maximum number of rotated log files to retain
|
|
44
|
+
maxLogFiles: 5,
|
|
45
|
+
// Maximum number of pending asynchronous log writes allowed in memory before dropping
|
|
46
|
+
maxLogQueueSize: 1000,
|
|
47
|
+
// Optional custom error callback: (err, event) => void
|
|
48
|
+
onLogError: null
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Validates user-provided options and merges them with defaults.
|
|
52
|
+
* Throws clear, helpful errors if an invalid option is passed.
|
|
53
|
+
*
|
|
54
|
+
* @param userConfig - Custom configuration provided by the developer
|
|
55
|
+
* @returns Validated and frozen configuration object
|
|
56
|
+
*/
|
|
57
|
+
function resolveConfig(userConfig = {}) {
|
|
58
|
+
if (userConfig === null || typeof userConfig !== 'object' || Array.isArray(userConfig)) {
|
|
59
|
+
throw new TypeError('[Z-Shield] Configuration must be a plain object.');
|
|
60
|
+
}
|
|
61
|
+
const rawConfig = { ...exports.DEFAULT_CONFIG, ...userConfig };
|
|
62
|
+
// Validate appName
|
|
63
|
+
if (typeof rawConfig.appName !== 'string' || rawConfig.appName.trim().length === 0) {
|
|
64
|
+
throw new TypeError('[Z-Shield] "appName" must be a non-empty string.');
|
|
65
|
+
}
|
|
66
|
+
// Prevent directory traversal characters in appName (e.g., "../hacker")
|
|
67
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(rawConfig.appName)) {
|
|
68
|
+
throw new Error('[Z-Shield] "appName" can only contain letters, numbers, dashes, and underscores.');
|
|
69
|
+
}
|
|
70
|
+
// Validate mode
|
|
71
|
+
if (rawConfig.mode !== 'monitor' && rawConfig.mode !== 'protect') {
|
|
72
|
+
throw new Error(`[Z-Shield] Invalid mode "${String(rawConfig.mode)}". Mode must be either "monitor" or "protect".`);
|
|
73
|
+
}
|
|
74
|
+
// Validate windowMs
|
|
75
|
+
if (typeof rawConfig.windowMs !== 'number' || !Number.isFinite(rawConfig.windowMs) || rawConfig.windowMs <= 0) {
|
|
76
|
+
throw new TypeError('[Z-Shield] "windowMs" must be a positive number in milliseconds.');
|
|
77
|
+
}
|
|
78
|
+
// Validate maxRequests
|
|
79
|
+
if (typeof rawConfig.maxRequests !== 'number' || !Number.isInteger(rawConfig.maxRequests) || rawConfig.maxRequests <= 0) {
|
|
80
|
+
throw new TypeError('[Z-Shield] "maxRequests" must be a positive integer.');
|
|
81
|
+
}
|
|
82
|
+
// Validate logDir
|
|
83
|
+
if (typeof rawConfig.logDir !== 'string' || rawConfig.logDir.trim().length === 0) {
|
|
84
|
+
throw new TypeError('[Z-Shield] "logDir" must be a non-empty string path.');
|
|
85
|
+
}
|
|
86
|
+
// Validate trustProxy
|
|
87
|
+
if (typeof rawConfig.trustProxy !== 'boolean') {
|
|
88
|
+
throw new TypeError('[Z-Shield] "trustProxy" must be a boolean (true or false).');
|
|
89
|
+
}
|
|
90
|
+
// Validate excludeRoutes
|
|
91
|
+
if (!Array.isArray(rawConfig.excludeRoutes) ||
|
|
92
|
+
!rawConfig.excludeRoutes.every(r => typeof r === 'string' && r.trim().length > 0)) {
|
|
93
|
+
throw new TypeError('[Z-Shield] "excludeRoutes" must be an array of non-empty string route prefixes.');
|
|
94
|
+
}
|
|
95
|
+
// Validate maxTrackedIps
|
|
96
|
+
if (typeof rawConfig.maxTrackedIps !== 'number' || !Number.isInteger(rawConfig.maxTrackedIps) || rawConfig.maxTrackedIps <= 0) {
|
|
97
|
+
throw new TypeError('[Z-Shield] "maxTrackedIps" must be a positive integer.');
|
|
98
|
+
}
|
|
99
|
+
// Support and validate blockDuration if provided
|
|
100
|
+
if (userConfig.blockDuration !== undefined) {
|
|
101
|
+
rawConfig.blockDurationMs = (0, block_manager_1.parseDuration)(userConfig.blockDuration);
|
|
102
|
+
}
|
|
103
|
+
// Validate blockDurationMs
|
|
104
|
+
if (typeof rawConfig.blockDurationMs !== 'number' || !Number.isFinite(rawConfig.blockDurationMs) || rawConfig.blockDurationMs <= 0) {
|
|
105
|
+
throw new TypeError('[Z-Shield] "blockDurationMs" must be a positive number in milliseconds.');
|
|
106
|
+
}
|
|
107
|
+
// Validate maxBlockedIps
|
|
108
|
+
if (typeof rawConfig.maxBlockedIps !== 'number' || !Number.isInteger(rawConfig.maxBlockedIps) || rawConfig.maxBlockedIps <= 0) {
|
|
109
|
+
throw new TypeError('[Z-Shield] "maxBlockedIps" must be a positive integer.');
|
|
110
|
+
}
|
|
111
|
+
// Validate autoBlock
|
|
112
|
+
if (typeof rawConfig.autoBlock !== 'boolean') {
|
|
113
|
+
throw new TypeError('[Z-Shield] "autoBlock" must be a boolean (true or false).');
|
|
114
|
+
}
|
|
115
|
+
// Validate logFilename
|
|
116
|
+
if (typeof rawConfig.logFilename !== 'string' || rawConfig.logFilename.trim().length === 0) {
|
|
117
|
+
throw new TypeError('[Z-Shield] "logFilename" must be a non-empty string.');
|
|
118
|
+
}
|
|
119
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(rawConfig.logFilename) ||
|
|
120
|
+
rawConfig.logFilename.includes('..') ||
|
|
121
|
+
rawConfig.logFilename.includes('/') ||
|
|
122
|
+
rawConfig.logFilename.includes('\\')) {
|
|
123
|
+
throw new Error('[Z-Shield] "logFilename" must be a safe filename without path traversal characters.');
|
|
124
|
+
}
|
|
125
|
+
// Validate maxLogSizeBytes
|
|
126
|
+
if (typeof rawConfig.maxLogSizeBytes !== 'number' || !Number.isInteger(rawConfig.maxLogSizeBytes) || rawConfig.maxLogSizeBytes <= 0) {
|
|
127
|
+
throw new TypeError('[Z-Shield] "maxLogSizeBytes" must be a positive integer.');
|
|
128
|
+
}
|
|
129
|
+
// Validate maxLogFiles
|
|
130
|
+
if (typeof rawConfig.maxLogFiles !== 'number' || !Number.isInteger(rawConfig.maxLogFiles) || rawConfig.maxLogFiles < 0) {
|
|
131
|
+
throw new TypeError('[Z-Shield] "maxLogFiles" must be a non-negative integer.');
|
|
132
|
+
}
|
|
133
|
+
// Validate maxLogQueueSize
|
|
134
|
+
if (typeof rawConfig.maxLogQueueSize !== 'number' || !Number.isInteger(rawConfig.maxLogQueueSize) || rawConfig.maxLogQueueSize <= 0) {
|
|
135
|
+
throw new TypeError('[Z-Shield] "maxLogQueueSize" must be a positive integer.');
|
|
136
|
+
}
|
|
137
|
+
// Validate onLogError
|
|
138
|
+
if (rawConfig.onLogError !== null && typeof rawConfig.onLogError !== 'function') {
|
|
139
|
+
throw new TypeError('[Z-Shield] "onLogError" must be null or a function.');
|
|
140
|
+
}
|
|
141
|
+
// Freeze the object so application code cannot accidentally mutate it at runtime
|
|
142
|
+
return Object.freeze({
|
|
143
|
+
...rawConfig,
|
|
144
|
+
logDir: node_path_1.default.resolve(rawConfig.logDir),
|
|
145
|
+
excludeRoutes: Object.freeze([...rawConfig.excludeRoutes])
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path';\nimport { parseDuration } from './block-manager';\nimport type { ZShieldConfig, ZShieldOptions } from './types';\n\n/**\n * Default configuration values for Z-Shield.\n * Designed with conservative, safe defaults.\n */\nexport const DEFAULT_CONFIG: ZShieldConfig = {\n // Unique identifier for the host application (useful when multiple apps share a server)\n appName: 'default-app',\n\n // Mode: 'monitor' (detect and log only) or 'protect' (enforce 429 and temporary blocks)\n mode: 'monitor',\n\n // Time window for tracking requests in milliseconds (default: 60,000ms = 1 minute)\n windowMs: 60 * 1000,\n\n // Maximum allowed requests from a single IP within the windowMs\n maxRequests: 100,\n\n // Directory where JSONL security event logs will be stored\n logDir: path.resolve(process.cwd(), '.z-shield-logs'),\n\n // Whether to trust reverse-proxy IP headers (e.g., X-Forwarded-For)\n // CRITICAL: Must be false by default to prevent client IP spoofing attacks\n trustProxy: false,\n\n // Array of route prefixes that bypass abuse tracking (e.g. internal health checks)\n excludeRoutes: ['/health', '/favicon.ico'],\n\n // Maximum number of distinct client IPs to track in memory simultaneously\n // Protects against Memory Exhaustion DoS attacks\n maxTrackedIps: 10000,\n\n // Duration in milliseconds for temporary IP blocks (default: 15 minutes)\n blockDurationMs: 15 * 60 * 1000,\n\n // Maximum number of blocked IPs to keep in memory simultaneously\n maxBlockedIps: 5000,\n\n // Whether exceeding rate limit in protect mode automatically triggers a temporary block\n autoBlock: false,\n\n // Filename for the active JSON Lines log file\n logFilename: 'events.jsonl',\n\n // Maximum size in bytes before rotating the log file (default: 5MB)\n maxLogSizeBytes: 5 * 1024 * 1024,\n\n // Maximum number of rotated log files to retain\n maxLogFiles: 5,\n\n // Maximum number of pending asynchronous log writes allowed in memory before dropping\n maxLogQueueSize: 1000,\n\n // Optional custom error callback: (err, event) => void\n onLogError: null\n};\n\n/**\n * Validates user-provided options and merges them with defaults.\n * Throws clear, helpful errors if an invalid option is passed.\n *\n * @param userConfig - Custom configuration provided by the developer\n * @returns Validated and frozen configuration object\n */\nexport function resolveConfig(userConfig: ZShieldOptions | ZShieldConfig = {}): ZShieldConfig {\n if (userConfig === null || typeof userConfig !== 'object' || Array.isArray(userConfig)) {\n throw new TypeError('[Z-Shield] Configuration must be a plain object.');\n }\n\n const rawConfig = { ...DEFAULT_CONFIG, ...userConfig };\n\n // Validate appName\n if (typeof rawConfig.appName !== 'string' || rawConfig.appName.trim().length === 0) {\n throw new TypeError('[Z-Shield] \"appName\" must be a non-empty string.');\n }\n // Prevent directory traversal characters in appName (e.g., \"../hacker\")\n if (!/^[a-zA-Z0-9_-]+$/.test(rawConfig.appName)) {\n throw new Error('[Z-Shield] \"appName\" can only contain letters, numbers, dashes, and underscores.');\n }\n\n // Validate mode\n if (rawConfig.mode !== 'monitor' && rawConfig.mode !== 'protect') {\n throw new Error(`[Z-Shield] Invalid mode \"${String(rawConfig.mode)}\". Mode must be either \"monitor\" or \"protect\".`);\n }\n\n // Validate windowMs\n if (typeof rawConfig.windowMs !== 'number' || !Number.isFinite(rawConfig.windowMs) || rawConfig.windowMs <= 0) {\n throw new TypeError('[Z-Shield] \"windowMs\" must be a positive number in milliseconds.');\n }\n\n // Validate maxRequests\n if (typeof rawConfig.maxRequests !== 'number' || !Number.isInteger(rawConfig.maxRequests) || rawConfig.maxRequests <= 0) {\n throw new TypeError('[Z-Shield] \"maxRequests\" must be a positive integer.');\n }\n\n // Validate logDir\n if (typeof rawConfig.logDir !== 'string' || rawConfig.logDir.trim().length === 0) {\n throw new TypeError('[Z-Shield] \"logDir\" must be a non-empty string path.');\n }\n\n // Validate trustProxy\n if (typeof rawConfig.trustProxy !== 'boolean') {\n throw new TypeError('[Z-Shield] \"trustProxy\" must be a boolean (true or false).');\n }\n\n // Validate excludeRoutes\n if (\n !Array.isArray(rawConfig.excludeRoutes) ||\n !rawConfig.excludeRoutes.every(r => typeof r === 'string' && r.trim().length > 0)\n ) {\n throw new TypeError('[Z-Shield] \"excludeRoutes\" must be an array of non-empty string route prefixes.');\n }\n\n // Validate maxTrackedIps\n if (typeof rawConfig.maxTrackedIps !== 'number' || !Number.isInteger(rawConfig.maxTrackedIps) || rawConfig.maxTrackedIps <= 0) {\n throw new TypeError('[Z-Shield] \"maxTrackedIps\" must be a positive integer.');\n }\n\n // Support and validate blockDuration if provided\n if (userConfig.blockDuration !== undefined) {\n rawConfig.blockDurationMs = parseDuration(userConfig.blockDuration);\n }\n\n // Validate blockDurationMs\n if (typeof rawConfig.blockDurationMs !== 'number' || !Number.isFinite(rawConfig.blockDurationMs) || rawConfig.blockDurationMs <= 0) {\n throw new TypeError('[Z-Shield] \"blockDurationMs\" must be a positive number in milliseconds.');\n }\n\n // Validate maxBlockedIps\n if (typeof rawConfig.maxBlockedIps !== 'number' || !Number.isInteger(rawConfig.maxBlockedIps) || rawConfig.maxBlockedIps <= 0) {\n throw new TypeError('[Z-Shield] \"maxBlockedIps\" must be a positive integer.');\n }\n\n // Validate autoBlock\n if (typeof rawConfig.autoBlock !== 'boolean') {\n throw new TypeError('[Z-Shield] \"autoBlock\" must be a boolean (true or false).');\n }\n\n // Validate logFilename\n if (typeof rawConfig.logFilename !== 'string' || rawConfig.logFilename.trim().length === 0) {\n throw new TypeError('[Z-Shield] \"logFilename\" must be a non-empty string.');\n }\n if (\n !/^[a-zA-Z0-9._-]+$/.test(rawConfig.logFilename) ||\n rawConfig.logFilename.includes('..') ||\n rawConfig.logFilename.includes('/') ||\n rawConfig.logFilename.includes('\\\\')\n ) {\n throw new Error('[Z-Shield] \"logFilename\" must be a safe filename without path traversal characters.');\n }\n\n // Validate maxLogSizeBytes\n if (typeof rawConfig.maxLogSizeBytes !== 'number' || !Number.isInteger(rawConfig.maxLogSizeBytes) || rawConfig.maxLogSizeBytes <= 0) {\n throw new TypeError('[Z-Shield] \"maxLogSizeBytes\" must be a positive integer.');\n }\n\n // Validate maxLogFiles\n if (typeof rawConfig.maxLogFiles !== 'number' || !Number.isInteger(rawConfig.maxLogFiles) || rawConfig.maxLogFiles < 0) {\n throw new TypeError('[Z-Shield] \"maxLogFiles\" must be a non-negative integer.');\n }\n\n // Validate maxLogQueueSize\n if (typeof rawConfig.maxLogQueueSize !== 'number' || !Number.isInteger(rawConfig.maxLogQueueSize) || rawConfig.maxLogQueueSize <= 0) {\n throw new TypeError('[Z-Shield] \"maxLogQueueSize\" must be a positive integer.');\n }\n\n // Validate onLogError\n if (rawConfig.onLogError !== null && typeof rawConfig.onLogError !== 'function') {\n throw new TypeError('[Z-Shield] \"onLogError\" must be null or a function.');\n }\n\n // Freeze the object so application code cannot accidentally mutate it at runtime\n return Object.freeze({\n ...rawConfig,\n logDir: path.resolve(rawConfig.logDir),\n excludeRoutes: Object.freeze([...rawConfig.excludeRoutes])\n }) as ZShieldConfig;\n}\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { RateLimiter } from './rate-limiter';
|
|
2
|
+
import type { ZShieldConfig } from './types';
|
|
3
|
+
export interface DetectorOptions {
|
|
4
|
+
rateLimiter: RateLimiter;
|
|
5
|
+
config: ZShieldConfig;
|
|
6
|
+
}
|
|
7
|
+
export interface CheckResult {
|
|
8
|
+
isSuspicious: boolean;
|
|
9
|
+
type: string;
|
|
10
|
+
severity: string;
|
|
11
|
+
reason: string | null;
|
|
12
|
+
count: number;
|
|
13
|
+
maxRequests: number;
|
|
14
|
+
remaining: number;
|
|
15
|
+
resetTime: number;
|
|
16
|
+
timestamp: string;
|
|
17
|
+
}
|
|
18
|
+
export interface InspectResult {
|
|
19
|
+
isSuspicious: boolean;
|
|
20
|
+
count: number;
|
|
21
|
+
maxRequests: number;
|
|
22
|
+
remaining: number;
|
|
23
|
+
resetTime: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Detector - Evaluates incoming requests and detects abuse patterns.
|
|
27
|
+
*
|
|
28
|
+
* In Phase 2, this evaluates whether a client IP has exceeded the
|
|
29
|
+
* maximum request threshold within the configured time window.
|
|
30
|
+
*/
|
|
31
|
+
export declare class Detector {
|
|
32
|
+
readonly rateLimiter: RateLimiter;
|
|
33
|
+
readonly config: ZShieldConfig;
|
|
34
|
+
/**
|
|
35
|
+
* @param options - Configuration containing rateLimiter and resolved config
|
|
36
|
+
*/
|
|
37
|
+
constructor({ rateLimiter, config }: DetectorOptions);
|
|
38
|
+
/**
|
|
39
|
+
* Checks an incoming request against detection rules.
|
|
40
|
+
*
|
|
41
|
+
* @param ip - Client IP address
|
|
42
|
+
* @param req - Request object (Express Request or standard Request)
|
|
43
|
+
* @param now - Timestamp
|
|
44
|
+
* @returns Detection evaluation result
|
|
45
|
+
*/
|
|
46
|
+
check(ip: string, req?: unknown, now?: number): CheckResult;
|
|
47
|
+
/**
|
|
48
|
+
* Inspects current status without incrementing counters.
|
|
49
|
+
*
|
|
50
|
+
* @param ip - Client IP address
|
|
51
|
+
* @param now - Timestamp
|
|
52
|
+
* @returns Inspection status
|
|
53
|
+
*/
|
|
54
|
+
inspect(ip: string, now?: number): InspectResult;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,qBAAa,QAAQ;IACnB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAE/B;;OAEG;IACH,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,eAAe,EAUnD;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,OAAY,EAAE,GAAG,GAAE,MAAmB,GAAG,WAAW,CA6B1E;IAED;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,aAAa,CAU3D;CACF"}
|
package/dist/detector.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Detector = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Detector - Evaluates incoming requests and detects abuse patterns.
|
|
6
|
+
*
|
|
7
|
+
* In Phase 2, this evaluates whether a client IP has exceeded the
|
|
8
|
+
* maximum request threshold within the configured time window.
|
|
9
|
+
*/
|
|
10
|
+
class Detector {
|
|
11
|
+
rateLimiter;
|
|
12
|
+
config;
|
|
13
|
+
/**
|
|
14
|
+
* @param options - Configuration containing rateLimiter and resolved config
|
|
15
|
+
*/
|
|
16
|
+
constructor({ rateLimiter, config }) {
|
|
17
|
+
if (!rateLimiter) {
|
|
18
|
+
throw new TypeError('[Z-Shield] Detector requires a RateLimiter instance.');
|
|
19
|
+
}
|
|
20
|
+
if (!config) {
|
|
21
|
+
throw new TypeError('[Z-Shield] Detector requires a resolved config object.');
|
|
22
|
+
}
|
|
23
|
+
this.rateLimiter = rateLimiter;
|
|
24
|
+
this.config = config;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Checks an incoming request against detection rules.
|
|
28
|
+
*
|
|
29
|
+
* @param ip - Client IP address
|
|
30
|
+
* @param req - Request object (Express Request or standard Request)
|
|
31
|
+
* @param now - Timestamp
|
|
32
|
+
* @returns Detection evaluation result
|
|
33
|
+
*/
|
|
34
|
+
check(ip, req = {}, now = Date.now()) {
|
|
35
|
+
const status = this.rateLimiter.record(ip, now);
|
|
36
|
+
if (status.isExceeded) {
|
|
37
|
+
const windowSeconds = Math.round(this.config.windowMs / 1000);
|
|
38
|
+
return {
|
|
39
|
+
isSuspicious: true,
|
|
40
|
+
type: 'rate_limit',
|
|
41
|
+
severity: 'warning',
|
|
42
|
+
reason: `Request threshold exceeded (${status.count}/${this.config.maxRequests} in ${windowSeconds}s)`,
|
|
43
|
+
count: status.count,
|
|
44
|
+
maxRequests: this.config.maxRequests,
|
|
45
|
+
remaining: status.remaining,
|
|
46
|
+
resetTime: status.resetTime,
|
|
47
|
+
timestamp: new Date(now).toISOString()
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
isSuspicious: false,
|
|
52
|
+
type: 'normal',
|
|
53
|
+
severity: 'info',
|
|
54
|
+
reason: null,
|
|
55
|
+
count: status.count,
|
|
56
|
+
maxRequests: this.config.maxRequests,
|
|
57
|
+
remaining: status.remaining,
|
|
58
|
+
resetTime: status.resetTime,
|
|
59
|
+
timestamp: new Date(now).toISOString()
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Inspects current status without incrementing counters.
|
|
64
|
+
*
|
|
65
|
+
* @param ip - Client IP address
|
|
66
|
+
* @param now - Timestamp
|
|
67
|
+
* @returns Inspection status
|
|
68
|
+
*/
|
|
69
|
+
inspect(ip, now = Date.now()) {
|
|
70
|
+
const status = this.rateLimiter.get(ip, now);
|
|
71
|
+
return {
|
|
72
|
+
isSuspicious: status.isExceeded,
|
|
73
|
+
count: status.count,
|
|
74
|
+
maxRequests: this.config.maxRequests,
|
|
75
|
+
remaining: status.remaining,
|
|
76
|
+
resetTime: status.resetTime
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.Detector = Detector;
|
|
81
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":";;;AA4BA;;;;;GAKG;AACH;IACW,WAAW,CAAc;IACzB,MAAM,CAAgB;IAE/B;;OAEG;IACH,YAAY,EAAE,WAAW,EAAE,MAAM,EAAmB;QAClD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,SAAS,CAAC,sDAAsD,CAAC,CAAC;QAC9E,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,SAAS,CAAC,wDAAwD,CAAC,CAAC;QAChF,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,EAAU,EAAE,GAAG,GAAY,EAAE,EAAE,GAAG,GAAW,IAAI,CAAC,GAAG,EAAE;QAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAEhD,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;YAC9D,OAAO;gBACL,YAAY,EAAE,IAAI;gBAClB,IAAI,EAAE,YAAY;gBAClB,QAAQ,EAAE,SAAS;gBACnB,MAAM,EAAE,+BAA+B,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,OAAO,aAAa,IAAI;gBACtG,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;gBACpC,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE;aACvC,CAAC;QACJ,CAAC;QAED,OAAO;YACL,YAAY,EAAE,KAAK;YACnB,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,MAAM;YAChB,MAAM,EAAE,IAAI;YACZ,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YACpC,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE;SACvC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,EAAU,EAAE,GAAG,GAAW,IAAI,CAAC,GAAG,EAAE;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAE7C,OAAO;YACL,YAAY,EAAE,MAAM,CAAC,UAAU;YAC/B,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YACpC,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;SAC5B,CAAC;IACJ,CAAC;CACF","sourcesContent":["import type { RateLimiter } from './rate-limiter';\nimport type { ZShieldConfig } from './types';\n\nexport interface DetectorOptions {\n rateLimiter: RateLimiter;\n config: ZShieldConfig;\n}\n\nexport interface CheckResult {\n isSuspicious: boolean;\n type: string;\n severity: string;\n reason: string | null;\n count: number;\n maxRequests: number;\n remaining: number;\n resetTime: number;\n timestamp: string;\n}\n\nexport interface InspectResult {\n isSuspicious: boolean;\n count: number;\n maxRequests: number;\n remaining: number;\n resetTime: number;\n}\n\n/**\n * Detector - Evaluates incoming requests and detects abuse patterns.\n *\n * In Phase 2, this evaluates whether a client IP has exceeded the\n * maximum request threshold within the configured time window.\n */\nexport class Detector {\n readonly rateLimiter: RateLimiter;\n readonly config: ZShieldConfig;\n\n /**\n * @param options - Configuration containing rateLimiter and resolved config\n */\n constructor({ rateLimiter, config }: DetectorOptions) {\n if (!rateLimiter) {\n throw new TypeError('[Z-Shield] Detector requires a RateLimiter instance.');\n }\n if (!config) {\n throw new TypeError('[Z-Shield] Detector requires a resolved config object.');\n }\n\n this.rateLimiter = rateLimiter;\n this.config = config;\n }\n\n /**\n * Checks an incoming request against detection rules.\n *\n * @param ip - Client IP address\n * @param req - Request object (Express Request or standard Request)\n * @param now - Timestamp\n * @returns Detection evaluation result\n */\n check(ip: string, req: unknown = {}, now: number = Date.now()): CheckResult {\n const status = this.rateLimiter.record(ip, now);\n\n if (status.isExceeded) {\n const windowSeconds = Math.round(this.config.windowMs / 1000);\n return {\n isSuspicious: true,\n type: 'rate_limit',\n severity: 'warning',\n reason: `Request threshold exceeded (${status.count}/${this.config.maxRequests} in ${windowSeconds}s)`,\n count: status.count,\n maxRequests: this.config.maxRequests,\n remaining: status.remaining,\n resetTime: status.resetTime,\n timestamp: new Date(now).toISOString()\n };\n }\n\n return {\n isSuspicious: false,\n type: 'normal',\n severity: 'info',\n reason: null,\n count: status.count,\n maxRequests: this.config.maxRequests,\n remaining: status.remaining,\n resetTime: status.resetTime,\n timestamp: new Date(now).toISOString()\n };\n }\n\n /**\n * Inspects current status without incrementing counters.\n *\n * @param ip - Client IP address\n * @param now - Timestamp\n * @returns Inspection status\n */\n inspect(ip: string, now: number = Date.now()): InspectResult {\n const status = this.rateLimiter.get(ip, now);\n\n return {\n isSuspicious: status.isExceeded,\n count: status.count,\n maxRequests: this.config.maxRequests,\n remaining: status.remaining,\n resetTime: status.resetTime\n };\n }\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createMiddleware, extractClientIp, isRouteExcluded, safelyEndResponse } from './middleware';
|
|
2
|
+
import { createNextShield, withNextShield, extractNextClientIp } from './next';
|
|
3
|
+
import { resolveConfig, DEFAULT_CONFIG } from './config';
|
|
4
|
+
import { RateLimiter } from './rate-limiter';
|
|
5
|
+
import { Detector } from './detector';
|
|
6
|
+
import { BlockManager, isValidIp, normalizeIp, canonicalizeIpv6, parseDuration, type BlockInfo } from './block-manager';
|
|
7
|
+
import { Logger, stripAnsi, sanitizeString, sanitizeRoute, sanitizeMethod } from './logger';
|
|
8
|
+
import type { ZShieldConfig, ZShieldOptions, ZShieldInstance, ZShieldFullInstance } from './types';
|
|
9
|
+
/**
|
|
10
|
+
* Main factory function for initializing Z-Shield.
|
|
11
|
+
*
|
|
12
|
+
* Usage in Express:
|
|
13
|
+
* const { createShield } = require('z-shield');
|
|
14
|
+
* const shield = createShield({ mode: 'protect', maxRequests: 50 });
|
|
15
|
+
* app.use(shield.middleware);
|
|
16
|
+
*
|
|
17
|
+
* Programmatic Block API:
|
|
18
|
+
* shield.block('198.51.100.1', '10m', 'Manual administrative block');
|
|
19
|
+
* shield.unblock('198.51.100.1');
|
|
20
|
+
* shield.isBlocked('198.51.100.1');
|
|
21
|
+
*
|
|
22
|
+
* @param options - Custom configuration options
|
|
23
|
+
* @returns Z-Shield instance with middleware, managers, logger, and programmatic methods
|
|
24
|
+
*/
|
|
25
|
+
export declare function createShield(options?: ZShieldOptions | ZShieldConfig): ZShieldInstance;
|
|
26
|
+
export { createMiddleware, extractClientIp, isRouteExcluded, safelyEndResponse, resolveConfig, DEFAULT_CONFIG, RateLimiter, Detector, BlockManager, isValidIp, normalizeIp, canonicalizeIpv6, parseDuration, Logger, stripAnsi, sanitizeString, sanitizeRoute, sanitizeMethod, createNextShield, withNextShield, extractNextClientIp };
|
|
27
|
+
export type { BlockInfo, ZShieldInstance, ZShieldFullInstance };
|
|
28
|
+
export * from './types';
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACrG,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACxH,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC5F,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EAEd,eAAe,EACf,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,cAAc,GAAG,aAAkB,GAAG,eAAe,CA4D1F;AAED,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,MAAM,EACN,SAAS,EACT,cAAc,EACd,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,mBAAmB,EACpB,CAAC;AAEF,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,mBAAmB,EAAE,CAAC;AAChE,cAAc,SAAS,CAAC"}
|