@atproto/oauth-provider 0.1.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/.postcssrc.yml +3 -0
- package/CHANGELOG.md +19 -0
- package/LICENSE.txt +7 -0
- package/dist/access-token/access-token-type.d.ts +6 -0
- package/dist/access-token/access-token-type.d.ts.map +1 -0
- package/dist/access-token/access-token-type.js +10 -0
- package/dist/access-token/access-token-type.js.map +1 -0
- package/dist/account/account-manager.d.ts +14 -0
- package/dist/account/account-manager.d.ts.map +1 -0
- package/dist/account/account-manager.js +39 -0
- package/dist/account/account-manager.js.map +1 -0
- package/dist/account/account-store.d.ts +39 -0
- package/dist/account/account-store.d.ts.map +1 -0
- package/dist/account/account-store.js +19 -0
- package/dist/account/account-store.js.map +1 -0
- package/dist/account/account.d.ts +8 -0
- package/dist/account/account.d.ts.map +1 -0
- package/dist/account/account.js +3 -0
- package/dist/account/account.js.map +1 -0
- package/dist/assets/app/bundle-manifest.json +22 -0
- package/dist/assets/app/main.css +3 -0
- package/dist/assets/app/main.js +20 -0
- package/dist/assets/app/main.js.map +1 -0
- package/dist/assets/asset.d.ts +9 -0
- package/dist/assets/asset.d.ts.map +1 -0
- package/dist/assets/asset.js +3 -0
- package/dist/assets/asset.js.map +1 -0
- package/dist/assets/assets-middleware.d.ts +2 -0
- package/dist/assets/assets-middleware.d.ts.map +1 -0
- package/dist/assets/assets-middleware.js +30 -0
- package/dist/assets/assets-middleware.js.map +1 -0
- package/dist/assets/index.d.ts +4 -0
- package/dist/assets/index.d.ts.map +1 -0
- package/dist/assets/index.js +65 -0
- package/dist/assets/index.js.map +1 -0
- package/dist/client/client-auth.d.ts +13 -0
- package/dist/client/client-auth.d.ts.map +1 -0
- package/dist/client/client-auth.js +35 -0
- package/dist/client/client-auth.js.map +1 -0
- package/dist/client/client-data.d.ts +8 -0
- package/dist/client/client-data.d.ts.map +1 -0
- package/dist/client/client-data.js +3 -0
- package/dist/client/client-data.js.map +1 -0
- package/dist/client/client-id.d.ts +4 -0
- package/dist/client/client-id.d.ts.map +1 -0
- package/dist/client/client-id.js +6 -0
- package/dist/client/client-id.js.map +1 -0
- package/dist/client/client-info.d.ts +13 -0
- package/dist/client/client-info.d.ts.map +1 -0
- package/dist/client/client-info.js +3 -0
- package/dist/client/client-info.js.map +1 -0
- package/dist/client/client-manager.d.ts +38 -0
- package/dist/client/client-manager.d.ts.map +1 -0
- package/dist/client/client-manager.js +534 -0
- package/dist/client/client-manager.js.map +1 -0
- package/dist/client/client-store.d.ts +13 -0
- package/dist/client/client-store.d.ts.map +1 -0
- package/dist/client/client-store.js +39 -0
- package/dist/client/client-store.js.map +1 -0
- package/dist/client/client-utils.d.ts +6 -0
- package/dist/client/client-utils.d.ts.map +1 -0
- package/dist/client/client-utils.js +40 -0
- package/dist/client/client-utils.js.map +1 -0
- package/dist/client/client.d.ts +41 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +163 -0
- package/dist/client/client.js.map +1 -0
- package/dist/constants.d.ts +42 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +53 -0
- package/dist/constants.js.map +1 -0
- package/dist/device/device-data.d.ts +20 -0
- package/dist/device/device-data.d.ts.map +1 -0
- package/dist/device/device-data.js +11 -0
- package/dist/device/device-data.js.map +1 -0
- package/dist/device/device-details.d.ts +17 -0
- package/dist/device/device-details.d.ts.map +1 -0
- package/dist/device/device-details.js +34 -0
- package/dist/device/device-details.js.map +1 -0
- package/dist/device/device-id.d.ts +6 -0
- package/dist/device/device-id.d.ts.map +1 -0
- package/dist/device/device-id.js +18 -0
- package/dist/device/device-id.js.map +1 -0
- package/dist/device/device-manager.d.ts +88 -0
- package/dist/device/device-manager.d.ts.map +1 -0
- package/dist/device/device-manager.js +206 -0
- package/dist/device/device-manager.js.map +1 -0
- package/dist/device/device-store.d.ts +15 -0
- package/dist/device/device-store.d.ts.map +1 -0
- package/dist/device/device-store.js +36 -0
- package/dist/device/device-store.js.map +1 -0
- package/dist/device/session-id.d.ts +6 -0
- package/dist/device/session-id.d.ts.map +1 -0
- package/dist/device/session-id.js +18 -0
- package/dist/device/session-id.js.map +1 -0
- package/dist/dpop/dpop-manager.d.ts +33 -0
- package/dist/dpop/dpop-manager.d.ts.map +1 -0
- package/dist/dpop/dpop-manager.js +115 -0
- package/dist/dpop/dpop-manager.js.map +1 -0
- package/dist/dpop/dpop-nonce.d.ts +13 -0
- package/dist/dpop/dpop-nonce.d.ts.map +1 -0
- package/dist/dpop/dpop-nonce.js +94 -0
- package/dist/dpop/dpop-nonce.js.map +1 -0
- package/dist/errors/access-denied-error.d.ts +8 -0
- package/dist/errors/access-denied-error.d.ts.map +1 -0
- package/dist/errors/access-denied-error.js +21 -0
- package/dist/errors/access-denied-error.js.map +1 -0
- package/dist/errors/account-selection-required-error.d.ts +6 -0
- package/dist/errors/account-selection-required-error.d.ts.map +1 -0
- package/dist/errors/account-selection-required-error.js +11 -0
- package/dist/errors/account-selection-required-error.js.map +1 -0
- package/dist/errors/consent-required-error.d.ts +6 -0
- package/dist/errors/consent-required-error.d.ts.map +1 -0
- package/dist/errors/consent-required-error.js +11 -0
- package/dist/errors/consent-required-error.js.map +1 -0
- package/dist/errors/invalid-authorization-details-error.d.ts +20 -0
- package/dist/errors/invalid-authorization-details-error.d.ts.map +1 -0
- package/dist/errors/invalid-authorization-details-error.js +26 -0
- package/dist/errors/invalid-authorization-details-error.js.map +1 -0
- package/dist/errors/invalid-client-error.d.ts +18 -0
- package/dist/errors/invalid-client-error.d.ts.map +1 -0
- package/dist/errors/invalid-client-error.js +24 -0
- package/dist/errors/invalid-client-error.js.map +1 -0
- package/dist/errors/invalid-client-id-error.d.ts +13 -0
- package/dist/errors/invalid-client-id-error.d.ts.map +1 -0
- package/dist/errors/invalid-client-id-error.js +25 -0
- package/dist/errors/invalid-client-id-error.js.map +1 -0
- package/dist/errors/invalid-client-metadata-error.d.ts +13 -0
- package/dist/errors/invalid-client-metadata-error.d.ts.map +1 -0
- package/dist/errors/invalid-client-metadata-error.js +23 -0
- package/dist/errors/invalid-client-metadata-error.js.map +1 -0
- package/dist/errors/invalid-dpop-key-binding-error.d.ts +12 -0
- package/dist/errors/invalid-dpop-key-binding-error.d.ts.map +1 -0
- package/dist/errors/invalid-dpop-key-binding-error.js +20 -0
- package/dist/errors/invalid-dpop-key-binding-error.js.map +1 -0
- package/dist/errors/invalid-dpop-proof-error.d.ts +5 -0
- package/dist/errors/invalid-dpop-proof-error.d.ts.map +1 -0
- package/dist/errors/invalid-dpop-proof-error.js +12 -0
- package/dist/errors/invalid-dpop-proof-error.js.map +1 -0
- package/dist/errors/invalid-grant-error.d.ts +14 -0
- package/dist/errors/invalid-grant-error.d.ts.map +1 -0
- package/dist/errors/invalid-grant-error.js +20 -0
- package/dist/errors/invalid-grant-error.js.map +1 -0
- package/dist/errors/invalid-parameters-error.d.ts +6 -0
- package/dist/errors/invalid-parameters-error.d.ts.map +1 -0
- package/dist/errors/invalid-parameters-error.js +11 -0
- package/dist/errors/invalid-parameters-error.js.map +1 -0
- package/dist/errors/invalid-redirect-uri-error.d.ts +11 -0
- package/dist/errors/invalid-redirect-uri-error.d.ts.map +1 -0
- package/dist/errors/invalid-redirect-uri-error.js +21 -0
- package/dist/errors/invalid-redirect-uri-error.js.map +1 -0
- package/dist/errors/invalid-request-error.d.ts +28 -0
- package/dist/errors/invalid-request-error.d.ts.map +1 -0
- package/dist/errors/invalid-request-error.js +34 -0
- package/dist/errors/invalid-request-error.js.map +1 -0
- package/dist/errors/invalid-token-error.d.ts +16 -0
- package/dist/errors/invalid-token-error.d.ts.map +1 -0
- package/dist/errors/invalid-token-error.js +45 -0
- package/dist/errors/invalid-token-error.js.map +1 -0
- package/dist/errors/login-required-error.d.ts +6 -0
- package/dist/errors/login-required-error.d.ts.map +1 -0
- package/dist/errors/login-required-error.js +11 -0
- package/dist/errors/login-required-error.js.map +1 -0
- package/dist/errors/oauth-error.d.ts +13 -0
- package/dist/errors/oauth-error.d.ts.map +1 -0
- package/dist/errors/oauth-error.js +29 -0
- package/dist/errors/oauth-error.js.map +1 -0
- package/dist/errors/unauthorized-client-error.d.ts +18 -0
- package/dist/errors/unauthorized-client-error.d.ts.map +1 -0
- package/dist/errors/unauthorized-client-error.js +24 -0
- package/dist/errors/unauthorized-client-error.js.map +1 -0
- package/dist/errors/use-dpop-nonce-error.d.ts +18 -0
- package/dist/errors/use-dpop-nonce-error.d.ts.map +1 -0
- package/dist/errors/use-dpop-nonce-error.js +27 -0
- package/dist/errors/use-dpop-nonce-error.js.map +1 -0
- package/dist/errors/www-authenticate-error.d.ts +9 -0
- package/dist/errors/www-authenticate-error.d.ts.map +1 -0
- package/dist/errors/www-authenticate-error.js +46 -0
- package/dist/errors/www-authenticate-error.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/html/build-document.d.ts +32 -0
- package/dist/lib/html/build-document.d.ts.map +1 -0
- package/dist/lib/html/build-document.js +61 -0
- package/dist/lib/html/build-document.js.map +1 -0
- package/dist/lib/html/escapers.d.ts +9 -0
- package/dist/lib/html/escapers.d.ts.map +1 -0
- package/dist/lib/html/escapers.js +66 -0
- package/dist/lib/html/escapers.js.map +1 -0
- package/dist/lib/html/html.d.ts +13 -0
- package/dist/lib/html/html.d.ts.map +1 -0
- package/dist/lib/html/html.js +53 -0
- package/dist/lib/html/html.js.map +1 -0
- package/dist/lib/html/index.d.ts +4 -0
- package/dist/lib/html/index.d.ts.map +1 -0
- package/dist/lib/html/index.js +21 -0
- package/dist/lib/html/index.js.map +1 -0
- package/dist/lib/html/tags.d.ts +34 -0
- package/dist/lib/html/tags.d.ts.map +1 -0
- package/dist/lib/html/tags.js +47 -0
- package/dist/lib/html/tags.js.map +1 -0
- package/dist/lib/html/util.d.ts +4 -0
- package/dist/lib/html/util.d.ts.map +1 -0
- package/dist/lib/html/util.js +20 -0
- package/dist/lib/html/util.js.map +1 -0
- package/dist/lib/http/accept.d.ts +29 -0
- package/dist/lib/http/accept.d.ts.map +1 -0
- package/dist/lib/http/accept.js +67 -0
- package/dist/lib/http/accept.js.map +1 -0
- package/dist/lib/http/context.d.ts +5 -0
- package/dist/lib/http/context.d.ts.map +1 -0
- package/dist/lib/http/context.js +10 -0
- package/dist/lib/http/context.js.map +1 -0
- package/dist/lib/http/index.d.ts +10 -0
- package/dist/lib/http/index.d.ts.map +1 -0
- package/dist/lib/http/index.js +26 -0
- package/dist/lib/http/index.js.map +1 -0
- package/dist/lib/http/method.d.ts +6 -0
- package/dist/lib/http/method.d.ts.map +1 -0
- package/dist/lib/http/method.js +19 -0
- package/dist/lib/http/method.js.map +1 -0
- package/dist/lib/http/middleware.d.ts +18 -0
- package/dist/lib/http/middleware.d.ts.map +1 -0
- package/dist/lib/http/middleware.js +118 -0
- package/dist/lib/http/middleware.js.map +1 -0
- package/dist/lib/http/parser.d.ts +33 -0
- package/dist/lib/http/parser.d.ts.map +1 -0
- package/dist/lib/http/parser.js +48 -0
- package/dist/lib/http/parser.js.map +1 -0
- package/dist/lib/http/path.d.ts +9 -0
- package/dist/lib/http/path.d.ts.map +1 -0
- package/dist/lib/http/path.js +54 -0
- package/dist/lib/http/path.js.map +1 -0
- package/dist/lib/http/request.d.ts +33 -0
- package/dist/lib/http/request.d.ts.map +1 -0
- package/dist/lib/http/request.js +86 -0
- package/dist/lib/http/request.js.map +1 -0
- package/dist/lib/http/response.d.ts +13 -0
- package/dist/lib/http/response.d.ts.map +1 -0
- package/dist/lib/http/response.js +98 -0
- package/dist/lib/http/response.js.map +1 -0
- package/dist/lib/http/route.d.ts +25 -0
- package/dist/lib/http/route.d.ts.map +1 -0
- package/dist/lib/http/route.js +39 -0
- package/dist/lib/http/route.js.map +1 -0
- package/dist/lib/http/router.d.ts +32 -0
- package/dist/lib/http/router.d.ts.map +1 -0
- package/dist/lib/http/router.js +74 -0
- package/dist/lib/http/router.js.map +1 -0
- package/dist/lib/http/stream.d.ts +13 -0
- package/dist/lib/http/stream.d.ts.map +1 -0
- package/dist/lib/http/stream.js +46 -0
- package/dist/lib/http/stream.js.map +1 -0
- package/dist/lib/http/types.d.ts +7 -0
- package/dist/lib/http/types.d.ts.map +1 -0
- package/dist/lib/http/types.js +3 -0
- package/dist/lib/http/types.js.map +1 -0
- package/dist/lib/http/url.d.ts +8 -0
- package/dist/lib/http/url.d.ts.map +1 -0
- package/dist/lib/http/url.js +22 -0
- package/dist/lib/http/url.js.map +1 -0
- package/dist/lib/redis.d.ts +5 -0
- package/dist/lib/redis.d.ts.map +1 -0
- package/dist/lib/redis.js +22 -0
- package/dist/lib/redis.js.map +1 -0
- package/dist/lib/util/authorization-header.d.ts +4 -0
- package/dist/lib/util/authorization-header.d.ts.map +1 -0
- package/dist/lib/util/authorization-header.js +23 -0
- package/dist/lib/util/authorization-header.js.map +1 -0
- package/dist/lib/util/cast.d.ts +2 -0
- package/dist/lib/util/cast.d.ts.map +1 -0
- package/dist/lib/util/cast.js +10 -0
- package/dist/lib/util/cast.js.map +1 -0
- package/dist/lib/util/crypto.d.ts +3 -0
- package/dist/lib/util/crypto.d.ts.map +1 -0
- package/dist/lib/util/crypto.js +29 -0
- package/dist/lib/util/crypto.js.map +1 -0
- package/dist/lib/util/date.d.ts +3 -0
- package/dist/lib/util/date.d.ts.map +1 -0
- package/dist/lib/util/date.js +12 -0
- package/dist/lib/util/date.js.map +1 -0
- package/dist/lib/util/hostname.d.ts +6 -0
- package/dist/lib/util/hostname.d.ts.map +1 -0
- package/dist/lib/util/hostname.js +24 -0
- package/dist/lib/util/hostname.js.map +1 -0
- package/dist/lib/util/redirect-uri.d.ts +7 -0
- package/dist/lib/util/redirect-uri.d.ts.map +1 -0
- package/dist/lib/util/redirect-uri.js +44 -0
- package/dist/lib/util/redirect-uri.js.map +1 -0
- package/dist/lib/util/time.d.ts +6 -0
- package/dist/lib/util/time.d.ts.map +1 -0
- package/dist/lib/util/time.js +28 -0
- package/dist/lib/util/time.js.map +1 -0
- package/dist/lib/util/type.d.ts +6 -0
- package/dist/lib/util/type.d.ts.map +1 -0
- package/dist/lib/util/type.js +3 -0
- package/dist/lib/util/type.js.map +1 -0
- package/dist/lib/util/well-known.d.ts +3 -0
- package/dist/lib/util/well-known.d.ts.map +1 -0
- package/dist/lib/util/well-known.js +11 -0
- package/dist/lib/util/well-known.js.map +1 -0
- package/dist/metadata/build-metadata.d.ts +14 -0
- package/dist/metadata/build-metadata.d.ts.map +1 -0
- package/dist/metadata/build-metadata.js +132 -0
- package/dist/metadata/build-metadata.js.map +1 -0
- package/dist/oauth-client.d.ts +4 -0
- package/dist/oauth-client.d.ts.map +1 -0
- package/dist/oauth-client.js +19 -0
- package/dist/oauth-client.js.map +1 -0
- package/dist/oauth-dpop.d.ts +3 -0
- package/dist/oauth-dpop.d.ts.map +1 -0
- package/dist/oauth-dpop.js +19 -0
- package/dist/oauth-dpop.js.map +1 -0
- package/dist/oauth-errors.d.ts +20 -0
- package/dist/oauth-errors.d.ts.map +1 -0
- package/dist/oauth-errors.js +43 -0
- package/dist/oauth-errors.js.map +1 -0
- package/dist/oauth-hooks.d.ts +42 -0
- package/dist/oauth-hooks.d.ts.map +1 -0
- package/dist/oauth-hooks.js +3 -0
- package/dist/oauth-hooks.js.map +1 -0
- package/dist/oauth-provider.d.ts +179 -0
- package/dist/oauth-provider.d.ts.map +1 -0
- package/dist/oauth-provider.js +748 -0
- package/dist/oauth-provider.js.map +1 -0
- package/dist/oauth-store.d.ts +11 -0
- package/dist/oauth-store.d.ts.map +1 -0
- package/dist/oauth-store.js +27 -0
- package/dist/oauth-store.js.map +1 -0
- package/dist/oauth-verifier.d.ts +66 -0
- package/dist/oauth-verifier.d.ts.map +1 -0
- package/dist/oauth-verifier.js +94 -0
- package/dist/oauth-verifier.js.map +1 -0
- package/dist/oidc/claims.d.ts +16 -0
- package/dist/oidc/claims.d.ts.map +1 -0
- package/dist/oidc/claims.js +29 -0
- package/dist/oidc/claims.js.map +1 -0
- package/dist/oidc/sub.d.ts +4 -0
- package/dist/oidc/sub.d.ts.map +1 -0
- package/dist/oidc/sub.js +6 -0
- package/dist/oidc/sub.js.map +1 -0
- package/dist/oidc/userinfo.d.ts +7 -0
- package/dist/oidc/userinfo.d.ts.map +1 -0
- package/dist/oidc/userinfo.js +3 -0
- package/dist/oidc/userinfo.js.map +1 -0
- package/dist/output/build-error-payload.d.ts +6 -0
- package/dist/output/build-error-payload.d.ts.map +1 -0
- package/dist/output/build-error-payload.js +108 -0
- package/dist/output/build-error-payload.js.map +1 -0
- package/dist/output/customization.d.ts +37 -0
- package/dist/output/customization.d.ts.map +1 -0
- package/dist/output/customization.js +62 -0
- package/dist/output/customization.js.map +1 -0
- package/dist/output/send-authorize-page.d.ts +43 -0
- package/dist/output/send-authorize-page.d.ts.map +1 -0
- package/dist/output/send-authorize-page.js +49 -0
- package/dist/output/send-authorize-page.js.map +1 -0
- package/dist/output/send-authorize-redirect.d.ts +25 -0
- package/dist/output/send-authorize-redirect.d.ts.map +1 -0
- package/dist/output/send-authorize-redirect.js +72 -0
- package/dist/output/send-authorize-redirect.js.map +1 -0
- package/dist/output/send-error-page.d.ts +5 -0
- package/dist/output/send-error-page.d.ts.map +1 -0
- package/dist/output/send-error-page.js +31 -0
- package/dist/output/send-error-page.js.map +1 -0
- package/dist/output/send-web-page.d.ts +8 -0
- package/dist/output/send-web-page.d.ts.map +1 -0
- package/dist/output/send-web-page.js +48 -0
- package/dist/output/send-web-page.js.map +1 -0
- package/dist/parameters/claims-requested.d.ts +3 -0
- package/dist/parameters/claims-requested.d.ts.map +1 -0
- package/dist/parameters/claims-requested.js +77 -0
- package/dist/parameters/claims-requested.js.map +1 -0
- package/dist/parameters/oidc-payload.d.ts +31 -0
- package/dist/parameters/oidc-payload.d.ts.map +1 -0
- package/dist/parameters/oidc-payload.js +25 -0
- package/dist/parameters/oidc-payload.js.map +1 -0
- package/dist/replay/replay-manager.d.ts +10 -0
- package/dist/replay/replay-manager.d.ts.map +1 -0
- package/dist/replay/replay-manager.js +23 -0
- package/dist/replay/replay-manager.js.map +1 -0
- package/dist/replay/replay-store-memory.d.ts +11 -0
- package/dist/replay/replay-store-memory.d.ts.map +1 -0
- package/dist/replay/replay-store-memory.js +30 -0
- package/dist/replay/replay-store-memory.js.map +1 -0
- package/dist/replay/replay-store-redis.d.ts +16 -0
- package/dist/replay/replay-store-redis.d.ts.map +1 -0
- package/dist/replay/replay-store-redis.js +20 -0
- package/dist/replay/replay-store-redis.js.map +1 -0
- package/dist/replay/replay-store.d.ts +16 -0
- package/dist/replay/replay-store.d.ts.map +1 -0
- package/dist/replay/replay-store.js +22 -0
- package/dist/replay/replay-store.js.map +1 -0
- package/dist/request/code.d.ts +7 -0
- package/dist/request/code.d.ts.map +1 -0
- package/dist/request/code.js +20 -0
- package/dist/request/code.js.map +1 -0
- package/dist/request/request-data.d.ts +21 -0
- package/dist/request/request-data.d.ts.map +1 -0
- package/dist/request/request-data.js +6 -0
- package/dist/request/request-data.js.map +1 -0
- package/dist/request/request-id.d.ts +6 -0
- package/dist/request/request-id.d.ts.map +1 -0
- package/dist/request/request-id.js +18 -0
- package/dist/request/request-id.js.map +1 -0
- package/dist/request/request-info.d.ts +12 -0
- package/dist/request/request-info.d.ts.map +1 -0
- package/dist/request/request-info.js +3 -0
- package/dist/request/request-info.js.map +1 -0
- package/dist/request/request-manager.d.ts +40 -0
- package/dist/request/request-manager.d.ts.map +1 -0
- package/dist/request/request-manager.js +310 -0
- package/dist/request/request-manager.js.map +1 -0
- package/dist/request/request-store-memory.d.ts +16 -0
- package/dist/request/request-store-memory.d.ts.map +1 -0
- package/dist/request/request-store-memory.js +31 -0
- package/dist/request/request-store-memory.js.map +1 -0
- package/dist/request/request-store-redis.d.ts +24 -0
- package/dist/request/request-store-redis.d.ts.map +1 -0
- package/dist/request/request-store-redis.js +58 -0
- package/dist/request/request-store-redis.js.map +1 -0
- package/dist/request/request-store.d.ts +27 -0
- package/dist/request/request-store.d.ts.map +1 -0
- package/dist/request/request-store.js +37 -0
- package/dist/request/request-store.js.map +1 -0
- package/dist/request/request-uri.d.ts +8 -0
- package/dist/request/request-uri.d.ts.map +1 -0
- package/dist/request/request-uri.js +24 -0
- package/dist/request/request-uri.js.map +1 -0
- package/dist/request/types.d.ts +328 -0
- package/dist/request/types.d.ts.map +1 -0
- package/dist/request/types.js +27 -0
- package/dist/request/types.js.map +1 -0
- package/dist/signer/signed-token-payload.d.ts +1694 -0
- package/dist/signer/signed-token-payload.d.ts.map +1 -0
- package/dist/signer/signed-token-payload.js +32 -0
- package/dist/signer/signed-token-payload.js.map +1 -0
- package/dist/signer/signer.d.ts +193 -0
- package/dist/signer/signer.d.ts.map +1 -0
- package/dist/signer/signer.js +101 -0
- package/dist/signer/signer.js.map +1 -0
- package/dist/token/refresh-token.d.ts +7 -0
- package/dist/token/refresh-token.d.ts.map +1 -0
- package/dist/token/refresh-token.js +20 -0
- package/dist/token/refresh-token.js.map +1 -0
- package/dist/token/token-claims.d.ts +1687 -0
- package/dist/token/token-claims.d.ts.map +1 -0
- package/dist/token/token-claims.js +30 -0
- package/dist/token/token-claims.js.map +1 -0
- package/dist/token/token-data.d.ts +20 -0
- package/dist/token/token-data.d.ts.map +1 -0
- package/dist/token/token-data.js +3 -0
- package/dist/token/token-data.js.map +1 -0
- package/dist/token/token-id.d.ts +7 -0
- package/dist/token/token-id.d.ts.map +1 -0
- package/dist/token/token-id.js +20 -0
- package/dist/token/token-id.js.map +1 -0
- package/dist/token/token-manager.d.ts +48 -0
- package/dist/token/token-manager.d.ts.map +1 -0
- package/dist/token/token-manager.js +421 -0
- package/dist/token/token-manager.js.map +1 -0
- package/dist/token/token-store.d.ts +35 -0
- package/dist/token/token-store.d.ts.map +1 -0
- package/dist/token/token-store.js +38 -0
- package/dist/token/token-store.js.map +1 -0
- package/dist/token/types.d.ts +250 -0
- package/dist/token/types.d.ts.map +1 -0
- package/dist/token/types.js +36 -0
- package/dist/token/types.js.map +1 -0
- package/dist/token/verify-token-claims.d.ts +17 -0
- package/dist/token/verify-token-claims.d.ts.map +1 -0
- package/dist/token/verify-token-claims.js +39 -0
- package/dist/token/verify-token-claims.js.map +1 -0
- package/package.json +83 -0
- package/rollup.config.js +55 -0
- package/src/access-token/access-token-type.ts +5 -0
- package/src/account/account-manager.ts +55 -0
- package/src/account/account-store.ts +74 -0
- package/src/account/account.ts +10 -0
- package/src/assets/app/app.tsx +28 -0
- package/src/assets/app/backend-data.ts +65 -0
- package/src/assets/app/components/accept-form.tsx +112 -0
- package/src/assets/app/components/account-identifier.tsx +18 -0
- package/src/assets/app/components/account-picker.tsx +108 -0
- package/src/assets/app/components/client-identifier.tsx +32 -0
- package/src/assets/app/components/client-name.tsx +30 -0
- package/src/assets/app/components/error-card.tsx +41 -0
- package/src/assets/app/components/help-card.tsx +42 -0
- package/src/assets/app/components/layout-title-page.tsx +43 -0
- package/src/assets/app/components/layout-welcome.tsx +58 -0
- package/src/assets/app/components/sign-in-form.tsx +290 -0
- package/src/assets/app/components/sign-up-account-form.tsx +210 -0
- package/src/assets/app/components/sign-up-disclaimer.tsx +44 -0
- package/src/assets/app/components/url-viewer.tsx +70 -0
- package/src/assets/app/cookies.ts +11 -0
- package/src/assets/app/hooks/use-api.ts +104 -0
- package/src/assets/app/hooks/use-bound-dispatch.ts +5 -0
- package/src/assets/app/hooks/use-csrf-token.ts +5 -0
- package/src/assets/app/lib/api.ts +64 -0
- package/src/assets/app/lib/clsx.ts +4 -0
- package/src/assets/app/lib/util.ts +10 -0
- package/src/assets/app/main.css +11 -0
- package/src/assets/app/main.tsx +28 -0
- package/src/assets/app/views/accept-view.tsx +51 -0
- package/src/assets/app/views/authorize-view.tsx +101 -0
- package/src/assets/app/views/error-view.tsx +27 -0
- package/src/assets/app/views/sign-in-view.tsx +121 -0
- package/src/assets/app/views/sign-up-view.tsx +93 -0
- package/src/assets/app/views/welcome-view.tsx +61 -0
- package/src/assets/asset.ts +8 -0
- package/src/assets/assets-middleware.ts +32 -0
- package/src/assets/index.ts +74 -0
- package/src/client/client-auth.ts +45 -0
- package/src/client/client-data.ts +9 -0
- package/src/client/client-id.ts +4 -0
- package/src/client/client-info.ts +13 -0
- package/src/client/client-manager.ts +818 -0
- package/src/client/client-store.ts +38 -0
- package/src/client/client-utils.ts +43 -0
- package/src/client/client.ts +231 -0
- package/src/constants.ts +69 -0
- package/src/device/device-data.ts +11 -0
- package/src/device/device-details.ts +43 -0
- package/src/device/device-id.ts +23 -0
- package/src/device/device-manager.ts +287 -0
- package/src/device/device-store.ts +35 -0
- package/src/device/session-id.ts +22 -0
- package/src/dpop/dpop-manager.ts +147 -0
- package/src/dpop/dpop-nonce.ts +104 -0
- package/src/errors/access-denied-error.ts +26 -0
- package/src/errors/account-selection-required-error.ts +12 -0
- package/src/errors/consent-required-error.ts +12 -0
- package/src/errors/invalid-authorization-details-error.ts +22 -0
- package/src/errors/invalid-client-error.ts +20 -0
- package/src/errors/invalid-client-id-error.ts +20 -0
- package/src/errors/invalid-client-metadata-error.ts +19 -0
- package/src/errors/invalid-dpop-key-binding-error.ts +21 -0
- package/src/errors/invalid-dpop-proof-error.ts +13 -0
- package/src/errors/invalid-grant-error.ts +16 -0
- package/src/errors/invalid-parameters-error.ts +12 -0
- package/src/errors/invalid-redirect-uri-error.ts +17 -0
- package/src/errors/invalid-request-error.ts +30 -0
- package/src/errors/invalid-token-error.ts +59 -0
- package/src/errors/login-required-error.ts +12 -0
- package/src/errors/oauth-error.ts +28 -0
- package/src/errors/unauthorized-client-error.ts +20 -0
- package/src/errors/use-dpop-nonce-error.ts +32 -0
- package/src/errors/www-authenticate-error.ts +65 -0
- package/src/index.ts +15 -0
- package/src/lib/html/README.md +9 -0
- package/src/lib/html/build-document.ts +98 -0
- package/src/lib/html/escapers.ts +66 -0
- package/src/lib/html/html.ts +61 -0
- package/src/lib/html/index.ts +5 -0
- package/src/lib/html/tags.ts +58 -0
- package/src/lib/html/util.ts +21 -0
- package/src/lib/http/README.md +11 -0
- package/src/lib/http/accept.ts +91 -0
- package/src/lib/http/context.ts +11 -0
- package/src/lib/http/index.ts +9 -0
- package/src/lib/http/method.ts +18 -0
- package/src/lib/http/middleware.ts +183 -0
- package/src/lib/http/parser.ts +64 -0
- package/src/lib/http/path.ts +82 -0
- package/src/lib/http/request.ts +141 -0
- package/src/lib/http/response.ts +133 -0
- package/src/lib/http/route.ts +56 -0
- package/src/lib/http/router.ts +118 -0
- package/src/lib/http/stream.ts +78 -0
- package/src/lib/http/types.ts +22 -0
- package/src/lib/http/url.ts +23 -0
- package/src/lib/redis.ts +23 -0
- package/src/lib/util/authorization-header.ts +26 -0
- package/src/lib/util/cast.ts +4 -0
- package/src/lib/util/crypto.ts +27 -0
- package/src/lib/util/date.ts +7 -0
- package/src/lib/util/hostname.ts +19 -0
- package/src/lib/util/redirect-uri.ts +46 -0
- package/src/lib/util/time.ts +33 -0
- package/src/lib/util/type.ts +4 -0
- package/src/lib/util/well-known.ts +8 -0
- package/src/metadata/build-metadata.ts +165 -0
- package/src/oauth-client.ts +3 -0
- package/src/oauth-dpop.ts +2 -0
- package/src/oauth-errors.ts +21 -0
- package/src/oauth-hooks.ts +66 -0
- package/src/oauth-provider.ts +1409 -0
- package/src/oauth-store.ts +11 -0
- package/src/oauth-verifier.ts +219 -0
- package/src/oidc/claims.ts +35 -0
- package/src/oidc/sub.ts +4 -0
- package/src/oidc/userinfo.ts +11 -0
- package/src/output/build-error-payload.ts +143 -0
- package/src/output/customization.ts +96 -0
- package/src/output/send-authorize-page.ts +111 -0
- package/src/output/send-authorize-redirect.ts +130 -0
- package/src/output/send-error-page.ts +41 -0
- package/src/output/send-web-page.ts +66 -0
- package/src/parameters/claims-requested.ts +106 -0
- package/src/parameters/oidc-payload.ts +28 -0
- package/src/replay/replay-manager.ts +38 -0
- package/src/replay/replay-store-memory.ts +36 -0
- package/src/replay/replay-store-redis.ts +31 -0
- package/src/replay/replay-store.ts +44 -0
- package/src/request/code.ts +24 -0
- package/src/request/request-data.ts +26 -0
- package/src/request/request-id.ts +23 -0
- package/src/request/request-info.ts +12 -0
- package/src/request/request-manager.ts +479 -0
- package/src/request/request-store-memory.ts +39 -0
- package/src/request/request-store-redis.ts +71 -0
- package/src/request/request-store.ts +54 -0
- package/src/request/request-uri.ts +29 -0
- package/src/request/types.ts +48 -0
- package/src/signer/signed-token-payload.ts +35 -0
- package/src/signer/signer.ts +165 -0
- package/src/token/refresh-token.ts +31 -0
- package/src/token/token-claims.ts +31 -0
- package/src/token/token-data.ts +33 -0
- package/src/token/token-id.ts +26 -0
- package/src/token/token-manager.ts +591 -0
- package/src/token/token-store.ts +78 -0
- package/src/token/types.ts +86 -0
- package/src/token/verify-token-claims.ts +65 -0
- package/tailwind.config.js +13 -0
- package/tsconfig.backend.json +9 -0
- package/tsconfig.frontend.json +11 -0
- package/tsconfig.json +8 -0
- package/tsconfig.tools.json +8 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
import {
|
2
|
+
HtmlValue,
|
3
|
+
cssEscaper,
|
4
|
+
htmlEscaper,
|
5
|
+
javascriptEscaper,
|
6
|
+
jsonEscaper,
|
7
|
+
} from './escapers.js'
|
8
|
+
import { Html } from './html.js'
|
9
|
+
|
10
|
+
export { type HtmlValue }
|
11
|
+
export const html = (
|
12
|
+
tpl: TemplateStringsArray,
|
13
|
+
...val: readonly HtmlValue[]
|
14
|
+
) =>
|
15
|
+
tpl.length === 1 && val.length === 0
|
16
|
+
? // Optimization for static HTML, avoid creating an iterable
|
17
|
+
Html.dangerouslyCreate(tpl)
|
18
|
+
: Html.dangerouslyCreate(htmlEscaper(tpl, val))
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Escapes code to use as a JavaScript string inside a `<script>` tag.
|
22
|
+
*/
|
23
|
+
export const javascriptCode = (code: string) =>
|
24
|
+
Html.dangerouslyCreate(javascriptEscaper(code))
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Creates an HTML safe JavaScript code block, with JSON serialization of the
|
28
|
+
* injected variables.
|
29
|
+
*
|
30
|
+
* @example
|
31
|
+
* ```js
|
32
|
+
* const dataOnTheServer = { foo: 'bar' };
|
33
|
+
* const clientScript = js`
|
34
|
+
* const data = ${dataOnTheServer};
|
35
|
+
* console.log(data);
|
36
|
+
* `
|
37
|
+
* console.log(clientScript.toString()); // Output: 'const data = {"foo":"bar"};console.log(data);'
|
38
|
+
* ```
|
39
|
+
*/
|
40
|
+
export const js = (tpl: TemplateStringsArray, ...val: readonly unknown[]) =>
|
41
|
+
tpl.length === 1 && val.length === 0
|
42
|
+
? // Optimization for static JavaScript, avoid un-necessary serialization
|
43
|
+
javascriptCode(tpl[0])
|
44
|
+
: javascriptCode(String.raw({ raw: tpl }, ...val.map(jsonCode)))
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Escapes a value to be used as a JSON string inside a `<script>` tag.
|
48
|
+
*
|
49
|
+
* @see {@link https://redux.js.org/usage/server-rendering#security-considerations}
|
50
|
+
*/
|
51
|
+
export const jsonCode = (value: unknown) =>
|
52
|
+
Html.dangerouslyCreate(jsonEscaper(value))
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Escapes a value to be uses as CSS styles inside a `<style>` tag.
|
56
|
+
*/
|
57
|
+
export const cssCode = (code: string) =>
|
58
|
+
Html.dangerouslyCreate(cssEscaper(code))
|
@@ -0,0 +1,21 @@
|
|
1
|
+
export type NestedIterable<V> = V | Iterable<NestedIterable<V>>
|
2
|
+
|
3
|
+
export function* stringReplacer(
|
4
|
+
source: string,
|
5
|
+
searchValue: string,
|
6
|
+
replaceValue: string,
|
7
|
+
): Generator<string, void, undefined> {
|
8
|
+
let previousIndex = 0
|
9
|
+
let index = source.indexOf(searchValue)
|
10
|
+
while (index !== -1) {
|
11
|
+
yield source.slice(previousIndex, index)
|
12
|
+
yield replaceValue
|
13
|
+
previousIndex = index + searchValue.length
|
14
|
+
index = source.indexOf(searchValue, previousIndex)
|
15
|
+
}
|
16
|
+
yield source.slice(previousIndex)
|
17
|
+
}
|
18
|
+
|
19
|
+
export function isString(value: unknown): value is string {
|
20
|
+
return typeof value === 'string'
|
21
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# utilities for generating middlewares to work with Node's http module or Express / Connect frameworks
|
2
|
+
|
3
|
+
This library uses a functional programming style to generate middleware
|
4
|
+
functions that can be used with Node's http module or Express / Connect
|
5
|
+
frameworks.
|
6
|
+
|
7
|
+
This code _could_ be used as a standalone library, but the Bluesky dev team does
|
8
|
+
not want to maintain it as such. As it is currently only used by the
|
9
|
+
`@atproto/oauth-provider` package, it is included here. Future development
|
10
|
+
should aim to keep this library independent of the rest of the
|
11
|
+
`@atproto/oauth-provider` package, so that it can be extracted and published.
|
@@ -0,0 +1,91 @@
|
|
1
|
+
import { mediaType } from '@hapi/accept'
|
2
|
+
|
3
|
+
import { SubCtx, subCtx } from './context.js'
|
4
|
+
import {
|
5
|
+
IncomingMessage,
|
6
|
+
Middleware,
|
7
|
+
NextFunction,
|
8
|
+
ServerResponse,
|
9
|
+
} from './types.js'
|
10
|
+
|
11
|
+
type View<
|
12
|
+
T,
|
13
|
+
D,
|
14
|
+
Req extends IncomingMessage = IncomingMessage,
|
15
|
+
Res extends ServerResponse = ServerResponse,
|
16
|
+
> = (
|
17
|
+
this: SubCtx<T, { data: D }>,
|
18
|
+
req: Req,
|
19
|
+
res: Res,
|
20
|
+
next: NextFunction,
|
21
|
+
) => void | PromiseLike<void>
|
22
|
+
|
23
|
+
/**
|
24
|
+
* @example
|
25
|
+
* ```ts
|
26
|
+
* app.use(
|
27
|
+
* acceptMiddleware(
|
28
|
+
* async function (req, res) {
|
29
|
+
* return { hello: 'world' }
|
30
|
+
* },
|
31
|
+
* {
|
32
|
+
* '': 'application/json', // Fallback to JSON
|
33
|
+
* 'text/plain': function (req, res) {
|
34
|
+
* res.writeHead(200).end(this.data.hello)
|
35
|
+
* },
|
36
|
+
* 'application/json': function (req, res) {
|
37
|
+
* res.writeHead(200).end(JSON.stringify(this.data))
|
38
|
+
* }
|
39
|
+
* }
|
40
|
+
* )
|
41
|
+
* )
|
42
|
+
*/
|
43
|
+
export function acceptMiddleware<
|
44
|
+
D,
|
45
|
+
T = void,
|
46
|
+
Req extends IncomingMessage = IncomingMessage,
|
47
|
+
Res extends ServerResponse = ServerResponse,
|
48
|
+
>(
|
49
|
+
controller: (this: T, req: Req, res: Res) => D | PromiseLike<D>,
|
50
|
+
views: Record<string, string | View<T, D, Req, Res>>,
|
51
|
+
fallback: Middleware<T> = (req, res, _next) => void res.writeHead(406).end(),
|
52
|
+
): (this: T, req: Req, res: Res, next: NextFunction) => Promise<void> {
|
53
|
+
const viewsMap = new Map(Object.entries(views))
|
54
|
+
const preferences = Array.from(viewsMap.keys()).filter(Boolean)
|
55
|
+
|
56
|
+
// Make sure that every view is either a function or a string that points to a
|
57
|
+
// function.
|
58
|
+
for (const type of viewsMap.keys()) {
|
59
|
+
const view = viewsMap.get(type)
|
60
|
+
if (typeof view === 'string' && typeof viewsMap.get(view) !== 'function') {
|
61
|
+
throw new Error(`Invalid view "${view}" for media type "${type}"`)
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
return async function (req, res, next) {
|
66
|
+
try {
|
67
|
+
const type = req.headers['accept']
|
68
|
+
? mediaType(req.headers['accept'], preferences) || undefined
|
69
|
+
: '' // indicate that the client accepts anything
|
70
|
+
|
71
|
+
let view = type != null ? viewsMap.get(type) : undefined
|
72
|
+
|
73
|
+
if (typeof view === 'string') view = viewsMap.get(view)
|
74
|
+
if (typeof view === 'string') throw new Error('Invalid view') // should not happen
|
75
|
+
|
76
|
+
if (view) {
|
77
|
+
const data = await controller.call(this, req, res)
|
78
|
+
const ctx = subCtx(this, 'data', data)
|
79
|
+
if (type) res.setHeader('Content-Type', type)
|
80
|
+
|
81
|
+
await view.call(ctx, req, res, next)
|
82
|
+
} else {
|
83
|
+
// media negotiation failed
|
84
|
+
await fallback.call(this, req, res, next)
|
85
|
+
}
|
86
|
+
} catch (err) {
|
87
|
+
if (!res.headersSent) res.removeHeader('Content-Type')
|
88
|
+
next(err)
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
export type SubCtx<Parent, Child> = Child & Omit<Parent, keyof Child>
|
2
|
+
|
3
|
+
export function subCtx<T, K extends string, V>(
|
4
|
+
ctx: T,
|
5
|
+
key: K,
|
6
|
+
value: V,
|
7
|
+
): SubCtx<T, { [_ in K]: V }> {
|
8
|
+
return Object.create(typeof ctx === 'object' ? ctx : null, {
|
9
|
+
[key]: { value, enumerable: true, writable: false },
|
10
|
+
})
|
11
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
export * from './accept.js'
|
2
|
+
export * from './context.js'
|
3
|
+
export * from './middleware.js'
|
4
|
+
export * from './parser.js'
|
5
|
+
export * from './request.js'
|
6
|
+
export * from './response.js'
|
7
|
+
export * from './router.js'
|
8
|
+
export * from './stream.js'
|
9
|
+
export * from './types.js'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { IncomingMessage } from './types.js'
|
2
|
+
|
3
|
+
export type MethodMatcherInput = string | Iterable<string> | MethodMatcher
|
4
|
+
export type MethodMatcher = (req: IncomingMessage) => boolean
|
5
|
+
|
6
|
+
export function createMethodMatcher(method: MethodMatcherInput): MethodMatcher {
|
7
|
+
if (method === '*') return () => true
|
8
|
+
if (typeof method === 'function') return method
|
9
|
+
|
10
|
+
if (typeof method === 'string') {
|
11
|
+
method = method.toUpperCase()
|
12
|
+
return (req) => req.method === method
|
13
|
+
}
|
14
|
+
|
15
|
+
const set = new Set(Array.from(method, (m) => m.toUpperCase()))
|
16
|
+
if (set.size === 0) return () => false
|
17
|
+
return (req) => req.method != null && set.has(req.method)
|
18
|
+
}
|
@@ -0,0 +1,183 @@
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
2
|
+
import { writeJson } from './response.js'
|
3
|
+
import { Middleware, Handler, NextFunction } from './types.js'
|
4
|
+
|
5
|
+
export function combineMiddlewares<M extends Middleware<any, any, any>>(
|
6
|
+
middlewares: Iterable<null | undefined | M>,
|
7
|
+
options?: { skipKeyword?: string },
|
8
|
+
): M
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Combine express/connect like middlewares (that can be async) into a single
|
12
|
+
* middleware.
|
13
|
+
*/
|
14
|
+
export function combineMiddlewares(
|
15
|
+
middlewares: Iterable<null | undefined | Middleware<unknown>>,
|
16
|
+
{ skipKeyword }: { skipKeyword?: string } = {},
|
17
|
+
): Middleware<unknown> {
|
18
|
+
const middlewaresArray = Array.from(middlewares).filter(
|
19
|
+
(x): x is NonNullable<typeof x> => x != null,
|
20
|
+
)
|
21
|
+
|
22
|
+
// Optimization: if there are no middlewares, return a noop middleware.
|
23
|
+
if (middlewaresArray.length === 0) return (req, res, next) => void next()
|
24
|
+
|
25
|
+
return function (req, res, next) {
|
26
|
+
let i = 0
|
27
|
+
const nextMiddleware = (err?: unknown) => {
|
28
|
+
if (err) {
|
29
|
+
if (skipKeyword && err === skipKeyword) next()
|
30
|
+
else next(err)
|
31
|
+
} else if (i >= middlewaresArray.length) {
|
32
|
+
next()
|
33
|
+
} else {
|
34
|
+
const currentMiddleware = middlewaresArray[i++]!
|
35
|
+
const currentNext = once(nextMiddleware)
|
36
|
+
try {
|
37
|
+
const result = currentMiddleware.call(this, req, res, currentNext)
|
38
|
+
Promise.resolve(result).catch(currentNext)
|
39
|
+
} catch (err) {
|
40
|
+
currentNext(err)
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
nextMiddleware()
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
export type AsHandler<M extends Middleware<any, any, any>> =
|
49
|
+
M extends Middleware<infer T, infer Req, infer Res>
|
50
|
+
? Handler<T, Req, Res>
|
51
|
+
: never
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Convert a middleware in a function that can be used as both a middleware and
|
55
|
+
* and handler.
|
56
|
+
*/
|
57
|
+
export function asHandler<M extends Middleware<any, any, any>>(
|
58
|
+
middleware: M,
|
59
|
+
options?: FinalHandlerOptions,
|
60
|
+
) {
|
61
|
+
return function (
|
62
|
+
this,
|
63
|
+
req,
|
64
|
+
res,
|
65
|
+
next = once(createFinalHandler(req, res, options)),
|
66
|
+
) {
|
67
|
+
return middleware.call(this, req, res, next)
|
68
|
+
} as AsHandler<M>
|
69
|
+
}
|
70
|
+
|
71
|
+
export type FinalHandlerOptions = {
|
72
|
+
debug?: boolean
|
73
|
+
}
|
74
|
+
|
75
|
+
export function createFinalHandler(
|
76
|
+
req: IncomingMessage,
|
77
|
+
res: ServerResponse,
|
78
|
+
options?: FinalHandlerOptions,
|
79
|
+
): NextFunction {
|
80
|
+
return (err) => {
|
81
|
+
if (err && (options?.debug ?? process.env['NODE_ENV'] === 'development')) {
|
82
|
+
console.error(err)
|
83
|
+
}
|
84
|
+
|
85
|
+
if (res.headersSent) {
|
86
|
+
// If an error occurred, and headers were sent, we can't know that the
|
87
|
+
// whole response body was sent. So we can't safely reuse the socket.
|
88
|
+
if (err) req.socket.destroy()
|
89
|
+
|
90
|
+
return
|
91
|
+
}
|
92
|
+
|
93
|
+
const { status, ...payload } = buildFallbackPayload(req, err)
|
94
|
+
|
95
|
+
res.setHeader('Content-Security-Policy', "default-src 'none'")
|
96
|
+
res.setHeader('X-Content-Type-Options', 'nosniff')
|
97
|
+
|
98
|
+
writeJson(res, payload, status)
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
function buildFallbackPayload(
|
103
|
+
req: IncomingMessage,
|
104
|
+
err: unknown,
|
105
|
+
): {
|
106
|
+
status: number
|
107
|
+
error: string
|
108
|
+
error_description: string
|
109
|
+
stack?: undefined | string
|
110
|
+
} {
|
111
|
+
const status = err ? getErrorStatusCode(err) : 404
|
112
|
+
const expose = getProp(err, 'expose', 'boolean') ?? status < 500
|
113
|
+
|
114
|
+
return {
|
115
|
+
status,
|
116
|
+
error: err
|
117
|
+
? expose
|
118
|
+
? getProp(err, 'code', 'string') ??
|
119
|
+
getProp(err, 'error', 'string') ??
|
120
|
+
'unknown_error'
|
121
|
+
: 'system_error'
|
122
|
+
: 'not_found',
|
123
|
+
error_description:
|
124
|
+
err instanceof Error
|
125
|
+
? expose
|
126
|
+
? getProp(err, 'error_description', 'string') ||
|
127
|
+
String(err.message) ||
|
128
|
+
'Unknown error'
|
129
|
+
: 'System error'
|
130
|
+
: `Cannot ${req.method} ${req.url}`,
|
131
|
+
stack:
|
132
|
+
err instanceof Error && process.env['NODE_ENV'] === 'development'
|
133
|
+
? err.stack
|
134
|
+
: undefined,
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
function getErrorStatusCode(err: NonNullable<unknown>): number {
|
139
|
+
const status =
|
140
|
+
getProp(err, 'status', 'number') ?? getProp(err, 'statusCode', 'number')
|
141
|
+
return status != null && status >= 400 && status < 600 ? status : 500
|
142
|
+
}
|
143
|
+
|
144
|
+
export function once<T extends NextFunction>(next: T): T {
|
145
|
+
let nextNullable: T | null = next
|
146
|
+
return function (err) {
|
147
|
+
if (!nextNullable) throw new Error('next() called multiple times')
|
148
|
+
const next = nextNullable
|
149
|
+
nextNullable = null
|
150
|
+
return next(err)
|
151
|
+
} as T
|
152
|
+
}
|
153
|
+
|
154
|
+
// eslint-disable-next-line
|
155
|
+
function getProp(obj: unknown, key: string, t: 'function'): Function | undefined
|
156
|
+
function getProp(obj: unknown, key: string, t: 'string'): string | undefined
|
157
|
+
function getProp(obj: unknown, key: string, t: 'number'): number | undefined
|
158
|
+
function getProp(obj: unknown, key: string, t: 'boolean'): boolean | undefined
|
159
|
+
function getProp(obj: unknown, key: string, t: 'object'): object | undefined
|
160
|
+
function getProp(obj: unknown, key: string, t: 'symbol'): symbol | undefined
|
161
|
+
function getProp(obj: unknown, key: string, t: 'bigint'): bigint | undefined
|
162
|
+
function getProp(obj: unknown, key: string, t: 'undefined'): undefined
|
163
|
+
function getProp(
|
164
|
+
obj: unknown,
|
165
|
+
key: string,
|
166
|
+
type:
|
167
|
+
| 'string'
|
168
|
+
| 'number'
|
169
|
+
| 'boolean'
|
170
|
+
| 'object'
|
171
|
+
| 'function'
|
172
|
+
| 'symbol'
|
173
|
+
| 'bigint'
|
174
|
+
| 'undefined',
|
175
|
+
): unknown
|
176
|
+
|
177
|
+
function getProp(obj: unknown, key: string, type: string): unknown {
|
178
|
+
if (obj != null && typeof obj === 'object' && key in obj) {
|
179
|
+
const value = (obj as Record<string, unknown>)[key]
|
180
|
+
if (typeof value === type) return value
|
181
|
+
}
|
182
|
+
return undefined
|
183
|
+
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import { parse as parseJson } from '@hapi/bourne'
|
2
|
+
import createHttpError from 'http-errors'
|
3
|
+
|
4
|
+
export type JsonScalar = string | number | boolean | null
|
5
|
+
export type Json = JsonScalar | Json[] | { [_ in string]?: Json }
|
6
|
+
|
7
|
+
export type Parser<T extends string = string, R = unknown> = {
|
8
|
+
readonly name: string
|
9
|
+
readonly test: (type: string) => type is T
|
10
|
+
readonly parse: (buffer: Buffer) => R
|
11
|
+
}
|
12
|
+
|
13
|
+
export type ParserName<P extends Parser> = P extends { readonly name: infer N }
|
14
|
+
? N
|
15
|
+
: never
|
16
|
+
export type ParserType<P extends Parser> = P extends Parser<infer T> ? T : never
|
17
|
+
export type ParserResult<P extends Parser> = ReturnType<P['parse']>
|
18
|
+
|
19
|
+
export type ParserForType<P extends Parser, T> =
|
20
|
+
P extends Parser<infer U> ? (U extends T ? P : never) : never
|
21
|
+
|
22
|
+
export const parsers = [
|
23
|
+
{
|
24
|
+
name: 'json',
|
25
|
+
test: (
|
26
|
+
type: string,
|
27
|
+
): type is `application/json` | `application/${string}+json` => {
|
28
|
+
return /^application\/(?:.+\+)?json$/.test(type)
|
29
|
+
},
|
30
|
+
parse: (buffer: Buffer): Json => {
|
31
|
+
try {
|
32
|
+
return parseJson(buffer.toString())
|
33
|
+
} catch (err) {
|
34
|
+
throw createHttpError(400, 'Invalid JSON', { cause: err })
|
35
|
+
}
|
36
|
+
},
|
37
|
+
},
|
38
|
+
{
|
39
|
+
name: 'urlencoded',
|
40
|
+
test: (type: string): type is 'application/x-www-form-urlencoded' => {
|
41
|
+
return type === 'application/x-www-form-urlencoded'
|
42
|
+
},
|
43
|
+
parse: (buffer: Buffer): Partial<Record<string, string>> => {
|
44
|
+
try {
|
45
|
+
if (!buffer.length) return {}
|
46
|
+
return Object.fromEntries(new URLSearchParams(buffer.toString()))
|
47
|
+
} catch (err) {
|
48
|
+
throw createHttpError(400, 'Invalid URL-encoded data', { cause: err })
|
49
|
+
}
|
50
|
+
},
|
51
|
+
},
|
52
|
+
{
|
53
|
+
name: 'bytes',
|
54
|
+
test: (type: string): type is 'application/octet-stream' => {
|
55
|
+
return type === 'application/octet-stream'
|
56
|
+
},
|
57
|
+
parse: (buffer: Buffer): Buffer => buffer,
|
58
|
+
},
|
59
|
+
] as const satisfies Parser[]
|
60
|
+
|
61
|
+
export type KnownParser = (typeof parsers)[number]
|
62
|
+
|
63
|
+
export type KnownNames = KnownParser['name']
|
64
|
+
export type KnownTypes = ParserType<KnownParser>
|
@@ -0,0 +1,82 @@
|
|
1
|
+
export type PathMatcher<P extends Params> = (pathname: string) => P | undefined
|
2
|
+
|
3
|
+
type StringPath<P extends Params> = string extends keyof P
|
4
|
+
? `/${string}`
|
5
|
+
: keyof P extends never
|
6
|
+
? `/${string}` | ``
|
7
|
+
: {
|
8
|
+
[K in keyof P]: K extends string
|
9
|
+
?
|
10
|
+
| `${`/:${K}` | `/${string}/:${K}`}${StringPath<Omit<P, K>>}`
|
11
|
+
| `${StringPath<Omit<P, K>>}${`/:${K}` | `/:${K}/${string}`}`
|
12
|
+
: never
|
13
|
+
}[keyof P]
|
14
|
+
|
15
|
+
export type Path<P extends Params> =
|
16
|
+
| string
|
17
|
+
| StringPath<P>
|
18
|
+
| RegExp
|
19
|
+
| PathMatcher<P>
|
20
|
+
export type Params = Record<string, undefined | string>
|
21
|
+
|
22
|
+
export function createPathMatcher<P extends Params = Params>(
|
23
|
+
refPath: Path<P>,
|
24
|
+
): PathMatcher<P> {
|
25
|
+
if (typeof refPath === 'string') {
|
26
|
+
// Create a path matcher for a path with parameters (like /foo/:fooId/bar/:barId).
|
27
|
+
if (refPath.includes('/:')) {
|
28
|
+
const refParts = refPath
|
29
|
+
.slice(1)
|
30
|
+
.split('/')
|
31
|
+
.map((part, i) => [part, i] as const)
|
32
|
+
const refPartsLength = refParts.length
|
33
|
+
|
34
|
+
const staticParts = refParts.filter(([p]) => !p.startsWith(':'))
|
35
|
+
const paramParts = refParts
|
36
|
+
// Extract parameters, ignoring those with no name (like /foo/:/bar).
|
37
|
+
.filter(([p]) => p.startsWith(':') && p.length > 1)
|
38
|
+
.map(([p, i]) => [p.slice(1), i] as const)
|
39
|
+
|
40
|
+
return (reqPath: string) => {
|
41
|
+
const reqParts = reqPath.slice(1).split('/')
|
42
|
+
|
43
|
+
if (reqParts.length !== refPartsLength) return undefined
|
44
|
+
|
45
|
+
// Make sure all static parts match.
|
46
|
+
for (let i = 0; i < staticParts.length; i++) {
|
47
|
+
const value = staticParts[i]![0]
|
48
|
+
const idx = staticParts[i]![1]
|
49
|
+
|
50
|
+
if (value !== reqParts[idx]) return undefined
|
51
|
+
}
|
52
|
+
|
53
|
+
// Then extract the parameters.
|
54
|
+
const params: Record<string, string> = {}
|
55
|
+
for (let i = 0; i < paramParts.length; i++) {
|
56
|
+
const name = paramParts[i]![0]
|
57
|
+
const idx = paramParts[i]![1]
|
58
|
+
|
59
|
+
const value = reqParts[idx]
|
60
|
+
|
61
|
+
// Empty parameter values are not allowed.
|
62
|
+
if (!value) return undefined
|
63
|
+
|
64
|
+
params[name] = value
|
65
|
+
}
|
66
|
+
|
67
|
+
return params as P
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
return (reqPath: string) => (reqPath === refPath ? ({} as P) : undefined)
|
72
|
+
}
|
73
|
+
|
74
|
+
if (refPath instanceof RegExp) {
|
75
|
+
return (reqPath: string) => {
|
76
|
+
const match = reqPath.match(refPath)
|
77
|
+
return match ? ((match.groups || {}) as P) : undefined
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
return refPath
|
82
|
+
}
|
@@ -0,0 +1,141 @@
|
|
1
|
+
import { parse as parseCookie, serialize as serializeCookie } from 'cookie'
|
2
|
+
import { randomBytes } from 'crypto'
|
3
|
+
import createHttpError from 'http-errors'
|
4
|
+
import { z } from 'zod'
|
5
|
+
|
6
|
+
import { KnownNames } from './parser.js'
|
7
|
+
import { appendHeader } from './response.js'
|
8
|
+
import { decodeStream, parseStream } from './stream.js'
|
9
|
+
import { IncomingMessage, ServerResponse } from './types.js'
|
10
|
+
import { UrlReference, urlMatch } from './url.js'
|
11
|
+
|
12
|
+
export function parseRequestPayload<
|
13
|
+
A extends readonly KnownNames[] = readonly KnownNames[],
|
14
|
+
>(req: IncomingMessage, allow?: A) {
|
15
|
+
return parseStream(
|
16
|
+
decodeStream(req, req.headers['content-encoding']),
|
17
|
+
req.headers['content-type'],
|
18
|
+
allow,
|
19
|
+
)
|
20
|
+
}
|
21
|
+
|
22
|
+
export async function validateRequestPayload<S extends z.ZodTypeAny>(
|
23
|
+
req: IncomingMessage,
|
24
|
+
schema: S,
|
25
|
+
allow: readonly KnownNames[] = ['json', 'urlencoded'],
|
26
|
+
): Promise<z.infer<S>> {
|
27
|
+
const payload = await parseRequestPayload(req, allow)
|
28
|
+
return schema.parseAsync(payload, { path: ['body'] })
|
29
|
+
}
|
30
|
+
|
31
|
+
export function validateFetchMode(
|
32
|
+
req: IncomingMessage,
|
33
|
+
res: ServerResponse,
|
34
|
+
expectedMode: readonly (
|
35
|
+
| null
|
36
|
+
| 'navigate'
|
37
|
+
| 'same-origin'
|
38
|
+
| 'no-cors'
|
39
|
+
| 'cors'
|
40
|
+
)[],
|
41
|
+
) {
|
42
|
+
const reqMode = req.headers['sec-fetch-mode'] ?? null
|
43
|
+
|
44
|
+
if (Array.isArray(reqMode)) {
|
45
|
+
throw createHttpError(400, `Invalid sec-fetch-mode header`)
|
46
|
+
}
|
47
|
+
|
48
|
+
if (!(expectedMode as (string | null)[]).includes(reqMode)) {
|
49
|
+
throw createHttpError(
|
50
|
+
403,
|
51
|
+
reqMode
|
52
|
+
? `Forbidden sec-fetch-mode "${reqMode}" (expected ${expectedMode})`
|
53
|
+
: `Missing sec-fetch-mode (expected ${expectedMode})`,
|
54
|
+
)
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
export function validateReferer(
|
59
|
+
req: IncomingMessage,
|
60
|
+
res: ServerResponse,
|
61
|
+
reference: UrlReference,
|
62
|
+
allowNull = false,
|
63
|
+
) {
|
64
|
+
const referer = req.headers['referer']
|
65
|
+
const refererUrl = referer ? new URL(referer) : null
|
66
|
+
if (refererUrl ? !urlMatch(refererUrl, reference) : !allowNull) {
|
67
|
+
throw createHttpError(403, `Invalid referer ${referer}`)
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
export async function setupCsrfToken(
|
72
|
+
req: IncomingMessage,
|
73
|
+
res: ServerResponse,
|
74
|
+
cookieName = 'csrf_token',
|
75
|
+
) {
|
76
|
+
const csrfToken = randomBytes(8).toString('hex')
|
77
|
+
appendHeader(
|
78
|
+
res,
|
79
|
+
'Set-Cookie',
|
80
|
+
serializeCookie(cookieName, csrfToken, {
|
81
|
+
secure: true,
|
82
|
+
httpOnly: false,
|
83
|
+
sameSite: 'lax',
|
84
|
+
path: req.url?.split('?', 1)[0] || '/',
|
85
|
+
}),
|
86
|
+
)
|
87
|
+
}
|
88
|
+
|
89
|
+
// CORS ensure not cross origin
|
90
|
+
export function validateSameOrigin(
|
91
|
+
req: IncomingMessage,
|
92
|
+
res: ServerResponse,
|
93
|
+
origin: string,
|
94
|
+
allowNull = true,
|
95
|
+
) {
|
96
|
+
const reqOrigin = req.headers['origin']
|
97
|
+
if (reqOrigin ? reqOrigin !== origin : !allowNull) {
|
98
|
+
throw createHttpError(403, `Invalid origin ${reqOrigin}`)
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
export function validateCsrfToken(
|
103
|
+
req: IncomingMessage,
|
104
|
+
res: ServerResponse,
|
105
|
+
csrfToken: string,
|
106
|
+
cookieName = 'csrf_token',
|
107
|
+
clearCookie = false,
|
108
|
+
) {
|
109
|
+
const cookies = parseHttpCookies(req)
|
110
|
+
if (
|
111
|
+
!csrfToken ||
|
112
|
+
!cookies ||
|
113
|
+
!cookieName ||
|
114
|
+
cookies[cookieName] !== csrfToken
|
115
|
+
) {
|
116
|
+
throw createHttpError(403, `Invalid CSRF token`)
|
117
|
+
}
|
118
|
+
|
119
|
+
if (clearCookie) {
|
120
|
+
appendHeader(
|
121
|
+
res,
|
122
|
+
'Set-Cookie',
|
123
|
+
serializeCookie(cookieName, '', {
|
124
|
+
secure: true,
|
125
|
+
httpOnly: false,
|
126
|
+
sameSite: 'lax',
|
127
|
+
maxAge: 0,
|
128
|
+
}),
|
129
|
+
)
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
export function parseHttpCookies(
|
134
|
+
req: IncomingMessage,
|
135
|
+
): null | Record<string, undefined | string> {
|
136
|
+
return 'cookies' in req && req.cookies // Already parsed by another middleware
|
137
|
+
? (req.cookies as any)
|
138
|
+
: req.headers['cookie']
|
139
|
+
? ((req as any).cookies = parseCookie(req.headers['cookie']))
|
140
|
+
: null
|
141
|
+
}
|