recker 1.0.20-next.b961eae → 1.0.20-next.e194d90
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 +31 -0
- package/dist/ai/adaptive-timeout.d.ts +0 -1
- package/dist/ai/client.d.ts +0 -1
- package/dist/ai/client.js +6 -0
- package/dist/ai/index.d.ts +3 -1
- package/dist/ai/index.js +3 -0
- package/dist/ai/providers/anthropic.d.ts +0 -1
- package/dist/ai/providers/base.d.ts +0 -1
- package/dist/ai/providers/google.d.ts +59 -0
- package/dist/ai/providers/google.js +305 -0
- package/dist/ai/providers/index.d.ts +4 -1
- package/dist/ai/providers/index.js +2 -0
- package/dist/ai/providers/ollama.d.ts +44 -0
- package/dist/ai/providers/ollama.js +240 -0
- package/dist/ai/providers/openai.d.ts +0 -1
- package/dist/ai/rate-limiter.d.ts +0 -1
- package/dist/ai/vector/index.d.ts +2 -0
- package/dist/ai/vector/index.js +2 -0
- package/dist/ai/vector/similarity.d.ts +2 -0
- package/dist/ai/vector/similarity.js +27 -0
- package/dist/ai/vector/store.d.ts +27 -0
- package/dist/ai/vector/store.js +82 -0
- package/dist/bench/generator.d.ts +0 -1
- package/dist/bench/stats.d.ts +0 -1
- package/dist/cache/basic-file-storage.d.ts +12 -0
- package/dist/cache/basic-file-storage.js +50 -0
- package/dist/cache/file-storage.d.ts +25 -11
- package/dist/cache/file-storage.js +175 -30
- package/dist/cache/memory-limits.d.ts +0 -1
- package/dist/cache/memory-storage.d.ts +0 -1
- package/dist/cache/redis-storage.d.ts +0 -1
- package/dist/cli/handler.d.ts +2 -1
- package/dist/cli/handler.js +36 -5
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +559 -5
- package/dist/cli/presets.d.ts +0 -1
- package/dist/cli/tui/ai-chat.d.ts +0 -1
- package/dist/cli/tui/load-dashboard.d.ts +0 -1
- package/dist/cli/tui/scroll-buffer.d.ts +0 -1
- package/dist/cli/tui/search-panel.d.ts +0 -1
- package/dist/cli/tui/shell-search.d.ts +0 -1
- package/dist/cli/tui/shell.d.ts +0 -1
- package/dist/cli/tui/websocket.d.ts +0 -1
- package/dist/constants/http-status.d.ts +0 -1
- package/dist/constants.d.ts +0 -1
- package/dist/contract/index.d.ts +0 -1
- package/dist/cookies/memory-cookie-jar.d.ts +0 -1
- package/dist/core/client.d.ts +0 -1
- package/dist/core/client.js +1 -1
- package/dist/core/errors.d.ts +0 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/request-promise.d.ts +0 -1
- package/dist/core/request.d.ts +0 -1
- package/dist/core/response.d.ts +0 -1
- package/dist/dns/index.d.ts +0 -1
- package/dist/dns/propagation.d.ts +0 -1
- package/dist/events/request-events.d.ts +0 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -0
- package/dist/mcp/client.d.ts +0 -1
- package/dist/mcp/contract.d.ts +0 -1
- package/dist/mcp/embeddings-loader.d.ts +0 -1
- package/dist/mcp/geoip-loader.d.ts +0 -1
- package/dist/mcp/index.d.ts +0 -1
- package/dist/mcp/ip-intel.d.ts +0 -1
- package/dist/mcp/search/hybrid-search.d.ts +0 -1
- package/dist/mcp/search/index.d.ts +0 -1
- package/dist/mcp/search/math.d.ts +0 -1
- package/dist/mcp/search/types.d.ts +0 -1
- package/dist/mcp/server.d.ts +6 -2
- package/dist/mcp/server.js +193 -151
- package/dist/mcp/tools/loader.d.ts +2 -0
- package/dist/mcp/tools/loader.js +41 -0
- package/dist/mcp/tools/network.d.ts +3 -0
- package/dist/mcp/tools/network.js +267 -0
- package/dist/mcp/tools/registry.d.ts +17 -0
- package/dist/mcp/tools/registry.js +37 -0
- package/dist/mcp/types.d.ts +0 -1
- package/dist/plugins/auth/api-key.d.ts +8 -0
- package/dist/plugins/auth/api-key.js +27 -0
- package/dist/plugins/auth/auth0.d.ts +33 -0
- package/dist/plugins/auth/auth0.js +94 -0
- package/dist/plugins/auth/aws-sigv4.d.ts +10 -0
- package/dist/plugins/auth/aws-sigv4.js +88 -0
- package/dist/plugins/auth/azure-ad.d.ts +48 -0
- package/dist/plugins/auth/azure-ad.js +152 -0
- package/dist/plugins/auth/basic.d.ts +7 -0
- package/dist/plugins/auth/basic.js +13 -0
- package/dist/plugins/auth/bearer.d.ts +8 -0
- package/dist/plugins/auth/bearer.js +17 -0
- package/dist/plugins/auth/cognito.d.ts +45 -0
- package/dist/plugins/auth/cognito.js +208 -0
- package/dist/plugins/auth/digest.d.ts +8 -0
- package/dist/plugins/auth/digest.js +100 -0
- package/dist/plugins/auth/firebase.d.ts +32 -0
- package/dist/plugins/auth/firebase.js +195 -0
- package/dist/plugins/auth/github-app.d.ts +36 -0
- package/dist/plugins/auth/github-app.js +170 -0
- package/dist/plugins/auth/google-service-account.d.ts +49 -0
- package/dist/plugins/auth/google-service-account.js +172 -0
- package/dist/plugins/auth/index.d.ts +15 -0
- package/dist/plugins/auth/index.js +15 -0
- package/dist/plugins/auth/mtls.d.ts +37 -0
- package/dist/plugins/auth/mtls.js +140 -0
- package/dist/plugins/auth/oauth2.d.ts +8 -0
- package/dist/plugins/auth/oauth2.js +26 -0
- package/dist/plugins/auth/oidc.d.ts +55 -0
- package/dist/plugins/auth/oidc.js +222 -0
- package/dist/plugins/auth/okta.d.ts +47 -0
- package/dist/plugins/auth/okta.js +157 -0
- package/dist/plugins/auth.d.ts +1 -45
- package/dist/plugins/auth.js +1 -268
- package/dist/plugins/cache.d.ts +0 -1
- package/dist/plugins/certificate-pinning.d.ts +59 -0
- package/dist/plugins/certificate-pinning.js +236 -0
- package/dist/plugins/circuit-breaker.d.ts +0 -1
- package/dist/plugins/compression.d.ts +0 -1
- package/dist/plugins/cookie-jar.d.ts +0 -1
- package/dist/plugins/dedup.d.ts +0 -1
- package/dist/plugins/graphql.d.ts +0 -1
- package/dist/plugins/grpc-web.d.ts +0 -1
- package/dist/plugins/har-player.d.ts +0 -1
- package/dist/plugins/har-recorder.d.ts +0 -1
- package/dist/plugins/hls.d.ts +0 -1
- package/dist/plugins/http2-push.d.ts +0 -1
- package/dist/plugins/http3.d.ts +0 -1
- package/dist/plugins/index.d.ts +27 -0
- package/dist/plugins/index.js +27 -0
- package/dist/plugins/interface-rotator.d.ts +0 -1
- package/dist/plugins/jsonrpc.d.ts +0 -1
- package/dist/plugins/logger.d.ts +0 -1
- package/dist/plugins/odata.d.ts +0 -1
- package/dist/plugins/pagination.d.ts +0 -1
- package/dist/plugins/proxy-rotator.d.ts +0 -1
- package/dist/plugins/rate-limit.d.ts +15 -0
- package/dist/plugins/rate-limit.js +162 -0
- package/dist/plugins/retry.d.ts +0 -1
- package/dist/plugins/scrape.d.ts +0 -1
- package/dist/plugins/server-timing.d.ts +0 -1
- package/dist/plugins/soap.d.ts +0 -1
- package/dist/plugins/user-agent.d.ts +0 -1
- package/dist/plugins/xml.d.ts +0 -1
- package/dist/plugins/xsrf.d.ts +0 -1
- package/dist/presets/anthropic.d.ts +0 -1
- package/dist/presets/aws.d.ts +0 -1
- package/dist/presets/azure-openai.d.ts +0 -1
- package/dist/presets/azure.d.ts +0 -1
- package/dist/presets/cloudflare.d.ts +0 -1
- package/dist/presets/cohere.d.ts +0 -1
- package/dist/presets/deepseek.d.ts +0 -1
- package/dist/presets/digitalocean.d.ts +0 -1
- package/dist/presets/discord.d.ts +0 -1
- package/dist/presets/fireworks.d.ts +0 -1
- package/dist/presets/gcp.d.ts +0 -1
- package/dist/presets/gemini.d.ts +0 -1
- package/dist/presets/github.d.ts +0 -1
- package/dist/presets/gitlab.d.ts +0 -1
- package/dist/presets/groq.d.ts +0 -1
- package/dist/presets/huggingface.d.ts +0 -1
- package/dist/presets/index.d.ts +0 -1
- package/dist/presets/linear.d.ts +0 -1
- package/dist/presets/mailgun.d.ts +0 -1
- package/dist/presets/meta.d.ts +0 -1
- package/dist/presets/mistral.d.ts +0 -1
- package/dist/presets/notion.d.ts +0 -1
- package/dist/presets/openai.d.ts +0 -1
- package/dist/presets/oracle.d.ts +0 -1
- package/dist/presets/perplexity.d.ts +0 -1
- package/dist/presets/registry.d.ts +0 -1
- package/dist/presets/replicate.d.ts +0 -1
- package/dist/presets/sinch.d.ts +0 -1
- package/dist/presets/slack.d.ts +0 -1
- package/dist/presets/stripe.d.ts +0 -1
- package/dist/presets/supabase.d.ts +0 -1
- package/dist/presets/tiktok.d.ts +0 -1
- package/dist/presets/together.d.ts +0 -1
- package/dist/presets/twilio.d.ts +0 -1
- package/dist/presets/vercel.d.ts +0 -1
- package/dist/presets/vultr.d.ts +0 -1
- package/dist/presets/xai.d.ts +0 -1
- package/dist/presets/youtube.d.ts +0 -1
- package/dist/protocols/ftp.d.ts +0 -1
- package/dist/protocols/index.d.ts +0 -1
- package/dist/protocols/sftp.d.ts +0 -1
- package/dist/protocols/telnet.d.ts +0 -1
- package/dist/recker.d.ts +0 -1
- package/dist/runner/request-runner.d.ts +0 -1
- package/dist/scrape/document.d.ts +0 -1
- package/dist/scrape/element.d.ts +0 -1
- package/dist/scrape/extractors.d.ts +0 -1
- package/dist/scrape/index.d.ts +0 -1
- package/dist/scrape/types.d.ts +0 -1
- package/dist/testing/index.d.ts +8 -1
- package/dist/testing/index.js +4 -0
- package/dist/testing/mock-dns-server.d.ts +69 -0
- package/dist/testing/mock-dns-server.js +269 -0
- package/dist/testing/mock-ftp-server.d.ts +89 -0
- package/dist/testing/mock-ftp-server.js +562 -0
- package/dist/testing/mock-hls-server.d.ts +0 -1
- package/dist/testing/mock-http-server.d.ts +0 -1
- package/dist/testing/mock-sse-server.d.ts +0 -1
- package/dist/testing/mock-telnet-server.d.ts +59 -0
- package/dist/testing/mock-telnet-server.js +273 -0
- package/dist/testing/mock-udp-server.d.ts +0 -1
- package/dist/testing/mock-websocket-server.d.ts +0 -1
- package/dist/testing/mock-whois-server.d.ts +56 -0
- package/dist/testing/mock-whois-server.js +234 -0
- package/dist/testing/mock.d.ts +0 -1
- package/dist/transport/base-udp.d.ts +0 -1
- package/dist/transport/fetch.d.ts +0 -1
- package/dist/transport/udp-response.d.ts +0 -1
- package/dist/transport/udp.d.ts +0 -1
- package/dist/transport/undici.d.ts +0 -1
- package/dist/types/ai.d.ts +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/logger.d.ts +0 -1
- package/dist/types/udp.d.ts +0 -1
- package/dist/udp/index.d.ts +0 -1
- package/dist/utils/agent-manager.d.ts +0 -1
- package/dist/utils/body.d.ts +0 -1
- package/dist/utils/cert.d.ts +0 -1
- package/dist/utils/charset.d.ts +0 -1
- package/dist/utils/chart.d.ts +0 -1
- package/dist/utils/client-pool.d.ts +0 -1
- package/dist/utils/colors.d.ts +0 -1
- package/dist/utils/concurrency.d.ts +0 -1
- package/dist/utils/dns-toolkit.d.ts +0 -1
- package/dist/utils/dns.d.ts +0 -1
- package/dist/utils/doh.d.ts +0 -1
- package/dist/utils/download.d.ts +0 -1
- package/dist/utils/env-proxy.d.ts +0 -1
- package/dist/utils/header-parser.d.ts +0 -1
- package/dist/utils/html-cleaner.d.ts +0 -1
- package/dist/utils/link-header.d.ts +0 -1
- package/dist/utils/optional-require.d.ts +0 -1
- package/dist/utils/progress.d.ts +0 -1
- package/dist/utils/rdap.d.ts +0 -1
- package/dist/utils/request-pool.d.ts +0 -1
- package/dist/utils/security-grader.d.ts +0 -1
- package/dist/utils/sparkline.d.ts +0 -1
- package/dist/utils/sse.d.ts +0 -1
- package/dist/utils/streaming.d.ts +0 -1
- package/dist/utils/system-metrics.d.ts +0 -1
- package/dist/utils/tls-inspector.d.ts +0 -1
- package/dist/utils/try-fn.d.ts +0 -1
- package/dist/utils/upload.d.ts +0 -1
- package/dist/utils/user-agent.d.ts +0 -1
- package/dist/utils/whois.d.ts +0 -1
- package/dist/webrtc/index.d.ts +0 -1
- package/dist/websocket/client.d.ts +0 -1
- package/package.json +10 -3
- package/dist/ai/adaptive-timeout.d.ts.map +0 -1
- package/dist/ai/client.d.ts.map +0 -1
- package/dist/ai/index.d.ts.map +0 -1
- package/dist/ai/providers/anthropic.d.ts.map +0 -1
- package/dist/ai/providers/base.d.ts.map +0 -1
- package/dist/ai/providers/index.d.ts.map +0 -1
- package/dist/ai/providers/openai.d.ts.map +0 -1
- package/dist/ai/rate-limiter.d.ts.map +0 -1
- package/dist/bench/generator.d.ts.map +0 -1
- package/dist/bench/stats.d.ts.map +0 -1
- package/dist/cache/file-storage.d.ts.map +0 -1
- package/dist/cache/memory-limits.d.ts.map +0 -1
- package/dist/cache/memory-storage.d.ts.map +0 -1
- package/dist/cache/redis-storage.d.ts.map +0 -1
- package/dist/cli/handler.d.ts.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/presets.d.ts.map +0 -1
- package/dist/cli/tui/ai-chat.d.ts.map +0 -1
- package/dist/cli/tui/load-dashboard.d.ts.map +0 -1
- package/dist/cli/tui/scroll-buffer.d.ts.map +0 -1
- package/dist/cli/tui/search-panel.d.ts.map +0 -1
- package/dist/cli/tui/shell-search.d.ts.map +0 -1
- package/dist/cli/tui/shell.d.ts.map +0 -1
- package/dist/cli/tui/websocket.d.ts.map +0 -1
- package/dist/constants/http-status.d.ts.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/contract/index.d.ts.map +0 -1
- package/dist/cookies/memory-cookie-jar.d.ts.map +0 -1
- package/dist/core/client.d.ts.map +0 -1
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/request-promise.d.ts.map +0 -1
- package/dist/core/request.d.ts.map +0 -1
- package/dist/core/response.d.ts.map +0 -1
- package/dist/dns/index.d.ts.map +0 -1
- package/dist/dns/propagation.d.ts.map +0 -1
- package/dist/events/request-events.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/mcp/client.d.ts.map +0 -1
- package/dist/mcp/contract.d.ts.map +0 -1
- package/dist/mcp/embeddings-loader.d.ts.map +0 -1
- package/dist/mcp/geoip-loader.d.ts.map +0 -1
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/ip-intel.d.ts.map +0 -1
- package/dist/mcp/search/hybrid-search.d.ts.map +0 -1
- package/dist/mcp/search/index.d.ts.map +0 -1
- package/dist/mcp/search/math.d.ts.map +0 -1
- package/dist/mcp/search/types.d.ts.map +0 -1
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/plugins/auth.d.ts.map +0 -1
- package/dist/plugins/cache.d.ts.map +0 -1
- package/dist/plugins/circuit-breaker.d.ts.map +0 -1
- package/dist/plugins/compression.d.ts.map +0 -1
- package/dist/plugins/cookie-jar.d.ts.map +0 -1
- package/dist/plugins/dedup.d.ts.map +0 -1
- package/dist/plugins/graphql.d.ts.map +0 -1
- package/dist/plugins/grpc-web.d.ts.map +0 -1
- package/dist/plugins/har-player.d.ts.map +0 -1
- package/dist/plugins/har-recorder.d.ts.map +0 -1
- package/dist/plugins/hls.d.ts.map +0 -1
- package/dist/plugins/http2-push.d.ts.map +0 -1
- package/dist/plugins/http3.d.ts.map +0 -1
- package/dist/plugins/interface-rotator.d.ts.map +0 -1
- package/dist/plugins/jsonrpc.d.ts.map +0 -1
- package/dist/plugins/logger.d.ts.map +0 -1
- package/dist/plugins/odata.d.ts.map +0 -1
- package/dist/plugins/pagination.d.ts.map +0 -1
- package/dist/plugins/proxy-rotator.d.ts.map +0 -1
- package/dist/plugins/retry.d.ts.map +0 -1
- package/dist/plugins/scrape.d.ts.map +0 -1
- package/dist/plugins/server-timing.d.ts.map +0 -1
- package/dist/plugins/soap.d.ts.map +0 -1
- package/dist/plugins/user-agent.d.ts.map +0 -1
- package/dist/plugins/xml.d.ts.map +0 -1
- package/dist/plugins/xsrf.d.ts.map +0 -1
- package/dist/presets/anthropic.d.ts.map +0 -1
- package/dist/presets/aws.d.ts.map +0 -1
- package/dist/presets/azure-openai.d.ts.map +0 -1
- package/dist/presets/azure.d.ts.map +0 -1
- package/dist/presets/cloudflare.d.ts.map +0 -1
- package/dist/presets/cohere.d.ts.map +0 -1
- package/dist/presets/deepseek.d.ts.map +0 -1
- package/dist/presets/digitalocean.d.ts.map +0 -1
- package/dist/presets/discord.d.ts.map +0 -1
- package/dist/presets/fireworks.d.ts.map +0 -1
- package/dist/presets/gcp.d.ts.map +0 -1
- package/dist/presets/gemini.d.ts.map +0 -1
- package/dist/presets/github.d.ts.map +0 -1
- package/dist/presets/gitlab.d.ts.map +0 -1
- package/dist/presets/groq.d.ts.map +0 -1
- package/dist/presets/huggingface.d.ts.map +0 -1
- package/dist/presets/index.d.ts.map +0 -1
- package/dist/presets/linear.d.ts.map +0 -1
- package/dist/presets/mailgun.d.ts.map +0 -1
- package/dist/presets/meta.d.ts.map +0 -1
- package/dist/presets/mistral.d.ts.map +0 -1
- package/dist/presets/notion.d.ts.map +0 -1
- package/dist/presets/openai.d.ts.map +0 -1
- package/dist/presets/oracle.d.ts.map +0 -1
- package/dist/presets/perplexity.d.ts.map +0 -1
- package/dist/presets/registry.d.ts.map +0 -1
- package/dist/presets/replicate.d.ts.map +0 -1
- package/dist/presets/sinch.d.ts.map +0 -1
- package/dist/presets/slack.d.ts.map +0 -1
- package/dist/presets/stripe.d.ts.map +0 -1
- package/dist/presets/supabase.d.ts.map +0 -1
- package/dist/presets/tiktok.d.ts.map +0 -1
- package/dist/presets/together.d.ts.map +0 -1
- package/dist/presets/twilio.d.ts.map +0 -1
- package/dist/presets/vercel.d.ts.map +0 -1
- package/dist/presets/vultr.d.ts.map +0 -1
- package/dist/presets/xai.d.ts.map +0 -1
- package/dist/presets/youtube.d.ts.map +0 -1
- package/dist/protocols/ftp.d.ts.map +0 -1
- package/dist/protocols/index.d.ts.map +0 -1
- package/dist/protocols/sftp.d.ts.map +0 -1
- package/dist/protocols/telnet.d.ts.map +0 -1
- package/dist/recker.d.ts.map +0 -1
- package/dist/runner/request-runner.d.ts.map +0 -1
- package/dist/scrape/document.d.ts.map +0 -1
- package/dist/scrape/element.d.ts.map +0 -1
- package/dist/scrape/extractors.d.ts.map +0 -1
- package/dist/scrape/index.d.ts.map +0 -1
- package/dist/scrape/types.d.ts.map +0 -1
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/mock-hls-server.d.ts.map +0 -1
- package/dist/testing/mock-http-server.d.ts.map +0 -1
- package/dist/testing/mock-sse-server.d.ts.map +0 -1
- package/dist/testing/mock-udp-server.d.ts.map +0 -1
- package/dist/testing/mock-websocket-server.d.ts.map +0 -1
- package/dist/testing/mock.d.ts.map +0 -1
- package/dist/transport/base-udp.d.ts.map +0 -1
- package/dist/transport/fetch.d.ts.map +0 -1
- package/dist/transport/udp-response.d.ts.map +0 -1
- package/dist/transport/udp.d.ts.map +0 -1
- package/dist/transport/undici.d.ts.map +0 -1
- package/dist/types/ai.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/logger.d.ts.map +0 -1
- package/dist/types/udp.d.ts.map +0 -1
- package/dist/udp/index.d.ts.map +0 -1
- package/dist/utils/agent-manager.d.ts.map +0 -1
- package/dist/utils/body.d.ts.map +0 -1
- package/dist/utils/cert.d.ts.map +0 -1
- package/dist/utils/charset.d.ts.map +0 -1
- package/dist/utils/chart.d.ts.map +0 -1
- package/dist/utils/client-pool.d.ts.map +0 -1
- package/dist/utils/colors.d.ts.map +0 -1
- package/dist/utils/concurrency.d.ts.map +0 -1
- package/dist/utils/dns-toolkit.d.ts.map +0 -1
- package/dist/utils/dns.d.ts.map +0 -1
- package/dist/utils/doh.d.ts.map +0 -1
- package/dist/utils/download.d.ts.map +0 -1
- package/dist/utils/env-proxy.d.ts.map +0 -1
- package/dist/utils/header-parser.d.ts.map +0 -1
- package/dist/utils/html-cleaner.d.ts.map +0 -1
- package/dist/utils/link-header.d.ts.map +0 -1
- package/dist/utils/optional-require.d.ts.map +0 -1
- package/dist/utils/progress.d.ts.map +0 -1
- package/dist/utils/rdap.d.ts.map +0 -1
- package/dist/utils/request-pool.d.ts.map +0 -1
- package/dist/utils/security-grader.d.ts.map +0 -1
- package/dist/utils/sparkline.d.ts.map +0 -1
- package/dist/utils/sse.d.ts.map +0 -1
- package/dist/utils/streaming.d.ts.map +0 -1
- package/dist/utils/system-metrics.d.ts.map +0 -1
- package/dist/utils/tls-inspector.d.ts.map +0 -1
- package/dist/utils/try-fn.d.ts.map +0 -1
- package/dist/utils/upload.d.ts.map +0 -1
- package/dist/utils/user-agent.d.ts.map +0 -1
- package/dist/utils/whois.d.ts.map +0 -1
- package/dist/webrtc/index.d.ts.map +0 -1
- package/dist/websocket/client.d.ts.map +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Middleware, Plugin } from '../../types/index.js';
|
|
2
|
+
import type { Dispatcher } from 'undici';
|
|
3
|
+
export interface MTLSOptions {
|
|
4
|
+
cert: string | Buffer;
|
|
5
|
+
key: string | Buffer;
|
|
6
|
+
ca?: string | Buffer | Array<string | Buffer>;
|
|
7
|
+
passphrase?: string;
|
|
8
|
+
certPath?: string;
|
|
9
|
+
keyPath?: string;
|
|
10
|
+
caPath?: string;
|
|
11
|
+
rejectUnauthorized?: boolean;
|
|
12
|
+
pfx?: string | Buffer;
|
|
13
|
+
pfxPassphrase?: string;
|
|
14
|
+
servername?: string;
|
|
15
|
+
minVersion?: 'TLSv1.2' | 'TLSv1.3';
|
|
16
|
+
maxVersion?: 'TLSv1.2' | 'TLSv1.3';
|
|
17
|
+
ciphers?: string;
|
|
18
|
+
ALPNProtocols?: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface MTLSCertificateInfo {
|
|
21
|
+
subject: Record<string, string>;
|
|
22
|
+
issuer: Record<string, string>;
|
|
23
|
+
validFrom: Date;
|
|
24
|
+
validTo: Date;
|
|
25
|
+
fingerprint: string;
|
|
26
|
+
serialNumber: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function parseCertificateInfo(cert: string | Buffer): MTLSCertificateInfo | null;
|
|
29
|
+
export declare function isCertificateValid(cert: string | Buffer, bufferDays?: number): {
|
|
30
|
+
valid: boolean;
|
|
31
|
+
expiresAt?: Date;
|
|
32
|
+
error?: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function mtls(options: MTLSOptions): Middleware;
|
|
35
|
+
export declare function mtlsPlugin(options: MTLSOptions): Plugin;
|
|
36
|
+
export declare function createMTLSAgent(options: MTLSOptions): Promise<Dispatcher>;
|
|
37
|
+
export declare function verifyCertificateFingerprint(cert: string | Buffer, expectedFingerprint: string): boolean;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
async function loadCertificateFile(path) {
|
|
2
|
+
const fs = await import('node:fs/promises');
|
|
3
|
+
return fs.readFile(path);
|
|
4
|
+
}
|
|
5
|
+
export function parseCertificateInfo(cert) {
|
|
6
|
+
try {
|
|
7
|
+
const crypto = require('node:crypto');
|
|
8
|
+
const x509 = new crypto.X509Certificate(cert);
|
|
9
|
+
return {
|
|
10
|
+
subject: parseX509Name(x509.subject),
|
|
11
|
+
issuer: parseX509Name(x509.issuer),
|
|
12
|
+
validFrom: new Date(x509.validFrom),
|
|
13
|
+
validTo: new Date(x509.validTo),
|
|
14
|
+
fingerprint: x509.fingerprint256,
|
|
15
|
+
serialNumber: x509.serialNumber,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function parseX509Name(name) {
|
|
23
|
+
const result = {};
|
|
24
|
+
const parts = name.split('\n');
|
|
25
|
+
for (const part of parts) {
|
|
26
|
+
const [key, value] = part.split('=');
|
|
27
|
+
if (key && value) {
|
|
28
|
+
result[key.trim()] = value.trim();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
export function isCertificateValid(cert, bufferDays = 30) {
|
|
34
|
+
const info = parseCertificateInfo(cert);
|
|
35
|
+
if (!info) {
|
|
36
|
+
return { valid: false, error: 'Failed to parse certificate' };
|
|
37
|
+
}
|
|
38
|
+
const now = new Date();
|
|
39
|
+
const bufferMs = bufferDays * 24 * 60 * 60 * 1000;
|
|
40
|
+
if (now < info.validFrom) {
|
|
41
|
+
return { valid: false, expiresAt: info.validTo, error: 'Certificate not yet valid' };
|
|
42
|
+
}
|
|
43
|
+
if (now > info.validTo) {
|
|
44
|
+
return { valid: false, expiresAt: info.validTo, error: 'Certificate expired' };
|
|
45
|
+
}
|
|
46
|
+
if (now.getTime() + bufferMs > info.validTo.getTime()) {
|
|
47
|
+
return { valid: true, expiresAt: info.validTo, error: `Certificate expires soon (${info.validTo.toISOString()})` };
|
|
48
|
+
}
|
|
49
|
+
return { valid: true, expiresAt: info.validTo };
|
|
50
|
+
}
|
|
51
|
+
async function createTLSOptions(options) {
|
|
52
|
+
const tlsOptions = {};
|
|
53
|
+
if (options.certPath) {
|
|
54
|
+
tlsOptions.cert = await loadCertificateFile(options.certPath);
|
|
55
|
+
}
|
|
56
|
+
else if (options.cert) {
|
|
57
|
+
tlsOptions.cert = options.cert;
|
|
58
|
+
}
|
|
59
|
+
if (options.keyPath) {
|
|
60
|
+
tlsOptions.key = await loadCertificateFile(options.keyPath);
|
|
61
|
+
}
|
|
62
|
+
else if (options.key) {
|
|
63
|
+
tlsOptions.key = options.key;
|
|
64
|
+
}
|
|
65
|
+
if (options.caPath) {
|
|
66
|
+
tlsOptions.ca = await loadCertificateFile(options.caPath);
|
|
67
|
+
}
|
|
68
|
+
else if (options.ca) {
|
|
69
|
+
tlsOptions.ca = options.ca;
|
|
70
|
+
}
|
|
71
|
+
if (options.passphrase) {
|
|
72
|
+
tlsOptions.passphrase = options.passphrase;
|
|
73
|
+
}
|
|
74
|
+
if (options.pfx) {
|
|
75
|
+
tlsOptions.pfx = options.pfx;
|
|
76
|
+
if (options.pfxPassphrase) {
|
|
77
|
+
tlsOptions.passphrase = options.pfxPassphrase;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (options.rejectUnauthorized !== undefined) {
|
|
81
|
+
tlsOptions.rejectUnauthorized = options.rejectUnauthorized;
|
|
82
|
+
}
|
|
83
|
+
if (options.servername) {
|
|
84
|
+
tlsOptions.servername = options.servername;
|
|
85
|
+
}
|
|
86
|
+
if (options.minVersion) {
|
|
87
|
+
tlsOptions.minVersion = options.minVersion;
|
|
88
|
+
}
|
|
89
|
+
if (options.maxVersion) {
|
|
90
|
+
tlsOptions.maxVersion = options.maxVersion;
|
|
91
|
+
}
|
|
92
|
+
if (options.ciphers) {
|
|
93
|
+
tlsOptions.ciphers = options.ciphers;
|
|
94
|
+
}
|
|
95
|
+
if (options.ALPNProtocols) {
|
|
96
|
+
tlsOptions.ALPNProtocols = options.ALPNProtocols;
|
|
97
|
+
}
|
|
98
|
+
return tlsOptions;
|
|
99
|
+
}
|
|
100
|
+
export function mtls(options) {
|
|
101
|
+
let validated = false;
|
|
102
|
+
return async (req, next) => {
|
|
103
|
+
if (!validated) {
|
|
104
|
+
if (options.cert || options.certPath) {
|
|
105
|
+
const cert = options.cert || (options.certPath ? await loadCertificateFile(options.certPath) : null);
|
|
106
|
+
if (cert) {
|
|
107
|
+
const validation = isCertificateValid(cert);
|
|
108
|
+
if (!validation.valid) {
|
|
109
|
+
throw new Error(`mTLS certificate error: ${validation.error}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
validated = true;
|
|
114
|
+
}
|
|
115
|
+
return next(req);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export function mtlsPlugin(options) {
|
|
119
|
+
return (client) => {
|
|
120
|
+
client.use(mtls(options));
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
export async function createMTLSAgent(options) {
|
|
124
|
+
const { Agent } = await import('undici');
|
|
125
|
+
const tlsOptions = await createTLSOptions(options);
|
|
126
|
+
return new Agent({
|
|
127
|
+
connect: {
|
|
128
|
+
...tlsOptions,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
export function verifyCertificateFingerprint(cert, expectedFingerprint) {
|
|
133
|
+
const info = parseCertificateInfo(cert);
|
|
134
|
+
if (!info) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
const normalizedExpected = expectedFingerprint.replace(/:/g, '').toLowerCase();
|
|
138
|
+
const normalizedActual = info.fingerprint.replace(/:/g, '').toLowerCase();
|
|
139
|
+
return normalizedExpected === normalizedActual;
|
|
140
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Middleware, Plugin } from '../../types/index.js';
|
|
2
|
+
export interface OAuth2Options {
|
|
3
|
+
accessToken: string | (() => string | Promise<string>);
|
|
4
|
+
tokenType?: string;
|
|
5
|
+
onTokenExpired?: () => Promise<string>;
|
|
6
|
+
}
|
|
7
|
+
export declare function oauth2(options: OAuth2Options): Middleware;
|
|
8
|
+
export declare function oauth2Plugin(options: OAuth2Options): Plugin;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function oauth2(options) {
|
|
2
|
+
const tokenType = options.tokenType ?? 'Bearer';
|
|
3
|
+
return async (req, next) => {
|
|
4
|
+
const token = typeof options.accessToken === 'function'
|
|
5
|
+
? await options.accessToken()
|
|
6
|
+
: options.accessToken;
|
|
7
|
+
const authReq = req.withHeader('Authorization', `${tokenType} ${token}`);
|
|
8
|
+
const response = await next(authReq);
|
|
9
|
+
if (response.status === 401 && options.onTokenExpired) {
|
|
10
|
+
try {
|
|
11
|
+
const newToken = await options.onTokenExpired();
|
|
12
|
+
const retryReq = req.withHeader('Authorization', `${tokenType} ${newToken}`);
|
|
13
|
+
return next(retryReq);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return response;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return response;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function oauth2Plugin(options) {
|
|
23
|
+
return (client) => {
|
|
24
|
+
client.use(oauth2(options));
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Middleware, Plugin } from '../../types/index.js';
|
|
2
|
+
export interface OIDCOptions {
|
|
3
|
+
issuer: string;
|
|
4
|
+
clientId: string;
|
|
5
|
+
clientSecret?: string;
|
|
6
|
+
redirectUri?: string;
|
|
7
|
+
scopes?: string[];
|
|
8
|
+
accessToken?: string | (() => string | Promise<string>);
|
|
9
|
+
refreshToken?: string;
|
|
10
|
+
tokenStorage?: {
|
|
11
|
+
get: () => Promise<OIDCTokens | null>;
|
|
12
|
+
set: (tokens: OIDCTokens) => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
audience?: string;
|
|
15
|
+
fetch?: typeof fetch;
|
|
16
|
+
}
|
|
17
|
+
export interface OIDCTokens {
|
|
18
|
+
accessToken: string;
|
|
19
|
+
refreshToken?: string;
|
|
20
|
+
idToken?: string;
|
|
21
|
+
expiresAt?: number;
|
|
22
|
+
tokenType?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface OIDCDiscoveryDocument {
|
|
25
|
+
issuer: string;
|
|
26
|
+
authorization_endpoint: string;
|
|
27
|
+
token_endpoint: string;
|
|
28
|
+
userinfo_endpoint?: string;
|
|
29
|
+
jwks_uri: string;
|
|
30
|
+
revocation_endpoint?: string;
|
|
31
|
+
introspection_endpoint?: string;
|
|
32
|
+
end_session_endpoint?: string;
|
|
33
|
+
scopes_supported?: string[];
|
|
34
|
+
response_types_supported: string[];
|
|
35
|
+
grant_types_supported?: string[];
|
|
36
|
+
token_endpoint_auth_methods_supported?: string[];
|
|
37
|
+
}
|
|
38
|
+
declare function fetchDiscoveryDocument(issuer: string, customFetch?: typeof fetch): Promise<OIDCDiscoveryDocument>;
|
|
39
|
+
declare function exchangeCode(discovery: OIDCDiscoveryDocument, options: OIDCOptions, code: string, codeVerifier?: string, customFetch?: typeof fetch): Promise<OIDCTokens>;
|
|
40
|
+
declare function refreshTokens(discovery: OIDCDiscoveryDocument, options: OIDCOptions, refreshToken: string, customFetch?: typeof fetch): Promise<OIDCTokens>;
|
|
41
|
+
declare function clientCredentialsFlow(discovery: OIDCDiscoveryDocument, options: OIDCOptions, customFetch?: typeof fetch): Promise<OIDCTokens>;
|
|
42
|
+
export declare function generatePKCE(): {
|
|
43
|
+
codeVerifier: string;
|
|
44
|
+
codeChallenge: string;
|
|
45
|
+
};
|
|
46
|
+
export declare function generateAuthorizationUrl(options: OIDCOptions & {
|
|
47
|
+
state?: string;
|
|
48
|
+
nonce?: string;
|
|
49
|
+
pkce?: {
|
|
50
|
+
codeChallenge: string;
|
|
51
|
+
};
|
|
52
|
+
}): Promise<string>;
|
|
53
|
+
export declare function oidc(options: OIDCOptions): Middleware;
|
|
54
|
+
export declare function oidcPlugin(options: OIDCOptions): Plugin;
|
|
55
|
+
export { fetchDiscoveryDocument, exchangeCode, refreshTokens, clientCredentialsFlow };
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
const discoveryCache = new Map();
|
|
3
|
+
async function fetchDiscoveryDocument(issuer, customFetch = fetch) {
|
|
4
|
+
const cached = discoveryCache.get(issuer);
|
|
5
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
6
|
+
return cached.doc;
|
|
7
|
+
}
|
|
8
|
+
const wellKnownUrl = `${issuer.replace(/\/$/, '')}/.well-known/openid-configuration`;
|
|
9
|
+
const response = await customFetch(wellKnownUrl);
|
|
10
|
+
if (!response.ok) {
|
|
11
|
+
throw new Error(`Failed to fetch OIDC discovery document: ${response.status}`);
|
|
12
|
+
}
|
|
13
|
+
const doc = await response.json();
|
|
14
|
+
discoveryCache.set(issuer, {
|
|
15
|
+
doc,
|
|
16
|
+
expiresAt: Date.now() + 3600000,
|
|
17
|
+
});
|
|
18
|
+
return doc;
|
|
19
|
+
}
|
|
20
|
+
async function exchangeCode(discovery, options, code, codeVerifier, customFetch = fetch) {
|
|
21
|
+
const params = new URLSearchParams({
|
|
22
|
+
grant_type: 'authorization_code',
|
|
23
|
+
client_id: options.clientId,
|
|
24
|
+
code,
|
|
25
|
+
redirect_uri: options.redirectUri || '',
|
|
26
|
+
});
|
|
27
|
+
if (options.clientSecret) {
|
|
28
|
+
params.set('client_secret', options.clientSecret);
|
|
29
|
+
}
|
|
30
|
+
if (codeVerifier) {
|
|
31
|
+
params.set('code_verifier', codeVerifier);
|
|
32
|
+
}
|
|
33
|
+
const response = await customFetch(discovery.token_endpoint, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
37
|
+
},
|
|
38
|
+
body: params.toString(),
|
|
39
|
+
});
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
const error = await response.text();
|
|
42
|
+
throw new Error(`Token exchange failed: ${error}`);
|
|
43
|
+
}
|
|
44
|
+
const data = await response.json();
|
|
45
|
+
return {
|
|
46
|
+
accessToken: data.access_token,
|
|
47
|
+
refreshToken: data.refresh_token,
|
|
48
|
+
idToken: data.id_token,
|
|
49
|
+
expiresAt: data.expires_in ? Date.now() + data.expires_in * 1000 : undefined,
|
|
50
|
+
tokenType: data.token_type || 'Bearer',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function refreshTokens(discovery, options, refreshToken, customFetch = fetch) {
|
|
54
|
+
const params = new URLSearchParams({
|
|
55
|
+
grant_type: 'refresh_token',
|
|
56
|
+
client_id: options.clientId,
|
|
57
|
+
refresh_token: refreshToken,
|
|
58
|
+
});
|
|
59
|
+
if (options.clientSecret) {
|
|
60
|
+
params.set('client_secret', options.clientSecret);
|
|
61
|
+
}
|
|
62
|
+
const response = await customFetch(discovery.token_endpoint, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: {
|
|
65
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
66
|
+
},
|
|
67
|
+
body: params.toString(),
|
|
68
|
+
});
|
|
69
|
+
if (!response.ok) {
|
|
70
|
+
const error = await response.text();
|
|
71
|
+
throw new Error(`Token refresh failed: ${error}`);
|
|
72
|
+
}
|
|
73
|
+
const data = await response.json();
|
|
74
|
+
return {
|
|
75
|
+
accessToken: data.access_token,
|
|
76
|
+
refreshToken: data.refresh_token || refreshToken,
|
|
77
|
+
idToken: data.id_token,
|
|
78
|
+
expiresAt: data.expires_in ? Date.now() + data.expires_in * 1000 : undefined,
|
|
79
|
+
tokenType: data.token_type || 'Bearer',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async function clientCredentialsFlow(discovery, options, customFetch = fetch) {
|
|
83
|
+
if (!options.clientSecret) {
|
|
84
|
+
throw new Error('Client credentials flow requires clientSecret');
|
|
85
|
+
}
|
|
86
|
+
const params = new URLSearchParams({
|
|
87
|
+
grant_type: 'client_credentials',
|
|
88
|
+
client_id: options.clientId,
|
|
89
|
+
client_secret: options.clientSecret,
|
|
90
|
+
});
|
|
91
|
+
if (options.scopes && options.scopes.length > 0) {
|
|
92
|
+
params.set('scope', options.scopes.join(' '));
|
|
93
|
+
}
|
|
94
|
+
if (options.audience) {
|
|
95
|
+
params.set('audience', options.audience);
|
|
96
|
+
}
|
|
97
|
+
const response = await customFetch(discovery.token_endpoint, {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: {
|
|
100
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
101
|
+
},
|
|
102
|
+
body: params.toString(),
|
|
103
|
+
});
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
const error = await response.text();
|
|
106
|
+
throw new Error(`Client credentials flow failed: ${error}`);
|
|
107
|
+
}
|
|
108
|
+
const data = await response.json();
|
|
109
|
+
return {
|
|
110
|
+
accessToken: data.access_token,
|
|
111
|
+
expiresAt: data.expires_in ? Date.now() + data.expires_in * 1000 : undefined,
|
|
112
|
+
tokenType: data.token_type || 'Bearer',
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export function generatePKCE() {
|
|
116
|
+
const codeVerifier = randomBytes(32).toString('base64url');
|
|
117
|
+
const codeChallenge = createHash('sha256')
|
|
118
|
+
.update(codeVerifier)
|
|
119
|
+
.digest('base64url');
|
|
120
|
+
return { codeVerifier, codeChallenge };
|
|
121
|
+
}
|
|
122
|
+
export async function generateAuthorizationUrl(options) {
|
|
123
|
+
const discovery = await fetchDiscoveryDocument(options.issuer, options.fetch);
|
|
124
|
+
const params = new URLSearchParams({
|
|
125
|
+
response_type: 'code',
|
|
126
|
+
client_id: options.clientId,
|
|
127
|
+
redirect_uri: options.redirectUri || '',
|
|
128
|
+
scope: (options.scopes || ['openid']).join(' '),
|
|
129
|
+
});
|
|
130
|
+
if (options.state) {
|
|
131
|
+
params.set('state', options.state);
|
|
132
|
+
}
|
|
133
|
+
if (options.nonce) {
|
|
134
|
+
params.set('nonce', options.nonce);
|
|
135
|
+
}
|
|
136
|
+
if (options.pkce) {
|
|
137
|
+
params.set('code_challenge', options.pkce.codeChallenge);
|
|
138
|
+
params.set('code_challenge_method', 'S256');
|
|
139
|
+
}
|
|
140
|
+
if (options.audience) {
|
|
141
|
+
params.set('audience', options.audience);
|
|
142
|
+
}
|
|
143
|
+
return `${discovery.authorization_endpoint}?${params.toString()}`;
|
|
144
|
+
}
|
|
145
|
+
export function oidc(options) {
|
|
146
|
+
let cachedTokens = null;
|
|
147
|
+
let discoveryDoc = null;
|
|
148
|
+
const customFetch = options.fetch || fetch;
|
|
149
|
+
const getDiscovery = async () => {
|
|
150
|
+
if (!discoveryDoc) {
|
|
151
|
+
discoveryDoc = await fetchDiscoveryDocument(options.issuer, customFetch);
|
|
152
|
+
}
|
|
153
|
+
return discoveryDoc;
|
|
154
|
+
};
|
|
155
|
+
const getTokens = async () => {
|
|
156
|
+
if (options.tokenStorage) {
|
|
157
|
+
const stored = await options.tokenStorage.get();
|
|
158
|
+
if (stored) {
|
|
159
|
+
cachedTokens = stored;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (cachedTokens && cachedTokens.expiresAt && cachedTokens.expiresAt > Date.now() + 60000) {
|
|
163
|
+
return cachedTokens;
|
|
164
|
+
}
|
|
165
|
+
if (cachedTokens?.refreshToken || options.refreshToken) {
|
|
166
|
+
const discovery = await getDiscovery();
|
|
167
|
+
const refreshToken = cachedTokens?.refreshToken || options.refreshToken;
|
|
168
|
+
try {
|
|
169
|
+
cachedTokens = await refreshTokens(discovery, options, refreshToken, customFetch);
|
|
170
|
+
if (options.tokenStorage) {
|
|
171
|
+
await options.tokenStorage.set(cachedTokens);
|
|
172
|
+
}
|
|
173
|
+
return cachedTokens;
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (options.accessToken) {
|
|
179
|
+
const token = typeof options.accessToken === 'function'
|
|
180
|
+
? await options.accessToken()
|
|
181
|
+
: options.accessToken;
|
|
182
|
+
return { accessToken: token, tokenType: 'Bearer' };
|
|
183
|
+
}
|
|
184
|
+
if (options.clientSecret) {
|
|
185
|
+
const discovery = await getDiscovery();
|
|
186
|
+
cachedTokens = await clientCredentialsFlow(discovery, options, customFetch);
|
|
187
|
+
if (options.tokenStorage) {
|
|
188
|
+
await options.tokenStorage.set(cachedTokens);
|
|
189
|
+
}
|
|
190
|
+
return cachedTokens;
|
|
191
|
+
}
|
|
192
|
+
throw new Error('No valid authentication method available. Provide accessToken, refreshToken, or clientSecret.');
|
|
193
|
+
};
|
|
194
|
+
return async (req, next) => {
|
|
195
|
+
const tokens = await getTokens();
|
|
196
|
+
const tokenType = tokens.tokenType || 'Bearer';
|
|
197
|
+
const authReq = req.withHeader('Authorization', `${tokenType} ${tokens.accessToken}`);
|
|
198
|
+
const response = await next(authReq);
|
|
199
|
+
if (response.status === 401 && (cachedTokens?.refreshToken || options.refreshToken)) {
|
|
200
|
+
try {
|
|
201
|
+
const discovery = await getDiscovery();
|
|
202
|
+
const refreshToken = cachedTokens?.refreshToken || options.refreshToken;
|
|
203
|
+
cachedTokens = await refreshTokens(discovery, options, refreshToken, customFetch);
|
|
204
|
+
if (options.tokenStorage) {
|
|
205
|
+
await options.tokenStorage.set(cachedTokens);
|
|
206
|
+
}
|
|
207
|
+
const retryReq = req.withHeader('Authorization', `${cachedTokens.tokenType || 'Bearer'} ${cachedTokens.accessToken}`);
|
|
208
|
+
return next(retryReq);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return response;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return response;
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
export function oidcPlugin(options) {
|
|
218
|
+
return (client) => {
|
|
219
|
+
client.use(oidc(options));
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
export { fetchDiscoveryDocument, exchangeCode, refreshTokens, clientCredentialsFlow };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Middleware, Plugin } from '../../types/index.js';
|
|
2
|
+
import { OIDCTokens } from './oidc.js';
|
|
3
|
+
export interface OktaOptions {
|
|
4
|
+
domain: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret?: string;
|
|
7
|
+
authorizationServerId?: string;
|
|
8
|
+
scopes?: string[];
|
|
9
|
+
accessToken?: string | (() => string | Promise<string>);
|
|
10
|
+
refreshToken?: string;
|
|
11
|
+
tokenStorage?: {
|
|
12
|
+
get: () => Promise<OIDCTokens | null>;
|
|
13
|
+
set: (tokens: OIDCTokens) => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
apiToken?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function generateOktaAuthUrl(options: OktaOptions & {
|
|
18
|
+
redirectUri: string;
|
|
19
|
+
state?: string;
|
|
20
|
+
nonce?: string;
|
|
21
|
+
usePKCE?: boolean;
|
|
22
|
+
prompt?: 'none' | 'consent' | 'login';
|
|
23
|
+
idp?: string;
|
|
24
|
+
loginHint?: string;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
url: string;
|
|
27
|
+
codeVerifier?: string;
|
|
28
|
+
}>;
|
|
29
|
+
export declare function exchangeOktaCode(options: OktaOptions & {
|
|
30
|
+
code: string;
|
|
31
|
+
redirectUri: string;
|
|
32
|
+
codeVerifier?: string;
|
|
33
|
+
}): Promise<OIDCTokens>;
|
|
34
|
+
export declare function getOktaUserInfo(domain: string, authorizationServerId: string | undefined, accessToken: string): Promise<Record<string, unknown>>;
|
|
35
|
+
export declare function introspectOktaToken(options: OktaOptions & {
|
|
36
|
+
token: string;
|
|
37
|
+
tokenTypeHint?: 'access_token' | 'refresh_token';
|
|
38
|
+
}): Promise<{
|
|
39
|
+
active: boolean;
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}>;
|
|
42
|
+
export declare function revokeOktaToken(options: OktaOptions & {
|
|
43
|
+
token: string;
|
|
44
|
+
tokenTypeHint?: 'access_token' | 'refresh_token';
|
|
45
|
+
}): Promise<void>;
|
|
46
|
+
export declare function okta(options: OktaOptions): Middleware;
|
|
47
|
+
export declare function oktaPlugin(options: OktaOptions): Plugin;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { oidc, generatePKCE } from './oidc.js';
|
|
2
|
+
function getOktaIssuer(domain, authorizationServerId) {
|
|
3
|
+
const serverId = authorizationServerId || 'default';
|
|
4
|
+
return `https://${domain}/oauth2/${serverId}`;
|
|
5
|
+
}
|
|
6
|
+
export async function generateOktaAuthUrl(options) {
|
|
7
|
+
const issuer = getOktaIssuer(options.domain, options.authorizationServerId);
|
|
8
|
+
const pkce = options.usePKCE ? generatePKCE() : undefined;
|
|
9
|
+
const params = new URLSearchParams({
|
|
10
|
+
response_type: 'code',
|
|
11
|
+
client_id: options.clientId,
|
|
12
|
+
redirect_uri: options.redirectUri,
|
|
13
|
+
scope: (options.scopes || ['openid', 'profile', 'email']).join(' '),
|
|
14
|
+
});
|
|
15
|
+
if (options.state) {
|
|
16
|
+
params.set('state', options.state);
|
|
17
|
+
}
|
|
18
|
+
if (options.nonce) {
|
|
19
|
+
params.set('nonce', options.nonce);
|
|
20
|
+
}
|
|
21
|
+
if (pkce) {
|
|
22
|
+
params.set('code_challenge', pkce.codeChallenge);
|
|
23
|
+
params.set('code_challenge_method', 'S256');
|
|
24
|
+
}
|
|
25
|
+
if (options.prompt) {
|
|
26
|
+
params.set('prompt', options.prompt);
|
|
27
|
+
}
|
|
28
|
+
if (options.idp) {
|
|
29
|
+
params.set('idp', options.idp);
|
|
30
|
+
}
|
|
31
|
+
if (options.loginHint) {
|
|
32
|
+
params.set('login_hint', options.loginHint);
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
url: `${issuer}/v1/authorize?${params.toString()}`,
|
|
36
|
+
codeVerifier: pkce?.codeVerifier,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function exchangeOktaCode(options) {
|
|
40
|
+
const issuer = getOktaIssuer(options.domain, options.authorizationServerId);
|
|
41
|
+
const tokenUrl = `${issuer}/v1/token`;
|
|
42
|
+
const params = new URLSearchParams({
|
|
43
|
+
grant_type: 'authorization_code',
|
|
44
|
+
client_id: options.clientId,
|
|
45
|
+
code: options.code,
|
|
46
|
+
redirect_uri: options.redirectUri,
|
|
47
|
+
});
|
|
48
|
+
if (options.clientSecret) {
|
|
49
|
+
params.set('client_secret', options.clientSecret);
|
|
50
|
+
}
|
|
51
|
+
if (options.codeVerifier) {
|
|
52
|
+
params.set('code_verifier', options.codeVerifier);
|
|
53
|
+
}
|
|
54
|
+
const response = await fetch(tokenUrl, {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: {
|
|
57
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
58
|
+
Accept: 'application/json',
|
|
59
|
+
},
|
|
60
|
+
body: params.toString(),
|
|
61
|
+
});
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
const error = await response.text();
|
|
64
|
+
throw new Error(`Okta token exchange failed: ${error}`);
|
|
65
|
+
}
|
|
66
|
+
const data = await response.json();
|
|
67
|
+
return {
|
|
68
|
+
accessToken: data.access_token,
|
|
69
|
+
refreshToken: data.refresh_token,
|
|
70
|
+
idToken: data.id_token,
|
|
71
|
+
expiresAt: data.expires_in ? Date.now() + data.expires_in * 1000 : undefined,
|
|
72
|
+
tokenType: data.token_type || 'Bearer',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export async function getOktaUserInfo(domain, authorizationServerId, accessToken) {
|
|
76
|
+
const issuer = getOktaIssuer(domain, authorizationServerId);
|
|
77
|
+
const response = await fetch(`${issuer}/v1/userinfo`, {
|
|
78
|
+
headers: {
|
|
79
|
+
Authorization: `Bearer ${accessToken}`,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
throw new Error(`Failed to get user info: ${response.status}`);
|
|
84
|
+
}
|
|
85
|
+
return response.json();
|
|
86
|
+
}
|
|
87
|
+
export async function introspectOktaToken(options) {
|
|
88
|
+
const issuer = getOktaIssuer(options.domain, options.authorizationServerId);
|
|
89
|
+
const params = new URLSearchParams({
|
|
90
|
+
token: options.token,
|
|
91
|
+
client_id: options.clientId,
|
|
92
|
+
});
|
|
93
|
+
if (options.clientSecret) {
|
|
94
|
+
params.set('client_secret', options.clientSecret);
|
|
95
|
+
}
|
|
96
|
+
if (options.tokenTypeHint) {
|
|
97
|
+
params.set('token_type_hint', options.tokenTypeHint);
|
|
98
|
+
}
|
|
99
|
+
const response = await fetch(`${issuer}/v1/introspect`, {
|
|
100
|
+
method: 'POST',
|
|
101
|
+
headers: {
|
|
102
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
103
|
+
Accept: 'application/json',
|
|
104
|
+
},
|
|
105
|
+
body: params.toString(),
|
|
106
|
+
});
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
throw new Error(`Token introspection failed: ${response.status}`);
|
|
109
|
+
}
|
|
110
|
+
return response.json();
|
|
111
|
+
}
|
|
112
|
+
export async function revokeOktaToken(options) {
|
|
113
|
+
const issuer = getOktaIssuer(options.domain, options.authorizationServerId);
|
|
114
|
+
const params = new URLSearchParams({
|
|
115
|
+
token: options.token,
|
|
116
|
+
client_id: options.clientId,
|
|
117
|
+
});
|
|
118
|
+
if (options.clientSecret) {
|
|
119
|
+
params.set('client_secret', options.clientSecret);
|
|
120
|
+
}
|
|
121
|
+
if (options.tokenTypeHint) {
|
|
122
|
+
params.set('token_type_hint', options.tokenTypeHint);
|
|
123
|
+
}
|
|
124
|
+
const response = await fetch(`${issuer}/v1/revoke`, {
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers: {
|
|
127
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
128
|
+
},
|
|
129
|
+
body: params.toString(),
|
|
130
|
+
});
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
throw new Error(`Token revocation failed: ${response.status}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export function okta(options) {
|
|
136
|
+
if (options.apiToken) {
|
|
137
|
+
return async (req, next) => {
|
|
138
|
+
const authReq = req.withHeader('Authorization', `SSWS ${options.apiToken}`);
|
|
139
|
+
return next(authReq);
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const issuer = getOktaIssuer(options.domain, options.authorizationServerId);
|
|
143
|
+
return oidc({
|
|
144
|
+
issuer,
|
|
145
|
+
clientId: options.clientId,
|
|
146
|
+
clientSecret: options.clientSecret,
|
|
147
|
+
scopes: options.scopes || ['openid', 'profile', 'email'],
|
|
148
|
+
accessToken: options.accessToken,
|
|
149
|
+
refreshToken: options.refreshToken,
|
|
150
|
+
tokenStorage: options.tokenStorage,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
export function oktaPlugin(options) {
|
|
154
|
+
return (client) => {
|
|
155
|
+
client.use(okta(options));
|
|
156
|
+
};
|
|
157
|
+
}
|