@atproto/oauth-provider 0.5.1 → 0.6.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/CHANGELOG.md +39 -0
- package/dist/account/account-manager.d.ts +7 -5
- package/dist/account/account-manager.d.ts.map +1 -1
- package/dist/account/account-manager.js +34 -25
- package/dist/account/account-manager.js.map +1 -1
- package/dist/account/account-store.d.ts +13 -5
- package/dist/account/account-store.d.ts.map +1 -1
- package/dist/account/account-store.js +24 -8
- package/dist/account/account-store.js.map +1 -1
- package/dist/account/account.d.ts +1 -11
- package/dist/account/account.d.ts.map +1 -1
- package/dist/account/{sign-up-data.d.ts → sign-up-input.d.ts} +5 -5
- package/dist/account/sign-up-input.d.ts.map +1 -0
- package/dist/account/{sign-up-data.js → sign-up-input.js} +3 -3
- package/dist/account/sign-up-input.js.map +1 -0
- package/dist/assets/assets-middleware.d.ts +2 -0
- package/dist/assets/assets-middleware.d.ts.map +1 -1
- package/dist/assets/assets-middleware.js +12 -14
- package/dist/assets/assets-middleware.js.map +1 -1
- package/dist/errors/invalid-invite-code-error.d.ts +5 -0
- package/dist/errors/invalid-invite-code-error.d.ts.map +1 -0
- package/dist/errors/invalid-invite-code-error.js +11 -0
- package/dist/errors/invalid-invite-code-error.js.map +1 -0
- package/dist/errors/oauth-error.d.ts +2 -2
- package/dist/errors/oauth-error.js.map +1 -1
- package/dist/lib/csp/index.d.ts +5 -6
- package/dist/lib/csp/index.d.ts.map +1 -1
- package/dist/lib/csp/index.js +14 -11
- package/dist/lib/csp/index.js.map +1 -1
- package/dist/lib/hcaptcha.d.ts +5 -3
- package/dist/lib/hcaptcha.d.ts.map +1 -1
- package/dist/lib/hcaptcha.js +7 -4
- package/dist/lib/hcaptcha.js.map +1 -1
- package/dist/lib/html/build-document.d.ts +2 -2
- package/dist/lib/html/build-document.d.ts.map +1 -1
- package/dist/lib/html/build-document.js +11 -7
- package/dist/lib/html/build-document.js.map +1 -1
- package/dist/lib/html/html.d.ts.map +1 -1
- package/dist/lib/html/html.js +10 -13
- package/dist/lib/html/html.js.map +1 -1
- package/dist/lib/html/util.d.ts +0 -1
- package/dist/lib/html/util.d.ts.map +1 -1
- package/dist/lib/html/util.js +0 -4
- package/dist/lib/html/util.js.map +1 -1
- package/dist/lib/http/response.d.ts +3 -1
- package/dist/lib/http/response.d.ts.map +1 -1
- package/dist/lib/http/response.js +3 -0
- package/dist/lib/http/response.js.map +1 -1
- package/dist/lib/http/security-headers.d.ts +48 -0
- package/dist/lib/http/security-headers.d.ts.map +1 -0
- package/dist/lib/http/security-headers.js +62 -0
- package/dist/lib/http/security-headers.js.map +1 -0
- package/dist/lib/util/type.d.ts +8 -0
- package/dist/lib/util/type.d.ts.map +1 -1
- package/dist/lib/util/type.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 +4 -25
- package/dist/oauth-hooks.d.ts.map +1 -1
- package/dist/oauth-provider.d.ts.map +1 -1
- package/dist/oauth-provider.js +26 -25
- package/dist/oauth-provider.js.map +1 -1
- package/dist/output/backend-data.d.ts +4 -0
- package/dist/output/backend-data.d.ts.map +1 -0
- package/dist/output/backend-data.js +19 -0
- package/dist/output/backend-data.js.map +1 -0
- package/dist/output/build-authorize-data.d.ts +3 -19
- package/dist/output/build-authorize-data.d.ts.map +1 -1
- package/dist/output/build-authorize-data.js.map +1 -1
- package/dist/output/build-customization-data.d.ts +11 -18
- package/dist/output/build-customization-data.d.ts.map +1 -1
- package/dist/output/build-customization-data.js +1 -1
- package/dist/output/build-customization-data.js.map +1 -1
- package/dist/output/build-error-data.d.ts +3 -0
- package/dist/output/build-error-data.d.ts.map +1 -0
- package/dist/output/build-error-data.js +10 -0
- package/dist/output/build-error-data.js.map +1 -0
- package/dist/output/build-error-payload.d.ts +2 -1
- package/dist/output/build-error-payload.d.ts.map +1 -1
- package/dist/output/build-error-payload.js.map +1 -1
- package/dist/output/output-manager.d.ts +10 -4
- package/dist/output/output-manager.d.ts.map +1 -1
- package/dist/output/output-manager.js +68 -39
- package/dist/output/output-manager.js.map +1 -1
- package/dist/output/send-web-page.d.ts +6 -10
- package/dist/output/send-web-page.d.ts.map +1 -1
- package/dist/output/send-web-page.js +27 -47
- package/dist/output/send-web-page.js.map +1 -1
- package/dist/signer/signed-token-payload.d.ts +3 -3
- package/dist/signer/signer.d.ts +2 -2
- package/package.json +7 -39
- package/src/account/account-manager.ts +55 -34
- package/src/account/account-store.ts +29 -6
- package/src/account/account.ts +1 -14
- package/src/account/{sign-up-data.ts → sign-up-input.ts} +2 -2
- package/src/assets/assets-middleware.ts +11 -17
- package/src/errors/invalid-invite-code-error.ts +10 -0
- package/src/errors/oauth-error.ts +1 -1
- package/src/lib/csp/index.ts +16 -13
- package/src/lib/hcaptcha.ts +10 -7
- package/src/lib/html/build-document.ts +15 -8
- package/src/lib/html/html.ts +11 -18
- package/src/lib/html/util.ts +0 -4
- package/src/lib/http/response.ts +9 -1
- package/src/lib/http/security-headers.ts +91 -0
- package/src/lib/util/type.ts +18 -0
- package/src/oauth-errors.ts +1 -0
- package/src/oauth-hooks.ts +4 -25
- package/src/oauth-provider.ts +40 -34
- package/src/output/backend-data.ts +18 -0
- package/src/output/build-authorize-data.ts +3 -26
- package/src/output/build-customization-data.ts +2 -13
- package/src/output/build-error-data.ts +8 -0
- package/src/output/build-error-payload.ts +4 -2
- package/src/output/output-manager.ts +86 -47
- package/src/output/send-web-page.ts +29 -58
- package/tsconfig.backend.json +1 -2
- package/tsconfig.backend.tsbuildinfo +1 -1
- package/tsconfig.json +1 -5
- package/.linguirc +0 -57
- package/dist/account/sign-up-data.d.ts.map +0 -1
- package/dist/account/sign-up-data.js.map +0 -1
- package/dist/assets/app/bundle-manifest.json +0 -614
- package/dist/assets/app/index-ItwwtJ8r.js +0 -36
- package/dist/assets/app/index-ItwwtJ8r.js.map +0 -1
- package/dist/assets/app/main-B_dNxQo_.js +0 -4
- package/dist/assets/app/main-B_dNxQo_.js.map +0 -1
- package/dist/assets/app/main-CSatvmRR.css +0 -3
- package/dist/assets/app/main-CSatvmRR.js +0 -306
- package/dist/assets/app/main-CSatvmRR.js.map +0 -1
- package/dist/assets/app/messages-BQeltXSF.js +0 -4
- package/dist/assets/app/messages-BQeltXSF.js.map +0 -1
- package/dist/assets/app/messages-BQkEhfjg.js +0 -4
- package/dist/assets/app/messages-BQkEhfjg.js.map +0 -1
- package/dist/assets/app/messages-BUjKj_UJ.js +0 -4
- package/dist/assets/app/messages-BUjKj_UJ.js.map +0 -1
- package/dist/assets/app/messages-BWIQa8fO.js +0 -4
- package/dist/assets/app/messages-BWIQa8fO.js.map +0 -1
- package/dist/assets/app/messages-BaNVb0bp.js +0 -4
- package/dist/assets/app/messages-BaNVb0bp.js.map +0 -1
- package/dist/assets/app/messages-BaizVXcF.js +0 -4
- package/dist/assets/app/messages-BaizVXcF.js.map +0 -1
- package/dist/assets/app/messages-BfoClA1Y.js +0 -4
- package/dist/assets/app/messages-BfoClA1Y.js.map +0 -1
- package/dist/assets/app/messages-BsKGDZnC.js +0 -4
- package/dist/assets/app/messages-BsKGDZnC.js.map +0 -1
- package/dist/assets/app/messages-Bu-TJhml.js +0 -4
- package/dist/assets/app/messages-Bu-TJhml.js.map +0 -1
- package/dist/assets/app/messages-BvOKnBQk.js +0 -4
- package/dist/assets/app/messages-BvOKnBQk.js.map +0 -1
- package/dist/assets/app/messages-BxDzCiWz.js +0 -4
- package/dist/assets/app/messages-BxDzCiWz.js.map +0 -1
- package/dist/assets/app/messages-CDgFOy4S.js +0 -4
- package/dist/assets/app/messages-CDgFOy4S.js.map +0 -1
- package/dist/assets/app/messages-CLbTz0o9.js +0 -4
- package/dist/assets/app/messages-CLbTz0o9.js.map +0 -1
- package/dist/assets/app/messages-CNwSh0t7.js +0 -4
- package/dist/assets/app/messages-CNwSh0t7.js.map +0 -1
- package/dist/assets/app/messages-CSMNJ6P8.js +0 -4
- package/dist/assets/app/messages-CSMNJ6P8.js.map +0 -1
- package/dist/assets/app/messages-CZQUw3mp.js +0 -4
- package/dist/assets/app/messages-CZQUw3mp.js.map +0 -1
- package/dist/assets/app/messages-CZT41oVp.js +0 -4
- package/dist/assets/app/messages-CZT41oVp.js.map +0 -1
- package/dist/assets/app/messages-C_b-d3t8.js +0 -4
- package/dist/assets/app/messages-C_b-d3t8.js.map +0 -1
- package/dist/assets/app/messages-C_u3MTc2.js +0 -4
- package/dist/assets/app/messages-C_u3MTc2.js.map +0 -1
- package/dist/assets/app/messages-Cn8nHZic.js +0 -4
- package/dist/assets/app/messages-Cn8nHZic.js.map +0 -1
- package/dist/assets/app/messages-CtDywJUm.js +0 -4
- package/dist/assets/app/messages-CtDywJUm.js.map +0 -1
- package/dist/assets/app/messages-CurtIjBF.js +0 -4
- package/dist/assets/app/messages-CurtIjBF.js.map +0 -1
- package/dist/assets/app/messages-Cv6zIbaP.js +0 -4
- package/dist/assets/app/messages-Cv6zIbaP.js.map +0 -1
- package/dist/assets/app/messages-D1eLQuPE.js +0 -4
- package/dist/assets/app/messages-D1eLQuPE.js.map +0 -1
- package/dist/assets/app/messages-D8vHEaYW.js +0 -4
- package/dist/assets/app/messages-D8vHEaYW.js.map +0 -1
- package/dist/assets/app/messages-DJ1Q4GeC.js +0 -4
- package/dist/assets/app/messages-DJ1Q4GeC.js.map +0 -1
- package/dist/assets/app/messages-DRL3exqd.js +0 -4
- package/dist/assets/app/messages-DRL3exqd.js.map +0 -1
- package/dist/assets/app/messages-DWLPQRTp.js +0 -4
- package/dist/assets/app/messages-DWLPQRTp.js.map +0 -1
- package/dist/assets/app/messages-DjVaE9YE.js +0 -4
- package/dist/assets/app/messages-DjVaE9YE.js.map +0 -1
- package/dist/assets/app/messages-DqpMfFJR.js +0 -4
- package/dist/assets/app/messages-DqpMfFJR.js.map +0 -1
- package/dist/assets/app/messages-ETjhJBEN.js +0 -4
- package/dist/assets/app/messages-ETjhJBEN.js.map +0 -1
- package/dist/assets/app/messages-EUKrgrGn.js +0 -4
- package/dist/assets/app/messages-EUKrgrGn.js.map +0 -1
- package/dist/assets/app/messages-QQrOUcPW.js +0 -4
- package/dist/assets/app/messages-QQrOUcPW.js.map +0 -1
- package/dist/assets/app/messages-e2QGqFL6.js +0 -4
- package/dist/assets/app/messages-e2QGqFL6.js.map +0 -1
- package/dist/assets/app/messages-p61py7gD.js +0 -4
- package/dist/assets/app/messages-p61py7gD.js.map +0 -1
- package/dist/assets/asset.d.ts +0 -9
- package/dist/assets/asset.d.ts.map +0 -1
- package/dist/assets/asset.js +0 -3
- package/dist/assets/asset.js.map +0 -1
- package/dist/assets/index.d.ts +0 -5
- package/dist/assets/index.d.ts.map +0 -1
- package/dist/assets/index.js +0 -78
- package/dist/assets/index.js.map +0 -1
- package/rollup.config.js +0 -98
- package/src/assets/app/app.tsx +0 -43
- package/src/assets/app/backend-data.ts +0 -27
- package/src/assets/app/backend-types.ts +0 -66
- package/src/assets/app/components/forms/button-toggle-visibility.tsx +0 -43
- package/src/assets/app/components/forms/button.tsx +0 -60
- package/src/assets/app/components/forms/fieldset.tsx +0 -55
- package/src/assets/app/components/forms/form-card-async.tsx +0 -103
- package/src/assets/app/components/forms/form-card.tsx +0 -49
- package/src/assets/app/components/forms/input-checkbox.tsx +0 -73
- package/src/assets/app/components/forms/input-container.tsx +0 -107
- package/src/assets/app/components/forms/input-email-address.tsx +0 -66
- package/src/assets/app/components/forms/input-new-password.tsx +0 -62
- package/src/assets/app/components/forms/input-password.tsx +0 -88
- package/src/assets/app/components/forms/input-text.tsx +0 -76
- package/src/assets/app/components/forms/input-token.tsx +0 -94
- package/src/assets/app/components/forms/wizard-card.tsx +0 -116
- package/src/assets/app/components/layouts/layout-title-page.tsx +0 -77
- package/src/assets/app/components/layouts/layout-welcome.tsx +0 -73
- package/src/assets/app/components/utils/account-identifier.tsx +0 -23
- package/src/assets/app/components/utils/account-image.tsx +0 -33
- package/src/assets/app/components/utils/admonition.tsx +0 -52
- package/src/assets/app/components/utils/client-name.tsx +0 -45
- package/src/assets/app/components/utils/error-card.tsx +0 -93
- package/src/assets/app/components/utils/error-message.tsx +0 -62
- package/src/assets/app/components/utils/help-card.tsx +0 -46
- package/src/assets/app/components/utils/icons.tsx +0 -88
- package/src/assets/app/components/utils/link-anchor.tsx +0 -28
- package/src/assets/app/components/utils/link-title.tsx +0 -26
- package/src/assets/app/components/utils/multi-lang-string.tsx +0 -56
- package/src/assets/app/components/utils/password-strength-label.tsx +0 -37
- package/src/assets/app/components/utils/password-strength-meter.tsx +0 -58
- package/src/assets/app/components/utils/url-viewer.tsx +0 -73
- package/src/assets/app/cookies.ts +0 -11
- package/src/assets/app/hooks/use-api.ts +0 -178
- package/src/assets/app/hooks/use-async-action.ts +0 -120
- package/src/assets/app/hooks/use-bound-dispatch.ts +0 -5
- package/src/assets/app/hooks/use-browser-color-scheme.ts +0 -31
- package/src/assets/app/hooks/use-csrf-token.ts +0 -5
- package/src/assets/app/hooks/use-random-string.ts +0 -37
- package/src/assets/app/hooks/use-stepper.ts +0 -87
- package/src/assets/app/index.html +0 -182
- package/src/assets/app/lib/api.ts +0 -267
- package/src/assets/app/lib/clsx.ts +0 -6
- package/src/assets/app/lib/json-client.ts +0 -94
- package/src/assets/app/lib/password.ts +0 -98
- package/src/assets/app/lib/ref.ts +0 -17
- package/src/assets/app/lib/util.ts +0 -13
- package/src/assets/app/locales/an/messages.po +0 -492
- package/src/assets/app/locales/ast/messages.po +0 -492
- package/src/assets/app/locales/ca/messages.po +0 -492
- package/src/assets/app/locales/da/messages.po +0 -492
- package/src/assets/app/locales/de/messages.po +0 -492
- package/src/assets/app/locales/el/messages.po +0 -492
- package/src/assets/app/locales/en/messages.po +0 -492
- package/src/assets/app/locales/en-GB/messages.po +0 -492
- package/src/assets/app/locales/es/messages.po +0 -492
- package/src/assets/app/locales/eu/messages.po +0 -492
- package/src/assets/app/locales/fi/messages.po +0 -492
- package/src/assets/app/locales/fr/messages.po +0 -492
- package/src/assets/app/locales/ga/messages.po +0 -492
- package/src/assets/app/locales/gl/messages.po +0 -492
- package/src/assets/app/locales/hi/messages.po +0 -492
- package/src/assets/app/locales/hu/messages.po +0 -492
- package/src/assets/app/locales/ia/messages.po +0 -492
- package/src/assets/app/locales/id/messages.po +0 -492
- package/src/assets/app/locales/it/messages.po +0 -492
- package/src/assets/app/locales/ja/messages.po +0 -492
- package/src/assets/app/locales/km/messages.po +0 -492
- package/src/assets/app/locales/ko/messages.po +0 -492
- package/src/assets/app/locales/load.ts +0 -8
- package/src/assets/app/locales/locale-context.ts +0 -19
- package/src/assets/app/locales/locale-provider.tsx +0 -112
- package/src/assets/app/locales/locale-selector.tsx +0 -58
- package/src/assets/app/locales/locales.ts +0 -168
- package/src/assets/app/locales/ne/messages.po +0 -492
- package/src/assets/app/locales/nl/messages.po +0 -492
- package/src/assets/app/locales/pl/messages.po +0 -492
- package/src/assets/app/locales/pt-BR/messages.po +0 -492
- package/src/assets/app/locales/ro/messages.po +0 -492
- package/src/assets/app/locales/ru/messages.po +0 -492
- package/src/assets/app/locales/sv/messages.po +0 -492
- package/src/assets/app/locales/th/messages.po +0 -492
- package/src/assets/app/locales/tr/messages.po +0 -492
- package/src/assets/app/locales/uk/messages.po +0 -492
- package/src/assets/app/locales/vi/messages.po +0 -492
- package/src/assets/app/locales/zh-CN/messages.po +0 -492
- package/src/assets/app/locales/zh-HK/messages.po +0 -492
- package/src/assets/app/locales/zh-TW/messages.po +0 -492
- package/src/assets/app/main.css +0 -33
- package/src/assets/app/main.tsx +0 -44
- package/src/assets/app/views/authorize/accept/accept-form.tsx +0 -150
- package/src/assets/app/views/authorize/accept/accept-view.tsx +0 -70
- package/src/assets/app/views/authorize/authorize-view.tsx +0 -180
- package/src/assets/app/views/authorize/reset-password/reset-password-confirm-form.tsx +0 -88
- package/src/assets/app/views/authorize/reset-password/reset-password-request-form.tsx +0 -80
- package/src/assets/app/views/authorize/reset-password/reset-password-view.tsx +0 -127
- package/src/assets/app/views/authorize/sign-in/sign-in-form.tsx +0 -244
- package/src/assets/app/views/authorize/sign-in/sign-in-picker.tsx +0 -116
- package/src/assets/app/views/authorize/sign-in/sign-in-view.tsx +0 -145
- package/src/assets/app/views/authorize/sign-up/sign-up-account-form.tsx +0 -140
- package/src/assets/app/views/authorize/sign-up/sign-up-disclaimer.tsx +0 -51
- package/src/assets/app/views/authorize/sign-up/sign-up-handle-form.tsx +0 -289
- package/src/assets/app/views/authorize/sign-up/sign-up-hcaptcha-form.tsx +0 -108
- package/src/assets/app/views/authorize/sign-up/sign-up-view.tsx +0 -158
- package/src/assets/app/views/authorize/welcome/welcome-view.tsx +0 -56
- package/src/assets/app/views/error/error-view.tsx +0 -31
- package/src/assets/asset.ts +0 -9
- package/src/assets/index.ts +0 -86
- package/tailwind.config.js +0 -31
- package/tsconfig.frontend.json +0 -11
- package/tsconfig.frontend.tsbuildinfo +0 -1
- package/tsconfig.tools.json +0 -8
- package/tsconfig.tools.tsbuildinfo +0 -1
- package/vite.config.mjs +0 -16
package/src/lib/util/type.ts
CHANGED
@@ -9,6 +9,24 @@ export type Override<T, V> = Simplify<{
|
|
9
9
|
}>
|
10
10
|
export type Awaitable<T> = T | Promise<T>
|
11
11
|
|
12
|
+
/**
|
13
|
+
* Converts a tuple to the equivalent type of combining every item into a single
|
14
|
+
* one. If any of the item in the tuple is non nullish, the result will be non
|
15
|
+
* nullish.
|
16
|
+
*/
|
17
|
+
export type CombinedTuple<T extends readonly unknown[]> = T extends []
|
18
|
+
? undefined
|
19
|
+
: Exclude<
|
20
|
+
T[number],
|
21
|
+
// If any item in the tuple is never `null` (resp. `undefined`), exclude
|
22
|
+
// `null` (resp. `undefined`) from `T[number]`
|
23
|
+
{
|
24
|
+
[K in keyof T]-?:
|
25
|
+
| (null extends T[K] ? never : null)
|
26
|
+
| (undefined extends T[K] ? never : undefined)
|
27
|
+
}[keyof T]
|
28
|
+
>
|
29
|
+
|
12
30
|
/**
|
13
31
|
* Similar to {@link Required} but also ensures that all values are defined.
|
14
32
|
*/
|
package/src/oauth-errors.ts
CHANGED
@@ -12,6 +12,7 @@ export { InvalidClientMetadataError } from './errors/invalid-client-metadata-err
|
|
12
12
|
export { InvalidDpopKeyBindingError } from './errors/invalid-dpop-key-binding-error.js'
|
13
13
|
export { InvalidDpopProofError } from './errors/invalid-dpop-proof-error.js'
|
14
14
|
export { InvalidGrantError } from './errors/invalid-grant-error.js'
|
15
|
+
export { InvalidInviteCodeError } from './errors/invalid-invite-code-error.js'
|
15
16
|
export { InvalidParametersError } from './errors/invalid-parameters-error.js'
|
16
17
|
export { InvalidRedirectUriError } from './errors/invalid-redirect-uri-error.js'
|
17
18
|
export { InvalidRequestError } from './errors/invalid-request-error.js'
|
package/src/oauth-hooks.ts
CHANGED
@@ -7,7 +7,7 @@ import {
|
|
7
7
|
} from '@atproto/oauth-types'
|
8
8
|
import { Account } from './account/account.js'
|
9
9
|
import { SignInData } from './account/sign-in-data.js'
|
10
|
-
import {
|
10
|
+
import { SignUpInput } from './account/sign-up-input.js'
|
11
11
|
import { ClientAuth } from './client/client-auth.js'
|
12
12
|
import { ClientId } from './client/client-id.js'
|
13
13
|
import { ClientInfo } from './client/client-info.js'
|
@@ -17,7 +17,7 @@ import { HcaptchaConfig, HcaptchaVerifyResult } from './lib/hcaptcha.js'
|
|
17
17
|
import { RequestMetadata } from './lib/http/request.js'
|
18
18
|
import { Awaitable } from './lib/util/type.js'
|
19
19
|
import { AccessDeniedError, OAuthError } from './oauth-errors.js'
|
20
|
-
import { DeviceAccountInfo, DeviceId } from './oauth-store.js'
|
20
|
+
import { DeviceAccountInfo, DeviceId, SignUpData } from './oauth-store.js'
|
21
21
|
|
22
22
|
// Make sure all types needed to implement the OAuthHooks are exported
|
23
23
|
export {
|
@@ -42,6 +42,7 @@ export {
|
|
42
42
|
type RequestMetadata,
|
43
43
|
type SignInData,
|
44
44
|
type SignUpData,
|
45
|
+
type SignUpInput,
|
45
46
|
}
|
46
47
|
|
47
48
|
export type OAuthHooks = {
|
@@ -71,36 +72,14 @@ export type OAuthHooks = {
|
|
71
72
|
account: Account
|
72
73
|
}) => Awaitable<undefined | OAuthAuthorizationDetails>
|
73
74
|
|
74
|
-
/**
|
75
|
-
* This hook is called whenever an hcaptcha challenge is verified
|
76
|
-
* during sign-up (if hcaptcha is enabled).
|
77
|
-
*
|
78
|
-
* @throws {InvalidRequestError} to deny the sign-up
|
79
|
-
*/
|
80
|
-
onSignupHcaptchaResult?: (data: {
|
81
|
-
data: SignUpData
|
82
|
-
/**
|
83
|
-
* This indicates not only wether the hCaptcha challenge succeeded, but also
|
84
|
-
* if the score was low enough according to the
|
85
|
-
* {@link HcaptchaConfig.scoreThreshold}.
|
86
|
-
*
|
87
|
-
* @see {@link HCaptchaClient.isAllowed}
|
88
|
-
*/
|
89
|
-
allowed: boolean
|
90
|
-
result: HcaptchaVerifyResult
|
91
|
-
deviceId: DeviceId
|
92
|
-
deviceMetadata: RequestMetadata
|
93
|
-
}) => Awaitable<void>
|
94
|
-
|
95
75
|
/**
|
96
76
|
* This hook is called when a user attempts to sign up, after every validation
|
97
77
|
* has passed (including hcaptcha).
|
98
78
|
*/
|
99
79
|
onSignupAttempt?: (data: {
|
100
|
-
|
80
|
+
input: SignUpInput
|
101
81
|
deviceId: DeviceId
|
102
82
|
deviceMetadata: RequestMetadata
|
103
|
-
hcaptchaResult?: HcaptchaVerifyResult
|
104
83
|
}) => Awaitable<void>
|
105
84
|
|
106
85
|
/**
|
package/src/oauth-provider.ts
CHANGED
@@ -45,7 +45,7 @@ import {
|
|
45
45
|
} from './account/account-store.js'
|
46
46
|
import { Account } from './account/account.js'
|
47
47
|
import { signInDataSchema } from './account/sign-in-data.js'
|
48
|
-
import {
|
48
|
+
import { signUpInputSchema } from './account/sign-up-input.js'
|
49
49
|
import { authorizeAssetsMiddleware } from './assets/assets-middleware.js'
|
50
50
|
import { ClientAuth, authJwkThumbprint } from './client/client-auth.js'
|
51
51
|
import {
|
@@ -1145,28 +1145,27 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1145
1145
|
* Wrap an OAuth endpoint in a middleware that will set the appropriate
|
1146
1146
|
* response headers and format the response as JSON.
|
1147
1147
|
*/
|
1148
|
-
const jsonHandler = <T, TReq extends Req, TRes extends Res,
|
1149
|
-
buildJson: (
|
1150
|
-
|
1148
|
+
const jsonHandler = <T, TReq extends Req, TRes extends Res, Payload>(
|
1149
|
+
buildJson: (
|
1150
|
+
this: T,
|
1151
|
+
req: TReq,
|
1152
|
+
res: TRes,
|
1153
|
+
) => Awaitable<{ payload: Payload; status?: number }>,
|
1151
1154
|
): Handler<T, TReq, TRes> =>
|
1152
1155
|
async function (req, res) {
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
}
|
1156
|
+
// https://www.rfc-editor.org/rfc/rfc6749.html#section-5.1
|
1157
|
+
res.setHeader('Cache-Control', 'no-store')
|
1158
|
+
res.setHeader('Pragma', 'no-cache')
|
1159
|
+
|
1160
|
+
// Ensure we can agree on a content encoding & type before starting to
|
1161
|
+
// build the JSON response.
|
1162
|
+
if (!negotiateContent(req, ['application/json'])) {
|
1163
|
+
throw createHttpError(406, 'Unsupported media type')
|
1164
|
+
}
|
1163
1165
|
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
} else if (!res.headersSent) {
|
1168
|
-
res.writeHead(status ?? 204).end()
|
1169
|
-
}
|
1166
|
+
try {
|
1167
|
+
const { payload, status = 200 } = await buildJson.call(this, req, res)
|
1168
|
+
writeJson(res, payload, { status })
|
1170
1169
|
} catch (err) {
|
1171
1170
|
onError?.(req, res, err, 'OAuth request error')
|
1172
1171
|
|
@@ -1180,13 +1179,13 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1180
1179
|
}
|
1181
1180
|
}
|
1182
1181
|
|
1183
|
-
const oauthHandler = <T, TReq extends Req, TRes extends Res,
|
1184
|
-
buildOAuthResponse: (this: T, req: TReq, res: TRes) => Awaitable<
|
1182
|
+
const oauthHandler = <T, TReq extends Req, TRes extends Res, Payload>(
|
1183
|
+
buildOAuthResponse: (this: T, req: TReq, res: TRes) => Awaitable<Payload>,
|
1185
1184
|
status?: number,
|
1186
1185
|
) =>
|
1187
1186
|
combineMiddlewares([
|
1188
1187
|
corsHeaders,
|
1189
|
-
jsonHandler<T, TReq, TRes,
|
1188
|
+
jsonHandler<T, TReq, TRes, Payload>(async function (req, res) {
|
1190
1189
|
try {
|
1191
1190
|
// https://datatracker.ietf.org/doc/html/rfc9449#section-8.2
|
1192
1191
|
const dpopNonce = server.nextDpopNonce()
|
@@ -1196,7 +1195,8 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1196
1195
|
res.appendHeader('Access-Control-Expose-Headers', name)
|
1197
1196
|
}
|
1198
1197
|
|
1199
|
-
|
1198
|
+
const payload = await buildOAuthResponse.call(this, req, res)
|
1199
|
+
return { payload, status }
|
1200
1200
|
} catch (err) {
|
1201
1201
|
if (!res.headersSent && err instanceof WWWAuthenticateError) {
|
1202
1202
|
const name = 'WWW-Authenticate'
|
@@ -1206,7 +1206,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1206
1206
|
|
1207
1207
|
throw err
|
1208
1208
|
}
|
1209
|
-
}
|
1209
|
+
}),
|
1210
1210
|
])
|
1211
1211
|
|
1212
1212
|
const apiHandler = <
|
@@ -1214,7 +1214,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1214
1214
|
TReq extends Req,
|
1215
1215
|
TRes extends Res,
|
1216
1216
|
S extends z.ZodTypeAny,
|
1217
|
-
|
1217
|
+
Payload,
|
1218
1218
|
>(
|
1219
1219
|
inputSchema: S,
|
1220
1220
|
buildJson: (
|
@@ -1223,10 +1223,10 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1223
1223
|
res: TRes,
|
1224
1224
|
input: z.infer<S>,
|
1225
1225
|
context: ApiContext,
|
1226
|
-
) =>
|
1226
|
+
) => Awaitable<Payload>,
|
1227
1227
|
status?: number,
|
1228
1228
|
) =>
|
1229
|
-
jsonHandler<T, TReq, TRes,
|
1229
|
+
jsonHandler<T, TReq, TRes, Payload>(async function (req, res) {
|
1230
1230
|
validateFetchMode(req, res, ['same-origin'])
|
1231
1231
|
validateFetchSite(req, res, ['same-origin'])
|
1232
1232
|
validateSameOrigin(req, res, issuerOrigin)
|
@@ -1252,12 +1252,13 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1252
1252
|
res,
|
1253
1253
|
)
|
1254
1254
|
|
1255
|
-
const
|
1256
|
-
const input = await inputSchema.parseAsync(
|
1255
|
+
const inputRaw = await parseHttpRequest(req, ['json'])
|
1256
|
+
const input = await inputSchema.parseAsync(inputRaw, { path: ['body'] })
|
1257
1257
|
|
1258
1258
|
const context: ApiContext = { requestUri, deviceId, deviceMetadata }
|
1259
|
-
|
1260
|
-
|
1259
|
+
const payload = await buildJson.call(this, req, res, input, context)
|
1260
|
+
return { payload, status }
|
1261
|
+
})
|
1261
1262
|
|
1262
1263
|
const navigationHandler = <T, TReq extends Req, TRes extends Res>(
|
1263
1264
|
handler: (this: T, req: TReq, res: TRes) => Awaitable<void>,
|
@@ -1478,6 +1479,8 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1478
1479
|
} catch (err) {
|
1479
1480
|
onError?.(req, res, err, 'Failed to revoke token')
|
1480
1481
|
}
|
1482
|
+
|
1483
|
+
return {}
|
1481
1484
|
}),
|
1482
1485
|
)
|
1483
1486
|
router.get(
|
@@ -1577,14 +1580,15 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1577
1580
|
apiHandler(
|
1578
1581
|
z.object({ handle: handleSchema }).strict(),
|
1579
1582
|
async function (req, res, data) {
|
1580
|
-
|
1583
|
+
await server.accountManager.verifyHandleAvailability(data.handle)
|
1584
|
+
return { available: true }
|
1581
1585
|
},
|
1582
1586
|
),
|
1583
1587
|
)
|
1584
1588
|
|
1585
1589
|
router.post(
|
1586
1590
|
'/oauth/authorize/sign-up',
|
1587
|
-
apiHandler(
|
1591
|
+
apiHandler(signUpInputSchema, async function (req, res, data, ctx) {
|
1588
1592
|
return server.signUp(ctx, data)
|
1589
1593
|
}),
|
1590
1594
|
)
|
@@ -1602,6 +1606,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1602
1606
|
resetPasswordRequestDataSchema,
|
1603
1607
|
async function (req, res, data) {
|
1604
1608
|
await server.accountManager.resetPasswordRequest(data)
|
1609
|
+
return { success: true }
|
1605
1610
|
},
|
1606
1611
|
),
|
1607
1612
|
)
|
@@ -1612,6 +1617,7 @@ export class OAuthProvider extends OAuthVerifier {
|
|
1612
1617
|
resetPasswordConfirmDataSchema,
|
1613
1618
|
async function (req, res, data) {
|
1614
1619
|
await server.accountManager.resetPasswordConfirm(data)
|
1620
|
+
return { success: true }
|
1615
1621
|
},
|
1616
1622
|
),
|
1617
1623
|
)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { Html, js } from '../lib/html/index.js'
|
2
|
+
|
3
|
+
export function declareBackendData(values: Record<string, unknown>): Html {
|
4
|
+
return Html.dangerouslyCreate(backendDataGenerator(values))
|
5
|
+
}
|
6
|
+
|
7
|
+
export function* backendDataGenerator(
|
8
|
+
values: Record<string, unknown>,
|
9
|
+
): Generator<Html> {
|
10
|
+
for (const [key, val] of Object.entries(values)) {
|
11
|
+
yield js`window[${key}]=${val};`
|
12
|
+
}
|
13
|
+
// The script tag is removed after the data is assigned to the global
|
14
|
+
// variables to prevent other scripts from reading the values. The "app"
|
15
|
+
// script will read the global variable and then unset it. See
|
16
|
+
// `readBackendData()` in "src/assets/app/backend-data.ts".
|
17
|
+
yield js`document.currentScript.remove();`
|
18
|
+
}
|
@@ -1,7 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
OAuthClientMetadata,
|
4
|
-
} from '@atproto/oauth-types'
|
1
|
+
import type { AuthorizeData, Session } from '@atproto/oauth-provider-api'
|
2
|
+
import { OAuthAuthorizationRequestParameters } from '@atproto/oauth-types'
|
5
3
|
import { DeviceAccountInfo } from '../account/account-store.js'
|
6
4
|
import { Account } from '../account/account.js'
|
7
5
|
import { Client } from '../client/client.js'
|
@@ -30,28 +28,7 @@ export type AuthorizationResultAuthorize = {
|
|
30
28
|
}
|
31
29
|
}
|
32
30
|
|
33
|
-
|
34
|
-
// (app/backend-types.ts)
|
35
|
-
|
36
|
-
type Session = {
|
37
|
-
account: Account
|
38
|
-
info?: never // Prevent accidental leaks to frontend
|
39
|
-
|
40
|
-
selected: boolean
|
41
|
-
loginRequired: boolean
|
42
|
-
consentRequired: boolean
|
43
|
-
}
|
44
|
-
|
45
|
-
export type AuthorizeData = {
|
46
|
-
clientId: string
|
47
|
-
clientMetadata: OAuthClientMetadata
|
48
|
-
clientTrusted: boolean
|
49
|
-
requestUri: string
|
50
|
-
loginHint?: string
|
51
|
-
scopeDetails?: ScopeDetail[]
|
52
|
-
newSessionsRequireConsent: boolean
|
53
|
-
sessions: Session[]
|
54
|
-
}
|
31
|
+
export type { AuthorizeData, Session }
|
55
32
|
|
56
33
|
export function buildAuthorizeData(
|
57
34
|
data: AuthorizationResultAuthorize,
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { z } from 'zod'
|
2
|
+
import { CustomizationData } from '@atproto/oauth-provider-api'
|
2
3
|
import { hcaptchaConfigSchema } from '../lib/hcaptcha.js'
|
3
4
|
import { isLinkRel } from '../lib/html/build-document.js'
|
4
5
|
import { multiLangStringSchema } from '../lib/locale.js'
|
@@ -59,7 +60,7 @@ export const brandingConfigSchema = z.object({
|
|
59
60
|
name: z.string().optional(),
|
60
61
|
logo: z.string().optional(),
|
61
62
|
colors: colorsDefinitionSchema.optional(),
|
62
|
-
links: z.array(linkDefinitionSchema).
|
63
|
+
links: z.array(linkDefinitionSchema).optional(),
|
63
64
|
})
|
64
65
|
export type BrandingInput = z.input<typeof brandingConfigSchema>
|
65
66
|
export type Branding = z.infer<typeof brandingConfigSchema>
|
@@ -86,18 +87,6 @@ export const customizationSchema = z.object({
|
|
86
87
|
export type CustomizationInput = z.input<typeof customizationSchema>
|
87
88
|
export type Customization = z.infer<typeof customizationSchema>
|
88
89
|
|
89
|
-
export type CustomizationData = {
|
90
|
-
// Functional customization
|
91
|
-
hcaptchaSiteKey?: string
|
92
|
-
inviteCodeRequired?: boolean
|
93
|
-
availableUserDomains?: string[]
|
94
|
-
|
95
|
-
// Aesthetic customization
|
96
|
-
name?: string
|
97
|
-
logo?: string
|
98
|
-
links?: readonly LinkDefinition[]
|
99
|
-
}
|
100
|
-
|
101
90
|
export function buildCustomizationData({
|
102
91
|
branding,
|
103
92
|
availableUserDomains,
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import { ErrorData } from '@atproto/oauth-provider-api'
|
2
|
+
import { buildErrorPayload } from './build-error-payload.js'
|
3
|
+
|
4
|
+
// @NOTE: The primary role of this function is to ensure that the ErrorPayload
|
5
|
+
// and ErrorData types are in sync.
|
6
|
+
export function buildErrorData(error: unknown): ErrorData {
|
7
|
+
return buildErrorPayload(error)
|
8
|
+
}
|
@@ -50,10 +50,12 @@ export function buildErrorStatus(error: unknown): number {
|
|
50
50
|
return 500
|
51
51
|
}
|
52
52
|
|
53
|
-
export
|
53
|
+
export type ErrorPayload = {
|
54
54
|
error: string
|
55
55
|
error_description: string
|
56
|
-
}
|
56
|
+
}
|
57
|
+
|
58
|
+
export function buildErrorPayload(error: unknown): ErrorPayload {
|
57
59
|
if (error instanceof OAuthError) {
|
58
60
|
return error.toJSON()
|
59
61
|
}
|
@@ -1,8 +1,10 @@
|
|
1
1
|
import type { ServerResponse } from 'node:http'
|
2
|
-
import {
|
3
|
-
import {
|
2
|
+
import { CustomizationData } from '@atproto/oauth-provider-api'
|
3
|
+
import { assets } from '@atproto/oauth-provider-ui'
|
4
|
+
import { buildAssetUrl } from '../assets/assets-middleware.js'
|
4
5
|
import { CspConfig, mergeCsp } from '../lib/csp/index.js'
|
5
6
|
import {
|
7
|
+
AssetRef,
|
6
8
|
Html,
|
7
9
|
LinkAttrs,
|
8
10
|
MetaAttrs,
|
@@ -10,7 +12,9 @@ import {
|
|
10
12
|
html,
|
11
13
|
isLinkRel,
|
12
14
|
} from '../lib/html/index.js'
|
15
|
+
import { CrossOriginEmbedderPolicy } from '../lib/http/security-headers.js'
|
13
16
|
import { AVAILABLE_LOCALES, Locale, isAvailableLocale } from '../lib/locale.js'
|
17
|
+
import { declareBackendData } from './backend-data.js'
|
14
18
|
import {
|
15
19
|
AuthorizationResultAuthorize,
|
16
20
|
buildAuthorizeData,
|
@@ -21,15 +25,28 @@ import {
|
|
21
25
|
buildCustomizationCss,
|
22
26
|
buildCustomizationData,
|
23
27
|
} from './build-customization-data.js'
|
24
|
-
import {
|
25
|
-
import {
|
28
|
+
import { buildErrorData } from './build-error-data.js'
|
29
|
+
import { buildErrorStatus } from './build-error-payload.js'
|
30
|
+
import { sendWebPage } from './send-web-page.js'
|
31
|
+
|
32
|
+
const BASE_CSP: CspConfig = {
|
33
|
+
// API calls are made to the same origin
|
34
|
+
'connect-src': ["'self'"],
|
35
|
+
// Allow loading of PDS logo & User avatars
|
36
|
+
'img-src': ['data:', 'https:'],
|
37
|
+
// Prevent embedding in iframes
|
38
|
+
'frame-ancestors': ["'none'"],
|
39
|
+
}
|
26
40
|
|
27
|
-
|
41
|
+
/**
|
42
|
+
* @see {@link https://docs.hcaptcha.com/#content-security-policy-settings}
|
43
|
+
*/
|
44
|
+
const HCAPTCHA_CSP: CspConfig = {
|
28
45
|
'script-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
|
29
46
|
'frame-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
|
30
47
|
'style-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
|
31
48
|
'connect-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
|
32
|
-
}
|
49
|
+
}
|
33
50
|
|
34
51
|
export type SendPageOptions = {
|
35
52
|
preferredLocales?: readonly string[]
|
@@ -41,43 +58,57 @@ export class OutputManager {
|
|
41
58
|
{ name: 'robots', content: 'noindex' },
|
42
59
|
{ name: 'description', content: 'ATProto OAuth authorization page' },
|
43
60
|
]
|
44
|
-
readonly scripts: readonly (Asset | Html)[]
|
45
|
-
readonly styles: readonly (Asset | Html)[]
|
46
61
|
readonly csp: CspConfig
|
62
|
+
readonly coep: CrossOriginEmbedderPolicy
|
63
|
+
readonly customizationData: CustomizationData
|
64
|
+
readonly customizationCss: Html
|
47
65
|
|
48
66
|
constructor(customization: Customization) {
|
49
67
|
this.links = customization.branding?.links
|
50
68
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
// Note: building scripts/styles/csp here for two reasons:
|
55
|
-
// 1. To avoid re-building it on every request
|
56
|
-
// 2. To throw during init if the customization/config is invalid
|
57
|
-
|
58
|
-
this.scripts = [
|
59
|
-
declareBackendData('__availableLocales', AVAILABLE_LOCALES),
|
60
|
-
declareBackendData(
|
61
|
-
'__customizationData',
|
62
|
-
buildCustomizationData(customization),
|
63
|
-
),
|
64
|
-
// Last (to be able to read the "backend data" variables)
|
65
|
-
...scripts.filter((asset) => asset.isEntry),
|
66
|
-
]
|
67
|
-
|
68
|
-
this.styles = [
|
69
|
-
// First (to be overridden by customization)
|
70
|
-
...styles,
|
71
|
-
cssCode(buildCustomizationCss(customization)),
|
72
|
-
]
|
73
|
-
|
74
|
-
const customizationCsp = customization?.hcaptcha ? HCAPTCHA_CSP : undefined
|
75
|
-
const assetsCsp: CspConfig = {
|
76
|
-
'script-src': scripts.map(assetToCsp),
|
77
|
-
'style-src': styles.map(assetToCsp),
|
78
|
-
}
|
69
|
+
// "cache" these:
|
70
|
+
this.customizationData = buildCustomizationData(customization)
|
71
|
+
this.customizationCss = cssCode(buildCustomizationCss(customization))
|
79
72
|
|
80
|
-
this.csp = mergeCsp(
|
73
|
+
this.csp = mergeCsp(
|
74
|
+
BASE_CSP,
|
75
|
+
customization?.hcaptcha ? HCAPTCHA_CSP : undefined,
|
76
|
+
)
|
77
|
+
// Because we are loading avatar images from external sources, that might
|
78
|
+
// not have CORP headers set, we need to use at least "credentialless".
|
79
|
+
this.coep = customization?.hcaptcha
|
80
|
+
? // https://github.com/hCaptcha/react-hcaptcha/issues/259
|
81
|
+
// @TODO Remove the use of `unsafeNone` once the issue above is resolved
|
82
|
+
CrossOriginEmbedderPolicy.unsafeNone
|
83
|
+
: CrossOriginEmbedderPolicy.credentialless
|
84
|
+
}
|
85
|
+
|
86
|
+
buildAssets(
|
87
|
+
name: string,
|
88
|
+
backendData: Record<string, unknown>,
|
89
|
+
): {
|
90
|
+
scripts: (AssetRef | Html)[]
|
91
|
+
styles: (AssetRef | Html)[]
|
92
|
+
} {
|
93
|
+
return {
|
94
|
+
scripts: [
|
95
|
+
declareBackendData(backendData),
|
96
|
+
// After backend injected data
|
97
|
+
...Array.from(assets)
|
98
|
+
.filter(
|
99
|
+
([, item]) =>
|
100
|
+
item.type === 'chunk' && item.isEntry && item.name === name,
|
101
|
+
)
|
102
|
+
.map(([filename]) => ({ url: buildAssetUrl(filename) })),
|
103
|
+
],
|
104
|
+
styles: [
|
105
|
+
...Array.from(assets)
|
106
|
+
.filter(([, item]) => item.mime === 'text/css')
|
107
|
+
.map(([filename]) => ({ url: buildAssetUrl(filename) })),
|
108
|
+
// Last (to be able to override the default styles)
|
109
|
+
this.customizationCss,
|
110
|
+
],
|
111
|
+
}
|
81
112
|
}
|
82
113
|
|
83
114
|
async sendAuthorizePage(
|
@@ -89,17 +120,21 @@ export class OutputManager {
|
|
89
120
|
data.parameters.ui_locales?.split(' ') ?? options?.preferredLocales,
|
90
121
|
)
|
91
122
|
|
123
|
+
const { scripts, styles } = this.buildAssets('authorization-page', {
|
124
|
+
__availableLocales: AVAILABLE_LOCALES,
|
125
|
+
__customizationData: this.customizationData,
|
126
|
+
__authorizeData: buildAuthorizeData(data),
|
127
|
+
})
|
128
|
+
|
92
129
|
return sendWebPage(res, {
|
93
|
-
scripts
|
94
|
-
|
95
|
-
...this.scripts,
|
96
|
-
],
|
97
|
-
styles: this.styles,
|
130
|
+
scripts,
|
131
|
+
styles,
|
98
132
|
meta: this.meta,
|
99
133
|
links: this.buildLinks(locale),
|
100
134
|
htmlAttrs: { lang: locale },
|
101
135
|
body: html`<div id="root"></div>`,
|
102
136
|
csp: this.csp,
|
137
|
+
coep: this.coep,
|
103
138
|
})
|
104
139
|
}
|
105
140
|
|
@@ -110,18 +145,22 @@ export class OutputManager {
|
|
110
145
|
): Promise<void> {
|
111
146
|
const locale = negotiateLocale(options?.preferredLocales)
|
112
147
|
|
148
|
+
const { scripts, styles } = this.buildAssets('error-page', {
|
149
|
+
__availableLocales: AVAILABLE_LOCALES,
|
150
|
+
__customizationData: this.customizationData,
|
151
|
+
__errorData: buildErrorData(err),
|
152
|
+
})
|
153
|
+
|
113
154
|
return sendWebPage(res, {
|
114
155
|
status: buildErrorStatus(err),
|
115
|
-
scripts
|
116
|
-
|
117
|
-
...this.scripts,
|
118
|
-
],
|
119
|
-
styles: this.styles,
|
156
|
+
scripts,
|
157
|
+
styles,
|
120
158
|
meta: this.meta,
|
121
159
|
links: this.buildLinks(locale),
|
122
160
|
htmlAttrs: { lang: locale },
|
123
161
|
body: html`<div id="root"></div>`,
|
124
162
|
csp: this.csp,
|
163
|
+
coep: this.coep,
|
125
164
|
})
|
126
165
|
}
|
127
166
|
|