@tellescope/sdk 1.256.13 → 1.256.15
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/lib/cjs/tests/api_tests/auto_merge_form_submission.test.js +1 -1
- package/lib/cjs/tests/api_tests/auto_merge_form_submission.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.js +388 -0
- package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/integrations_redacted.test.js +3 -3
- package/lib/cjs/tests/api_tests/integrations_redacted.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/organization_signup.test.d.ts +20 -0
- package/lib/cjs/tests/api_tests/organization_signup.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/organization_signup.test.js +272 -0
- package/lib/cjs/tests/api_tests/organization_signup.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/purchase_made_trigger.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/purchase_made_trigger.test.js +103 -162
- package/lib/cjs/tests/api_tests/purchase_made_trigger.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +336 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +354 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +389 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +324 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +282 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts +33 -0
- package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.js +249 -0
- package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts +42 -0
- package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js +281 -0
- package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.d.ts +38 -0
- package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.js +390 -0
- package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.js +1003 -0
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.d.ts +42 -0
- package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.js +323 -0
- package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts +29 -0
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.js +335 -0
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts +32 -0
- package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js +237 -0
- package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts +28 -0
- package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.js +349 -0
- package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts +30 -0
- package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js +314 -0
- package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.d.ts +21 -0
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.js +362 -0
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.d.ts +21 -0
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.js +366 -0
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.d.ts +32 -0
- package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.js +248 -0
- package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts +19 -0
- package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.js +138 -0
- package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts +24 -0
- package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js +201 -0
- package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.d.ts +29 -0
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.js +278 -0
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.d.ts +17 -0
- package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.js +155 -0
- package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/prototype-pollution.test.d.ts +2 -0
- package/lib/cjs/tests/api_tests/security/prototype-pollution.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/prototype-pollution.test.js +88 -0
- package/lib/cjs/tests/api_tests/security/prototype-pollution.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts +34 -0
- package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.js +230 -0
- package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts +2 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js +242 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.d.ts +2 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.js +148 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts +45 -0
- package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.js +388 -0
- package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.d.ts +38 -0
- package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.js +222 -0
- package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js +354 -0
- package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts +28 -0
- package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.js +442 -0
- package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/webhook-timeout.test.d.ts +19 -0
- package/lib/cjs/tests/api_tests/security/webhook-timeout.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/webhook-timeout.test.js +156 -0
- package/lib/cjs/tests/api_tests/security/webhook-timeout.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js +329 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/webhook_error_handling.test.js +2 -2
- package/lib/cjs/tests/api_tests/webhook_error_handling.test.js.map +1 -1
- package/lib/cjs/tests/setup_isolated.d.ts +68 -0
- package/lib/cjs/tests/setup_isolated.d.ts.map +1 -0
- package/lib/cjs/tests/setup_isolated.js +232 -0
- package/lib/cjs/tests/setup_isolated.js.map +1 -0
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +287 -227
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.js +89 -0
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.js.map +1 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js +140 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
- package/lib/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/lib/esm/tests/api_tests/auto_merge_form_submission.test.js +1 -1
- package/lib/esm/tests/api_tests/auto_merge_form_submission.test.js.map +1 -1
- package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.js +383 -0
- package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.js.map +1 -0
- package/lib/esm/tests/api_tests/integrations_redacted.test.js +3 -3
- package/lib/esm/tests/api_tests/integrations_redacted.test.js.map +1 -1
- package/lib/esm/tests/api_tests/organization_signup.test.d.ts +20 -0
- package/lib/esm/tests/api_tests/organization_signup.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/organization_signup.test.js +264 -0
- package/lib/esm/tests/api_tests/organization_signup.test.js.map +1 -0
- package/lib/esm/tests/api_tests/purchase_made_trigger.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/purchase_made_trigger.test.js +104 -163
- package/lib/esm/tests/api_tests/purchase_made_trigger.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +332 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +350 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +382 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +317 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +277 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts +33 -0
- package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.js +244 -0
- package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts +42 -0
- package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js +276 -0
- package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.d.ts +38 -0
- package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.js +386 -0
- package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.js +996 -0
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.d.ts +42 -0
- package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.js +316 -0
- package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts +29 -0
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.js +331 -0
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts +32 -0
- package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js +233 -0
- package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts +28 -0
- package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.js +345 -0
- package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts +30 -0
- package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js +310 -0
- package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.d.ts +21 -0
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.js +358 -0
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.d.ts +21 -0
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.js +362 -0
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.d.ts +32 -0
- package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.js +243 -0
- package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts +19 -0
- package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.js +134 -0
- package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts +24 -0
- package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js +194 -0
- package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.d.ts +29 -0
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.js +271 -0
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.d.ts +17 -0
- package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.js +151 -0
- package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/prototype-pollution.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/security/prototype-pollution.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/prototype-pollution.test.js +84 -0
- package/lib/esm/tests/api_tests/security/prototype-pollution.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts +34 -0
- package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.js +223 -0
- package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.js +238 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html.test.js +144 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts +45 -0
- package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.js +381 -0
- package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.d.ts +38 -0
- package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.js +218 -0
- package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js +350 -0
- package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts +28 -0
- package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.js +435 -0
- package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/webhook-timeout.test.d.ts +19 -0
- package/lib/esm/tests/api_tests/security/webhook-timeout.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/webhook-timeout.test.js +149 -0
- package/lib/esm/tests/api_tests/security/webhook-timeout.test.js.map +1 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js +324 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
- package/lib/esm/tests/api_tests/webhook_error_handling.test.js +2 -2
- package/lib/esm/tests/api_tests/webhook_error_handling.test.js.map +1 -1
- package/lib/esm/tests/setup_isolated.d.ts +68 -0
- package/lib/esm/tests/setup_isolated.d.ts.map +1 -0
- package/lib/esm/tests/setup_isolated.js +221 -0
- package/lib/esm/tests/setup_isolated.js.map +1 -0
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +287 -227
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
- package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
- package/lib/esm/tests/unit_tests/do_not_send_address.test.js +85 -0
- package/lib/esm/tests/unit_tests/do_not_send_address.test.js.map +1 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js +113 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/tests/api_tests/auto_merge_form_submission.test.ts +1 -1
- package/src/tests/api_tests/enduser_observations_auto_review.test.ts +358 -0
- package/src/tests/api_tests/integrations_redacted.test.ts +1 -1
- package/src/tests/api_tests/organization_signup.test.ts +240 -0
- package/src/tests/api_tests/purchase_made_trigger.test.ts +29 -41
- package/src/tests/api_tests/security/add-to-journey-foreign-enduserid.test.ts +207 -0
- package/src/tests/api_tests/security/{F-0005-ai-conversations-rbac.test.ts → ai-conversations-rbac.test.ts} +14 -14
- package/src/tests/api_tests/security/{F-0166-allowed-paths-wildcard-bypass.test.ts → allowed-paths-confinement.test.ts} +11 -11
- package/src/tests/api_tests/security/automated-actions-process-gate.test.ts +237 -0
- package/src/tests/api_tests/security/booking-info-idor-token-mint.test.ts +224 -0
- package/src/tests/api_tests/security/{F-0053-cascade-role-rename-cross-tenant.test.ts → cascade-role-rename-cross-tenant.test.ts} +10 -10
- package/src/tests/api_tests/security/{F-0001-data-sync-redaction-bypass.test.ts → data-sync-redaction-bypass.test.ts} +9 -9
- package/src/tests/api_tests/security/{F-0006-develop-health-benefit-verification-rbac.test.ts → develop-health-benefit-verification-rbac.test.ts} +7 -8
- package/src/tests/api_tests/security/{F-0116-F-0119-enduser-cross-create.test.ts → enduser-cross-create.test.ts} +25 -25
- package/src/tests/api_tests/security/{F-0106-F-0110-enduser-write-restrictions.test.ts → enduser-write-restrictions.test.ts} +12 -14
- package/src/tests/api_tests/security/form-logic-js-execution.test.ts +183 -0
- package/src/tests/api_tests/security/{F-0145-globalunique-leak.test.ts → globalunique-conflict-redaction.test.ts} +5 -6
- package/src/tests/api_tests/security/{F-0008-handle-incoming-communication-cross-tenant.test.ts → handle-incoming-communication-cross-tenant.test.ts} +8 -8
- package/src/tests/api_tests/security/{F-0007-invite-user-enumeration.test.ts → invite-user-enumeration.test.ts} +8 -8
- package/src/tests/api_tests/security/{F-0151-load-inbox-redaction.test.ts → load-inbox-redaction.test.ts} +5 -6
- package/src/tests/api_tests/security/{F-0016-prototype-pollution.test.ts → prototype-pollution.test.ts} +4 -4
- package/src/tests/api_tests/security/{F-0025-proxy-image-unauth-ssrf.test.ts → proxy-image-unauth-ssrf.test.ts} +11 -12
- package/src/tests/api_tests/security/{F-0013-sanitize-user-html-with-iframes.test.ts → sanitize-user-html-with-iframes.test.ts} +5 -5
- package/src/tests/api_tests/security/{F-0013-sanitize-user-html.test.ts → sanitize-user-html.test.ts} +4 -4
- package/src/tests/api_tests/security/schema-adminonly-enforcement.test.ts +287 -0
- package/src/tests/api_tests/security/{F-0076-self-admin-role-assignment.test.ts → self-admin-role-assignment.test.ts} +13 -13
- package/src/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.ts +162 -0
- package/src/tests/api_tests/security/{F-0015-webhook-outbound-ssrf.test.ts → webhook-outbound-ssrf.test.ts} +13 -14
- package/src/tests/api_tests/security/{F-0155-webhook-timeout.test.ts → webhook-timeout.test.ts} +6 -7
- package/src/tests/api_tests/tickets_bulk_assign_from_queue.test.ts +279 -0
- package/src/tests/api_tests/webhook_error_handling.test.ts +1 -1
- package/src/tests/setup_isolated.ts +170 -0
- package/src/tests/tests.ts +60 -18
- package/src/tests/unit_tests/do_not_send_address.test.ts +60 -0
- package/src/tests/unit_tests/openapi_spec_freshness.test.ts +88 -0
- package/test_generated.pdf +0 -0
- package/src/tests/api_tests/security/readonly-enduser-preview.test.ts +0 -301
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
12
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
require('source-map-support').install();
|
|
38
|
+
import { Session } from "../../../sdk";
|
|
39
|
+
import { async_test, log_header, } from "@tellescope/testing";
|
|
40
|
+
import { setup_tests } from "../../setup";
|
|
41
|
+
var host = process.env.API_URL || 'http://localhost:8080';
|
|
42
|
+
var ENDUSER_PASSWORD = 'F0151TestPassword!123';
|
|
43
|
+
/**
|
|
44
|
+
* Regression test: `load_inbox_data` must apply enduser field redactions.
|
|
45
|
+
*
|
|
46
|
+
* load_inbox_data serialized $lookup'ed endusers via convert_id_name only (NOT applyRedactions),
|
|
47
|
+
* so endusers.hashedPassword (redactions:['all']) leaked to staff sessions — while the sibling
|
|
48
|
+
* phone_calls in the same response correctly went through applyRedactions.
|
|
49
|
+
*
|
|
50
|
+
* Repro: create an enduser, set their portal password (→ hashedPassword), seed an inbound
|
|
51
|
+
* (logOnly) email so the enduser appears in the inbox join, then load_inbox_data as staff and
|
|
52
|
+
* assert the returned enduser entry has NO hashedPassword.
|
|
53
|
+
*/
|
|
54
|
+
export var load_inbox_redaction_tests = function (_a) {
|
|
55
|
+
var sdk = _a.sdk;
|
|
56
|
+
return __awaiter(void 0, void 0, void 0, function () {
|
|
57
|
+
var enduserId, emailId, email, enduser_1, seeded, _b, _c;
|
|
58
|
+
return __generator(this, function (_d) {
|
|
59
|
+
switch (_d.label) {
|
|
60
|
+
case 0:
|
|
61
|
+
log_header("load_inbox_data enduser redaction");
|
|
62
|
+
_d.label = 1;
|
|
63
|
+
case 1:
|
|
64
|
+
_d.trys.push([1, , 6, 15]);
|
|
65
|
+
email = "f0151-enduser-".concat(Date.now(), "@example.com");
|
|
66
|
+
return [4 /*yield*/, sdk.api.endusers.createOne({ email: email, fname: 'F0151', lname: 'Inbox' })];
|
|
67
|
+
case 2:
|
|
68
|
+
enduser_1 = _d.sent();
|
|
69
|
+
enduserId = enduser_1.id;
|
|
70
|
+
return [4 /*yield*/, sdk.api.endusers.set_password({ id: enduser_1.id, password: ENDUSER_PASSWORD })
|
|
71
|
+
// Seed an inbound logOnly email so the enduser is joined into the inbox payload
|
|
72
|
+
];
|
|
73
|
+
case 3:
|
|
74
|
+
_d.sent();
|
|
75
|
+
return [4 /*yield*/, sdk.api.emails.createOne({
|
|
76
|
+
enduserId: enduser_1.id, subject: 'F0151 seed', textContent: 'seed',
|
|
77
|
+
logOnly: true, inbound: true,
|
|
78
|
+
})];
|
|
79
|
+
case 4:
|
|
80
|
+
seeded = _d.sent();
|
|
81
|
+
emailId = seeded.id;
|
|
82
|
+
return [4 /*yield*/, async_test('load_inbox_data does not leak enduser.hashedPassword to staff', function () { return sdk.api.endusers.load_inbox_data({ enduserIds: [enduser_1.id] }); }, {
|
|
83
|
+
onResult: function (r) {
|
|
84
|
+
var _a;
|
|
85
|
+
var returned = ((_a = r === null || r === void 0 ? void 0 : r.endusers) !== null && _a !== void 0 ? _a : []).find(function (e) { var _a; return ((_a = (e.id || e._id)) === null || _a === void 0 ? void 0 : _a.toString()) === enduserId; });
|
|
86
|
+
// require that the enduser actually came back (so the assertion is meaningful),
|
|
87
|
+
// and that hashedPassword is absent
|
|
88
|
+
return !!returned && !('hashedPassword' in returned);
|
|
89
|
+
},
|
|
90
|
+
})];
|
|
91
|
+
case 5:
|
|
92
|
+
_d.sent();
|
|
93
|
+
return [3 /*break*/, 15];
|
|
94
|
+
case 6:
|
|
95
|
+
if (!emailId) return [3 /*break*/, 10];
|
|
96
|
+
_d.label = 7;
|
|
97
|
+
case 7:
|
|
98
|
+
_d.trys.push([7, 9, , 10]);
|
|
99
|
+
return [4 /*yield*/, sdk.api.emails.deleteOne(emailId)];
|
|
100
|
+
case 8:
|
|
101
|
+
_d.sent();
|
|
102
|
+
return [3 /*break*/, 10];
|
|
103
|
+
case 9:
|
|
104
|
+
_b = _d.sent();
|
|
105
|
+
return [3 /*break*/, 10];
|
|
106
|
+
case 10:
|
|
107
|
+
if (!enduserId) return [3 /*break*/, 14];
|
|
108
|
+
_d.label = 11;
|
|
109
|
+
case 11:
|
|
110
|
+
_d.trys.push([11, 13, , 14]);
|
|
111
|
+
return [4 /*yield*/, sdk.api.endusers.deleteOne(enduserId)];
|
|
112
|
+
case 12:
|
|
113
|
+
_d.sent();
|
|
114
|
+
return [3 /*break*/, 14];
|
|
115
|
+
case 13:
|
|
116
|
+
_c = _d.sent();
|
|
117
|
+
return [3 /*break*/, 14];
|
|
118
|
+
case 14: return [7 /*endfinally*/];
|
|
119
|
+
case 15: return [2 /*return*/];
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
if (require.main === module) {
|
|
125
|
+
console.log("\uD83C\uDF10 Using API URL: ".concat(host));
|
|
126
|
+
var sdk_1 = new Session({ host: host });
|
|
127
|
+
var sdkNonAdmin_1 = new Session({ host: host });
|
|
128
|
+
var runTests = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
129
|
+
return __generator(this, function (_a) {
|
|
130
|
+
switch (_a.label) {
|
|
131
|
+
case 0: return [4 /*yield*/, setup_tests(sdk_1, sdkNonAdmin_1)];
|
|
132
|
+
case 1:
|
|
133
|
+
_a.sent();
|
|
134
|
+
return [4 /*yield*/, load_inbox_redaction_tests({ sdk: sdk_1, sdkNonAdmin: sdkNonAdmin_1 })];
|
|
135
|
+
case 2:
|
|
136
|
+
_a.sent();
|
|
137
|
+
return [2 /*return*/];
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}); };
|
|
141
|
+
runTests()
|
|
142
|
+
.then(function () {
|
|
143
|
+
console.log("✅ load_inbox_data redaction test suite completed successfully");
|
|
144
|
+
process.exit(0);
|
|
145
|
+
})
|
|
146
|
+
.catch(function (error) {
|
|
147
|
+
console.error("❌ load_inbox_data redaction test suite failed:", error);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=load-inbox-redaction.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-inbox-redaction.test.js","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/load-inbox-redaction.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prototype-pollution.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/prototype-pollution.test.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,yBAAyB,qBAgCrC,CAAA"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
12
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import { add_value_for_dotted_key } from "@tellescope/utilities";
|
|
38
|
+
// Regression test: prototype pollution via dotted-key assignment.
|
|
39
|
+
// add_value_for_dotted_key must NOT write through __proto__/constructor/prototype path segments
|
|
40
|
+
// (which would pollute Object.prototype process-wide), while still performing legitimate dotted assignment.
|
|
41
|
+
//
|
|
42
|
+
// Pure-function test — no Session needed. Runs in the main suite and standalone:
|
|
43
|
+
// ./build_cjs.sh && cd packages/public/sdk && node -r dotenv/config lib/cjs/tests/api_tests/security/prototype-pollution.test.js
|
|
44
|
+
var fail = function (msg) { throw new Error(msg); };
|
|
45
|
+
export var prototype_pollution_tests = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
46
|
+
var leakedA, leakedB, leakedC, obj, flat;
|
|
47
|
+
return __generator(this, function (_a) {
|
|
48
|
+
console.log("Running prototype-pollution regression tests");
|
|
49
|
+
// 1. __proto__ path must not pollute Object.prototype
|
|
50
|
+
add_value_for_dotted_key({ insurance: {} }, 'insurance.__proto__.__pp_a__', 'polluted');
|
|
51
|
+
leakedA = {}.__pp_a__;
|
|
52
|
+
delete Object.prototype.__pp_a__; // clean up regardless, so a failure here can't contaminate the rest of the suite
|
|
53
|
+
if (leakedA !== undefined)
|
|
54
|
+
fail('Object.prototype polluted via __proto__ path');
|
|
55
|
+
// 2. constructor.prototype path must not pollute
|
|
56
|
+
add_value_for_dotted_key({ insurance: {} }, 'insurance.constructor.prototype.__pp_b__', 'polluted');
|
|
57
|
+
leakedB = {}.__pp_b__;
|
|
58
|
+
delete Object.prototype.__pp_b__;
|
|
59
|
+
if (leakedB !== undefined)
|
|
60
|
+
fail('Object.prototype polluted via constructor.prototype path');
|
|
61
|
+
// 3. a leading __proto__ segment must not pollute either
|
|
62
|
+
add_value_for_dotted_key({}, '__proto__.__pp_c__', 'polluted');
|
|
63
|
+
leakedC = {}.__pp_c__;
|
|
64
|
+
delete Object.prototype.__pp_c__;
|
|
65
|
+
if (leakedC !== undefined)
|
|
66
|
+
fail('Object.prototype polluted via leading __proto__ segment');
|
|
67
|
+
obj = { a: { b: {} } };
|
|
68
|
+
add_value_for_dotted_key(obj, 'a.b.c', 42);
|
|
69
|
+
if (obj.a.b.c !== 42)
|
|
70
|
+
fail('legitimate dotted assignment broke');
|
|
71
|
+
flat = {};
|
|
72
|
+
add_value_for_dotted_key(flat, 'name', 'ok');
|
|
73
|
+
if (flat.name !== 'ok')
|
|
74
|
+
fail('single-key assignment broke');
|
|
75
|
+
console.log("✅ prototype-pollution regression tests passed");
|
|
76
|
+
return [2 /*return*/];
|
|
77
|
+
});
|
|
78
|
+
}); };
|
|
79
|
+
if (require.main === module) {
|
|
80
|
+
prototype_pollution_tests()
|
|
81
|
+
.then(function () { console.log("✅ suite completed"); process.exit(0); })
|
|
82
|
+
.catch(function (err) { console.error("❌ suite failed:", err); process.exit(1); });
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=prototype-pollution.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prototype-pollution.test.js","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/prototype-pollution.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAEhE,kEAAkE;AAClE,gGAAgG;AAChG,4GAA4G;AAC5G,EAAE;AACF,iFAAiF;AACjF,mIAAmI;AAEnI,IAAM,IAAI,GAAG,UAAC,GAAW,IAAO,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAA,CAAC,CAAC,CAAA;AAEtD,MAAM,CAAC,IAAM,yBAAyB,GAAG;;;QACvC,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAA;QAE3D,sDAAsD;QACtD,wBAAwB,CAAC,EAAE,SAAS,EAAE,EAAE,EAAS,EAAE,8BAA8B,EAAE,UAAU,CAAC,CAAA;QACxF,OAAO,GAAI,EAAU,CAAC,QAAQ,CAAA;QACpC,OAAQ,MAAM,CAAC,SAAiB,CAAC,QAAQ,CAAA,CAAC,iFAAiF;QAC3H,IAAI,OAAO,KAAK,SAAS;YAAE,IAAI,CAAC,8CAA8C,CAAC,CAAA;QAE/E,iDAAiD;QACjD,wBAAwB,CAAC,EAAE,SAAS,EAAE,EAAE,EAAS,EAAE,0CAA0C,EAAE,UAAU,CAAC,CAAA;QACpG,OAAO,GAAI,EAAU,CAAC,QAAQ,CAAA;QACpC,OAAQ,MAAM,CAAC,SAAiB,CAAC,QAAQ,CAAA;QACzC,IAAI,OAAO,KAAK,SAAS;YAAE,IAAI,CAAC,0DAA0D,CAAC,CAAA;QAE3F,yDAAyD;QACzD,wBAAwB,CAAC,EAAS,EAAE,oBAAoB,EAAE,UAAU,CAAC,CAAA;QAC/D,OAAO,GAAI,EAAU,CAAC,QAAQ,CAAA;QACpC,OAAQ,MAAM,CAAC,SAAiB,CAAC,QAAQ,CAAA;QACzC,IAAI,OAAO,KAAK,SAAS;YAAE,IAAI,CAAC,yDAAyD,CAAC,CAAA;QAGpF,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAS,CAAA;QACnC,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QAC1C,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;YAAE,IAAI,CAAC,oCAAoC,CAAC,CAAA;QAG1D,IAAI,GAAG,EAAS,CAAA;QACtB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;QAC5C,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;YAAE,IAAI,CAAC,6BAA6B,CAAC,CAAA;QAE3D,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;;;KAC7D,CAAA;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE;IAC3B,yBAAyB,EAAE;SACxB,IAAI,CAAC,cAAQ,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA,CAAC,CAAC,CAAC;SACjE,KAAK,CAAC,UAAC,GAAG,IAAO,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;CAC9E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Session } from "../../../sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Regression tests: `/v1/proxy-image` must refuse internal and non-image destinations.
|
|
4
|
+
*
|
|
5
|
+
* GET /v1/proxy-image accepted an arbitrary ?url= and streamed the upstream response body straight
|
|
6
|
+
* back with Access-Control-Allow-Origin: *, with no authentication, no destination validation and no
|
|
7
|
+
* content-type restriction. That reaches http://169.254.169.254/ (EC2 instance credentials under
|
|
8
|
+
* IMDSv1), 127.0.0.1, and anything else inside the VPC.
|
|
9
|
+
*
|
|
10
|
+
* The endpoint's only legitimate job is to re-serve an image that ALREADY renders in the staff
|
|
11
|
+
* browser, with permissive CORS headers, so html2canvas can rasterize a form-response PDF without
|
|
12
|
+
* tainting the canvas (canvas.toDataURL() throws on a tainted canvas, and the form-response view sets
|
|
13
|
+
* crossOrigin="anonymous"). Anything reachable only from inside our network was therefore never a
|
|
14
|
+
* legitimate input — which is why refusing non-public destinations cannot regress the feature.
|
|
15
|
+
*
|
|
16
|
+
* Repro: stand up a local HTTP server that serves a JSON secret, point proxy-image at it with no
|
|
17
|
+
* credentials, and assert the secret does not come back.
|
|
18
|
+
* - red (unfixed): the sentinel body is streamed back to an unauthenticated caller
|
|
19
|
+
* - green (fixed): the request is refused and the sentinel server is never contacted
|
|
20
|
+
*
|
|
21
|
+
* Assertions are deliberately written as "4xx and nothing leaked" rather than pinning an exact status,
|
|
22
|
+
* because the fix both authenticates the endpoint and moves it to POST (the url moves into the body so
|
|
23
|
+
* presigned S3 URLs for patient attachments stop landing in access logs). Either 401 or 404/405 on the
|
|
24
|
+
* old GET shape is an acceptable outcome; streaming the body is not.
|
|
25
|
+
*
|
|
26
|
+
* The authenticated happy-path test lives with the Phase 2 endpoint change — it cannot exist here
|
|
27
|
+
* because the POST route does not yet exist, and a test that fails for "not implemented" would muddy
|
|
28
|
+
* the vulnerability proof.
|
|
29
|
+
*/
|
|
30
|
+
export declare const proxy_image_ssrf_tests: ({ sdk }: {
|
|
31
|
+
sdk: Session;
|
|
32
|
+
sdkNonAdmin: Session;
|
|
33
|
+
}) => Promise<void>;
|
|
34
|
+
//# sourceMappingURL=proxy-image-unauth-ssrf.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-image-unauth-ssrf.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/proxy-image-unauth-ssrf.test.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AA0BtC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,sBAAsB;SAA2B,OAAO;iBAAe,OAAO;mBAkG1F,CAAA"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
12
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
require('source-map-support').install();
|
|
38
|
+
import http from "http";
|
|
39
|
+
import axios from "axios";
|
|
40
|
+
import { Session } from "../../../sdk";
|
|
41
|
+
import { async_test, log_header, } from "@tellescope/testing";
|
|
42
|
+
import { setup_tests } from "../../setup";
|
|
43
|
+
var host = process.env.API_URL || 'http://localhost:8080';
|
|
44
|
+
var LOCAL_HOSTNAMES = ['localhost', '127.0.0.1', '::1'];
|
|
45
|
+
/**
|
|
46
|
+
* 127.0.0.1 only means "the machine running this test" when the API is also local. Against staging or
|
|
47
|
+
* prod it is the API server itself — the sentinel below would never be contacted, every assertion
|
|
48
|
+
* here would pass for the wrong reason, and we would be probing a live environment. Fail loudly.
|
|
49
|
+
*/
|
|
50
|
+
var assert_local_api = function () {
|
|
51
|
+
var hostname = new URL(host).hostname;
|
|
52
|
+
if (!LOCAL_HOSTNAMES.includes(hostname)) {
|
|
53
|
+
throw new Error("SSRF tests must run against a local API (got ".concat(host, "). ")
|
|
54
|
+
+ "127.0.0.1 would resolve to the API server rather than this machine, so the tests would be meaningless.");
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Regression tests: `/v1/proxy-image` must refuse internal and non-image destinations.
|
|
59
|
+
*
|
|
60
|
+
* GET /v1/proxy-image accepted an arbitrary ?url= and streamed the upstream response body straight
|
|
61
|
+
* back with Access-Control-Allow-Origin: *, with no authentication, no destination validation and no
|
|
62
|
+
* content-type restriction. That reaches http://169.254.169.254/ (EC2 instance credentials under
|
|
63
|
+
* IMDSv1), 127.0.0.1, and anything else inside the VPC.
|
|
64
|
+
*
|
|
65
|
+
* The endpoint's only legitimate job is to re-serve an image that ALREADY renders in the staff
|
|
66
|
+
* browser, with permissive CORS headers, so html2canvas can rasterize a form-response PDF without
|
|
67
|
+
* tainting the canvas (canvas.toDataURL() throws on a tainted canvas, and the form-response view sets
|
|
68
|
+
* crossOrigin="anonymous"). Anything reachable only from inside our network was therefore never a
|
|
69
|
+
* legitimate input — which is why refusing non-public destinations cannot regress the feature.
|
|
70
|
+
*
|
|
71
|
+
* Repro: stand up a local HTTP server that serves a JSON secret, point proxy-image at it with no
|
|
72
|
+
* credentials, and assert the secret does not come back.
|
|
73
|
+
* - red (unfixed): the sentinel body is streamed back to an unauthenticated caller
|
|
74
|
+
* - green (fixed): the request is refused and the sentinel server is never contacted
|
|
75
|
+
*
|
|
76
|
+
* Assertions are deliberately written as "4xx and nothing leaked" rather than pinning an exact status,
|
|
77
|
+
* because the fix both authenticates the endpoint and moves it to POST (the url moves into the body so
|
|
78
|
+
* presigned S3 URLs for patient attachments stop landing in access logs). Either 401 or 404/405 on the
|
|
79
|
+
* old GET shape is an acceptable outcome; streaming the body is not.
|
|
80
|
+
*
|
|
81
|
+
* The authenticated happy-path test lives with the Phase 2 endpoint change — it cannot exist here
|
|
82
|
+
* because the POST route does not yet exist, and a test that fails for "not implemented" would muddy
|
|
83
|
+
* the vulnerability proof.
|
|
84
|
+
*/
|
|
85
|
+
export var proxy_image_ssrf_tests = function (_a) {
|
|
86
|
+
var sdk = _a.sdk;
|
|
87
|
+
return __awaiter(void 0, void 0, void 0, function () {
|
|
88
|
+
var SENTINEL, sentinelHits, sentinel, sentinelPort, sentinelURL_1, call_unauthenticated, call_authenticated_1;
|
|
89
|
+
return __generator(this, function (_b) {
|
|
90
|
+
switch (_b.label) {
|
|
91
|
+
case 0:
|
|
92
|
+
log_header("proxy-image unauthenticated SSRF");
|
|
93
|
+
assert_local_api();
|
|
94
|
+
SENTINEL = "f0025-sentinel-".concat(Date.now(), "-").concat(Math.random().toString(36).slice(2));
|
|
95
|
+
sentinelHits = 0;
|
|
96
|
+
sentinel = http.createServer(function (_, res) {
|
|
97
|
+
sentinelHits++;
|
|
98
|
+
res.writeHead(200, { 'content-type': 'application/json' });
|
|
99
|
+
res.end(JSON.stringify({ sentinel: SENTINEL, credentials: 'internal-only' }));
|
|
100
|
+
});
|
|
101
|
+
_b.label = 1;
|
|
102
|
+
case 1:
|
|
103
|
+
_b.trys.push([1, , 9, 10]);
|
|
104
|
+
return [4 /*yield*/, new Promise(function (resolve) { return sentinel.listen(0, '127.0.0.1', function () { return resolve(); }); })];
|
|
105
|
+
case 2:
|
|
106
|
+
_b.sent();
|
|
107
|
+
sentinelPort = sentinel.address().port;
|
|
108
|
+
sentinelURL_1 = "http://127.0.0.1:".concat(sentinelPort, "/latest/meta-data/iam/security-credentials/");
|
|
109
|
+
call_unauthenticated = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
110
|
+
var res, body;
|
|
111
|
+
var _a;
|
|
112
|
+
return __generator(this, function (_b) {
|
|
113
|
+
switch (_b.label) {
|
|
114
|
+
case 0:
|
|
115
|
+
sentinelHits = 0;
|
|
116
|
+
return [4 /*yield*/, axios.get("".concat(host, "/v1/proxy-image"), {
|
|
117
|
+
params: { url: sentinelURL_1 },
|
|
118
|
+
validateStatus: function () { return true; },
|
|
119
|
+
responseType: 'text',
|
|
120
|
+
transformResponse: [function (d) { return d; }],
|
|
121
|
+
timeout: 10000,
|
|
122
|
+
})];
|
|
123
|
+
case 1:
|
|
124
|
+
res = _b.sent();
|
|
125
|
+
body = typeof res.data === 'string' ? res.data : JSON.stringify((_a = res.data) !== null && _a !== void 0 ? _a : '');
|
|
126
|
+
return [2 /*return*/, { status: res.status, leaked: body.includes(SENTINEL), sentinelHits: sentinelHits }];
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}); };
|
|
130
|
+
// T1 — the core SSRF: an unauthenticated caller must not be able to read an internal resource.
|
|
131
|
+
return [4 /*yield*/, async_test('proxy-image does not stream an internal non-image resource to an unauthenticated caller', call_unauthenticated, {
|
|
132
|
+
// Positive control: a numeric status proves we actually reached our API rather than failing to
|
|
133
|
+
// connect (a connection error would make "nothing leaked" true for the wrong reason).
|
|
134
|
+
onResult: function (r) { return (typeof r.status === 'number'
|
|
135
|
+
&& r.leaked === false
|
|
136
|
+
&& r.sentinelHits === 0); },
|
|
137
|
+
})
|
|
138
|
+
// T2 — the unauthenticated surface itself: the request must be refused outright, and the
|
|
139
|
+
// destination must never be contacted (no SSRF-as-a-side-effect even when the body is withheld).
|
|
140
|
+
];
|
|
141
|
+
case 3:
|
|
142
|
+
// T1 — the core SSRF: an unauthenticated caller must not be able to read an internal resource.
|
|
143
|
+
_b.sent();
|
|
144
|
+
// T2 — the unauthenticated surface itself: the request must be refused outright, and the
|
|
145
|
+
// destination must never be contacted (no SSRF-as-a-side-effect even when the body is withheld).
|
|
146
|
+
return [4 /*yield*/, async_test('proxy-image refuses an unauthenticated request without contacting the destination', call_unauthenticated, { onResult: function (r) { return r.status >= 400 && r.status < 500 && r.sentinelHits === 0; } })
|
|
147
|
+
// Authenticating is not enough on its own — a staff session must not be able to reach an internal
|
|
148
|
+
// address either. These use the real session, and are deterministic (no external network).
|
|
149
|
+
];
|
|
150
|
+
case 4:
|
|
151
|
+
// T2 — the unauthenticated surface itself: the request must be refused outright, and the
|
|
152
|
+
// destination must never be contacted (no SSRF-as-a-side-effect even when the body is withheld).
|
|
153
|
+
_b.sent();
|
|
154
|
+
call_authenticated_1 = function (url) { return __awaiter(void 0, void 0, void 0, function () {
|
|
155
|
+
var res;
|
|
156
|
+
return __generator(this, function (_a) {
|
|
157
|
+
switch (_a.label) {
|
|
158
|
+
case 0:
|
|
159
|
+
sentinelHits = 0;
|
|
160
|
+
return [4 /*yield*/, axios.post("".concat(host, "/v1/proxy-image"), { url: url }, {
|
|
161
|
+
headers: { Authorization: "Bearer ".concat(sdk.authToken) },
|
|
162
|
+
validateStatus: function () { return true; },
|
|
163
|
+
timeout: 10000,
|
|
164
|
+
})];
|
|
165
|
+
case 1:
|
|
166
|
+
res = _a.sent();
|
|
167
|
+
return [2 /*return*/, { status: res.status, sentinelHits: sentinelHits }];
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}); };
|
|
171
|
+
return [4 /*yield*/, async_test('proxy-image refuses a private destination even for an authenticated staff session', function () { return call_authenticated_1(sentinelURL_1); }, { onResult: function (r) { return r.status === 400 && r.sentinelHits === 0; } })];
|
|
172
|
+
case 5:
|
|
173
|
+
_b.sent();
|
|
174
|
+
return [4 /*yield*/, async_test('proxy-image refuses cloud metadata for an authenticated staff session', function () { return call_authenticated_1('https://169.254.169.254/latest/meta-data/'); }, { onResult: function (r) { return r.status === 400; } })
|
|
175
|
+
// Scheme and port are pinned: only https on 443, which is all the PDF export ever needs.
|
|
176
|
+
];
|
|
177
|
+
case 6:
|
|
178
|
+
_b.sent();
|
|
179
|
+
// Scheme and port are pinned: only https on 443, which is all the PDF export ever needs.
|
|
180
|
+
return [4 /*yield*/, async_test('proxy-image refuses a plain http destination', function () { return call_authenticated_1('http://example.com/logo.png'); }, { onResult: function (r) { return r.status === 400; } })];
|
|
181
|
+
case 7:
|
|
182
|
+
// Scheme and port are pinned: only https on 443, which is all the PDF export ever needs.
|
|
183
|
+
_b.sent();
|
|
184
|
+
return [4 /*yield*/, async_test('proxy-image refuses a non-443 port', function () { return call_authenticated_1('https://example.com:8443/logo.png'); }, { onResult: function (r) { return r.status === 400; } })];
|
|
185
|
+
case 8:
|
|
186
|
+
_b.sent();
|
|
187
|
+
return [3 /*break*/, 10];
|
|
188
|
+
case 9:
|
|
189
|
+
sentinel.close();
|
|
190
|
+
return [7 /*endfinally*/];
|
|
191
|
+
case 10: return [2 /*return*/];
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
if (require.main === module) {
|
|
197
|
+
console.log("\uD83C\uDF10 Using API URL: ".concat(host));
|
|
198
|
+
var sdk_1 = new Session({ host: host });
|
|
199
|
+
var sdkNonAdmin_1 = new Session({ host: host });
|
|
200
|
+
var runTests = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
201
|
+
return __generator(this, function (_a) {
|
|
202
|
+
switch (_a.label) {
|
|
203
|
+
case 0: return [4 /*yield*/, setup_tests(sdk_1, sdkNonAdmin_1)];
|
|
204
|
+
case 1:
|
|
205
|
+
_a.sent();
|
|
206
|
+
return [4 /*yield*/, proxy_image_ssrf_tests({ sdk: sdk_1, sdkNonAdmin: sdkNonAdmin_1 })];
|
|
207
|
+
case 2:
|
|
208
|
+
_a.sent();
|
|
209
|
+
return [2 /*return*/];
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}); };
|
|
213
|
+
runTests()
|
|
214
|
+
.then(function () {
|
|
215
|
+
console.log("✅ proxy-image SSRF test suite completed successfully");
|
|
216
|
+
process.exit(0);
|
|
217
|
+
})
|
|
218
|
+
.catch(function (error) {
|
|
219
|
+
console.error("❌ proxy-image SSRF test suite failed:", error);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=proxy-image-unauth-ssrf.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-image-unauth-ssrf.test.js","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/proxy-image-unauth-ssrf.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-user-html-with-iframes.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/sanitize-user-html-with-iframes.test.ts"],"names":[],"mappings":"AA+CA,eAAO,MAAM,qCAAqC,qBAiKjD,CAAA"}
|