checkly 9.5.0 → 10.0.0-rc.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/dist/ai-context/context.js +1 -0
- package/dist/ai-context/context.js.map +1 -1
- package/dist/ai-context/onboarding-boilerplate/checkly-config-template.ts +2 -0
- package/dist/ai-context/public-skills/checkly/SKILL.md +18 -5
- package/dist/ai-context/skills-command/references/communicate.md +6 -3
- package/dist/ai-context/skills-command/references/configure-api-checks.md +1 -9
- package/dist/ai-context/skills-command/references/configure-browser-checks.md +1 -8
- package/dist/ai-context/skills-command/references/configure-check-groups.md +1 -0
- package/dist/ai-context/skills-command/references/configure-dns-monitors.md +1 -9
- package/dist/ai-context/skills-command/references/configure-grpc-monitors.md +24 -0
- package/dist/ai-context/skills-command/references/configure-heartbeat-monitors.md +1 -9
- package/dist/ai-context/skills-command/references/configure-icmp-monitors.md +1 -9
- package/dist/ai-context/skills-command/references/configure-multistep-checks.md +1 -9
- package/dist/ai-context/skills-command/references/configure-playwright-checks.md +1 -1
- package/dist/ai-context/skills-command/references/configure-supporting-constructs.md +6 -2
- package/dist/ai-context/skills-command/references/configure-tcp-monitors.md +1 -10
- package/dist/ai-context/skills-command/references/configure-url-monitors.md +1 -10
- package/dist/ai-context/skills-command/references/configure.md +16 -5
- package/dist/ai-context/skills-command/references/initialize.md +11 -3
- package/dist/ai-context/skills-command/references/investigate-checks.md +1 -1
- package/dist/auth/api-key.d.ts +24 -0
- package/dist/auth/api-key.js +104 -0
- package/dist/auth/api-key.js.map +1 -0
- package/dist/auth/device-flow.d.ts +57 -0
- package/dist/auth/device-flow.js +221 -0
- package/dist/auth/device-flow.js.map +1 -0
- package/dist/auth/index.d.ts +6 -6
- package/dist/auth/index.js +64 -64
- package/dist/auth/index.js.map +1 -1
- package/dist/commands/api.js +43 -10
- package/dist/commands/api.js.map +1 -1
- package/dist/commands/authCommand.d.ts +2 -0
- package/dist/commands/authCommand.js +77 -7
- package/dist/commands/authCommand.js.map +1 -1
- package/dist/commands/debug/parse-project.d.ts +1 -0
- package/dist/commands/debug/parse-project.js +5 -2
- package/dist/commands/debug/parse-project.js.map +1 -1
- package/dist/commands/deploy.d.ts +7 -1
- package/dist/commands/deploy.js +627 -271
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/import/plan.js +18 -4
- package/dist/commands/import/plan.js.map +1 -1
- package/dist/commands/init.js +29 -13
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +18 -2
- package/dist/commands/login.js +681 -48
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +7 -1
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/pw-test.js +3 -2
- package/dist/commands/pw-test.js.map +1 -1
- package/dist/commands/switch.js +23 -10
- package/dist/commands/switch.js.map +1 -1
- package/dist/commands/test.js +16 -17
- package/dist/commands/test.js.map +1 -1
- package/dist/commands/trigger.js +4 -3
- package/dist/commands/trigger.js.map +1 -1
- package/dist/commands/validate.js +1 -0
- package/dist/commands/validate.js.map +1 -1
- package/dist/constants.d.ts +1 -2
- package/dist/constants.js +0 -1
- package/dist/constants.js.map +1 -1
- package/dist/constructs/alert-channel-codegen.d.ts +6 -1
- package/dist/constructs/alert-channel-codegen.js +12 -6
- package/dist/constructs/alert-channel-codegen.js.map +1 -1
- package/dist/constructs/alert-escalation-policy-codegen.d.ts +7 -0
- package/dist/constructs/alert-escalation-policy-codegen.js +25 -8
- package/dist/constructs/alert-escalation-policy-codegen.js.map +1 -1
- package/dist/constructs/api-assertion.d.ts +0 -2
- package/dist/constructs/api-assertion.js +0 -4
- package/dist/constructs/api-assertion.js.map +1 -1
- package/dist/constructs/api-check-codegen.js +1 -1
- package/dist/constructs/api-check-codegen.js.map +1 -1
- package/dist/constructs/api-check.d.ts +4 -22
- package/dist/constructs/api-check.js +15 -17
- package/dist/constructs/api-check.js.map +1 -1
- package/dist/constructs/api-request-codegen.js +10 -8
- package/dist/constructs/api-request-codegen.js.map +1 -1
- package/dist/constructs/browser-check-bundle.d.ts +19 -13
- package/dist/constructs/browser-check-bundle.js +5 -1
- package/dist/constructs/browser-check-bundle.js.map +1 -1
- package/dist/constructs/browser-check.d.ts +1 -4
- package/dist/constructs/browser-check.js +1 -1
- package/dist/constructs/browser-check.js.map +1 -1
- package/dist/constructs/check-codegen.d.ts +39 -14
- package/dist/constructs/check-codegen.js +101 -23
- package/dist/constructs/check-codegen.js.map +1 -1
- package/dist/constructs/check-group-codegen.js +23 -9
- package/dist/constructs/check-group-codegen.js.map +1 -1
- package/dist/constructs/check-group-v1.d.ts +19 -14
- package/dist/constructs/check-group-v1.js +39 -14
- package/dist/constructs/check-group-v1.js.map +1 -1
- package/dist/constructs/check-group-v2.d.ts +0 -20
- package/dist/constructs/check-group-v2.js +0 -4
- package/dist/constructs/check-group-v2.js.map +1 -1
- package/dist/constructs/check.d.ts +45 -32
- package/dist/constructs/check.js +78 -17
- package/dist/constructs/check.js.map +1 -1
- package/dist/constructs/construct-codegen.d.ts +1 -2
- package/dist/constructs/construct-diagnostics.d.ts +3 -0
- package/dist/constructs/construct-diagnostics.js +11 -0
- package/dist/constructs/construct-diagnostics.js.map +1 -1
- package/dist/constructs/construct.d.ts +25 -4
- package/dist/constructs/construct.js +41 -5
- package/dist/constructs/construct.js.map +1 -1
- package/dist/constructs/dns-request-codegen.js +1 -1
- package/dist/constructs/dns-request-codegen.js.map +1 -1
- package/dist/constructs/email-alert-channel-codegen.js +1 -1
- package/dist/constructs/email-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/frequency-codegen.js +10 -2
- package/dist/constructs/frequency-codegen.js.map +1 -1
- package/dist/constructs/frequency.d.ts +8 -3
- package/dist/constructs/frequency.js +7 -2
- package/dist/constructs/frequency.js.map +1 -1
- package/dist/constructs/grpc-monitor.js +19 -0
- package/dist/constructs/grpc-monitor.js.map +1 -1
- package/dist/constructs/grpc-request-codegen.js +13 -4
- package/dist/constructs/grpc-request-codegen.js.map +1 -1
- package/dist/constructs/grpc-request.d.ts +23 -0
- package/dist/constructs/heartbeat-monitor.d.ts +2 -1
- package/dist/constructs/heartbeat-monitor.js +2 -2
- package/dist/constructs/heartbeat-monitor.js.map +1 -1
- package/dist/constructs/icmp-request-codegen.js +1 -1
- package/dist/constructs/icmp-request-codegen.js.map +1 -1
- package/dist/constructs/incidentio-alert-channel-codegen.d.ts +1 -1
- package/dist/constructs/incidentio-alert-channel-codegen.js +14 -8
- package/dist/constructs/incidentio-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/index.d.ts +1 -1
- package/dist/constructs/index.js +1 -1
- package/dist/constructs/index.js.map +1 -1
- package/dist/constructs/internal/assertion-validation.js +1 -2
- package/dist/constructs/internal/assertion-validation.js.map +1 -1
- package/dist/constructs/internal/codegen/context.d.ts +73 -6
- package/dist/constructs/internal/codegen/context.js +78 -6
- package/dist/constructs/internal/codegen/context.js.map +1 -1
- package/dist/constructs/internal/codegen/index.d.ts +3 -1
- package/dist/constructs/internal/codegen/index.js +2 -1
- package/dist/constructs/internal/codegen/index.js.map +1 -1
- package/dist/constructs/internal/codegen/render.d.ts +68 -0
- package/dist/constructs/internal/codegen/render.js +75 -0
- package/dist/constructs/internal/codegen/render.js.map +1 -0
- package/dist/constructs/internal/common-diagnostics.d.ts +1 -2
- package/dist/constructs/internal/common-diagnostics.js +6 -14
- package/dist/constructs/internal/common-diagnostics.js.map +1 -1
- package/dist/constructs/internal/declaring-file.d.ts +39 -0
- package/dist/constructs/internal/declaring-file.js +139 -0
- package/dist/constructs/internal/declaring-file.js.map +1 -0
- package/dist/constructs/internal/retry-strategy-defaults.d.ts +13 -0
- package/dist/constructs/internal/retry-strategy-defaults.js +14 -0
- package/dist/constructs/internal/retry-strategy-defaults.js.map +1 -0
- package/dist/constructs/key-value-pair-codegen.d.ts +6 -1
- package/dist/constructs/key-value-pair-codegen.js +24 -3
- package/dist/constructs/key-value-pair-codegen.js.map +1 -1
- package/dist/constructs/maintenance-window-codegen.d.ts +7 -0
- package/dist/constructs/maintenance-window-codegen.js +36 -19
- package/dist/constructs/maintenance-window-codegen.js.map +1 -1
- package/dist/constructs/maintenance-window.d.ts +35 -3
- package/dist/constructs/maintenance-window.js +35 -1
- package/dist/constructs/maintenance-window.js.map +1 -1
- package/dist/constructs/monitor.d.ts +1 -1
- package/dist/constructs/msteams-alert-channel-codegen.d.ts +1 -1
- package/dist/constructs/msteams-alert-channel-codegen.js +8 -18
- package/dist/constructs/msteams-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/opsgenie-alert-channel-codegen.js +1 -1
- package/dist/constructs/opsgenie-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/pagerduty-alert-channel-codegen.js +1 -1
- package/dist/constructs/pagerduty-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/phone-call-alert-channel-codegen.js +1 -1
- package/dist/constructs/phone-call-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/playwright-check-bundle.d.ts +7 -1
- package/dist/constructs/playwright-check-bundle.js +3 -0
- package/dist/constructs/playwright-check-bundle.js.map +1 -1
- package/dist/constructs/playwright-check-codegen.d.ts +85 -0
- package/dist/constructs/playwright-check-codegen.js +212 -0
- package/dist/constructs/playwright-check-codegen.js.map +1 -0
- package/dist/constructs/playwright-check.d.ts +14 -24
- package/dist/constructs/playwright-check.js +16 -52
- package/dist/constructs/playwright-check.js.map +1 -1
- package/dist/constructs/retry-strategy-codegen.d.ts +7 -1
- package/dist/constructs/retry-strategy-codegen.js +41 -32
- package/dist/constructs/retry-strategy-codegen.js.map +1 -1
- package/dist/constructs/retry-strategy.d.ts +0 -4
- package/dist/constructs/retry-strategy.js +5 -8
- package/dist/constructs/retry-strategy.js.map +1 -1
- package/dist/constructs/session.d.ts +26 -1
- package/dist/constructs/session.js +33 -2
- package/dist/constructs/session.js.map +1 -1
- package/dist/constructs/slack-alert-channel-codegen.js +1 -1
- package/dist/constructs/slack-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/slack-app-alert-channel-codegen.js +1 -1
- package/dist/constructs/slack-app-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/sms-alert-channel-codegen.js +1 -1
- package/dist/constructs/sms-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/ssl-request-codegen.js +4 -3
- package/dist/constructs/ssl-request-codegen.js.map +1 -1
- package/dist/constructs/status-page-v3-automation-rule-codegen.js +5 -4
- package/dist/constructs/status-page-v3-automation-rule-codegen.js.map +1 -1
- package/dist/constructs/status-page-v3-codegen.js +3 -2
- package/dist/constructs/status-page-v3-codegen.js.map +1 -1
- package/dist/constructs/status-page-v3-component-codegen.js +8 -7
- package/dist/constructs/status-page-v3-component-codegen.js.map +1 -1
- package/dist/constructs/tcp-monitor-codegen.js +3 -2
- package/dist/constructs/tcp-monitor-codegen.js.map +1 -1
- package/dist/constructs/tcp-monitor.d.ts +4 -3
- package/dist/constructs/tcp-monitor.js +3 -2
- package/dist/constructs/tcp-monitor.js.map +1 -1
- package/dist/constructs/telegram-alert-channel-codegen.d.ts +1 -1
- package/dist/constructs/telegram-alert-channel-codegen.js +14 -8
- package/dist/constructs/telegram-alert-channel-codegen.js.map +1 -1
- package/dist/constructs/time-zone.d.ts +24 -0
- package/dist/constructs/time-zone.js +455 -0
- package/dist/constructs/time-zone.js.map +1 -0
- package/dist/constructs/traceroute-request-codegen.js +2 -2
- package/dist/constructs/traceroute-request-codegen.js.map +1 -1
- package/dist/constructs/url-monitor-codegen.js +1 -1
- package/dist/constructs/url-monitor-codegen.js.map +1 -1
- package/dist/constructs/url-monitor.d.ts +3 -2
- package/dist/constructs/url-monitor.js +3 -0
- package/dist/constructs/url-monitor.js.map +1 -1
- package/dist/constructs/url-request-codegen.js +4 -3
- package/dist/constructs/url-request-codegen.js.map +1 -1
- package/dist/constructs/webhook-alert-channel-codegen.js +3 -3
- package/dist/constructs/webhook-alert-channel-codegen.js.map +1 -1
- package/dist/formatters/check-result-detail.js +0 -185
- package/dist/formatters/check-result-detail.js.map +1 -1
- package/dist/helpers/activate-account.d.ts +14 -0
- package/dist/helpers/activate-account.js +25 -0
- package/dist/helpers/activate-account.js.map +1 -0
- package/dist/helpers/cli-mode.d.ts +18 -0
- package/dist/helpers/cli-mode.js +41 -2
- package/dist/helpers/cli-mode.js.map +1 -1
- package/dist/helpers/command-preview.d.ts +44 -0
- package/dist/helpers/command-preview.js +29 -9
- package/dist/helpers/command-preview.js.map +1 -1
- package/dist/helpers/flags.d.ts +10 -0
- package/dist/helpers/flags.js +17 -0
- package/dist/helpers/flags.js.map +1 -1
- package/dist/helpers/onboarding/boilerplate.js +13 -1
- package/dist/helpers/onboarding/boilerplate.js.map +1 -1
- package/dist/helpers/onboarding/index.d.ts +1 -1
- package/dist/helpers/onboarding/index.js +1 -1
- package/dist/helpers/onboarding/index.js.map +1 -1
- package/dist/helpers/onboarding/messages.d.ts +6 -0
- package/dist/helpers/onboarding/messages.js +14 -0
- package/dist/helpers/onboarding/messages.js.map +1 -1
- package/dist/helpers/onboarding/skill-install.js +2 -2
- package/dist/helpers/onboarding/skill-install.js.map +1 -1
- package/dist/helpers/wrap.js +1 -1
- package/dist/helpers/wrap.js.map +1 -1
- package/dist/reporters/abstract-list.js +11 -2
- package/dist/reporters/abstract-list.js.map +1 -1
- package/dist/reporters/github.js +3 -2
- package/dist/reporters/github.js.map +1 -1
- package/dist/reporters/util.d.ts +1 -0
- package/dist/reporters/util.js +5 -58
- package/dist/reporters/util.js.map +1 -1
- package/dist/rest/analytics.js +0 -4
- package/dist/rest/analytics.js.map +1 -1
- package/dist/rest/api.d.ts +8 -1
- package/dist/rest/api.js +21 -3
- package/dist/rest/api.js.map +1 -1
- package/dist/rest/check-results.d.ts +1 -50
- package/dist/rest/check-results.js.map +1 -1
- package/dist/rest/checkly-storage.d.ts +6 -1
- package/dist/rest/checkly-storage.js +13 -2
- package/dist/rest/checkly-storage.js.map +1 -1
- package/dist/rest/errors.d.ts +13 -0
- package/dist/rest/errors.js +5 -1
- package/dist/rest/errors.js.map +1 -1
- package/dist/rest/projects.d.ts +254 -4
- package/dist/rest/projects.js +184 -12
- package/dist/rest/projects.js.map +1 -1
- package/dist/services/abstract-check-runner.d.ts +11 -0
- package/dist/services/abstract-check-runner.js +98 -46
- package/dist/services/abstract-check-runner.js.map +1 -1
- package/dist/services/check-parser/bundler.d.ts +26 -0
- package/dist/services/check-parser/bundler.js +81 -7
- package/dist/services/check-parser/bundler.js.map +1 -1
- package/dist/services/check-parser/cache-hash.d.ts +1 -4
- package/dist/services/check-parser/cache-hash.js.map +1 -1
- package/dist/services/checkly-config-codegen.js +1 -4
- package/dist/services/checkly-config-codegen.js.map +1 -1
- package/dist/services/checkly-config-loader.d.ts +7 -33
- package/dist/services/checkly-config-loader.js +50 -47
- package/dist/services/checkly-config-loader.js.map +1 -1
- package/dist/services/config.d.ts +2 -0
- package/dist/services/config.js +14 -0
- package/dist/services/config.js.map +1 -1
- package/dist/services/content-hash.d.ts +14 -0
- package/dist/services/content-hash.js +22 -0
- package/dist/services/content-hash.js.map +1 -0
- package/dist/services/deploy-diff/diff-lines.d.ts +38 -0
- package/dist/services/deploy-diff/diff-lines.js +191 -0
- package/dist/services/deploy-diff/diff-lines.js.map +1 -0
- package/dist/services/deploy-diff/import-shape.d.ts +171 -0
- package/dist/services/deploy-diff/import-shape.js +633 -0
- package/dist/services/deploy-diff/import-shape.js.map +1 -0
- package/dist/services/deploy-diff/legacy-payload.d.ts +22 -0
- package/dist/services/deploy-diff/legacy-payload.js +51 -0
- package/dist/services/deploy-diff/legacy-payload.js.map +1 -0
- package/dist/services/deploy-diff/plan-summary.d.ts +37 -0
- package/dist/services/deploy-diff/plan-summary.js +154 -0
- package/dist/services/deploy-diff/plan-summary.js.map +1 -0
- package/dist/services/deploy-diff/preview-output.d.ts +61 -0
- package/dist/services/deploy-diff/preview-output.js +394 -0
- package/dist/services/deploy-diff/preview-output.js.map +1 -0
- package/dist/services/deploy-diff/render.d.ts +53 -0
- package/dist/services/deploy-diff/render.js +317 -0
- package/dist/services/deploy-diff/render.js.map +1 -0
- package/dist/services/deploy-diff/shape-changes.d.ts +2 -0
- package/dist/services/deploy-diff/shape-changes.js +35 -0
- package/dist/services/deploy-diff/shape-changes.js.map +1 -0
- package/dist/services/deploy-diff/source-index.d.ts +18 -0
- package/dist/services/deploy-diff/source-index.js +48 -0
- package/dist/services/deploy-diff/source-index.js.map +1 -0
- package/dist/services/deploy-diff/variable-names.d.ts +30 -0
- package/dist/services/deploy-diff/variable-names.js +64 -0
- package/dist/services/deploy-diff/variable-names.js.map +1 -0
- package/dist/services/project-parser.d.ts +5 -0
- package/dist/services/project-parser.js +25 -13
- package/dist/services/project-parser.js.map +1 -1
- package/dist/services/snapshot-service.d.ts +25 -8
- package/dist/services/snapshot-service.js +46 -4
- package/dist/services/snapshot-service.js.map +1 -1
- package/dist/services/test-filters.d.ts +18 -0
- package/dist/services/test-filters.js +10 -0
- package/dist/services/test-filters.js.map +1 -1
- package/dist/services/test-runner.js +7 -3
- package/dist/services/test-runner.js.map +1 -1
- package/dist/services/test-session-cancel.js +1 -1
- package/dist/services/test-session-cancel.js.map +1 -1
- package/dist/services/util.d.ts +17 -2
- package/dist/services/util.js +118 -11
- package/dist/services/util.js.map +1 -1
- package/dist/services/write-back/apply-edits.d.ts +29 -0
- package/dist/services/write-back/apply-edits.js +255 -0
- package/dist/services/write-back/apply-edits.js.map +1 -0
- package/dist/services/write-back/helper-edit.d.ts +135 -0
- package/dist/services/write-back/helper-edit.js +343 -0
- package/dist/services/write-back/helper-edit.js.map +1 -0
- package/dist/services/write-back/imports.d.ts +30 -0
- package/dist/services/write-back/imports.js +82 -0
- package/dist/services/write-back/imports.js.map +1 -0
- package/dist/services/write-back/literal-edit.d.ts +183 -0
- package/dist/services/write-back/literal-edit.js +359 -0
- package/dist/services/write-back/literal-edit.js.map +1 -0
- package/dist/services/write-back/output.d.ts +26 -0
- package/dist/services/write-back/output.js +110 -0
- package/dist/services/write-back/output.js.map +1 -0
- package/dist/services/write-back/plan.d.ts +173 -0
- package/dist/services/write-back/plan.js +968 -0
- package/dist/services/write-back/plan.js.map +1 -0
- package/dist/services/write-back/source-file.d.ts +118 -0
- package/dist/services/write-back/source-file.js +432 -0
- package/dist/services/write-back/source-file.js.map +1 -0
- package/dist/sourcegen/index.d.ts +1 -1
- package/dist/sourcegen/index.js +1 -1
- package/dist/sourcegen/index.js.map +1 -1
- package/dist/sourcegen/program.d.ts +19 -1
- package/dist/sourcegen/program.js +32 -7
- package/dist/sourcegen/program.js.map +1 -1
- package/oclif.manifest.json +676 -635
- package/package.json +13 -13
- package/dist/commands/rules.d.ts +0 -9
- package/dist/commands/rules.js +0 -13
- package/dist/commands/rules.js.map +0 -1
- package/dist/constructs/agentic-check-codegen.d.ts +0 -22
- package/dist/constructs/agentic-check-codegen.js +0 -59
- package/dist/constructs/agentic-check-codegen.js.map +0 -1
- package/dist/constructs/agentic-check.d.ts +0 -237
- package/dist/constructs/agentic-check.js +0 -100
- package/dist/constructs/agentic-check.js.map +0 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import axios, { isAxiosError } from 'axios';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
import { jwtDecode } from 'jwt-decode';
|
|
4
|
+
import { getDefaults as getApiDefaults } from '../rest/api.js';
|
|
5
|
+
import { handleErrorResponse } from '../rest/errors.js';
|
|
6
|
+
import { assignProxy } from '../services/proxy.js';
|
|
7
|
+
function createDefaultClient(accessToken) {
|
|
8
|
+
// Keep axios instance stateless
|
|
9
|
+
const { baseURL } = getApiDefaults();
|
|
10
|
+
const axiosConf = assignProxy(baseURL, {
|
|
11
|
+
baseURL,
|
|
12
|
+
headers: {
|
|
13
|
+
Accept: 'application/json, text/plain, */*',
|
|
14
|
+
Authorization: `Bearer ${accessToken}`,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
return axios.create(axiosConf);
|
|
18
|
+
}
|
|
19
|
+
const defaultDeps = {
|
|
20
|
+
createClient: createDefaultClient,
|
|
21
|
+
hostname: () => os.hostname(),
|
|
22
|
+
sleep: ms => new Promise(resolve => setTimeout(resolve, ms)),
|
|
23
|
+
};
|
|
24
|
+
// The device code is spent once its tokens are issued, so an exchange that
|
|
25
|
+
// fails here costs the user another approval in the browser; ride out a
|
|
26
|
+
// brief API hiccup first.
|
|
27
|
+
const RETRY_DELAYS_MS = [1_000, 3_000];
|
|
28
|
+
// Failures where the request never reached the server.
|
|
29
|
+
const NOT_SENT_CODES = new Set(['ECONNREFUSED', 'ENOTFOUND', 'EAI_AGAIN']);
|
|
30
|
+
/**
|
|
31
|
+
* Any brief failure: for requests that are safe to repeat. Wider than the
|
|
32
|
+
* shared API client's policy (rest/retry.ts), which leaves out 500 and 408:
|
|
33
|
+
* here giving up costs the user another browser approval, not just a
|
|
34
|
+
* failed command.
|
|
35
|
+
*/
|
|
36
|
+
function isTransient(error) {
|
|
37
|
+
const status = error.response?.status;
|
|
38
|
+
return status === undefined || status >= 500 || status === 408 || status === 429;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A failure the server certainly did not act on: for creating an API key,
|
|
42
|
+
* where repeating a request that was processed but whose answer was lost
|
|
43
|
+
* would leave an extra long-lived key nobody holds.
|
|
44
|
+
*/
|
|
45
|
+
function wasNotProcessed(error) {
|
|
46
|
+
if (error.response) {
|
|
47
|
+
return error.response.status === 503 || error.response.status === 429;
|
|
48
|
+
}
|
|
49
|
+
return NOT_SENT_CODES.has(error.code ?? '');
|
|
50
|
+
}
|
|
51
|
+
async function withRetries(sleep, request, retryable) {
|
|
52
|
+
for (const delayMs of RETRY_DELAYS_MS) {
|
|
53
|
+
try {
|
|
54
|
+
return await request();
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (!isAxiosError(error) || !retryable(error)) {
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
await sleep(delayMs);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return request();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Trades an Auth0 access token for a long-lived Checkly API key, registering
|
|
67
|
+
* the user with Checkly first when the Auth0 identity is not known yet
|
|
68
|
+
* (that is what a fresh sign-up looks like from the CLI's point of view).
|
|
69
|
+
*/
|
|
70
|
+
export async function exchangeAccessTokenForApiKey(accessToken, deps = {}) {
|
|
71
|
+
const { createClient, hostname, sleep } = { ...defaultDeps, ...deps };
|
|
72
|
+
const client = createClient(accessToken);
|
|
73
|
+
try {
|
|
74
|
+
// Repeating this is safe: a registration that went through is seen by
|
|
75
|
+
// the next GET, so it is not attempted again.
|
|
76
|
+
await withRetries(sleep, async () => {
|
|
77
|
+
try {
|
|
78
|
+
await client.get('/users/me');
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error.response?.status === 401) {
|
|
82
|
+
await client.post('/users/', { accessToken });
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}, isTransient);
|
|
89
|
+
const apiKeyName = `CLI User Key (${hostname()})`;
|
|
90
|
+
const { data } = await withRetries(sleep, () => client.post(`/users/me/api-keys?name=${apiKeyName}`), wasNotProcessed);
|
|
91
|
+
return data;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
// The same typed errors as the regular API client, so callers can tell a
|
|
95
|
+
// failed or unreachable Checkly API from other failures.
|
|
96
|
+
handleErrorResponse(error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export async function credentialsFromTokens(tokens, deps = {}) {
|
|
100
|
+
const { name } = jwtDecode(tokens.idToken);
|
|
101
|
+
const { key } = await exchangeAccessTokenForApiKey(tokens.accessToken, deps);
|
|
102
|
+
return { name, key };
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=api-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key.js","sourceRoot":"","sources":["../../src/auth/api-key.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export declare const AUTH0_CLIENT_ID = "mBtwLFVm39GVZ1HpSRBSdRiLFucYxmMb";
|
|
2
|
+
export interface DeviceAuthorization {
|
|
3
|
+
deviceCode: string;
|
|
4
|
+
userCode: string;
|
|
5
|
+
verificationUri: string;
|
|
6
|
+
verificationUriComplete: string;
|
|
7
|
+
/** Epoch milliseconds after which the device code is no longer valid. */
|
|
8
|
+
expiresAt: number;
|
|
9
|
+
intervalMs: number;
|
|
10
|
+
}
|
|
11
|
+
export interface DeviceTokens {
|
|
12
|
+
accessToken: string;
|
|
13
|
+
idToken: string;
|
|
14
|
+
}
|
|
15
|
+
export interface OAuthResponse {
|
|
16
|
+
status: number;
|
|
17
|
+
data: any;
|
|
18
|
+
}
|
|
19
|
+
export interface DeviceFlowDeps {
|
|
20
|
+
/** Must resolve for non-2xx responses too; the flow reads OAuth error codes from the body. */
|
|
21
|
+
post: (url: string, params: URLSearchParams) => Promise<OAuthResponse>;
|
|
22
|
+
sleep: (ms: number) => Promise<void>;
|
|
23
|
+
now: () => number;
|
|
24
|
+
}
|
|
25
|
+
export declare class DeviceFlowError extends Error {
|
|
26
|
+
readonly code: string;
|
|
27
|
+
constructor(code: string, message: string, options?: ErrorOptions);
|
|
28
|
+
}
|
|
29
|
+
/** The Auth0 client does not have the device_code grant enabled. */
|
|
30
|
+
export declare class DeviceFlowNotAllowedError extends DeviceFlowError {
|
|
31
|
+
constructor(message: string);
|
|
32
|
+
}
|
|
33
|
+
export declare class DeviceFlow {
|
|
34
|
+
#private;
|
|
35
|
+
constructor(deps?: Partial<DeviceFlowDeps>);
|
|
36
|
+
requestAuthorization(): Promise<DeviceAuthorization>;
|
|
37
|
+
/**
|
|
38
|
+
* Polls until the user approves or the code expires. When the answers keep
|
|
39
|
+
* coming from something other than the login server (a proxy or captive
|
|
40
|
+
* portal), `onUnexpectedAnswers` is called once per such run with the latest one, and
|
|
41
|
+
* polling goes on: the user may still be getting past a captive portal,
|
|
42
|
+
* and the code stays valid.
|
|
43
|
+
*/
|
|
44
|
+
pollForTokens(auth: DeviceAuthorization, { onUnexpectedAnswers }?: {
|
|
45
|
+
onUnexpectedAnswers?: (failure: string) => void;
|
|
46
|
+
}): Promise<DeviceTokens>;
|
|
47
|
+
/**
|
|
48
|
+
* A single token request without waiting, so a caller can check a stored
|
|
49
|
+
* code and return at once. `tokens` once the user has approved; otherwise
|
|
50
|
+
* `failure` says why the login server could not answer, if it could not
|
|
51
|
+
* (the user may then have approved without the CLI seeing it yet).
|
|
52
|
+
*/
|
|
53
|
+
pollOnce(auth: DeviceAuthorization): Promise<{
|
|
54
|
+
tokens?: DeviceTokens;
|
|
55
|
+
failure?: string;
|
|
56
|
+
}>;
|
|
57
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { assignProxy } from '../services/proxy.js';
|
|
3
|
+
import config from '../services/config.js';
|
|
4
|
+
// OAuth 2.0 Device Authorization Grant (RFC 8628) against Checkly's Auth0 tenant.
|
|
5
|
+
// The user opens a URL on any device and enters a short code; the CLI polls for
|
|
6
|
+
// the tokens. Unlike the authorization-code flow this needs no local callback
|
|
7
|
+
// server, so it works over SSH, in containers and from agent sandboxes.
|
|
8
|
+
export const AUTH0_CLIENT_ID = 'mBtwLFVm39GVZ1HpSRBSdRiLFucYxmMb';
|
|
9
|
+
const deviceCodeUrl = () => `${config.getAuthUrl()}/oauth/device/code`;
|
|
10
|
+
const tokenUrl = () => `${config.getAuthUrl()}/oauth/token`;
|
|
11
|
+
const AUTH0_SCOPES = 'openid profile email';
|
|
12
|
+
const DEVICE_CODE_GRANT = 'urn:ietf:params:oauth:grant-type:device_code';
|
|
13
|
+
const DEFAULT_INTERVAL_MS = 5_000;
|
|
14
|
+
const SLOW_DOWN_STEP_MS = 5_000;
|
|
15
|
+
// Upper bound for the time between polls, from the server's interval or
|
|
16
|
+
// after backing off: a delay beyond setTimeout's range would fire at once,
|
|
17
|
+
// and a long one would notice an approval late. Deliberately departs from
|
|
18
|
+
// RFC 8628's "add 5 seconds on every slow_down" once reached; no login server
|
|
19
|
+
// we use needs a minute between polls.
|
|
20
|
+
const MAX_INTERVAL_MS = 60_000;
|
|
21
|
+
// How many answers in a row that did not come from the login server (a proxy
|
|
22
|
+
// or captive portal) a waiting login takes before it reports them.
|
|
23
|
+
const MAX_UNEXPECTED_RESPONSES = 5;
|
|
24
|
+
const REQUEST_TIMEOUT_MS = 30_000;
|
|
25
|
+
export class DeviceFlowError extends Error {
|
|
26
|
+
code;
|
|
27
|
+
constructor(code, message, options) {
|
|
28
|
+
super(message, options);
|
|
29
|
+
this.code = code;
|
|
30
|
+
this.name = 'DeviceFlowError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** The Auth0 client does not have the device_code grant enabled. */
|
|
34
|
+
export class DeviceFlowNotAllowedError extends DeviceFlowError {
|
|
35
|
+
constructor(message) {
|
|
36
|
+
super('unauthorized_client', message);
|
|
37
|
+
this.name = 'DeviceFlowNotAllowedError';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const defaultDeps = {
|
|
41
|
+
post: async (url, params) => {
|
|
42
|
+
const { status, data } = await axios.post(url, params, assignProxy(url, {
|
|
43
|
+
headers: {
|
|
44
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
45
|
+
'Accept-Encoding': '*',
|
|
46
|
+
},
|
|
47
|
+
validateStatus: () => true,
|
|
48
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
49
|
+
}));
|
|
50
|
+
return { status, data };
|
|
51
|
+
},
|
|
52
|
+
sleep: ms => new Promise(resolve => setTimeout(resolve, ms)),
|
|
53
|
+
now: () => Date.now(),
|
|
54
|
+
};
|
|
55
|
+
function errorFrom(data, fallback) {
|
|
56
|
+
const code = data?.error ?? fallback;
|
|
57
|
+
const message = data?.error_description ?? `Authentication failed (${code})`;
|
|
58
|
+
if (code === 'unauthorized_client') {
|
|
59
|
+
return new DeviceFlowNotAllowedError(message);
|
|
60
|
+
}
|
|
61
|
+
return new DeviceFlowError(code, message);
|
|
62
|
+
}
|
|
63
|
+
function notFromLoginServer(what) {
|
|
64
|
+
return `${what} that did not come from the login server; check your network or proxy settings`;
|
|
65
|
+
}
|
|
66
|
+
function unexpectedResponseError() {
|
|
67
|
+
return new DeviceFlowError('invalid_response', 'The login server returned an unexpected response. Check your network or proxy settings and try again.');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Names a failed request by its error code only: error messages can carry
|
|
71
|
+
* request or proxy URLs, credentials included.
|
|
72
|
+
*/
|
|
73
|
+
function transportFailure(error) {
|
|
74
|
+
const code = error?.code;
|
|
75
|
+
return typeof code === 'string' ? code : 'network error';
|
|
76
|
+
}
|
|
77
|
+
function tokenParams(auth) {
|
|
78
|
+
return new URLSearchParams({
|
|
79
|
+
grant_type: DEVICE_CODE_GRANT,
|
|
80
|
+
device_code: auth.deviceCode,
|
|
81
|
+
client_id: AUTH0_CLIENT_ID,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
export class DeviceFlow {
|
|
85
|
+
#deps;
|
|
86
|
+
constructor(deps = {}) {
|
|
87
|
+
this.#deps = { ...defaultDeps, ...deps };
|
|
88
|
+
}
|
|
89
|
+
async requestAuthorization() {
|
|
90
|
+
const params = new URLSearchParams({
|
|
91
|
+
client_id: AUTH0_CLIENT_ID,
|
|
92
|
+
scope: AUTH0_SCOPES,
|
|
93
|
+
});
|
|
94
|
+
let response;
|
|
95
|
+
try {
|
|
96
|
+
response = await this.#deps.post(deviceCodeUrl(), params);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
throw new DeviceFlowError('network_error', `Could not reach the login server (${transportFailure(error)}). `
|
|
100
|
+
+ 'Check your network or proxy settings and try again.', { cause: error });
|
|
101
|
+
}
|
|
102
|
+
const { status, data } = response;
|
|
103
|
+
// A proxy or captive portal can answer in place of the login server, with
|
|
104
|
+
// an HTML page and any status; without these checks the user would see an
|
|
105
|
+
// unhelpful error or "undefined" for the URL and the code.
|
|
106
|
+
if (status < 200 || status >= 300) {
|
|
107
|
+
if (typeof data?.error !== 'string') {
|
|
108
|
+
throw unexpectedResponseError();
|
|
109
|
+
}
|
|
110
|
+
throw errorFrom(data, 'device_authorization_failed');
|
|
111
|
+
}
|
|
112
|
+
const isText = (value) => typeof value === 'string' && value !== '';
|
|
113
|
+
if (!isText(data?.device_code) || !isText(data?.user_code) || !isText(data?.verification_uri)
|
|
114
|
+
|| !(Number.isFinite(data?.expires_in) && data.expires_in > 0)) {
|
|
115
|
+
throw unexpectedResponseError();
|
|
116
|
+
}
|
|
117
|
+
// At least a second and at most MAX_INTERVAL_MS, whatever the response says.
|
|
118
|
+
const intervalSeconds = Number.isFinite(data.interval) && data.interval > 0
|
|
119
|
+
? Math.min(MAX_INTERVAL_MS / 1000, Math.max(1, data.interval))
|
|
120
|
+
: DEFAULT_INTERVAL_MS / 1000;
|
|
121
|
+
return {
|
|
122
|
+
deviceCode: data.device_code,
|
|
123
|
+
userCode: data.user_code,
|
|
124
|
+
verificationUri: data.verification_uri,
|
|
125
|
+
verificationUriComplete: isText(data.verification_uri_complete)
|
|
126
|
+
? data.verification_uri_complete
|
|
127
|
+
: data.verification_uri,
|
|
128
|
+
expiresAt: this.#deps.now() + data.expires_in * 1000,
|
|
129
|
+
intervalMs: intervalSeconds * 1000,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Polls until the user approves or the code expires. When the answers keep
|
|
134
|
+
* coming from something other than the login server (a proxy or captive
|
|
135
|
+
* portal), `onUnexpectedAnswers` is called once per such run with the latest one, and
|
|
136
|
+
* polling goes on: the user may still be getting past a captive portal,
|
|
137
|
+
* and the code stays valid.
|
|
138
|
+
*/
|
|
139
|
+
async pollForTokens(auth, { onUnexpectedAnswers } = {}) {
|
|
140
|
+
const params = tokenParams(auth);
|
|
141
|
+
let intervalMs = auth.intervalMs;
|
|
142
|
+
let lastFailure;
|
|
143
|
+
let unexpectedInARow = 0;
|
|
144
|
+
while (this.#deps.now() + intervalMs <= auth.expiresAt) {
|
|
145
|
+
await this.#deps.sleep(intervalMs);
|
|
146
|
+
const result = await this.#requestTokens(params);
|
|
147
|
+
lastFailure = result.failure;
|
|
148
|
+
unexpectedInARow = result.unexpected ? unexpectedInARow + 1 : 0;
|
|
149
|
+
if (unexpectedInARow === MAX_UNEXPECTED_RESPONSES) {
|
|
150
|
+
onUnexpectedAnswers?.(result.failure);
|
|
151
|
+
}
|
|
152
|
+
if (result.state === 'slow_down') {
|
|
153
|
+
intervalMs = Math.min(MAX_INTERVAL_MS, intervalMs + SLOW_DOWN_STEP_MS);
|
|
154
|
+
}
|
|
155
|
+
else if (result.state === 'approved') {
|
|
156
|
+
return result.tokens;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// A code the user approved can still expire here when the login server
|
|
160
|
+
// was unreachable at the end; say so rather than blaming the user.
|
|
161
|
+
throw new DeviceFlowError('expired_token', lastFailure
|
|
162
|
+
? `The login code expired; the last attempt to reach the login server failed (${lastFailure}). `
|
|
163
|
+
+ 'Please run the login again.'
|
|
164
|
+
: 'The login code expired before it was used. Please run the login again.');
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* A single token request without waiting, so a caller can check a stored
|
|
168
|
+
* code and return at once. `tokens` once the user has approved; otherwise
|
|
169
|
+
* `failure` says why the login server could not answer, if it could not
|
|
170
|
+
* (the user may then have approved without the CLI seeing it yet).
|
|
171
|
+
*/
|
|
172
|
+
async pollOnce(auth) {
|
|
173
|
+
const result = await this.#requestTokens(tokenParams(auth));
|
|
174
|
+
return result.state === 'approved' ? { tokens: result.tokens } : { failure: result.failure };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* One token request. Polling can last as long as the code is valid, often
|
|
178
|
+
* after the user has already approved it in the browser, so a network
|
|
179
|
+
* failure, a server-side error, a rate limit or an answer that did not come from the
|
|
180
|
+
* login server (e.g. a proxy's or captive portal's page) counts as "try
|
|
181
|
+
* again" rather than ending the login; only an OAuth error from the server
|
|
182
|
+
* is final.
|
|
183
|
+
*/
|
|
184
|
+
async #requestTokens(params) {
|
|
185
|
+
let response;
|
|
186
|
+
try {
|
|
187
|
+
response = await this.#deps.post(tokenUrl(), params);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
return { state: 'pending', failure: transportFailure(error) };
|
|
191
|
+
}
|
|
192
|
+
const { status, data } = response;
|
|
193
|
+
if (status >= 200 && status < 300) {
|
|
194
|
+
if (!data?.access_token || !data?.id_token) {
|
|
195
|
+
return { state: 'pending', failure: notFromLoginServer('a response without tokens'), unexpected: true };
|
|
196
|
+
}
|
|
197
|
+
return { state: 'approved', tokens: { accessToken: data.access_token, idToken: data.id_token } };
|
|
198
|
+
}
|
|
199
|
+
// Not counted as unexpected: an outage of the login server itself is
|
|
200
|
+
// worth waiting out for as long as the code is valid.
|
|
201
|
+
if (status >= 500) {
|
|
202
|
+
return { state: 'pending', failure: `HTTP ${status}` };
|
|
203
|
+
}
|
|
204
|
+
if (data?.error === 'slow_down') {
|
|
205
|
+
return { state: 'slow_down' };
|
|
206
|
+
}
|
|
207
|
+
// Rate limited (by the login server or something in front of it): never
|
|
208
|
+
// a final answer, and it says nothing about whether the code was approved.
|
|
209
|
+
if (status === 429) {
|
|
210
|
+
return { state: 'slow_down', failure: 'HTTP 429' };
|
|
211
|
+
}
|
|
212
|
+
if (data?.error === 'authorization_pending') {
|
|
213
|
+
return { state: 'pending' };
|
|
214
|
+
}
|
|
215
|
+
if (typeof data?.error !== 'string') {
|
|
216
|
+
return { state: 'pending', failure: notFromLoginServer(`HTTP ${status}`), unexpected: true };
|
|
217
|
+
}
|
|
218
|
+
throw errorFrom(data, 'token_request_failed');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=device-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-flow.js","sourceRoot":"","sources":["../../src/auth/device-flow.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/** 'any' leaves both login and sign-up enabled on the hosted page. */
|
|
2
|
+
export type AuthMode = 'signup' | 'login' | 'any';
|
|
2
3
|
export declare function generatePKCE(): {
|
|
3
4
|
codeChallenge: string;
|
|
4
5
|
codeVerifier: string;
|
|
@@ -7,9 +8,8 @@ export declare class AuthContext {
|
|
|
7
8
|
#private;
|
|
8
9
|
private mode;
|
|
9
10
|
authenticationUrl: string;
|
|
10
|
-
constructor(mode: AuthMode
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}>;
|
|
11
|
+
constructor(mode: AuthMode, { timeoutMs }?: {
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
});
|
|
14
|
+
getAuth0Credentials(): Promise<import("./api-key.js").Credentials>;
|
|
15
15
|
}
|
package/dist/auth/index.js
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import * as os from 'os';
|
|
3
2
|
import * as http from 'http';
|
|
4
3
|
import * as crypto from 'crypto';
|
|
5
|
-
import { jwtDecode } from 'jwt-decode';
|
|
6
|
-
import { getDefaults as getApiDefaults } from '../rest/api.js';
|
|
7
|
-
import { assignProxy } from '../services/proxy.js';
|
|
8
4
|
import * as fs from 'fs';
|
|
9
5
|
import * as path from 'path';
|
|
10
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { credentialsFromTokens } from './api-key.js';
|
|
8
|
+
import { assignProxy } from '../services/proxy.js';
|
|
9
|
+
import config from '../services/config.js';
|
|
11
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
11
|
const AUTH0_CLIENT_ID = 'mBtwLFVm39GVZ1HpSRBSdRiLFucYxmMb';
|
|
13
|
-
const
|
|
12
|
+
const authorizationUrl = () => `${config.getAuthUrl()}/authorize`;
|
|
13
|
+
const tokenUrl = () => `${config.getAuthUrl()}/oauth/token`;
|
|
14
14
|
const AUTH0_SCOPES = 'openid profile email';
|
|
15
15
|
const AUTH0_CALLBACK_URL = 'http://localhost:4242';
|
|
16
|
+
// Long enough to sign up (which can include confirming an email address),
|
|
17
|
+
// short enough not to block an inline login for long; within what other CLIs
|
|
18
|
+
// use for a browser login (AWS CLI and Heroku wait 10 minutes).
|
|
19
|
+
const LOGIN_TIMEOUT_MS = 10 * 60 * 1000;
|
|
20
|
+
function escapeHtml(value) {
|
|
21
|
+
return (value ?? '').replace(/[&<>"']/g, char => `&#${char.charCodeAt(0)};`);
|
|
22
|
+
}
|
|
16
23
|
export function generatePKCE() {
|
|
17
24
|
const codeVerifier = crypto
|
|
18
25
|
.randomBytes(64)
|
|
@@ -39,8 +46,10 @@ export class AuthContext {
|
|
|
39
46
|
#codeVerifier;
|
|
40
47
|
#accessToken;
|
|
41
48
|
#idToken;
|
|
42
|
-
|
|
49
|
+
#timeoutMs;
|
|
50
|
+
constructor(mode, { timeoutMs = LOGIN_TIMEOUT_MS } = {}) {
|
|
43
51
|
this.mode = mode;
|
|
52
|
+
this.#timeoutMs = timeoutMs;
|
|
44
53
|
const { codeChallenge, codeVerifier } = generatePKCE();
|
|
45
54
|
this.#codeChallenge = codeChallenge;
|
|
46
55
|
this.#codeVerifier = codeVerifier;
|
|
@@ -52,15 +61,10 @@ export class AuthContext {
|
|
|
52
61
|
throw new Error('There was an unexpected error retrieving Auth0 token. Please try again or contact '
|
|
53
62
|
+ 'support@checklyhq.com if this problem persists');
|
|
54
63
|
}
|
|
55
|
-
|
|
56
|
-
const { key } = await this.#getApiKey();
|
|
57
|
-
return {
|
|
58
|
-
name,
|
|
59
|
-
key,
|
|
60
|
-
};
|
|
64
|
+
return credentialsFromTokens({ accessToken: this.#accessToken, idToken: this.#idToken });
|
|
61
65
|
}
|
|
62
66
|
#generateAuthenticationUrl() {
|
|
63
|
-
const url = new URL(
|
|
67
|
+
const url = new URL(authorizationUrl());
|
|
64
68
|
const params = new URLSearchParams({
|
|
65
69
|
client_id: AUTH0_CLIENT_ID,
|
|
66
70
|
code_challenge: this.#codeChallenge,
|
|
@@ -71,30 +75,61 @@ export class AuthContext {
|
|
|
71
75
|
state: this.#codeVerifier,
|
|
72
76
|
mode: this.mode === 'signup' ? 'signUp' : '',
|
|
73
77
|
allowLogin: this.mode === 'signup' ? 'false' : 'true',
|
|
74
|
-
allowSignUp: this.mode === '
|
|
78
|
+
allowSignUp: this.mode === 'login' ? 'false' : 'true',
|
|
75
79
|
});
|
|
76
80
|
url.search = params.toString();
|
|
77
81
|
return url.toString();
|
|
78
82
|
}
|
|
79
83
|
#startServer() {
|
|
80
84
|
return new Promise((resolve, reject) => {
|
|
85
|
+
// The CLI may keep running after the login (an authenticated command
|
|
86
|
+
// logging in inline), so nothing here may keep the process alive
|
|
87
|
+
// afterwards: every request gets an answer, the response that settles
|
|
88
|
+
// the login closes its connection instead of keeping it alive for the
|
|
89
|
+
// browser's next request, and the server stops listening.
|
|
81
90
|
const server = http.createServer();
|
|
91
|
+
// Nobody may ever finish the login in the browser; without a deadline
|
|
92
|
+
// the process (and an authenticated command logging in inline) would
|
|
93
|
+
// wait forever. No response carries `Connection: close` in that case,
|
|
94
|
+
// so connections the browser keeps alive are dropped explicitly.
|
|
95
|
+
const timer = setTimeout(() => {
|
|
96
|
+
server.close();
|
|
97
|
+
server.closeAllConnections();
|
|
98
|
+
reject(new Error('The login was not completed in time. Please run the login again.'));
|
|
99
|
+
}, this.#timeoutMs);
|
|
100
|
+
const stop = () => {
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
server.close();
|
|
103
|
+
};
|
|
82
104
|
server.on('request', (req, res) => {
|
|
83
105
|
if (req.url?.endsWith('.svg')) {
|
|
84
|
-
res.writeHead(200, { 'Content-Type': 'image/svg+xml' });
|
|
85
106
|
fs.readFile(path.join(__dirname, `.${req.url}`), 'utf8', (err, data) => {
|
|
86
|
-
if (
|
|
87
|
-
res.end(
|
|
107
|
+
if (err) {
|
|
108
|
+
res.writeHead(404).end();
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
res.writeHead(200, { 'Content-Type': 'image/svg+xml' }).end(data);
|
|
112
|
+
}
|
|
88
113
|
});
|
|
114
|
+
}
|
|
115
|
+
else if (req.url?.includes('favicon.ico')) {
|
|
116
|
+
res.writeHead(404).end();
|
|
89
117
|
// `req.url` has a '/' char at the beginning which needs removed to be valid searchParams input
|
|
90
118
|
}
|
|
91
|
-
else
|
|
119
|
+
else {
|
|
92
120
|
const responseParams = new URLSearchParams(req.url?.substring(1));
|
|
93
121
|
const code = responseParams.get('code');
|
|
94
122
|
const state = responseParams.get('state');
|
|
95
123
|
const error = responseParams.get('error');
|
|
96
124
|
const errorDescription = responseParams.get('error_description');
|
|
97
|
-
|
|
125
|
+
// A code or an error that answers this login (the state matches)
|
|
126
|
+
// settles it, as the device flow does; anything else, such as a
|
|
127
|
+
// stray request, leaves the server waiting for the real callback.
|
|
128
|
+
const settles = state === this.#codeVerifier && Boolean(code || error);
|
|
129
|
+
if (settles) {
|
|
130
|
+
res.setHeader('Connection', 'close');
|
|
131
|
+
}
|
|
132
|
+
if (code && settles) {
|
|
98
133
|
res.write(`
|
|
99
134
|
<html>
|
|
100
135
|
<style>
|
|
@@ -131,6 +166,7 @@ export class AuthContext {
|
|
|
131
166
|
</body>
|
|
132
167
|
</html>
|
|
133
168
|
`);
|
|
169
|
+
stop();
|
|
134
170
|
resolve(code);
|
|
135
171
|
}
|
|
136
172
|
else {
|
|
@@ -138,24 +174,24 @@ export class AuthContext {
|
|
|
138
174
|
<html>
|
|
139
175
|
<body>
|
|
140
176
|
<div style="height:100%;width:100%;inset:0;position:absolute;display:grid;place-items:center;background-color:#EFF2F7;text-align:center;font-family:Inter;">
|
|
141
|
-
<h3 style="font-weight:200;"
|
|
177
|
+
<h3 style="font-weight:200;">${settles ? 'Login failed. Go back to your terminal; you can close this tab.' : 'Login failed, please try again!'}</h3>
|
|
142
178
|
<p>
|
|
143
|
-
<b>${error}</b>: ${errorDescription}
|
|
179
|
+
<b>${escapeHtml(error)}</b>: ${escapeHtml(errorDescription)}
|
|
144
180
|
</p>
|
|
145
181
|
</div>
|
|
146
182
|
</body>
|
|
147
183
|
</html>
|
|
148
184
|
`);
|
|
185
|
+
if (settles) {
|
|
186
|
+
stop();
|
|
187
|
+
reject(new Error(`Login failed: ${errorDescription || error}`));
|
|
188
|
+
}
|
|
149
189
|
}
|
|
150
190
|
res.end();
|
|
151
191
|
}
|
|
152
192
|
});
|
|
153
|
-
const signals = ['SIGTERM', 'SIGHUP', 'SIGINT'];
|
|
154
|
-
signals.forEach(signal => process.on(signal, () => {
|
|
155
|
-
server.close();
|
|
156
|
-
process.exitCode = 1;
|
|
157
|
-
}));
|
|
158
193
|
server.listen(4242).on('error', (err) => {
|
|
194
|
+
clearTimeout(timer);
|
|
159
195
|
if (err.code === 'EADDRINUSE') {
|
|
160
196
|
reject(new Error('Unable to start a local server on port 4242.'
|
|
161
197
|
+ ' Please check that `checkly login` isn\'t already running in a separate tab.'
|
|
@@ -176,51 +212,15 @@ export class AuthContext {
|
|
|
176
212
|
code,
|
|
177
213
|
redirect_uri: AUTH0_CALLBACK_URL,
|
|
178
214
|
});
|
|
179
|
-
const tokenResponse = await
|
|
215
|
+
const tokenResponse = await axios.post(tokenUrl(), tokenParams, assignProxy(tokenUrl(), {
|
|
180
216
|
headers: {
|
|
181
217
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
182
218
|
'Accept-Encoding': '*',
|
|
183
219
|
},
|
|
184
|
-
});
|
|
220
|
+
}));
|
|
185
221
|
const { access_token: accessToken, id_token: idToken } = tokenResponse.data;
|
|
186
222
|
this.#accessToken = accessToken;
|
|
187
223
|
this.#idToken = idToken;
|
|
188
224
|
}
|
|
189
|
-
async #getApiKey() {
|
|
190
|
-
try {
|
|
191
|
-
await this.#fetchUser();
|
|
192
|
-
}
|
|
193
|
-
catch (error) {
|
|
194
|
-
if (error.response?.status === 401) {
|
|
195
|
-
await this.#registerUser();
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
throw error;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const apiKeyName = `CLI User Key (${os.hostname()})`;
|
|
202
|
-
const { data } = await this.#axiosInstance.post(`/users/me/api-keys?name=${apiKeyName}`);
|
|
203
|
-
return data;
|
|
204
|
-
}
|
|
205
|
-
async #fetchUser() {
|
|
206
|
-
const { data } = await this.#axiosInstance.get('/users/me');
|
|
207
|
-
return data;
|
|
208
|
-
}
|
|
209
|
-
async #registerUser() {
|
|
210
|
-
const { data } = await this.#axiosInstance.post('/users/', { accessToken: this.#accessToken });
|
|
211
|
-
return data;
|
|
212
|
-
}
|
|
213
|
-
get #axiosInstance() {
|
|
214
|
-
// Keep axios instance stateless
|
|
215
|
-
const { baseURL } = getApiDefaults();
|
|
216
|
-
const axiosConf = assignProxy(baseURL, {
|
|
217
|
-
baseURL,
|
|
218
|
-
headers: {
|
|
219
|
-
Accept: 'application/json, text/plain, */*',
|
|
220
|
-
Authorization: `Bearer ${this.#accessToken}`,
|
|
221
|
-
},
|
|
222
|
-
});
|
|
223
|
-
return axios.create(axiosConf);
|
|
224
|
-
}
|
|
225
225
|
}
|
|
226
226
|
//# sourceMappingURL=index.js.map
|