qa360 2.2.20 → 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.d.ts +12 -1
- package/{cli/dist → dist}/commands/crawl.js +70 -9
- 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 -262
- 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 -64
- package/core/package.json +0 -81
- 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/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,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SAML 2.0 Handler
|
|
3
|
+
*
|
|
4
|
+
* P1 - Enterprise SSO support
|
|
5
|
+
*
|
|
6
|
+
* Supports:
|
|
7
|
+
* - SP-initiated SSO (Service Provider initiates)
|
|
8
|
+
* - IdP-initiated SSO (Identity Provider initiates)
|
|
9
|
+
* - SAML Response parsing and validation
|
|
10
|
+
* - Assertion extraction and attribute reading
|
|
11
|
+
* - Signature verification (basic)
|
|
12
|
+
*
|
|
13
|
+
* @see https://www.oasis-open.org/committees/download.php/6058/sstc-saml-core-2.0.pdf
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* SAML 2.0 Handler class
|
|
17
|
+
*/
|
|
18
|
+
export class SAMLHandler {
|
|
19
|
+
config;
|
|
20
|
+
constructor(config) {
|
|
21
|
+
this.config = config;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate SAML AuthnRequest for SP-initiated SSO
|
|
25
|
+
* Creates a base64-encoded SAML request to send to IdP
|
|
26
|
+
*/
|
|
27
|
+
generateAuthnRequest(options) {
|
|
28
|
+
const id = this.generateId();
|
|
29
|
+
const issueInstant = new Date().toISOString();
|
|
30
|
+
const acsUrl = options?.assertionConsumerServiceUrl || this.config.acsUrl;
|
|
31
|
+
const protocolBinding = options?.protocolBinding || this.config.protocolBinding || 'HTTP-POST';
|
|
32
|
+
// Build SAML AuthnRequest XML
|
|
33
|
+
const samlRequest = `<?xml version="1.0" encoding="UTF-8"?>
|
|
34
|
+
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
|
|
35
|
+
ID="${id}"
|
|
36
|
+
Version="2.0"
|
|
37
|
+
IssueInstant="${issueInstant}"
|
|
38
|
+
ProtocolBinding="${protocolBinding}"
|
|
39
|
+
AssertionConsumerServiceURL="${acsUrl}"
|
|
40
|
+
Destination="${this.config.idpSsoUrl || ''}"${options?.forceAuthn ? ' ForceAuthn="true"' : ''}${options?.passive ? ' IsPassive="true"' : ''}>
|
|
41
|
+
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">${this.config.spEntityId}</saml:Issuer>
|
|
42
|
+
${options?.forceAuthn ? '<samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>' : ''}
|
|
43
|
+
${options?.passive ? '<samlp:NameIDPolicy AllowCreate="false" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>' : ''}
|
|
44
|
+
<samlp:RequestedAuthnContext Comparison="exact">
|
|
45
|
+
<saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
|
|
46
|
+
</samlp:RequestedAuthnContext>
|
|
47
|
+
</samlp:AuthnRequest>`;
|
|
48
|
+
// Base64 encode
|
|
49
|
+
return Buffer.from(samlRequest).toString('base64');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get IdP SSO URL with SAML request for SP-initiated flow
|
|
53
|
+
*/
|
|
54
|
+
getSSOUrl(options) {
|
|
55
|
+
if (!this.config.idpSsoUrl) {
|
|
56
|
+
throw new Error('IdP SSO URL not configured');
|
|
57
|
+
}
|
|
58
|
+
const samlRequest = this.generateAuthnRequest(options);
|
|
59
|
+
const params = new URLSearchParams({
|
|
60
|
+
SAMLRequest: samlRequest,
|
|
61
|
+
});
|
|
62
|
+
if (options?.relayState) {
|
|
63
|
+
params.append('RelayState', options.relayState);
|
|
64
|
+
}
|
|
65
|
+
const separator = this.config.idpSsoUrl.includes('?') ? '&' : '?';
|
|
66
|
+
return `${this.config.idpSsoUrl}${separator}${params.toString()}`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Parse SAML Response from IdP
|
|
70
|
+
* Extracts assertion and attributes from base64-encoded SAML response
|
|
71
|
+
*/
|
|
72
|
+
parseResponse(samlResponse) {
|
|
73
|
+
const errors = [];
|
|
74
|
+
try {
|
|
75
|
+
// Validate base64 format (basic check for valid characters)
|
|
76
|
+
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
77
|
+
const urlSafeBase64Regex = /^[A-Za-z0-9_-]*={0,2}$/;
|
|
78
|
+
// Decode base64
|
|
79
|
+
let decoded;
|
|
80
|
+
try {
|
|
81
|
+
if (!base64Regex.test(samlResponse) && !urlSafeBase64Regex.test(samlResponse)) {
|
|
82
|
+
throw new Error('Invalid base64 format');
|
|
83
|
+
}
|
|
84
|
+
decoded = Buffer.from(samlResponse, 'base64').toString('utf-8');
|
|
85
|
+
// Check if decoding produced valid UTF-8 text (SAML responses start with <?xml)
|
|
86
|
+
if (!decoded.startsWith('<?xml') && !decoded.startsWith('<samlp:') && !decoded.startsWith('<saml:')) {
|
|
87
|
+
throw new Error('Decoded content is not valid SAML XML');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Try URL-decoded base64
|
|
92
|
+
try {
|
|
93
|
+
const urlDecoded = decodeURIComponent(samlResponse);
|
|
94
|
+
if (!base64Regex.test(urlDecoded) && !urlSafeBase64Regex.test(urlDecoded)) {
|
|
95
|
+
throw new Error('Invalid base64 format after URL decode');
|
|
96
|
+
}
|
|
97
|
+
decoded = Buffer.from(urlDecoded, 'base64').toString('utf-8');
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
errors.push(e instanceof Error ? e.message : 'Invalid base64 encoding');
|
|
101
|
+
return { raw: samlResponse, errors };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Parse XML
|
|
105
|
+
const response = this.parseSAMLXML(decoded);
|
|
106
|
+
// Validate response
|
|
107
|
+
if (response.statusCode && response.statusCode !== 'urn:oasis:names:tc:SAML:2.0:status:Success') {
|
|
108
|
+
errors.push(`SAML status: ${response.statusCode} - ${response.statusMessage || 'Unknown error'}`);
|
|
109
|
+
}
|
|
110
|
+
if (response.destination && response.destination !== this.config.acsUrl) {
|
|
111
|
+
errors.push(`Destination mismatch: expected ${this.config.acsUrl}, got ${response.destination}`);
|
|
112
|
+
}
|
|
113
|
+
if (errors.length > 0) {
|
|
114
|
+
return { raw: samlResponse, errors };
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
raw: samlResponse,
|
|
118
|
+
response,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
return {
|
|
123
|
+
raw: samlResponse,
|
|
124
|
+
errors: [e instanceof Error ? e.message : 'Unknown parsing error'],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Parse SAML XML and extract relevant fields
|
|
130
|
+
*/
|
|
131
|
+
parseSAMLXML(xml) {
|
|
132
|
+
// Simple XML parsing without external dependencies
|
|
133
|
+
const response = {
|
|
134
|
+
id: '',
|
|
135
|
+
issueInstant: '',
|
|
136
|
+
version: '2.0',
|
|
137
|
+
};
|
|
138
|
+
// Extract Response attributes using regex
|
|
139
|
+
const idMatch = xml.match(/ID="([^"]+)"/);
|
|
140
|
+
if (idMatch)
|
|
141
|
+
response.id = idMatch[1];
|
|
142
|
+
const instantMatch = xml.match(/IssueInstant="([^"]+)"/);
|
|
143
|
+
if (instantMatch)
|
|
144
|
+
response.issueInstant = instantMatch[1];
|
|
145
|
+
const versionMatch = xml.match(/Version="([^"]+)"/);
|
|
146
|
+
if (versionMatch)
|
|
147
|
+
response.version = versionMatch[1];
|
|
148
|
+
const destMatch = xml.match(/Destination="([^"]+)"/);
|
|
149
|
+
if (destMatch)
|
|
150
|
+
response.destination = destMatch[1];
|
|
151
|
+
// Extract Issuer
|
|
152
|
+
const issuerMatch = xml.match(/<saml:Issuer[^>]*>([^<]+)<\/saml:Issuer>/);
|
|
153
|
+
if (issuerMatch)
|
|
154
|
+
response.issuer = issuerMatch[1].trim();
|
|
155
|
+
// Extract Status Code
|
|
156
|
+
const statusCodeMatch = xml.match(/<samlp:StatusCode[^>]*Value="([^"]+)"/);
|
|
157
|
+
if (statusCodeMatch)
|
|
158
|
+
response.statusCode = statusCodeMatch[1];
|
|
159
|
+
// Extract Status Message
|
|
160
|
+
const statusMsgMatch = xml.match(/<samlp:StatusMessage[^>]*>([^<]+)<\/samlp:StatusMessage>/);
|
|
161
|
+
if (statusMsgMatch)
|
|
162
|
+
response.statusMessage = statusMsgMatch[1].trim();
|
|
163
|
+
// Extract Assertion
|
|
164
|
+
const assertionMatch = xml.match(/<saml:Assertion[^>]*>([\s\S]*?)<\/saml:Assertion>/);
|
|
165
|
+
if (assertionMatch) {
|
|
166
|
+
response.assertion = this.parseAssertion(assertionMatch[1]);
|
|
167
|
+
}
|
|
168
|
+
return response;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Parse SAML Assertion
|
|
172
|
+
*/
|
|
173
|
+
parseAssertion(assertionXml) {
|
|
174
|
+
const assertion = {
|
|
175
|
+
id: '',
|
|
176
|
+
issueInstant: '',
|
|
177
|
+
issuer: '',
|
|
178
|
+
};
|
|
179
|
+
const idMatch = assertionXml.match(/ID="([^"]+)"/);
|
|
180
|
+
if (idMatch)
|
|
181
|
+
assertion.id = idMatch[1];
|
|
182
|
+
const instantMatch = assertionXml.match(/IssueInstant="([^"]+)"/);
|
|
183
|
+
if (instantMatch)
|
|
184
|
+
assertion.issueInstant = instantMatch[1];
|
|
185
|
+
const issuerMatch = assertionXml.match(/<saml:Issuer[^>]*>([^<]+)<\/saml:Issuer>/);
|
|
186
|
+
if (issuerMatch)
|
|
187
|
+
assertion.issuer = issuerMatch[1].trim();
|
|
188
|
+
// Extract Subject
|
|
189
|
+
const subjectMatch = assertionXml.match(/<saml:Subject[^>]*>([\s\S]*?)<\/saml:Subject>/);
|
|
190
|
+
if (subjectMatch) {
|
|
191
|
+
assertion.subject = this.parseSubject(subjectMatch[1]);
|
|
192
|
+
}
|
|
193
|
+
// Extract Conditions
|
|
194
|
+
const conditionsMatch = assertionXml.match(/<saml:Conditions[^>]*>([\s\S]*?)<\/saml:Conditions>/);
|
|
195
|
+
if (conditionsMatch) {
|
|
196
|
+
assertion.conditions = this.parseConditions(conditionsMatch[1]);
|
|
197
|
+
}
|
|
198
|
+
// Extract Attribute Statement
|
|
199
|
+
const attributeMatch = assertionXml.match(/<saml:AttributeStatement[^>]*>([\s\S]*?)<\/saml:AttributeStatement>/);
|
|
200
|
+
if (attributeMatch) {
|
|
201
|
+
assertion.attributes = this.parseAttributes(attributeMatch[1]);
|
|
202
|
+
}
|
|
203
|
+
// Extract AuthnStatement
|
|
204
|
+
const authnMatch = assertionXml.match(/<saml:AuthnStatement[^>]*>([\s\S]*?)<\/saml:AuthnStatement>/);
|
|
205
|
+
if (authnMatch) {
|
|
206
|
+
const authnInstantMatch = authnMatch[1].match(/AuthnInstant="([^"]+)"/);
|
|
207
|
+
const sessionIndexMatch = authnMatch[1].match(/SessionIndex="([^"]+)"/);
|
|
208
|
+
const sessionNotOnOrAfterMatch = authnMatch[1].match(/SessionNotOnOrAfter="([^"]+)"/);
|
|
209
|
+
assertion.authnStatement = {
|
|
210
|
+
authnInstant: authnInstantMatch?.[1] || '',
|
|
211
|
+
sessionIndex: sessionIndexMatch?.[1],
|
|
212
|
+
sessionNotOnOrAfter: sessionNotOnOrAfterMatch?.[1],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return assertion;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Parse SAML Subject
|
|
219
|
+
*/
|
|
220
|
+
parseSubject(subjectXml) {
|
|
221
|
+
const nameIdMatch = subjectXml.match(/<saml:NameID[^>]*>([^<]+)<\/saml:NameID>/);
|
|
222
|
+
const formatMatch = subjectXml.match(/<saml:NameID[^>]*Format="([^"]+)"/);
|
|
223
|
+
return {
|
|
224
|
+
nameId: nameIdMatch?.[1]?.trim() || '',
|
|
225
|
+
format: formatMatch?.[1],
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Parse SAML Conditions
|
|
230
|
+
*/
|
|
231
|
+
parseConditions(conditionsXml) {
|
|
232
|
+
const conditions = {};
|
|
233
|
+
const notBeforeMatch = conditionsXml.match(/NotBefore="([^"]+)"/);
|
|
234
|
+
if (notBeforeMatch)
|
|
235
|
+
conditions.notBefore = notBeforeMatch[1];
|
|
236
|
+
const notOnOrAfterMatch = conditionsXml.match(/NotOnOrAfter="([^"]+)"/);
|
|
237
|
+
if (notOnOrAfterMatch)
|
|
238
|
+
conditions.notOnOrAfter = notOnOrAfterMatch[1];
|
|
239
|
+
const audienceMatches = conditionsXml.matchAll(/<saml:Audience[^>]*>([^<]+)<\/saml:Audience>/g);
|
|
240
|
+
const audiences = [];
|
|
241
|
+
for (const match of audienceMatches) {
|
|
242
|
+
audiences.push(match[1].trim());
|
|
243
|
+
}
|
|
244
|
+
if (audiences.length > 0) {
|
|
245
|
+
conditions.audience = audiences;
|
|
246
|
+
}
|
|
247
|
+
return conditions;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Parse SAML Attributes
|
|
251
|
+
*/
|
|
252
|
+
parseAttributes(attributesXml) {
|
|
253
|
+
const attributes = {};
|
|
254
|
+
const attributeMatches = attributesXml.matchAll(/<saml:Attribute[^>]*Name="([^"]+)"[^>]*>([\s\S]*?)<\/saml:Attribute>/g);
|
|
255
|
+
for (const match of attributeMatches) {
|
|
256
|
+
const name = match[1];
|
|
257
|
+
const values = [];
|
|
258
|
+
const valueMatches = match[2].matchAll(/<saml:AttributeValue[^>]*>([^<]*)<\/saml:AttributeValue>/g);
|
|
259
|
+
for (const valueMatch of valueMatches) {
|
|
260
|
+
values.push(valueMatch[1].trim());
|
|
261
|
+
}
|
|
262
|
+
attributes[name] = values;
|
|
263
|
+
}
|
|
264
|
+
return attributes;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Validate SAML Response conditions
|
|
268
|
+
* Checks time validity and audience
|
|
269
|
+
*/
|
|
270
|
+
validateConditions(parsed) {
|
|
271
|
+
const errors = [];
|
|
272
|
+
const now = new Date();
|
|
273
|
+
if (!parsed.assertion?.conditions) {
|
|
274
|
+
return { valid: true, errors: [] };
|
|
275
|
+
}
|
|
276
|
+
const conditions = parsed.assertion.conditions;
|
|
277
|
+
// Check NotBefore
|
|
278
|
+
if (conditions.notBefore) {
|
|
279
|
+
const notBefore = new Date(conditions.notBefore);
|
|
280
|
+
if (now < notBefore) {
|
|
281
|
+
errors.push(`Response not valid until ${conditions.notBefore}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
// Check NotOnOrAfter
|
|
285
|
+
if (conditions.notOnOrAfter) {
|
|
286
|
+
const notOnOrAfter = new Date(conditions.notOnOrAfter);
|
|
287
|
+
if (now >= notOnOrAfter) {
|
|
288
|
+
errors.push(`Response expired at ${conditions.notOnOrAfter}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Check Audience
|
|
292
|
+
if (conditions.audience && conditions.audience.length > 0) {
|
|
293
|
+
if (!conditions.audience.includes(this.config.spEntityId)) {
|
|
294
|
+
errors.push(`Audience mismatch: expected ${this.config.spEntityId}, got ${conditions.audience.join(', ')}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
valid: errors.length === 0,
|
|
299
|
+
errors,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Extract user attributes from SAML response
|
|
304
|
+
*/
|
|
305
|
+
getUserAttributes(samlResponse) {
|
|
306
|
+
const parsed = this.parseResponse(samlResponse);
|
|
307
|
+
if (parsed.response?.assertion?.attributes) {
|
|
308
|
+
return parsed.response.assertion.attributes;
|
|
309
|
+
}
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Get NameID (user identifier) from SAML response
|
|
314
|
+
*/
|
|
315
|
+
getNameId(samlResponse) {
|
|
316
|
+
const parsed = this.parseResponse(samlResponse);
|
|
317
|
+
return parsed.response?.assertion?.subject?.nameId || null;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Get email from SAML response attributes
|
|
321
|
+
*/
|
|
322
|
+
getEmail(samlResponse) {
|
|
323
|
+
const attrs = this.getUserAttributes(samlResponse);
|
|
324
|
+
if (!attrs)
|
|
325
|
+
return null;
|
|
326
|
+
// Common email attribute names
|
|
327
|
+
const emailKeys = ['email', 'Email', 'EmailAddress', 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'];
|
|
328
|
+
for (const key of emailKeys) {
|
|
329
|
+
if (attrs[key] && attrs[key][0]) {
|
|
330
|
+
return attrs[key][0];
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Get display name from SAML response attributes
|
|
337
|
+
*/
|
|
338
|
+
getDisplayName(samlResponse) {
|
|
339
|
+
const attrs = this.getUserAttributes(samlResponse);
|
|
340
|
+
if (!attrs)
|
|
341
|
+
return null;
|
|
342
|
+
// Common name attribute names
|
|
343
|
+
const nameKeys = ['firstName', 'lastName', 'name', 'displayName', 'cn', 'http://schemas.microsoft.com/identity/claims/displayname'];
|
|
344
|
+
for (const key of nameKeys) {
|
|
345
|
+
if (attrs[key] && attrs[key][0]) {
|
|
346
|
+
return attrs[key][0];
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Generate unique ID for SAML requests
|
|
353
|
+
*/
|
|
354
|
+
generateId() {
|
|
355
|
+
return `_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Factory function to create SAML handler
|
|
360
|
+
*/
|
|
361
|
+
export function createSAMLHandler(config) {
|
|
362
|
+
return new SAMLHandler(config);
|
|
363
|
+
}
|
|
364
|
+
export default SAMLHandler;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebAuthn / Passkeys Handler
|
|
3
|
+
*
|
|
4
|
+
* P1 - Modern passwordless authentication
|
|
5
|
+
*
|
|
6
|
+
* Supports:
|
|
7
|
+
* - WebAuthn registration (credential creation)
|
|
8
|
+
* - WebAuthn authentication (assertion)
|
|
9
|
+
* - Passkeys (platform and cross-device)
|
|
10
|
+
* - Credential ID storage and lookup
|
|
11
|
+
*
|
|
12
|
+
* @see https://w3c.github.io/webauthn/
|
|
13
|
+
*/
|
|
14
|
+
export interface WebAuthnConfig {
|
|
15
|
+
/** Relying Party ID (usually the domain) */
|
|
16
|
+
rpId: string;
|
|
17
|
+
/** Relying Party name (app name) */
|
|
18
|
+
rpName: string;
|
|
19
|
+
/** Relying Party origin */
|
|
20
|
+
origin?: string;
|
|
21
|
+
/** User verification requirement */
|
|
22
|
+
userVerification?: 'required' | 'preferred' | 'discouraged';
|
|
23
|
+
/** Attestation preference */
|
|
24
|
+
attestation?: 'none' | 'indirect' | 'direct';
|
|
25
|
+
/** Require resident key (passkey) */
|
|
26
|
+
requireResidentKey?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface WebAuthnUser {
|
|
29
|
+
/** User ID (binary) */
|
|
30
|
+
id: ArrayBuffer;
|
|
31
|
+
/** Username */
|
|
32
|
+
name: string;
|
|
33
|
+
/** Display name */
|
|
34
|
+
displayName: string;
|
|
35
|
+
/** Optional icon */
|
|
36
|
+
icon?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface WebAuthnCredential {
|
|
39
|
+
/** Credential ID */
|
|
40
|
+
id: string;
|
|
41
|
+
/** Public key */
|
|
42
|
+
publicKey: string;
|
|
43
|
+
/** Sign counter */
|
|
44
|
+
counter: number;
|
|
45
|
+
/** User handle */
|
|
46
|
+
userHandle?: string;
|
|
47
|
+
/** Credential type */
|
|
48
|
+
type: 'public-key';
|
|
49
|
+
/** Transport hints */
|
|
50
|
+
transports?: AuthenticatorTransport[];
|
|
51
|
+
}
|
|
52
|
+
export interface RegistrationResult {
|
|
53
|
+
success: boolean;
|
|
54
|
+
credential?: WebAuthnCredential;
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface AuthenticationResult {
|
|
58
|
+
success: boolean;
|
|
59
|
+
credentialId?: string;
|
|
60
|
+
userHandle?: string;
|
|
61
|
+
error?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Types for WebAuthn API
|
|
65
|
+
*/
|
|
66
|
+
export interface PublicKeyCredentialCreationOptionsJSON {
|
|
67
|
+
challenge: string;
|
|
68
|
+
rp: {
|
|
69
|
+
id: string;
|
|
70
|
+
name: string;
|
|
71
|
+
};
|
|
72
|
+
user: {
|
|
73
|
+
id: string;
|
|
74
|
+
name: string;
|
|
75
|
+
displayName: string;
|
|
76
|
+
icon?: string;
|
|
77
|
+
};
|
|
78
|
+
pubKeyCredParams: {
|
|
79
|
+
type: string;
|
|
80
|
+
alg: number;
|
|
81
|
+
}[];
|
|
82
|
+
excludeCredentials?: {
|
|
83
|
+
id: string;
|
|
84
|
+
type: string;
|
|
85
|
+
}[];
|
|
86
|
+
authenticatorSelection?: {
|
|
87
|
+
authenticatorAttachment?: 'platform' | 'cross-platform';
|
|
88
|
+
requireResidentKey?: boolean;
|
|
89
|
+
userVerification?: 'required' | 'preferred' | 'discouraged';
|
|
90
|
+
};
|
|
91
|
+
attestation?: 'none' | 'indirect' | 'direct';
|
|
92
|
+
timeout?: number;
|
|
93
|
+
}
|
|
94
|
+
export interface PublicKeyCredentialRequestOptionsJSON {
|
|
95
|
+
challenge: string;
|
|
96
|
+
rpId?: string;
|
|
97
|
+
allowCredentials?: {
|
|
98
|
+
id: string;
|
|
99
|
+
type: string;
|
|
100
|
+
}[];
|
|
101
|
+
userVerification?: 'required' | 'preferred' | 'discouraged';
|
|
102
|
+
timeout?: number;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* WebAuthn Handler class
|
|
106
|
+
*/
|
|
107
|
+
export declare class WebAuthnHandler {
|
|
108
|
+
private config;
|
|
109
|
+
private credentials;
|
|
110
|
+
constructor(config: WebAuthnConfig);
|
|
111
|
+
/**
|
|
112
|
+
* Generate a random challenge for WebAuthn
|
|
113
|
+
*/
|
|
114
|
+
generateChallenge(): string;
|
|
115
|
+
/**
|
|
116
|
+
* Create registration options for WebAuthn navigator.credentials.create()
|
|
117
|
+
*/
|
|
118
|
+
createRegistrationOptions(user: WebAuthnUser, excludeCredentials?: string[]): PublicKeyCredentialCreationOptionsJSON;
|
|
119
|
+
/**
|
|
120
|
+
* Parse registration response from navigator.credentials.create()
|
|
121
|
+
*/
|
|
122
|
+
parseRegistration(response: any): Promise<RegistrationResult>;
|
|
123
|
+
/**
|
|
124
|
+
* Create authentication options for WebAuthn navigator.credentials.get()
|
|
125
|
+
*/
|
|
126
|
+
createAuthenticationOptions(allowedCredentials?: string[]): PublicKeyCredentialRequestOptionsJSON;
|
|
127
|
+
/**
|
|
128
|
+
* Parse authentication response from navigator.credentials.get()
|
|
129
|
+
*/
|
|
130
|
+
parseAuthentication(response: any): Promise<AuthenticationResult>;
|
|
131
|
+
/**
|
|
132
|
+
* Get stored credential by ID
|
|
133
|
+
*/
|
|
134
|
+
getCredential(credentialId: string): WebAuthnCredential | undefined;
|
|
135
|
+
/**
|
|
136
|
+
* Get all stored credentials for a user
|
|
137
|
+
*/
|
|
138
|
+
getCredentials(): WebAuthnCredential[];
|
|
139
|
+
/**
|
|
140
|
+
* Check if WebAuthn is supported in current browser
|
|
141
|
+
*/
|
|
142
|
+
isSupported(): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Check if platform authenticator is available
|
|
145
|
+
*/
|
|
146
|
+
isPlatformAvailable(): Promise<boolean>;
|
|
147
|
+
/**
|
|
148
|
+
* Check if conditional mediation (autofill) is supported
|
|
149
|
+
*/
|
|
150
|
+
isConditionalMediationSupported(): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Store credential externally
|
|
153
|
+
*/
|
|
154
|
+
storeCredential(credential: WebAuthnCredential): void;
|
|
155
|
+
/**
|
|
156
|
+
* Remove credential
|
|
157
|
+
*/
|
|
158
|
+
removeCredential(credentialId: string): boolean;
|
|
159
|
+
/**
|
|
160
|
+
* Clear all credentials
|
|
161
|
+
*/
|
|
162
|
+
clearCredentials(): void;
|
|
163
|
+
/**
|
|
164
|
+
* Helper: Convert ArrayBuffer to Base64
|
|
165
|
+
*/
|
|
166
|
+
private bufferToBase64;
|
|
167
|
+
/**
|
|
168
|
+
* Helper: Convert Base64 to Uint8Array
|
|
169
|
+
*/
|
|
170
|
+
private base64ToBuffer;
|
|
171
|
+
/**
|
|
172
|
+
* Helper to extract public key from attestation object
|
|
173
|
+
* This is a simplified version - full CBOR parsing would be more complex
|
|
174
|
+
*/
|
|
175
|
+
private extractPublicKeyFromAttestation;
|
|
176
|
+
private decoder;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Factory function to create WebAuthn handler
|
|
180
|
+
*/
|
|
181
|
+
export declare function createWebAuthnHandler(config: WebAuthnConfig): WebAuthnHandler;
|
|
182
|
+
export default WebAuthnHandler;
|