@atproto/oauth-provider 0.3.1 → 0.5.0
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/.linguirc +57 -0
- package/CHANGELOG.md +29 -0
- package/LICENSE.txt +1 -1
- package/dist/account/account-manager.d.ts +17 -3
- package/dist/account/account-manager.d.ts.map +1 -1
- package/dist/account/account-manager.js +102 -8
- package/dist/account/account-manager.js.map +1 -1
- package/dist/account/account-store.d.ts +81 -15
- package/dist/account/account-store.d.ts.map +1 -1
- package/dist/account/account-store.js +70 -19
- package/dist/account/account-store.js.map +1 -1
- package/dist/account/sign-in-data.d.ts +28 -0
- package/dist/account/sign-in-data.d.ts.map +1 -0
- package/dist/account/sign-in-data.js +16 -0
- package/dist/account/sign-in-data.js.map +1 -0
- package/dist/account/sign-up-data.d.ts +26 -0
- package/dist/account/sign-up-data.d.ts.map +1 -0
- package/dist/account/sign-up-data.js +11 -0
- package/dist/account/sign-up-data.js.map +1 -0
- package/dist/assets/app/bundle-manifest.json +598 -6
- package/dist/assets/app/index-ItwwtJ8r.js +36 -0
- package/dist/assets/app/index-ItwwtJ8r.js.map +1 -0
- package/dist/assets/app/main-B_dNxQo_.js +4 -0
- package/dist/assets/app/main-B_dNxQo_.js.map +1 -0
- package/dist/assets/app/main-CSatvmRR.css +3 -0
- package/dist/assets/app/main-CSatvmRR.js +306 -0
- package/dist/assets/app/main-CSatvmRR.js.map +1 -0
- package/dist/assets/app/messages-BQeltXSF.js +4 -0
- package/dist/assets/app/messages-BQeltXSF.js.map +1 -0
- package/dist/assets/app/messages-BQkEhfjg.js +4 -0
- package/dist/assets/app/messages-BQkEhfjg.js.map +1 -0
- package/dist/assets/app/messages-BUjKj_UJ.js +4 -0
- package/dist/assets/app/messages-BUjKj_UJ.js.map +1 -0
- package/dist/assets/app/messages-BWIQa8fO.js +4 -0
- package/dist/assets/app/messages-BWIQa8fO.js.map +1 -0
- package/dist/assets/app/messages-BaNVb0bp.js +4 -0
- package/dist/assets/app/messages-BaNVb0bp.js.map +1 -0
- package/dist/assets/app/messages-BaizVXcF.js +4 -0
- package/dist/assets/app/messages-BaizVXcF.js.map +1 -0
- package/dist/assets/app/messages-BfoClA1Y.js +4 -0
- package/dist/assets/app/messages-BfoClA1Y.js.map +1 -0
- package/dist/assets/app/messages-BsKGDZnC.js +4 -0
- package/dist/assets/app/messages-BsKGDZnC.js.map +1 -0
- package/dist/assets/app/messages-Bu-TJhml.js +4 -0
- package/dist/assets/app/messages-Bu-TJhml.js.map +1 -0
- package/dist/assets/app/messages-BvOKnBQk.js +4 -0
- package/dist/assets/app/messages-BvOKnBQk.js.map +1 -0
- package/dist/assets/app/messages-BxDzCiWz.js +4 -0
- package/dist/assets/app/messages-BxDzCiWz.js.map +1 -0
- package/dist/assets/app/messages-CDgFOy4S.js +4 -0
- package/dist/assets/app/messages-CDgFOy4S.js.map +1 -0
- package/dist/assets/app/messages-CLbTz0o9.js +4 -0
- package/dist/assets/app/messages-CLbTz0o9.js.map +1 -0
- package/dist/assets/app/messages-CNwSh0t7.js +4 -0
- package/dist/assets/app/messages-CNwSh0t7.js.map +1 -0
- package/dist/assets/app/messages-CSMNJ6P8.js +4 -0
- package/dist/assets/app/messages-CSMNJ6P8.js.map +1 -0
- package/dist/assets/app/messages-CZQUw3mp.js +4 -0
- package/dist/assets/app/messages-CZQUw3mp.js.map +1 -0
- package/dist/assets/app/messages-CZT41oVp.js +4 -0
- package/dist/assets/app/messages-CZT41oVp.js.map +1 -0
- package/dist/assets/app/messages-C_b-d3t8.js +4 -0
- package/dist/assets/app/messages-C_b-d3t8.js.map +1 -0
- package/dist/assets/app/messages-C_u3MTc2.js +4 -0
- package/dist/assets/app/messages-C_u3MTc2.js.map +1 -0
- package/dist/assets/app/messages-Cn8nHZic.js +4 -0
- package/dist/assets/app/messages-Cn8nHZic.js.map +1 -0
- package/dist/assets/app/messages-CtDywJUm.js +4 -0
- package/dist/assets/app/messages-CtDywJUm.js.map +1 -0
- package/dist/assets/app/messages-CurtIjBF.js +4 -0
- package/dist/assets/app/messages-CurtIjBF.js.map +1 -0
- package/dist/assets/app/messages-Cv6zIbaP.js +4 -0
- package/dist/assets/app/messages-Cv6zIbaP.js.map +1 -0
- package/dist/assets/app/messages-D1eLQuPE.js +4 -0
- package/dist/assets/app/messages-D1eLQuPE.js.map +1 -0
- package/dist/assets/app/messages-D8vHEaYW.js +4 -0
- package/dist/assets/app/messages-D8vHEaYW.js.map +1 -0
- package/dist/assets/app/messages-DJ1Q4GeC.js +4 -0
- package/dist/assets/app/messages-DJ1Q4GeC.js.map +1 -0
- package/dist/assets/app/messages-DRL3exqd.js +4 -0
- package/dist/assets/app/messages-DRL3exqd.js.map +1 -0
- package/dist/assets/app/messages-DWLPQRTp.js +4 -0
- package/dist/assets/app/messages-DWLPQRTp.js.map +1 -0
- package/dist/assets/app/messages-DjVaE9YE.js +4 -0
- package/dist/assets/app/messages-DjVaE9YE.js.map +1 -0
- package/dist/assets/app/messages-DqpMfFJR.js +4 -0
- package/dist/assets/app/messages-DqpMfFJR.js.map +1 -0
- package/dist/assets/app/messages-ETjhJBEN.js +4 -0
- package/dist/assets/app/messages-ETjhJBEN.js.map +1 -0
- package/dist/assets/app/messages-EUKrgrGn.js +4 -0
- package/dist/assets/app/messages-EUKrgrGn.js.map +1 -0
- package/dist/assets/app/messages-QQrOUcPW.js +4 -0
- package/dist/assets/app/messages-QQrOUcPW.js.map +1 -0
- package/dist/assets/app/messages-e2QGqFL6.js +4 -0
- package/dist/assets/app/messages-e2QGqFL6.js.map +1 -0
- package/dist/assets/app/messages-p61py7gD.js +4 -0
- package/dist/assets/app/messages-p61py7gD.js.map +1 -0
- package/dist/assets/asset.d.ts +1 -0
- package/dist/assets/asset.d.ts.map +1 -1
- package/dist/assets/assets-middleware.d.ts.map +1 -1
- package/dist/assets/assets-middleware.js +12 -7
- package/dist/assets/assets-middleware.js.map +1 -1
- package/dist/assets/index.d.ts +3 -2
- package/dist/assets/index.d.ts.map +1 -1
- package/dist/assets/index.js +13 -1
- package/dist/assets/index.js.map +1 -1
- package/dist/client/client-store.d.ts +3 -3
- package/dist/client/client-store.d.ts.map +1 -1
- package/dist/client/client-store.js +6 -5
- package/dist/client/client-store.js.map +1 -1
- package/dist/device/device-manager.d.ts +12 -13
- package/dist/device/device-manager.d.ts.map +1 -1
- package/dist/device/device-manager.js +5 -3
- package/dist/device/device-manager.js.map +1 -1
- package/dist/device/device-store.d.ts +3 -3
- package/dist/device/device-store.d.ts.map +1 -1
- package/dist/device/device-store.js +10 -9
- package/dist/device/device-store.js.map +1 -1
- package/dist/dpop/dpop-manager.d.ts +15 -7
- package/dist/dpop/dpop-manager.d.ts.map +1 -1
- package/dist/dpop/dpop-manager.js +17 -3
- package/dist/dpop/dpop-manager.js.map +1 -1
- package/dist/dpop/dpop-nonce.d.ts +11 -5
- package/dist/dpop/dpop-nonce.d.ts.map +1 -1
- package/dist/dpop/dpop-nonce.js +47 -38
- package/dist/dpop/dpop-nonce.js.map +1 -1
- package/dist/errors/handle-unavailable-error.d.ts +11 -0
- package/dist/errors/handle-unavailable-error.d.ts.map +1 -0
- package/dist/errors/handle-unavailable-error.js +19 -0
- package/dist/errors/handle-unavailable-error.js.map +1 -0
- package/dist/errors/invalid-request-error.d.ts +6 -8
- package/dist/errors/invalid-request-error.d.ts.map +1 -1
- package/dist/errors/invalid-request-error.js +10 -8
- package/dist/errors/invalid-request-error.js.map +1 -1
- package/dist/lib/csp/index.d.ts +18 -0
- package/dist/lib/csp/index.d.ts.map +1 -0
- package/dist/lib/csp/index.js +72 -0
- package/dist/lib/csp/index.js.map +1 -0
- package/dist/lib/hcaptcha.d.ts +177 -0
- package/dist/lib/hcaptcha.d.ts.map +1 -0
- package/dist/lib/hcaptcha.js +155 -0
- package/dist/lib/hcaptcha.js.map +1 -0
- package/dist/lib/html/build-document.d.ts +11 -3
- package/dist/lib/html/build-document.d.ts.map +1 -1
- package/dist/lib/html/build-document.js +51 -15
- package/dist/lib/html/build-document.js.map +1 -1
- package/dist/lib/http/middleware.d.ts.map +1 -1
- package/dist/lib/http/middleware.js +4 -1
- package/dist/lib/http/middleware.js.map +1 -1
- package/dist/lib/http/request.d.ts +18 -3
- package/dist/lib/http/request.d.ts.map +1 -1
- package/dist/lib/http/request.js +56 -23
- package/dist/lib/http/request.js.map +1 -1
- package/dist/lib/http/response.d.ts +4 -2
- package/dist/lib/http/response.d.ts.map +1 -1
- package/dist/lib/http/response.js +23 -5
- package/dist/lib/http/response.js.map +1 -1
- package/dist/lib/locale.d.ts +15 -0
- package/dist/lib/locale.d.ts.map +1 -0
- package/dist/lib/locale.js +17 -0
- package/dist/lib/locale.js.map +1 -0
- package/dist/lib/util/function.d.ts +2 -2
- package/dist/lib/util/function.d.ts.map +1 -1
- package/dist/lib/util/function.js.map +1 -1
- package/dist/lib/util/type.d.ts +88 -1
- package/dist/lib/util/type.d.ts.map +1 -1
- package/dist/lib/util/type.js +41 -0
- package/dist/lib/util/type.js.map +1 -1
- package/dist/metadata/build-metadata.d.ts +2 -2
- package/dist/metadata/build-metadata.d.ts.map +1 -1
- package/dist/metadata/build-metadata.js.map +1 -1
- package/dist/oauth-errors.d.ts +1 -0
- package/dist/oauth-errors.d.ts.map +1 -1
- package/dist/oauth-errors.js +3 -1
- package/dist/oauth-errors.js.map +1 -1
- package/dist/oauth-hooks.d.ts +60 -3
- package/dist/oauth-hooks.d.ts.map +1 -1
- package/dist/oauth-hooks.js +3 -3
- package/dist/oauth-hooks.js.map +1 -1
- package/dist/oauth-provider.d.ts +28 -22
- package/dist/oauth-provider.d.ts.map +1 -1
- package/dist/oauth-provider.js +212 -211
- package/dist/oauth-provider.js.map +1 -1
- package/dist/oauth-verifier.d.ts +1 -1
- package/dist/oauth-verifier.d.ts.map +1 -1
- package/dist/oauth-verifier.js +2 -1
- package/dist/oauth-verifier.js.map +1 -1
- package/dist/output/build-authorize-data.d.ts +0 -1
- package/dist/output/build-authorize-data.d.ts.map +1 -1
- package/dist/output/build-authorize-data.js +0 -1
- package/dist/output/build-authorize-data.js.map +1 -1
- package/dist/output/build-customization-data.d.ts +232 -0
- package/dist/output/build-customization-data.d.ts.map +1 -0
- package/dist/output/build-customization-data.js +145 -0
- package/dist/output/build-customization-data.js.map +1 -0
- package/dist/output/output-manager.d.ts +16 -9
- package/dist/output/output-manager.d.ts.map +1 -1
- package/dist/output/output-manager.js +78 -42
- package/dist/output/output-manager.js.map +1 -1
- package/dist/output/send-authorize-redirect.d.ts +9 -6
- package/dist/output/send-authorize-redirect.d.ts.map +1 -1
- package/dist/output/send-authorize-redirect.js +20 -14
- package/dist/output/send-authorize-redirect.js.map +1 -1
- package/dist/output/send-web-page.d.ts +7 -2
- package/dist/output/send-web-page.d.ts.map +1 -1
- package/dist/output/send-web-page.js +37 -21
- package/dist/output/send-web-page.js.map +1 -1
- package/dist/request/request-manager.d.ts +1 -1
- package/dist/request/request-manager.d.ts.map +1 -1
- package/dist/request/request-manager.js +4 -4
- package/dist/request/request-manager.js.map +1 -1
- package/dist/request/request-store.d.ts +3 -3
- package/dist/request/request-store.d.ts.map +1 -1
- package/dist/request/request-store.js +11 -10
- package/dist/request/request-store.js.map +1 -1
- package/dist/token/token-store.d.ts +4 -4
- package/dist/token/token-store.d.ts.map +1 -1
- package/dist/token/token-store.js +13 -12
- package/dist/token/token-store.js.map +1 -1
- package/package.json +46 -21
- package/rollup.config.js +61 -17
- package/src/account/account-manager.ts +159 -8
- package/src/account/account-store.ts +127 -32
- package/src/account/sign-in-data.ts +15 -0
- package/src/account/sign-up-data.ts +11 -0
- package/src/assets/app/app.tsx +31 -16
- package/src/assets/app/backend-data.ts +15 -60
- package/src/assets/app/backend-types.ts +66 -0
- package/src/assets/app/components/forms/button-toggle-visibility.tsx +43 -0
- package/src/assets/app/components/forms/button.tsx +60 -0
- package/src/assets/app/components/forms/fieldset.tsx +55 -0
- package/src/assets/app/components/forms/form-card-async.tsx +103 -0
- package/src/assets/app/components/forms/form-card.tsx +49 -0
- package/src/assets/app/components/forms/input-checkbox.tsx +73 -0
- package/src/assets/app/components/forms/input-container.tsx +107 -0
- package/src/assets/app/components/forms/input-email-address.tsx +66 -0
- package/src/assets/app/components/forms/input-new-password.tsx +62 -0
- package/src/assets/app/components/forms/input-password.tsx +88 -0
- package/src/assets/app/components/forms/input-text.tsx +76 -0
- package/src/assets/app/components/forms/input-token.tsx +94 -0
- package/src/assets/app/components/forms/wizard-card.tsx +116 -0
- package/src/assets/app/components/layouts/layout-title-page.tsx +77 -0
- package/src/assets/app/components/layouts/layout-welcome.tsx +73 -0
- package/src/assets/app/components/utils/account-identifier.tsx +23 -0
- package/src/assets/app/components/utils/account-image.tsx +33 -0
- package/src/assets/app/components/utils/admonition.tsx +52 -0
- package/src/assets/app/components/utils/client-name.tsx +45 -0
- package/src/assets/app/components/utils/error-card.tsx +93 -0
- package/src/assets/app/components/utils/error-message.tsx +62 -0
- package/src/assets/app/components/utils/help-card.tsx +46 -0
- package/src/assets/app/components/utils/icons.tsx +88 -0
- package/src/assets/app/components/utils/link-anchor.tsx +28 -0
- package/src/assets/app/components/utils/link-title.tsx +26 -0
- package/src/assets/app/components/utils/multi-lang-string.tsx +56 -0
- package/src/assets/app/components/utils/password-strength-label.tsx +37 -0
- package/src/assets/app/components/utils/password-strength-meter.tsx +58 -0
- package/src/assets/app/components/{url-viewer.tsx → utils/url-viewer.tsx} +9 -6
- package/src/assets/app/hooks/use-api.ts +128 -55
- package/src/assets/app/hooks/use-async-action.ts +120 -0
- package/src/assets/app/hooks/use-browser-color-scheme.ts +31 -0
- package/src/assets/app/hooks/use-csrf-token.ts +1 -1
- package/src/assets/app/hooks/use-random-string.ts +37 -0
- package/src/assets/app/hooks/use-stepper.ts +87 -0
- package/src/assets/app/index.html +182 -0
- package/src/assets/app/lib/api.ts +248 -79
- package/src/assets/app/lib/clsx.ts +5 -8
- package/src/assets/app/lib/json-client.ts +94 -0
- package/src/assets/app/lib/password.ts +98 -0
- package/src/assets/app/lib/ref.ts +17 -0
- package/src/assets/app/locales/an/messages.po +492 -0
- package/src/assets/app/locales/ast/messages.po +492 -0
- package/src/assets/app/locales/ca/messages.po +492 -0
- package/src/assets/app/locales/da/messages.po +492 -0
- package/src/assets/app/locales/de/messages.po +492 -0
- package/src/assets/app/locales/el/messages.po +492 -0
- package/src/assets/app/locales/en/messages.po +492 -0
- package/src/assets/app/locales/en-GB/messages.po +492 -0
- package/src/assets/app/locales/es/messages.po +492 -0
- package/src/assets/app/locales/eu/messages.po +492 -0
- package/src/assets/app/locales/fi/messages.po +492 -0
- package/src/assets/app/locales/fr/messages.po +492 -0
- package/src/assets/app/locales/ga/messages.po +492 -0
- package/src/assets/app/locales/gl/messages.po +492 -0
- package/src/assets/app/locales/hi/messages.po +492 -0
- package/src/assets/app/locales/hu/messages.po +492 -0
- package/src/assets/app/locales/ia/messages.po +492 -0
- package/src/assets/app/locales/id/messages.po +492 -0
- package/src/assets/app/locales/it/messages.po +492 -0
- package/src/assets/app/locales/ja/messages.po +492 -0
- package/src/assets/app/locales/km/messages.po +492 -0
- package/src/assets/app/locales/ko/messages.po +492 -0
- package/src/assets/app/locales/load.ts +8 -0
- package/src/assets/app/locales/locale-context.ts +19 -0
- package/src/assets/app/locales/locale-provider.tsx +112 -0
- package/src/assets/app/locales/locale-selector.tsx +58 -0
- package/src/assets/app/locales/locales.ts +168 -0
- package/src/assets/app/locales/ne/messages.po +492 -0
- package/src/assets/app/locales/nl/messages.po +492 -0
- package/src/assets/app/locales/pl/messages.po +492 -0
- package/src/assets/app/locales/pt-BR/messages.po +492 -0
- package/src/assets/app/locales/ro/messages.po +492 -0
- package/src/assets/app/locales/ru/messages.po +492 -0
- package/src/assets/app/locales/sv/messages.po +492 -0
- package/src/assets/app/locales/th/messages.po +492 -0
- package/src/assets/app/locales/tr/messages.po +492 -0
- package/src/assets/app/locales/uk/messages.po +492 -0
- package/src/assets/app/locales/vi/messages.po +492 -0
- package/src/assets/app/locales/zh-CN/messages.po +492 -0
- package/src/assets/app/locales/zh-HK/messages.po +492 -0
- package/src/assets/app/locales/zh-TW/messages.po +492 -0
- package/src/assets/app/main.css +23 -2
- package/src/assets/app/main.tsx +24 -8
- package/src/assets/app/views/authorize/accept/accept-form.tsx +150 -0
- package/src/assets/app/views/authorize/accept/accept-view.tsx +70 -0
- package/src/assets/app/views/authorize/authorize-view.tsx +180 -0
- package/src/assets/app/views/authorize/reset-password/reset-password-confirm-form.tsx +88 -0
- package/src/assets/app/views/authorize/reset-password/reset-password-request-form.tsx +80 -0
- package/src/assets/app/views/authorize/reset-password/reset-password-view.tsx +127 -0
- package/src/assets/app/views/authorize/sign-in/sign-in-form.tsx +244 -0
- package/src/assets/app/views/authorize/sign-in/sign-in-picker.tsx +116 -0
- package/src/assets/app/views/authorize/sign-in/sign-in-view.tsx +145 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-account-form.tsx +140 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-disclaimer.tsx +51 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-handle-form.tsx +289 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-hcaptcha-form.tsx +108 -0
- package/src/assets/app/views/authorize/sign-up/sign-up-view.tsx +158 -0
- package/src/assets/app/views/authorize/welcome/welcome-view.tsx +56 -0
- package/src/assets/app/views/error/error-view.tsx +31 -0
- package/src/assets/asset.ts +1 -0
- package/src/assets/assets-middleware.ts +13 -8
- package/src/assets/index.ts +15 -2
- package/src/client/client-store.ts +10 -12
- package/src/device/device-manager.ts +14 -15
- package/src/device/device-store.ts +9 -15
- package/src/dpop/dpop-manager.ts +20 -8
- package/src/dpop/dpop-nonce.ts +58 -40
- package/src/errors/handle-unavailable-error.ts +18 -0
- package/src/errors/invalid-request-error.ts +10 -8
- package/src/lib/csp/index.ts +98 -0
- package/src/lib/hcaptcha.ts +182 -0
- package/src/lib/html/build-document.ts +60 -16
- package/src/lib/http/middleware.ts +4 -3
- package/src/lib/http/request.ts +81 -28
- package/src/lib/http/response.ts +22 -9
- package/src/lib/locale.ts +21 -0
- package/src/lib/util/function.ts +0 -3
- package/src/lib/util/type.ts +130 -1
- package/src/metadata/build-metadata.ts +2 -1
- package/src/oauth-errors.ts +1 -0
- package/src/oauth-hooks.ts +69 -3
- package/src/oauth-provider.ts +410 -315
- package/src/oauth-verifier.ts +3 -1
- package/src/output/build-authorize-data.ts +1 -3
- package/src/output/build-customization-data.ts +189 -0
- package/src/output/output-manager.ts +111 -48
- package/src/output/send-authorize-redirect.ts +43 -36
- package/src/output/send-web-page.ts +40 -26
- package/src/request/request-manager.ts +4 -4
- package/src/request/request-store.ts +12 -16
- package/src/token/token-store.ts +14 -18
- package/tailwind.config.js +5 -0
- package/tsconfig.backend.tsbuildinfo +1 -1
- package/tsconfig.frontend.tsbuildinfo +1 -1
- package/tsconfig.tools.tsbuildinfo +1 -1
- package/vite.config.mjs +16 -0
- package/.postcssrc.yml +0 -3
- package/dist/assets/app/main.css +0 -3
- package/dist/assets/app/main.js +0 -20
- package/dist/assets/app/main.js.map +0 -1
- package/dist/output/customization.d.ts +0 -27
- package/dist/output/customization.d.ts.map +0 -1
- package/dist/output/customization.js +0 -88
- package/dist/output/customization.js.map +0 -1
- package/src/assets/app/components/accept-form.tsx +0 -137
- package/src/assets/app/components/account-identifier.tsx +0 -18
- package/src/assets/app/components/account-picker.tsx +0 -127
- package/src/assets/app/components/button.tsx +0 -34
- package/src/assets/app/components/client-name.tsx +0 -37
- package/src/assets/app/components/fieldset.tsx +0 -26
- package/src/assets/app/components/form-card.tsx +0 -47
- package/src/assets/app/components/help-card.tsx +0 -42
- package/src/assets/app/components/icons/alert-icon.tsx +0 -5
- package/src/assets/app/components/icons/at-symbol-icon.tsx +0 -5
- package/src/assets/app/components/icons/caret-right-icon.tsx +0 -5
- package/src/assets/app/components/icons/lock-icon.tsx +0 -5
- package/src/assets/app/components/icons/token-icon.tsx +0 -5
- package/src/assets/app/components/icons/util.tsx +0 -17
- package/src/assets/app/components/info-card.tsx +0 -45
- package/src/assets/app/components/input-checkbox.tsx +0 -47
- package/src/assets/app/components/input-container.tsx +0 -37
- package/src/assets/app/components/input-layout.tsx +0 -47
- package/src/assets/app/components/input-text.tsx +0 -69
- package/src/assets/app/components/layout-title-page.tsx +0 -60
- package/src/assets/app/components/layout-welcome.tsx +0 -74
- package/src/assets/app/components/sign-in-form.tsx +0 -337
- package/src/assets/app/components/sign-up-account-form.tsx +0 -194
- package/src/assets/app/components/sign-up-disclaimer.tsx +0 -44
- package/src/assets/app/views/accept-view.tsx +0 -55
- package/src/assets/app/views/authorize-view.tsx +0 -106
- package/src/assets/app/views/error-view.tsx +0 -36
- package/src/assets/app/views/sign-in-view.tsx +0 -111
- package/src/assets/app/views/sign-up-view.tsx +0 -86
- package/src/assets/app/views/welcome-view.tsx +0 -54
- package/src/output/customization.ts +0 -118
package/src/assets/index.ts
CHANGED
@@ -19,7 +19,7 @@ import type { ManifestItem } from '@atproto-labs/rollup-plugin-bundle-manifest'
|
|
19
19
|
// @ts-expect-error: This file is generated at build time
|
20
20
|
// eslint-disable-next-line import/no-unresolved
|
21
21
|
import appBundleManifestJson from './app/bundle-manifest.json'
|
22
|
-
import { Asset } from './asset'
|
22
|
+
import { Asset } from './asset.js'
|
23
23
|
|
24
24
|
const appBundleManifest: Map<string, ManifestItem> = new Map(
|
25
25
|
Object.entries(appBundleManifestJson),
|
@@ -27,7 +27,15 @@ const appBundleManifest: Map<string, ManifestItem> = new Map(
|
|
27
27
|
|
28
28
|
export const ASSETS_URL_PREFIX = '/@atproto/oauth-provider/~assets/'
|
29
29
|
|
30
|
-
export
|
30
|
+
export function* enumerateAssets(mime: string): IteratorObject<Asset, void> {
|
31
|
+
for (const [filename, manifest] of appBundleManifest) {
|
32
|
+
if (manifest.mime === mime) {
|
33
|
+
yield manifestItemToAsset(filename, manifest)
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
export function getAsset(inputFilename: string): Asset {
|
31
39
|
const filename = posix.normalize(inputFilename)
|
32
40
|
|
33
41
|
if (
|
@@ -41,6 +49,10 @@ export async function getAsset(inputFilename: string): Promise<Asset> {
|
|
41
49
|
const manifest = appBundleManifest.get(filename)
|
42
50
|
if (!manifest) throw new AssetNotFoundError(filename)
|
43
51
|
|
52
|
+
return manifestItemToAsset(filename, manifest)
|
53
|
+
}
|
54
|
+
|
55
|
+
function manifestItemToAsset(filename: string, manifest: ManifestItem): Asset {
|
44
56
|
// When this package is used as a regular "node_modules" dependency, and gets
|
45
57
|
// bundled by the consumer, the assets should be copied to the bundle's output
|
46
58
|
// directory. In case the bundler does not support copying assets from the
|
@@ -53,6 +65,7 @@ export async function getAsset(inputFilename: string): Promise<Asset> {
|
|
53
65
|
return {
|
54
66
|
url: posix.join(ASSETS_URL_PREFIX, filename),
|
55
67
|
type: manifest.mime,
|
68
|
+
isEntry: manifest.type === 'chunk' && manifest.isEntry,
|
56
69
|
sha256: manifest.sha256,
|
57
70
|
createStream: data
|
58
71
|
? () => Readable.from(Buffer.from(data, 'base64'))
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { OAuthClientMetadata } from '@atproto/oauth-types'
|
2
|
-
import { Awaitable } from '../lib/util/type.js'
|
2
|
+
import { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'
|
3
3
|
import { ClientId } from './client-id.js'
|
4
4
|
|
5
5
|
// Export all types needed to implement the ClientStore interface
|
@@ -11,15 +11,13 @@ export interface ClientStore {
|
|
11
11
|
findClient(clientId: ClientId): Awaitable<OAuthClientMetadata>
|
12
12
|
}
|
13
13
|
|
14
|
-
export
|
15
|
-
|
16
|
-
)
|
17
|
-
return typeof implementation.findClient === 'function'
|
18
|
-
}
|
14
|
+
export const isClientStore = buildInterfaceChecker<ClientStore>([
|
15
|
+
'findClient', //
|
16
|
+
])
|
19
17
|
|
20
|
-
export function ifClientStore(
|
21
|
-
implementation?:
|
22
|
-
): ClientStore | undefined {
|
18
|
+
export function ifClientStore<V extends Partial<ClientStore>>(
|
19
|
+
implementation?: V,
|
20
|
+
): (V & ClientStore) | undefined {
|
23
21
|
if (implementation && isClientStore(implementation)) {
|
24
22
|
return implementation
|
25
23
|
}
|
@@ -27,9 +25,9 @@ export function ifClientStore(
|
|
27
25
|
return undefined
|
28
26
|
}
|
29
27
|
|
30
|
-
export function asClientStore(
|
31
|
-
implementation?:
|
32
|
-
): ClientStore {
|
28
|
+
export function asClientStore<V extends Partial<ClientStore>>(
|
29
|
+
implementation?: V,
|
30
|
+
): V & ClientStore {
|
33
31
|
const store = ifClientStore(implementation)
|
34
32
|
if (store) return store
|
35
33
|
|
@@ -22,10 +22,13 @@ export const deviceManagerOptionsSchema = z.object({
|
|
22
22
|
/**
|
23
23
|
* Controls whether the IP address is read from the `X-Forwarded-For` header
|
24
24
|
* (if `true`), or from the `req.socket.remoteAddress` property (if `false`).
|
25
|
-
*
|
26
|
-
* @default true // (nowadays, most requests are proxied)
|
27
25
|
*/
|
28
|
-
trustProxy: z
|
26
|
+
trustProxy: z
|
27
|
+
.function()
|
28
|
+
.args<[addr: z.ZodString, i: z.ZodNumber]>(z.string(), z.number())
|
29
|
+
.returns(z.boolean())
|
30
|
+
.optional(),
|
31
|
+
|
29
32
|
/**
|
30
33
|
* Amount of time (in ms) after which session IDs will be rotated
|
31
34
|
*
|
@@ -88,6 +91,11 @@ export type DeviceManagerOptions = z.input<typeof deviceManagerOptionsSchema>
|
|
88
91
|
const cookieValueSchema = z.tuple([deviceIdSchema, sessionIdSchema])
|
89
92
|
type CookieValue = z.infer<typeof cookieValueSchema>
|
90
93
|
|
94
|
+
export type DeviceInfo = {
|
95
|
+
deviceId: DeviceId
|
96
|
+
deviceMetadata: RequestMetadata
|
97
|
+
}
|
98
|
+
|
91
99
|
/**
|
92
100
|
* This class provides an abstraction for keeping track of DEVICE sessions. It
|
93
101
|
* relies on a {@link DeviceStore} to persist session data and a cookie to
|
@@ -107,10 +115,7 @@ export class DeviceManager {
|
|
107
115
|
req: IncomingMessage,
|
108
116
|
res: ServerResponse,
|
109
117
|
forceRotate = false,
|
110
|
-
): Promise<{
|
111
|
-
deviceId: DeviceId
|
112
|
-
deviceMetadata: RequestMetadata
|
113
|
-
}> {
|
118
|
+
): Promise<DeviceInfo> {
|
114
119
|
const cookie = await this.getCookie(req)
|
115
120
|
if (cookie) {
|
116
121
|
return this.refresh(
|
@@ -127,10 +132,7 @@ export class DeviceManager {
|
|
127
132
|
private async create(
|
128
133
|
req: IncomingMessage,
|
129
134
|
res: ServerResponse,
|
130
|
-
): Promise<{
|
131
|
-
deviceId: DeviceId
|
132
|
-
deviceMetadata: RequestMetadata
|
133
|
-
}> {
|
135
|
+
): Promise<DeviceInfo> {
|
134
136
|
const deviceMetadata = this.getRequestMetadata(req)
|
135
137
|
|
136
138
|
const [deviceId, sessionId] = await Promise.all([
|
@@ -155,10 +157,7 @@ export class DeviceManager {
|
|
155
157
|
res: ServerResponse,
|
156
158
|
[deviceId, sessionId]: CookieValue,
|
157
159
|
forceRotate = false,
|
158
|
-
): Promise<{
|
159
|
-
deviceId: DeviceId
|
160
|
-
deviceMetadata: RequestMetadata
|
161
|
-
}> {
|
160
|
+
): Promise<DeviceInfo> {
|
162
161
|
const data = await this.store.readDevice(deviceId)
|
163
162
|
if (!data) return this.create(req, res)
|
164
163
|
|
@@ -1,10 +1,10 @@
|
|
1
|
-
import { Awaitable } from '../lib/util/type.js'
|
1
|
+
import { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'
|
2
2
|
import { DeviceData } from './device-data.js'
|
3
3
|
import { DeviceId } from './device-id.js'
|
4
4
|
|
5
5
|
// Export all types needed to implement the DeviceStore interface
|
6
|
-
export * from './device-id.js'
|
7
6
|
export * from './device-data.js'
|
7
|
+
export * from './device-id.js'
|
8
8
|
export * from './session-id.js'
|
9
9
|
|
10
10
|
export interface DeviceStore {
|
@@ -14,20 +14,14 @@ export interface DeviceStore {
|
|
14
14
|
deleteDevice(deviceId: DeviceId): Awaitable<void>
|
15
15
|
}
|
16
16
|
|
17
|
-
export
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
typeof implementation.updateDevice === 'function' &&
|
24
|
-
typeof implementation.deleteDevice === 'function'
|
25
|
-
)
|
26
|
-
}
|
17
|
+
export const isDeviceStore = buildInterfaceChecker<DeviceStore>([
|
18
|
+
'createDevice',
|
19
|
+
'readDevice',
|
20
|
+
'updateDevice',
|
21
|
+
'deleteDevice',
|
22
|
+
])
|
27
23
|
|
28
|
-
export function asDeviceStore(
|
29
|
-
implementation?: Record<string, unknown> & Partial<DeviceStore>,
|
30
|
-
): DeviceStore {
|
24
|
+
export function asDeviceStore<V>(implementation: V): V & DeviceStore {
|
31
25
|
if (!implementation || !isDeviceStore(implementation)) {
|
32
26
|
throw new Error('Invalid DeviceStore implementation')
|
33
27
|
}
|
package/src/dpop/dpop-manager.ts
CHANGED
@@ -1,30 +1,42 @@
|
|
1
1
|
import { createHash } from 'node:crypto'
|
2
2
|
import { EmbeddedJWK, calculateJwkThumbprint, errors, jwtVerify } from 'jose'
|
3
|
+
import { z } from 'zod'
|
3
4
|
import { DPOP_NONCE_MAX_AGE } from '../constants.js'
|
4
5
|
import { InvalidDpopProofError } from '../errors/invalid-dpop-proof-error.js'
|
5
6
|
import { UseDpopNonceError } from '../errors/use-dpop-nonce-error.js'
|
6
|
-
import {
|
7
|
+
import {
|
8
|
+
DpopNonce,
|
9
|
+
DpopSecret,
|
10
|
+
dpopSecretSchema,
|
11
|
+
rotationIntervalSchema,
|
12
|
+
} from './dpop-nonce.js'
|
7
13
|
|
8
14
|
const { JOSEError } = errors
|
9
15
|
|
10
|
-
export { DpopNonce, type
|
11
|
-
|
16
|
+
export { DpopNonce, type DpopSecret }
|
17
|
+
|
18
|
+
export const dpopManagerOptionsSchema = z.object({
|
12
19
|
/**
|
13
20
|
* Set this to `false` to disable the use of nonces in DPoP proofs. Set this
|
14
21
|
* to a secret Uint8Array or hex encoded string to use a predictable seed for
|
15
22
|
* all nonces (typically useful when multiple instances are running). Leave
|
16
23
|
* undefined to generate a random seed at startup.
|
17
24
|
*/
|
18
|
-
dpopSecret
|
19
|
-
|
20
|
-
}
|
25
|
+
dpopSecret: z.union([z.literal(false), dpopSecretSchema]).optional(),
|
26
|
+
dpopRotationInterval: rotationIntervalSchema.optional(),
|
27
|
+
})
|
28
|
+
export type DpopManagerOptions = z.input<typeof dpopManagerOptionsSchema>
|
21
29
|
|
22
30
|
export class DpopManager {
|
23
31
|
protected readonly dpopNonce?: DpopNonce
|
24
32
|
|
25
|
-
constructor(
|
33
|
+
constructor(options: DpopManagerOptions = {}) {
|
34
|
+
const { dpopSecret, dpopRotationInterval } =
|
35
|
+
dpopManagerOptionsSchema.parse(options)
|
26
36
|
this.dpopNonce =
|
27
|
-
dpopSecret === false
|
37
|
+
dpopSecret === false
|
38
|
+
? undefined
|
39
|
+
: new DpopNonce(dpopSecret, dpopRotationInterval)
|
28
40
|
}
|
29
41
|
|
30
42
|
nextNonce(): string | undefined {
|
package/src/dpop/dpop-nonce.ts
CHANGED
@@ -1,48 +1,68 @@
|
|
1
1
|
import { createHmac, randomBytes } from 'node:crypto'
|
2
|
+
import { z } from 'zod'
|
2
3
|
import { DPOP_NONCE_MAX_AGE } from '../constants.js'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
return arr
|
15
|
-
}
|
5
|
+
const MAX_ROTATION_INTERVAL = DPOP_NONCE_MAX_AGE / 3
|
6
|
+
const MIN_ROTATION_INTERVAL = Math.min(1000, MAX_ROTATION_INTERVAL)
|
7
|
+
|
8
|
+
export const rotationIntervalSchema = z
|
9
|
+
.number()
|
10
|
+
.int()
|
11
|
+
.min(MIN_ROTATION_INTERVAL)
|
12
|
+
.max(MAX_ROTATION_INTERVAL)
|
13
|
+
|
14
|
+
const SECRET_BYTE_LENGTH = 32
|
16
15
|
|
17
|
-
export
|
16
|
+
export const secretBytesSchema = z
|
17
|
+
.instanceof(Uint8Array)
|
18
|
+
.refine((secret) => secret.length === SECRET_BYTE_LENGTH, {
|
19
|
+
message: `Secret must be exactly ${SECRET_BYTE_LENGTH} bytes long`,
|
20
|
+
})
|
21
|
+
|
22
|
+
export const secretHexSchema = z
|
23
|
+
.string()
|
24
|
+
.regex(
|
25
|
+
/^[0-9a-f]+$/i,
|
26
|
+
`Secret must be a ${SECRET_BYTE_LENGTH * 2} chars hex string`,
|
27
|
+
)
|
28
|
+
.length(SECRET_BYTE_LENGTH * 2)
|
29
|
+
.transform((hex): Uint8Array => Buffer.from(hex, 'hex'))
|
30
|
+
|
31
|
+
export const dpopSecretSchema = z.union([secretBytesSchema, secretHexSchema])
|
32
|
+
export type DpopSecret = z.input<typeof dpopSecretSchema>
|
18
33
|
|
19
34
|
export class DpopNonce {
|
20
|
-
#
|
21
|
-
#
|
35
|
+
readonly #rotationInterval: number
|
36
|
+
readonly #secret: Uint8Array
|
22
37
|
|
38
|
+
// Nonce state
|
39
|
+
#counter: number
|
23
40
|
#prev: string
|
24
41
|
#now: string
|
25
42
|
#next: string
|
26
43
|
|
27
44
|
constructor(
|
28
|
-
|
29
|
-
|
45
|
+
secret: DpopSecret = randomBytes(SECRET_BYTE_LENGTH),
|
46
|
+
rotationInterval = MAX_ROTATION_INTERVAL,
|
30
47
|
) {
|
31
|
-
|
32
|
-
|
33
|
-
throw new TypeError('Invalid step')
|
34
|
-
}
|
35
|
-
|
36
|
-
this.#secret = Uint8Array.from(secret)
|
37
|
-
this.#counter = (Date.now() / step) | 0
|
48
|
+
this.#rotationInterval = rotationIntervalSchema.parse(rotationInterval)
|
49
|
+
this.#secret = Uint8Array.from(dpopSecretSchema.parse(secret))
|
38
50
|
|
51
|
+
this.#counter = this.currentCounter
|
39
52
|
this.#prev = this.compute(this.#counter - 1)
|
40
53
|
this.#now = this.compute(this.#counter)
|
41
54
|
this.#next = this.compute(this.#counter + 1)
|
42
55
|
}
|
43
56
|
|
57
|
+
/**
|
58
|
+
* Returns the number of full rotations since the epoch
|
59
|
+
*/
|
60
|
+
protected get currentCounter() {
|
61
|
+
return (Date.now() / this.#rotationInterval) | 0
|
62
|
+
}
|
63
|
+
|
44
64
|
protected rotate() {
|
45
|
-
const counter =
|
65
|
+
const counter = this.currentCounter
|
46
66
|
switch (counter - this.#counter) {
|
47
67
|
case 0:
|
48
68
|
// counter === this.#counter => nothing to do
|
@@ -84,20 +104,18 @@ export class DpopNonce {
|
|
84
104
|
public check(nonce: string) {
|
85
105
|
return this.#next === nonce || this.#now === nonce || this.#prev === nonce
|
86
106
|
}
|
107
|
+
}
|
87
108
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
}
|
101
|
-
return new DpopNonce(input, step)
|
102
|
-
}
|
109
|
+
function numTo64bits(num: number) {
|
110
|
+
const arr = new Uint8Array(8)
|
111
|
+
// @NOTE Assigning to an uint8 will only keep the last 8 int bits
|
112
|
+
arr[7] = num |= 0
|
113
|
+
arr[6] = num >>= 8
|
114
|
+
arr[5] = num >>= 8
|
115
|
+
arr[4] = num >>= 8
|
116
|
+
arr[3] = num >>= 8
|
117
|
+
arr[2] = num >>= 8
|
118
|
+
arr[1] = num >>= 8
|
119
|
+
arr[0] = num >>= 8
|
120
|
+
return arr
|
103
121
|
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { OAuthError } from './oauth-error.js'
|
2
|
+
|
3
|
+
export class HandleUnavailableError extends OAuthError {
|
4
|
+
constructor(
|
5
|
+
readonly reason: 'syntax' | 'domain' | 'slur' | 'taken',
|
6
|
+
details: string = 'That handle is not available',
|
7
|
+
cause?: unknown,
|
8
|
+
) {
|
9
|
+
super('handle_unavailable', details, 400, cause)
|
10
|
+
}
|
11
|
+
|
12
|
+
toJSON() {
|
13
|
+
return {
|
14
|
+
...super.toJSON(),
|
15
|
+
reason: this.reason,
|
16
|
+
} as const
|
17
|
+
}
|
18
|
+
}
|
@@ -2,23 +2,20 @@ import { OAuthError } from './oauth-error.js'
|
|
2
2
|
|
3
3
|
/**
|
4
4
|
* @see
|
5
|
-
* {@link https://datatracker.ietf.org/doc/html/rfc6749#section-5.2 | RFC6749 - Issuing an Access Token
|
6
|
-
*
|
7
|
-
* The request is missing a required parameter, includes an unsupported
|
5
|
+
* {@link https://datatracker.ietf.org/doc/html/rfc6749#section-5.2 | RFC6749 - Issuing an Access Token}
|
6
|
+
* : The request is missing a required parameter, includes an unsupported
|
8
7
|
* parameter value (other than grant type), repeats a parameter, includes
|
9
8
|
* multiple credentials, utilizes more than one mechanism for authenticating the
|
10
9
|
* client, or is otherwise malformed.
|
11
10
|
*
|
12
11
|
* @see
|
13
12
|
* {@link https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1 | RFC6749 - Authorization Code Grant, Authorization Request}
|
14
|
-
*
|
15
|
-
* The request is missing a required parameter, includes an invalid parameter
|
13
|
+
* : The request is missing a required parameter, includes an invalid parameter
|
16
14
|
* value, includes a parameter more than once, or is otherwise malformed.
|
17
15
|
*
|
18
16
|
* @see
|
19
|
-
* {@link https://datatracker.ietf.org/doc/html/rfc6750#section-3.1 | RFC6750 - The WWW-Authenticate Response Header Field
|
20
|
-
*
|
21
|
-
* The request is missing a required parameter, includes an unsupported
|
17
|
+
* {@link https://datatracker.ietf.org/doc/html/rfc6750#section-3.1 | RFC6750 - The WWW-Authenticate Response Header Field}
|
18
|
+
* : The request is missing a required parameter, includes an unsupported
|
22
19
|
* parameter or parameter value, repeats the same parameter, uses more than one
|
23
20
|
* method for including an access token, or is otherwise malformed. The resource
|
24
21
|
* server SHOULD respond with the HTTP 400 (Bad Request) status code.
|
@@ -27,4 +24,9 @@ export class InvalidRequestError extends OAuthError {
|
|
27
24
|
constructor(error_description: string, cause?: unknown) {
|
28
25
|
super('invalid_request', error_description, 400, cause)
|
29
26
|
}
|
27
|
+
|
28
|
+
static from(err: unknown, message = 'Invalid request data'): OAuthError {
|
29
|
+
if (err instanceof OAuthError) return err
|
30
|
+
return new InvalidRequestError(message, err)
|
31
|
+
}
|
30
32
|
}
|
@@ -0,0 +1,98 @@
|
|
1
|
+
import { Simplify } from '../util/type.js'
|
2
|
+
|
3
|
+
export type CspValue =
|
4
|
+
| `data:`
|
5
|
+
| `https:${string}`
|
6
|
+
| `'none'`
|
7
|
+
| `'self'`
|
8
|
+
| `'sha256-${string}'`
|
9
|
+
| `'nonce-${string}'`
|
10
|
+
| `'unsafe-inline'`
|
11
|
+
| `'unsafe-eval'`
|
12
|
+
| `'strict-dynamic'`
|
13
|
+
| `'report-sample'`
|
14
|
+
| `'unsafe-hashes'`
|
15
|
+
|
16
|
+
const STRING_DIRECTIVES = ['base-uri'] as const
|
17
|
+
const BOOLEAN_DIRECTIVES = [
|
18
|
+
'upgrade-insecure-requests',
|
19
|
+
'block-all-mixed-content',
|
20
|
+
] as const
|
21
|
+
const ARRAY_DIRECTIVES = [
|
22
|
+
'connect-src',
|
23
|
+
'default-src',
|
24
|
+
'form-action',
|
25
|
+
'frame-ancestors',
|
26
|
+
'frame-src',
|
27
|
+
'img-src',
|
28
|
+
'script-src',
|
29
|
+
'style-src',
|
30
|
+
] as const
|
31
|
+
|
32
|
+
export type CspConfig = Simplify<
|
33
|
+
{
|
34
|
+
[K in (typeof BOOLEAN_DIRECTIVES)[number]]?: boolean
|
35
|
+
} & {
|
36
|
+
[K in (typeof STRING_DIRECTIVES)[number]]?: CspValue
|
37
|
+
} & {
|
38
|
+
[K in (typeof ARRAY_DIRECTIVES)[number]]?: readonly CspValue[]
|
39
|
+
}
|
40
|
+
>
|
41
|
+
|
42
|
+
const NONE = "'none'"
|
43
|
+
|
44
|
+
export function buildCsp(config: CspConfig): string {
|
45
|
+
const values: string[] = []
|
46
|
+
|
47
|
+
for (const name of BOOLEAN_DIRECTIVES) {
|
48
|
+
if (config[name] === true) values.push(name)
|
49
|
+
}
|
50
|
+
|
51
|
+
for (const name of STRING_DIRECTIVES) {
|
52
|
+
if (config[name]) values.push(`${name} ${config[name]}`)
|
53
|
+
}
|
54
|
+
|
55
|
+
for (const name of ARRAY_DIRECTIVES) {
|
56
|
+
if (config[name]?.length) values.push(`${name} ${config[name].join(' ')}`)
|
57
|
+
}
|
58
|
+
|
59
|
+
return values.join('; ')
|
60
|
+
}
|
61
|
+
|
62
|
+
export function mergeCsp(a: CspConfig, b?: CspConfig): CspConfig
|
63
|
+
export function mergeCsp(a: CspConfig | undefined, b: CspConfig): CspConfig
|
64
|
+
export function mergeCsp(a?: CspConfig, b?: CspConfig): CspConfig | undefined
|
65
|
+
export function mergeCsp(a?: CspConfig, b?: CspConfig): CspConfig | undefined {
|
66
|
+
if (!a) return b
|
67
|
+
if (!b) return a
|
68
|
+
|
69
|
+
const result: CspConfig = {}
|
70
|
+
|
71
|
+
for (const name of BOOLEAN_DIRECTIVES) {
|
72
|
+
if (a[name] || b[name]) {
|
73
|
+
result[name] = true
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
for (const name of STRING_DIRECTIVES) {
|
78
|
+
if (a[name] || b[name]) {
|
79
|
+
const aNotNone = a[name] === NONE ? undefined : a[name]
|
80
|
+
const bNotNone = b[name] === NONE ? undefined : b[name]
|
81
|
+
// @NOTE b takes precedence
|
82
|
+
result[name] = bNotNone || aNotNone || NONE
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
for (const name of ARRAY_DIRECTIVES) {
|
87
|
+
if (a[name] && b[name]) {
|
88
|
+
const set = new Set(a[name])
|
89
|
+
if (b[name]) for (const value of b[name]) set.add(value)
|
90
|
+
if (set.size > 1 && set.has(NONE)) set.delete(NONE)
|
91
|
+
result[name] = [...set]
|
92
|
+
} else if (a[name] || b[name]) {
|
93
|
+
result[name] = Array.from((a[name] || b[name])!)
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
return result
|
98
|
+
}
|