qa360 2.3.0 → 2.3.1
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 +155 -262
- package/{cli/dist → dist}/commands/ai.js +1 -1
- package/{cli/dist → dist}/commands/coverage.js +1 -1
- package/{cli/dist → dist}/commands/crawl.js +2 -2
- package/{cli/dist → dist}/commands/doctor.js +2 -2
- package/{cli/dist → dist}/commands/explain.js +2 -2
- package/{cli/dist → dist}/commands/flakiness.js +1 -1
- package/{cli/dist → dist}/commands/generate.js +1 -1
- package/{cli/dist → dist}/commands/history.js +1 -1
- package/{cli/dist → dist}/commands/monitor.js +3 -3
- package/{cli/dist → dist}/commands/ollama.js +1 -1
- package/{cli/dist → dist}/commands/pack.js +2 -2
- package/{cli/dist → dist}/commands/regression.js +1 -1
- package/{cli/dist → dist}/commands/repair.js +1 -1
- package/{cli/dist → dist}/commands/retry.js +1 -1
- package/{cli/dist → dist}/commands/run.d.ts +1 -1
- package/{cli/dist → dist}/commands/run.js +1 -1
- package/{cli/dist → dist}/commands/secrets.js +1 -1
- package/{cli/dist → dist}/commands/serve.js +1 -1
- package/{cli/dist → dist}/commands/slo.js +1 -1
- package/{cli/dist → dist}/commands/verify.js +1 -1
- package/{cli/dist → dist}/core/adapters/playwright-native-api.d.ts +2 -0
- package/{cli/dist → dist}/core/adapters/playwright-native-api.js +20 -1
- package/{cli/dist → dist}/core/adapters/playwright-ui.d.ts +21 -0
- package/dist/core/adapters/playwright-ui.js +2050 -0
- package/{cli/dist → dist}/core/ai/ollama-provider.js +15 -3
- package/{cli/dist → dist}/core/artifacts/ui-artifacts.js +24 -4
- package/dist/core/auth/backup-codes-provider.d.ts +91 -0
- package/dist/core/auth/backup-codes-provider.js +215 -0
- package/{cli/dist → dist}/core/auth/basic-auth-provider.d.ts +6 -0
- package/{cli/dist → dist}/core/auth/basic-auth-provider.js +24 -6
- package/dist/core/auth/digest-auth-provider.d.ts +116 -0
- package/dist/core/auth/digest-auth-provider.js +244 -0
- package/dist/core/auth/hcaptcha-handler.d.ts +103 -0
- package/dist/core/auth/hcaptcha-handler.js +288 -0
- package/{cli/dist → dist}/core/auth/index.d.ts +81 -4
- package/{cli/dist → dist}/core/auth/index.js +15 -1
- package/dist/core/auth/oauth-handler.d.ts +408 -0
- package/dist/core/auth/oauth-handler.js +636 -0
- package/{cli/dist → dist}/core/auth/oauth2-provider.d.ts +9 -0
- package/dist/core/auth/oauth2-provider.js +227 -0
- package/dist/core/auth/otp-provider.d.ts +93 -0
- package/dist/core/auth/otp-provider.js +288 -0
- package/dist/core/auth/recaptcha-handler.d.ts +119 -0
- package/dist/core/auth/recaptcha-handler.js +301 -0
- package/dist/core/auth/remember-me-handler.d.ts +142 -0
- package/dist/core/auth/remember-me-handler.js +255 -0
- package/dist/core/auth/saml-handler.d.ts +173 -0
- package/dist/core/auth/saml-handler.js +364 -0
- package/dist/core/auth/webauthn-handler.d.ts +182 -0
- package/dist/core/auth/webauthn-handler.js +310 -0
- package/dist/core/crawler/advanced-interactions.d.ts +342 -0
- package/dist/core/crawler/advanced-interactions.js +1069 -0
- package/dist/core/crawler/blob-url-download-handler.d.ts +145 -0
- package/dist/core/crawler/blob-url-download-handler.js +392 -0
- package/dist/core/crawler/consent-handler.d.ts +49 -0
- package/dist/core/crawler/consent-handler.js +258 -0
- package/dist/core/crawler/cookie-manager.d.ts +166 -0
- package/dist/core/crawler/cookie-manager.js +353 -0
- package/dist/core/crawler/coop-coep-handler.d.ts +136 -0
- package/dist/core/crawler/coop-coep-handler.js +338 -0
- package/dist/core/crawler/csp-handler.d.ts +151 -0
- package/dist/core/crawler/csp-handler.js +415 -0
- package/dist/core/crawler/download-handler.d.ts +155 -0
- package/dist/core/crawler/download-handler.js +370 -0
- package/dist/core/crawler/email-testing-handler.d.ts +214 -0
- package/dist/core/crawler/email-testing-handler.js +398 -0
- package/dist/core/crawler/error-tracking-handler.d.ts +177 -0
- package/dist/core/crawler/error-tracking-handler.js +378 -0
- package/dist/core/crawler/form-handler.d.ts +100 -0
- package/dist/core/crawler/form-handler.js +465 -0
- package/dist/core/crawler/framework-wait-handler.d.ts +96 -0
- package/dist/core/crawler/framework-wait-handler.js +464 -0
- package/dist/core/crawler/geolocation-handler.d.ts +112 -0
- package/dist/core/crawler/geolocation-handler.js +276 -0
- package/dist/core/crawler/index.d.ts +78 -0
- package/{cli/dist → dist}/core/crawler/index.js +74 -1
- package/dist/core/crawler/intelligent-selector-generator.d.ts +164 -0
- package/dist/core/crawler/intelligent-selector-generator.js +612 -0
- package/{cli/dist → dist}/core/crawler/journey-generator.js +44 -1
- package/{cli/dist → dist}/core/crawler/page-analyzer.d.ts +16 -1
- package/{cli/dist → dist}/core/crawler/page-analyzer.js +469 -17
- package/dist/core/crawler/permissions-handler.d.ts +112 -0
- package/dist/core/crawler/permissions-handler.js +236 -0
- package/dist/core/crawler/permissions-policy-handler.d.ts +113 -0
- package/dist/core/crawler/permissions-policy-handler.js +402 -0
- package/dist/core/crawler/presets.d.ts +100 -0
- package/dist/core/crawler/presets.js +887 -0
- package/dist/core/crawler/repl-debug-handler.d.ts +105 -0
- package/dist/core/crawler/repl-debug-handler.js +552 -0
- package/dist/core/crawler/reporting-api-handler.d.ts +212 -0
- package/dist/core/crawler/reporting-api-handler.js +344 -0
- package/{cli/dist → dist}/core/crawler/selector-generator.d.ts +9 -0
- package/{cli/dist → dist}/core/crawler/selector-generator.js +99 -23
- package/dist/core/crawler/site-profiler.d.ts +89 -0
- package/dist/core/crawler/site-profiler.js +290 -0
- package/dist/core/crawler/sourcemaps-handler.d.ts +144 -0
- package/dist/core/crawler/sourcemaps-handler.js +420 -0
- package/dist/core/crawler/stacked-modals-handler.d.ts +118 -0
- package/dist/core/crawler/stacked-modals-handler.js +429 -0
- package/dist/core/crawler/trusted-types-handler.d.ts +149 -0
- package/dist/core/crawler/trusted-types-handler.js +413 -0
- package/{cli/dist → dist}/core/crawler/types.d.ts +68 -2
- package/dist/core/crawler/wait-strategies.d.ts +108 -0
- package/dist/core/crawler/wait-strategies.js +399 -0
- package/dist/core/fixtures/factories.d.ts +180 -0
- package/dist/core/fixtures/factories.js +279 -0
- package/dist/core/fixtures/index.d.ts +6 -0
- package/dist/core/fixtures/index.js +6 -0
- package/{cli/dist → dist}/core/generation/crawler-pack-generator.d.ts +13 -3
- package/dist/core/generation/crawler-pack-generator.js +232 -0
- package/{cli/dist → dist}/core/generation/index.d.ts +2 -0
- package/{cli/dist → dist}/core/generation/index.js +2 -0
- package/{cli/dist → dist}/core/index.d.ts +2 -0
- package/{cli/dist → dist}/core/index.js +4 -0
- package/dist/core/network/index.d.ts +7 -0
- package/dist/core/network/index.js +7 -0
- package/dist/core/network/network-manager.d.ts +237 -0
- package/dist/core/network/network-manager.js +343 -0
- package/dist/core/network/network-simulator.d.ts +158 -0
- package/dist/core/network/network-simulator.js +261 -0
- package/{cli/dist → dist}/core/pack/validator.js +2 -2
- package/{cli/dist → dist}/core/pack-v2/migrator.d.ts +5 -0
- package/{cli/dist → dist}/core/pack-v2/migrator.js +81 -6
- package/{cli/dist → dist}/core/pack-v2/validator.js +4 -3
- package/{cli/dist → dist}/core/pom/base-page.js +1 -1
- package/{cli/dist → dist}/core/pom/loader.js +1 -1
- package/dist/core/reporting/index.d.ts +9 -0
- package/dist/core/reporting/index.js +10 -0
- package/dist/core/reporting/junit-reporter.d.ts +114 -0
- package/dist/core/reporting/junit-reporter.js +306 -0
- package/{cli/dist → dist}/core/runner/e2e-helpers.d.ts +1 -1
- package/{cli/dist → dist}/core/runner/e2e-helpers.js +2 -2
- package/{cli/dist → dist}/core/runner/phase3-runner.d.ts +3 -0
- package/{cli/dist → dist}/core/runner/phase3-runner.js +45 -14
- package/dist/core/sharding/test-sharding.d.ts +137 -0
- package/dist/core/sharding/test-sharding.js +233 -0
- package/dist/core/storage/cookie-manager.d.ts +160 -0
- package/dist/core/storage/cookie-manager.js +268 -0
- package/dist/core/storage/index.d.ts +7 -0
- package/dist/core/storage/index.js +7 -0
- package/dist/core/storage/storage-helpers.d.ts +138 -0
- package/dist/core/storage/storage-helpers.js +315 -0
- package/dist/core/test-helpers/index.d.ts +6 -0
- package/dist/core/test-helpers/index.js +6 -0
- package/dist/core/test-helpers/state-reset.d.ts +119 -0
- package/dist/core/test-helpers/state-reset.js +234 -0
- package/{cli/dist → dist}/core/types/pack-v1.d.ts +15 -2
- package/{cli/dist → dist}/core/types/pack-v2.d.ts +1 -1
- package/dist/core/upload/chunked-uploader.d.ts +150 -0
- package/dist/core/upload/chunked-uploader.js +289 -0
- package/dist/core/upload/index.d.ts +11 -0
- package/dist/core/upload/index.js +8 -0
- package/dist/core/upload/mime-validator.d.ts +119 -0
- package/dist/core/upload/mime-validator.js +373 -0
- package/dist/core/upload/presigned-uploader.d.ts +118 -0
- package/dist/core/upload/presigned-uploader.js +274 -0
- package/dist/core/utils/device-emulation.d.ts +194 -0
- package/dist/core/utils/device-emulation.js +380 -0
- package/dist/core/utils/index.d.ts +8 -0
- package/dist/core/utils/index.js +8 -0
- package/dist/core/utils/retry.d.ts +145 -0
- package/dist/core/utils/retry.js +242 -0
- package/dist/core/utils/smart-wait.d.ts +133 -0
- package/dist/core/utils/smart-wait.js +417 -0
- package/dist/core/visual/index.d.ts +7 -0
- package/dist/core/visual/index.js +7 -0
- package/dist/core/visual/pixel-diff.d.ts +87 -0
- package/dist/core/visual/pixel-diff.js +213 -0
- package/dist/core/visual/screenshot-helper.d.ts +130 -0
- package/dist/core/visual/screenshot-helper.js +223 -0
- package/{cli/dist → dist}/utils/config.d.ts +1 -1
- package/examples/README.md +160 -0
- package/examples/accessibility.yml +48 -0
- package/examples/api-basic.yml +27 -0
- package/examples/complete.yml +146 -0
- package/examples/crawler.yml +38 -0
- package/examples/fullstack.yml +78 -0
- package/examples/security.yml +58 -0
- package/examples/ui-advanced.yml +49 -0
- package/examples/ui-basic.yml +24 -0
- package/package.json +33 -67
- package/CHANGELOG.md +0 -330
- package/CONTRIBUTING.md +0 -273
- package/QUICK_START.md +0 -191
- package/cli/CHANGELOG.md +0 -84
- package/cli/LICENSE +0 -24
- package/cli/README.md +0 -222
- package/cli/dist/core/adapters/playwright-ui.js +0 -864
- package/cli/dist/core/auth/oauth2-provider.js +0 -114
- package/cli/dist/core/coverage/analyzer.d.ts +0 -101
- package/cli/dist/core/coverage/analyzer.js +0 -415
- package/cli/dist/core/coverage/collector.d.ts +0 -74
- package/cli/dist/core/coverage/collector.js +0 -459
- package/cli/dist/core/coverage/config.d.ts +0 -37
- package/cli/dist/core/coverage/config.js +0 -156
- package/cli/dist/core/coverage/index.d.ts +0 -11
- package/cli/dist/core/coverage/index.js +0 -15
- package/cli/dist/core/coverage/types.d.ts +0 -267
- package/cli/dist/core/coverage/types.js +0 -6
- package/cli/dist/core/coverage/vault.d.ts +0 -95
- package/cli/dist/core/coverage/vault.js +0 -405
- package/cli/dist/core/crawler/index.d.ts +0 -57
- package/cli/dist/core/fixtures/index.d.ts +0 -8
- package/cli/dist/core/fixtures/index.js +0 -8
- package/cli/dist/core/generation/crawler-pack-generator.js +0 -231
- package/cli/dist/core/reporting/index.d.ts +0 -6
- package/cli/dist/core/reporting/index.js +0 -6
- package/cli/dist/core/visual/index.d.ts +0 -6
- package/cli/dist/core/visual/index.js +0 -6
- package/cli/package.json +0 -76
- package/core/LICENSE +0 -24
- package/core/README.md +0 -105
- package/core/package.json +0 -90
- package/core/schemas/pack.schema.json +0 -236
- /package/{cli/bin → bin}/qa360.js +0 -0
- /package/{cli/dist → dist}/cli-minimal.d.ts +0 -0
- /package/{cli/dist → dist}/cli-minimal.js +0 -0
- /package/{cli/dist → dist}/commands/ai.d.ts +0 -0
- /package/{cli/dist → dist}/commands/ask.d.ts +0 -0
- /package/{cli/dist → dist}/commands/ask.js +0 -0
- /package/{cli/dist → dist}/commands/coverage.d.ts +0 -0
- /package/{cli/dist → dist}/commands/crawl.d.ts +0 -0
- /package/{cli/dist → dist}/commands/doctor.d.ts +0 -0
- /package/{cli/dist → dist}/commands/examples.d.ts +0 -0
- /package/{cli/dist → dist}/commands/examples.js +0 -0
- /package/{cli/dist → dist}/commands/explain.d.ts +0 -0
- /package/{cli/dist → dist}/commands/flakiness.d.ts +0 -0
- /package/{cli/dist → dist}/commands/generate.d.ts +0 -0
- /package/{cli/dist → dist}/commands/history.d.ts +0 -0
- /package/{cli/dist → dist}/commands/init.d.ts +0 -0
- /package/{cli/dist → dist}/commands/init.js +0 -0
- /package/{cli/dist → dist}/commands/monitor.d.ts +0 -0
- /package/{cli/dist → dist}/commands/ollama.d.ts +0 -0
- /package/{cli/dist → dist}/commands/pack.d.ts +0 -0
- /package/{cli/dist → dist}/commands/regression.d.ts +0 -0
- /package/{cli/dist → dist}/commands/repair.d.ts +0 -0
- /package/{cli/dist → dist}/commands/report.d.ts +0 -0
- /package/{cli/dist → dist}/commands/report.js +0 -0
- /package/{cli/dist → dist}/commands/retry.d.ts +0 -0
- /package/{cli/dist → dist}/commands/scan.d.ts +0 -0
- /package/{cli/dist → dist}/commands/scan.js +0 -0
- /package/{cli/dist → dist}/commands/secrets.d.ts +0 -0
- /package/{cli/dist → dist}/commands/serve.d.ts +0 -0
- /package/{cli/dist → dist}/commands/slo.d.ts +0 -0
- /package/{cli/dist → dist}/commands/verify.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/gitleaks-secrets.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/gitleaks-secrets.js +0 -0
- /package/{cli/dist → dist}/core/adapters/jest-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/jest-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/k6-perf.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/k6-perf.js +0 -0
- /package/{cli/dist → dist}/core/adapters/osv-deps.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/osv-deps.js +0 -0
- /package/{cli/dist → dist}/core/adapters/playwright-native-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/playwright-native-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/pytest-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/pytest-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/semgrep-sast.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/semgrep-sast.js +0 -0
- /package/{cli/dist → dist}/core/adapters/unit-test-types.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/unit-test-types.js +0 -0
- /package/{cli/dist → dist}/core/adapters/vitest-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/vitest-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/zap-dast.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/zap-dast.js +0 -0
- /package/{cli/dist → dist}/core/ai/anthropic-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/anthropic-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/deepseek-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/deepseek-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/index.js +0 -0
- /package/{cli/dist → dist}/core/ai/llm-client.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/llm-client.js +0 -0
- /package/{cli/dist → dist}/core/ai/mock-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/mock-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/ollama-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/openai-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/openai-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/provider-factory.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/provider-factory.js +0 -0
- /package/{cli/dist → dist}/core/artifacts/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/artifacts/index.js +0 -0
- /package/{cli/dist → dist}/core/artifacts/ui-artifacts.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/engine.js +0 -0
- /package/{cli/dist → dist}/core/assertions/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/index.js +0 -0
- /package/{cli/dist → dist}/core/assertions/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/types.js +0 -0
- /package/{cli/dist → dist}/core/auth/api-key-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/api-key-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/aws-iam-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/aws-iam-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/azure-ad-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/azure-ad-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/gcp-adc-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/gcp-adc-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/jwt-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/jwt-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/manager.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/manager.js +0 -0
- /package/{cli/dist → dist}/core/auth/totp-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/totp-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/ui-login-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/ui-login-provider.js +0 -0
- /package/{cli/dist → dist}/core/cache/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/cache/index.js +0 -0
- /package/{cli/dist → dist}/core/cache/lru-cache.d.ts +0 -0
- /package/{cli/dist → dist}/core/cache/lru-cache.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/analyzer.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/analyzer.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/collector.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/collector.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/config.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/config.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/index.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/index.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/types.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/types.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/vault.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/vault.js +0 -0
- /package/{cli/dist → dist}/core/crawler/journey-generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/crawler/types.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/assets.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/assets.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/index.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/server.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/server.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/types.js +0 -0
- /package/{cli/dist → dist}/core/discoverer/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/discoverer/index.js +0 -0
- /package/{cli/dist → dist}/core/fixtures/loader.d.ts +0 -0
- /package/{cli/dist → dist}/core/fixtures/loader.js +0 -0
- /package/{cli/dist → dist}/core/fixtures/resolver.d.ts +0 -0
- /package/{cli/dist → dist}/core/fixtures/resolver.js +0 -0
- /package/{cli/dist → dist}/core/fixtures/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/fixtures/types.js +0 -0
- /package/{cli/dist → dist}/core/flakiness/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/flakiness/index.js +0 -0
- /package/{cli/dist → dist}/core/generation/code-formatter.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/code-formatter.js +0 -0
- /package/{cli/dist → dist}/core/generation/code-generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/code-generator.js +0 -0
- /package/{cli/dist → dist}/core/generation/generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/generator.js +0 -0
- /package/{cli/dist → dist}/core/generation/pack-generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/pack-generator.js +0 -0
- /package/{cli/dist → dist}/core/generation/prompt-builder.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/prompt-builder.js +0 -0
- /package/{cli/dist → dist}/core/generation/source-analyzer.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/source-analyzer.js +0 -0
- /package/{cli/dist → dist}/core/generation/test-optimizer.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/test-optimizer.js +0 -0
- /package/{cli/dist → dist}/core/generation/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/types.js +0 -0
- /package/{cli/dist → dist}/core/hooks/compose.d.ts +0 -0
- /package/{cli/dist → dist}/core/hooks/compose.js +0 -0
- /package/{cli/dist → dist}/core/hooks/runner.d.ts +0 -0
- /package/{cli/dist → dist}/core/hooks/runner.js +0 -0
- /package/{cli/dist → dist}/core/pack/migrator.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack/migrator.js +0 -0
- /package/{cli/dist → dist}/core/pack/validator.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack-v2/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack-v2/index.js +0 -0
- /package/{cli/dist → dist}/core/pack-v2/loader.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack-v2/loader.js +0 -0
- /package/{cli/dist → dist}/core/pack-v2/validator.d.ts +0 -0
- /package/{cli/dist → dist}/core/parallel/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/parallel/index.js +0 -0
- /package/{cli/dist → dist}/core/parallel/parallel-runner.d.ts +0 -0
- /package/{cli/dist → dist}/core/parallel/parallel-runner.js +0 -0
- /package/{cli/dist → dist}/core/pom/base-page.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/index.js +0 -0
- /package/{cli/dist → dist}/core/pom/loader.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/types.js +0 -0
- /package/{cli/dist → dist}/core/proof/bundle.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/bundle.js +0 -0
- /package/{cli/dist → dist}/core/proof/canonicalize.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/canonicalize.js +0 -0
- /package/{cli/dist → dist}/core/proof/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/index.js +0 -0
- /package/{cli/dist → dist}/core/proof/schema.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/schema.js +0 -0
- /package/{cli/dist → dist}/core/proof/signer.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/signer.js +0 -0
- /package/{cli/dist → dist}/core/proof/verifier.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/verifier.js +0 -0
- /package/{cli/dist → dist}/core/regression/detector.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/detector.js +0 -0
- /package/{cli/dist → dist}/core/regression/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/index.js +0 -0
- /package/{cli/dist → dist}/core/regression/trend-analyzer.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/trend-analyzer.js +0 -0
- /package/{cli/dist → dist}/core/regression/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/types.js +0 -0
- /package/{cli/dist → dist}/core/regression/vault.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/vault.js +0 -0
- /package/{cli/dist → dist}/core/repair/engine/fixer.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/engine/fixer.js +0 -0
- /package/{cli/dist → dist}/core/repair/engine/suggestion-engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/engine/suggestion-engine.js +0 -0
- /package/{cli/dist → dist}/core/repair/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/index.js +0 -0
- /package/{cli/dist → dist}/core/repair/repairer.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/repairer.js +0 -0
- /package/{cli/dist → dist}/core/repair/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/types.js +0 -0
- /package/{cli/dist → dist}/core/repair/utils/error-analyzer.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/utils/error-analyzer.js +0 -0
- /package/{cli/dist → dist}/core/reporting/html-reporter.d.ts +0 -0
- /package/{cli/dist → dist}/core/reporting/html-reporter.js +0 -0
- /package/{cli/dist → dist}/core/retry/flakiness-integration.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/flakiness-integration.js +0 -0
- /package/{cli/dist → dist}/core/retry/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/index.js +0 -0
- /package/{cli/dist → dist}/core/retry/retry-engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/retry-engine.js +0 -0
- /package/{cli/dist → dist}/core/retry/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/types.js +0 -0
- /package/{cli/dist → dist}/core/retry/vault.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/vault.js +0 -0
- /package/{cli/dist → dist}/core/schemas/pack.schema.json +0 -0
- /package/{cli/dist → dist}/core/secrets/crypto.d.ts +0 -0
- /package/{cli/dist → dist}/core/secrets/crypto.js +0 -0
- /package/{cli/dist → dist}/core/secrets/manager.d.ts +0 -0
- /package/{cli/dist → dist}/core/secrets/manager.js +0 -0
- /package/{cli/dist → dist}/core/security/redaction-patterns-extended.d.ts +0 -0
- /package/{cli/dist → dist}/core/security/redaction-patterns-extended.js +0 -0
- /package/{cli/dist → dist}/core/security/redactor.d.ts +0 -0
- /package/{cli/dist → dist}/core/security/redactor.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/assertion-healer.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/assertion-healer.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/engine.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/index.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/selector-healer.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/selector-healer.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/types.js +0 -0
- /package/{cli/dist → dist}/core/serve/diagnostics-collector.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/diagnostics-collector.js +0 -0
- /package/{cli/dist → dist}/core/serve/health-checker.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/health-checker.js +0 -0
- /package/{cli/dist → dist}/core/serve/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/index.js +0 -0
- /package/{cli/dist → dist}/core/serve/metrics-collector.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/metrics-collector.js +0 -0
- /package/{cli/dist → dist}/core/serve/process-manager.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/process-manager.js +0 -0
- /package/{cli/dist → dist}/core/serve/server.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/server.js +0 -0
- /package/{cli/dist → dist}/core/slo/config.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/config.js +0 -0
- /package/{cli/dist → dist}/core/slo/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/index.js +0 -0
- /package/{cli/dist → dist}/core/slo/sli-calculator.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/sli-calculator.js +0 -0
- /package/{cli/dist → dist}/core/slo/slo-tracker.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/slo-tracker.js +0 -0
- /package/{cli/dist → dist}/core/slo/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/types.js +0 -0
- /package/{cli/dist → dist}/core/slo/vault.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/vault.js +0 -0
- /package/{cli/dist → dist}/core/tui/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/index.js +0 -0
- /package/{cli/dist → dist}/core/tui/monitor.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/monitor.js +0 -0
- /package/{cli/dist → dist}/core/tui/renderer.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/renderer.js +0 -0
- /package/{cli/dist → dist}/core/tui/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/types.js +0 -0
- /package/{cli/dist → dist}/core/types/pack-v1.js +0 -0
- /package/{cli/dist → dist}/core/types/pack-v2.js +0 -0
- /package/{cli/dist → dist}/core/types/trust-score.d.ts +0 -0
- /package/{cli/dist → dist}/core/types/trust-score.js +0 -0
- /package/{cli/dist → dist}/core/vault/cas.d.ts +0 -0
- /package/{cli/dist → dist}/core/vault/cas.js +0 -0
- /package/{cli/dist → dist}/core/vault/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/vault/index.js +0 -0
- /package/{cli/dist → dist}/core/visual/visual-regression.d.ts +0 -0
- /package/{cli/dist → dist}/core/visual/visual-regression.js +0 -0
- /package/{cli/dist → dist}/core/watch/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/watch/index.js +0 -0
- /package/{cli/dist → dist}/core/watch/watch-mode.d.ts +0 -0
- /package/{cli/dist → dist}/core/watch/watch-mode.js +0 -0
- /package/{cli/dist → dist}/generators/index.d.ts +0 -0
- /package/{cli/dist → dist}/generators/index.js +0 -0
- /package/{cli/dist → dist}/generators/json-reporter.d.ts +0 -0
- /package/{cli/dist → dist}/generators/json-reporter.js +0 -0
- /package/{cli/dist → dist}/generators/test-generator.d.ts +0 -0
- /package/{cli/dist → dist}/generators/test-generator.js +0 -0
- /package/{cli/dist → dist}/index.d.ts +0 -0
- /package/{cli/dist → dist}/index.js +0 -0
- /package/{cli/dist → dist}/scanners/dom-scanner.d.ts +0 -0
- /package/{cli/dist → dist}/scanners/dom-scanner.js +0 -0
- /package/{cli/dist → dist}/scanners/index.d.ts +0 -0
- /package/{cli/dist → dist}/scanners/index.js +0 -0
- /package/{cli/dist → dist}/schemas/pack.schema.json +0 -0
- /package/{cli/dist → dist}/types/scan.d.ts +0 -0
- /package/{cli/dist → dist}/types/scan.js +0 -0
- /package/{cli/dist → dist}/utils/config.js +0 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Digest Authentication Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements HTTP Digest Authentication (RFC 2617).
|
|
5
|
+
* Handles challenge-response flow with nonce handling.
|
|
6
|
+
*
|
|
7
|
+
* P1 Feature: Digest Auth is more secure than Basic Auth as it doesn't send
|
|
8
|
+
* the password in plaintext. Instead, it uses a challenge-response mechanism
|
|
9
|
+
* with MD5 hashing.
|
|
10
|
+
*
|
|
11
|
+
* Algorithm:
|
|
12
|
+
* 1. Client makes request without auth
|
|
13
|
+
* 2. Server responds with 401 and WWW-Authenticate header containing:
|
|
14
|
+
* - realm: Protection space
|
|
15
|
+
* - nonce: Server-generated unique value
|
|
16
|
+
* - qop: Quality of protection (auth or auth-int)
|
|
17
|
+
* - opaque: Client should return unchanged
|
|
18
|
+
* 3. Client calculates response using MD5 and retries
|
|
19
|
+
*
|
|
20
|
+
* Response calculation:
|
|
21
|
+
* HA1 = MD5(username:realm:password)
|
|
22
|
+
* HA2 = MD5(method:digestURI)
|
|
23
|
+
* response = MD5(HA1:nonce:HA2) // simplified
|
|
24
|
+
*/
|
|
25
|
+
import { createCacheKey, authCache } from './index.js';
|
|
26
|
+
/**
|
|
27
|
+
* Generates MD5 hash using Node.js crypto
|
|
28
|
+
*/
|
|
29
|
+
function md5Hash(data) {
|
|
30
|
+
const crypto = require('node:crypto');
|
|
31
|
+
return crypto.createHash('md5').update(data).digest('hex');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generates a client nonce (cnonce)
|
|
35
|
+
*/
|
|
36
|
+
function generateCnonce() {
|
|
37
|
+
const crypto = require('node:crypto');
|
|
38
|
+
return crypto.randomBytes(16).toString('hex').substring(0, 32);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parses WWW-Authenticate header for Digest challenge
|
|
42
|
+
* @example
|
|
43
|
+
* parseDigestHeader('Digest realm="test", nonce="abc123", qop="auth"')
|
|
44
|
+
* // => { realm: 'test', nonce: 'abc123', qop: 'auth' }
|
|
45
|
+
*/
|
|
46
|
+
export function parseDigestHeader(header) {
|
|
47
|
+
if (!header.toLowerCase().startsWith('digest ')) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const challengePart = header.substring(7);
|
|
51
|
+
const result = {};
|
|
52
|
+
// Parse key="value" pairs
|
|
53
|
+
const pairs = challengePart.match(/(\w+)="([^"]*)"/g);
|
|
54
|
+
if (!pairs) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
for (const pair of pairs) {
|
|
58
|
+
const match = pair.match(/(\w+)="([^"]*)"/);
|
|
59
|
+
if (match) {
|
|
60
|
+
const [, key, value] = match;
|
|
61
|
+
result[key] = value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (!result.realm || !result.nonce) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Calculates Digest response
|
|
71
|
+
* @param username Username
|
|
72
|
+
* @param password Password
|
|
73
|
+
* @param realm Realm from challenge
|
|
74
|
+
* @param nonce Nonce from challenge
|
|
75
|
+
* @param method HTTP method
|
|
76
|
+
* @param uri Request URI
|
|
77
|
+
* @param qop Quality of protection
|
|
78
|
+
* @param opaque Opaque value from challenge
|
|
79
|
+
* @param nc Nonce count
|
|
80
|
+
* @param cnonce Client nonce
|
|
81
|
+
*/
|
|
82
|
+
export function calculateDigestResponse(username, password, realm, nonce, method, uri, qop, opaque, nc = '00000001', cnonce) {
|
|
83
|
+
const clientCnonce = cnonce || generateCnonce();
|
|
84
|
+
// HA1 = MD5(username:realm:password)
|
|
85
|
+
const ha1 = md5Hash(`${username}:${realm}:${password}`);
|
|
86
|
+
// HA2 = MD5(method:uri)
|
|
87
|
+
const ha2 = md5Hash(`${method}:${uri}`);
|
|
88
|
+
// Response
|
|
89
|
+
let response;
|
|
90
|
+
if (qop) {
|
|
91
|
+
// response = MD5(HA1:nonce:nc:cnonce:qop:HA2)
|
|
92
|
+
response = md5Hash(`${ha1}:${nonce}:${nc}:${clientCnonce}:${qop}:${ha2}`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// response = MD5(HA1:nonce:HA2)
|
|
96
|
+
response = md5Hash(`${ha1}:${nonce}:${ha2}`);
|
|
97
|
+
}
|
|
98
|
+
// Build Authorization header value
|
|
99
|
+
const parts = [
|
|
100
|
+
`username="${username}"`,
|
|
101
|
+
`realm="${realm}"`,
|
|
102
|
+
`nonce="${nonce}"`,
|
|
103
|
+
`uri="${uri}"`,
|
|
104
|
+
`response="${response}"`,
|
|
105
|
+
`algorithm=MD5`,
|
|
106
|
+
];
|
|
107
|
+
if (qop) {
|
|
108
|
+
parts.push(`qop=${qop}`);
|
|
109
|
+
parts.push(`nc=${nc}`);
|
|
110
|
+
parts.push(`cnonce="${clientCnonce}"`);
|
|
111
|
+
}
|
|
112
|
+
if (opaque) {
|
|
113
|
+
parts.push(`opaque="${opaque}"`);
|
|
114
|
+
}
|
|
115
|
+
return `Digest ${parts.join(', ')}`;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Digest Authentication Provider
|
|
119
|
+
*/
|
|
120
|
+
export class DigestAuthProvider {
|
|
121
|
+
type = 'digest';
|
|
122
|
+
storedChallenges = new Map();
|
|
123
|
+
nonceCounters = new Map();
|
|
124
|
+
async authenticate(config) {
|
|
125
|
+
const { username, password, realm, cache } = config;
|
|
126
|
+
if (!username || !password) {
|
|
127
|
+
return {
|
|
128
|
+
success: false,
|
|
129
|
+
error: 'Username and password are required for Digest auth'
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const cacheKey = this.getCacheKey(config);
|
|
133
|
+
// Check cache first
|
|
134
|
+
if (cache?.enabled !== false) {
|
|
135
|
+
const cached = authCache.get(cacheKey);
|
|
136
|
+
if (cached) {
|
|
137
|
+
return { success: true, credentials: cached };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// For Digest auth, we need to make an initial request to get the challenge
|
|
141
|
+
// This will be handled by the adapter when it receives a 401
|
|
142
|
+
// For now, return credentials that can be used to build the header
|
|
143
|
+
const credentials = {
|
|
144
|
+
type: 'digest',
|
|
145
|
+
username,
|
|
146
|
+
password, // Store password securely for challenge response
|
|
147
|
+
realm,
|
|
148
|
+
headers: {
|
|
149
|
+
// Placeholder - actual header will be built on 401 response
|
|
150
|
+
'X-Digest-Auth-User': username,
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
// Cache if enabled
|
|
154
|
+
if (cache?.enabled !== false) {
|
|
155
|
+
const ttl = cache?.ttl || 3600;
|
|
156
|
+
authCache.set(cacheKey, credentials, ttl);
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
success: true,
|
|
160
|
+
credentials
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Stores a Digest challenge received from server
|
|
165
|
+
*/
|
|
166
|
+
storeChallenge(url, challenge) {
|
|
167
|
+
this.storedChallenges.set(url, challenge);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Retrieves stored challenge for a URL
|
|
171
|
+
*/
|
|
172
|
+
getChallenge(url) {
|
|
173
|
+
return this.storedChallenges.get(url);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Builds Authorization header for a request using stored challenge
|
|
177
|
+
*/
|
|
178
|
+
async buildAuthorizationHeader(url, method, config) {
|
|
179
|
+
const challenge = this.getChallenge(url);
|
|
180
|
+
if (!challenge) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
const uri = new URL(url).pathname + new URL(url).search;
|
|
184
|
+
const nc = this.getNonceCount(challenge.nonce);
|
|
185
|
+
const cnonce = generateCnonce();
|
|
186
|
+
return calculateDigestResponse(config.username, config.password, challenge.realm, challenge.nonce, method, uri, challenge.qop, challenge.opaque, nc, cnonce);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Gets next nonce count for a given nonce
|
|
190
|
+
*/
|
|
191
|
+
getNonceCount(nonce) {
|
|
192
|
+
const current = this.nonceCounters.get(nonce) || 0;
|
|
193
|
+
this.nonceCounters.set(nonce, current + 1);
|
|
194
|
+
return current.toString(16).padStart(8, '0');
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Handles 401 response and returns new request headers
|
|
198
|
+
*/
|
|
199
|
+
async handleChallenge(url, method, authenticateHeader, config) {
|
|
200
|
+
const challenge = parseDigestHeader(authenticateHeader);
|
|
201
|
+
if (!challenge) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
this.storeChallenge(url, challenge);
|
|
205
|
+
const authHeader = await this.buildAuthorizationHeader(url, method, config);
|
|
206
|
+
if (!authHeader) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
'Authorization': authHeader
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async clear(config) {
|
|
214
|
+
const key = this.getCacheKey(config);
|
|
215
|
+
authCache.clear(key);
|
|
216
|
+
}
|
|
217
|
+
async validate(config) {
|
|
218
|
+
return !!(config.username && config.password);
|
|
219
|
+
}
|
|
220
|
+
getCacheKey(config) {
|
|
221
|
+
const crypto = require('node:crypto');
|
|
222
|
+
const hash = crypto
|
|
223
|
+
.createHash('sha256')
|
|
224
|
+
.update(`${config.username}:${config.realm || ''}`)
|
|
225
|
+
.digest('hex')
|
|
226
|
+
.substring(0, 16);
|
|
227
|
+
return createCacheKey('digest', hash);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Clears stored challenges and counters
|
|
231
|
+
*/
|
|
232
|
+
clearState() {
|
|
233
|
+
this.storedChallenges.clear();
|
|
234
|
+
this.nonceCounters.clear();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Creates a Digest auth provider instance
|
|
239
|
+
*/
|
|
240
|
+
export function createDigestAuthProvider() {
|
|
241
|
+
return new DigestAuthProvider();
|
|
242
|
+
}
|
|
243
|
+
// Re-export types and utilities
|
|
244
|
+
// Types are exported from index.ts
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hCaptcha Handler
|
|
3
|
+
*
|
|
4
|
+
* Supports hCaptcha (privacy-focused CAPTCHA alternative)
|
|
5
|
+
*
|
|
6
|
+
* Test mode bypass uses hCaptcha's official test keys:
|
|
7
|
+
* - Site key: 10000000-ffff-ffff-ffff-000000000001
|
|
8
|
+
* - Secret key: 0x0000000000000000000000000000000000000000
|
|
9
|
+
*
|
|
10
|
+
* @see https://docs.hcaptcha.com/#integration-testing-test-keys
|
|
11
|
+
*/
|
|
12
|
+
export interface HcaptchaConfig {
|
|
13
|
+
/** Site key for hCaptcha */
|
|
14
|
+
siteKey?: string;
|
|
15
|
+
/** Use test mode (always returns valid token) */
|
|
16
|
+
testMode?: boolean;
|
|
17
|
+
/** CSS selector for the hCaptcha container */
|
|
18
|
+
selector?: string;
|
|
19
|
+
/** Timeout for solving (ms) */
|
|
20
|
+
timeout?: number;
|
|
21
|
+
/** hCaptcha is invisible/challenge-only */
|
|
22
|
+
isInvisible?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface HcaptchaTokenResponse {
|
|
25
|
+
success: boolean;
|
|
26
|
+
token: string;
|
|
27
|
+
challengeTs?: string;
|
|
28
|
+
hostname?: string;
|
|
29
|
+
errorCodes?: string[];
|
|
30
|
+
}
|
|
31
|
+
export declare const HCAPTCHA_TEST_SITE_KEY = "10000000-ffff-ffff-ffff-000000000001";
|
|
32
|
+
export declare const HCAPTCHA_TEST_SECRET = "0x0000000000000000000000000000000000000000";
|
|
33
|
+
export declare class HcaptchaHandler {
|
|
34
|
+
private testMode;
|
|
35
|
+
private timeout;
|
|
36
|
+
constructor(options?: {
|
|
37
|
+
testMode?: boolean;
|
|
38
|
+
timeout?: number;
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Detect if hCaptcha is present on the page
|
|
42
|
+
*/
|
|
43
|
+
detectHcaptcha(page: any): Promise<{
|
|
44
|
+
present: boolean;
|
|
45
|
+
siteKey?: string;
|
|
46
|
+
isInvisible?: boolean;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Solve hCaptcha
|
|
50
|
+
*
|
|
51
|
+
* In test mode, injects a test token
|
|
52
|
+
* In production, waits for user interaction
|
|
53
|
+
*/
|
|
54
|
+
solve(page: any, config?: HcaptchaConfig): Promise<HcaptchaTokenResponse>;
|
|
55
|
+
/**
|
|
56
|
+
* Solve hCaptcha in test mode
|
|
57
|
+
*/
|
|
58
|
+
private solveTestMode;
|
|
59
|
+
/**
|
|
60
|
+
* Solve hCaptcha in production mode (requires human interaction)
|
|
61
|
+
*/
|
|
62
|
+
private solveProduction;
|
|
63
|
+
/**
|
|
64
|
+
* Execute hCaptcha (for invisible hCaptcha)
|
|
65
|
+
*/
|
|
66
|
+
execute(page: any, config?: HcaptchaConfig): Promise<HcaptchaTokenResponse>;
|
|
67
|
+
/**
|
|
68
|
+
* Verify an hCaptcha token (server-side simulation)
|
|
69
|
+
*
|
|
70
|
+
* In real usage, this would call hCaptcha's siteverify API:
|
|
71
|
+
* POST https://hcaptcha.com/siteverify
|
|
72
|
+
*/
|
|
73
|
+
verifyToken(token: string, secret?: string): Promise<HcaptchaTokenResponse>;
|
|
74
|
+
/**
|
|
75
|
+
* Wait for hCaptcha to be ready
|
|
76
|
+
*/
|
|
77
|
+
waitForReady(page: any, timeout?: number): Promise<boolean>;
|
|
78
|
+
/**
|
|
79
|
+
* Inject test site key into page
|
|
80
|
+
*/
|
|
81
|
+
injectTestSiteKey(page: any, elementSelector: string): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Generate a test token for mocking
|
|
84
|
+
*/
|
|
85
|
+
private generateTestToken;
|
|
86
|
+
private sleep;
|
|
87
|
+
/**
|
|
88
|
+
* Reset all hCaptcha widgets on the page
|
|
89
|
+
*/
|
|
90
|
+
reset(page: any): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Get the current response token from hCaptcha
|
|
93
|
+
*/
|
|
94
|
+
getResponse(page: any, widgetId?: string): Promise<string | null>;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Factory function to create an hCaptcha handler
|
|
98
|
+
*/
|
|
99
|
+
export declare function createHcaptchaHandler(options?: {
|
|
100
|
+
testMode?: boolean;
|
|
101
|
+
timeout?: number;
|
|
102
|
+
}): HcaptchaHandler;
|
|
103
|
+
export default HcaptchaHandler;
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hCaptcha Handler
|
|
3
|
+
*
|
|
4
|
+
* Supports hCaptcha (privacy-focused CAPTCHA alternative)
|
|
5
|
+
*
|
|
6
|
+
* Test mode bypass uses hCaptcha's official test keys:
|
|
7
|
+
* - Site key: 10000000-ffff-ffff-ffff-000000000001
|
|
8
|
+
* - Secret key: 0x0000000000000000000000000000000000000000
|
|
9
|
+
*
|
|
10
|
+
* @see https://docs.hcaptcha.com/#integration-testing-test-keys
|
|
11
|
+
*/
|
|
12
|
+
// Test keys from hCaptcha (always return valid responses)
|
|
13
|
+
export const HCAPTCHA_TEST_SITE_KEY = '10000000-ffff-ffff-ffff-000000000001';
|
|
14
|
+
export const HCAPTCHA_TEST_SECRET = '0x0000000000000000000000000000000000000000';
|
|
15
|
+
// Common hCaptcha selectors
|
|
16
|
+
const HCAPTCHA_SELECTORS = [
|
|
17
|
+
'iframe[src*="hcaptcha"]',
|
|
18
|
+
'div.h-captcha',
|
|
19
|
+
'div[data-hcaptcha]',
|
|
20
|
+
'div[data-sitekey*="0x"]',
|
|
21
|
+
];
|
|
22
|
+
const BYPASS_SCRIPT = (siteKey, testMode) => `
|
|
23
|
+
(function() {
|
|
24
|
+
if (typeof window.hcaptcha !== 'undefined') {
|
|
25
|
+
window.__qa360_hcaptcha_ready = true;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Mock hcaptcha object for test mode
|
|
30
|
+
if (${testMode}) {
|
|
31
|
+
window.hcaptcha = {
|
|
32
|
+
ready: function(cb) { cb(); },
|
|
33
|
+
execute: function(siteKey, options) {
|
|
34
|
+
return Promise.resolve({
|
|
35
|
+
response: 'TEST_HCAPTCHA_TOKEN',
|
|
36
|
+
key: '${siteKey}'
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
render: function(container, options) {
|
|
40
|
+
return 'hcaptcha-widget-id';
|
|
41
|
+
},
|
|
42
|
+
reset: function(widgetId) {},
|
|
43
|
+
getResponse: function(widgetId) {
|
|
44
|
+
return 'TEST_HCAPTCHA_TOKEN';
|
|
45
|
+
},
|
|
46
|
+
getRespKey: function(widgetId) {
|
|
47
|
+
return '${siteKey}';
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
window.__qa360_hcaptcha_ready = true;
|
|
51
|
+
}
|
|
52
|
+
})();
|
|
53
|
+
`;
|
|
54
|
+
export class HcaptchaHandler {
|
|
55
|
+
testMode;
|
|
56
|
+
timeout;
|
|
57
|
+
constructor(options = {}) {
|
|
58
|
+
this.testMode = options.testMode ?? true;
|
|
59
|
+
this.timeout = options.timeout ?? 10000;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Detect if hCaptcha is present on the page
|
|
63
|
+
*/
|
|
64
|
+
async detectHcaptcha(page) {
|
|
65
|
+
const result = await page.evaluate(() => {
|
|
66
|
+
// Check for hCaptcha elements
|
|
67
|
+
const hcaptchaDiv = document.querySelector('.h-captcha');
|
|
68
|
+
const dataAttr = document.querySelector('[data-hcaptcha]');
|
|
69
|
+
const hcaptchaIframe = document.querySelector('iframe[src*="hcaptcha"]');
|
|
70
|
+
// Check for invisible hCaptcha
|
|
71
|
+
const isInvisible = !!document.querySelector('[data-sitekey*="invisible"]') ||
|
|
72
|
+
!!document.querySelector('.h-captcha[data-size="invisible"]');
|
|
73
|
+
// Try to extract site key
|
|
74
|
+
let siteKey;
|
|
75
|
+
const siteKeyEl = document.querySelector('[data-sitekey]');
|
|
76
|
+
if (siteKeyEl) {
|
|
77
|
+
siteKey = siteKeyEl.getAttribute('data-sitekey') || undefined;
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
present: !!(hcaptchaDiv || dataAttr || hcaptchaIframe),
|
|
81
|
+
siteKey,
|
|
82
|
+
isInvisible,
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Solve hCaptcha
|
|
89
|
+
*
|
|
90
|
+
* In test mode, injects a test token
|
|
91
|
+
* In production, waits for user interaction
|
|
92
|
+
*/
|
|
93
|
+
async solve(page, config = {}) {
|
|
94
|
+
const { testMode = this.testMode, selector } = config;
|
|
95
|
+
const detection = await this.detectHcaptcha(page);
|
|
96
|
+
if (!detection.present) {
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
token: '',
|
|
100
|
+
errorCodes: ['NO_HCAPTCHA_FOUND'],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (testMode) {
|
|
104
|
+
return await this.solveTestMode(page, config);
|
|
105
|
+
}
|
|
106
|
+
// Production mode: Wait for user to solve
|
|
107
|
+
return await this.solveProduction(page, selector, detection.isInvisible);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Solve hCaptcha in test mode
|
|
111
|
+
*/
|
|
112
|
+
async solveTestMode(page, config) {
|
|
113
|
+
const siteKey = config.siteKey || HCAPTCHA_TEST_SITE_KEY;
|
|
114
|
+
// Inject bypass script
|
|
115
|
+
await page.evaluate(BYPASS_SCRIPT(siteKey, true));
|
|
116
|
+
// Simulate successful callback
|
|
117
|
+
await page.evaluate((testToken) => {
|
|
118
|
+
// Dispatch custom event that hCaptcha fires on success
|
|
119
|
+
const event = new CustomEvent('hcaptcha-success', {
|
|
120
|
+
detail: { response: testToken }
|
|
121
|
+
});
|
|
122
|
+
window.dispatchEvent(event);
|
|
123
|
+
// Set response on any hCaptcha widgets
|
|
124
|
+
const widgets = document.querySelectorAll('.h-captcha');
|
|
125
|
+
widgets.forEach((widget) => {
|
|
126
|
+
widget.dataset.response = testToken;
|
|
127
|
+
});
|
|
128
|
+
}, this.generateTestToken());
|
|
129
|
+
return {
|
|
130
|
+
success: true,
|
|
131
|
+
token: this.generateTestToken(),
|
|
132
|
+
challengeTs: new Date().toISOString(),
|
|
133
|
+
hostname: 'test.hcaptcha.com',
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Solve hCaptcha in production mode (requires human interaction)
|
|
138
|
+
*/
|
|
139
|
+
async solveProduction(page, selector, isInvisible) {
|
|
140
|
+
const startTime = Date.now();
|
|
141
|
+
while (Date.now() - startTime < this.timeout) {
|
|
142
|
+
const result = await page.evaluate(() => {
|
|
143
|
+
if (typeof window.hcaptcha === 'undefined') {
|
|
144
|
+
return { ready: false, token: null };
|
|
145
|
+
}
|
|
146
|
+
const response = window.hcaptcha.getResponse();
|
|
147
|
+
if (response) {
|
|
148
|
+
return { ready: true, token: response };
|
|
149
|
+
}
|
|
150
|
+
return { ready: false, token: null };
|
|
151
|
+
});
|
|
152
|
+
if (result.ready && result.token) {
|
|
153
|
+
return {
|
|
154
|
+
success: true,
|
|
155
|
+
token: result.token,
|
|
156
|
+
challengeTs: new Date().toISOString(),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
await this.sleep(500);
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
success: false,
|
|
163
|
+
token: '',
|
|
164
|
+
errorCodes: ['TIMEOUT'],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Execute hCaptcha (for invisible hCaptcha)
|
|
169
|
+
*/
|
|
170
|
+
async execute(page, config = {}) {
|
|
171
|
+
const { testMode = this.testMode, isInvisible = false } = config;
|
|
172
|
+
if (testMode) {
|
|
173
|
+
return {
|
|
174
|
+
success: true,
|
|
175
|
+
token: this.generateTestToken(),
|
|
176
|
+
challengeTs: new Date().toISOString(),
|
|
177
|
+
hostname: 'test.hcaptcha.com',
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const result = await page.evaluate(() => {
|
|
181
|
+
if (typeof window.hcaptcha === 'undefined') {
|
|
182
|
+
return { success: false, token: null };
|
|
183
|
+
}
|
|
184
|
+
return window.hcaptcha.execute().then((token) => ({
|
|
185
|
+
success: true,
|
|
186
|
+
token,
|
|
187
|
+
})).catch(() => ({
|
|
188
|
+
success: false,
|
|
189
|
+
token: null,
|
|
190
|
+
}));
|
|
191
|
+
});
|
|
192
|
+
if (!result.success) {
|
|
193
|
+
return {
|
|
194
|
+
success: false,
|
|
195
|
+
token: '',
|
|
196
|
+
errorCodes: ['EXECUTION_FAILED'],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
success: true,
|
|
201
|
+
token: result.token,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Verify an hCaptcha token (server-side simulation)
|
|
206
|
+
*
|
|
207
|
+
* In real usage, this would call hCaptcha's siteverify API:
|
|
208
|
+
* POST https://hcaptcha.com/siteverify
|
|
209
|
+
*/
|
|
210
|
+
async verifyToken(token, secret) {
|
|
211
|
+
if (this.testMode) {
|
|
212
|
+
return {
|
|
213
|
+
success: true,
|
|
214
|
+
token,
|
|
215
|
+
challengeTs: new Date().toISOString(),
|
|
216
|
+
hostname: 'test.hcaptcha.com',
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// Production: Would call siteverify endpoint
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
token,
|
|
223
|
+
errorCodes: ['SITEVERIFY_NOT_IMPLEMENTED'],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Wait for hCaptcha to be ready
|
|
228
|
+
*/
|
|
229
|
+
async waitForReady(page, timeout = 10000) {
|
|
230
|
+
const startTime = Date.now();
|
|
231
|
+
while (Date.now() - startTime < timeout) {
|
|
232
|
+
const ready = await page.evaluate(() => typeof window.hcaptcha !== 'undefined');
|
|
233
|
+
if (ready)
|
|
234
|
+
return true;
|
|
235
|
+
await this.sleep(100);
|
|
236
|
+
}
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Inject test site key into page
|
|
241
|
+
*/
|
|
242
|
+
async injectTestSiteKey(page, elementSelector) {
|
|
243
|
+
await page.evaluate((sel, testKey) => {
|
|
244
|
+
const el = document.querySelector(sel);
|
|
245
|
+
if (el) {
|
|
246
|
+
el.setAttribute('data-sitekey', testKey);
|
|
247
|
+
}
|
|
248
|
+
}, elementSelector, HCAPTCHA_TEST_SITE_KEY);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Generate a test token for mocking
|
|
252
|
+
*/
|
|
253
|
+
generateTestToken() {
|
|
254
|
+
const timestamp = Date.now();
|
|
255
|
+
return `TEST_HCAPTCHA_TOKEN_${timestamp}`;
|
|
256
|
+
}
|
|
257
|
+
sleep(ms) {
|
|
258
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Reset all hCaptcha widgets on the page
|
|
262
|
+
*/
|
|
263
|
+
async reset(page) {
|
|
264
|
+
await page.evaluate(() => {
|
|
265
|
+
if (typeof window.hcaptcha !== 'undefined') {
|
|
266
|
+
window.hcaptcha.reset();
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Get the current response token from hCaptcha
|
|
272
|
+
*/
|
|
273
|
+
async getResponse(page, widgetId) {
|
|
274
|
+
return await page.evaluate((id) => {
|
|
275
|
+
if (typeof window.hcaptcha === 'undefined') {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
return window.hcaptcha.getResponse(id);
|
|
279
|
+
}, widgetId);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Factory function to create an hCaptcha handler
|
|
284
|
+
*/
|
|
285
|
+
export function createHcaptchaHandler(options) {
|
|
286
|
+
return new HcaptchaHandler(options);
|
|
287
|
+
}
|
|
288
|
+
export default HcaptchaHandler;
|