@atproto/oauth-provider 0.16.5 → 0.17.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 +32 -0
- package/dist/access-token/access-token-mode.js +2 -5
- package/dist/access-token/access-token-mode.js.map +1 -1
- package/dist/account/account-manager.js +25 -33
- package/dist/account/account-manager.js.map +1 -1
- package/dist/account/account-store.js +11 -32
- package/dist/account/account-store.js.map +1 -1
- package/dist/account/sign-in-data.js +9 -12
- package/dist/account/sign-in-data.js.map +1 -1
- package/dist/account/sign-up-input.js +14 -17
- package/dist/account/sign-up-input.js.map +1 -1
- package/dist/client/client-auth.js +1 -2
- package/dist/client/client-data.js +1 -2
- package/dist/client/client-id.js +2 -5
- package/dist/client/client-id.js.map +1 -1
- package/dist/client/client-info.js +1 -2
- package/dist/client/client-manager.js +86 -97
- package/dist/client/client-manager.js.map +1 -1
- package/dist/client/client-store.js +7 -26
- package/dist/client/client-store.js.map +1 -1
- package/dist/client/client-utils.js +10 -14
- package/dist/client/client-utils.js.map +1 -1
- package/dist/client/client.js +43 -53
- package/dist/client/client.js.map +1 -1
- package/dist/constants.js +28 -31
- package/dist/constants.js.map +1 -1
- package/dist/customization/branding.js +8 -11
- package/dist/customization/branding.js.map +1 -1
- package/dist/customization/build-customization-css.js +8 -11
- package/dist/customization/build-customization-css.js.map +1 -1
- package/dist/customization/build-customization-data.js +1 -4
- package/dist/customization/build-customization-data.js.map +1 -1
- package/dist/customization/colors.js +11 -14
- package/dist/customization/colors.js.map +1 -1
- package/dist/customization/customization.js +8 -11
- package/dist/customization/customization.js.map +1 -1
- package/dist/customization/links.js +7 -10
- package/dist/customization/links.js.map +1 -1
- package/dist/device/device-data.js +7 -10
- package/dist/device/device-data.js.map +1 -1
- package/dist/device/device-id.js +11 -16
- package/dist/device/device-id.js.map +1 -1
- package/dist/device/device-manager.js +32 -38
- package/dist/device/device-manager.js.map +1 -1
- package/dist/device/device-store.js +7 -25
- package/dist/device/device-store.js.map +1 -1
- package/dist/device/session-id.js +9 -13
- package/dist/device/session-id.js.map +1 -1
- package/dist/dpop/dpop-manager.d.ts +3 -3
- package/dist/dpop/dpop-manager.js +38 -43
- package/dist/dpop/dpop-manager.js.map +1 -1
- package/dist/dpop/dpop-nonce.d.ts +2 -2
- package/dist/dpop/dpop-nonce.d.ts.map +1 -1
- package/dist/dpop/dpop-nonce.js +14 -18
- package/dist/dpop/dpop-nonce.js.map +1 -1
- package/dist/dpop/dpop-proof.js +1 -2
- package/dist/errors/access-denied-error.js +2 -6
- package/dist/errors/access-denied-error.js.map +1 -1
- package/dist/errors/account-selection-required-error.js +2 -6
- package/dist/errors/account-selection-required-error.js.map +1 -1
- package/dist/errors/authorization-error.js +7 -12
- package/dist/errors/authorization-error.js.map +1 -1
- package/dist/errors/consent-required-error.js +2 -6
- package/dist/errors/consent-required-error.js.map +1 -1
- package/dist/errors/error-parser.js +14 -18
- package/dist/errors/error-parser.js.map +1 -1
- package/dist/errors/handle-unavailable-error.js +2 -7
- package/dist/errors/handle-unavailable-error.js.map +1 -1
- package/dist/errors/invalid-authorization-details-error.js +2 -6
- package/dist/errors/invalid-authorization-details-error.js.map +1 -1
- package/dist/errors/invalid-client-error.js +2 -6
- package/dist/errors/invalid-client-error.js.map +1 -1
- package/dist/errors/invalid-client-id-error.js +2 -6
- package/dist/errors/invalid-client-id-error.js.map +1 -1
- package/dist/errors/invalid-client-metadata-error.js +7 -11
- package/dist/errors/invalid-client-metadata-error.js.map +1 -1
- package/dist/errors/invalid-credentials-error.js +2 -7
- package/dist/errors/invalid-credentials-error.js.map +1 -1
- package/dist/errors/invalid-dpop-key-binding-error.js +2 -6
- package/dist/errors/invalid-dpop-key-binding-error.js.map +1 -1
- package/dist/errors/invalid-dpop-proof-error.js +2 -6
- package/dist/errors/invalid-dpop-proof-error.js.map +1 -1
- package/dist/errors/invalid-grant-error.js +2 -6
- package/dist/errors/invalid-grant-error.js.map +1 -1
- package/dist/errors/invalid-invite-code-error.d.ts +1 -1
- package/dist/errors/invalid-invite-code-error.d.ts.map +1 -1
- package/dist/errors/invalid-invite-code-error.js +2 -6
- package/dist/errors/invalid-invite-code-error.js.map +1 -1
- package/dist/errors/invalid-redirect-uri-error.js +2 -6
- package/dist/errors/invalid-redirect-uri-error.js.map +1 -1
- package/dist/errors/invalid-request-error.js +3 -7
- package/dist/errors/invalid-request-error.js.map +1 -1
- package/dist/errors/invalid-scope-error.js +2 -6
- package/dist/errors/invalid-scope-error.js.map +1 -1
- package/dist/errors/invalid-token-error.js +10 -15
- package/dist/errors/invalid-token-error.js.map +1 -1
- package/dist/errors/login-required-error.js +2 -6
- package/dist/errors/login-required-error.js.map +1 -1
- package/dist/errors/oauth-error.js +1 -9
- package/dist/errors/oauth-error.js.map +1 -1
- package/dist/errors/second-authentication-factor-required-error.js +2 -8
- package/dist/errors/second-authentication-factor-required-error.js.map +1 -1
- package/dist/errors/unauthorized-client-error.js +2 -6
- package/dist/errors/unauthorized-client-error.js.map +1 -1
- package/dist/errors/use-dpop-nonce-error.js +4 -8
- package/dist/errors/use-dpop-nonce-error.js.map +1 -1
- package/dist/errors/www-authenticate-error.js +4 -9
- package/dist/errors/www-authenticate-error.js.map +1 -1
- package/dist/index.js +14 -30
- package/dist/index.js.map +1 -1
- package/dist/lexicon/lexicon-data.js +1 -2
- package/dist/lexicon/lexicon-getter.js +6 -10
- package/dist/lexicon/lexicon-getter.js.map +1 -1
- package/dist/lexicon/lexicon-manager.js +10 -30
- package/dist/lexicon/lexicon-manager.js.map +1 -1
- package/dist/lexicon/lexicon-store.js +5 -10
- package/dist/lexicon/lexicon-store.js.map +1 -1
- package/dist/lib/csp/index.js +3 -8
- package/dist/lib/csp/index.js.map +1 -1
- package/dist/lib/hcaptcha.js +33 -43
- package/dist/lib/hcaptcha.js.map +1 -1
- package/dist/lib/html/build-document.js +19 -24
- package/dist/lib/html/build-document.js.map +1 -1
- package/dist/lib/html/escapers.js +10 -16
- package/dist/lib/html/escapers.js.map +1 -1
- package/dist/lib/html/html.js +1 -5
- package/dist/lib/html/html.js.map +1 -1
- package/dist/lib/html/hydration-data.js +6 -10
- package/dist/lib/html/hydration-data.js.map +1 -1
- package/dist/lib/html/index.js +3 -19
- package/dist/lib/html/index.js.map +1 -1
- package/dist/lib/html/tags.js +14 -23
- package/dist/lib/html/tags.js.map +1 -1
- package/dist/lib/html/util.js +1 -4
- package/dist/lib/html/util.js.map +1 -1
- package/dist/lib/http/accept.d.ts.map +1 -1
- package/dist/lib/http/accept.js +8 -8
- package/dist/lib/http/accept.js.map +1 -1
- package/dist/lib/http/context.js +1 -4
- package/dist/lib/http/context.js.map +1 -1
- package/dist/lib/http/headers.js +1 -4
- package/dist/lib/http/headers.js.map +1 -1
- package/dist/lib/http/index.js +10 -26
- package/dist/lib/http/index.js.map +1 -1
- package/dist/lib/http/method.js +1 -4
- package/dist/lib/http/method.js.map +1 -1
- package/dist/lib/http/middleware.js +11 -17
- package/dist/lib/http/middleware.js.map +1 -1
- package/dist/lib/http/parser.js +13 -20
- package/dist/lib/http/parser.js.map +1 -1
- package/dist/lib/http/path.js +1 -4
- package/dist/lib/http/path.js.map +1 -1
- package/dist/lib/http/request.d.ts.map +1 -1
- package/dist/lib/http/request.js +32 -47
- package/dist/lib/http/request.js.map +1 -1
- package/dist/lib/http/response.js +14 -27
- package/dist/lib/http/response.js.map +1 -1
- package/dist/lib/http/route.js +9 -12
- package/dist/lib/http/route.js.map +1 -1
- package/dist/lib/http/router.js +8 -13
- package/dist/lib/http/router.js.map +1 -1
- package/dist/lib/http/security-headers.js +10 -15
- package/dist/lib/http/security-headers.js.map +1 -1
- package/dist/lib/http/stream.js +12 -20
- package/dist/lib/http/stream.js.map +1 -1
- package/dist/lib/http/types.js +1 -2
- package/dist/lib/http/url.js +1 -4
- package/dist/lib/http/url.js.map +1 -1
- package/dist/lib/nsid.js +4 -8
- package/dist/lib/nsid.js.map +1 -1
- package/dist/lib/redis.js +4 -7
- package/dist/lib/redis.js.map +1 -1
- package/dist/lib/util/authorization-header.js +11 -15
- package/dist/lib/util/authorization-header.js.map +1 -1
- package/dist/lib/util/cast.js +3 -8
- package/dist/lib/util/cast.js.map +1 -1
- package/dist/lib/util/color.js +23 -32
- package/dist/lib/util/color.js.map +1 -1
- package/dist/lib/util/crypto.js +5 -10
- package/dist/lib/util/crypto.js.map +1 -1
- package/dist/lib/util/date.js +2 -6
- package/dist/lib/util/date.js.map +1 -1
- package/dist/lib/util/error.js +5 -8
- package/dist/lib/util/error.js.map +1 -1
- package/dist/lib/util/function.js +3 -8
- package/dist/lib/util/function.js.map +1 -1
- package/dist/lib/util/locale.js +3 -6
- package/dist/lib/util/locale.js.map +1 -1
- package/dist/lib/util/object.js +1 -4
- package/dist/lib/util/object.js.map +1 -1
- package/dist/lib/util/redirect-uri.js +3 -6
- package/dist/lib/util/redirect-uri.js.map +1 -1
- package/dist/lib/util/time.js +5 -9
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/type.d.ts.map +1 -1
- package/dist/lib/util/type.js +1 -5
- package/dist/lib/util/type.js.map +1 -1
- package/dist/lib/util/ui8.js +3 -8
- package/dist/lib/util/ui8.js.map +1 -1
- package/dist/lib/util/well-known.js +1 -4
- package/dist/lib/util/well-known.js.map +1 -1
- package/dist/lib/util/zod-error.js +4 -8
- package/dist/lib/util/zod-error.js.map +1 -1
- package/dist/lib/write-form-redirect.js +9 -12
- package/dist/lib/write-form-redirect.js.map +1 -1
- package/dist/lib/write-html.js +12 -15
- package/dist/lib/write-html.js.map +1 -1
- package/dist/metadata/build-metadata.js +9 -12
- package/dist/metadata/build-metadata.js.map +1 -1
- package/dist/oauth-client.js +2 -18
- package/dist/oauth-client.js.map +1 -1
- package/dist/oauth-dpop.js +2 -18
- package/dist/oauth-dpop.js.map +1 -1
- package/dist/oauth-errors.js +24 -42
- package/dist/oauth-errors.js.map +1 -1
- package/dist/oauth-hooks.js +8 -15
- package/dist/oauth-hooks.js.map +1 -1
- package/dist/oauth-middleware.js +13 -16
- package/dist/oauth-middleware.js.map +1 -1
- package/dist/oauth-provider.js +108 -125
- package/dist/oauth-provider.js.map +1 -1
- package/dist/oauth-store.js +7 -23
- package/dist/oauth-store.js.map +1 -1
- package/dist/oauth-verifier.js +41 -53
- package/dist/oauth-verifier.js.map +1 -1
- package/dist/oidc/sub.js +2 -5
- package/dist/oidc/sub.js.map +1 -1
- package/dist/replay/replay-manager.js +6 -11
- package/dist/replay/replay-manager.js.map +1 -1
- package/dist/replay/replay-store-memory.js +5 -7
- package/dist/replay/replay-store-memory.js.map +1 -1
- package/dist/replay/replay-store-redis.js +3 -8
- package/dist/replay/replay-store-redis.js.map +1 -1
- package/dist/replay/replay-store.js +3 -8
- package/dist/replay/replay-store.js.map +1 -1
- package/dist/request/code.js +10 -15
- package/dist/request/code.js.map +1 -1
- package/dist/request/request-data.js +1 -5
- package/dist/request/request-data.js.map +1 -1
- package/dist/request/request-id.js +9 -13
- package/dist/request/request-id.js.map +1 -1
- package/dist/request/request-manager.js +61 -71
- package/dist/request/request-manager.js.map +1 -1
- package/dist/request/request-store.js +9 -27
- package/dist/request/request-store.js.map +1 -1
- package/dist/request/request-uri.js +17 -23
- package/dist/request/request-uri.js.map +1 -1
- package/dist/result/authorization-redirect-parameters.js +1 -2
- package/dist/result/authorization-result-authorize-page.js +1 -2
- package/dist/result/authorization-result-redirect.js +1 -2
- package/dist/router/assets/assets-manifest.d.ts.map +1 -1
- package/dist/router/assets/assets-manifest.js +14 -15
- package/dist/router/assets/assets-manifest.js.map +1 -1
- package/dist/router/assets/assets.d.ts.map +1 -1
- package/dist/router/assets/assets.js +25 -27
- package/dist/router/assets/assets.js.map +1 -1
- package/dist/router/assets/csrf.js +16 -25
- package/dist/router/assets/csrf.js.map +1 -1
- package/dist/router/assets/send-account-page.js +3 -6
- package/dist/router/assets/send-account-page.js.map +1 -1
- package/dist/router/assets/send-authorization-page.js +3 -6
- package/dist/router/assets/send-authorization-page.js.map +1 -1
- package/dist/router/assets/send-cookie-error-page.js +3 -6
- package/dist/router/assets/send-cookie-error-page.js.map +1 -1
- package/dist/router/assets/send-error-page.js +6 -9
- package/dist/router/assets/send-error-page.js.map +1 -1
- package/dist/router/assets/send-redirect.js +12 -20
- package/dist/router/assets/send-redirect.js.map +1 -1
- package/dist/router/create-account-page-middleware.js +11 -14
- package/dist/router/create-account-page-middleware.js.map +1 -1
- package/dist/router/create-api-middleware.js +83 -90
- package/dist/router/create-api-middleware.js.map +1 -1
- package/dist/router/create-authorization-page-middleware.js +43 -46
- package/dist/router/create-authorization-page-middleware.js.map +1 -1
- package/dist/router/create-oauth-middleware.js +31 -34
- package/dist/router/create-oauth-middleware.js.map +1 -1
- package/dist/router/error-handler.js +1 -2
- package/dist/router/middleware-options.js +1 -2
- package/dist/signer/access-token-payload.js +12 -15
- package/dist/signer/access-token-payload.js.map +1 -1
- package/dist/signer/api-token-payload.js +8 -11
- package/dist/signer/api-token-payload.js.map +1 -1
- package/dist/signer/signer.js +11 -17
- package/dist/signer/signer.js.map +1 -1
- package/dist/token/refresh-token.js +10 -15
- package/dist/token/refresh-token.js.map +1 -1
- package/dist/token/token-claims.js +1 -2
- package/dist/token/token-data.js +1 -2
- package/dist/token/token-id.js +10 -15
- package/dist/token/token-id.js.map +1 -1
- package/dist/token/token-manager.js +40 -51
- package/dist/token/token-manager.js.map +1 -1
- package/dist/token/token-store.js +7 -25
- package/dist/token/token-store.js.map +1 -1
- package/dist/types/authorization-response-error.js +8 -12
- package/dist/types/authorization-response-error.js.map +1 -1
- package/dist/types/color-hue.js +2 -5
- package/dist/types/color-hue.js.map +1 -1
- package/dist/types/email-otp.js +2 -5
- package/dist/types/email-otp.js.map +1 -1
- package/dist/types/email.js +6 -9
- package/dist/types/email.js.map +1 -1
- package/dist/types/handle.js +6 -9
- package/dist/types/handle.js.map +1 -1
- package/dist/types/invite-code.js +2 -5
- package/dist/types/invite-code.js.map +1 -1
- package/dist/types/par-response-error.js +5 -9
- package/dist/types/par-response-error.js.map +1 -1
- package/dist/types/password.js +3 -6
- package/dist/types/password.js.map +1 -1
- package/dist/types/rgb-color.js +7 -10
- package/dist/types/rgb-color.js.map +1 -1
- package/package.json +20 -22
- package/src/dpop/dpop-nonce.ts +1 -1
- package/src/errors/invalid-invite-code-error.ts +1 -1
- package/src/lib/http/accept.ts +4 -1
- package/src/lib/http/request.ts +4 -1
- package/src/lib/util/type.ts +0 -1
- package/src/router/assets/assets-manifest.ts +3 -1
- package/src/router/assets/assets.ts +2 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-manager.js","sourceRoot":"","sources":["../../src/request/request-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAtprotoDid } from '@atproto/did'\nimport { LexResolverError } from '@atproto/lex-resolver'\nimport type { Account } from '@atproto/oauth-provider-api'\nimport { isAtprotoOauthScope } from '@atproto/oauth-scopes'\nimport {\n OAuthAuthorizationRequestParameters,\n OAuthAuthorizationServerMetadata,\n} from '@atproto/oauth-types'\nimport { isValidHandle } from '@atproto/syntax'\nimport { ClientAuth } from '../client/client-auth.js'\nimport { ClientId } from '../client/client-id.js'\nimport { Client } from '../client/client.js'\nimport {\n AUTHORIZATION_INACTIVITY_TIMEOUT,\n NODE_ENV,\n PAR_EXPIRES_IN,\n TOKEN_MAX_AGE,\n} from '../constants.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { AccessDeniedError } from '../errors/access-denied-error.js'\nimport { AuthorizationError } from '../errors/authorization-error.js'\nimport { ConsentRequiredError } from '../errors/consent-required-error.js'\nimport { InvalidAuthorizationDetailsError } from '../errors/invalid-authorization-details-error.js'\nimport { InvalidGrantError } from '../errors/invalid-grant-error.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { InvalidScopeError } from '../errors/invalid-scope-error.js'\nimport { LexiconManager } from '../lexicon/lexicon-manager.js'\nimport { RequestMetadata } from '../lib/http/request.js'\nimport { OAuthHooks } from '../oauth-hooks.js'\nimport { Signer } from '../signer/signer.js'\nimport { Code, generateCode } from './code.js'\nimport {\n RequestDataAuthorized,\n isRequestDataAuthorized,\n} from './request-data.js'\nimport { generateRequestId } from './request-id.js'\nimport { RequestStore, UpdateRequestData } from './request-store.js'\nimport {\n RequestUri,\n decodeRequestUri,\n encodeRequestUri,\n} from './request-uri.js'\n\nexport class RequestManager {\n constructor(\n protected readonly store: RequestStore,\n protected readonly lexiconManager: LexiconManager,\n protected readonly signer: Signer,\n protected readonly metadata: OAuthAuthorizationServerMetadata,\n protected readonly hooks: OAuthHooks,\n protected readonly tokenMaxAge = TOKEN_MAX_AGE,\n ) {}\n\n protected createTokenExpiry() {\n return new Date(Date.now() + this.tokenMaxAge)\n }\n\n async createAuthorizationRequest(\n client: Client,\n clientAuth: null | ClientAuth,\n input: Readonly<OAuthAuthorizationRequestParameters>,\n deviceId: null | DeviceId,\n ) {\n const parameters = await this.validate(client, clientAuth, input)\n\n await this.hooks.onAuthorizationRequest?.call(null, {\n client,\n clientAuth,\n parameters,\n })\n\n const expiresAt = new Date(Date.now() + PAR_EXPIRES_IN)\n const requestId = await generateRequestId()\n\n await this.store.createRequest(requestId, {\n clientId: client.id,\n clientAuth,\n parameters,\n expiresAt,\n deviceId,\n sub: null,\n code: null,\n })\n\n const requestUri = encodeRequestUri(requestId)\n return { requestUri, expiresAt, parameters }\n }\n\n protected async validate(\n client: Client,\n clientAuth: null | ClientAuth,\n parameters: Readonly<OAuthAuthorizationRequestParameters>,\n ): Promise<Readonly<OAuthAuthorizationRequestParameters>> {\n // -------------------------------\n // Validate unsupported parameters\n // -------------------------------\n\n for (const k of [\n // Known unsupported OIDC parameters\n 'claims',\n 'id_token_hint',\n 'nonce', // note that OIDC \"nonce\" is redundant with PKCE\n ] as const) {\n if (parameters[k] !== undefined) {\n throw new AuthorizationError(parameters, `Unsupported \"${k}\" parameter`)\n }\n }\n\n // -----------------------\n // Validate against server\n // -----------------------\n\n if (\n !this.metadata.response_types_supported?.includes(\n parameters.response_type,\n )\n ) {\n throw new AuthorizationError(\n parameters,\n `Unsupported response_type \"${parameters.response_type}\"`,\n 'unsupported_response_type',\n )\n }\n\n if (\n parameters.response_type === 'code' &&\n !this.metadata.grant_types_supported?.includes('authorization_code')\n ) {\n throw new AuthorizationError(\n parameters,\n `Unsupported grant_type \"authorization_code\"`,\n 'invalid_request',\n )\n }\n\n if (parameters.authorization_details) {\n for (const detail of parameters.authorization_details) {\n if (\n !this.metadata.authorization_details_types_supported?.includes(\n detail.type,\n )\n ) {\n throw new InvalidAuthorizationDetailsError(\n parameters,\n `Unsupported \"authorization_details\" type \"${detail.type}\"`,\n )\n }\n }\n }\n\n // -----------------------\n // Validate against client\n // -----------------------\n\n parameters = client.validateRequest(parameters)\n\n // -------------------\n // Validate parameters\n // -------------------\n\n if (!parameters.redirect_uri) {\n // Should already be ensured by client.validateRequest(). Adding here for\n // clarity & extra safety.\n throw new AuthorizationError(parameters, 'Missing \"redirect_uri\"')\n }\n\n // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10#section-1.4.1\n // > The authorization server MAY fully or partially ignore the scope\n // > requested by the client, based on the authorization server policy or\n // > the resource owner's instructions. If the issued access token scope is\n // > different from the one requested by the client, the authorization\n // > server MUST include the scope response parameter in the token response\n // > (Section 3.2.3) to inform the client of the actual scope granted.\n\n // Let's make sure the scopes are unique (to reduce the token & storage\n // size).\n const scopes = new Set(parameters.scope?.split(' '))\n\n // @NOTE An app requesting a not yet supported list of scopes will need to\n // re-authenticate the user once the scopes are supported. This is due to\n // the fact that the AS does not know how to properly display those scopes\n // to the user, so it cannot properly ask for consent.\n const scope =\n Array.from(scopes).filter(isAtprotoOauthScope).join(' ') || undefined\n parameters = { ...parameters, scope }\n\n if (parameters.code_challenge) {\n switch (parameters.code_challenge_method) {\n case undefined:\n // https://datatracker.ietf.org/doc/html/rfc7636#section-4.3\n parameters = { ...parameters, code_challenge_method: 'plain' }\n // falls through\n case 'plain':\n case 'S256':\n break\n default: {\n throw new AuthorizationError(\n parameters,\n `Unsupported code_challenge_method \"${parameters.code_challenge_method}\"`,\n )\n }\n }\n } else {\n if (parameters.code_challenge_method) {\n // https://datatracker.ietf.org/doc/html/rfc7636#section-4.4.1\n throw new AuthorizationError(\n parameters,\n 'code_challenge is required when code_challenge_method is provided',\n )\n }\n\n // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-4.1.2.1\n //\n // > An AS MUST reject requests without a code_challenge from public\n // > clients, and MUST reject such requests from other clients unless\n // > there is reasonable assurance that the client mitigates\n // > authorization code injection in other ways. See Section 7.5.1 for\n // > details.\n //\n // > [...] In the specific deployment and the specific request, there is\n // > reasonable assurance by the authorization server that the client\n // > implements the OpenID Connect nonce mechanism properly.\n //\n // atproto does not implement the OpenID Connect nonce mechanism, so we\n // require the use of PKCE for all clients.\n\n throw new AuthorizationError(parameters, 'Use of PKCE is required')\n }\n\n // -----------------\n // atproto extension\n // -----------------\n\n if (parameters.response_type !== 'code') {\n throw new AuthorizationError(\n parameters,\n 'atproto only supports the \"code\" response_type',\n )\n }\n\n if (!scopes.has('atproto')) {\n throw new InvalidScopeError(parameters, 'The \"atproto\" scope is required')\n } else if (scopes.has('openid')) {\n throw new InvalidScopeError(\n parameters,\n 'OpenID Connect is not compatible with atproto',\n )\n }\n\n if (parameters.code_challenge_method !== 'S256') {\n throw new AuthorizationError(\n parameters,\n 'atproto requires use of \"S256\" code_challenge_method',\n )\n }\n\n // atproto extension: if the client is not trusted, and not authenticated,\n // force users to consent to authorization requests. We do this to avoid\n // unauthenticated clients from being able to silently re-authenticate\n // users.\n if (\n !client.info.isTrusted &&\n !client.info.isFirstParty &&\n client.metadata.token_endpoint_auth_method === 'none'\n ) {\n if (parameters.prompt === 'none') {\n throw new ConsentRequiredError(\n parameters,\n 'Public clients are not allowed to use silent-sign-on',\n )\n }\n\n // force \"consent\" for unauthenticated third party clients, unless they\n // are trying to create accounts:\n if (parameters.prompt !== 'create') {\n parameters = { ...parameters, prompt: 'consent' }\n }\n }\n\n // atproto extension: ensure that the login_hint is a valid handle or DID\n // @NOTE we to allow invalid case here, which is not spec'd anywhere.\n const hint = parameters.login_hint?.toLowerCase()\n if (hint) {\n if (!isAtprotoDid(hint) && !isValidHandle(hint)) {\n throw new AuthorizationError(parameters, `Invalid login_hint \"${hint}\"`)\n }\n\n // @TODO: ensure that the account actually exists on this server (there is\n // no point in showing the UI to the user if the account does not exist).\n\n // Update the parameters to ensure the right case is used\n parameters = { ...parameters, login_hint: hint }\n }\n\n // Make sure that every nsid in the scope resolves to a valid permission set\n // lexicon\n if (parameters.scope) {\n try {\n await this.lexiconManager.getPermissionSetsFromScope(parameters.scope)\n } catch (err) {\n // Parse expected errors\n if (err instanceof LexResolverError) {\n throw new AuthorizationError(\n parameters,\n err.message,\n 'invalid_scope',\n err,\n )\n }\n\n // Unexpected error\n throw err\n }\n }\n\n return parameters\n }\n\n /**\n * Reads the {@link ClientId} associated with a request URI without any of\n * the validation or side-effects performed by {@link RequestManager.get}\n *\n * Returns `undefined` when no such request exists.\n */\n async peekClientId(requestUri: RequestUri): Promise<ClientId | undefined> {\n const requestId = decodeRequestUri(requestUri)\n const data = await this.store.readRequest(requestId)\n return data?.clientId\n }\n\n async get(requestUri: RequestUri, deviceId?: DeviceId, clientId?: ClientId) {\n const requestId = decodeRequestUri(requestUri)\n\n const data = await this.store.readRequest(requestId)\n if (!data) throw new InvalidRequestError('Unknown request_uri')\n\n const updates: UpdateRequestData = {}\n\n try {\n if (data.sub || data.code) {\n // If an account was linked to the request, the next step is to exchange\n // the code for a token.\n throw new AccessDeniedError(\n data.parameters,\n 'This request was already authorized',\n )\n }\n\n if (data.expiresAt < new Date()) {\n throw new AccessDeniedError(data.parameters, 'This request has expired')\n } else {\n updates.expiresAt = new Date(\n Date.now() + AUTHORIZATION_INACTIVITY_TIMEOUT,\n )\n }\n\n if (clientId != null && data.clientId !== clientId) {\n throw new AccessDeniedError(\n data.parameters,\n 'This request was initiated for another client',\n )\n }\n\n if (deviceId != null) {\n if (!data.deviceId) {\n updates.deviceId = deviceId\n } else if (data.deviceId !== deviceId) {\n throw new AccessDeniedError(\n data.parameters,\n 'This request was initiated from another device',\n )\n }\n }\n } catch (err) {\n await this.store.deleteRequest(requestId)\n throw err\n }\n\n if (Object.keys(updates).length > 0) {\n await this.store.updateRequest(requestId, updates)\n }\n\n return {\n requestUri,\n expiresAt: updates.expiresAt || data.expiresAt,\n parameters: data.parameters,\n clientId: data.clientId,\n }\n }\n\n async setAuthorized(\n requestUri: RequestUri,\n client: Client,\n account: Account,\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n scopeOverride?: string,\n ): Promise<Code> {\n const requestId = decodeRequestUri(requestUri)\n\n const data = await this.store.readRequest(requestId)\n if (!data) throw new InvalidRequestError('Unknown request_uri')\n\n let { parameters } = data\n\n try {\n if (data.expiresAt < new Date()) {\n throw new AccessDeniedError(parameters, 'This request has expired')\n }\n if (!data.deviceId) {\n throw new AccessDeniedError(\n parameters,\n 'This request was not initiated',\n )\n }\n if (data.deviceId !== deviceId) {\n throw new AccessDeniedError(\n parameters,\n 'This request was initiated from another device',\n )\n }\n if (data.sub || data.code) {\n throw new AccessDeniedError(\n parameters,\n 'This request was already authorized',\n )\n }\n\n // If a new scope value is provided, update the parameters by ensuring\n // that every existing scope in the parameters is also present in the\n // override value. This allows the user to remove scopes from the request,\n // but not to add new ones.\n if (scopeOverride != null) {\n const allowedScopes = new Set(scopeOverride.split(' '))\n const existingScopes = parameters.scope?.split(' ')\n\n // Compute the intersection of the existing scopes and the overrides.\n const newScopes = existingScopes?.filter((s) => allowedScopes.has(s))\n\n // Validate: make sure the new scopes are valid\n if (!newScopes?.includes('atproto')) {\n throw new AccessDeniedError(\n parameters,\n 'The \"atproto\" scope is required',\n )\n }\n\n parameters = { ...parameters, scope: newScopes.join(' ') }\n }\n\n // Only response_type=code is supported\n const code = await generateCode()\n\n // Bind the request to the account, preventing it from being used again.\n await this.store.updateRequest(requestId, {\n sub: account.sub,\n code,\n // Allow the client to exchange the code for a token within the next 60 seconds.\n expiresAt: new Date(Date.now() + AUTHORIZATION_INACTIVITY_TIMEOUT),\n parameters,\n })\n\n await this.hooks.onAuthorized?.call(null, {\n client,\n account,\n parameters,\n deviceId,\n deviceMetadata,\n requestId,\n })\n\n return code\n } catch (err) {\n await this.store.deleteRequest(requestId)\n throw err\n }\n }\n\n /**\n * @note If this method throws an error, any token previously generated from\n * the same `code` **must** me revoked.\n */\n public async consumeCode(code: Code): Promise<RequestDataAuthorized> {\n const result = await this.store.consumeRequestCode(code)\n if (!result) throw new InvalidGrantError('Invalid code')\n\n const { requestId, data } = result\n\n // Fool-proofing the store implementation against code replay attacks (in\n // case consumeRequestCode() does not delete the request).\n if (NODE_ENV !== 'production') {\n const result = await this.store.readRequest(requestId)\n if (result) {\n throw new Error('Invalid store implementation: request not deleted')\n }\n }\n\n if (!isRequestDataAuthorized(data) || data.code !== code) {\n // Should never happen: maybe the store implementation is faulty ?\n throw new Error('Unexpected request state')\n }\n\n if (data.expiresAt < new Date()) {\n throw new InvalidGrantError('This code has expired')\n }\n\n return data\n }\n\n async delete(requestUri: RequestUri): Promise<void> {\n const requestId = decodeRequestUri(requestUri)\n await this.store.deleteRequest(requestId)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"request-manager.js","sourceRoot":"","sources":["../../src/request/request-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAtprotoDid } from '@atproto/did'\nimport { LexResolverError } from '@atproto/lex-resolver'\nimport type { Account } from '@atproto/oauth-provider-api'\nimport { isAtprotoOauthScope } from '@atproto/oauth-scopes'\nimport {\n OAuthAuthorizationRequestParameters,\n OAuthAuthorizationServerMetadata,\n} from '@atproto/oauth-types'\nimport { isValidHandle } from '@atproto/syntax'\nimport { ClientAuth } from '../client/client-auth.js'\nimport { ClientId } from '../client/client-id.js'\nimport { Client } from '../client/client.js'\nimport {\n AUTHORIZATION_INACTIVITY_TIMEOUT,\n NODE_ENV,\n PAR_EXPIRES_IN,\n TOKEN_MAX_AGE,\n} from '../constants.js'\nimport { DeviceId } from '../device/device-id.js'\nimport { AccessDeniedError } from '../errors/access-denied-error.js'\nimport { AuthorizationError } from '../errors/authorization-error.js'\nimport { ConsentRequiredError } from '../errors/consent-required-error.js'\nimport { InvalidAuthorizationDetailsError } from '../errors/invalid-authorization-details-error.js'\nimport { InvalidGrantError } from '../errors/invalid-grant-error.js'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { InvalidScopeError } from '../errors/invalid-scope-error.js'\nimport { LexiconManager } from '../lexicon/lexicon-manager.js'\nimport { RequestMetadata } from '../lib/http/request.js'\nimport { OAuthHooks } from '../oauth-hooks.js'\nimport { Signer } from '../signer/signer.js'\nimport { Code, generateCode } from './code.js'\nimport {\n RequestDataAuthorized,\n isRequestDataAuthorized,\n} from './request-data.js'\nimport { generateRequestId } from './request-id.js'\nimport { RequestStore, UpdateRequestData } from './request-store.js'\nimport {\n RequestUri,\n decodeRequestUri,\n encodeRequestUri,\n} from './request-uri.js'\n\nexport class RequestManager {\n constructor(\n protected readonly store: RequestStore,\n protected readonly lexiconManager: LexiconManager,\n protected readonly signer: Signer,\n protected readonly metadata: OAuthAuthorizationServerMetadata,\n protected readonly hooks: OAuthHooks,\n protected readonly tokenMaxAge = TOKEN_MAX_AGE,\n ) {}\n\n protected createTokenExpiry() {\n return new Date(Date.now() + this.tokenMaxAge)\n }\n\n async createAuthorizationRequest(\n client: Client,\n clientAuth: null | ClientAuth,\n input: Readonly<OAuthAuthorizationRequestParameters>,\n deviceId: null | DeviceId,\n ) {\n const parameters = await this.validate(client, clientAuth, input)\n\n await this.hooks.onAuthorizationRequest?.call(null, {\n client,\n clientAuth,\n parameters,\n })\n\n const expiresAt = new Date(Date.now() + PAR_EXPIRES_IN)\n const requestId = await generateRequestId()\n\n await this.store.createRequest(requestId, {\n clientId: client.id,\n clientAuth,\n parameters,\n expiresAt,\n deviceId,\n sub: null,\n code: null,\n })\n\n const requestUri = encodeRequestUri(requestId)\n return { requestUri, expiresAt, parameters }\n }\n\n protected async validate(\n client: Client,\n clientAuth: null | ClientAuth,\n parameters: Readonly<OAuthAuthorizationRequestParameters>,\n ): Promise<Readonly<OAuthAuthorizationRequestParameters>> {\n // -------------------------------\n // Validate unsupported parameters\n // -------------------------------\n\n for (const k of [\n // Known unsupported OIDC parameters\n 'claims',\n 'id_token_hint',\n 'nonce', // note that OIDC \"nonce\" is redundant with PKCE\n ] as const) {\n if (parameters[k] !== undefined) {\n throw new AuthorizationError(parameters, `Unsupported \"${k}\" parameter`)\n }\n }\n\n // -----------------------\n // Validate against server\n // -----------------------\n\n if (\n !this.metadata.response_types_supported?.includes(\n parameters.response_type,\n )\n ) {\n throw new AuthorizationError(\n parameters,\n `Unsupported response_type \"${parameters.response_type}\"`,\n 'unsupported_response_type',\n )\n }\n\n if (\n parameters.response_type === 'code' &&\n !this.metadata.grant_types_supported?.includes('authorization_code')\n ) {\n throw new AuthorizationError(\n parameters,\n `Unsupported grant_type \"authorization_code\"`,\n 'invalid_request',\n )\n }\n\n if (parameters.authorization_details) {\n for (const detail of parameters.authorization_details) {\n if (\n !this.metadata.authorization_details_types_supported?.includes(\n detail.type,\n )\n ) {\n throw new InvalidAuthorizationDetailsError(\n parameters,\n `Unsupported \"authorization_details\" type \"${detail.type}\"`,\n )\n }\n }\n }\n\n // -----------------------\n // Validate against client\n // -----------------------\n\n parameters = client.validateRequest(parameters)\n\n // -------------------\n // Validate parameters\n // -------------------\n\n if (!parameters.redirect_uri) {\n // Should already be ensured by client.validateRequest(). Adding here for\n // clarity & extra safety.\n throw new AuthorizationError(parameters, 'Missing \"redirect_uri\"')\n }\n\n // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-10#section-1.4.1\n // > The authorization server MAY fully or partially ignore the scope\n // > requested by the client, based on the authorization server policy or\n // > the resource owner's instructions. If the issued access token scope is\n // > different from the one requested by the client, the authorization\n // > server MUST include the scope response parameter in the token response\n // > (Section 3.2.3) to inform the client of the actual scope granted.\n\n // Let's make sure the scopes are unique (to reduce the token & storage\n // size).\n const scopes = new Set(parameters.scope?.split(' '))\n\n // @NOTE An app requesting a not yet supported list of scopes will need to\n // re-authenticate the user once the scopes are supported. This is due to\n // the fact that the AS does not know how to properly display those scopes\n // to the user, so it cannot properly ask for consent.\n const scope =\n Array.from(scopes).filter(isAtprotoOauthScope).join(' ') || undefined\n parameters = { ...parameters, scope }\n\n if (parameters.code_challenge) {\n switch (parameters.code_challenge_method) {\n case undefined:\n // https://datatracker.ietf.org/doc/html/rfc7636#section-4.3\n parameters = { ...parameters, code_challenge_method: 'plain' }\n // falls through\n case 'plain':\n case 'S256':\n break\n default: {\n throw new AuthorizationError(\n parameters,\n `Unsupported code_challenge_method \"${parameters.code_challenge_method}\"`,\n )\n }\n }\n } else {\n if (parameters.code_challenge_method) {\n // https://datatracker.ietf.org/doc/html/rfc7636#section-4.4.1\n throw new AuthorizationError(\n parameters,\n 'code_challenge is required when code_challenge_method is provided',\n )\n }\n\n // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-4.1.2.1\n //\n // > An AS MUST reject requests without a code_challenge from public\n // > clients, and MUST reject such requests from other clients unless\n // > there is reasonable assurance that the client mitigates\n // > authorization code injection in other ways. See Section 7.5.1 for\n // > details.\n //\n // > [...] In the specific deployment and the specific request, there is\n // > reasonable assurance by the authorization server that the client\n // > implements the OpenID Connect nonce mechanism properly.\n //\n // atproto does not implement the OpenID Connect nonce mechanism, so we\n // require the use of PKCE for all clients.\n\n throw new AuthorizationError(parameters, 'Use of PKCE is required')\n }\n\n // -----------------\n // atproto extension\n // -----------------\n\n if (parameters.response_type !== 'code') {\n throw new AuthorizationError(\n parameters,\n 'atproto only supports the \"code\" response_type',\n )\n }\n\n if (!scopes.has('atproto')) {\n throw new InvalidScopeError(parameters, 'The \"atproto\" scope is required')\n } else if (scopes.has('openid')) {\n throw new InvalidScopeError(\n parameters,\n 'OpenID Connect is not compatible with atproto',\n )\n }\n\n if (parameters.code_challenge_method !== 'S256') {\n throw new AuthorizationError(\n parameters,\n 'atproto requires use of \"S256\" code_challenge_method',\n )\n }\n\n // atproto extension: if the client is not trusted, and not authenticated,\n // force users to consent to authorization requests. We do this to avoid\n // unauthenticated clients from being able to silently re-authenticate\n // users.\n if (\n !client.info.isTrusted &&\n !client.info.isFirstParty &&\n client.metadata.token_endpoint_auth_method === 'none'\n ) {\n if (parameters.prompt === 'none') {\n throw new ConsentRequiredError(\n parameters,\n 'Public clients are not allowed to use silent-sign-on',\n )\n }\n\n // force \"consent\" for unauthenticated third party clients, unless they\n // are trying to create accounts:\n if (parameters.prompt !== 'create') {\n parameters = { ...parameters, prompt: 'consent' }\n }\n }\n\n // atproto extension: ensure that the login_hint is a valid handle or DID\n // @NOTE we to allow invalid case here, which is not spec'd anywhere.\n const hint = parameters.login_hint?.toLowerCase()\n if (hint) {\n if (!isAtprotoDid(hint) && !isValidHandle(hint)) {\n throw new AuthorizationError(parameters, `Invalid login_hint \"${hint}\"`)\n }\n\n // @TODO: ensure that the account actually exists on this server (there is\n // no point in showing the UI to the user if the account does not exist).\n\n // Update the parameters to ensure the right case is used\n parameters = { ...parameters, login_hint: hint }\n }\n\n // Make sure that every nsid in the scope resolves to a valid permission set\n // lexicon\n if (parameters.scope) {\n try {\n await this.lexiconManager.getPermissionSetsFromScope(parameters.scope)\n } catch (err) {\n // Parse expected errors\n if (err instanceof LexResolverError) {\n throw new AuthorizationError(\n parameters,\n err.message,\n 'invalid_scope',\n err,\n )\n }\n\n // Unexpected error\n throw err\n }\n }\n\n return parameters\n }\n\n /**\n * Reads the {@link ClientId} associated with a request URI without any of\n * the validation or side-effects performed by {@link RequestManager.get}\n *\n * Returns `undefined` when no such request exists.\n */\n async peekClientId(requestUri: RequestUri): Promise<ClientId | undefined> {\n const requestId = decodeRequestUri(requestUri)\n const data = await this.store.readRequest(requestId)\n return data?.clientId\n }\n\n async get(requestUri: RequestUri, deviceId?: DeviceId, clientId?: ClientId) {\n const requestId = decodeRequestUri(requestUri)\n\n const data = await this.store.readRequest(requestId)\n if (!data) throw new InvalidRequestError('Unknown request_uri')\n\n const updates: UpdateRequestData = {}\n\n try {\n if (data.sub || data.code) {\n // If an account was linked to the request, the next step is to exchange\n // the code for a token.\n throw new AccessDeniedError(\n data.parameters,\n 'This request was already authorized',\n )\n }\n\n if (data.expiresAt < new Date()) {\n throw new AccessDeniedError(data.parameters, 'This request has expired')\n } else {\n updates.expiresAt = new Date(\n Date.now() + AUTHORIZATION_INACTIVITY_TIMEOUT,\n )\n }\n\n if (clientId != null && data.clientId !== clientId) {\n throw new AccessDeniedError(\n data.parameters,\n 'This request was initiated for another client',\n )\n }\n\n if (deviceId != null) {\n if (!data.deviceId) {\n updates.deviceId = deviceId\n } else if (data.deviceId !== deviceId) {\n throw new AccessDeniedError(\n data.parameters,\n 'This request was initiated from another device',\n )\n }\n }\n } catch (err) {\n await this.store.deleteRequest(requestId)\n throw err\n }\n\n if (Object.keys(updates).length > 0) {\n await this.store.updateRequest(requestId, updates)\n }\n\n return {\n requestUri,\n expiresAt: updates.expiresAt || data.expiresAt,\n parameters: data.parameters,\n clientId: data.clientId,\n }\n }\n\n async setAuthorized(\n requestUri: RequestUri,\n client: Client,\n account: Account,\n deviceId: DeviceId,\n deviceMetadata: RequestMetadata,\n scopeOverride?: string,\n ): Promise<Code> {\n const requestId = decodeRequestUri(requestUri)\n\n const data = await this.store.readRequest(requestId)\n if (!data) throw new InvalidRequestError('Unknown request_uri')\n\n let { parameters } = data\n\n try {\n if (data.expiresAt < new Date()) {\n throw new AccessDeniedError(parameters, 'This request has expired')\n }\n if (!data.deviceId) {\n throw new AccessDeniedError(\n parameters,\n 'This request was not initiated',\n )\n }\n if (data.deviceId !== deviceId) {\n throw new AccessDeniedError(\n parameters,\n 'This request was initiated from another device',\n )\n }\n if (data.sub || data.code) {\n throw new AccessDeniedError(\n parameters,\n 'This request was already authorized',\n )\n }\n\n // If a new scope value is provided, update the parameters by ensuring\n // that every existing scope in the parameters is also present in the\n // override value. This allows the user to remove scopes from the request,\n // but not to add new ones.\n if (scopeOverride != null) {\n const allowedScopes = new Set(scopeOverride.split(' '))\n const existingScopes = parameters.scope?.split(' ')\n\n // Compute the intersection of the existing scopes and the overrides.\n const newScopes = existingScopes?.filter((s) => allowedScopes.has(s))\n\n // Validate: make sure the new scopes are valid\n if (!newScopes?.includes('atproto')) {\n throw new AccessDeniedError(\n parameters,\n 'The \"atproto\" scope is required',\n )\n }\n\n parameters = { ...parameters, scope: newScopes.join(' ') }\n }\n\n // Only response_type=code is supported\n const code = await generateCode()\n\n // Bind the request to the account, preventing it from being used again.\n await this.store.updateRequest(requestId, {\n sub: account.sub,\n code,\n // Allow the client to exchange the code for a token within the next 60 seconds.\n expiresAt: new Date(Date.now() + AUTHORIZATION_INACTIVITY_TIMEOUT),\n parameters,\n })\n\n await this.hooks.onAuthorized?.call(null, {\n client,\n account,\n parameters,\n deviceId,\n deviceMetadata,\n requestId,\n })\n\n return code\n } catch (err) {\n await this.store.deleteRequest(requestId)\n throw err\n }\n }\n\n /**\n * @note If this method throws an error, any token previously generated from\n * the same `code` **must** me revoked.\n */\n public async consumeCode(code: Code): Promise<RequestDataAuthorized> {\n const result = await this.store.consumeRequestCode(code)\n if (!result) throw new InvalidGrantError('Invalid code')\n\n const { requestId, data } = result\n\n // Fool-proofing the store implementation against code replay attacks (in\n // case consumeRequestCode() does not delete the request).\n if (NODE_ENV !== 'production') {\n const result = await this.store.readRequest(requestId)\n if (result) {\n throw new Error('Invalid store implementation: request not deleted')\n }\n }\n\n if (!isRequestDataAuthorized(data) || data.code !== code) {\n // Should never happen: maybe the store implementation is faulty ?\n throw new Error('Unexpected request state')\n }\n\n if (data.expiresAt < new Date()) {\n throw new InvalidGrantError('This code has expired')\n }\n\n return data\n }\n\n async delete(requestUri: RequestUri): Promise<void> {\n const requestId = decodeRequestUri(requestUri)\n await this.store.deleteRequest(requestId)\n }\n}\n"]}
|
|
@@ -1,37 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.isRequestStore = exports.InvalidGrantError = void 0;
|
|
18
|
-
exports.asRequestStore = asRequestStore;
|
|
19
|
-
const invalid_grant_error_js_1 = require("../errors/invalid-grant-error.js");
|
|
20
|
-
Object.defineProperty(exports, "InvalidGrantError", { enumerable: true, get: function () { return invalid_grant_error_js_1.InvalidGrantError; } });
|
|
21
|
-
const type_js_1 = require("../lib/util/type.js");
|
|
1
|
+
import { InvalidGrantError } from '../errors/invalid-grant-error.js';
|
|
2
|
+
import { buildInterfaceChecker } from '../lib/util/type.js';
|
|
22
3
|
// Export all types needed to implement the RequestStore interface
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
4
|
+
export * from './code.js';
|
|
5
|
+
export * from './request-data.js';
|
|
6
|
+
export * from './request-id.js';
|
|
7
|
+
export { InvalidGrantError };
|
|
8
|
+
export const isRequestStore = buildInterfaceChecker([
|
|
27
9
|
'createRequest',
|
|
28
10
|
'readRequest',
|
|
29
11
|
'updateRequest',
|
|
30
12
|
'deleteRequest',
|
|
31
13
|
'consumeRequestCode',
|
|
32
14
|
]);
|
|
33
|
-
function asRequestStore(implementation) {
|
|
34
|
-
if (!implementation || !
|
|
15
|
+
export function asRequestStore(implementation) {
|
|
16
|
+
if (!implementation || !isRequestStore(implementation)) {
|
|
35
17
|
throw new Error('Invalid RequestStore implementation');
|
|
36
18
|
}
|
|
37
19
|
return implementation;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-store.js","sourceRoot":"","sources":["../../src/request/request-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"request-store.js","sourceRoot":"","sources":["../../src/request/request-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,EAAa,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAKtE,kEAAkE;AAClE,cAAc,WAAW,CAAA;AACzB,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAa/B,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAsB5B,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAAe;IAChE,eAAe;IACf,aAAa;IACb,eAAe;IACf,eAAe;IACf,oBAAoB;CACrB,CAAC,CAAA;AAEF,MAAM,UAAU,cAAc,CAC5B,cAAkB;IAElB,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC","sourcesContent":["import { InvalidGrantError } from '../errors/invalid-grant-error.js'\nimport { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'\nimport { Code } from './code.js'\nimport { RequestData } from './request-data.js'\nimport { RequestId } from './request-id.js'\n\n// Export all types needed to implement the RequestStore interface\nexport * from './code.js'\nexport * from './request-data.js'\nexport * from './request-id.js'\nexport type { Awaitable }\n\nexport type UpdateRequestData = Pick<\n Partial<RequestData>,\n 'sub' | 'code' | 'deviceId' | 'expiresAt' | 'parameters'\n>\n\nexport type FoundRequestResult = {\n requestId: RequestId\n data: RequestData\n}\n\nexport { InvalidGrantError }\n\nexport interface RequestStore {\n createRequest(requestId: RequestId, data: RequestData): Awaitable<void>\n /**\n * Note that expired requests **can** be returned to yield a different error\n * message than if the request was not found.\n */\n readRequest(requestId: RequestId): Awaitable<RequestData | null>\n updateRequest(requestId: RequestId, data: UpdateRequestData): Awaitable<void>\n deleteRequest(requestId: RequestId): void | Awaitable<void>\n /**\n * @note it is **IMPORTANT** that this method prevents concurrent retrieval of\n * the same code. If two requests are made with the same code, only one of\n * them should succeed and return the request data.\n *\n * @throws {InvalidGrantError} - When the request is not found or has expired\n * (allows to provide an error message instead of returning `null`).\n */\n consumeRequestCode(code: Code): Awaitable<FoundRequestResult | null>\n}\n\nexport const isRequestStore = buildInterfaceChecker<RequestStore>([\n 'createRequest',\n 'readRequest',\n 'updateRequest',\n 'deleteRequest',\n 'consumeRequestCode',\n])\n\nexport function asRequestStore<V extends Partial<RequestStore>>(\n implementation?: V,\n): V & RequestStore {\n if (!implementation || !isRequestStore(implementation)) {\n throw new Error('Invalid RequestStore implementation')\n }\n return implementation\n}\n"]}
|
|
@@ -1,34 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const zod_1 = require("zod");
|
|
8
|
-
const invalid_request_error_js_1 = require("../errors/invalid-request-error.js");
|
|
9
|
-
const error_js_1 = require("../lib/util/error.js");
|
|
10
|
-
const request_id_js_1 = require("./request-id.js");
|
|
11
|
-
exports.REQUEST_URI_PREFIX = 'urn:ietf:params:oauth:request_uri:';
|
|
12
|
-
exports.requestUriSchema = zod_1.z
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { InvalidRequestError } from '../errors/invalid-request-error.js';
|
|
3
|
+
import { formatError } from '../lib/util/error.js';
|
|
4
|
+
import { requestIdSchema } from './request-id.js';
|
|
5
|
+
export const REQUEST_URI_PREFIX = 'urn:ietf:params:oauth:request_uri:';
|
|
6
|
+
export const requestUriSchema = z
|
|
13
7
|
.string()
|
|
14
|
-
.refinement((data) => data.startsWith(
|
|
15
|
-
|
|
16
|
-
code:
|
|
8
|
+
.refinement((data) => data.startsWith(REQUEST_URI_PREFIX) &&
|
|
9
|
+
requestIdSchema.safeParse(decodeRequestUri(data)).success, {
|
|
10
|
+
code: z.ZodIssueCode.custom,
|
|
17
11
|
message: 'Invalid request_uri format',
|
|
18
12
|
});
|
|
19
|
-
function encodeRequestUri(requestId) {
|
|
20
|
-
return `${
|
|
13
|
+
export function encodeRequestUri(requestId) {
|
|
14
|
+
return `${REQUEST_URI_PREFIX}${encodeURIComponent(requestId)}`;
|
|
21
15
|
}
|
|
22
|
-
function decodeRequestUri(requestUri) {
|
|
23
|
-
const requestIdEnc = requestUri.slice(
|
|
16
|
+
export function decodeRequestUri(requestUri) {
|
|
17
|
+
const requestIdEnc = requestUri.slice(REQUEST_URI_PREFIX.length);
|
|
24
18
|
return decodeURIComponent(requestIdEnc);
|
|
25
19
|
}
|
|
26
|
-
function parseRequestUri(requestUri, parseParams) {
|
|
27
|
-
const parseResult =
|
|
20
|
+
export function parseRequestUri(requestUri, parseParams) {
|
|
21
|
+
const parseResult = requestUriSchema.safeParse(requestUri, parseParams);
|
|
28
22
|
if (!parseResult.success) {
|
|
29
23
|
const err = parseResult.error;
|
|
30
|
-
const msg =
|
|
31
|
-
throw new
|
|
24
|
+
const msg = formatError(err, 'Invalid "request_uri" query parameter');
|
|
25
|
+
throw new InvalidRequestError(msg, err);
|
|
32
26
|
}
|
|
33
27
|
return parseResult.data;
|
|
34
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-uri.js","sourceRoot":"","sources":["../../src/request/request-uri.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"request-uri.js","sourceRoot":"","sources":["../../src/request/request-uri.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAa,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE5D,MAAM,CAAC,MAAM,kBAAkB,GAAG,oCAAoC,CAAA;AAEtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC;KAC9B,MAAM,EAAE;KACR,UAAU,CACT,CAAC,IAAI,EAAsD,EAAE,CAC3D,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC;IACnC,eAAe,CAAC,SAAS,CAAC,gBAAgB,CAAC,IAAW,CAAC,CAAC,CAAC,OAAO,EAClE;IACE,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM;IAC3B,OAAO,EAAE,4BAA4B;CACtC,CACF,CAAA;AAIH,MAAM,UAAU,gBAAgB,CAAC,SAAoB;IACnD,OAAO,GAAG,kBAAkB,GAAG,kBAAkB,CAAC,SAAS,CAAc,EAAE,CAAA;AAC7E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAAsB;IACrD,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAChE,OAAO,kBAAkB,CAAC,YAAY,CAAc,CAAA;AACtD,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,UAAkB,EAClB,WAA4C;IAE5C,MAAM,WAAW,GAAG,gBAAgB,CAAC,SAAS,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;IACvE,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,CAAA;QAC7B,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,uCAAuC,CAAC,CAAA;QACrE,MAAM,IAAI,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACzC,CAAC;IACD,OAAO,WAAW,CAAC,IAAI,CAAA;AACzB,CAAC","sourcesContent":["import { z } from 'zod'\nimport { InvalidRequestError } from '../errors/invalid-request-error.js'\nimport { formatError } from '../lib/util/error.js'\nimport { RequestId, requestIdSchema } from './request-id.js'\n\nexport const REQUEST_URI_PREFIX = 'urn:ietf:params:oauth:request_uri:'\n\nexport const requestUriSchema = z\n .string()\n .refinement(\n (data): data is `${typeof REQUEST_URI_PREFIX}${RequestId}` =>\n data.startsWith(REQUEST_URI_PREFIX) &&\n requestIdSchema.safeParse(decodeRequestUri(data as any)).success,\n {\n code: z.ZodIssueCode.custom,\n message: 'Invalid request_uri format',\n },\n )\n\nexport type RequestUri = z.infer<typeof requestUriSchema>\n\nexport function encodeRequestUri(requestId: RequestId): RequestUri {\n return `${REQUEST_URI_PREFIX}${encodeURIComponent(requestId) as RequestId}`\n}\n\nexport function decodeRequestUri(requestUri: RequestUri): RequestId {\n const requestIdEnc = requestUri.slice(REQUEST_URI_PREFIX.length)\n return decodeURIComponent(requestIdEnc) as RequestId\n}\n\nexport function parseRequestUri(\n requestUri: string,\n parseParams?: { path?: (string | number)[] },\n): RequestUri {\n const parseResult = requestUriSchema.safeParse(requestUri, parseParams)\n if (!parseResult.success) {\n const err = parseResult.error\n const msg = formatError(err, 'Invalid \"request_uri\" query parameter')\n throw new InvalidRequestError(msg, err)\n }\n return parseResult.data\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets-manifest.d.ts","sourceRoot":"","sources":["../../../src/router/assets/assets-manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assets-manifest.d.ts","sourceRoot":"","sources":["../../../src/router/assets/assets-manifest.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAA;AAC3D,OAAO,EACL,UAAU,EAIX,MAAM,yBAAyB,CAAA;AAuBhC,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM;2BAqDxB,MAAM;;;;;EAqBrC"}
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const node_stream_1 = require("node:stream");
|
|
7
|
-
const index_js_1 = require("../../lib/http/index.js");
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { Readable } from 'node:stream';
|
|
5
|
+
import { validateFetchDest, validateFetchSite, writeStream, } from '../../lib/http/index.js';
|
|
8
6
|
const ASSETS_URL_PREFIX = '/@atproto/oauth-provider/~assets/';
|
|
9
|
-
function parseAssetsManifest(manifestPath) {
|
|
7
|
+
export function parseAssetsManifest(manifestPath) {
|
|
10
8
|
// Using `require` instead of `JSON.parse(readFileSync())` so that node's
|
|
11
9
|
// watch mode can pick up changes to the manifest file.
|
|
12
|
-
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
13
12
|
const manifest = require(manifestPath);
|
|
14
13
|
const assets = new Map(Object.entries(manifest).map(([filename, { data, ...item }]) => {
|
|
15
14
|
const buffer = data ? Buffer.from(data, 'base64') : null;
|
|
16
|
-
const filepath =
|
|
15
|
+
const filepath = join(manifestPath, '..', filename);
|
|
17
16
|
const stream = buffer
|
|
18
|
-
? () =>
|
|
19
|
-
: () =>
|
|
17
|
+
? () => Readable.from(buffer)
|
|
18
|
+
: () => createReadStream(filepath);
|
|
20
19
|
return [filename, { ...item, stream }];
|
|
21
20
|
}));
|
|
22
21
|
const assetsMiddleware = (req, res, next) => {
|
|
@@ -33,8 +32,8 @@ function parseAssetsManifest(manifestPath) {
|
|
|
33
32
|
try {
|
|
34
33
|
// Allow "null" (ie. no header) to allow loading assets outside of a
|
|
35
34
|
// fetch context (not from a web page).
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
validateFetchSite(req, [null, 'none', 'cross-site', 'same-origin']);
|
|
36
|
+
validateFetchDest(req, [null, 'document', 'style', 'script']);
|
|
38
37
|
}
|
|
39
38
|
catch (err) {
|
|
40
39
|
return next(err);
|
|
@@ -44,7 +43,7 @@ function parseAssetsManifest(manifestPath) {
|
|
|
44
43
|
}
|
|
45
44
|
res.setHeader('ETag', asset.sha256);
|
|
46
45
|
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
|
47
|
-
|
|
46
|
+
writeStream(res, asset.stream(), { contentType: asset.mime });
|
|
48
47
|
};
|
|
49
48
|
return {
|
|
50
49
|
getAssets,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets-manifest.js","sourceRoot":"","sources":["../../../src/router/assets/assets-manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assets-manifest.js","sourceRoot":"","sources":["../../../src/router/assets/assets-manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import { createReadStream } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { join } from 'node:path'\nimport { Readable } from 'node:stream'\nimport type { Manifest } from '@atproto-labs/rollup-plugin-bundle-manifest'\nimport { AssetRef } from '../../lib/html/build-document.js'\nimport {\n Middleware,\n validateFetchDest,\n validateFetchSite,\n writeStream,\n} from '../../lib/http/index.js'\n\ntype Asset =\n | {\n type: 'asset'\n mime?: string\n sha256: string\n stream: () => Readable\n }\n | {\n type: 'chunk'\n mime: string\n sha256: string\n dynamicImports: string[]\n isDynamicEntry: boolean\n isEntry: boolean\n isImplicitEntry: boolean\n name: string\n stream: () => Readable\n }\n\nconst ASSETS_URL_PREFIX = '/@atproto/oauth-provider/~assets/'\n\nexport function parseAssetsManifest(manifestPath: string) {\n // Using `require` instead of `JSON.parse(readFileSync())` so that node's\n // watch mode can pick up changes to the manifest file.\n const require = createRequire(import.meta.url)\n\n // eslint-disable-next-line import/no-dynamic-require\n const manifest = require(manifestPath) as Manifest\n\n const assets = new Map<string, Asset>(\n Object.entries(manifest).map(([filename, { data, ...item }]) => {\n const buffer = data ? Buffer.from(data, 'base64') : null\n const filepath = join(manifestPath, '..', filename)\n const stream = buffer\n ? () => Readable.from(buffer)\n : () => createReadStream(filepath)\n return [filename, { ...item, stream }]\n }),\n )\n\n const assetsMiddleware: Middleware = (req, res, next) => {\n if (req.method !== 'GET' && req.method !== 'HEAD') return next()\n if (!req.url?.startsWith(ASSETS_URL_PREFIX)) return next()\n\n const filename = decodeURIComponent(req.url.slice(ASSETS_URL_PREFIX.length))\n if (!filename) return next()\n\n const asset = assets.get(filename)\n if (!asset) return next()\n\n try {\n // Allow \"null\" (ie. no header) to allow loading assets outside of a\n // fetch context (not from a web page).\n validateFetchSite(req, [null, 'none', 'cross-site', 'same-origin'])\n validateFetchDest(req, [null, 'document', 'style', 'script'])\n } catch (err) {\n return next(err)\n }\n\n if (req.headers['if-none-match'] === asset.sha256) {\n return void res.writeHead(304).end()\n }\n\n res.setHeader('ETag', asset.sha256)\n res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')\n\n writeStream(res, asset.stream(), { contentType: asset.mime })\n }\n\n return {\n getAssets,\n assetsMiddleware,\n }\n\n function getAssets(entryName: string) {\n const scripts = getScripts(entryName)\n if (!scripts.length) return null\n const styles = getStyles(entryName)\n return { scripts, styles }\n }\n\n function getScripts(entryName: string) {\n return Array.from(assets)\n .filter(\n ([, asset]) =>\n asset.type === 'chunk' && asset.isEntry && asset.name === entryName,\n )\n .map(assetEntryUrl)\n }\n\n function getStyles(_entryName: string) {\n return Array.from(assets)\n .filter(([, asset]) => asset.mime === 'text/css')\n .map(assetEntryUrl)\n }\n}\n\nfunction assetEntryUrl([filename]: [string, Asset]): AssetRef {\n return { url: assetUrl(filename) }\n}\n\nfunction assetUrl(filename: string) {\n return `${ASSETS_URL_PREFIX}${encodeURIComponent(filename)}`\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../../src/router/assets/assets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../../src/router/assets/assets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAEhE,OAAO,KAAK,EAAE,aAAa,IAAI,eAAe,EAAE,MAAM,2CAA2C,CAAA;AAGjG,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAA;AAIpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EAEL,sBAAsB,EACvB,MAAM,oCAAoC,CAAA;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAiBjD,KAAK,aAAa,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAA;AAU9C,eAAO,MAAM,gBAAgB,8CAAsB,CAAA;AAqBnD,MAAM,MAAM,iBAAiB,GAAG,sBAAsB,GAAG,oBAAoB,CAAA;AAE7E,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,aAAa,EAC7D,IAAI,EAAE,CAAC,EACP,aAAa,EAAE,aAAa,EAC5B,QAAQ,GAAE,iBAAsB,IA6B9B,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,SAAS,iBAAiB,GAAG;IAC3B,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAA;CACpD,KACA,OAAO,CAAC,IAAI,CAAC,CAqBjB"}
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const write_html_js_1 = require("../../lib/write-html.js");
|
|
13
|
-
const assets_manifest_js_1 = require("./assets-manifest.js");
|
|
14
|
-
const csrf_js_1 = require("./csrf.js");
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { buildCustomizationCss } from '../../customization/build-customization-css.js';
|
|
3
|
+
import { buildCustomizationData } from '../../customization/build-customization-data.js';
|
|
4
|
+
import { mergeCsp } from '../../lib/csp/index.js';
|
|
5
|
+
import { declareHydrationData } from '../../lib/html/hydration-data.js';
|
|
6
|
+
import { cssCode, html } from '../../lib/html/index.js';
|
|
7
|
+
import { CrossOriginEmbedderPolicy, } from '../../lib/http/security-headers.js';
|
|
8
|
+
import { mergeDefaults } from '../../lib/util/object.js';
|
|
9
|
+
import { writeHtml } from '../../lib/write-html.js';
|
|
10
|
+
import { parseAssetsManifest } from './assets-manifest.js';
|
|
11
|
+
import { setupCsrfToken } from './csrf.js';
|
|
15
12
|
// If the "ui" and "frontend" packages are ever unified, this can be replaced
|
|
16
13
|
// with a single expression:
|
|
17
14
|
//
|
|
18
15
|
// const { getAssets, assetsMiddleware } = parseAssetsManifest(
|
|
19
16
|
// require.resolve('@atproto/oauth-provider-ui/bundle-manifest.json'),
|
|
20
17
|
// )
|
|
21
|
-
const
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
const ui = parseAssetsManifest(require.resolve('@atproto/oauth-provider-ui/bundle-manifest.json'));
|
|
22
20
|
function getAssets(entryName) {
|
|
23
21
|
const assetRef = ui.getAssets(entryName);
|
|
24
22
|
if (assetRef)
|
|
@@ -26,7 +24,7 @@ function getAssets(entryName) {
|
|
|
26
24
|
// Fool-proof. Should never happen.
|
|
27
25
|
throw new Error(`Entry "${entryName}" not found in assets`);
|
|
28
26
|
}
|
|
29
|
-
|
|
27
|
+
export const assetsMiddleware = ui.assetsMiddleware;
|
|
30
28
|
const SPA_CSP = {
|
|
31
29
|
// API calls are made to the same origin
|
|
32
30
|
'connect-src': ["'self'"],
|
|
@@ -44,19 +42,19 @@ const HCAPTCHA_CSP = {
|
|
|
44
42
|
'style-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
|
|
45
43
|
'connect-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
|
|
46
44
|
};
|
|
47
|
-
function sendWebAppFactory(page, customization, defaults = {}) {
|
|
45
|
+
export function sendWebAppFactory(page, customization, defaults = {}) {
|
|
48
46
|
// Pre-computed options:
|
|
49
|
-
const customizationData =
|
|
50
|
-
const customizationCss =
|
|
47
|
+
const customizationData = buildCustomizationData(customization);
|
|
48
|
+
const customizationCss = cssCode(buildCustomizationCss(customization));
|
|
51
49
|
const { scripts, styles } = getAssets(page);
|
|
52
|
-
const csp =
|
|
50
|
+
const csp = mergeCsp(SPA_CSP, customization.hcaptcha ? HCAPTCHA_CSP : undefined);
|
|
53
51
|
const coep = customization.hcaptcha
|
|
54
52
|
? // hCaptcha's implementation of COEP is currently broken. Let's disable it
|
|
55
53
|
// to avoid breaking the entire page.
|
|
56
54
|
//
|
|
57
55
|
// https://github.com/hCaptcha/react-hcaptcha/issues/259
|
|
58
56
|
// https://github.com/hCaptcha/react-hcaptcha/issues/380
|
|
59
|
-
|
|
57
|
+
CrossOriginEmbedderPolicy.unsafeNone
|
|
60
58
|
: // Since we are loading avatars form other origins, which might not have
|
|
61
59
|
// CORP headers, we need to use the "credentialless" value, which allows
|
|
62
60
|
// loading cross-origin resources without credentials (cookies, client
|
|
@@ -64,19 +62,19 @@ function sendWebAppFactory(page, customization, defaults = {}) {
|
|
|
64
62
|
// "unsafe-none". Ideally, we would want to set COEP to "require-corp" and
|
|
65
63
|
// ensure that all cross-origin resources have the appropriate CORP
|
|
66
64
|
// headers.
|
|
67
|
-
|
|
65
|
+
CrossOriginEmbedderPolicy.credentialless;
|
|
68
66
|
return async function sendWebApp(req, res, options) {
|
|
69
|
-
await
|
|
70
|
-
const script =
|
|
67
|
+
await setupCsrfToken(req, res);
|
|
68
|
+
const script = declareHydrationData({
|
|
71
69
|
...options.data,
|
|
72
70
|
__customizationData: customizationData,
|
|
73
71
|
});
|
|
74
|
-
return
|
|
72
|
+
return writeHtml(res, mergeDefaults(defaults, options, {
|
|
75
73
|
bodyAttrs: { class: 'text-text-default bg-contrast-0' },
|
|
76
|
-
csp: options?.csp ?
|
|
74
|
+
csp: options?.csp ? mergeCsp(csp, options.csp) : csp,
|
|
77
75
|
coep: options?.coep ?? coep,
|
|
78
76
|
meta: [{ name: 'robots', content: 'noindex' }],
|
|
79
|
-
body:
|
|
77
|
+
body: html `<div id="root"></div>`,
|
|
80
78
|
scripts: [script, ...scripts],
|
|
81
79
|
styles: [...styles, customizationCss],
|
|
82
80
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../src/router/assets/assets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../src/router/assets/assets.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { createRequire } from 'node:module'\nimport type { HydrationData as UiHydrationData } from '@atproto/oauth-provider-ui/hydration-data'\nimport { buildCustomizationCss } from '../../customization/build-customization-css.js'\nimport { buildCustomizationData } from '../../customization/build-customization-data.js'\nimport { Customization } from '../../customization/customization.js'\nimport { CspConfig, mergeCsp } from '../../lib/csp/index.js'\nimport { declareHydrationData } from '../../lib/html/hydration-data.js'\nimport { cssCode, html } from '../../lib/html/index.js'\nimport { WriteResponseOptions } from '../../lib/http/response.js'\nimport {\n CrossOriginEmbedderPolicy,\n SecurityHeadersOptions,\n} from '../../lib/http/security-headers.js'\nimport { mergeDefaults } from '../../lib/util/object.js'\nimport { Simplify } from '../../lib/util/type.js'\nimport { WriteHtmlOptions, writeHtml } from '../../lib/write-html.js'\nimport { parseAssetsManifest } from './assets-manifest.js'\nimport { setupCsrfToken } from './csrf.js'\n\n// If the \"ui\" and \"frontend\" packages are ever unified, this can be replaced\n// with a single expression:\n//\n// const { getAssets, assetsMiddleware } = parseAssetsManifest(\n// require.resolve('@atproto/oauth-provider-ui/bundle-manifest.json'),\n// )\n\nconst require = createRequire(import.meta.url)\nconst ui = parseAssetsManifest(\n require.resolve('@atproto/oauth-provider-ui/bundle-manifest.json'),\n)\n\ntype HydrationData = Simplify<UiHydrationData>\n\nfunction getAssets(entryName: keyof HydrationData) {\n const assetRef = ui.getAssets(entryName)\n if (assetRef) return assetRef\n\n // Fool-proof. Should never happen.\n throw new Error(`Entry \"${entryName}\" not found in assets`)\n}\n\nexport const assetsMiddleware = ui.assetsMiddleware\n\nconst SPA_CSP: CspConfig = {\n // API calls are made to the same origin\n 'connect-src': [\"'self'\"],\n // Allow loading of PDS logo & User avatars\n 'img-src': ['data:', 'https:'],\n // Prevent embedding in iframes\n 'frame-ancestors': [\"'none'\"],\n}\n\n/**\n * @see {@link https://docs.hcaptcha.com/#content-security-policy-settings}\n */\nconst HCAPTCHA_CSP: CspConfig = {\n 'script-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],\n 'frame-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],\n 'style-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],\n 'connect-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],\n}\n\nexport type SendWebAppOptions = SecurityHeadersOptions & WriteResponseOptions\n\nexport function sendWebAppFactory<P extends keyof HydrationData>(\n page: P,\n customization: Customization,\n defaults: SendWebAppOptions = {},\n) {\n // Pre-computed options:\n const customizationData = buildCustomizationData(customization)\n const customizationCss = cssCode(buildCustomizationCss(customization))\n const { scripts, styles } = getAssets(page)\n\n const csp = mergeCsp(\n SPA_CSP,\n customization.hcaptcha ? HCAPTCHA_CSP : undefined,\n )\n\n const coep = customization.hcaptcha\n ? // hCaptcha's implementation of COEP is currently broken. Let's disable it\n // to avoid breaking the entire page.\n //\n // https://github.com/hCaptcha/react-hcaptcha/issues/259\n // https://github.com/hCaptcha/react-hcaptcha/issues/380\n CrossOriginEmbedderPolicy.unsafeNone\n : // Since we are loading avatars form other origins, which might not have\n // CORP headers, we need to use the \"credentialless\" value, which allows\n // loading cross-origin resources without credentials (cookies, client\n // certificates, etc.). This is a more secure alternative to\n // \"unsafe-none\". Ideally, we would want to set COEP to \"require-corp\" and\n // ensure that all cross-origin resources have the appropriate CORP\n // headers.\n CrossOriginEmbedderPolicy.credentialless\n\n return async function sendWebApp(\n req: IncomingMessage,\n res: ServerResponse,\n options: SendWebAppOptions & {\n data: Omit<HydrationData[P], '__customizationData'>\n },\n ): Promise<void> {\n await setupCsrfToken(req, res)\n\n const script = declareHydrationData({\n ...options.data,\n __customizationData: customizationData,\n })\n\n return writeHtml(\n res,\n mergeDefaults<WriteHtmlOptions>(defaults, options, {\n bodyAttrs: { class: 'text-text-default bg-contrast-0' },\n csp: options?.csp ? mergeCsp(csp, options.csp) : csp,\n coep: options?.coep ?? coep,\n meta: [{ name: 'robots', content: 'noindex' }],\n body: html`<div id=\"root\"></div>`,\n scripts: [script, ...scripts],\n styles: [...styles, customizationCss],\n }),\n )\n }\n}\n"]}
|