recker 1.0.43 → 1.0.44
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 +47 -0
- package/dist/bin/recker-linux-x64 +0 -0
- package/dist/bin/recker-macos-x64 +0 -0
- package/dist/bin/recker-win-x64.exe +0 -0
- package/dist/bin/rek.cjs +85152 -100207
- package/dist/browser/ai/adaptive-timeout.d.ts +50 -0
- package/dist/browser/ai/adaptive-timeout.js +208 -0
- package/dist/browser/ai/client.d.ts +22 -0
- package/dist/browser/ai/client.js +294 -0
- package/dist/browser/ai/index.d.ts +14 -0
- package/dist/browser/ai/index.js +11 -0
- package/dist/browser/ai/providers/anthropic.d.ts +63 -0
- package/dist/browser/ai/providers/anthropic.js +370 -0
- package/dist/browser/ai/providers/base.d.ts +48 -0
- package/dist/browser/ai/providers/base.js +150 -0
- package/dist/browser/ai/providers/google.d.ts +59 -0
- package/dist/browser/ai/providers/google.js +305 -0
- package/dist/browser/ai/providers/ollama.d.ts +44 -0
- package/dist/browser/ai/providers/ollama.js +240 -0
- package/dist/browser/ai/providers/openai.d.ts +64 -0
- package/dist/browser/ai/providers/openai.js +298 -0
- package/dist/browser/ai/rate-limiter.d.ts +43 -0
- package/dist/browser/ai/rate-limiter.js +215 -0
- package/dist/browser/ai/vector/index.d.ts +2 -0
- package/dist/browser/ai/vector/index.js +2 -0
- package/dist/browser/ai/vector/similarity.d.ts +2 -0
- package/dist/browser/ai/vector/similarity.js +27 -0
- package/dist/browser/ai/vector/store.d.ts +27 -0
- package/dist/browser/ai/vector/store.js +82 -0
- package/dist/browser/browser/cache.d.ts +2 -40
- package/dist/browser/browser/cache.js +2 -199
- package/dist/browser/browser/index.d.ts +8 -0
- package/dist/browser/browser/index.js +8 -0
- package/dist/browser/browser/recker.d.ts +8 -1
- package/dist/browser/browser/recker.js +8 -2
- package/dist/browser/cache/indexed-db.d.ts +10 -0
- package/dist/browser/cache/indexed-db.js +88 -0
- package/dist/browser/cache/service-worker-cache.d.ts +18 -0
- package/dist/browser/cache/service-worker-cache.js +103 -0
- package/dist/browser/cache.d.ts +2 -40
- package/dist/browser/cache.js +2 -199
- package/dist/browser/constants/user-agents.d.ts +7 -0
- package/dist/browser/constants/user-agents.js +7 -0
- package/dist/browser/core/client.d.ts +2 -0
- package/dist/browser/core/client.js +19 -1
- package/dist/browser/index.d.ts +8 -0
- package/dist/browser/index.js +8 -0
- package/dist/browser/plugins/har-recorder.d.ts +40 -0
- package/dist/browser/plugins/har-recorder.js +120 -0
- package/dist/browser/plugins/network-simulation.d.ts +7 -0
- package/dist/browser/plugins/network-simulation.js +13 -0
- package/dist/browser/presets/android.d.ts +2 -0
- package/dist/browser/presets/android.js +16 -0
- package/dist/browser/presets/anthropic.d.ts +8 -0
- package/dist/browser/presets/anthropic.js +27 -0
- package/dist/browser/presets/aws.d.ts +19 -0
- package/dist/browser/presets/aws.js +68 -0
- package/dist/browser/presets/azure-openai.d.ts +10 -0
- package/dist/browser/presets/azure-openai.js +35 -0
- package/dist/browser/presets/azure.d.ts +41 -0
- package/dist/browser/presets/azure.js +104 -0
- package/dist/browser/presets/chaturbate.d.ts +2 -0
- package/dist/browser/presets/chaturbate.js +17 -0
- package/dist/browser/presets/cloudflare.d.ts +12 -0
- package/dist/browser/presets/cloudflare.js +39 -0
- package/dist/browser/presets/cohere.d.ts +7 -0
- package/dist/browser/presets/cohere.js +22 -0
- package/dist/browser/presets/deepseek.d.ts +7 -0
- package/dist/browser/presets/deepseek.js +22 -0
- package/dist/browser/presets/digitalocean.d.ts +5 -0
- package/dist/browser/presets/digitalocean.js +16 -0
- package/dist/browser/presets/discord.d.ts +6 -0
- package/dist/browser/presets/discord.js +17 -0
- package/dist/browser/presets/elevenlabs.d.ts +6 -0
- package/dist/browser/presets/elevenlabs.js +20 -0
- package/dist/browser/presets/enhancers.d.ts +20 -0
- package/dist/browser/presets/enhancers.js +85 -0
- package/dist/browser/presets/fireworks.d.ts +7 -0
- package/dist/browser/presets/fireworks.js +22 -0
- package/dist/browser/presets/gcp.d.ts +34 -0
- package/dist/browser/presets/gcp.js +91 -0
- package/dist/browser/presets/gemini.d.ts +7 -0
- package/dist/browser/presets/gemini.js +23 -0
- package/dist/browser/presets/github.d.ts +6 -0
- package/dist/browser/presets/github.js +17 -0
- package/dist/browser/presets/gitlab.d.ts +6 -0
- package/dist/browser/presets/gitlab.js +16 -0
- package/dist/browser/presets/groq.d.ts +7 -0
- package/dist/browser/presets/groq.js +22 -0
- package/dist/browser/presets/hubspot.d.ts +9 -0
- package/dist/browser/presets/hubspot.js +28 -0
- package/dist/browser/presets/huggingface.d.ts +7 -0
- package/dist/browser/presets/huggingface.js +23 -0
- package/dist/browser/presets/index.d.ts +47 -0
- package/dist/browser/presets/index.js +47 -0
- package/dist/browser/presets/ios.d.ts +2 -0
- package/dist/browser/presets/ios.js +13 -0
- package/dist/browser/presets/linear.d.ts +5 -0
- package/dist/browser/presets/linear.js +16 -0
- package/dist/browser/presets/mailgun.d.ts +7 -0
- package/dist/browser/presets/mailgun.js +20 -0
- package/dist/browser/presets/meta.d.ts +10 -0
- package/dist/browser/presets/meta.js +33 -0
- package/dist/browser/presets/mistral.d.ts +7 -0
- package/dist/browser/presets/mistral.js +22 -0
- package/dist/browser/presets/notion.d.ts +6 -0
- package/dist/browser/presets/notion.js +17 -0
- package/dist/browser/presets/openai.d.ts +9 -0
- package/dist/browser/presets/openai.js +30 -0
- package/dist/browser/presets/oracle.d.ts +19 -0
- package/dist/browser/presets/oracle.js +117 -0
- package/dist/browser/presets/perplexity.d.ts +7 -0
- package/dist/browser/presets/perplexity.js +22 -0
- package/dist/browser/presets/pinecone.d.ts +8 -0
- package/dist/browser/presets/pinecone.js +42 -0
- package/dist/browser/presets/registry.d.ts +23 -0
- package/dist/browser/presets/registry.js +519 -0
- package/dist/browser/presets/replicate.d.ts +7 -0
- package/dist/browser/presets/replicate.js +23 -0
- package/dist/browser/presets/sendgrid.d.ts +6 -0
- package/dist/browser/presets/sendgrid.js +20 -0
- package/dist/browser/presets/sentry.d.ts +11 -0
- package/dist/browser/presets/sentry.js +48 -0
- package/dist/browser/presets/sinch.d.ts +9 -0
- package/dist/browser/presets/sinch.js +39 -0
- package/dist/browser/presets/slack.d.ts +5 -0
- package/dist/browser/presets/slack.js +16 -0
- package/dist/browser/presets/square.d.ts +10 -0
- package/dist/browser/presets/square.js +33 -0
- package/dist/browser/presets/stripe.d.ts +7 -0
- package/dist/browser/presets/stripe.js +23 -0
- package/dist/browser/presets/supabase.d.ts +6 -0
- package/dist/browser/presets/supabase.js +18 -0
- package/dist/browser/presets/tiktok.d.ts +10 -0
- package/dist/browser/presets/tiktok.js +38 -0
- package/dist/browser/presets/together.d.ts +7 -0
- package/dist/browser/presets/together.js +22 -0
- package/dist/browser/presets/twilio.d.ts +6 -0
- package/dist/browser/presets/twilio.js +17 -0
- package/dist/browser/presets/vercel.d.ts +6 -0
- package/dist/browser/presets/vercel.js +23 -0
- package/dist/browser/presets/vultr.d.ts +5 -0
- package/dist/browser/presets/vultr.js +16 -0
- package/dist/browser/presets/xai.d.ts +8 -0
- package/dist/browser/presets/xai.js +23 -0
- package/dist/browser/presets/youtube.d.ts +5 -0
- package/dist/browser/presets/youtube.js +20 -0
- package/dist/browser/recker.d.ts +8 -1
- package/dist/browser/recker.js +8 -2
- package/dist/browser/scrape/document.d.ts +5 -4
- package/dist/browser/scrape/document.js +89 -76
- package/dist/browser/scrape/element.d.ts +10 -8
- package/dist/browser/scrape/element.js +295 -81
- package/dist/browser/scrape/extractors.d.ts +11 -11
- package/dist/browser/scrape/extractors.js +145 -113
- package/dist/browser/scrape/parser/back.d.ts +1 -0
- package/dist/browser/scrape/parser/back.js +3 -0
- package/dist/browser/scrape/parser/index.d.ts +20 -0
- package/dist/browser/scrape/parser/index.js +19 -0
- package/dist/browser/scrape/parser/matcher.d.ts +30 -0
- package/dist/browser/scrape/parser/matcher.js +99 -0
- package/dist/browser/scrape/parser/nodes/comment.d.ts +12 -0
- package/dist/browser/scrape/parser/nodes/comment.js +21 -0
- package/dist/browser/scrape/parser/nodes/html.d.ts +110 -0
- package/dist/browser/scrape/parser/nodes/html.js +978 -0
- package/dist/browser/scrape/parser/nodes/node.d.ts +18 -0
- package/dist/browser/scrape/parser/nodes/node.js +31 -0
- package/dist/browser/scrape/parser/nodes/text.d.ts +14 -0
- package/dist/browser/scrape/parser/nodes/text.js +30 -0
- package/dist/browser/scrape/parser/nodes/type.d.ts +6 -0
- package/dist/browser/scrape/parser/nodes/type.js +7 -0
- package/dist/browser/scrape/parser/parse.d.ts +1 -0
- package/dist/browser/scrape/parser/parse.js +1 -0
- package/dist/browser/scrape/parser/valid.d.ts +2 -0
- package/dist/browser/scrape/parser/valid.js +5 -0
- package/dist/browser/scrape/parser/void-tag.d.ts +7 -0
- package/dist/browser/scrape/parser/void-tag.js +43 -0
- package/dist/browser/scrape/types.d.ts +7 -0
- package/dist/browser/seo/analyzer.d.ts +59 -0
- package/dist/browser/seo/analyzer.js +1399 -0
- package/dist/browser/seo/keywords.d.ts +16 -0
- package/dist/browser/seo/keywords.js +55 -0
- package/dist/browser/seo/rules/accessibility.d.ts +2 -0
- package/dist/browser/seo/rules/accessibility.js +733 -0
- package/dist/browser/seo/rules/ai-search.d.ts +2 -0
- package/dist/browser/seo/rules/ai-search.js +436 -0
- package/dist/browser/seo/rules/analytics.d.ts +2 -0
- package/dist/browser/seo/rules/analytics.js +306 -0
- package/dist/browser/seo/rules/best-practices.d.ts +2 -0
- package/dist/browser/seo/rules/best-practices.js +195 -0
- package/dist/browser/seo/rules/canonical.d.ts +12 -0
- package/dist/browser/seo/rules/canonical.js +270 -0
- package/dist/browser/seo/rules/content.d.ts +2 -0
- package/dist/browser/seo/rules/content.js +522 -0
- package/dist/browser/seo/rules/crawl.d.ts +2 -0
- package/dist/browser/seo/rules/crawl.js +435 -0
- package/dist/browser/seo/rules/cwv.d.ts +2 -0
- package/dist/browser/seo/rules/cwv.js +248 -0
- package/dist/browser/seo/rules/ecommerce.d.ts +2 -0
- package/dist/browser/seo/rules/ecommerce.js +312 -0
- package/dist/browser/seo/rules/i18n.d.ts +2 -0
- package/dist/browser/seo/rules/i18n.js +288 -0
- package/dist/browser/seo/rules/images.d.ts +2 -0
- package/dist/browser/seo/rules/images.js +255 -0
- package/dist/browser/seo/rules/index.d.ts +52 -0
- package/dist/browser/seo/rules/index.js +159 -0
- package/dist/browser/seo/rules/internal-linking.d.ts +2 -0
- package/dist/browser/seo/rules/internal-linking.js +394 -0
- package/dist/browser/seo/rules/links.d.ts +2 -0
- package/dist/browser/seo/rules/links.js +498 -0
- package/dist/browser/seo/rules/local.d.ts +2 -0
- package/dist/browser/seo/rules/local.js +289 -0
- package/dist/browser/seo/rules/meta.d.ts +2 -0
- package/dist/browser/seo/rules/meta.js +805 -0
- package/dist/browser/seo/rules/mobile.d.ts +2 -0
- package/dist/browser/seo/rules/mobile.js +161 -0
- package/dist/browser/seo/rules/performance.d.ts +2 -0
- package/dist/browser/seo/rules/performance.js +738 -0
- package/dist/browser/seo/rules/pwa.d.ts +2 -0
- package/dist/browser/seo/rules/pwa.js +299 -0
- package/dist/browser/seo/rules/readability.d.ts +2 -0
- package/dist/browser/seo/rules/readability.js +264 -0
- package/dist/browser/seo/rules/redirects.d.ts +16 -0
- package/dist/browser/seo/rules/redirects.js +199 -0
- package/dist/browser/seo/rules/resources.d.ts +2 -0
- package/dist/browser/seo/rules/resources.js +390 -0
- package/dist/browser/seo/rules/schema.d.ts +2 -0
- package/dist/browser/seo/rules/schema.js +379 -0
- package/dist/browser/seo/rules/security.d.ts +2 -0
- package/dist/browser/seo/rules/security.js +877 -0
- package/dist/browser/seo/rules/social.d.ts +2 -0
- package/dist/browser/seo/rules/social.js +603 -0
- package/dist/browser/seo/rules/structural.d.ts +2 -0
- package/dist/browser/seo/rules/structural.js +223 -0
- package/dist/browser/seo/rules/technical-advanced.d.ts +10 -0
- package/dist/browser/seo/rules/technical-advanced.js +289 -0
- package/dist/browser/seo/rules/technical.d.ts +2 -0
- package/dist/browser/seo/rules/technical.js +480 -0
- package/dist/browser/seo/rules/thresholds.d.ts +196 -0
- package/dist/browser/seo/rules/thresholds.js +118 -0
- package/dist/browser/seo/rules/types.d.ts +498 -0
- package/dist/browser/seo/rules/types.js +11 -0
- package/dist/browser/seo/types.d.ts +211 -0
- package/dist/browser/seo/types.js +1 -0
- package/dist/browser/transport/curl.d.ts +4 -0
- package/dist/browser/transport/curl.js +101 -0
- package/dist/browser/transport/undici.js +1 -2
- package/dist/browser/transport/worker.d.ts +18 -0
- package/dist/browser/transport/worker.js +278 -0
- package/dist/browser/types/index.d.ts +4 -1
- package/dist/browser/utils/binary-manager.d.ts +4 -0
- package/dist/browser/utils/binary-manager.js +72 -0
- package/dist/browser/utils/user-agent.js +2 -13
- package/dist/cache/indexed-db.d.ts +10 -0
- package/dist/cache/indexed-db.js +88 -0
- package/dist/cache/service-worker-cache.d.ts +18 -0
- package/dist/cache/service-worker-cache.js +103 -0
- package/dist/cli/commands/ai.d.ts +2 -0
- package/dist/cli/commands/ai.js +162 -0
- package/dist/cli/commands/bench.d.ts +2 -0
- package/dist/cli/commands/bench.js +51 -0
- package/dist/cli/commands/dns.d.ts +2 -0
- package/dist/cli/commands/dns.js +295 -0
- package/dist/cli/commands/har.d.ts +2 -0
- package/dist/cli/commands/har.js +171 -0
- package/dist/cli/commands/hls.d.ts +2 -0
- package/dist/cli/commands/hls.js +192 -0
- package/dist/cli/commands/network.d.ts +2 -0
- package/dist/cli/commands/network.js +288 -0
- package/dist/cli/commands/protocols.d.ts +2 -0
- package/dist/cli/commands/protocols.js +344 -0
- package/dist/cli/commands/scrape.d.ts +2 -0
- package/dist/cli/commands/scrape.js +176 -0
- package/dist/cli/commands/security.d.ts +2 -0
- package/dist/cli/commands/security.js +57 -0
- package/dist/cli/commands/seo.d.ts +2 -0
- package/dist/cli/commands/seo.js +125 -0
- package/dist/cli/commands/serve.d.ts +2 -0
- package/dist/cli/commands/serve.js +531 -0
- package/dist/cli/commands/spider.d.ts +3 -0
- package/dist/cli/commands/spider.js +456 -0
- package/dist/cli/commands/utils.d.ts +2 -0
- package/dist/cli/commands/utils.js +176 -0
- package/dist/cli/commands/vector.d.ts +2 -0
- package/dist/cli/commands/vector.js +158 -0
- package/dist/cli/handler.d.ts +2 -2
- package/dist/cli/handler.js +6 -6
- package/dist/cli/helpers.d.ts +7 -0
- package/dist/cli/helpers.js +128 -0
- package/dist/cli/index.js +96 -5228
- package/dist/cli/parser/help.d.ts +2 -0
- package/dist/cli/parser/help.js +52 -0
- package/dist/cli/parser/index.d.ts +3 -0
- package/dist/cli/parser/index.js +3 -0
- package/dist/cli/parser/parser.d.ts +4 -0
- package/dist/cli/parser/parser.js +146 -0
- package/dist/cli/parser/types.d.ts +41 -0
- package/dist/cli/parser/types.js +1 -0
- package/dist/cli/presets.d.ts +1 -1
- package/dist/cli/presets.js +1 -1
- package/dist/cli/router.d.ts +36 -0
- package/dist/cli/router.js +195 -0
- package/dist/cli/tui/ai-chat.js +1 -1
- package/dist/cli/tui/commands/context.d.ts +9 -0
- package/dist/cli/tui/commands/context.js +1 -0
- package/dist/cli/tui/commands/dns.d.ts +10 -0
- package/dist/cli/tui/commands/dns.js +461 -0
- package/dist/cli/tui/commands/hls.d.ts +2 -0
- package/dist/cli/tui/commands/hls.js +162 -0
- package/dist/cli/tui/commands/ip.d.ts +2 -0
- package/dist/cli/tui/commands/ip.js +45 -0
- package/dist/cli/tui/commands/network.d.ts +3 -0
- package/dist/cli/tui/commands/network.js +81 -0
- package/dist/cli/tui/commands/protocols.d.ts +6 -0
- package/dist/cli/tui/commands/protocols.js +531 -0
- package/dist/cli/tui/commands/security.d.ts +2 -0
- package/dist/cli/tui/commands/security.js +48 -0
- package/dist/cli/tui/commands/seo.d.ts +2 -0
- package/dist/cli/tui/commands/seo.js +74 -0
- package/dist/cli/tui/context.d.ts +12 -0
- package/dist/cli/tui/context.js +1 -0
- package/dist/cli/tui/shell.d.ts +11 -20
- package/dist/cli/tui/shell.js +216 -1873
- package/dist/constants/user-agents.d.ts +7 -0
- package/dist/constants/user-agents.js +7 -0
- package/dist/core/client.d.ts +2 -0
- package/dist/core/client.js +19 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/cli.js +2 -3
- package/dist/mcp/data/embeddings.json +1 -1
- package/dist/mcp/tools/network.js +298 -158
- package/dist/plugins/har-player.d.ts +23 -0
- package/dist/plugins/har-player.js +49 -0
- package/dist/plugins/har-recorder.d.ts +37 -3
- package/dist/plugins/har-recorder.js +116 -63
- package/dist/plugins/network-simulation.d.ts +7 -0
- package/dist/plugins/network-simulation.js +13 -0
- package/dist/presets/android.d.ts +2 -0
- package/dist/presets/android.js +16 -0
- package/dist/presets/chaturbate.d.ts +2 -0
- package/dist/presets/chaturbate.js +17 -0
- package/dist/presets/elevenlabs.d.ts +6 -0
- package/dist/presets/elevenlabs.js +20 -0
- package/dist/presets/enhancers.d.ts +20 -0
- package/dist/presets/enhancers.js +85 -0
- package/dist/presets/hubspot.d.ts +9 -0
- package/dist/presets/hubspot.js +28 -0
- package/dist/presets/index.d.ts +10 -0
- package/dist/presets/index.js +10 -0
- package/dist/presets/ios.d.ts +2 -0
- package/dist/presets/ios.js +13 -0
- package/dist/presets/pinecone.d.ts +8 -0
- package/dist/presets/pinecone.js +42 -0
- package/dist/presets/registry.js +60 -0
- package/dist/presets/sendgrid.d.ts +6 -0
- package/dist/presets/sendgrid.js +20 -0
- package/dist/presets/sentry.d.ts +11 -0
- package/dist/presets/sentry.js +48 -0
- package/dist/presets/square.d.ts +10 -0
- package/dist/presets/square.js +33 -0
- package/dist/recker.d.ts +3 -0
- package/dist/recker.js +4 -0
- package/dist/scrape/document.d.ts +5 -4
- package/dist/scrape/document.js +89 -76
- package/dist/scrape/element.d.ts +10 -8
- package/dist/scrape/element.js +295 -81
- package/dist/scrape/extractors.d.ts +11 -11
- package/dist/scrape/extractors.js +145 -113
- package/dist/scrape/index.d.ts +2 -0
- package/dist/scrape/index.js +1 -0
- package/dist/scrape/parser/back.d.ts +1 -0
- package/dist/scrape/parser/back.js +3 -0
- package/dist/scrape/parser/index.d.ts +20 -0
- package/dist/scrape/parser/index.js +19 -0
- package/dist/scrape/parser/matcher.d.ts +30 -0
- package/dist/scrape/parser/matcher.js +99 -0
- package/dist/scrape/parser/nodes/comment.d.ts +12 -0
- package/dist/scrape/parser/nodes/comment.js +21 -0
- package/dist/scrape/parser/nodes/html.d.ts +110 -0
- package/dist/scrape/parser/nodes/html.js +978 -0
- package/dist/scrape/parser/nodes/node.d.ts +18 -0
- package/dist/scrape/parser/nodes/node.js +31 -0
- package/dist/scrape/parser/nodes/text.d.ts +14 -0
- package/dist/scrape/parser/nodes/text.js +30 -0
- package/dist/scrape/parser/nodes/type.d.ts +6 -0
- package/dist/scrape/parser/nodes/type.js +7 -0
- package/dist/scrape/parser/parse.d.ts +1 -0
- package/dist/scrape/parser/parse.js +1 -0
- package/dist/scrape/parser/valid.d.ts +2 -0
- package/dist/scrape/parser/valid.js +5 -0
- package/dist/scrape/parser/void-tag.d.ts +7 -0
- package/dist/scrape/parser/void-tag.js +43 -0
- package/dist/scrape/spider.d.ts +19 -0
- package/dist/scrape/spider.js +28 -3
- package/dist/scrape/types.d.ts +7 -0
- package/dist/seo/analyzer.d.ts +15 -5
- package/dist/seo/analyzer.js +636 -175
- package/dist/seo/formatter.d.ts +16 -0
- package/dist/seo/formatter.js +228 -0
- package/dist/seo/index.d.ts +2 -0
- package/dist/seo/index.js +1 -0
- package/dist/seo/keywords.d.ts +16 -0
- package/dist/seo/keywords.js +55 -0
- package/dist/seo/rules/accessibility.js +96 -57
- package/dist/seo/rules/ai-search.js +44 -31
- package/dist/seo/rules/analytics.d.ts +2 -0
- package/dist/seo/rules/analytics.js +306 -0
- package/dist/seo/rules/best-practices.js +21 -14
- package/dist/seo/rules/canonical.js +53 -32
- package/dist/seo/rules/content.js +317 -31
- package/dist/seo/rules/crawl.js +55 -40
- package/dist/seo/rules/cwv.js +21 -15
- package/dist/seo/rules/ecommerce.js +82 -22
- package/dist/seo/rules/i18n.js +75 -36
- package/dist/seo/rules/images.js +109 -30
- package/dist/seo/rules/index.js +2 -0
- package/dist/seo/rules/internal-linking.js +58 -39
- package/dist/seo/rules/links.js +79 -52
- package/dist/seo/rules/local.js +49 -25
- package/dist/seo/rules/meta.js +339 -81
- package/dist/seo/rules/mobile.js +112 -2
- package/dist/seo/rules/performance.js +434 -66
- package/dist/seo/rules/pwa.js +36 -39
- package/dist/seo/rules/readability.js +31 -22
- package/dist/seo/rules/redirects.js +21 -15
- package/dist/seo/rules/resources.js +59 -42
- package/dist/seo/rules/schema.js +333 -8
- package/dist/seo/rules/security.js +142 -80
- package/dist/seo/rules/social.js +277 -47
- package/dist/seo/rules/structural.js +87 -19
- package/dist/seo/rules/technical-advanced.js +30 -24
- package/dist/seo/rules/technical.js +243 -42
- package/dist/seo/rules/types.d.ts +53 -1
- package/dist/seo/seo-spider.d.ts +22 -0
- package/dist/seo/seo-spider.js +77 -13
- package/dist/seo/types.d.ts +8 -1
- package/dist/seo/validators/llms-txt.js +19 -0
- package/dist/seo/validators/rss.d.ts +11 -0
- package/dist/seo/validators/rss.js +93 -0
- package/dist/seo/validators/sitemap.js +36 -26
- package/dist/transport/curl.d.ts +4 -0
- package/dist/transport/curl.js +101 -0
- package/dist/transport/udp.js +0 -1
- package/dist/transport/undici.js +1 -2
- package/dist/transport/worker.d.ts +18 -0
- package/dist/transport/worker.js +278 -0
- package/dist/types/index.d.ts +4 -1
- package/dist/utils/binary-manager.d.ts +4 -0
- package/dist/utils/binary-manager.js +72 -0
- package/dist/utils/optional-require.d.ts +7 -8
- package/dist/utils/optional-require.js +2 -21
- package/dist/utils/upload.d.ts +6 -0
- package/dist/utils/upload.js +11 -0
- package/dist/utils/user-agent.js +2 -13
- package/dist/version.js +1 -1
- package/package.json +12 -6
- package/dist/browser/utils/optional-require.d.ts +0 -19
- package/dist/browser/utils/optional-require.js +0 -105
|
@@ -21,7 +21,7 @@ export const securityRules = [
|
|
|
21
21
|
if (ctx.isHttps === true) {
|
|
22
22
|
return createResult({ id: 'https-required', name: 'HTTPS', category: 'security', severity: 'error' }, 'pass', 'Page is served over HTTPS');
|
|
23
23
|
}
|
|
24
|
-
return
|
|
24
|
+
return createResult({ id: 'https-required', name: 'HTTPS', category: 'security', severity: 'error' }, 'info', 'Not applicable (HTTPS status unavailable)', { recommendation: 'This rule checks if the page is served over HTTPS when protocol information is available' });
|
|
25
25
|
},
|
|
26
26
|
},
|
|
27
27
|
{
|
|
@@ -42,7 +42,7 @@ export const securityRules = [
|
|
|
42
42
|
},
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
return
|
|
45
|
+
return createResult({ id: 'mixed-content', name: 'Mixed Content', category: 'security', severity: 'error' }, 'info', 'Not applicable (no mixed content detected or HTTPS not used)', { recommendation: 'This rule checks for HTTP resources on HTTPS pages when mixed content is detected' });
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
48
|
{
|
|
@@ -52,8 +52,9 @@ export const securityRules = [
|
|
|
52
52
|
severity: 'warning',
|
|
53
53
|
description: 'HTTP traffic should redirect to HTTPS',
|
|
54
54
|
check: (ctx) => {
|
|
55
|
-
if (ctx.httpRedirectsToHttps === undefined)
|
|
56
|
-
return
|
|
55
|
+
if (ctx.httpRedirectsToHttps === undefined) {
|
|
56
|
+
return createResult({ id: 'http-redirect', name: 'HTTP to HTTPS Redirect', category: 'security', severity: 'warning' }, 'info', 'Not applicable (HTTP redirect status unavailable)', { recommendation: 'This rule checks if HTTP traffic redirects to HTTPS when redirect information is available' });
|
|
57
|
+
}
|
|
57
58
|
if (!ctx.httpRedirectsToHttps) {
|
|
58
59
|
return createResult({ id: 'http-redirect', name: 'HTTP to HTTPS Redirect', category: 'security', severity: 'warning' }, 'warn', 'HTTP does not redirect to HTTPS', {
|
|
59
60
|
recommendation: 'Configure server to redirect all HTTP traffic to HTTPS',
|
|
@@ -67,6 +68,32 @@ export const securityRules = [
|
|
|
67
68
|
return createResult({ id: 'http-redirect', name: 'HTTP to HTTPS Redirect', category: 'security', severity: 'warning' }, 'pass', 'HTTP redirects to HTTPS');
|
|
68
69
|
},
|
|
69
70
|
},
|
|
71
|
+
{
|
|
72
|
+
id: 'internal-links-https',
|
|
73
|
+
name: 'Internal Links Use HTTPS',
|
|
74
|
+
category: 'security',
|
|
75
|
+
severity: 'warning',
|
|
76
|
+
description: 'Internal links should use HTTPS to avoid mixed content and redirect chains',
|
|
77
|
+
check: (ctx) => {
|
|
78
|
+
if (ctx.internalHttpLinks === undefined) {
|
|
79
|
+
return createResult({ id: 'internal-links-https', name: 'Internal Links Use HTTPS', category: 'security', severity: 'warning' }, 'info', 'Not applicable (internal link data unavailable)', { recommendation: 'This rule checks internal links for HTTPS usage when link analysis is available' });
|
|
80
|
+
}
|
|
81
|
+
if (ctx.internalHttpLinks > 0) {
|
|
82
|
+
const examples = ctx.internalHttpLinkUrls?.slice(0, 3) || [];
|
|
83
|
+
return createResult({ id: 'internal-links-https', name: 'Internal Links Use HTTPS', category: 'security', severity: 'warning' }, 'warn', `${ctx.internalHttpLinks} internal link(s) use HTTP instead of HTTPS`, {
|
|
84
|
+
value: ctx.internalHttpLinks,
|
|
85
|
+
recommendation: 'Update all internal links to use HTTPS URLs',
|
|
86
|
+
evidence: {
|
|
87
|
+
found: `${ctx.internalHttpLinks} HTTP internal links${examples.length > 0 ? `: ${examples.join(', ')}` : ''}`,
|
|
88
|
+
expected: 'All internal links should use HTTPS',
|
|
89
|
+
impact: 'HTTP links cause unnecessary redirects, slow page loads, and may trigger mixed content warnings. Search engines prefer sites with consistent HTTPS usage.',
|
|
90
|
+
learnMore: 'https://web.dev/why-https-matters/',
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return createResult({ id: 'internal-links-https', name: 'Internal Links Use HTTPS', category: 'security', severity: 'warning' }, 'pass', 'All internal links use HTTPS');
|
|
95
|
+
},
|
|
96
|
+
},
|
|
70
97
|
{
|
|
71
98
|
id: 'security-csp-exists',
|
|
72
99
|
name: 'Content Security Policy (CSP)',
|
|
@@ -74,8 +101,9 @@ export const securityRules = [
|
|
|
74
101
|
severity: 'warning',
|
|
75
102
|
description: 'Content Security Policy header should be present to mitigate XSS attacks.',
|
|
76
103
|
check: (ctx) => {
|
|
77
|
-
if (!ctx.responseHeaders)
|
|
78
|
-
return
|
|
104
|
+
if (!ctx.responseHeaders) {
|
|
105
|
+
return createResult({ id: 'security-csp-exists', name: 'Content Security Policy', category: 'security', severity: 'warning' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for CSP headers when HTTP response headers are available' });
|
|
106
|
+
}
|
|
79
107
|
const cspHeader = ctx.responseHeaders['content-security-policy'] || ctx.responseHeaders['Content-Security-Policy'];
|
|
80
108
|
if (!cspHeader) {
|
|
81
109
|
return createResult({ id: 'security-csp-exists', name: 'Content Security Policy', category: 'security', severity: 'warning' }, 'warn', 'Content-Security-Policy header is missing', {
|
|
@@ -97,11 +125,13 @@ export const securityRules = [
|
|
|
97
125
|
severity: 'warning',
|
|
98
126
|
description: 'CSP should be effective against XSS attacks',
|
|
99
127
|
check: (ctx) => {
|
|
100
|
-
if (!ctx.responseHeaders)
|
|
101
|
-
return
|
|
128
|
+
if (!ctx.responseHeaders) {
|
|
129
|
+
return createResult({ id: 'security-csp-xss-effective', name: 'CSP XSS Effectiveness', category: 'security', severity: 'warning' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks CSP effectiveness when HTTP response headers are available' });
|
|
130
|
+
}
|
|
102
131
|
const cspHeader = ctx.responseHeaders['content-security-policy'] || ctx.responseHeaders['Content-Security-Policy'];
|
|
103
|
-
if (!cspHeader)
|
|
104
|
-
return
|
|
132
|
+
if (!cspHeader) {
|
|
133
|
+
return createResult({ id: 'security-csp-xss-effective', name: 'CSP XSS Effectiveness', category: 'security', severity: 'warning' }, 'info', 'Not applicable (CSP header not present)', { recommendation: 'This rule checks CSP effectiveness when a Content-Security-Policy header exists' });
|
|
134
|
+
}
|
|
105
135
|
const csp = String(cspHeader).toLowerCase();
|
|
106
136
|
const weaknesses = [];
|
|
107
137
|
if (csp.includes("'unsafe-inline'") && !csp.includes("'strict-dynamic'") && !csp.includes("'nonce-")) {
|
|
@@ -137,11 +167,13 @@ export const securityRules = [
|
|
|
137
167
|
severity: 'error',
|
|
138
168
|
description: 'CSP should have script-src and object-src directives to prevent unsafe script execution',
|
|
139
169
|
check: (ctx) => {
|
|
140
|
-
if (!ctx.responseHeaders)
|
|
141
|
-
return
|
|
170
|
+
if (!ctx.responseHeaders) {
|
|
171
|
+
return createResult({ id: 'security-csp-directives', name: 'CSP Required Directives', category: 'security', severity: 'error' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks CSP directives when HTTP response headers are available' });
|
|
172
|
+
}
|
|
142
173
|
const cspHeader = ctx.responseHeaders['content-security-policy'] || ctx.responseHeaders['Content-Security-Policy'];
|
|
143
|
-
if (!cspHeader)
|
|
144
|
-
return
|
|
174
|
+
if (!cspHeader) {
|
|
175
|
+
return createResult({ id: 'security-csp-directives', name: 'CSP Required Directives', category: 'security', severity: 'error' }, 'info', 'Not applicable (CSP header not present)', { recommendation: 'This rule checks CSP directives when a Content-Security-Policy header exists' });
|
|
176
|
+
}
|
|
145
177
|
const csp = String(cspHeader).toLowerCase();
|
|
146
178
|
const missingDirectives = [];
|
|
147
179
|
if (!csp.includes('script-src') && !csp.includes('default-src')) {
|
|
@@ -196,8 +228,9 @@ export const securityRules = [
|
|
|
196
228
|
severity: 'warning',
|
|
197
229
|
description: 'HSTS header forces secure connections and improves SEO indirectly.',
|
|
198
230
|
check: (ctx) => {
|
|
199
|
-
if (!ctx.responseHeaders)
|
|
200
|
-
return
|
|
231
|
+
if (!ctx.responseHeaders) {
|
|
232
|
+
return createResult({ id: 'security-hsts-exists', name: 'HSTS Header', category: 'security', severity: 'warning' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for HSTS headers when HTTP response headers are available' });
|
|
233
|
+
}
|
|
201
234
|
const hstsHeader = ctx.responseHeaders['strict-transport-security'] || ctx.responseHeaders['Strict-Transport-Security'];
|
|
202
235
|
if (!hstsHeader) {
|
|
203
236
|
return createResult({ id: 'security-hsts-exists', name: 'HSTS Header', category: 'security', severity: 'warning' }, 'warn', 'Strict-Transport-Security header is missing', {
|
|
@@ -219,11 +252,13 @@ export const securityRules = [
|
|
|
219
252
|
severity: 'info',
|
|
220
253
|
description: 'HSTS should have a strong policy with long max-age and includeSubDomains',
|
|
221
254
|
check: (ctx) => {
|
|
222
|
-
if (!ctx.responseHeaders)
|
|
223
|
-
return
|
|
255
|
+
if (!ctx.responseHeaders) {
|
|
256
|
+
return createResult({ id: 'security-hsts-strong', name: 'Strong HSTS Policy', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks HSTS policy strength when HTTP response headers are available' });
|
|
257
|
+
}
|
|
224
258
|
const hstsHeader = ctx.responseHeaders['strict-transport-security'] || ctx.responseHeaders['Strict-Transport-Security'];
|
|
225
|
-
if (!hstsHeader)
|
|
226
|
-
return
|
|
259
|
+
if (!hstsHeader) {
|
|
260
|
+
return createResult({ id: 'security-hsts-strong', name: 'Strong HSTS Policy', category: 'security', severity: 'info' }, 'info', 'Not applicable (HSTS header not present)', { recommendation: 'This rule checks HSTS policy strength when a Strict-Transport-Security header exists' });
|
|
261
|
+
}
|
|
227
262
|
const hsts = String(hstsHeader).toLowerCase();
|
|
228
263
|
const weaknesses = [];
|
|
229
264
|
const maxAgeMatch = hsts.match(/max-age\s*=\s*(\d+)/);
|
|
@@ -258,8 +293,9 @@ export const securityRules = [
|
|
|
258
293
|
severity: 'info',
|
|
259
294
|
description: 'COOP ensures proper origin isolation for security',
|
|
260
295
|
check: (ctx) => {
|
|
261
|
-
if (!ctx.responseHeaders)
|
|
262
|
-
return
|
|
296
|
+
if (!ctx.responseHeaders) {
|
|
297
|
+
return createResult({ id: 'security-coop', name: 'Cross-Origin-Opener-Policy', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for COOP headers when HTTP response headers are available' });
|
|
298
|
+
}
|
|
263
299
|
const coopHeader = ctx.responseHeaders['cross-origin-opener-policy'] || ctx.responseHeaders['Cross-Origin-Opener-Policy'];
|
|
264
300
|
if (!coopHeader) {
|
|
265
301
|
return createResult({ id: 'security-coop', name: 'Cross-Origin-Opener-Policy', category: 'security', severity: 'info' }, 'info', 'Cross-Origin-Opener-Policy header is missing', {
|
|
@@ -289,8 +325,9 @@ export const securityRules = [
|
|
|
289
325
|
severity: 'info',
|
|
290
326
|
description: 'COEP prevents loading cross-origin resources without explicit permission',
|
|
291
327
|
check: (ctx) => {
|
|
292
|
-
if (!ctx.responseHeaders)
|
|
293
|
-
return
|
|
328
|
+
if (!ctx.responseHeaders) {
|
|
329
|
+
return createResult({ id: 'security-coep', name: 'Cross-Origin-Embedder-Policy', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for COEP headers when HTTP response headers are available' });
|
|
330
|
+
}
|
|
294
331
|
const coepHeader = ctx.responseHeaders['cross-origin-embedder-policy'] || ctx.responseHeaders['Cross-Origin-Embedder-Policy'];
|
|
295
332
|
if (!coepHeader) {
|
|
296
333
|
return createResult({ id: 'security-coep', name: 'Cross-Origin-Embedder-Policy', category: 'security', severity: 'info' }, 'info', 'Cross-Origin-Embedder-Policy header is missing', {
|
|
@@ -312,11 +349,13 @@ export const securityRules = [
|
|
|
312
349
|
severity: 'info',
|
|
313
350
|
description: 'Trusted Types help prevent DOM-based XSS attacks',
|
|
314
351
|
check: (ctx) => {
|
|
315
|
-
if (!ctx.responseHeaders)
|
|
316
|
-
return
|
|
352
|
+
if (!ctx.responseHeaders) {
|
|
353
|
+
return createResult({ id: 'security-trusted-types', name: 'Trusted Types', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for Trusted Types in CSP when HTTP response headers are available' });
|
|
354
|
+
}
|
|
317
355
|
const cspHeader = ctx.responseHeaders['content-security-policy'] || ctx.responseHeaders['Content-Security-Policy'];
|
|
318
|
-
if (!cspHeader)
|
|
319
|
-
return
|
|
356
|
+
if (!cspHeader) {
|
|
357
|
+
return createResult({ id: 'security-trusted-types', name: 'Trusted Types', category: 'security', severity: 'info' }, 'info', 'Not applicable (CSP header not present)', { recommendation: 'This rule checks for Trusted Types when a Content-Security-Policy header exists' });
|
|
358
|
+
}
|
|
320
359
|
const csp = String(cspHeader).toLowerCase();
|
|
321
360
|
if (csp.includes('require-trusted-types-for')) {
|
|
322
361
|
return createResult({ id: 'security-trusted-types', name: 'Trusted Types', category: 'security', severity: 'info' }, 'pass', 'Trusted Types policy enabled via CSP');
|
|
@@ -338,8 +377,9 @@ export const securityRules = [
|
|
|
338
377
|
severity: 'warning',
|
|
339
378
|
description: 'X-Frame-Options header should be present to prevent clickjacking.',
|
|
340
379
|
check: (ctx) => {
|
|
341
|
-
if (!ctx.responseHeaders)
|
|
342
|
-
return
|
|
380
|
+
if (!ctx.responseHeaders) {
|
|
381
|
+
return createResult({ id: 'security-xfo-exists', name: 'X-Frame-Options', category: 'security', severity: 'warning' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for X-Frame-Options headers when HTTP response headers are available' });
|
|
382
|
+
}
|
|
343
383
|
const xfoHeader = ctx.responseHeaders['x-frame-options'] || ctx.responseHeaders['X-Frame-Options'];
|
|
344
384
|
if (!xfoHeader) {
|
|
345
385
|
return createResult({ id: 'security-xfo-exists', name: 'X-Frame-Options', category: 'security', severity: 'warning' }, 'warn', 'X-Frame-Options header is missing', {
|
|
@@ -361,12 +401,14 @@ export const securityRules = [
|
|
|
361
401
|
severity: 'info',
|
|
362
402
|
description: 'CSP frame-ancestors is the modern replacement for X-Frame-Options',
|
|
363
403
|
check: (ctx) => {
|
|
364
|
-
if (!ctx.responseHeaders)
|
|
365
|
-
return
|
|
404
|
+
if (!ctx.responseHeaders) {
|
|
405
|
+
return createResult({ id: 'security-frame-ancestors', name: 'CSP frame-ancestors', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for CSP frame-ancestors when HTTP response headers are available' });
|
|
406
|
+
}
|
|
366
407
|
const cspHeader = ctx.responseHeaders['content-security-policy'] || ctx.responseHeaders['Content-Security-Policy'];
|
|
367
408
|
const xfoHeader = ctx.responseHeaders['x-frame-options'] || ctx.responseHeaders['X-Frame-Options'];
|
|
368
|
-
if (!cspHeader && !xfoHeader)
|
|
369
|
-
return
|
|
409
|
+
if (!cspHeader && !xfoHeader) {
|
|
410
|
+
return createResult({ id: 'security-frame-ancestors', name: 'CSP frame-ancestors', category: 'security', severity: 'info' }, 'info', 'Not applicable (neither CSP nor X-Frame-Options present)', { recommendation: 'This rule checks CSP frame-ancestors when clickjacking protection headers are present' });
|
|
411
|
+
}
|
|
370
412
|
if (cspHeader && String(cspHeader).toLowerCase().includes('frame-ancestors')) {
|
|
371
413
|
return createResult({ id: 'security-frame-ancestors', name: 'CSP frame-ancestors', category: 'security', severity: 'info' }, 'pass', 'CSP frame-ancestors directive present (modern clickjacking protection)');
|
|
372
414
|
}
|
|
@@ -380,7 +422,7 @@ export const securityRules = [
|
|
|
380
422
|
},
|
|
381
423
|
});
|
|
382
424
|
}
|
|
383
|
-
return
|
|
425
|
+
return createResult({ id: 'security-frame-ancestors', name: 'CSP frame-ancestors', category: 'security', severity: 'info' }, 'info', 'Not applicable (clickjacking protection configured without frame-ancestors)', { recommendation: 'This rule checks modern frame-ancestors directive in CSP for enhanced clickjacking protection' });
|
|
384
426
|
},
|
|
385
427
|
},
|
|
386
428
|
{
|
|
@@ -390,8 +432,9 @@ export const securityRules = [
|
|
|
390
432
|
severity: 'warning',
|
|
391
433
|
description: 'Review Access-Control-Allow-Origin header for proper CORS configuration.',
|
|
392
434
|
check: (ctx) => {
|
|
393
|
-
if (!ctx.responseHeaders)
|
|
394
|
-
return
|
|
435
|
+
if (!ctx.responseHeaders) {
|
|
436
|
+
return createResult({ id: 'security-cors-config', name: 'CORS Configuration', category: 'security', severity: 'warning' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks CORS configuration when HTTP response headers are available' });
|
|
437
|
+
}
|
|
395
438
|
const acaoHeader = ctx.responseHeaders['access-control-allow-origin'] || ctx.responseHeaders['Access-Control-Allow-Origin'];
|
|
396
439
|
if (acaoHeader === '*') {
|
|
397
440
|
return createResult({ id: 'security-cors-config', name: 'CORS Configuration', category: 'security', severity: 'warning' }, 'warn', 'Access-Control-Allow-Origin is set to "*"', {
|
|
@@ -416,8 +459,9 @@ export const securityRules = [
|
|
|
416
459
|
severity: 'warning',
|
|
417
460
|
description: 'X-Content-Type-Options header prevents MIME sniffing attacks.',
|
|
418
461
|
check: (ctx) => {
|
|
419
|
-
if (!ctx.responseHeaders)
|
|
420
|
-
return
|
|
462
|
+
if (!ctx.responseHeaders) {
|
|
463
|
+
return createResult({ id: 'security-xcto-exists', name: 'X-Content-Type-Options', category: 'security', severity: 'warning' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for X-Content-Type-Options headers when HTTP response headers are available' });
|
|
464
|
+
}
|
|
421
465
|
const xctoHeader = ctx.responseHeaders['x-content-type-options'] || ctx.responseHeaders['X-Content-Type-Options'];
|
|
422
466
|
if (!xctoHeader) {
|
|
423
467
|
return createResult({ id: 'security-xcto-exists', name: 'X-Content-Type-Options', category: 'security', severity: 'warning' }, 'warn', 'X-Content-Type-Options header is missing', {
|
|
@@ -438,8 +482,9 @@ export const securityRules = [
|
|
|
438
482
|
severity: 'info',
|
|
439
483
|
description: 'Referrer-Policy controls how much referrer information is sent with requests.',
|
|
440
484
|
check: (ctx) => {
|
|
441
|
-
if (!ctx.responseHeaders)
|
|
442
|
-
return
|
|
485
|
+
if (!ctx.responseHeaders) {
|
|
486
|
+
return createResult({ id: 'security-rp-exists', name: 'Referrer-Policy', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for Referrer-Policy headers when HTTP response headers are available' });
|
|
487
|
+
}
|
|
443
488
|
const rpHeader = ctx.responseHeaders['referrer-policy'] || ctx.responseHeaders['Referrer-Policy'];
|
|
444
489
|
if (!rpHeader) {
|
|
445
490
|
return createResult({ id: 'security-rp-exists', name: 'Referrer-Policy', category: 'security', severity: 'info' }, 'info', 'Referrer-Policy header is missing', {
|
|
@@ -460,8 +505,9 @@ export const securityRules = [
|
|
|
460
505
|
severity: 'info',
|
|
461
506
|
description: 'Permissions-Policy controls browser features available to the page.',
|
|
462
507
|
check: (ctx) => {
|
|
463
|
-
if (!ctx.responseHeaders)
|
|
464
|
-
return
|
|
508
|
+
if (!ctx.responseHeaders) {
|
|
509
|
+
return createResult({ id: 'security-pp-exists', name: 'Permissions-Policy', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for Permissions-Policy headers when HTTP response headers are available' });
|
|
510
|
+
}
|
|
465
511
|
const ppHeader = ctx.responseHeaders['permissions-policy'] || ctx.responseHeaders['Permissions-Policy'];
|
|
466
512
|
if (!ppHeader) {
|
|
467
513
|
return createResult({ id: 'security-pp-exists', name: 'Permissions-Policy', category: 'security', severity: 'info' }, 'info', 'Permissions-Policy header is missing', {
|
|
@@ -482,8 +528,9 @@ export const securityRules = [
|
|
|
482
528
|
severity: 'info',
|
|
483
529
|
description: 'X-XSS-Protection is deprecated but may still provide protection in older browsers',
|
|
484
530
|
check: (ctx) => {
|
|
485
|
-
if (!ctx.responseHeaders)
|
|
486
|
-
return
|
|
531
|
+
if (!ctx.responseHeaders) {
|
|
532
|
+
return createResult({ id: 'security-xxss', name: 'X-XSS-Protection', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for deprecated X-XSS-Protection headers when HTTP response headers are available' });
|
|
533
|
+
}
|
|
487
534
|
const xxssHeader = ctx.responseHeaders['x-xss-protection'] || ctx.responseHeaders['X-XSS-Protection'];
|
|
488
535
|
if (xxssHeader && String(xxssHeader).includes('1')) {
|
|
489
536
|
return createResult({ id: 'security-xxss', name: 'X-XSS-Protection', category: 'security', severity: 'info' }, 'info', 'X-XSS-Protection is enabled but deprecated', {
|
|
@@ -496,7 +543,7 @@ export const securityRules = [
|
|
|
496
543
|
},
|
|
497
544
|
});
|
|
498
545
|
}
|
|
499
|
-
return
|
|
546
|
+
return createResult({ id: 'security-xxss', name: 'X-XSS-Protection', category: 'security', severity: 'info' }, 'info', 'Not applicable (X-XSS-Protection not present or disabled)', { recommendation: 'This rule checks for deprecated X-XSS-Protection headers when present' });
|
|
500
547
|
},
|
|
501
548
|
},
|
|
502
549
|
{
|
|
@@ -506,8 +553,9 @@ export const securityRules = [
|
|
|
506
553
|
severity: 'info',
|
|
507
554
|
description: 'CORP restricts which origins can load your resources',
|
|
508
555
|
check: (ctx) => {
|
|
509
|
-
if (!ctx.responseHeaders)
|
|
510
|
-
return
|
|
556
|
+
if (!ctx.responseHeaders) {
|
|
557
|
+
return createResult({ id: 'security-corp', name: 'Cross-Origin-Resource-Policy', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for CORP headers when HTTP response headers are available' });
|
|
558
|
+
}
|
|
511
559
|
const corpHeader = ctx.responseHeaders['cross-origin-resource-policy'] || ctx.responseHeaders['Cross-Origin-Resource-Policy'];
|
|
512
560
|
if (!corpHeader) {
|
|
513
561
|
return createResult({ id: 'security-corp', name: 'Cross-Origin-Resource-Policy', category: 'security', severity: 'info' }, 'info', 'Cross-Origin-Resource-Policy header is missing', {
|
|
@@ -529,8 +577,9 @@ export const securityRules = [
|
|
|
529
577
|
severity: 'error',
|
|
530
578
|
description: 'SSL certificate must be valid and not expired',
|
|
531
579
|
check: (ctx) => {
|
|
532
|
-
if (ctx.sslCertificate === undefined)
|
|
533
|
-
return
|
|
580
|
+
if (ctx.sslCertificate === undefined) {
|
|
581
|
+
return createResult({ id: 'security-ssl-valid', name: 'SSL Certificate Valid', category: 'security', severity: 'error' }, 'info', 'Not applicable (SSL certificate information unavailable)', { recommendation: 'This rule checks SSL certificate validity when certificate information is available' });
|
|
582
|
+
}
|
|
534
583
|
if (!ctx.sslCertificate.valid) {
|
|
535
584
|
return createResult({ id: 'security-ssl-valid', name: 'SSL Certificate Valid', category: 'security', severity: 'error' }, 'fail', 'SSL certificate is invalid', {
|
|
536
585
|
recommendation: 'Renew or replace the SSL certificate immediately',
|
|
@@ -550,8 +599,9 @@ export const securityRules = [
|
|
|
550
599
|
severity: 'warning',
|
|
551
600
|
description: 'SSL certificate should not expire within 30 days',
|
|
552
601
|
check: (ctx) => {
|
|
553
|
-
if (!ctx.sslCertificate?.expiryDate)
|
|
554
|
-
return
|
|
602
|
+
if (!ctx.sslCertificate?.expiryDate) {
|
|
603
|
+
return createResult({ id: 'security-ssl-expiry', name: 'SSL Certificate Expiry', category: 'security', severity: 'warning' }, 'info', 'Not applicable (SSL certificate expiry date unavailable)', { recommendation: 'This rule checks SSL certificate expiration when certificate expiry information is available' });
|
|
604
|
+
}
|
|
555
605
|
const expiryDate = new Date(ctx.sslCertificate.expiryDate);
|
|
556
606
|
const now = new Date();
|
|
557
607
|
const daysUntilExpiry = Math.floor((expiryDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
|
@@ -591,8 +641,9 @@ export const securityRules = [
|
|
|
591
641
|
severity: 'error',
|
|
592
642
|
description: 'SSL certificate CN/SAN must match the domain',
|
|
593
643
|
check: (ctx) => {
|
|
594
|
-
if (ctx.sslCertificate?.nameMismatch === undefined)
|
|
595
|
-
return
|
|
644
|
+
if (ctx.sslCertificate?.nameMismatch === undefined) {
|
|
645
|
+
return createResult({ id: 'security-ssl-name-match', name: 'SSL Certificate Name Match', category: 'security', severity: 'error' }, 'info', 'Not applicable (SSL certificate name match information unavailable)', { recommendation: 'This rule checks SSL certificate name matching when certificate domain information is available' });
|
|
646
|
+
}
|
|
596
647
|
if (ctx.sslCertificate.nameMismatch) {
|
|
597
648
|
return createResult({ id: 'security-ssl-name-match', name: 'SSL Certificate Name Match', category: 'security', severity: 'error' }, 'fail', 'SSL certificate name mismatch', {
|
|
598
649
|
recommendation: 'Get a certificate that matches your domain name',
|
|
@@ -613,8 +664,9 @@ export const securityRules = [
|
|
|
613
664
|
severity: 'error',
|
|
614
665
|
description: 'Server should use TLS 1.2 or higher',
|
|
615
666
|
check: (ctx) => {
|
|
616
|
-
if (!ctx.tlsVersion)
|
|
617
|
-
return
|
|
667
|
+
if (!ctx.tlsVersion) {
|
|
668
|
+
return createResult({ id: 'security-tls-version', name: 'TLS Version', category: 'security', severity: 'error' }, 'info', 'Not applicable (TLS version information unavailable)', { recommendation: 'This rule checks TLS version when TLS connection information is available' });
|
|
669
|
+
}
|
|
618
670
|
const version = ctx.tlsVersion;
|
|
619
671
|
const insecureVersions = ['SSLv2', 'SSLv3', 'TLSv1', 'TLSv1.0', 'TLSv1.1'];
|
|
620
672
|
if (insecureVersions.includes(version)) {
|
|
@@ -637,8 +689,9 @@ export const securityRules = [
|
|
|
637
689
|
severity: 'info',
|
|
638
690
|
description: 'SSL certificate should be from a trusted CA',
|
|
639
691
|
check: (ctx) => {
|
|
640
|
-
if (!ctx.sslCertificate?.issuer)
|
|
641
|
-
return
|
|
692
|
+
if (!ctx.sslCertificate?.issuer) {
|
|
693
|
+
return createResult({ id: 'security-ssl-issuer', name: 'SSL Certificate Issuer', category: 'security', severity: 'info' }, 'info', 'Not applicable (SSL certificate issuer information unavailable)', { recommendation: 'This rule checks SSL certificate issuer when certificate issuer information is available' });
|
|
694
|
+
}
|
|
642
695
|
const issuer = ctx.sslCertificate.issuer;
|
|
643
696
|
const selfSigned = issuer.toLowerCase().includes('self-signed') ||
|
|
644
697
|
ctx.sslCertificate.selfSigned === true;
|
|
@@ -661,8 +714,9 @@ export const securityRules = [
|
|
|
661
714
|
severity: 'error',
|
|
662
715
|
description: 'Password fields must only appear on HTTPS pages',
|
|
663
716
|
check: (ctx) => {
|
|
664
|
-
if (ctx.hasPasswordField === undefined)
|
|
665
|
-
return
|
|
717
|
+
if (ctx.hasPasswordField === undefined) {
|
|
718
|
+
return createResult({ id: 'security-password-on-http', name: 'Password Fields on HTTP', category: 'security', severity: 'error' }, 'info', 'Not applicable (password field information unavailable)', { recommendation: 'This rule checks for password fields on insecure pages when password field data is available' });
|
|
719
|
+
}
|
|
666
720
|
if (ctx.hasPasswordField && ctx.isHttps === false) {
|
|
667
721
|
return createResult({ id: 'security-password-on-http', name: 'Password Fields on HTTP', category: 'security', severity: 'error' }, 'fail', 'Password field on insecure HTTP page', {
|
|
668
722
|
recommendation: 'Enable HTTPS for all pages with password fields',
|
|
@@ -674,7 +728,7 @@ export const securityRules = [
|
|
|
674
728
|
if (ctx.hasPasswordField && ctx.isHttps === true) {
|
|
675
729
|
return createResult({ id: 'security-password-on-http', name: 'Password Fields on HTTP', category: 'security', severity: 'error' }, 'pass', 'Password fields are on HTTPS');
|
|
676
730
|
}
|
|
677
|
-
return
|
|
731
|
+
return createResult({ id: 'security-password-on-http', name: 'Password Fields on HTTP', category: 'security', severity: 'error' }, 'info', 'Not applicable (no password fields detected)', { recommendation: 'This rule checks if password fields are only used on HTTPS pages when password fields are present' });
|
|
678
732
|
},
|
|
679
733
|
},
|
|
680
734
|
{
|
|
@@ -684,8 +738,9 @@ export const securityRules = [
|
|
|
684
738
|
severity: 'warning',
|
|
685
739
|
description: 'Forms should only submit to HTTPS endpoints',
|
|
686
740
|
check: (ctx) => {
|
|
687
|
-
if (ctx.formsOnHttp === undefined)
|
|
688
|
-
return
|
|
741
|
+
if (ctx.formsOnHttp === undefined) {
|
|
742
|
+
return createResult({ id: 'security-forms-on-http', name: 'Forms on HTTP', category: 'security', severity: 'warning' }, 'info', 'Not applicable (form submission data unavailable)', { recommendation: 'This rule checks if forms submit to HTTPS endpoints when form data is available' });
|
|
743
|
+
}
|
|
689
744
|
if (ctx.formsOnHttp > 0) {
|
|
690
745
|
return createResult({ id: 'security-forms-on-http', name: 'Forms on HTTP', category: 'security', severity: 'warning' }, 'warn', `${ctx.formsOnHttp} form(s) submit to HTTP`, {
|
|
691
746
|
value: ctx.formsOnHttp,
|
|
@@ -705,11 +760,13 @@ export const securityRules = [
|
|
|
705
760
|
severity: 'info',
|
|
706
761
|
description: 'Server header should not reveal detailed version information',
|
|
707
762
|
check: (ctx) => {
|
|
708
|
-
if (!ctx.responseHeaders)
|
|
709
|
-
return
|
|
763
|
+
if (!ctx.responseHeaders) {
|
|
764
|
+
return createResult({ id: 'security-server-disclosure', name: 'Server Version Disclosure', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for server version disclosure when HTTP response headers are available' });
|
|
765
|
+
}
|
|
710
766
|
const serverHeader = ctx.responseHeaders['server'] || ctx.responseHeaders['Server'];
|
|
711
|
-
if (!serverHeader)
|
|
712
|
-
return
|
|
767
|
+
if (!serverHeader) {
|
|
768
|
+
return createResult({ id: 'security-server-disclosure', name: 'Server Version Disclosure', category: 'security', severity: 'info' }, 'info', 'Not applicable (Server header not present)', { recommendation: 'This rule checks for server version disclosure when Server header is present' });
|
|
769
|
+
}
|
|
713
770
|
const server = String(serverHeader);
|
|
714
771
|
if (/\d+\.\d+/.test(server)) {
|
|
715
772
|
return createResult({ id: 'security-server-disclosure', name: 'Server Version Disclosure', category: 'security', severity: 'info' }, 'info', `Server header reveals version: ${server}`, {
|
|
@@ -720,7 +777,7 @@ export const securityRules = [
|
|
|
720
777
|
},
|
|
721
778
|
});
|
|
722
779
|
}
|
|
723
|
-
return
|
|
780
|
+
return createResult({ id: 'security-server-disclosure', name: 'Server Version Disclosure', category: 'security', severity: 'info' }, 'info', 'Not applicable (Server header not present or does not disclose version)', { recommendation: 'This rule checks if the Server header reveals version information' });
|
|
724
781
|
},
|
|
725
782
|
},
|
|
726
783
|
{
|
|
@@ -730,8 +787,9 @@ export const securityRules = [
|
|
|
730
787
|
severity: 'info',
|
|
731
788
|
description: 'X-Powered-By header reveals technology stack',
|
|
732
789
|
check: (ctx) => {
|
|
733
|
-
if (!ctx.responseHeaders)
|
|
734
|
-
return
|
|
790
|
+
if (!ctx.responseHeaders) {
|
|
791
|
+
return createResult({ id: 'security-x-powered-by', name: 'X-Powered-By Header', category: 'security', severity: 'info' }, 'info', 'Not applicable (response headers unavailable)', { recommendation: 'This rule checks for X-Powered-By header disclosure when HTTP response headers are available' });
|
|
792
|
+
}
|
|
735
793
|
const xPoweredBy = ctx.responseHeaders['x-powered-by'] || ctx.responseHeaders['X-Powered-By'];
|
|
736
794
|
if (xPoweredBy) {
|
|
737
795
|
return createResult({ id: 'security-x-powered-by', name: 'X-Powered-By Header', category: 'security', severity: 'info' }, 'info', `X-Powered-By header present: ${xPoweredBy}`, {
|
|
@@ -742,7 +800,7 @@ export const securityRules = [
|
|
|
742
800
|
},
|
|
743
801
|
});
|
|
744
802
|
}
|
|
745
|
-
return
|
|
803
|
+
return createResult({ id: 'security-x-powered-by', name: 'X-Powered-By Header', category: 'security', severity: 'info' }, 'info', 'Not applicable (X-Powered-By header not present)', { recommendation: 'This rule checks for X-Powered-By header disclosure when the header is present' });
|
|
746
804
|
},
|
|
747
805
|
},
|
|
748
806
|
{
|
|
@@ -752,8 +810,9 @@ export const securityRules = [
|
|
|
752
810
|
severity: 'info',
|
|
753
811
|
description: 'Server should support Server Name Indication (SNI)',
|
|
754
812
|
check: (ctx) => {
|
|
755
|
-
if (ctx.sniSupported === undefined)
|
|
756
|
-
return
|
|
813
|
+
if (ctx.sniSupported === undefined) {
|
|
814
|
+
return createResult({ id: 'ssl-sni-support', name: 'SNI Support', category: 'security', severity: 'info' }, 'info', 'Not applicable (SNI support information unavailable)', { recommendation: 'This rule checks for SNI support when SNI information is available' });
|
|
815
|
+
}
|
|
757
816
|
if (!ctx.sniSupported) {
|
|
758
817
|
return createResult({ id: 'ssl-sni-support', name: 'SNI Support', category: 'security', severity: 'info' }, 'info', 'Server may not support SNI', {
|
|
759
818
|
recommendation: 'Ensure web server supports SNI for proper HTTPS functionality',
|
|
@@ -762,7 +821,7 @@ export const securityRules = [
|
|
|
762
821
|
}
|
|
763
822
|
});
|
|
764
823
|
}
|
|
765
|
-
return
|
|
824
|
+
return createResult({ id: 'ssl-sni-support', name: 'SNI Support', category: 'security', severity: 'info' }, 'info', 'Not applicable (SNI is supported)', { recommendation: 'This rule checks for SNI support issues when SNI is not supported' });
|
|
766
825
|
},
|
|
767
826
|
},
|
|
768
827
|
{
|
|
@@ -772,8 +831,9 @@ export const securityRules = [
|
|
|
772
831
|
severity: 'warning',
|
|
773
832
|
description: 'Sitemap should only contain HTTPS URLs',
|
|
774
833
|
check: (ctx) => {
|
|
775
|
-
if (ctx.sitemapHttpUrls === undefined)
|
|
776
|
-
return
|
|
834
|
+
if (ctx.sitemapHttpUrls === undefined) {
|
|
835
|
+
return createResult({ id: 'sitemap-https-urls', name: 'HTTPS URLs in Sitemap', category: 'security', severity: 'warning' }, 'info', 'Not applicable (sitemap URL data unavailable)', { recommendation: 'This rule checks sitemap URLs for HTTPS usage when sitemap data is available' });
|
|
836
|
+
}
|
|
777
837
|
if (ctx.sitemapHttpUrls > 0) {
|
|
778
838
|
return createResult({ id: 'sitemap-https-urls', name: 'HTTPS URLs in Sitemap', category: 'security', severity: 'warning' }, 'warn', `Sitemap contains ${ctx.sitemapHttpUrls} HTTP URLs`, {
|
|
779
839
|
value: ctx.sitemapHttpUrls,
|
|
@@ -795,10 +855,12 @@ export const securityRules = [
|
|
|
795
855
|
severity: 'info',
|
|
796
856
|
description: 'HTTPS sites should implement HSTS for security',
|
|
797
857
|
check: (ctx) => {
|
|
798
|
-
if (!ctx.isHttps)
|
|
799
|
-
return
|
|
800
|
-
|
|
801
|
-
|
|
858
|
+
if (!ctx.isHttps) {
|
|
859
|
+
return createResult({ id: 'security-hsts', name: 'HSTS Header', category: 'security', severity: 'info' }, 'info', 'Not applicable (page is not served over HTTPS)', { recommendation: 'This rule checks HSTS implementation on HTTPS sites only' });
|
|
860
|
+
}
|
|
861
|
+
if (ctx.hasHsts === undefined) {
|
|
862
|
+
return createResult({ id: 'security-hsts', name: 'HSTS Header', category: 'security', severity: 'info' }, 'info', 'Not applicable (HSTS status unavailable)', { recommendation: 'This rule checks for HSTS headers when HSTS information is available' });
|
|
863
|
+
}
|
|
802
864
|
if (!ctx.hasHsts) {
|
|
803
865
|
return createResult({ id: 'security-hsts', name: 'HSTS Header', category: 'security', severity: 'info' }, 'info', 'Missing Strict-Transport-Security header', {
|
|
804
866
|
recommendation: 'Implement HSTS to enforce HTTPS connections',
|