/**
* Zod schemas for web security tools
*/
import { z } from "zod";
/**
* Gobuster directory enumeration schema
*/
export const GobusterDirSchema = z.object({
url: z
.string()
.url()
.describe("Target URL (e.g., 'https://example.com')"),
wordlist: z
.string()
.default("/usr/share/wordlists/dirb/common.txt")
.describe("Wordlist file path"),
extensions: z
.string()
.optional()
.describe("File extensions to append (e.g., 'php,html,txt')"),
threads: z
.number()
.int()
.min(1)
.max(100)
.default(10)
.describe("Number of concurrent threads"),
status_codes: z
.string()
.default("200,204,301,302,307,401,403")
.describe("Positive status codes (comma-separated)"),
timeout: z
.number()
.int()
.min(10)
.max(3600)
.default(600)
.describe("Scan timeout in seconds"),
user_agent: z
.string()
.optional()
.describe("Custom User-Agent string"),
follow_redirect: z
.boolean()
.default(false)
.describe("Follow redirects"),
});
export type GobusterDirInput = z.infer<typeof GobusterDirSchema>;
/**
* Gobuster DNS enumeration schema
*/
export const GobusterDnsSchema = z.object({
domain: z
.string()
.describe("Target domain (e.g., 'example.com')"),
wordlist: z
.string()
.default("/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt")
.describe("Subdomain wordlist file path"),
threads: z
.number()
.int()
.min(1)
.max(100)
.default(10)
.describe("Number of concurrent threads"),
timeout: z
.number()
.int()
.min(10)
.max(3600)
.default(600)
.describe("Scan timeout in seconds"),
resolver: z
.string()
.optional()
.describe("Custom DNS resolver (e.g., '8.8.8.8')"),
});
export type GobusterDnsInput = z.infer<typeof GobusterDnsSchema>;
/**
* SQLMap schema
*/
export const SQLMapSchema = z.object({
url: z
.string()
.url()
.describe("Target URL"),
data: z
.string()
.optional()
.describe("POST data string"),
cookie: z
.string()
.optional()
.describe("HTTP Cookie header value"),
method: z
.enum(["GET", "POST"])
.default("GET")
.describe("HTTP method"),
parameter: z
.string()
.optional()
.describe("Testable parameter(s) (e.g., 'id', '*' for all)"),
level: z
.number()
.int()
.min(1)
.max(5)
.default(1)
.describe("Level of tests (1-5, default: 1)"),
risk: z
.number()
.int()
.min(1)
.max(3)
.default(1)
.describe("Risk of tests (1-3, default: 1)"),
dbms: z
.enum(["MySQL", "PostgreSQL", "MSSQL", "Oracle", "SQLite", "MongoDB"])
.optional()
.describe("Force DBMS type"),
technique: z
.string()
.optional()
.describe("SQL injection techniques (e.g., 'BEUSTQ')"),
batch: z
.boolean()
.default(true)
.describe("Never ask for user input (batch mode)"),
timeout: z
.number()
.int()
.min(10)
.max(3600)
.default(1800)
.describe("Scan timeout in seconds"),
});
export type SQLMapInput = z.infer<typeof SQLMapSchema>;
/**
* Nikto web scanner schema
*/
export const NiktoSchema = z.object({
target: z
.string()
.describe("Target host or URL"),
port: z
.number()
.int()
.min(1)
.max(65535)
.default(80)
.describe("Port to scan"),
ssl: z
.boolean()
.default(false)
.describe("Force SSL/HTTPS mode"),
tuning: z
.string()
.optional()
.describe("Tuning options (e.g., '1' for interesting files, '2' for misconfig)"),
timeout: z
.number()
.int()
.min(10)
.max(3600)
.default(600)
.describe("Scan timeout in seconds"),
});
export type NiktoInput = z.infer<typeof NiktoSchema>;
/**
* WPScan WordPress scanner schema
*/
export const WPScanSchema = z.object({
url: z
.string()
.url()
.describe("WordPress site URL"),
enumerate: z
.string()
.default("vp,vt,u")
.describe("Enumeration: vp (vulnerable plugins), vt (vulnerable themes), u (users)"),
api_token: z
.string()
.optional()
.describe("WPScan API token for vulnerability data"),
plugins_detection: z
.enum(["passive", "aggressive", "mixed"])
.default("passive")
.describe("Plugin detection mode"),
timeout: z
.number()
.int()
.min(10)
.max(3600)
.default(600)
.describe("Scan timeout in seconds"),
});
export type WPScanInput = z.infer<typeof WPScanSchema>;
/**
* ffuf fuzzer schema
*/
export const FfufSchema = z.object({
url: z
.string()
.describe("Target URL with FUZZ keyword (e.g., 'https://example.com/FUZZ')"),
wordlist: z
.string()
.default("/usr/share/wordlists/dirb/common.txt")
.describe("Wordlist file path"),
method: z
.enum(["GET", "POST", "PUT", "DELETE", "PATCH"])
.default("GET")
.describe("HTTP method"),
headers: z
.record(z.string())
.optional()
.describe("Custom headers as key-value pairs"),
data: z
.string()
.optional()
.describe("POST data"),
match_codes: z
.string()
.default("200,204,301,302,307,401,403,405,500")
.describe("Match HTTP status codes"),
filter_codes: z
.string()
.optional()
.describe("Filter HTTP status codes"),
threads: z
.number()
.int()
.min(1)
.max(100)
.default(40)
.describe("Number of concurrent threads"),
timeout: z
.number()
.int()
.min(10)
.max(3600)
.default(600)
.describe("Scan timeout in seconds"),
});
export type FfufInput = z.infer<typeof FfufSchema>;
/**
* Nuclei scanner schema
*/
export const NucleiSchema = z.object({
target: z
.string()
.describe("Target URL or host"),
templates: z
.string()
.optional()
.describe("Template or template directory (default: all templates)"),
severity: z
.enum(["info", "low", "medium", "high", "critical"])
.optional()
.describe("Filter by severity"),
tags: z
.array(z.string())
.optional()
.describe("Filter by tags (e.g., ['cve', 'owasp'])"),
threads: z
.number()
.int()
.min(1)
.max(100)
.default(25)
.describe("Number of concurrent threads"),
timeout: z
.number()
.int()
.min(10)
.max(3600)
.default(600)
.describe("Scan timeout in seconds"),
});
export type NucleiInput = z.infer<typeof NucleiSchema>;