@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,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
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;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.sanitize_user_html_with_iframes_tests = void 0;
|
|
40
|
+
var utilities_1 = require("@tellescope/utilities");
|
|
41
|
+
// Companion to sanitize-user-html.test.ts (pattern 06 — XSS via dangerouslySetInnerHTML).
|
|
42
|
+
//
|
|
43
|
+
// sanitize_user_html_with_iframes is the variant used by the live form's field description, so
|
|
44
|
+
// admins can embed video / scheduling widgets. It permits <iframe> and NOTHING else beyond what
|
|
45
|
+
// sanitize_user_html allows. This asserts:
|
|
46
|
+
// 1. permitting iframe did not reopen any of the base vectors (the full payload list is re-run)
|
|
47
|
+
// 2. only absolute https iframes survive — relative, protocol-relative, http, javascript:, data:
|
|
48
|
+
// and srcdoc frames are dropped, along with their fallback content
|
|
49
|
+
// 3. the restrictive sandbox is forced, but an author-supplied sandbox is honored
|
|
50
|
+
// 4. sanitize_user_html itself still strips iframes (the boundary between the two functions)
|
|
51
|
+
//
|
|
52
|
+
// Pure-function test — no Session needed. Runs as part of the main suite and standalone:
|
|
53
|
+
// ./build_cjs.sh && cd packages/public/sdk && node -r dotenv/config lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js
|
|
54
|
+
var fail = function (msg) { throw new Error(msg); };
|
|
55
|
+
// Same as has_no_executable_vector in the base sanitizer test, minus the '<iframe' clause (iframes are
|
|
56
|
+
// expected in this function's output). Everything else must still be neutralized.
|
|
57
|
+
var has_no_executable_vector_allowing_iframe = function (out) {
|
|
58
|
+
var o = out.toLowerCase();
|
|
59
|
+
var withoutValues = o.replace(/"[^"]*"/g, '""').replace(/'[^']*'/g, "''");
|
|
60
|
+
return !/\son[a-z]+\s*=/.test(withoutValues) // no live on*= event-handler attribute
|
|
61
|
+
&& !o.includes('javascript:')
|
|
62
|
+
&& !o.includes('vbscript:')
|
|
63
|
+
&& !o.includes('<script')
|
|
64
|
+
&& !o.includes('<svg')
|
|
65
|
+
&& !o.includes('<math')
|
|
66
|
+
&& !o.includes('<object')
|
|
67
|
+
&& !o.includes('<embed')
|
|
68
|
+
&& !o.includes('<form')
|
|
69
|
+
&& !o.includes('<noscript')
|
|
70
|
+
&& !o.includes('<template')
|
|
71
|
+
&& !o.includes('srcdoc'); // an inline document is arbitrary markup
|
|
72
|
+
};
|
|
73
|
+
// Tokens that must NEVER appear in the forced default. allow-top-navigation is the important one:
|
|
74
|
+
// it is what stops a hostile embed from redirecting the patient's form page to a phishing site.
|
|
75
|
+
var FORBIDDEN_SANDBOX_TOKENS = [
|
|
76
|
+
'allow-top-navigation',
|
|
77
|
+
'allow-downloads',
|
|
78
|
+
'allow-modals',
|
|
79
|
+
'allow-pointer-lock',
|
|
80
|
+
'allow-orientation-lock',
|
|
81
|
+
];
|
|
82
|
+
var sanitize_user_html_with_iframes_tests = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
83
|
+
var xssPayloads, _i, xssPayloads_1, _a, name_1, payload, out, badSrcs, _b, badSrcs_1, _c, name_2, src, out, fallback, srcdoc, handlers, yt, _d, FORBIDDEN_SANDBOX_TOKENS_1, token, authorSandbox, emptySandbox, noref, allowAttr, heading, table, list, link, img, dataimg, fmt, shared, adminTemplate, templated, endToEnd;
|
|
84
|
+
return __generator(this, function (_e) {
|
|
85
|
+
console.log("Running sanitize_user_html_with_iframes XSS regression tests");
|
|
86
|
+
xssPayloads = [
|
|
87
|
+
['img onerror', "<img src=x onerror=\"alert(document.domain)\">"],
|
|
88
|
+
['svg onload', "<svg onload=\"alert(1)\"></svg>"],
|
|
89
|
+
['svg animate onbegin', "<svg><animate onbegin=\"alert(1)\" attributeName=\"x\" dur=\"1s\"></svg>"],
|
|
90
|
+
['details ontoggle', "<details open ontoggle=\"alert(1)\"></details>"],
|
|
91
|
+
['input onfocus autofocus', "<input autofocus onfocus=\"alert(1)\">"],
|
|
92
|
+
['body onpageshow', "<body onpageshow=\"alert(1)\">"],
|
|
93
|
+
['a javascript scheme', "<a href=\"javascript:alert(1)\">x</a>"],
|
|
94
|
+
['a javascript entity-encoded', "<a href=\"jav	ascript:alert(1)\">x</a>"],
|
|
95
|
+
['script tag', "<script>alert(1)</script>"],
|
|
96
|
+
['onerror newline before =', "<img src=x onerror\n=\"alert(1)\">"],
|
|
97
|
+
['onerror mixed case', "<IMG SRC=x OnErRoR=\"alert(1)\">"],
|
|
98
|
+
['marquee onstart', "<marquee onstart=\"alert(1)\">x</marquee>"],
|
|
99
|
+
['mathml mglyph style mxss', "<math><mtext><table><mglyph><style><!--</style><img src=x onerror=alert(1)>"],
|
|
100
|
+
['svg foreignObject', "<svg><foreignObject><img src=x onerror=alert(1)></foreignObject></svg>"],
|
|
101
|
+
['noscript context confusion', "<noscript><p title=\"</noscript><img src=x onerror=alert(1)>\">"],
|
|
102
|
+
['template content', "<template><img src=x onerror=alert(1)></template>"],
|
|
103
|
+
['comment confusion', "<!--><img src=x onerror=alert(1)>-->"],
|
|
104
|
+
['cdata confusion', "<![CDATA[<img src=x onerror=alert(1)>]]>"],
|
|
105
|
+
['markup inside attr value', "<img src=\"x\" alt=\"<script>alert(1)</script>\">"],
|
|
106
|
+
['vbscript scheme', "<a href=\"vbscript:msgbox(1)\">x</a>"],
|
|
107
|
+
['data text/html href', "<a href=\"data:text/html,<script>alert(1)</script>\">x</a>"],
|
|
108
|
+
['javascript decimal entity', "<a href=\"Javascript:alert(1)\">x</a>"],
|
|
109
|
+
['javascript newline entity', "<a href=\"jav
ascript:alert(1)\">x</a>"],
|
|
110
|
+
];
|
|
111
|
+
for (_i = 0, xssPayloads_1 = xssPayloads; _i < xssPayloads_1.length; _i++) {
|
|
112
|
+
_a = xssPayloads_1[_i], name_1 = _a[0], payload = _a[1];
|
|
113
|
+
out = (0, utilities_1.sanitize_user_html_with_iframes)(payload);
|
|
114
|
+
if (!has_no_executable_vector_allowing_iframe(out))
|
|
115
|
+
fail("XSS not neutralized [".concat(name_1, "] -> ").concat(out));
|
|
116
|
+
}
|
|
117
|
+
badSrcs = [
|
|
118
|
+
['javascript scheme', "javascript:alert(1)"],
|
|
119
|
+
['data text/html', "data:text/html,<script>alert(1)</script>"],
|
|
120
|
+
['http (not https)', "http://evil.example"],
|
|
121
|
+
// sanitize-html does NOT reject protocol-relative iframe srcs on its own when
|
|
122
|
+
// allowProtocolRelative is set — this is the self-origin framing vector and the reason the
|
|
123
|
+
// sanitizer does its own absolute-https check.
|
|
124
|
+
['protocol-relative', "//app.tellescope.com/"],
|
|
125
|
+
['root-relative', "/portal/settings"],
|
|
126
|
+
['bare relative', "settings"],
|
|
127
|
+
['whitespace-obfuscated', " https:/\\/\\evil"],
|
|
128
|
+
['tab-entity javascript', "jav	ascript:alert(1)"],
|
|
129
|
+
['scheme-only', "https://"],
|
|
130
|
+
['empty', ""],
|
|
131
|
+
];
|
|
132
|
+
for (_b = 0, badSrcs_1 = badSrcs; _b < badSrcs_1.length; _b++) {
|
|
133
|
+
_c = badSrcs_1[_b], name_2 = _c[0], src = _c[1];
|
|
134
|
+
out = (0, utilities_1.sanitize_user_html_with_iframes)("<iframe src=\"".concat(src, "\"></iframe>"));
|
|
135
|
+
if (out.toLowerCase().includes('<iframe'))
|
|
136
|
+
fail("bad iframe src survived [".concat(name_2, "] -> ").concat(out));
|
|
137
|
+
}
|
|
138
|
+
fallback = (0, utilities_1.sanitize_user_html_with_iframes)("<iframe src=\"/x\">FALLBACK-TEXT</iframe>");
|
|
139
|
+
if (fallback.includes('FALLBACK-TEXT'))
|
|
140
|
+
fail("dropped iframe leaked its fallback text: ".concat(fallback));
|
|
141
|
+
if (fallback.toLowerCase().includes('<iframe'))
|
|
142
|
+
fail("dropped iframe survived: ".concat(fallback));
|
|
143
|
+
srcdoc = (0, utilities_1.sanitize_user_html_with_iframes)("<iframe src=\"https://ok.example\" srcdoc=\"<img src=x onerror=alert(1)>\"></iframe>");
|
|
144
|
+
if (srcdoc.toLowerCase().includes('srcdoc'))
|
|
145
|
+
fail("srcdoc not stripped: ".concat(srcdoc));
|
|
146
|
+
if (!srcdoc.toLowerCase().includes('<iframe'))
|
|
147
|
+
fail("valid iframe dropped alongside srcdoc: ".concat(srcdoc));
|
|
148
|
+
handlers = (0, utilities_1.sanitize_user_html_with_iframes)("<iframe src=\"https://ok.example\" onload=\"alert(1)\" id=\"x\" name=\"getElementById\"></iframe>");
|
|
149
|
+
if (!handlers.toLowerCase().includes('<iframe'))
|
|
150
|
+
fail("valid iframe dropped: ".concat(handlers));
|
|
151
|
+
if (/\son[a-z]+\s*=/.test(handlers.toLowerCase()))
|
|
152
|
+
fail("iframe event handler survived: ".concat(handlers));
|
|
153
|
+
if (/\b(id|name)\s*=/.test(handlers))
|
|
154
|
+
fail("iframe id/name not stripped (DOM clobbering): ".concat(handlers));
|
|
155
|
+
yt = (0, utilities_1.sanitize_user_html_with_iframes)("<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/abc\" frameBorder=\"0\"></iframe>");
|
|
156
|
+
if (!yt.includes('src="https://www.youtube.com/embed/abc"'))
|
|
157
|
+
fail("youtube embed src stripped: ".concat(yt));
|
|
158
|
+
if (!(yt.includes('width="560"') && yt.includes('height="315"')))
|
|
159
|
+
fail("iframe dimensions stripped: ".concat(yt));
|
|
160
|
+
if (!yt.toLowerCase().includes('frameborder'))
|
|
161
|
+
fail("frameborder stripped: ".concat(yt));
|
|
162
|
+
// forced containment
|
|
163
|
+
if (!yt.includes("sandbox=\"".concat(utilities_1.DEFAULT_IFRAME_SANDBOX, "\"")))
|
|
164
|
+
fail("sandbox not forced: ".concat(yt));
|
|
165
|
+
if (!yt.toLowerCase().includes('referrerpolicy='))
|
|
166
|
+
fail("referrerpolicy not set: ".concat(yt));
|
|
167
|
+
for (_d = 0, FORBIDDEN_SANDBOX_TOKENS_1 = FORBIDDEN_SANDBOX_TOKENS; _d < FORBIDDEN_SANDBOX_TOKENS_1.length; _d++) {
|
|
168
|
+
token = FORBIDDEN_SANDBOX_TOKENS_1[_d];
|
|
169
|
+
if (utilities_1.DEFAULT_IFRAME_SANDBOX.includes(token))
|
|
170
|
+
fail("forced sandbox must not grant ".concat(token, ": ").concat(utilities_1.DEFAULT_IFRAME_SANDBOX));
|
|
171
|
+
}
|
|
172
|
+
// allow-same-origin IS granted — required for real embeds (a Loom embed renders blank without it)
|
|
173
|
+
// and harmless because the src is guaranteed cross-origin by the check asserted above.
|
|
174
|
+
if (!utilities_1.DEFAULT_IFRAME_SANDBOX.includes('allow-same-origin'))
|
|
175
|
+
fail("forced sandbox must grant allow-same-origin so real embeds render: ".concat(utilities_1.DEFAULT_IFRAME_SANDBOX));
|
|
176
|
+
authorSandbox = (0, utilities_1.sanitize_user_html_with_iframes)("<iframe src=\"https://ok.example\" sandbox=\"allow-scripts\"></iframe>");
|
|
177
|
+
if (!authorSandbox.includes('sandbox="allow-scripts"'))
|
|
178
|
+
fail("author sandbox not honored: ".concat(authorSandbox));
|
|
179
|
+
emptySandbox = (0, utilities_1.sanitize_user_html_with_iframes)("<iframe src=\"https://ok.example\" sandbox=\"\"></iframe>");
|
|
180
|
+
if (emptySandbox.includes('allow-'))
|
|
181
|
+
fail("empty sandbox was replaced with the permissive default: ".concat(emptySandbox));
|
|
182
|
+
if (!/\ssandbox(\s|>)/.test(emptySandbox))
|
|
183
|
+
fail("empty sandbox attribute lost entirely: ".concat(emptySandbox));
|
|
184
|
+
noref = (0, utilities_1.sanitize_user_html_with_iframes)("<iframe src=\"https://ok.example\" referrerpolicy=\"no-referrer\"></iframe>");
|
|
185
|
+
if (!noref.includes('referrerpolicy="no-referrer"'))
|
|
186
|
+
fail("author referrerpolicy not honored: ".concat(noref));
|
|
187
|
+
allowAttr = (0, utilities_1.sanitize_user_html_with_iframes)("<iframe src=\"https://ok.example\" allow=\"autoplay; encrypted-media\" allowfullscreen></iframe>");
|
|
188
|
+
if (!allowAttr.includes('allow="autoplay; encrypted-media"'))
|
|
189
|
+
fail("allow attribute stripped: ".concat(allowAttr));
|
|
190
|
+
heading = (0, utilities_1.sanitize_user_html_with_iframes)("<h1>Welcome</h1><h3 style=\"color:#333\">Sub</h3>");
|
|
191
|
+
if (!(heading.includes('<h1>') && heading.includes('<h3') && heading.toLowerCase().includes('color')))
|
|
192
|
+
fail("headings/style stripped: ".concat(heading));
|
|
193
|
+
table = (0, utilities_1.sanitize_user_html_with_iframes)("<table><thead><tr><th>H</th></tr></thead><tbody><tr><td style=\"padding:4px\" colspan=\"2\">cell</td></tr></tbody></table>");
|
|
194
|
+
if (!(table.includes('<table') && table.includes('<td') && table.includes('colspan')))
|
|
195
|
+
fail("table stripped: ".concat(table));
|
|
196
|
+
list = (0, utilities_1.sanitize_user_html_with_iframes)("<ul><li>a</li></ul><ol start=\"3\"><li>c</li></ol>");
|
|
197
|
+
if (!(list.includes('<ul') && list.includes('<li') && list.includes('<ol')))
|
|
198
|
+
fail("list stripped: ".concat(list));
|
|
199
|
+
link = (0, utilities_1.sanitize_user_html_with_iframes)("<a href=\"https://example.com\">link</a>");
|
|
200
|
+
if (!link.includes('href="https://example.com"'))
|
|
201
|
+
fail("safe link stripped: ".concat(link));
|
|
202
|
+
if (!link.toLowerCase().includes('noopener'))
|
|
203
|
+
fail("external link not hardened: ".concat(link));
|
|
204
|
+
img = (0, utilities_1.sanitize_user_html_with_iframes)("<img src=\"https://cdn.example.com/a.png\" alt=\"pic\" width=\"200\">");
|
|
205
|
+
if (!(img.includes('src="https://cdn.example.com/a.png"') && img.includes('alt="pic"')))
|
|
206
|
+
fail("image stripped: ".concat(img));
|
|
207
|
+
dataimg = (0, utilities_1.sanitize_user_html_with_iframes)("<img src=\"data:image/png;base64,iVBORw0KGgo=\">");
|
|
208
|
+
if (!dataimg.includes('data:image/png'))
|
|
209
|
+
fail("data: image stripped: ".concat(dataimg));
|
|
210
|
+
fmt = (0, utilities_1.sanitize_user_html_with_iframes)("<p><strong>b</strong> <em>i</em> <span style=\"font-size:14px\">s</span></p><blockquote>q</blockquote>");
|
|
211
|
+
if (!(fmt.includes('<strong>') && fmt.includes('<span') && fmt.toLowerCase().includes('font-size')))
|
|
212
|
+
fail("formatting stripped: ".concat(fmt));
|
|
213
|
+
shared = (0, utilities_1.sanitize_user_html)("<iframe src=\"https://www.youtube.com/embed/abc\"></iframe>");
|
|
214
|
+
if (shared.toLowerCase().includes('<iframe'))
|
|
215
|
+
fail("sanitize_user_html must still strip iframes: ".concat(shared));
|
|
216
|
+
adminTemplate = "<p>Hi {{enduser.fname}}, watch this:</p><iframe src=\"https://www.youtube.com/embed/abc\"></iframe>";
|
|
217
|
+
templated = (0, utilities_1.replace_form_field_template_values)(adminTemplate, {
|
|
218
|
+
enduser: { fname: "<iframe src=\"https://evil.example/phish\"></iframe>" },
|
|
219
|
+
responses: [],
|
|
220
|
+
escapeNewlinesAsHTMLBreaks: true,
|
|
221
|
+
escapeHTMLValues: true,
|
|
222
|
+
});
|
|
223
|
+
endToEnd = (0, utilities_1.sanitize_user_html_with_iframes)(templated);
|
|
224
|
+
if (!endToEnd.includes('src="https://www.youtube.com/embed/abc"'))
|
|
225
|
+
fail("admin's own iframe did not survive: ".concat(endToEnd));
|
|
226
|
+
// The patient's markup must survive only as inert escaped text — so 'evil.example' may still
|
|
227
|
+
// appear as visible characters, but there must be exactly one LIVE frame (the admin's).
|
|
228
|
+
if (!endToEnd.includes('<iframe'))
|
|
229
|
+
fail("patient markup not escaped to inert text: ".concat(endToEnd));
|
|
230
|
+
if ((endToEnd.toLowerCase().match(/<iframe/g) || []).length !== 1)
|
|
231
|
+
fail("patient-injected iframe became a live frame: ".concat(endToEnd));
|
|
232
|
+
console.log("✅ sanitize_user_html_with_iframes XSS regression tests passed");
|
|
233
|
+
return [2 /*return*/];
|
|
234
|
+
});
|
|
235
|
+
}); };
|
|
236
|
+
exports.sanitize_user_html_with_iframes_tests = sanitize_user_html_with_iframes_tests;
|
|
237
|
+
if (require.main === module) {
|
|
238
|
+
(0, exports.sanitize_user_html_with_iframes_tests)()
|
|
239
|
+
.then(function () { console.log("✅ suite completed"); process.exit(0); })
|
|
240
|
+
.catch(function (err) { console.error("❌ suite failed:", err); process.exit(1); });
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=sanitize-user-html-with-iframes.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-user-html-with-iframes.test.js","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/sanitize-user-html-with-iframes.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-user-html.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/sanitize-user-html.test.ts"],"names":[],"mappings":"AAgCA,eAAO,MAAM,4BAA4B,qBAsExC,CAAA"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
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;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.sanitize_user_html_xss_tests = void 0;
|
|
40
|
+
var utilities_1 = require("@tellescope/utilities");
|
|
41
|
+
// Regression test: XSS via dangerouslySetInnerHTML.
|
|
42
|
+
// sanitize_user_html is the canonical render-time sanitizer that replaced remove_script_tags
|
|
43
|
+
// at every dangerouslySetInnerHTML sink. This asserts it neutralizes XSS vectors (incl. encoded /
|
|
44
|
+
// whitespace / mixed-case / iframe-srcdoc bypass variants) while preserving legitimate
|
|
45
|
+
// customization HTML (tables, headings, lists, links, images, inline styles).
|
|
46
|
+
//
|
|
47
|
+
// Pure-function test — no Session needed. Runs as part of the main suite and standalone:
|
|
48
|
+
// ./build_cjs.sh && cd packages/public/sdk && node -r dotenv/config lib/cjs/tests/api_tests/security/sanitize-user-html.test.js
|
|
49
|
+
var fail = function (msg) { throw new Error(msg); };
|
|
50
|
+
var has_no_executable_vector = function (out) {
|
|
51
|
+
var o = out.toLowerCase();
|
|
52
|
+
// A handler smuggled into an attribute VALUE (e.g. title="<img onerror=...>") is inert
|
|
53
|
+
// text — strip quoted values before checking for *live* on*= attributes to avoid false positives.
|
|
54
|
+
var withoutValues = o.replace(/"[^"]*"/g, '""').replace(/'[^']*'/g, "''");
|
|
55
|
+
return !/\son[a-z]+\s*=/.test(withoutValues) // no live on*= event-handler attribute
|
|
56
|
+
&& !o.includes('javascript:') // dropped schemes never appear in safe output
|
|
57
|
+
&& !o.includes('vbscript:')
|
|
58
|
+
&& !o.includes('<script') // literal dangerous tags (encoded <script is fine)
|
|
59
|
+
&& !o.includes('<iframe')
|
|
60
|
+
&& !o.includes('<svg')
|
|
61
|
+
&& !o.includes('<math')
|
|
62
|
+
&& !o.includes('<object')
|
|
63
|
+
&& !o.includes('<embed')
|
|
64
|
+
&& !o.includes('<form')
|
|
65
|
+
&& !o.includes('<noscript')
|
|
66
|
+
&& !o.includes('<template');
|
|
67
|
+
};
|
|
68
|
+
var sanitize_user_html_xss_tests = function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
69
|
+
var xssPayloads, _i, xssPayloads_1, _a, name_1, payload, out, clobber, heading, table, list, link, img, dataimg, fmt, mixed;
|
|
70
|
+
return __generator(this, function (_b) {
|
|
71
|
+
console.log("Running sanitize_user_html XSS regression tests");
|
|
72
|
+
xssPayloads = [
|
|
73
|
+
['img onerror', "<img src=x onerror=\"alert(document.domain)\">"],
|
|
74
|
+
['svg onload', "<svg onload=\"alert(1)\"></svg>"],
|
|
75
|
+
['svg animate onbegin', "<svg><animate onbegin=\"alert(1)\" attributeName=\"x\" dur=\"1s\"></svg>"],
|
|
76
|
+
['details ontoggle', "<details open ontoggle=\"alert(1)\"></details>"],
|
|
77
|
+
['input onfocus autofocus', "<input autofocus onfocus=\"alert(1)\">"],
|
|
78
|
+
['body onpageshow', "<body onpageshow=\"alert(1)\">"],
|
|
79
|
+
['a javascript scheme', "<a href=\"javascript:alert(1)\">x</a>"],
|
|
80
|
+
['a javascript entity-encoded', "<a href=\"jav	ascript:alert(1)\">x</a>"],
|
|
81
|
+
['iframe javascript src', "<iframe src=\"javascript:alert(1)\"></iframe>"],
|
|
82
|
+
['iframe srcdoc nested', "<iframe srcdoc=\"<img src=x onerror=alert(1)>\"></iframe>"],
|
|
83
|
+
['script tag', "<script>alert(1)</script>"],
|
|
84
|
+
['onerror newline before =', "<img src=x onerror\n=\"alert(1)\">"],
|
|
85
|
+
['onerror mixed case', "<IMG SRC=x OnErRoR=\"alert(1)\">"],
|
|
86
|
+
['marquee onstart', "<marquee onstart=\"alert(1)\">x</marquee>"],
|
|
87
|
+
// mutation / namespace confusion — svg/math/noscript/template must be stripped
|
|
88
|
+
['mathml mglyph style mxss', "<math><mtext><table><mglyph><style><!--</style><img src=x onerror=alert(1)>"],
|
|
89
|
+
['svg foreignObject', "<svg><foreignObject><img src=x onerror=alert(1)></foreignObject></svg>"],
|
|
90
|
+
['noscript context confusion', "<noscript><p title=\"</noscript><img src=x onerror=alert(1)>\">"],
|
|
91
|
+
['template content', "<template><img src=x onerror=alert(1)></template>"],
|
|
92
|
+
// comment / CDATA confusion
|
|
93
|
+
['comment confusion', "<!--><img src=x onerror=alert(1)>-->"],
|
|
94
|
+
['cdata confusion', "<![CDATA[<img src=x onerror=alert(1)>]]>"],
|
|
95
|
+
// markup smuggled inside an attribute value must stay inert
|
|
96
|
+
['markup inside attr value', "<img src=\"x\" alt=\"<script>alert(1)</script>\">"],
|
|
97
|
+
// protocol obfuscation
|
|
98
|
+
['vbscript scheme', "<a href=\"vbscript:msgbox(1)\">x</a>"],
|
|
99
|
+
['data text/html href', "<a href=\"data:text/html,<script>alert(1)</script>\">x</a>"],
|
|
100
|
+
['javascript decimal entity', "<a href=\"Javascript:alert(1)\">x</a>"],
|
|
101
|
+
['javascript newline entity', "<a href=\"jav
ascript:alert(1)\">x</a>"],
|
|
102
|
+
];
|
|
103
|
+
for (_i = 0, xssPayloads_1 = xssPayloads; _i < xssPayloads_1.length; _i++) {
|
|
104
|
+
_a = xssPayloads_1[_i], name_1 = _a[0], payload = _a[1];
|
|
105
|
+
out = (0, utilities_1.sanitize_user_html)(payload);
|
|
106
|
+
if (!has_no_executable_vector(out))
|
|
107
|
+
fail("XSS not neutralized [".concat(name_1, "] -> ").concat(out));
|
|
108
|
+
}
|
|
109
|
+
clobber = (0, utilities_1.sanitize_user_html)("<a id=\"x\" name=\"getElementById\">link</a><img name=\"y\">");
|
|
110
|
+
if (/\b(id|name)\s*=/.test(clobber))
|
|
111
|
+
fail("id/name not stripped (DOM clobbering): ".concat(clobber));
|
|
112
|
+
heading = (0, utilities_1.sanitize_user_html)("<h1>Welcome</h1><h3 style=\"color:#333\">Sub</h3>");
|
|
113
|
+
if (!(heading.includes('<h1>') && heading.includes('<h3') && heading.toLowerCase().includes('color')))
|
|
114
|
+
fail("headings/style stripped: ".concat(heading));
|
|
115
|
+
table = (0, utilities_1.sanitize_user_html)("<table><thead><tr><th>H</th></tr></thead><tbody><tr><td style=\"padding:4px\" colspan=\"2\">cell</td></tr></tbody></table>");
|
|
116
|
+
if (!(table.includes('<table') && table.includes('<td') && table.includes('colspan')))
|
|
117
|
+
fail("table stripped: ".concat(table));
|
|
118
|
+
list = (0, utilities_1.sanitize_user_html)("<ul><li>a</li></ul><ol start=\"3\"><li>c</li></ol>");
|
|
119
|
+
if (!(list.includes('<ul') && list.includes('<li') && list.includes('<ol')))
|
|
120
|
+
fail("list stripped: ".concat(list));
|
|
121
|
+
link = (0, utilities_1.sanitize_user_html)("<a href=\"https://example.com\">link</a>");
|
|
122
|
+
if (!link.includes('href="https://example.com"'))
|
|
123
|
+
fail("safe link stripped: ".concat(link));
|
|
124
|
+
if (!link.toLowerCase().includes('noopener'))
|
|
125
|
+
fail("external link not hardened: ".concat(link));
|
|
126
|
+
img = (0, utilities_1.sanitize_user_html)("<img src=\"https://cdn.example.com/a.png\" alt=\"pic\" width=\"200\">");
|
|
127
|
+
if (!(img.includes('src="https://cdn.example.com/a.png"') && img.includes('alt="pic"')))
|
|
128
|
+
fail("http image stripped: ".concat(img));
|
|
129
|
+
dataimg = (0, utilities_1.sanitize_user_html)("<img src=\"data:image/png;base64,iVBORw0KGgo=\">");
|
|
130
|
+
if (!dataimg.includes('data:image/png'))
|
|
131
|
+
fail("data: image stripped: ".concat(dataimg));
|
|
132
|
+
fmt = (0, utilities_1.sanitize_user_html)("<p><strong>b</strong> <em>i</em> <span style=\"font-size:14px\">s</span></p><blockquote>q</blockquote>");
|
|
133
|
+
if (!(fmt.includes('<strong>') && fmt.includes('<span') && fmt.toLowerCase().includes('font-size')))
|
|
134
|
+
fail("formatting stripped: ".concat(fmt));
|
|
135
|
+
mixed = (0, utilities_1.sanitize_user_html)("<p>Hello <b>name</b></p><img src=x onerror=\"steal()\">");
|
|
136
|
+
if (!(mixed.includes('<b>name</b>') && !/\son[a-z]+\s*=/.test(mixed.toLowerCase())))
|
|
137
|
+
fail("mixed content not handled: ".concat(mixed));
|
|
138
|
+
console.log("✅ sanitize_user_html XSS regression tests passed");
|
|
139
|
+
return [2 /*return*/];
|
|
140
|
+
});
|
|
141
|
+
}); };
|
|
142
|
+
exports.sanitize_user_html_xss_tests = sanitize_user_html_xss_tests;
|
|
143
|
+
if (require.main === module) {
|
|
144
|
+
(0, exports.sanitize_user_html_xss_tests)()
|
|
145
|
+
.then(function () { console.log("✅ suite completed"); process.exit(0); })
|
|
146
|
+
.catch(function (err) { console.error("❌ suite failed:", err); process.exit(1); });
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=sanitize-user-html.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-user-html.test.js","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/sanitize-user-html.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Session } from "../../../sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Regression test: `adminOnly` custom actions must be enforced at runtime, not merely declared.
|
|
4
|
+
*
|
|
5
|
+
* `adminOnly: true` on a CUSTOM action in schema.ts was documentation-only. The runtime gate
|
|
6
|
+
* (routing.ts:944) reads the flag off the options object built by getCustomEndpointFields, and
|
|
7
|
+
* api.ts:609 set `adminOnly: o.adminOnly` without ever consulting `action.adminOnly`. So every
|
|
8
|
+
* admin-only custom action had to declare the flag twice, and the copies desynced: 11 of 20
|
|
9
|
+
* declared custom actions were unenforced at runtime while both public doc artifacts
|
|
10
|
+
* (openapi.json and the unauthenticated GET /documentation feed, which read the SCHEMA flag)
|
|
11
|
+
* advertised "**Admin only.**".
|
|
12
|
+
*
|
|
13
|
+
* DEFAULT CRUD actions never had this bug — routing.ts:2434 etc. read
|
|
14
|
+
* model.defaultActions.<op>.adminOnly straight off the schema. The fix
|
|
15
|
+
* (`adminOnly: o.adminOnly ?? action.adminOnly`) makes custom actions behave the same way.
|
|
16
|
+
*
|
|
17
|
+
* Five of the 11 were de-flagged in the schema instead, because the flag itself was wrong and
|
|
18
|
+
* enforcing it would revert a deliberate decision: users.invite_user carries an explicit
|
|
19
|
+
* "no longer admin only, but controlled by users.create" and send_invitation_to_existing is its
|
|
20
|
+
* sibling; organizations.create_and_join is the self-service signup path and would 401 every new
|
|
21
|
+
* org (a fresh user has no roles — the handler is what grants Admin); sync_note_to_canvas is
|
|
22
|
+
* designed around `access: 'read'` for non-admin callers; background_errors.mark_read substitutes
|
|
23
|
+
* its own RBAC check that intentionally admits non-admins holding the verb.
|
|
24
|
+
*
|
|
25
|
+
* SAFETY: every probe fails EARLY inside its handler — after the adminOnly gate but before any
|
|
26
|
+
* vendor call. Pre-fix these requests really do reach the handler, and these handlers talk to
|
|
27
|
+
* Twilio, Athena and Canvas:
|
|
28
|
+
* - trigger_events : no `action` key + an absent triggerId => the loop `continue`s (inert)
|
|
29
|
+
* - athena-subscription: frequency 1 trips the `frequency < 5` guard on the handler's first line
|
|
30
|
+
* - sync-athena : 404s on the missing Athena integration (skipped if one exists)
|
|
31
|
+
* - link-twilio : takes NO parameters and can CREATE A REAL TWILIO SUBACCOUNT, so it is
|
|
32
|
+
* probed only when the org already has a twilioSID (handler short-circuits)
|
|
33
|
+
* - twilio-embed : no phoneNumberSid => 404 no-config or 400, both before any Twilio call
|
|
34
|
+
* - handle-autoreply : absent enduserId => `if (!enduser) return` (communications.ts:42)
|
|
35
|
+
* Input validation runs BEFORE the adminOnly gate (routing.ts:921 orders access, then validate),
|
|
36
|
+
* so every probe body must be schema-VALID or the test would prove nothing.
|
|
37
|
+
*
|
|
38
|
+
* RED (pre-fix): the six group-B rows fail — each reaches its handler and returns a non-401.
|
|
39
|
+
* GREEN (post-fix): all six return 401 "Admin access only"; the group-A controls are unchanged.
|
|
40
|
+
*/
|
|
41
|
+
export declare const schema_adminonly_enforcement_tests: ({ sdk }: {
|
|
42
|
+
sdk: Session;
|
|
43
|
+
sdkNonAdmin: Session;
|
|
44
|
+
}) => Promise<void>;
|
|
45
|
+
//# sourceMappingURL=schema-adminonly-enforcement.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-adminonly-enforcement.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/schema-adminonly-enforcement.test.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAqBtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,kCAAkC;SAA2B,OAAO;iBAAe,OAAO;mBAwMtG,CAAA"}
|