@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":"function.js","sourceRoot":"","sources":["../../../src/lib/util/function.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"function.js","sourceRoot":"","sources":["../../../src/lib/util/function.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAM,EACN,GAAG,IAAmB;IAEtB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAuC,CAAA;AACpE,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,EAAK;IAEL,IAAI,UAAU,GAAa,EAAE,CAAA;IAC7B,OAAO,UAAU,GAAG,IAAI;QACtB,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,EAAE,GAAG,UAAU,CAAA;YACrB,UAAU,GAAG,IAAI,CAAA;YACjB,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAA;QAC/B,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACnD,CAAM,CAAA;AACR,CAAC;AAED,MAAM,UAAU,UAAU,CAAwB,KAAQ;IACxD,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAC7B,CAAC","sourcesContent":["/**\n * This function serves two purposes:\n * - It ensures that the return value is a Promise, even if the function returns\n * a \"thenable\" (i.e. a Promise-like object).\n * - It allows to avoid assigning a `this` context to the function, which is\n * particularly useful when the function is a member of a \"private\" object.\n */\nexport async function callAsync<F extends (...args: any[]) => unknown>(\n fn: F,\n ...args: Parameters<F>\n): Promise<Awaited<ReturnType<F>>>\nexport async function callAsync<F extends (...args: any[]) => unknown>(\n fn?: F,\n ...args: Parameters<F>\n): Promise<Awaited<ReturnType<F>> | undefined>\nexport async function callAsync<F extends (...args: any[]) => unknown>(\n fn?: F,\n ...args: Parameters<F>\n): Promise<Awaited<ReturnType<F>> | undefined> {\n return (await fn?.(...args)) as Awaited<ReturnType<F>> | undefined\n}\n\nexport function invokeOnce<T extends (this: any, ...a: any[]) => any>(\n fn: T,\n): T {\n let fnNullable: T | null = fn\n return function (...args) {\n if (fnNullable) {\n const fn = fnNullable\n fnNullable = null\n return fn.call(this, ...args)\n }\n throw new Error('Function called multiple times')\n } as T\n}\n\nexport function includedIn<T>(this: readonly T[], value: T): boolean {\n return this.includes(value)\n}\n"]}
|
package/dist/lib/util/locale.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.multiLangStringSchema = exports.localeSchema = void 0;
|
|
4
|
-
const zod_1 = require("zod");
|
|
5
|
-
exports.localeSchema = zod_1.z
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const localeSchema = z
|
|
6
3
|
.string()
|
|
7
4
|
.regex(/^[a-z]{2,3}(-[A-Z]{2})?$/, 'Invalid locale');
|
|
8
|
-
|
|
5
|
+
export const multiLangStringSchema = z.record(localeSchema, z.string().optional());
|
|
9
6
|
//# sourceMappingURL=locale.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale.js","sourceRoot":"","sources":["../../../src/lib/util/locale.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"locale.js","sourceRoot":"","sources":["../../../src/lib/util/locale.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC;KAC1B,MAAM,EAAE;KACR,KAAK,CAAC,0BAA0B,EAAE,gBAAgB,CAAC,CAAA;AAGtD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAC3C,YAAY,EACZ,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CACtB,CAAA","sourcesContent":["import { z } from 'zod'\n\nexport const localeSchema = z\n .string()\n .regex(/^[a-z]{2,3}(-[A-Z]{2})?$/, 'Invalid locale')\nexport type Locale = z.infer<typeof localeSchema>\n\nexport const multiLangStringSchema = z.record(\n localeSchema,\n z.string().optional(),\n)\nexport type MultiLangString = z.infer<typeof multiLangStringSchema>\n"]}
|
package/dist/lib/util/object.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.mergeDefaults = mergeDefaults;
|
|
4
|
-
function mergeDefaults(defaults, ...overrides) {
|
|
1
|
+
export function mergeDefaults(defaults, ...overrides) {
|
|
5
2
|
// @NOTE Not using the spread operator here because TS allows "undefined"
|
|
6
3
|
// values to be spread, which can lead to defaults being overwritten with
|
|
7
4
|
// "undefined". This function ensures that only defined values in "options"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object.js","sourceRoot":"","sources":["../../../src/lib/util/object.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"object.js","sourceRoot":"","sources":["../../../src/lib/util/object.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAC3B,QAAW,EACX,GAAG,SAA4B;IAE/B,yEAAyE;IACzE,yEAAyE;IACzE,2EAA2E;IAC3E,yDAAyD;IACzD,IAAI,CAAC,SAAS,CAAC,MAAM;QAAE,OAAO,QAAQ,CAAA;IACtC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,QAAQ,CAAA;IAC7C,MAAM,MAAM,GAAM,EAAE,GAAG,QAAQ,EAAO,CAAA;IACtC,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;QAChC,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;gBAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;gBAC1B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;gBACrB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC","sourcesContent":["export function mergeDefaults<T extends object>(\n defaults: T,\n ...overrides: (T | undefined)[]\n): T {\n // @NOTE Not using the spread operator here because TS allows \"undefined\"\n // values to be spread, which can lead to defaults being overwritten with\n // \"undefined\". This function ensures that only defined values in \"options\"\n // will overwrite the corresponding values in \"defaults\".\n if (!overrides.length) return defaults\n if (!overrides.some(Boolean)) return defaults\n const result: T = { ...defaults } as T\n for (const options of overrides) {\n if (options) {\n for (const key in options) {\n const value = options[key]\n if (value !== undefined) {\n result[key] = value\n }\n }\n }\n }\n return result\n}\n"]}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.compareRedirectUri = compareRedirectUri;
|
|
4
|
-
const oauth_types_1 = require("@atproto/oauth-types");
|
|
1
|
+
import { isLoopbackHost } from '@atproto/oauth-types';
|
|
5
2
|
/**
|
|
6
3
|
*
|
|
7
4
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc8252#section-8.4}
|
|
8
5
|
* @see {@link https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-8.4.2}
|
|
9
6
|
*/
|
|
10
|
-
function compareRedirectUri(allowed_uri, request_uri) {
|
|
7
|
+
export function compareRedirectUri(allowed_uri, request_uri) {
|
|
11
8
|
// https://datatracker.ietf.org/doc/html/rfc8252#section-8.4
|
|
12
9
|
//
|
|
13
10
|
// > Authorization servers MUST require clients to register their complete
|
|
@@ -19,7 +16,7 @@ function compareRedirectUri(allowed_uri, request_uri) {
|
|
|
19
16
|
return true;
|
|
20
17
|
// https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
|
|
21
18
|
const allowedUri = new URL(allowed_uri);
|
|
22
|
-
if (
|
|
19
|
+
if (isLoopbackHost(allowedUri.hostname)) {
|
|
23
20
|
const requestUri = new URL(request_uri);
|
|
24
21
|
return (
|
|
25
22
|
// > The authorization server MUST allow any port to be specified at the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redirect-uri.js","sourceRoot":"","sources":["../../../src/lib/util/redirect-uri.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"redirect-uri.js","sourceRoot":"","sources":["../../../src/lib/util/redirect-uri.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,WAAmB,EACnB,WAAmB;IAEnB,4DAA4D;IAC5D,EAAE;IACF,0EAA0E;IAC1E,yEAAyE;IACzE,wEAAwE;IACxE,wEAAwE;IACxE,kEAAkE;IAClE,IAAI,WAAW,KAAK,WAAW;QAAE,OAAO,IAAI,CAAA;IAE5C,4DAA4D;IAC5D,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAA;IACvC,IAAI,cAAc,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAA;QAEvC,OAAO;QACL,wEAAwE;QACxE,sEAAsE;QACtE,uEAAuE;QACvE,sCAAsC;QACtC,EAAE;QACF,wEAAwE;QACxE,aAAa;QACb,CAAC,CAAC,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI,CAAC;YACzD,UAAU,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ;YAC3C,UAAU,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ;YAC3C,UAAU,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ;YAC3C,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM;YACvC,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC,IAAI;YACnC,UAAU,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ;YAC3C,UAAU,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ,CAC5C,CAAA;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["import { isLoopbackHost } from '@atproto/oauth-types'\n\n/**\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc8252#section-8.4}\n * @see {@link https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-8.4.2}\n */\nexport function compareRedirectUri(\n allowed_uri: string,\n request_uri: string,\n): boolean {\n // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4\n //\n // > Authorization servers MUST require clients to register their complete\n // > redirect URI (including the path component) and reject authorization\n // > requests that specify a redirect URI that doesn't exactly match the\n // > one that was registered; the exception is loopback redirects, where\n // > an exact match is required except for the port URI component.\n if (allowed_uri === request_uri) return true\n\n // https://datatracker.ietf.org/doc/html/rfc8252#section-7.3\n const allowedUri = new URL(allowed_uri)\n if (isLoopbackHost(allowedUri.hostname)) {\n const requestUri = new URL(request_uri)\n\n return (\n // > The authorization server MUST allow any port to be specified at the\n // > time of the request for loopback IP redirect URIs, to accommodate\n // > clients that obtain an available ephemeral port from the operating\n // > system at the time of the request\n //\n // Note: We only apply this rule if the allowed URI does not have a port\n // specified.\n (!allowedUri.port || allowedUri.port === requestUri.port) &&\n allowedUri.hostname === requestUri.hostname &&\n allowedUri.pathname === requestUri.pathname &&\n allowedUri.protocol === requestUri.protocol &&\n allowedUri.search === requestUri.search &&\n allowedUri.hash === requestUri.hash &&\n allowedUri.username === requestUri.username &&\n allowedUri.password === requestUri.password\n )\n }\n\n return false\n}\n"]}
|
package/dist/lib/util/time.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.onOvertimeDefault = onOvertimeDefault;
|
|
4
|
-
exports.constantTime = constantTime;
|
|
5
|
-
const promises_1 = require("node:timers/promises");
|
|
6
|
-
function onOvertimeDefault(options) {
|
|
1
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
2
|
+
export function onOvertimeDefault(options) {
|
|
7
3
|
console.warn(`constantTime: execution time was ${options.elapsed}ms (which is greater than ${options.time}ms). You should increase the "time" to properly defend against timing attacks.`);
|
|
8
4
|
}
|
|
9
5
|
/**
|
|
10
6
|
* Utility function to protect against timing attacks.
|
|
11
7
|
*/
|
|
12
|
-
async function constantTime(time, fn, onOvertime = onOvertimeDefault) {
|
|
8
|
+
export async function constantTime(time, fn, onOvertime = onOvertimeDefault) {
|
|
13
9
|
if (!Number.isFinite(time) || time <= 0) {
|
|
14
10
|
throw new TypeError(`"time" must be a positive number`);
|
|
15
11
|
}
|
|
@@ -23,7 +19,7 @@ async function constantTime(time, fn, onOvertime = onOvertimeDefault) {
|
|
|
23
19
|
const remaining = time - elapsed;
|
|
24
20
|
if (remaining >= 0) {
|
|
25
21
|
// Happy path, execution time was smaller than "time"
|
|
26
|
-
await (
|
|
22
|
+
await sleep(remaining);
|
|
27
23
|
}
|
|
28
24
|
else {
|
|
29
25
|
// The function execution took longer than "time"
|
|
@@ -31,7 +27,7 @@ async function constantTime(time, fn, onOvertime = onOvertimeDefault) {
|
|
|
31
27
|
// Sleep until the next multiple of "time" to mitigate any attack
|
|
32
28
|
const multiplier = Math.ceil(elapsed / time);
|
|
33
29
|
const remaining = multiplier * time - elapsed;
|
|
34
|
-
await (
|
|
30
|
+
await sleep(remaining);
|
|
35
31
|
}
|
|
36
32
|
}
|
|
37
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.js","sourceRoot":"","sources":["../../../src/lib/util/time.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"time.js","sourceRoot":"","sources":["../../../src/lib/util/time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAG1D,MAAM,UAAU,iBAAiB,CAAC,OAKjC;IACC,OAAO,CAAC,IAAI,CACV,oCAAoC,OAAO,CAAC,OAAO,6BAA6B,OAAO,CAAC,IAAI,gFAAgF,CAC7K,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAY,EACZ,EAAsB,EACtB,UAAU,GAAG,iBAAiB;IAE9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAA;IACzD,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACxB,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAA;IACnB,CAAC;YAAS,CAAC;QACT,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,MAAM,OAAO,GAAG,GAAG,GAAG,KAAK,CAAA;QAE3B,MAAM,SAAS,GAAG,IAAI,GAAG,OAAO,CAAA;QAChC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,qDAAqD;YACrD,MAAM,KAAK,CAAC,SAAS,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,iDAAiD;YACjD,UAAU,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;YAEzC,iEAAiE;YACjE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;YAC5C,MAAM,SAAS,GAAG,UAAU,GAAG,IAAI,GAAG,OAAO,CAAA;YAE7C,MAAM,KAAK,CAAC,SAAS,CAAC,CAAA;QACxB,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["import { setTimeout as sleep } from 'node:timers/promises'\nimport { Awaitable } from './type.js'\n\nexport function onOvertimeDefault(options: {\n start: number\n end: number\n elapsed: number\n time: number\n}): void {\n console.warn(\n `constantTime: execution time was ${options.elapsed}ms (which is greater than ${options.time}ms). You should increase the \"time\" to properly defend against timing attacks.`,\n )\n}\n\n/**\n * Utility function to protect against timing attacks.\n */\nexport async function constantTime<R>(\n time: number,\n fn: () => Awaitable<R>,\n onOvertime = onOvertimeDefault,\n): Promise<R> {\n if (!Number.isFinite(time) || time <= 0) {\n throw new TypeError(`\"time\" must be a positive number`)\n }\n\n const start = Date.now()\n try {\n return await fn()\n } finally {\n const end = Date.now()\n const elapsed = end - start\n\n const remaining = time - elapsed\n if (remaining >= 0) {\n // Happy path, execution time was smaller than \"time\"\n await sleep(remaining)\n } else {\n // The function execution took longer than \"time\"\n onOvertime({ start, end, elapsed, time })\n\n // Sleep until the next multiple of \"time\" to mitigate any attack\n const multiplier = Math.ceil(elapsed / time)\n const remaining = multiplier * time - elapsed\n\n await sleep(remaining)\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../src/lib/util/type.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../../src/lib/util/type.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAA;AACvD,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC;KACnC,CAAC,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GACnC,CAAC,CAAC,CAAC,CAAC,GACJ,CAAC,SAAS,MAAM,CAAC,GACf,CAAC,CAAC,CAAC,CAAC,GACJ,KAAK;CACZ,CAAC,CAAA;AACF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AACzC,MAAM,MAAM,eAAe,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,QAAQ,CAC1D,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;KACb,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC9B,CACF,CAAA;AACD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI;KACzC,EAAE,IAAI,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,KAAK,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;CACpD,CAAA;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,GAAG,KAAK,IAAI,QAAQ,CAC9D,CAAC,GAAG;KACD,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,GAC5B,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,GAC3B,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;CAC7B,CACF,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,SAAS,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,GAClE,SAAS,GACT,OAAO,CACL,CAAC,CAAC,MAAM,CAAC,EAGT;KACG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GACX,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,GAClC,CAAC,SAAS,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,SAAS,CAAC;CACjD,CAAC,MAAM,CAAC,CAAC,CACX,CAAA;AAEL;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;CAAE,CAAA;AAI/E;;;;;GAKG;AACH,KAAK,cAAc,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG,MAAM,CAAC,GAAG,KAAK,CAAA;AAExD;;;;;;;GAOG;AACH,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CAC7E,CAAC,EAAE,MAAM,CAAC,KACP,IAAI,GACL,CAAC,GACD,KAAK,CAAA;AAET;;;;;GAKG;AACH,KAAK,gBAAgB,CAAC,CAAC,IAYrB,mBAAmB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,MAAM,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAE1E;;;;;;;;;;;;GAYG;AACH,KAAK,YAAY,CAAC,CAAC,IAAI,oBAAoB,CAAC,CAAC,CAAC,CAAA;AAE9C,KAAK,oBAAoB,CACvB,CAAC,EAED,GAAG,SAAS,SAAS,GAAG,EAAE,GAAG,EAAE,EAE/B,IAAI,GAAG,gBAAgB,CAAC,CAAC,CAAC,IAG1B;IAAC,IAAI;CAAC,SAAS,CAAC,KAAK,CAAC,GAElB,GAAG,GAGH,oBAAoB,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAA;AAErE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,qBAAqB,GAC/B,CAAC,SAAS,MAAM,EAAE,MAAM,SAAS,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,MACjE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,KAAG,KAAK,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC,CACf,CAAA"}
|
package/dist/lib/util/type.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildInterfaceChecker = void 0;
|
|
4
1
|
/**
|
|
5
2
|
* This utility allows to create an assertion function that checks if a
|
|
6
3
|
* particular interface is fully implemented by some value.
|
|
@@ -38,7 +35,6 @@ exports.buildInterfaceChecker = void 0;
|
|
|
38
35
|
* buildInterfaceChecker<{ foo: string; bar: string }>(['foo', 'baz'])
|
|
39
36
|
* ```
|
|
40
37
|
*/
|
|
41
|
-
const buildInterfaceChecker = (keys) => (value) => keys.every((name) => value[name] !== undefined);
|
|
42
|
-
exports.buildInterfaceChecker = buildInterfaceChecker;
|
|
38
|
+
export const buildInterfaceChecker = (keys) => (value) => keys.every((name) => value[name] !== undefined);
|
|
43
39
|
// </hardcore-mode>
|
|
44
40
|
//# sourceMappingURL=type.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type.js","sourceRoot":"","sources":["../../../src/lib/util/type.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"type.js","sourceRoot":"","sources":["../../../src/lib/util/type.ts"],"names":[],"mappings":"AA2IA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAChC,CAAmB,IAA+C,EAAE,EAAE,CACtE,CAAuB,KAAQ,EAAmC,EAAE,CAClE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAA;AAEnD,mBAAmB","sourcesContent":["export type Simplify<T> = { [K in keyof T]: T[K] } & {}\nexport type Override<T, V> = Simplify<{\n [K in keyof (V & T)]: K extends keyof V\n ? V[K]\n : K extends keyof T\n ? T[K]\n : never\n}>\nexport type Awaitable<T> = T | Promise<T>\nexport type NonNullableKeys<T, K extends keyof T> = Simplify<\n OmitKey<T, K> & {\n [P in K]-?: NonNullable<T[P]>\n }\n>\n/**\n * When a type has an `[x: string]: unknown` index signature, in addition to\n * some known properties, using {@link Omit} will result in a type that only has\n * the index signature, and no known properties.\n *\n * ```ts\n * Omit<{ a: 3; b: 4; [x: string]: unknown }, 'a'> // { [x: string]: unknown }\n * ```\n *\n * In order to properly omit specific known properties from a type with an index\n * signature, we need to use another utility type that will behave correctly.\n *\n * ```ts\n * OmitKey<{ a: 3; b: 4; [x: string]: unknown }, 'a'> // { b: 4; [x: string]: unknown }\n * ```\n */\nexport type OmitKey<T, K extends keyof T> = {\n [K2 in keyof T as K2 extends K ? never : K2]: T[K2]\n}\n\nexport type RequiredKey<T, K extends keyof T = never> = Simplify<\n T & {\n [L in K]-?: unknown extends T[L]\n ? NonNullable<unknown> | null\n : Exclude<T[L], undefined>\n }\n>\n\n/**\n * Converts a tuple to the equivalent type of combining every item into a single\n * one. If any of the item in the tuple is non nullish, the result will be non\n * nullish.\n */\nexport type CombinedTuple<T extends readonly unknown[]> = T extends []\n ? undefined\n : Exclude<\n T[number],\n // If any item in the tuple is never `null` (resp. `undefined`), exclude\n // `null` (resp. `undefined`) from `T[number]`\n {\n [K in keyof T]-?:\n | (null extends T[K] ? never : null)\n | (undefined extends T[K] ? never : undefined)\n }[keyof T]\n >\n\n/**\n * Similar to {@link Required} but also ensures that all values are defined.\n */\nexport type RequiredDefined<T> = { [K in keyof T]-?: Exclude<T[K], undefined> }\n\n// <hardcore-mode> (don't touch this)\n\n/**\n * @example\n * ```ts\n * type F = UnionToFnUnion<'a' | 'b'> // (() => 'a') | (() => 'b')\n * ```\n */\ntype UnionToFnUnion<T> = T extends any ? () => T : never\n\n/**\n * @example\n * ```ts\n * type A = UnionToIntersection<(() => 'a') | (() => 'b')> // (() => 'a') & (() => 'b')\n *\n * UnionToIntersection<{ foo: string | number } | { foo: number; bar: 4 }> // { foo: number; bar: 4 }\n * ```\n */\ntype UnionToIntersection<T> = (T extends any ? (x: T) => void : never) extends (\n x: infer U,\n) => void\n ? U\n : never\n\n/**\n * @example\n * ```ts\n * type B = ExtractUnionItem<'a' | 'b'> // 'b'\n * ```\n */\ntype ExtractUnionItem<T> =\n // There exists a quirk in the way TypeScript works when inferring return\n // types of an (disjoined) intersection of functions:\n //\n // type AnB = (() => 'a') & (() => 'b')\n // type B = AnB extends () => infer R ? R : never // 'b'\n //\n // By turning the input union T (e.g. 'a' | 'b') into a union of function\n // (() => 'a') | (() => 'b') and then into an intersection of those functions\n // (() => 'a') & (() => 'b'), we can exploit the special TypeScript behavior\n // to infer only the last return type from the functions, which is effectively\n // equal to the last item of the input union T.\n UnionToIntersection<UnionToFnUnion<T>> extends () => infer R ? R : never\n\n/**\n * Utility that turn a union of types (`'a' | 'b'`) into a tuple with matching\n * types (`['a', 'b']`).\n *\n * @note this only work with unions of \"const\" types. Using this with globals\n * types (`string`, etc.) will yield unexpected results.\n *\n * @example\n * ```ts\n * type T = UnionToTuple<'a' | 'b'> // ['a', 'b']\n * type T = UnionToTuple<'a' | 'b' | 'c'> // ['a', 'b', 'c']\n * ```\n */\ntype UnionToTuple<T> = UnionToTupleInternal<T>\n\ntype UnionToTupleInternal<\n T,\n // Accumulator for terminal recursivity (initialized to empty tuple)\n Acc extends readonly any[] = [],\n // Get the next item from the union (if any)\n Next = ExtractUnionItem<T>,\n> =\n // If there were no more items to extract from the union T, then we are done\n [Next] extends [never]\n ? // Return result of previous recursive calls\n Acc\n : // Recursively call UnionToTupleInternal by Exclude'ing the Next item from\n // the union (T) and adding it to the accumulator.\n UnionToTupleInternal<Exclude<T, Next>, readonly [Next, ...Acc]>\n\n/**\n * This utility allows to create an assertion function that checks if a\n * particular interface is fully implemented by some value.\n *\n * The use of the (rather complex) {@link UnionToTuple} allows to ensure that,\n * at runtime, all the required interface keys are indeed checked, and that\n * future additions to the interface do not result in a false sense of type\n * safety.\n *\n * @note This function should not be made public, as it relies on a quirk of\n * TypeScript to work properly.\n *\n * @example Valid use\n *\n * ```ts\n * const isFoo = buildInterfaceChecker<{ foo: string }>(['foo'])\n * const isFooBar = buildInterfaceChecker<{ foo: string; bar: boolean }>([\n * 'foo',\n * 'bar',\n * ])\n *\n * declare const val: { foo?: string }\n *\n * if (isFoo(val)) {\n * val // { foo: string }\n * }\n * ```\n *\n * @example Use cases where the runtime keys do not match the interface keys\n *\n * ```ts\n * buildInterfaceChecker<{ foo: string }>([])\n * buildInterfaceChecker<{ foo: string }>(['fee'])\n * buildInterfaceChecker<{ foo: string; bar: string }>(['foo'])\n * buildInterfaceChecker<{ foo: string; bar: string }>(['foo', 'baz'])\n * ```\n */\nexport const buildInterfaceChecker =\n <I extends object>(keys: readonly string[] & UnionToTuple<keyof I>) =>\n <V extends Partial<I>>(value: V): value is V & RequiredDefined<I> =>\n keys.every((name) => value[name] !== undefined)\n\n// </hardcore-mode>\n"]}
|
package/dist/lib/util/ui8.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseUi8Hex = parseUi8Hex;
|
|
4
|
-
exports.parseUi8Dec = parseUi8Dec;
|
|
5
|
-
exports.asUi8 = asUi8;
|
|
6
|
-
function parseUi8Hex(v) {
|
|
1
|
+
export function parseUi8Hex(v) {
|
|
7
2
|
return asUi8(parseInt(v, 16));
|
|
8
3
|
}
|
|
9
|
-
function parseUi8Dec(v) {
|
|
4
|
+
export function parseUi8Dec(v) {
|
|
10
5
|
return asUi8(parseInt(v, 10));
|
|
11
6
|
}
|
|
12
|
-
function asUi8(v) {
|
|
7
|
+
export function asUi8(v) {
|
|
13
8
|
if (v >= 0 && v <= 255 && Number.isInteger(v))
|
|
14
9
|
return v;
|
|
15
10
|
throw new TypeError(`Invalid value "${v}" (expected an integer between 0 and 255)`);
|
package/dist/lib/util/ui8.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui8.js","sourceRoot":"","sources":["../../../src/lib/util/ui8.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ui8.js","sourceRoot":"","sources":["../../../src/lib/util/ui8.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAC/B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAC/B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,CAAS;IAC7B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAA;IACvD,MAAM,IAAI,SAAS,CACjB,kBAAkB,CAAC,2CAA2C,CAC/D,CAAA;AACH,CAAC","sourcesContent":["export function parseUi8Hex(v: string) {\n return asUi8(parseInt(v, 16))\n}\n\nexport function parseUi8Dec(v: string) {\n return asUi8(parseInt(v, 10))\n}\n\nexport function asUi8(v: number) {\n if (v >= 0 && v <= 255 && Number.isInteger(v)) return v\n throw new TypeError(\n `Invalid value \"${v}\" (expected an integer between 0 and 255)`,\n )\n}\n"]}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildWellknownUrl = buildWellknownUrl;
|
|
4
|
-
function buildWellknownUrl(url, name) {
|
|
1
|
+
export function buildWellknownUrl(url, name) {
|
|
5
2
|
const path = url.pathname === '/'
|
|
6
3
|
? `/.well-known/${name}`
|
|
7
4
|
: `${url.pathname.replace(/\/+$/, '')}/${name}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"well-known.js","sourceRoot":"","sources":["../../../src/lib/util/well-known.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"well-known.js","sourceRoot":"","sources":["../../../src/lib/util/well-known.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,GAAQ,EAAE,IAAY;IACtD,MAAM,IAAI,GACR,GAAG,CAAC,QAAQ,KAAK,GAAG;QAClB,CAAC,CAAC,gBAAgB,IAAI,EAAE;QACxB,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAA;IAEnD,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;AAC3B,CAAC","sourcesContent":["export function buildWellknownUrl(url: URL, name: string): URL {\n const path =\n url.pathname === '/'\n ? `/.well-known/${name}`\n : `${url.pathname.replace(/\\/+$/, '')}/${name}`\n\n return new URL(path, url)\n}\n"]}
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.formatZodError = formatZodError;
|
|
4
|
-
exports.formatZodIssue = formatZodIssue;
|
|
5
|
-
const zod_1 = require("zod");
|
|
6
|
-
function formatZodError(err, prefix) {
|
|
1
|
+
import { ZodIssueCode } from 'zod';
|
|
2
|
+
export function formatZodError(err, prefix) {
|
|
7
3
|
const message = err.issues.length
|
|
8
4
|
? err.issues.map(formatZodIssue).join('; ')
|
|
9
5
|
: err.message; // Should never happen (issues should never be empty)
|
|
10
6
|
return prefix ? `${prefix}: ${message}` : message;
|
|
11
7
|
}
|
|
12
|
-
function formatZodIssue(issue) {
|
|
13
|
-
if (issue.code ===
|
|
8
|
+
export function formatZodIssue(issue) {
|
|
9
|
+
if (issue.code === ZodIssueCode.invalid_union) {
|
|
14
10
|
return issue.unionErrors
|
|
15
11
|
.map((err) => err.issues.map(formatZodIssue).join('; '))
|
|
16
12
|
.join(', or ');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zod-error.js","sourceRoot":"","sources":["../../../src/lib/util/zod-error.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"zod-error.js","sourceRoot":"","sources":["../../../src/lib/util/zod-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAE,MAAM,KAAK,CAAA;AAEtD,MAAM,UAAU,cAAc,CAAC,GAAa,EAAE,MAAe;IAC3D,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM;QAC/B,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC3C,CAAC,CAAC,GAAG,CAAC,OAAO,CAAA,CAAC,qDAAqD;IACrE,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,aAAa,EAAE,CAAC;QAC9C,OAAO,KAAK,CAAC,WAAW;aACrB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aACvD,IAAI,CAAC,OAAO,CAAC,CAAA;IAClB,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QACjE,OAAO,GAAG,KAAK,CAAC,OAAO,aAAa,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;IACrD,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACtB,OAAO,GAAG,KAAK,CAAC,OAAO,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;IACtD,CAAC;IAED,OAAO,KAAK,CAAC,OAAO,CAAA;AACtB,CAAC","sourcesContent":["import { ZodError, ZodIssue, ZodIssueCode } from 'zod'\n\nexport function formatZodError(err: ZodError, prefix?: string): string {\n const message = err.issues.length\n ? err.issues.map(formatZodIssue).join('; ')\n : err.message // Should never happen (issues should never be empty)\n return prefix ? `${prefix}: ${message}` : message\n}\n\nexport function formatZodIssue(issue: ZodIssue): string {\n if (issue.code === ZodIssueCode.invalid_union) {\n return issue.unionErrors\n .map((err) => err.issues.map(formatZodIssue).join('; '))\n .join(', or ')\n }\n\n if (issue.path.length === 1 && typeof issue.path[0] === 'number') {\n return `${issue.message} at index ${issue.path[0]}`\n }\n\n if (issue.path.length) {\n return `${issue.message} at ${issue.path.join('.')}`\n }\n\n return issue.message\n}\n"]}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const index_js_1 = require("./html/index.js");
|
|
5
|
-
const request_js_1 = require("./http/request.js");
|
|
6
|
-
const write_html_js_1 = require("./write-html.js");
|
|
1
|
+
import { html, js } from './html/index.js';
|
|
2
|
+
import { setCookie } from './http/request.js';
|
|
3
|
+
import { writeHtml } from './write-html.js';
|
|
7
4
|
// We prevent the user from coming "back" to this page and resubmitting the form
|
|
8
5
|
// repeatedly by disabling the submit button after the first submission.
|
|
9
|
-
const SCRIPT =
|
|
6
|
+
const SCRIPT = js `
|
|
10
7
|
const form = document.forms[0];
|
|
11
8
|
|
|
12
9
|
let canSubmit = true;
|
|
@@ -25,19 +22,19 @@ setTimeout(() => {
|
|
|
25
22
|
`;
|
|
26
23
|
// @NOTE If translations and design are needed, consider replacing this with a
|
|
27
24
|
// web app page.
|
|
28
|
-
function writeFormRedirect(res, method, uri, params, options) {
|
|
25
|
+
export function writeFormRedirect(res, method, uri, params, options) {
|
|
29
26
|
res.setHeader('Cache-Control', 'no-store');
|
|
30
27
|
// Prevent the Chrome from caching this page
|
|
31
28
|
// see: https://latesthackingnews.com/2023/12/12/google-updates-chrome-bfcache-for-faster-page-viewing/
|
|
32
|
-
|
|
33
|
-
return
|
|
29
|
+
setCookie(res, 'bfCacheBypass', 'foo', { maxAge: 1, sameSite: 'lax' });
|
|
30
|
+
return writeHtml(res, {
|
|
34
31
|
...options,
|
|
35
32
|
htmlAttrs: { lang: 'en' },
|
|
36
33
|
scripts: [SCRIPT],
|
|
37
|
-
body:
|
|
34
|
+
body: html `
|
|
38
35
|
<form method="${method}" action="${uri}">
|
|
39
36
|
${Array.from(params, ([key, value]) => [
|
|
40
|
-
|
|
37
|
+
html `<input type="hidden" name="${key}" value="${value}" />`,
|
|
41
38
|
])}
|
|
42
39
|
<input type="submit" value="Continue" />
|
|
43
40
|
</form>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-form-redirect.js","sourceRoot":"","sources":["../../src/lib/write-form-redirect.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"write-form-redirect.js","sourceRoot":"","sources":["../../src/lib/write-form-redirect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAI3C,gFAAgF;AAChF,wEAAwE;AACxE,MAAM,MAAM,GAAG,EAAE,CAAA;;;;;;;;;;;;;;;;CAgBhB,CAAA;AAED,8EAA8E;AAC9E,gBAAgB;AAEhB,MAAM,UAAU,iBAAiB,CAC/B,GAAmB,EACnB,MAAsB,EACtB,GAAW,EACX,MAAkC,EAClC,OAAkC;IAElC,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAA;IAE1C,4CAA4C;IAC5C,uGAAuG;IACvG,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAEtE,OAAO,SAAS,CAAC,GAAG,EAAE;QACpB,GAAG,OAAO;QACV,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;QACzB,OAAO,EAAE,CAAC,MAAM,CAAC;QACjB,IAAI,EAAE,IAAI,CAAA;sBACQ,MAAM,aAAa,GAAG;UAClC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;YACrC,IAAI,CAAA,8BAA8B,GAAG,YAAY,KAAK,MAAM;SAC7D,CAAC;;;KAGL;KACF,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import type { ServerResponse } from 'node:http'\nimport { html, js } from './html/index.js'\nimport { setCookie } from './http/request.js'\nimport { SecurityHeadersOptions } from './http/security-headers.js'\nimport { writeHtml } from './write-html.js'\n\nexport type WriteFormRedirectOptions = SecurityHeadersOptions\n\n// We prevent the user from coming \"back\" to this page and resubmitting the form\n// repeatedly by disabling the submit button after the first submission.\nconst SCRIPT = js`\nconst form = document.forms[0];\n\nlet canSubmit = true;\n\nform.addEventListener('submit', (event) => {\n if (!canSubmit) {\n event.preventDefault();\n } else {\n canSubmit = false;\n }\n});\n\nsetTimeout(() => {\n form.submit();\n}, 1);\n`\n\n// @NOTE If translations and design are needed, consider replacing this with a\n// web app page.\n\nexport function writeFormRedirect(\n res: ServerResponse,\n method: 'post' | 'get',\n uri: string,\n params: Iterable<[string, string]>,\n options?: WriteFormRedirectOptions,\n): void {\n res.setHeader('Cache-Control', 'no-store')\n\n // Prevent the Chrome from caching this page\n // see: https://latesthackingnews.com/2023/12/12/google-updates-chrome-bfcache-for-faster-page-viewing/\n setCookie(res, 'bfCacheBypass', 'foo', { maxAge: 1, sameSite: 'lax' })\n\n return writeHtml(res, {\n ...options,\n htmlAttrs: { lang: 'en' },\n scripts: [SCRIPT],\n body: html`\n <form method=\"${method}\" action=\"${uri}\">\n ${Array.from(params, ([key, value]) => [\n html`<input type=\"hidden\" name=\"${key}\" value=\"${value}\" />`,\n ])}\n <input type=\"submit\" value=\"Continue\" />\n </form>\n `,\n })\n}\n"]}
|
package/dist/lib/write-html.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const response_js_1 = require("./http/response.js");
|
|
8
|
-
const security_headers_js_1 = require("./http/security-headers.js");
|
|
9
|
-
function writeHtml(res, options) {
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mergeCsp } from './csp/index.js';
|
|
3
|
+
import { Html, buildDocument, } from './html/index.js';
|
|
4
|
+
import { writeBuffer } from './http/response.js';
|
|
5
|
+
import { setSecurityHeaders, } from './http/security-headers.js';
|
|
6
|
+
export function writeHtml(res, options) {
|
|
10
7
|
// @NOTE the csp string might be quite long. In that case it might be tempting
|
|
11
8
|
// to set it through the http-equiv <meta> in the HTML. However, some
|
|
12
9
|
// directives cannot be enforced by browsers when set through the meta tag
|
|
13
10
|
// (e.g. 'frame-ancestors'). Therefore, it's better to set the CSP through the
|
|
14
11
|
// HTTP header.
|
|
15
|
-
const csp =
|
|
12
|
+
const csp = mergeCsp({
|
|
16
13
|
// Keep "upgrade-insecure-requests" in sync with HSTS setting. HSTS is
|
|
17
14
|
// typically set to false for localhost endpoints. Chrome and FF will
|
|
18
15
|
// ignore "upgrade-insecure-requests" from localhost, but Safari will
|
|
@@ -23,10 +20,10 @@ function writeHtml(res, options) {
|
|
|
23
20
|
'script-src': options.scripts?.map(assetToCsp).filter((v) => v != null),
|
|
24
21
|
'style-src': options.styles?.map(assetToCsp).filter((v) => v != null),
|
|
25
22
|
}, options.csp);
|
|
26
|
-
const html =
|
|
23
|
+
const html = buildDocument(options).toString();
|
|
27
24
|
// HTML pages should always be served with safety protection headers
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
setSecurityHeaders(res, { ...options, csp });
|
|
26
|
+
writeBuffer(res, html, {
|
|
30
27
|
...options,
|
|
31
28
|
contentType: options?.contentType ?? 'text/html; charset=utf-8',
|
|
32
29
|
});
|
|
@@ -34,9 +31,9 @@ function writeHtml(res, options) {
|
|
|
34
31
|
function assetToCsp(asset) {
|
|
35
32
|
if (asset == null)
|
|
36
33
|
return undefined;
|
|
37
|
-
if (asset instanceof
|
|
34
|
+
if (asset instanceof Html) {
|
|
38
35
|
// Inline assets are "allowed" by their hash
|
|
39
|
-
const hash =
|
|
36
|
+
const hash = createHash('sha256');
|
|
40
37
|
for (const fragment of asset)
|
|
41
38
|
hash.update(fragment);
|
|
42
39
|
return `'sha256-${hash.digest('base64')}'`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write-html.js","sourceRoot":"","sources":["../../src/lib/write-html.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"write-html.js","sourceRoot":"","sources":["../../src/lib/write-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAY,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAGL,IAAI,EACJ,aAAa,GACd,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAwB,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACtE,OAAO,EAEL,kBAAkB,GACnB,MAAM,4BAA4B,CAAA;AAMnC,MAAM,UAAU,SAAS,CACvB,GAAmB,EACnB,OAAyB;IAEzB,8EAA8E;IAC9E,qEAAqE;IACrE,0EAA0E;IAC1E,8EAA8E;IAC9E,eAAe;IACf,MAAM,GAAG,GAAG,QAAQ,CAClB;QACE,sEAAsE;QACtE,qEAAqE;QACrE,qEAAqE;QACrE,mEAAmE;QACnE,2BAA2B,EAAE,OAAO,CAAC,IAAI,KAAK,KAAK;QACnD,aAAa,EAAE,CAAC,QAAQ,CAAC;QACzB,UAAU,EAAE,OAAO,CAAC,IAAI,EAAE,MAAyC;QACnE,YAAY,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC;QACvE,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC;KACtE,EACD,OAAO,CAAC,GAAG,CACZ,CAAA;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAA;IAE9C,oEAAoE;IACpE,kBAAkB,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,CAAC,CAAA;IAC5C,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE;QACrB,GAAG,OAAO;QACV,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,0BAA0B;KAChE,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAuB;IACzC,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,SAAS,CAAA;IACnC,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;QAC1B,4CAA4C;QAC5C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;QACjC,KAAK,MAAM,QAAQ,IAAI,KAAK;YAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACnD,OAAO,WAAW,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAA;IAC5C,CAAC;SAAM,CAAC;QACN,iDAAiD;QACjD,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACpE,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAA8C,CAAA;QAC1E,CAAC;QAED,kDAAkD;QAClD,OAAO,QAAQ,CAAA;IACjB,CAAC;AACH,CAAC","sourcesContent":["import { createHash } from 'node:crypto'\nimport type { ServerResponse } from 'node:http'\nimport { CspValue, mergeCsp } from './csp/index.js'\nimport {\n AssetRef,\n BuildDocumentOptions,\n Html,\n buildDocument,\n} from './html/index.js'\nimport { WriteResponseOptions, writeBuffer } from './http/response.js'\nimport {\n SecurityHeadersOptions,\n setSecurityHeaders,\n} from './http/security-headers.js'\n\nexport type WriteHtmlOptions = BuildDocumentOptions &\n WriteResponseOptions &\n SecurityHeadersOptions\n\nexport function writeHtml(\n res: ServerResponse,\n options: WriteHtmlOptions,\n): void {\n // @NOTE the csp string might be quite long. In that case it might be tempting\n // to set it through the http-equiv <meta> in the HTML. However, some\n // directives cannot be enforced by browsers when set through the meta tag\n // (e.g. 'frame-ancestors'). Therefore, it's better to set the CSP through the\n // HTTP header.\n const csp = mergeCsp(\n {\n // Keep \"upgrade-insecure-requests\" in sync with HSTS setting. HSTS is\n // typically set to false for localhost endpoints. Chrome and FF will\n // ignore \"upgrade-insecure-requests\" from localhost, but Safari will\n // enforce it, requiring to be explicitly disable it for localhost.\n 'upgrade-insecure-requests': options.hsts !== false,\n 'default-src': [\"'none'\"],\n 'base-uri': options.base?.origin as undefined | `https://${string}`,\n 'script-src': options.scripts?.map(assetToCsp).filter((v) => v != null),\n 'style-src': options.styles?.map(assetToCsp).filter((v) => v != null),\n },\n options.csp,\n )\n\n const html = buildDocument(options).toString()\n\n // HTML pages should always be served with safety protection headers\n setSecurityHeaders(res, { ...options, csp })\n writeBuffer(res, html, {\n ...options,\n contentType: options?.contentType ?? 'text/html; charset=utf-8',\n })\n}\n\nfunction assetToCsp(asset?: Html | AssetRef): undefined | CspValue {\n if (asset == null) return undefined\n if (asset instanceof Html) {\n // Inline assets are \"allowed\" by their hash\n const hash = createHash('sha256')\n for (const fragment of asset) hash.update(fragment)\n return `'sha256-${hash.digest('base64')}'`\n } else {\n // External assets are referenced by their origin\n if (asset.url.startsWith('https:') || asset.url.startsWith('http:')) {\n return new URL(asset.url).origin as `https:${string}` | `http:${string}`\n }\n\n // Internal assets are served from the same origin\n return `'self'`\n }\n}\n"]}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const oauth_types_1 = require("@atproto/oauth-types");
|
|
5
|
-
const client_js_1 = require("../client/client.js");
|
|
6
|
-
const crypto_js_1 = require("../lib/util/crypto.js");
|
|
1
|
+
import { oauthAuthorizationServerMetadataValidator, } from '@atproto/oauth-types';
|
|
2
|
+
import { Client } from '../client/client.js';
|
|
3
|
+
import { VERIFY_ALGOS } from '../lib/util/crypto.js';
|
|
7
4
|
/**
|
|
8
5
|
* @see {@link https://datatracker.ietf.org/doc/html/rfc8414#section-2}
|
|
9
6
|
* @see {@link https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata}
|
|
10
7
|
* @see {@link https://openid.net/specs/openid-connect-prompt-create-1_0.html}
|
|
11
8
|
*/
|
|
12
|
-
function buildMetadata(issuer, keyset, customMetadata) {
|
|
13
|
-
return
|
|
9
|
+
export function buildMetadata(issuer, keyset, customMetadata) {
|
|
10
|
+
return oauthAuthorizationServerMetadataValidator.parse({
|
|
14
11
|
issuer,
|
|
15
12
|
scopes_supported: [
|
|
16
13
|
'atproto',
|
|
@@ -78,7 +75,7 @@ function buildMetadata(issuer, keyset, customMetadata) {
|
|
|
78
75
|
// https://datatracker.ietf.org/doc/html/rfc9207
|
|
79
76
|
authorization_response_iss_parameter_supported: true,
|
|
80
77
|
// https://datatracker.ietf.org/doc/html/rfc9101#section-4
|
|
81
|
-
request_object_signing_alg_values_supported: [...
|
|
78
|
+
request_object_signing_alg_values_supported: [...VERIFY_ALGOS, 'none'],
|
|
82
79
|
request_object_encryption_alg_values_supported: [], // None
|
|
83
80
|
request_object_encryption_enc_values_supported: [], // None
|
|
84
81
|
request_parameter_supported: true,
|
|
@@ -87,8 +84,8 @@ function buildMetadata(issuer, keyset, customMetadata) {
|
|
|
87
84
|
jwks_uri: new URL('/oauth/jwks', issuer).href,
|
|
88
85
|
authorization_endpoint: new URL('/oauth/authorize', issuer).href,
|
|
89
86
|
token_endpoint: new URL('/oauth/token', issuer).href,
|
|
90
|
-
token_endpoint_auth_methods_supported: [...
|
|
91
|
-
token_endpoint_auth_signing_alg_values_supported: [...
|
|
87
|
+
token_endpoint_auth_methods_supported: [...Client.AUTH_METHODS_SUPPORTED],
|
|
88
|
+
token_endpoint_auth_signing_alg_values_supported: [...VERIFY_ALGOS],
|
|
92
89
|
revocation_endpoint: new URL('/oauth/revoke', issuer).href,
|
|
93
90
|
// @TODO Should we implement these endpoints?
|
|
94
91
|
// introspection_endpoint: new URL('/oauth/introspect', issuer).href,
|
|
@@ -97,7 +94,7 @@ function buildMetadata(issuer, keyset, customMetadata) {
|
|
|
97
94
|
pushed_authorization_request_endpoint: new URL('/oauth/par', issuer).href,
|
|
98
95
|
require_pushed_authorization_requests: true,
|
|
99
96
|
// https://datatracker.ietf.org/doc/html/rfc9449#section-5.1
|
|
100
|
-
dpop_signing_alg_values_supported: [...
|
|
97
|
+
dpop_signing_alg_values_supported: [...VERIFY_ALGOS],
|
|
101
98
|
// https://datatracker.ietf.org/doc/html/rfc9396#section-14.4
|
|
102
99
|
authorization_details_types_supported: customMetadata?.authorization_details_types_supported,
|
|
103
100
|
// https://www.rfc-editor.org/rfc/rfc9728.html#section-4
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-metadata.js","sourceRoot":"","sources":["../../src/metadata/build-metadata.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build-metadata.js","sourceRoot":"","sources":["../../src/metadata/build-metadata.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,yCAAyC,GAC1C,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAOpD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,MAA6B,EAC7B,MAAc,EACd,cAA+B;IAE/B,OAAO,yCAAyC,CAAC,KAAK,CAAC;QACrD,MAAM;QAEN,gBAAgB,EAAE;YAChB,SAAS;YAET,yEAAyE;YACzE,kCAAkC;YAClC,kBAAkB;YAClB,oBAAoB;YACpB,sBAAsB;YAEtB,gEAAgE;SACjE;QACD,uBAAuB,EAAE;YACvB,EAAE;YACF,QAAQ,EAAE,6CAA6C;YACvD,+DAA+D;SAChE;QACD,wBAAwB,EAAE;YACxB,QAAQ;YACR,MAAM;YACN,WAAW;YAEX,SAAS;YACT,UAAU;YACV,yBAAyB;YACzB,mBAAmB;YACnB,gBAAgB;YAChB,oBAAoB;YACpB,cAAc;SACf;QACD,wBAAwB,EAAE;YACxB,mFAAmF;YACnF,OAAO;YACP,UAAU;YACV,0FAA0F;YAC1F,WAAW;SACZ;QACD,qBAAqB,EAAE;YACrB,EAAE;YACF,oBAAoB;YACpB,eAAe;SAChB;QACD,gCAAgC,EAAE;YAChC,sGAAsG;YACtG,MAAM;YAEN,iCAAiC;YACjC,WAAW;SACZ;QACD,oBAAoB,EAAE;YACpB,EAAE;YACF,OAAO;SACR;QACD,wBAAwB,EAAE;YACxB,EAAE;YACF,MAAM;YACN,OAAO;YACP,OAAO;YACP,aAAa;SACd;QAED,iEAAiE;QACjE,uBAAuB,EAAE;YACvB,MAAM;YACN,OAAO;YACP,SAAS;YACT,gBAAgB;YAChB,QAAQ;SACT;QAED,gDAAgD;QAChD,8CAA8C,EAAE,IAAI;QAEpD,0DAA0D;QAC1D,2CAA2C,EAAE,CAAC,GAAG,YAAY,EAAE,MAAM,CAAC;QACtE,8CAA8C,EAAE,EAAE,EAAE,OAAO;QAC3D,8CAA8C,EAAE,EAAE,EAAE,OAAO;QAE3D,2BAA2B,EAAE,IAAI;QACjC,+BAA+B,EAAE,IAAI;QACrC,gCAAgC,EAAE,IAAI;QAEtC,QAAQ,EAAE,IAAI,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,IAAI;QAE7C,sBAAsB,EAAE,IAAI,GAAG,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC,IAAI;QAEhE,cAAc,EAAE,IAAI,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,IAAI;QACpD,qCAAqC,EAAE,CAAC,GAAG,MAAM,CAAC,sBAAsB,CAAC;QACzE,gDAAgD,EAAE,CAAC,GAAG,YAAY,CAAC;QAEnE,mBAAmB,EAAE,IAAI,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,IAAI;QAE1D,6CAA6C;QAC7C,qEAAqE;QACrE,+DAA+D;QAE/D,0DAA0D;QAC1D,qCAAqC,EAAE,IAAI,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,IAAI;QAEzE,qCAAqC,EAAE,IAAI;QAE3C,4DAA4D;QAC5D,iCAAiC,EAAE,CAAC,GAAG,YAAY,CAAC;QAEpD,6DAA6D;QAC7D,qCAAqC,EACnC,cAAc,EAAE,qCAAqC;QAEvD,wDAAwD;QACxD,mBAAmB,EAAE,cAAc,EAAE,mBAAmB;QAExD,uFAAuF;QACvF,qCAAqC,EAAE,IAAI;KAC5C,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { Keyset } from '@atproto/jwk'\nimport {\n OAuthAuthorizationServerMetadata,\n OAuthIssuerIdentifier,\n oauthAuthorizationServerMetadataValidator,\n} from '@atproto/oauth-types'\nimport { Client } from '../client/client.js'\nimport { VERIFY_ALGOS } from '../lib/util/crypto.js'\n\nexport type CustomMetadata = {\n authorization_details_types_supported?: string[]\n protected_resources?: string[]\n}\n\n/**\n * @see {@link https://datatracker.ietf.org/doc/html/rfc8414#section-2}\n * @see {@link https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata}\n * @see {@link https://openid.net/specs/openid-connect-prompt-create-1_0.html}\n */\nexport function buildMetadata(\n issuer: OAuthIssuerIdentifier,\n keyset: Keyset,\n customMetadata?: CustomMetadata,\n): OAuthAuthorizationServerMetadata {\n return oauthAuthorizationServerMetadataValidator.parse({\n issuer,\n\n scopes_supported: [\n 'atproto',\n\n // These serve as hint that this server supports the transitional scopes.\n // This is not a specced behavior.\n 'transition:email',\n 'transition:generic',\n 'transition:chat.bsky',\n\n // Other atproto scopes can't be enumerated as they are dynamic.\n ],\n subject_types_supported: [\n //\n 'public', // The same \"sub\" is returned for all clients\n // 'pairwise', // A different \"sub\" is returned for each client\n ],\n response_types_supported: [\n // OAuth\n 'code',\n // 'token',\n\n // OpenID\n // 'none',\n // 'code id_token token',\n // 'code id_token',\n // 'code token',\n // 'id_token token',\n // 'id_token',\n ],\n response_modes_supported: [\n // https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes\n 'query',\n 'fragment',\n // https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html#FormPostResponseMode\n 'form_post',\n ],\n grant_types_supported: [\n //\n 'authorization_code',\n 'refresh_token',\n ],\n code_challenge_methods_supported: [\n // https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#pkce-code-challenge-method\n 'S256',\n\n // atproto does not allow \"plain\"\n // 'plain',\n ],\n ui_locales_supported: [\n //\n 'en-US',\n ],\n display_values_supported: [\n //\n 'page',\n 'popup',\n 'touch',\n // 'wap', LoL\n ],\n\n // https://openid.net/specs/openid-connect-prompt-create-1_0.html\n prompt_values_supported: [\n 'none',\n 'login',\n 'consent',\n 'select_account',\n 'create',\n ],\n\n // https://datatracker.ietf.org/doc/html/rfc9207\n authorization_response_iss_parameter_supported: true,\n\n // https://datatracker.ietf.org/doc/html/rfc9101#section-4\n request_object_signing_alg_values_supported: [...VERIFY_ALGOS, 'none'],\n request_object_encryption_alg_values_supported: [], // None\n request_object_encryption_enc_values_supported: [], // None\n\n request_parameter_supported: true,\n request_uri_parameter_supported: true,\n require_request_uri_registration: true,\n\n jwks_uri: new URL('/oauth/jwks', issuer).href,\n\n authorization_endpoint: new URL('/oauth/authorize', issuer).href,\n\n token_endpoint: new URL('/oauth/token', issuer).href,\n token_endpoint_auth_methods_supported: [...Client.AUTH_METHODS_SUPPORTED],\n token_endpoint_auth_signing_alg_values_supported: [...VERIFY_ALGOS],\n\n revocation_endpoint: new URL('/oauth/revoke', issuer).href,\n\n // @TODO Should we implement these endpoints?\n // introspection_endpoint: new URL('/oauth/introspect', issuer).href,\n // end_session_endpoint: new URL('/oauth/logout', issuer).href,\n\n // https://datatracker.ietf.org/doc/html/rfc9126#section-5\n pushed_authorization_request_endpoint: new URL('/oauth/par', issuer).href,\n\n require_pushed_authorization_requests: true,\n\n // https://datatracker.ietf.org/doc/html/rfc9449#section-5.1\n dpop_signing_alg_values_supported: [...VERIFY_ALGOS],\n\n // https://datatracker.ietf.org/doc/html/rfc9396#section-14.4\n authorization_details_types_supported:\n customMetadata?.authorization_details_types_supported,\n\n // https://www.rfc-editor.org/rfc/rfc9728.html#section-4\n protected_resources: customMetadata?.protected_resources,\n\n // https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-00.html\n client_id_metadata_document_supported: true,\n })\n}\n"]}
|
package/dist/oauth-client.js
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
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
|
-
__exportStar(require("@atproto/oauth-types"), exports);
|
|
18
|
-
__exportStar(require("./client/client-utils.js"), exports);
|
|
1
|
+
export * from '@atproto/oauth-types';
|
|
2
|
+
export * from './client/client-utils.js';
|
|
19
3
|
//# sourceMappingURL=oauth-client.js.map
|
package/dist/oauth-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-client.js","sourceRoot":"","sources":["../src/oauth-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"oauth-client.js","sourceRoot":"","sources":["../src/oauth-client.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AAEpC,cAAc,0BAA0B,CAAA","sourcesContent":["export * from '@atproto/oauth-types'\nexport type * from './client/client.js'\nexport * from './client/client-utils.js'\n"]}
|
package/dist/oauth-dpop.js
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
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
|
-
__exportStar(require("./dpop/dpop-nonce.js"), exports);
|
|
18
|
-
__exportStar(require("./dpop/dpop-manager.js"), exports);
|
|
1
|
+
export * from './dpop/dpop-nonce.js';
|
|
2
|
+
export * from './dpop/dpop-manager.js';
|
|
19
3
|
//# sourceMappingURL=oauth-dpop.js.map
|
package/dist/oauth-dpop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-dpop.js","sourceRoot":"","sources":["../src/oauth-dpop.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"oauth-dpop.js","sourceRoot":"","sources":["../src/oauth-dpop.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA","sourcesContent":["export * from './dpop/dpop-nonce.js'\nexport * from './dpop/dpop-manager.js'\n"]}
|