@atproto/oauth-provider 0.22.7 → 0.22.9

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/customization/background.d.ts +4 -4
  3. package/dist/customization/background.d.ts.map +1 -1
  4. package/dist/customization/background.js +3 -2
  5. package/dist/customization/background.js.map +1 -1
  6. package/dist/customization/branding.d.ts +8 -8
  7. package/dist/customization/branding.d.ts.map +1 -1
  8. package/dist/customization/branding.js +2 -1
  9. package/dist/customization/branding.js.map +1 -1
  10. package/dist/customization/build-customization-coep.d.ts +4 -0
  11. package/dist/customization/build-customization-coep.d.ts.map +1 -0
  12. package/dist/customization/build-customization-coep.js +11 -0
  13. package/dist/customization/build-customization-coep.js.map +1 -0
  14. package/dist/customization/build-customization-csp.d.ts +9 -0
  15. package/dist/customization/build-customization-csp.d.ts.map +1 -0
  16. package/dist/customization/build-customization-csp.js +56 -0
  17. package/dist/customization/build-customization-csp.js.map +1 -0
  18. package/dist/customization/customization.d.ts +11 -11
  19. package/dist/customization/image-url.d.ts +3 -0
  20. package/dist/customization/image-url.d.ts.map +1 -0
  21. package/dist/customization/image-url.js +10 -0
  22. package/dist/customization/image-url.js.map +1 -0
  23. package/dist/lib/csp/index.d.ts.map +1 -1
  24. package/dist/lib/csp/index.js +17 -2
  25. package/dist/lib/csp/index.js.map +1 -1
  26. package/dist/lib/http/stream.d.ts +9 -3
  27. package/dist/lib/http/stream.d.ts.map +1 -1
  28. package/dist/lib/http/stream.js +34 -5
  29. package/dist/lib/http/stream.js.map +1 -1
  30. package/dist/oauth-provider.d.ts +1 -1
  31. package/dist/oauth-provider.d.ts.map +1 -1
  32. package/dist/oauth-provider.js +1 -1
  33. package/dist/oauth-provider.js.map +1 -1
  34. package/dist/router/assets/assets.d.ts +5 -0
  35. package/dist/router/assets/assets.d.ts.map +1 -1
  36. package/dist/router/assets/assets.js +32 -33
  37. package/dist/router/assets/assets.js.map +1 -1
  38. package/package.json +11 -12
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @atproto/oauth-provider
2
2
 
3
+ ## 0.22.9
4
+
5
+ ### Patch Changes
6
+
7
+ - [#5547](https://github.com/bluesky-social/atproto/pull/5547) [`80bcda7`](https://github.com/bluesky-social/atproto/commit/80bcda748b435ecfecc18158921f4a84de2b4247) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Narrow the CSP `img-src` directive for customization images: the `data:` scheme source is now emitted only when a customization image is actually configured as a `data:` uri, and http(s) customization images contribute their own origin.
8
+
9
+ - [#5536](https://github.com/bluesky-social/atproto/pull/5536) [`7f6785b`](https://github.com/bluesky-social/atproto/commit/7f6785bd4c48438e621c9b96265a52f14d64ce3c) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Remove unused dev dependency `@types/send`
10
+
11
+ - [#5499](https://github.com/bluesky-social/atproto/pull/5499) [`210907c`](https://github.com/bluesky-social/atproto/commit/210907c801d281c6b83c92bf94c888b2dc3d531f) Thanks [@fatfingers23](https://github.com/fatfingers23)! - Resolve permission set lexicons hosted on the PDS itself from the local actor store instead of fetching them over the network. Re-export `LexResolverError` from `@atproto/oauth-provider`.
12
+
13
+ - [#5547](https://github.com/bluesky-social/atproto/pull/5547) [`80bcda7`](https://github.com/bluesky-social/atproto/commit/80bcda748b435ecfecc18158921f4a84de2b4247) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add support for http: customization assets in development
14
+ - Updated dependencies [[`210907c`](https://github.com/bluesky-social/atproto/commit/210907c801d281c6b83c92bf94c888b2dc3d531f), [`210907c`](https://github.com/bluesky-social/atproto/commit/210907c801d281c6b83c92bf94c888b2dc3d531f), [`1f639d9`](https://github.com/bluesky-social/atproto/commit/1f639d97498981eea3553b9a20a8538437af9658), [`210907c`](https://github.com/bluesky-social/atproto/commit/210907c801d281c6b83c92bf94c888b2dc3d531f), [`210907c`](https://github.com/bluesky-social/atproto/commit/210907c801d281c6b83c92bf94c888b2dc3d531f), [`210907c`](https://github.com/bluesky-social/atproto/commit/210907c801d281c6b83c92bf94c888b2dc3d531f)]:
15
+ - @atproto/lex-resolver@0.3.0
16
+ - @atproto/oauth-provider-ui@0.10.4
17
+ - @atproto/lex-document@0.1.12
18
+
19
+ ## 0.22.8
20
+
21
+ ### Patch Changes
22
+
23
+ - [#5502](https://github.com/bluesky-social/atproto/pull/5502) [`ac0989b`](https://github.com/bluesky-social/atproto/commit/ac0989bf9e16affd4aa919df8609b12f4ee8cd65) Thanks [@devinivy](https://github.com/devinivy)! - Bound the request bodies accepted by the OAuth and account-management endpoints
24
+ at 100 KiB. The bound is on the decoded body, so a compressed request is
25
+ measured after decompression, and a `content-length` above it is rejected
26
+ without reading the body. Oversized bodies fail with a 413.
27
+ - Updated dependencies [[`f88aa58`](https://github.com/bluesky-social/atproto/commit/f88aa5842df9aba9f208a6073272b43ef9bd089d)]:
28
+ - @atproto-labs/fetch-node@0.4.0
29
+ - @atproto/oauth-provider-ui@0.10.3
30
+ - @atproto/lex-resolver@0.2.13
31
+
3
32
  ## 0.22.7
4
33
 
5
34
  ### Patch Changes
@@ -1,10 +1,10 @@
1
1
  import { z } from 'zod';
2
2
  export declare const backgroundsSchema: z.ZodObject<{
3
- light: z.ZodOptional<z.ZodString>;
4
- dark: z.ZodOptional<z.ZodString>;
3
+ light: z.ZodOptional<z.ZodEffects<z.ZodString, `data:${string}` | `http://${string}` | `https://${string}`, string>>;
4
+ dark: z.ZodOptional<z.ZodEffects<z.ZodString, `data:${string}` | `http://${string}` | `https://${string}`, string>>;
5
5
  }, "strip", z.ZodTypeAny, {
6
- light?: string | undefined;
7
- dark?: string | undefined;
6
+ light?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
7
+ dark?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
8
8
  }, {
9
9
  light?: string | undefined;
10
10
  dark?: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../../src/customization/background.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,iBAAiB;;;;;;;;;EAG5B,CAAA;AACF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
1
+ {"version":3,"file":"background.d.ts","sourceRoot":"","sources":["../../src/customization/background.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,iBAAiB;;;;;;;;;EAG5B,CAAA;AACF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
@@ -1,7 +1,8 @@
1
1
  import { z } from 'zod';
2
+ import { imageUrlSchema } from './image-url.js';
2
3
  // Light- and dark-mode background image URLs for the authorization screens.
3
4
  export const backgroundsSchema = z.object({
4
- light: z.string().url().optional(),
5
- dark: z.string().url().optional(),
5
+ light: imageUrlSchema.optional(),
6
+ dark: imageUrlSchema.optional(),
6
7
  });
7
8
  //# sourceMappingURL=background.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"background.js","sourceRoot":"","sources":["../../src/customization/background.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,4EAA4E;AAC5E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAA","sourcesContent":["import { z } from 'zod'\n\n// Light- and dark-mode background image URLs for the authorization screens.\nexport const backgroundsSchema = z.object({\n light: z.string().url().optional(),\n dark: z.string().url().optional(),\n})\nexport type Backgrounds = z.infer<typeof backgroundsSchema>\n"]}
1
+ {"version":3,"file":"background.js","sourceRoot":"","sources":["../../src/customization/background.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE/C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,cAAc,CAAC,QAAQ,EAAE;IAChC,IAAI,EAAE,cAAc,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAA","sourcesContent":["import { z } from 'zod'\nimport { imageUrlSchema } from './image-url.js'\n\n// Light- and dark-mode background image URLs for the authorization screens.\nexport const backgroundsSchema = z.object({\n light: imageUrlSchema.optional(),\n dark: imageUrlSchema.optional(),\n})\nexport type Backgrounds = z.infer<typeof backgroundsSchema>\n"]}
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  export declare const brandingSchema: z.ZodObject<{
3
3
  name: z.ZodOptional<z.ZodString>;
4
- logo: z.ZodOptional<z.ZodString>;
4
+ logo: z.ZodOptional<z.ZodEffects<z.ZodString, `data:${string}` | `http://${string}` | `https://${string}`, string>>;
5
5
  colors: z.ZodOptional<z.ZodObject<Record<"error" | "info" | "primary" | "success" | "warning", z.ZodOptional<z.ZodEffects<z.ZodString, import("../lib/util/color.js").RgbColor, string>>>, "strip", z.ZodTypeAny, {
6
6
  error?: import("../lib/util/color.js").RgbColor | undefined;
7
7
  info?: import("../lib/util/color.js").RgbColor | undefined;
@@ -16,11 +16,11 @@ export declare const brandingSchema: z.ZodObject<{
16
16
  warning?: string | undefined;
17
17
  }>>;
18
18
  background: z.ZodOptional<z.ZodObject<{
19
- light: z.ZodOptional<z.ZodString>;
20
- dark: z.ZodOptional<z.ZodString>;
19
+ light: z.ZodOptional<z.ZodEffects<z.ZodString, `data:${string}` | `http://${string}` | `https://${string}`, string>>;
20
+ dark: z.ZodOptional<z.ZodEffects<z.ZodString, `data:${string}` | `http://${string}` | `https://${string}`, string>>;
21
21
  }, "strip", z.ZodTypeAny, {
22
- light?: string | undefined;
23
- dark?: string | undefined;
22
+ light?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
23
+ dark?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
24
24
  }, {
25
25
  light?: string | undefined;
26
26
  dark?: string | undefined;
@@ -40,7 +40,7 @@ export declare const brandingSchema: z.ZodObject<{
40
40
  }>, "many">>;
41
41
  }, "strip", z.ZodTypeAny, {
42
42
  name?: string | undefined;
43
- logo?: string | undefined;
43
+ logo?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
44
44
  colors?: {
45
45
  error?: import("../lib/util/color.js").RgbColor | undefined;
46
46
  info?: import("../lib/util/color.js").RgbColor | undefined;
@@ -49,8 +49,8 @@ export declare const brandingSchema: z.ZodObject<{
49
49
  warning?: import("../lib/util/color.js").RgbColor | undefined;
50
50
  } | undefined;
51
51
  background?: {
52
- light?: string | undefined;
53
- dark?: string | undefined;
52
+ light?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
53
+ dark?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
54
54
  } | undefined;
55
55
  links?: {
56
56
  title: string | Record<string, string | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/customization/branding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAC3D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA"}
1
+ {"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/customization/branding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAMvB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAC3D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA"}
@@ -1,10 +1,11 @@
1
1
  import { z } from 'zod';
2
2
  import { backgroundsSchema } from './background.js';
3
3
  import { colorsSchema } from './colors.js';
4
+ import { imageUrlSchema } from './image-url.js';
4
5
  import { linksSchema } from './links.js';
5
6
  export const brandingSchema = z.object({
6
7
  name: z.string().optional(),
7
- logo: z.string().url().optional(),
8
+ logo: imageUrlSchema.optional(),
8
9
  colors: colorsSchema.optional(),
9
10
  background: backgroundsSchema.optional(),
10
11
  links: z.array(linksSchema).optional(),
@@ -1 +1 @@
1
- {"version":3,"file":"branding.js","sourceRoot":"","sources":["../../src/customization/branding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACjC,MAAM,EAAE,YAAY,CAAC,QAAQ,EAAE;IAC/B,UAAU,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACxC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE;CACvC,CAAC,CAAA","sourcesContent":["import { z } from 'zod'\nimport { backgroundsSchema } from './background.js'\nimport { colorsSchema } from './colors.js'\nimport { linksSchema } from './links.js'\n\nexport const brandingSchema = z.object({\n name: z.string().optional(),\n logo: z.string().url().optional(),\n colors: colorsSchema.optional(),\n background: backgroundsSchema.optional(),\n links: z.array(linksSchema).optional(),\n})\nexport type BrandingConfig = z.input<typeof brandingSchema>\nexport type Branding = z.infer<typeof brandingSchema>\n"]}
1
+ {"version":3,"file":"branding.js","sourceRoot":"","sources":["../../src/customization/branding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,cAAc,CAAC,QAAQ,EAAE;IAC/B,MAAM,EAAE,YAAY,CAAC,QAAQ,EAAE;IAC/B,UAAU,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACxC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE;CACvC,CAAC,CAAA","sourcesContent":["import { z } from 'zod'\nimport { backgroundsSchema } from './background.js'\nimport { colorsSchema } from './colors.js'\nimport { imageUrlSchema } from './image-url.js'\nimport { linksSchema } from './links.js'\n\nexport const brandingSchema = z.object({\n name: z.string().optional(),\n logo: imageUrlSchema.optional(),\n colors: colorsSchema.optional(),\n background: backgroundsSchema.optional(),\n links: z.array(linksSchema).optional(),\n})\nexport type BrandingConfig = z.input<typeof brandingSchema>\nexport type Branding = z.infer<typeof brandingSchema>\n"]}
@@ -0,0 +1,4 @@
1
+ import { CrossOriginEmbedderPolicy } from '../lib/http/security-headers.js';
2
+ import type { Customization } from './customization.js';
3
+ export declare function buildCustomizationCoep({ hcaptcha, }: Customization): CrossOriginEmbedderPolicy | undefined;
4
+ //# sourceMappingURL=build-customization-coep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-customization-coep.d.ts","sourceRoot":"","sources":["../../src/customization/build-customization-coep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAA;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,GACT,EAAE,aAAa,GAAG,yBAAyB,GAAG,SAAS,CAOvD"}
@@ -0,0 +1,11 @@
1
+ import { CrossOriginEmbedderPolicy } from '../lib/http/security-headers.js';
2
+ export function buildCustomizationCoep({ hcaptcha, }) {
3
+ // hCaptcha's implementation of COEP is currently broken. Let's disable it
4
+ // to avoid breaking the entire page.
5
+ //
6
+ // https://github.com/hCaptcha/react-hcaptcha/issues/259
7
+ // https://github.com/hCaptcha/react-hcaptcha/issues/380
8
+ if (hcaptcha)
9
+ return CrossOriginEmbedderPolicy.unsafeNone;
10
+ }
11
+ //# sourceMappingURL=build-customization-coep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-customization-coep.js","sourceRoot":"","sources":["../../src/customization/build-customization-coep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAA;AAG3E,MAAM,UAAU,sBAAsB,CAAC,EACrC,QAAQ,GACM;IACd,0EAA0E;IAC1E,qCAAqC;IACrC,EAAE;IACF,wDAAwD;IACxD,wDAAwD;IACxD,IAAI,QAAQ;QAAE,OAAO,yBAAyB,CAAC,UAAU,CAAA;AAC3D,CAAC","sourcesContent":["import { CrossOriginEmbedderPolicy } from '../lib/http/security-headers.js'\nimport type { Customization } from './customization.js'\n\nexport function buildCustomizationCoep({\n hcaptcha,\n}: Customization): CrossOriginEmbedderPolicy | undefined {\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 if (hcaptcha) return CrossOriginEmbedderPolicy.unsafeNone\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { CspConfig } from '../lib/csp/index.js';
2
+ import type { Customization } from './customization.js';
3
+ /**
4
+ * Transforms the customization settings into a Content Security Policy (CSP)
5
+ * configuration, based on the ways customization settings are used in the
6
+ * @atproto/oauth-provider-ui web app.
7
+ */
8
+ export declare function buildCustomizationCsp({ branding, hcaptcha, }: Customization): Generator<CspConfig, void, unknown>;
9
+ //# sourceMappingURL=build-customization-csp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-customization-csp.d.ts","sourceRoot":"","sources":["../../src/customization/build-customization-csp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAYvD;;;;GAIG;AACH,wBAAiB,qBAAqB,CAAC,EACrC,QAAQ,EACR,QAAQ,GACT,EAAE,aAAa,GAAG,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,CAgCrD"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @see {@link https://docs.hcaptcha.com/#content-security-policy-settings}
3
+ */
4
+ const HCAPTCHA_CSP = {
5
+ 'script-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
6
+ 'frame-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
7
+ 'style-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
8
+ 'connect-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
9
+ };
10
+ /**
11
+ * Transforms the customization settings into a Content Security Policy (CSP)
12
+ * configuration, based on the ways customization settings are used in the
13
+ * @atproto/oauth-provider-ui web app.
14
+ */
15
+ export function* buildCustomizationCsp({ branding, hcaptcha, }) {
16
+ // branding related CSP
17
+ if (branding) {
18
+ for (const uri of [
19
+ branding.logo,
20
+ branding.background?.dark,
21
+ branding.background?.light,
22
+ ]) {
23
+ if (uri != null) {
24
+ if (isHttpUri(uri)) {
25
+ yield { 'img-src': [uri] };
26
+ }
27
+ else if (isDataUri(uri)) {
28
+ // CSP hash sources (e.g. `sha256-<hash>`) do not authorize image
29
+ // fetches: they only apply to inline scripts/styles (and external
30
+ // scripts carrying integrity metadata), never to an `img-src` URL
31
+ // match. See the "Sources" note in:
32
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/img-src
33
+ // So the only way to allow a `data:` image is the `data:` scheme
34
+ // source, which we add here exclusively when the customization
35
+ // actually references a `data:` uri.
36
+ yield { 'img-src': ['data:'] };
37
+ }
38
+ else {
39
+ throw new Error(`Unsupported URI format: ${uri}`);
40
+ }
41
+ }
42
+ }
43
+ }
44
+ // hCaptcha related CSP
45
+ if (hcaptcha) {
46
+ yield HCAPTCHA_CSP;
47
+ }
48
+ }
49
+ function isHttpUri(uri) {
50
+ return uri.startsWith('http://') || uri.startsWith('https://');
51
+ }
52
+ function isDataUri(uri) {
53
+ // Basic validation of data URIs
54
+ return uri.startsWith('data:') && uri.length > 5 && uri.indexOf(',', 5) !== -1;
55
+ }
56
+ //# sourceMappingURL=build-customization-csp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-customization-csp.js","sourceRoot":"","sources":["../../src/customization/build-customization-csp.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,YAAY,GAAc;IAC9B,YAAY,EAAE,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;IAChE,WAAW,EAAE,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;IAC/D,WAAW,EAAE,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;IAC/D,aAAa,EAAE,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;CAClE,CAAA;AAED;;;;GAIG;AACH,MAAM,SAAS,CAAC,CAAC,qBAAqB,CAAC,EACrC,QAAQ,EACR,QAAQ,GACM;IACd,uBAAuB;IACvB,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,MAAM,GAAG,IAAI;YAChB,QAAQ,CAAC,IAAI;YACb,QAAQ,CAAC,UAAU,EAAE,IAAI;YACzB,QAAQ,CAAC,UAAU,EAAE,KAAK;SAC3B,EAAE,CAAC;YACF,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;gBAChB,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;oBACnB,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,CAAA;gBAC5B,CAAC;qBAAM,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC1B,iEAAiE;oBACjE,kEAAkE;oBAClE,kEAAkE;oBAClE,oCAAoC;oBACpC,sGAAsG;oBACtG,iEAAiE;oBACjE,+DAA+D;oBAC/D,qCAAqC;oBACrC,MAAM,EAAE,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE,CAAA;gBAChC,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,EAAE,CAAC,CAAA;gBACnD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,uBAAuB;IACvB,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,YAAY,CAAA;IACpB,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAChB,GAAW;IAEX,OAAO,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;AAChE,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,gCAAgC;IAChC,OAAO,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAA;AAChF,CAAC","sourcesContent":["import type { CspConfig } from '../lib/csp/index.js'\nimport type { Customization } from './customization.js'\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\n/**\n * Transforms the customization settings into a Content Security Policy (CSP)\n * configuration, based on the ways customization settings are used in the\n * @atproto/oauth-provider-ui web app.\n */\nexport function* buildCustomizationCsp({\n branding,\n hcaptcha,\n}: Customization): Generator<CspConfig, void, unknown> {\n // branding related CSP\n if (branding) {\n for (const uri of [\n branding.logo,\n branding.background?.dark,\n branding.background?.light,\n ]) {\n if (uri != null) {\n if (isHttpUri(uri)) {\n yield { 'img-src': [uri] }\n } else if (isDataUri(uri)) {\n // CSP hash sources (e.g. `sha256-<hash>`) do not authorize image\n // fetches: they only apply to inline scripts/styles (and external\n // scripts carrying integrity metadata), never to an `img-src` URL\n // match. See the \"Sources\" note in:\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/img-src\n // So the only way to allow a `data:` image is the `data:` scheme\n // source, which we add here exclusively when the customization\n // actually references a `data:` uri.\n yield { 'img-src': ['data:'] }\n } else {\n throw new Error(`Unsupported URI format: ${uri}`)\n }\n }\n }\n }\n\n // hCaptcha related CSP\n if (hcaptcha) {\n yield HCAPTCHA_CSP\n }\n}\n\nfunction isHttpUri(\n uri: string,\n): uri is `http://${string}` | `https://${string}` {\n return uri.startsWith('http://') || uri.startsWith('https://')\n}\n\nfunction isDataUri(uri: string): uri is `data:${string}` {\n // Basic validation of data URIs\n return uri.startsWith('data:') && uri.length > 5 && uri.indexOf(',', 5) !== -1\n}\n"]}
@@ -10,7 +10,7 @@ export declare const customizationSchema: z.ZodObject<{
10
10
  */
11
11
  branding: z.ZodOptional<z.ZodObject<{
12
12
  name: z.ZodOptional<z.ZodString>;
13
- logo: z.ZodOptional<z.ZodString>;
13
+ logo: z.ZodOptional<z.ZodEffects<z.ZodString, `data:${string}` | `http://${string}` | `https://${string}`, string>>;
14
14
  colors: z.ZodOptional<z.ZodObject<Record<"error" | "info" | "primary" | "success" | "warning", z.ZodOptional<z.ZodEffects<z.ZodString, import("../lib/util/color.js").RgbColor, string>>>, "strip", z.ZodTypeAny, {
15
15
  error?: import("../lib/util/color.js").RgbColor | undefined;
16
16
  info?: import("../lib/util/color.js").RgbColor | undefined;
@@ -25,11 +25,11 @@ export declare const customizationSchema: z.ZodObject<{
25
25
  warning?: string | undefined;
26
26
  }>>;
27
27
  background: z.ZodOptional<z.ZodObject<{
28
- light: z.ZodOptional<z.ZodString>;
29
- dark: z.ZodOptional<z.ZodString>;
28
+ light: z.ZodOptional<z.ZodEffects<z.ZodString, `data:${string}` | `http://${string}` | `https://${string}`, string>>;
29
+ dark: z.ZodOptional<z.ZodEffects<z.ZodString, `data:${string}` | `http://${string}` | `https://${string}`, string>>;
30
30
  }, "strip", z.ZodTypeAny, {
31
- light?: string | undefined;
32
- dark?: string | undefined;
31
+ light?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
32
+ dark?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
33
33
  }, {
34
34
  light?: string | undefined;
35
35
  dark?: string | undefined;
@@ -49,7 +49,7 @@ export declare const customizationSchema: z.ZodObject<{
49
49
  }>, "many">>;
50
50
  }, "strip", z.ZodTypeAny, {
51
51
  name?: string | undefined;
52
- logo?: string | undefined;
52
+ logo?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
53
53
  colors?: {
54
54
  error?: import("../lib/util/color.js").RgbColor | undefined;
55
55
  info?: import("../lib/util/color.js").RgbColor | undefined;
@@ -58,8 +58,8 @@ export declare const customizationSchema: z.ZodObject<{
58
58
  warning?: import("../lib/util/color.js").RgbColor | undefined;
59
59
  } | undefined;
60
60
  background?: {
61
- light?: string | undefined;
62
- dark?: string | undefined;
61
+ light?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
62
+ dark?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
63
63
  } | undefined;
64
64
  links?: {
65
65
  title: string | Record<string, string | undefined>;
@@ -117,7 +117,7 @@ export declare const customizationSchema: z.ZodObject<{
117
117
  availableUserDomains?: string[] | undefined;
118
118
  branding?: {
119
119
  name?: string | undefined;
120
- logo?: string | undefined;
120
+ logo?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
121
121
  colors?: {
122
122
  error?: import("../lib/util/color.js").RgbColor | undefined;
123
123
  info?: import("../lib/util/color.js").RgbColor | undefined;
@@ -126,8 +126,8 @@ export declare const customizationSchema: z.ZodObject<{
126
126
  warning?: import("../lib/util/color.js").RgbColor | undefined;
127
127
  } | undefined;
128
128
  background?: {
129
- light?: string | undefined;
130
- dark?: string | undefined;
129
+ light?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
130
+ dark?: `data:${string}` | `http://${string}` | `https://${string}` | undefined;
131
131
  } | undefined;
132
132
  links?: {
133
133
  title: string | Record<string, string | undefined>;
@@ -0,0 +1,3 @@
1
+ import { z } from 'zod';
2
+ export declare const imageUrlSchema: z.ZodEffects<z.ZodString, `data:${string}` | `http://${string}` | `https://${string}`, string>;
3
+ //# sourceMappingURL=image-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-url.d.ts","sourceRoot":"","sources":["../../src/customization/image-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,cAAc,gGAWxB,CAAA"}
@@ -0,0 +1,10 @@
1
+ import { z } from 'zod';
2
+ export const imageUrlSchema = z
3
+ .string()
4
+ .url()
5
+ .refine((url) => url.startsWith('data:') ||
6
+ url.startsWith('http:') ||
7
+ url.startsWith('https:'), {
8
+ message: 'URL must start with data:, http:, or https:',
9
+ });
10
+ //# sourceMappingURL=image-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-url.js","sourceRoot":"","sources":["../../src/customization/image-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC;KAC5B,MAAM,EAAE;KACR,GAAG,EAAE;KACL,MAAM,CACL,CAAC,GAAG,EAAsE,EAAE,CAC1E,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;IACvB,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;IACvB,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAC1B;IACE,OAAO,EAAE,6CAA6C;CACvD,CACF,CAAA","sourcesContent":["import { z } from 'zod'\n\nexport const imageUrlSchema = z\n .string()\n .url()\n .refine(\n (url): url is `data:${string}` | `http://${string}` | `https://${string}` =>\n url.startsWith('data:') ||\n url.startsWith('http:') ||\n url.startsWith('https:'),\n {\n message: 'URL must start with data:, http:, or https:',\n },\n )\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/csp/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE9D,MAAM,MAAM,QAAQ,GAChB,OAAO,GACP,QAAQ,MAAM,EAAE,GAChB,SAAS,MAAM,EAAE,GACjB,QAAQ,GACR,QAAQ,GACR,WAAW,MAAM,GAAG,GACpB,UAAU,MAAM,GAAG,GACnB,iBAAiB,GACjB,eAAe,GACf,kBAAkB,GAClB,iBAAiB,GACjB,iBAAiB,CAAA;AAErB,QAAA,MAAM,iBAAiB,YAAI,UAAU,CAAU,CAAA;AAC/C,QAAA,MAAM,kBAAkB,YACtB,2BAA2B,EAC3B,yBAAyB,CACjB,CAAA;AACV,QAAA,MAAM,gBAAgB,YACpB,aAAa,EACb,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,CACH,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,QAAQ,CAC9B;KACG,CAAC,IAAI,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO;CACrD,GAAG;KACD,CAAC,IAAI,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ;CACrD,GAAG;KACD,CAAC,IAAI,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC;CAC9D,CACF,CAAA;AAID,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAkBlD;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACjE,GAAG,OAAO,EAAE,CAAC,GAEiD,aAAa,CAAC,CAAC,CAAC,CAC/E;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,CA8BhE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/csp/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE9D,MAAM,MAAM,QAAQ,GAChB,OAAO,GACP,QAAQ,MAAM,EAAE,GAChB,SAAS,MAAM,EAAE,GACjB,QAAQ,GACR,QAAQ,GACR,WAAW,MAAM,GAAG,GACpB,UAAU,MAAM,GAAG,GACnB,iBAAiB,GACjB,eAAe,GACf,kBAAkB,GAClB,iBAAiB,GACjB,iBAAiB,CAAA;AAErB,QAAA,MAAM,iBAAiB,YAAI,UAAU,CAAU,CAAA;AAC/C,QAAA,MAAM,kBAAkB,YACtB,2BAA2B,EAC3B,yBAAyB,CACjB,CAAA;AACV,QAAA,MAAM,gBAAgB,YACpB,aAAa,EACb,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,CACH,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,QAAQ,CAC9B;KACG,CAAC,IAAI,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO;CACrD,GAAG;KACD,CAAC,IAAI,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ;CACrD,GAAG;KACD,CAAC,IAAI,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC;CAC9D,CACF,CAAA;AAID,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAkBlD;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,EACjE,GAAG,OAAO,EAAE,CAAC,oBAId;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,CAuChE"}
@@ -33,6 +33,8 @@ export function buildCsp(config) {
33
33
  return values.join('; ');
34
34
  }
35
35
  export function mergeCsp(...configs) {
36
+ if (!configs.length)
37
+ return {};
36
38
  return configs.filter((v) => v != null).reduce(combineCsp);
37
39
  }
38
40
  export function combineCsp(a, b) {
@@ -57,12 +59,25 @@ export function combineCsp(a, b) {
57
59
  if (b[name])
58
60
  for (const value of b[name])
59
61
  set.add(value);
62
+ // Remove URL values if the protocol is already present in the set
63
+ for (const value of set) {
64
+ if (value.startsWith('http://')) {
65
+ if (set.has('http:'))
66
+ set.delete(value);
67
+ }
68
+ else if (value.startsWith('https://')) {
69
+ if (set.has('https:'))
70
+ set.delete(value);
71
+ }
72
+ }
60
73
  if (set.size > 1 && set.has(NONE))
61
74
  set.delete(NONE);
62
75
  result[name] = [...set];
63
76
  }
64
- else if (a[name] || b[name]) {
65
- result[name] = a[name] || b[name];
77
+ else {
78
+ const value = a[name] || b[name];
79
+ if (value)
80
+ result[name] = [...value];
66
81
  }
67
82
  }
68
83
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/csp/index.ts"],"names":[],"mappings":"AAgBA,MAAM,iBAAiB,GAAG,CAAC,UAAU,CAAU,CAAA;AAC/C,MAAM,kBAAkB,GAAG;IACzB,2BAA2B;IAC3B,yBAAyB;CACjB,CAAA;AACV,MAAM,gBAAgB,GAAG;IACvB,aAAa;IACb,aAAa;IACb,aAAa;IACb,iBAAiB;IACjB,WAAW;IACX,SAAS;IACT,YAAY;IACZ,WAAW;CACH,CAAA;AAYV,MAAM,IAAI,GAAG,QAAQ,CAAA;AAErB,MAAM,UAAU,QAAQ,CAAC,MAAiB;IACxC,MAAM,MAAM,GAAa,EAAE,CAAA;IAE3B,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9C,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,IAAI,MAAM,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC1D,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,yCAAyC;QACzC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC5D,IAAI,GAAG,EAAE,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACpE,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,GAAG,OAAU;IAEb,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,UAAU,CAAqB,CAAA;AAChF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAY,EAAE,CAAY;IACnD,MAAM,MAAM,GAAc,EAAE,CAAA;IAE5B,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;QACtC,wCAAwC;QACxC,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA;QAChC,IAAI,KAAK,IAAI,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;IACzC,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YACvD,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YACvD,2BAA2B;YAC3B,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,QAAQ,IAAI,IAAI,CAAA;QAC7C,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;YAC5B,IAAI,CAAC,CAAC,IAAI,CAAC;gBAAE,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC;oBAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACxD,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YACnD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAA;QACzB,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC","sourcesContent":["import type { CombinedTuple, Simplify } from '../util/type.js'\n\nexport type CspValue =\n | `data:`\n | `http:${string}`\n | `https:${string}`\n | `'none'`\n | `'self'`\n | `'sha256-${string}'`\n | `'nonce-${string}'`\n | `'unsafe-inline'`\n | `'unsafe-eval'`\n | `'strict-dynamic'`\n | `'report-sample'`\n | `'unsafe-hashes'`\n\nconst STRING_DIRECTIVES = ['base-uri'] as const\nconst BOOLEAN_DIRECTIVES = [\n 'upgrade-insecure-requests',\n 'block-all-mixed-content',\n] as const\nconst ARRAY_DIRECTIVES = [\n 'connect-src',\n 'default-src',\n 'form-action',\n 'frame-ancestors',\n 'frame-src',\n 'img-src',\n 'script-src',\n 'style-src',\n] as const\n\nexport type CspConfig = Simplify<\n {\n [K in (typeof BOOLEAN_DIRECTIVES)[number]]?: boolean\n } & {\n [K in (typeof STRING_DIRECTIVES)[number]]?: CspValue\n } & {\n [K in (typeof ARRAY_DIRECTIVES)[number]]?: Iterable<CspValue>\n }\n>\n\nconst NONE = \"'none'\"\n\nexport function buildCsp(config: CspConfig): string {\n const values: string[] = []\n\n for (const name of BOOLEAN_DIRECTIVES) {\n if (config[name] === true) values.push(name)\n }\n\n for (const name of STRING_DIRECTIVES) {\n if (config[name]) values.push(`${name} ${config[name]}`)\n }\n\n for (const name of ARRAY_DIRECTIVES) {\n // Remove duplicate values by using a Set\n const val = config[name] ? new Set(config[name]) : undefined\n if (val?.size) values.push(`${name} ${Array.from(val).join(' ')}`)\n }\n\n return values.join('; ')\n}\n\nexport function mergeCsp<C extends (CspConfig | null | undefined)[]>(\n ...configs: C\n) {\n return configs.filter((v) => v != null).reduce(combineCsp) as CombinedTuple<C>\n}\n\nexport function combineCsp(a: CspConfig, b: CspConfig): CspConfig {\n const result: CspConfig = {}\n\n for (const name of BOOLEAN_DIRECTIVES) {\n // @NOTE b (if defined) takes precedence\n const value = b[name] ?? a[name]\n if (value != null) result[name] = value\n }\n\n for (const name of STRING_DIRECTIVES) {\n if (a[name] || b[name]) {\n const aNotNone = a[name] === NONE ? undefined : a[name]\n const bNotNone = b[name] === NONE ? undefined : b[name]\n // @NOTE b takes precedence\n result[name] = bNotNone || aNotNone || NONE\n }\n }\n\n for (const name of ARRAY_DIRECTIVES) {\n if (a[name] && b[name]) {\n const set = new Set(a[name])\n if (b[name]) for (const value of b[name]) set.add(value)\n if (set.size > 1 && set.has(NONE)) set.delete(NONE)\n result[name] = [...set]\n } else if (a[name] || b[name]) {\n result[name] = a[name] || b[name]\n }\n }\n\n return result\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/csp/index.ts"],"names":[],"mappings":"AAgBA,MAAM,iBAAiB,GAAG,CAAC,UAAU,CAAU,CAAA;AAC/C,MAAM,kBAAkB,GAAG;IACzB,2BAA2B;IAC3B,yBAAyB;CACjB,CAAA;AACV,MAAM,gBAAgB,GAAG;IACvB,aAAa;IACb,aAAa;IACb,aAAa;IACb,iBAAiB;IACjB,WAAW;IACX,SAAS;IACT,YAAY;IACZ,WAAW;CACH,CAAA;AAYV,MAAM,IAAI,GAAG,QAAQ,CAAA;AAErB,MAAM,UAAU,QAAQ,CAAC,MAAiB;IACxC,MAAM,MAAM,GAAa,EAAE,CAAA;IAE3B,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9C,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,IAAI,MAAM,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC1D,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,yCAAyC;QACzC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC5D,IAAI,GAAG,EAAE,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACpE,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,GAAG,OAAU;IAEb,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,EAAsB,CAAA;IAClD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,UAAU,CAAqB,CAAA;AAChF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAY,EAAE,CAAY;IACnD,MAAM,MAAM,GAAc,EAAE,CAAA;IAE5B,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;QACtC,wCAAwC;QACxC,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA;QAChC,IAAI,KAAK,IAAI,IAAI;YAAE,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;IACzC,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YACvD,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YACvD,2BAA2B;YAC3B,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,IAAI,QAAQ,IAAI,IAAI,CAAA;QAC7C,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;YAC5B,IAAI,CAAC,CAAC,IAAI,CAAC;gBAAE,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC;oBAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACxD,kEAAkE;YAClE,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;gBACxB,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;oBAChC,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;wBAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBACzC,CAAC;qBAAM,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBACxC,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;wBAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;gBAC1C,CAAC;YACH,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YACnD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAA;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA;YAChC,IAAI,KAAK;gBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC","sourcesContent":["import type { CombinedTuple, Simplify } from '../util/type.js'\n\nexport type CspValue =\n | `data:`\n | `http:${string}`\n | `https:${string}`\n | `'none'`\n | `'self'`\n | `'sha256-${string}'`\n | `'nonce-${string}'`\n | `'unsafe-inline'`\n | `'unsafe-eval'`\n | `'strict-dynamic'`\n | `'report-sample'`\n | `'unsafe-hashes'`\n\nconst STRING_DIRECTIVES = ['base-uri'] as const\nconst BOOLEAN_DIRECTIVES = [\n 'upgrade-insecure-requests',\n 'block-all-mixed-content',\n] as const\nconst ARRAY_DIRECTIVES = [\n 'connect-src',\n 'default-src',\n 'form-action',\n 'frame-ancestors',\n 'frame-src',\n 'img-src',\n 'script-src',\n 'style-src',\n] as const\n\nexport type CspConfig = Simplify<\n {\n [K in (typeof BOOLEAN_DIRECTIVES)[number]]?: boolean\n } & {\n [K in (typeof STRING_DIRECTIVES)[number]]?: CspValue\n } & {\n [K in (typeof ARRAY_DIRECTIVES)[number]]?: Iterable<CspValue>\n }\n>\n\nconst NONE = \"'none'\"\n\nexport function buildCsp(config: CspConfig): string {\n const values: string[] = []\n\n for (const name of BOOLEAN_DIRECTIVES) {\n if (config[name] === true) values.push(name)\n }\n\n for (const name of STRING_DIRECTIVES) {\n if (config[name]) values.push(`${name} ${config[name]}`)\n }\n\n for (const name of ARRAY_DIRECTIVES) {\n // Remove duplicate values by using a Set\n const val = config[name] ? new Set(config[name]) : undefined\n if (val?.size) values.push(`${name} ${Array.from(val).join(' ')}`)\n }\n\n return values.join('; ')\n}\n\nexport function mergeCsp<C extends (CspConfig | null | undefined)[]>(\n ...configs: C\n) {\n if (!configs.length) return {} as CombinedTuple<C>\n return configs.filter((v) => v != null).reduce(combineCsp) as CombinedTuple<C>\n}\n\nexport function combineCsp(a: CspConfig, b: CspConfig): CspConfig {\n const result: CspConfig = {}\n\n for (const name of BOOLEAN_DIRECTIVES) {\n // @NOTE b (if defined) takes precedence\n const value = b[name] ?? a[name]\n if (value != null) result[name] = value\n }\n\n for (const name of STRING_DIRECTIVES) {\n if (a[name] || b[name]) {\n const aNotNone = a[name] === NONE ? undefined : a[name]\n const bNotNone = b[name] === NONE ? undefined : b[name]\n // @NOTE b takes precedence\n result[name] = bNotNone || aNotNone || NONE\n }\n }\n\n for (const name of ARRAY_DIRECTIVES) {\n if (a[name] && b[name]) {\n const set = new Set(a[name])\n if (b[name]) for (const value of b[name]) set.add(value)\n // Remove URL values if the protocol is already present in the set\n for (const value of set) {\n if (value.startsWith('http://')) {\n if (set.has('http:')) set.delete(value)\n } else if (value.startsWith('https://')) {\n if (set.has('https:')) set.delete(value)\n }\n }\n if (set.size > 1 && set.has(NONE)) set.delete(NONE)\n result[name] = [...set]\n } else {\n const value = a[name] || b[name]\n if (value) result[name] = [...value]\n }\n }\n\n return result\n}\n"]}
@@ -1,14 +1,20 @@
1
1
  import type { IncomingMessage } from 'node:http';
2
- import type { Readable } from 'node:stream';
2
+ import { type Readable } from 'node:stream';
3
3
  import { type KnownNames, type ParserResult } from './parser.js';
4
- export declare function decodeHttpRequest(req: IncomingMessage): Readable;
4
+ /**
5
+ * Bounds the decoded request body, whichever content-encoding it arrived with.
6
+ * The payloads these routes legitimately carry are single-digit kilobytes, so
7
+ * this leaves ample headroom.
8
+ */
9
+ export declare const DEFAULT_MAX_BODY_SIZE: number;
10
+ export declare function decodeHttpRequest(req: IncomingMessage, maxSize: number): Readable;
5
11
  /**
6
12
  * Generic method that parses a stream of unknown nature (HTTP request/response,
7
13
  * socket, file, etc.), but of known mime type, into a parsed object.
8
14
  *
9
15
  * @throws {TypeError} If the content-type is not valid or supported.
10
16
  */
11
- export declare function parseHttpRequest<A extends readonly KnownNames[]>(req: IncomingMessage, allow: A): Promise<ParserResult<Extract<{
17
+ export declare function parseHttpRequest<A extends readonly KnownNames[]>(req: IncomingMessage, allow: A, maxSize?: number): Promise<ParserResult<Extract<{
12
18
  readonly name: 'json';
13
19
  readonly test: (mime: string) => mime is `application/json` | `application/${string}+json`;
14
20
  readonly parse: (buffer: Buffer<ArrayBufferLike>, { charset }: import("./parser.js").ContentType) => import("./parser.js").Json;
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/lib/http/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAG3C,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,YAAY,EAGlB,MAAM,aAAa,CAAA;AAEpB,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,GAAG,QAAQ,CAQhE;AAED;;;;;GAKG;AAEH,wBAAsB,gBAAgB,CAAC,CAAC,SAAS,SAAS,UAAU,EAAE,EACpE,GAAG,EAAE,eAAe,EACpB,KAAK,EAAE,CAAC;;;;;UAiBuB,CAAC,CAAC,MAAM,CAAC;;;;;;;;;;;;;KAEzC;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3E"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/lib/http/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EAAe,KAAK,QAAQ,EAAY,MAAM,aAAa,CAAA;AAOlE,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,YAAY,EAGlB,MAAM,aAAa,CAAA;AAEpB;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAAa,CAAA;AAE/C,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,MAAM,GACd,QAAQ,CAoCV;AAED;;;;;GAKG;AAEH,wBAAsB,gBAAgB,CAAC,CAAC,SAAS,SAAS,UAAU,EAAE,EACpE,GAAG,EAAE,eAAe,EACpB,KAAK,EAAE,CAAC,EACR,OAAO,GAAE,MAA8B;;;;;UAiBR,CAAC,CAAC,MAAM,CAAC;;;;;;;;;;;;;KAEzC;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3E"}
@@ -1,9 +1,38 @@
1
+ import { pipeline } from 'node:stream';
1
2
  import createHttpError from 'http-errors';
2
- import { decodeStream, streamToNodeBuffer } from '@atproto/common';
3
+ import { MaxSizeChecker, createDecoders, streamToNodeBuffer, } from '@atproto/common';
3
4
  import { parseContentType, parsers, } from './parser.js';
4
- export function decodeHttpRequest(req) {
5
+ /**
6
+ * Bounds the decoded request body, whichever content-encoding it arrived with.
7
+ * The payloads these routes legitimately carry are single-digit kilobytes, so
8
+ * this leaves ample headroom.
9
+ */
10
+ export const DEFAULT_MAX_BODY_SIZE = 100 * 1024; // 100 KiB
11
+ export function decodeHttpRequest(req, maxSize) {
12
+ // @NOTE Content-Length counts the octets actually transferred, i.e. the
13
+ // body *after* content-encoding. It therefore bounds the wire size, which
14
+ // the MaxSizeChecker below does not (that one bounds the decoded size);
15
+ // these are two distinct bounds that happen to share a constant. It is not
16
+ // a substitute for the checker: the header is absent under chunked transfer
17
+ // encoding, and a client may understate it.
18
+ const contentLength = req.headers['content-length'];
19
+ if (contentLength != null) {
20
+ const size = Number(contentLength);
21
+ if (!Number.isInteger(size) || size < 0) {
22
+ throw createHttpError(400, 'Invalid content-length');
23
+ }
24
+ if (size > maxSize) {
25
+ throw createHttpError(413, 'Payload too large');
26
+ }
27
+ }
5
28
  try {
6
- return decodeStream(req, req.headers['content-encoding']);
29
+ // @NOTE The checker is applied even when the body is not encoded: nothing
30
+ // else bounds the size of these requests.
31
+ return pipeline([
32
+ req,
33
+ ...createDecoders(req.headers['content-encoding']),
34
+ new MaxSizeChecker(maxSize, () => createHttpError(413, 'Payload too large')),
35
+ ], () => { });
7
36
  }
8
37
  catch (cause) {
9
38
  const message = cause instanceof TypeError ? cause.message : `Invalid content-encoding`;
@@ -16,13 +45,13 @@ export function decodeHttpRequest(req) {
16
45
  *
17
46
  * @throws {TypeError} If the content-type is not valid or supported.
18
47
  */
19
- export async function parseHttpRequest(req, allow) {
48
+ export async function parseHttpRequest(req, allow, maxSize = DEFAULT_MAX_BODY_SIZE) {
20
49
  const type = parseContentType(req.headers['content-type'] ?? 'application/octet-stream');
21
50
  const parser = parsers.find((parser) => allow.includes(parser.name) && parser.test(type.mime));
22
51
  if (!parser) {
23
52
  throw createHttpError(415, `Unsupported content-type: ${type.mime}`);
24
53
  }
25
- const stream = decodeHttpRequest(req);
54
+ const stream = decodeHttpRequest(req, maxSize);
26
55
  const buffer = await streamToNodeBuffer(stream);
27
56
  return parser.parse(buffer, type);
28
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../../src/lib/http/stream.ts"],"names":[],"mappings":"AAEA,OAAO,eAAe,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAClE,OAAO,EAIL,gBAAgB,EAChB,OAAO,GACR,MAAM,aAAa,CAAA;AAEpB,MAAM,UAAU,iBAAiB,CAAC,GAAoB;IACpD,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAA;IAC3D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GACX,KAAK,YAAY,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAA;QACzE,MAAM,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IAChD,CAAC;AACH,CAAC;AAED;;;;;GAKG;AAEH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAoB,EACpB,KAAQ;IAER,MAAM,IAAI,GAAG,gBAAgB,CAC3B,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,0BAA0B,CAC1D,CAAA;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CACzB,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAClE,CAAA;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,eAAe,CAAC,GAAG,EAAE,6BAA6B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACtE,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;IACrC,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAC/C,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAE/B,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAA0B;IAC1D,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QAC7B,mCAAmC;IACrC,CAAC;AACH,CAAC","sourcesContent":["import type { IncomingMessage } from 'node:http'\nimport type { Readable } from 'node:stream'\nimport createHttpError from 'http-errors'\nimport { decodeStream, streamToNodeBuffer } from '@atproto/common'\nimport {\n type KnownNames,\n type KnownParser,\n type ParserResult,\n parseContentType,\n parsers,\n} from './parser.js'\n\nexport function decodeHttpRequest(req: IncomingMessage): Readable {\n try {\n return decodeStream(req, req.headers['content-encoding'])\n } catch (cause) {\n const message =\n cause instanceof TypeError ? cause.message : `Invalid content-encoding`\n throw createHttpError(415, message, { cause })\n }\n}\n\n/**\n * Generic method that parses a stream of unknown nature (HTTP request/response,\n * socket, file, etc.), but of known mime type, into a parsed object.\n *\n * @throws {TypeError} If the content-type is not valid or supported.\n */\n\nexport async function parseHttpRequest<A extends readonly KnownNames[]>(\n req: IncomingMessage,\n allow: A,\n) {\n const type = parseContentType(\n req.headers['content-type'] ?? 'application/octet-stream',\n )\n\n const parser = parsers.find(\n (parser) => allow.includes(parser.name) && parser.test(type.mime),\n )\n\n if (!parser) {\n throw createHttpError(415, `Unsupported content-type: ${type.mime}`)\n }\n\n const stream = decodeHttpRequest(req)\n const buffer = await streamToNodeBuffer(stream)\n return parser.parse(buffer, type) as ParserResult<\n Extract<KnownParser, { name: A[number] }>\n >\n}\n\nexport async function flushStream(stream: AsyncIterable<any>): Promise<void> {\n for await (const _ of stream) {\n // Consume the stream to completion\n }\n}\n"]}
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../../src/lib/http/stream.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,QAAQ,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,eAAe,MAAM,aAAa,CAAA;AACzC,OAAO,EACL,cAAc,EACd,cAAc,EACd,kBAAkB,GACnB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAIL,gBAAgB,EAChB,OAAO,GACR,MAAM,aAAa,CAAA;AAEpB;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,GAAG,IAAI,CAAA,CAAC,UAAU;AAE1D,MAAM,UAAU,iBAAiB,CAC/B,GAAoB,EACpB,OAAe;IAEf,wEAAwE;IACxE,0EAA0E;IAC1E,wEAAwE;IACxE,2EAA2E;IAC3E,4EAA4E;IAC5E,4CAA4C;IAC5C,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACnD,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC,CAAA;QAClC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACxC,MAAM,eAAe,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAA;QACtD,CAAC;QACD,IAAI,IAAI,GAAG,OAAO,EAAE,CAAC;YACnB,MAAM,eAAe,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAA;QACjD,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,0EAA0E;QAC1E,0CAA0C;QAC1C,OAAO,QAAQ,CACb;YACE,GAAG;YACH,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;YAClD,IAAI,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,CAC/B,eAAe,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAC1C;SACF,EACD,GAAG,EAAE,GAAE,CAAC,CACC,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GACX,KAAK,YAAY,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAA;QACzE,MAAM,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IAChD,CAAC;AACH,CAAC;AAED;;;;;GAKG;AAEH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAoB,EACpB,KAAQ,EACR,OAAO,GAAW,qBAAqB;IAEvC,MAAM,IAAI,GAAG,gBAAgB,CAC3B,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,0BAA0B,CAC1D,CAAA;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CACzB,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAClE,CAAA;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,eAAe,CAAC,GAAG,EAAE,6BAA6B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACtE,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAC/C,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAE/B,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAA0B;IAC1D,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QAC7B,mCAAmC;IACrC,CAAC;AACH,CAAC","sourcesContent":["import type { IncomingMessage } from 'node:http'\nimport { type Duplex, type Readable, pipeline } from 'node:stream'\nimport createHttpError from 'http-errors'\nimport {\n MaxSizeChecker,\n createDecoders,\n streamToNodeBuffer,\n} from '@atproto/common'\nimport {\n type KnownNames,\n type KnownParser,\n type ParserResult,\n parseContentType,\n parsers,\n} from './parser.js'\n\n/**\n * Bounds the decoded request body, whichever content-encoding it arrived with.\n * The payloads these routes legitimately carry are single-digit kilobytes, so\n * this leaves ample headroom.\n */\nexport const DEFAULT_MAX_BODY_SIZE = 100 * 1024 // 100 KiB\n\nexport function decodeHttpRequest(\n req: IncomingMessage,\n maxSize: number,\n): Readable {\n // @NOTE Content-Length counts the octets actually transferred, i.e. the\n // body *after* content-encoding. It therefore bounds the wire size, which\n // the MaxSizeChecker below does not (that one bounds the decoded size);\n // these are two distinct bounds that happen to share a constant. It is not\n // a substitute for the checker: the header is absent under chunked transfer\n // encoding, and a client may understate it.\n const contentLength = req.headers['content-length']\n if (contentLength != null) {\n const size = Number(contentLength)\n if (!Number.isInteger(size) || size < 0) {\n throw createHttpError(400, 'Invalid content-length')\n }\n if (size > maxSize) {\n throw createHttpError(413, 'Payload too large')\n }\n }\n\n try {\n // @NOTE The checker is applied even when the body is not encoded: nothing\n // else bounds the size of these requests.\n return pipeline(\n [\n req,\n ...createDecoders(req.headers['content-encoding']),\n new MaxSizeChecker(maxSize, () =>\n createHttpError(413, 'Payload too large'),\n ),\n ],\n () => {},\n ) as Duplex\n } catch (cause) {\n const message =\n cause instanceof TypeError ? cause.message : `Invalid content-encoding`\n throw createHttpError(415, message, { cause })\n }\n}\n\n/**\n * Generic method that parses a stream of unknown nature (HTTP request/response,\n * socket, file, etc.), but of known mime type, into a parsed object.\n *\n * @throws {TypeError} If the content-type is not valid or supported.\n */\n\nexport async function parseHttpRequest<A extends readonly KnownNames[]>(\n req: IncomingMessage,\n allow: A,\n maxSize: number = DEFAULT_MAX_BODY_SIZE,\n) {\n const type = parseContentType(\n req.headers['content-type'] ?? 'application/octet-stream',\n )\n\n const parser = parsers.find(\n (parser) => allow.includes(parser.name) && parser.test(type.mime),\n )\n\n if (!parser) {\n throw createHttpError(415, `Unsupported content-type: ${type.mime}`)\n }\n\n const stream = decodeHttpRequest(req, maxSize)\n const buffer = await streamToNodeBuffer(stream)\n return parser.parse(buffer, type) as ParserResult<\n Extract<KnownParser, { name: A[number] }>\n >\n}\n\nexport async function flushStream(stream: AsyncIterable<any>): Promise<void> {\n for await (const _ of stream) {\n // Consume the stream to completion\n }\n}\n"]}
@@ -40,7 +40,7 @@ export { Keyset } from '@atproto/jwk';
40
40
  export type * from '@atproto/jwk-jose';
41
41
  export { JoseKey } from '@atproto/jwk-jose';
42
42
  export type * from '@atproto/lex-resolver';
43
- export { LexResolver } from '@atproto/lex-resolver';
43
+ export { LexResolver, LexResolverError } from '@atproto/lex-resolver';
44
44
  export { AccessTokenMode };
45
45
  export type { AccessTokenPayload, AuthorizationRedirectParameters, AuthorizationResultAuthorizePage as AuthorizationResultAuthorize, AuthorizationResultRedirect, Branding, BrandingConfig, CustomMetadata, Customization, CustomizationConfig, ErrorHandler, HcaptchaConfig, LoopbackMetadataGetter, MultiLangString, OAuthAuthorizationServerMetadata, VerifyTokenPayloadOptions, };
46
46
  export type ClientJwksCache = SimpleStore<string, Jwks>;
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-provider.d.ts","sourceRoot":"","sources":["../src/oauth-provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth-provider.d.ts","sourceRoot":"","sources":["../src/oauth-provider.ts"],"names":[],"mappings":"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"}
@@ -41,7 +41,7 @@ import { isPARResponseError } from './types/par-response-error.js';
41
41
  export { safeFetchWrap } from '@atproto-labs/fetch-node';
42
42
  export { Keyset } from '@atproto/jwk';
43
43
  export { JoseKey } from '@atproto/jwk-jose';
44
- export { LexResolver } from '@atproto/lex-resolver';
44
+ export { LexResolver, LexResolverError } from '@atproto/lex-resolver';
45
45
  export { AccessTokenMode };
46
46
  export class OAuthProvider extends OAuthVerifier {
47
47
  constructor({
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-provider.js","sourceRoot":"","sources":["../src/oauth-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto'\nimport type { Redis, RedisOptions } from 'ioredis'\nimport type { Jwks } from '@atproto/jwk'\nimport { LexResolver } from '@atproto/lex-resolver'\nimport type { Account } from '@atproto/oauth-provider-api'\nimport {\n CLIENT_ASSERTION_TYPE_JWT_BEARER,\n type OAuthAccessToken,\n type OAuthAuthorizationCodeGrantTokenRequest,\n type OAuthAuthorizationRequestJar,\n type OAuthAuthorizationRequestPar,\n type OAuthAuthorizationRequestParameters,\n type OAuthAuthorizationRequestQuery,\n type OAuthAuthorizationServerMetadata,\n type OAuthClientCredentials,\n type OAuthClientMetadata,\n type OAuthParResponse,\n type OAuthRefreshTokenGrantTokenRequest,\n type OAuthTokenIdentification,\n type OAuthTokenRequest,\n type OAuthTokenResponse,\n type OAuthTokenType,\n atprotoLoopbackClientMetadata,\n oauthAuthorizationRequestParametersSchema,\n} from '@atproto/oauth-types'\nimport { safeFetchWrap } from '@atproto-labs/fetch-node'\nimport type { SimpleStore } from '@atproto-labs/simple-store'\nimport { SimpleStoreMemory } from '@atproto-labs/simple-store-memory'\nimport { AccessTokenMode } from './access-token/access-token-mode.js'\nimport { AccountManager } from './account/account-manager.js'\nimport {\n type AccountStore,\n type AuthorizedClientData,\n type DeviceAccount,\n asAccountStore,\n} from './account/account-store.js'\nimport { resolveLoginHint } from './account/login-hint.js'\nimport type { ClientAuth, ClientAuthLegacy } from './client/client-auth.js'\nimport type { ClientId } from './client/client-id.js'\nimport {\n ClientManager,\n type LoopbackMetadataGetter,\n} from './client/client-manager.js'\nimport { type ClientStore, ifClientStore } from './client/client-store.js'\nimport type { Client } from './client/client.js'\nimport type { Branding, BrandingConfig } from './customization/branding.js'\nimport {\n type Customization,\n type CustomizationConfig,\n customizationSchema,\n} from './customization/customization.js'\nimport type { DeviceId } from './device/device-id.js'\nimport {\n type DeviceInfo,\n DeviceManager,\n type DeviceManagerOptions,\n} from './device/device-manager.js'\nimport { type DeviceStore, asDeviceStore } from './device/device-store.js'\nimport { AccountSelectionRequiredError } from './errors/account-selection-required-error.js'\nimport { AuthorizationError } from './errors/authorization-error.js'\nimport { ConsentRequiredError } from './errors/consent-required-error.js'\nimport { InvalidDpopKeyBindingError } from './errors/invalid-dpop-key-binding-error.js'\nimport { InvalidDpopProofError } from './errors/invalid-dpop-proof-error.js'\nimport { InvalidGrantError } from './errors/invalid-grant-error.js'\nimport { InvalidRequestError } from './errors/invalid-request-error.js'\nimport { LoginRequiredError } from './errors/login-required-error.js'\nimport { LexiconManager } from './lexicon/lexicon-manager.js'\nimport { type LexiconStore, asLexiconStore } from './lexicon/lexicon-store.js'\nimport type { HcaptchaConfig } from './lib/hcaptcha.js'\nimport type { RequestMetadata } from './lib/http/request.js'\nimport { dateToRelativeSeconds } from './lib/util/date.js'\nimport { formatError } from './lib/util/error.js'\nimport type { MultiLangString } from './lib/util/locale.js'\nimport {\n type CustomMetadata,\n buildMetadata,\n} from './metadata/build-metadata.js'\nimport { AUTHENTICATION_MAX_AGE, TOKEN_MAX_AGE } from './oauth-constants.js'\nimport type { OAuthHooks } from './oauth-hooks.js'\nimport {\n type DpopProof,\n OAuthVerifier,\n type OAuthVerifierOptions,\n type VerifyTokenPayloadOptions,\n} from './oauth-verifier.js'\nimport { type ReplayStore, ifReplayStore } from './replay/replay-store.js'\nimport { codeSchema } from './request/code.js'\nimport { RequestManager } from './request/request-manager.js'\nimport { type RequestStore, asRequestStore } from './request/request-store.js'\nimport { parseRequestUri } from './request/request-uri.js'\nimport type { AuthorizationRedirectParameters } from './result/authorization-redirect-parameters.js'\nimport type { AuthorizationResultAuthorizePage } from './result/authorization-result-authorize-page.js'\nimport type { AuthorizationResultRedirect } from './result/authorization-result-redirect.js'\nimport type { ErrorHandler } from './router/error-handler.js'\nimport type { AccessTokenPayload } from './signer/access-token-payload.js'\nimport { refreshTokenSchema } from './token/refresh-token.js'\nimport type { TokenData } from './token/token-data.js'\nimport { TokenManager } from './token/token-manager.js'\nimport { type TokenStore, asTokenStore } from './token/token-store.js'\nimport { isPARResponseError } from './types/par-response-error.js'\n\n// Re-export dependencies that are part of the public API of this package, so\n// that consumers don't have to install them separately.\nexport { safeFetchWrap } from '@atproto-labs/fetch-node'\nexport type * from '@atproto/jwk'\nexport { Keyset } from '@atproto/jwk'\nexport type * from '@atproto/jwk-jose'\nexport { JoseKey } from '@atproto/jwk-jose'\nexport type * from '@atproto/lex-resolver'\nexport { LexResolver } from '@atproto/lex-resolver'\n\nexport { AccessTokenMode }\nexport type {\n AccessTokenPayload,\n AuthorizationRedirectParameters,\n AuthorizationResultAuthorizePage as AuthorizationResultAuthorize,\n AuthorizationResultRedirect,\n Branding,\n BrandingConfig,\n CustomMetadata,\n Customization,\n CustomizationConfig,\n ErrorHandler,\n HcaptchaConfig,\n LoopbackMetadataGetter,\n MultiLangString,\n OAuthAuthorizationServerMetadata,\n VerifyTokenPayloadOptions,\n}\n\nexport type ClientJwksCache = SimpleStore<string, Jwks>\nexport type ClientMetadataCache = SimpleStore<string, OAuthClientMetadata>\nexport type OAuthStore = AccountStore &\n ClientStore &\n DeviceStore &\n LexiconStore &\n ReplayStore &\n RequestStore &\n TokenStore\n\ntype OAuthProviderConfig = {\n /**\n * Maximum age a device/account session can be before requiring\n * re-authentication.\n */\n authenticationMaxAge?: number\n\n /**\n * Maximum age access & id tokens can be before requiring a refresh.\n */\n tokenMaxAge?: number\n\n /**\n * If set to {@link AccessTokenMode.stateless}, the generated access tokens\n * will contain all the necessary information to validate the token without\n * needing to query the database. This is useful for cases where the Resource\n * Server is on a different host/server than the Authorization Server.\n *\n * When set to {@link AccessTokenMode.light}, the access tokens will contain\n * only the necessary information to validate the token, but the token id\n * will need to be queried from the database to retrieve the full token\n * information (scope, audience, etc.)\n *\n * @see {@link AccessTokenMode}\n * @default {AccessTokenMode.stateless}\n */\n accessTokenMode?: AccessTokenMode\n\n /**\n * Additional metadata to be included in the discovery document.\n */\n metadata?: CustomMetadata\n\n /**\n * A Lexicon resolver instance to use for fetching lexicon schemas.\n */\n lexResolver?: LexResolver\n\n /**\n * A custom fetch function that can be used to fetch the client metadata from\n * the internet. By default, the fetch function is a safeFetchWrap() function\n * that protects against SSRF attacks, large responses & known bad domains. If\n * you want to disable all protections, you can provide `globalThis.fetch` as\n * fetch function.\n */\n safeFetch?: typeof globalThis.fetch\n\n /**\n * A redis instance to use for replay protection. If not provided, replay\n * protection will use memory storage.\n */\n redis?: Redis | RedisOptions | string\n\n /**\n * This will be used as the default store for all the stores. If a store is\n * not provided, this store will be used instead. If the `store` does not\n * implement a specific store, a runtime error will be thrown. Make sure that\n * this store implements all the interfaces not provided in the other\n * `<name>Store` options.\n */\n store?: Partial<OAuthStore>\n\n accountStore?: AccountStore\n clientStore?: ClientStore\n deviceStore?: DeviceStore\n lexiconStore?: LexiconStore\n replayStore?: ReplayStore\n requestStore?: RequestStore\n tokenStore?: TokenStore\n\n /**\n * In order to speed up the client fetching process, you can provide a cache\n * to store HTTP responses.\n *\n * @note the cached entries should automatically expire after a certain time (typically 10 minutes)\n */\n clientJwksCache?: ClientJwksCache\n\n /**\n * In order to speed up the client fetching process, you can provide a cache\n * to store HTTP responses.\n *\n * @note the cached entries should automatically expire after a certain time (typically 10 minutes)\n */\n clientMetadataCache?: ClientMetadataCache\n\n /**\n * In order to enable loopback clients, you can provide a function that\n * returns the client metadata for a given loopback URL. This is useful for\n * development and testing purposes. This function is not called for internet\n * clients.\n *\n * @default is as specified by ATPROTO\n */\n loopbackMetadata?: null | false | LoopbackMetadataGetter\n}\n\nexport type OAuthProviderOptions = OAuthProviderConfig &\n OAuthVerifierOptions &\n OAuthHooks &\n DeviceManagerOptions &\n CustomizationConfig\n\nexport class OAuthProvider extends OAuthVerifier {\n protected readonly accessTokenMode: AccessTokenMode\n protected readonly hooks: OAuthHooks\n\n public readonly metadata: OAuthAuthorizationServerMetadata\n public readonly customization: Customization\n\n public readonly authenticationMaxAge: number\n\n public readonly accountManager: AccountManager\n public readonly deviceManager: DeviceManager\n public readonly clientManager: ClientManager\n public readonly lexiconManager: LexiconManager\n public readonly requestManager: RequestManager\n public readonly tokenManager: TokenManager\n\n public constructor({\n // OAuthProviderConfig\n authenticationMaxAge = AUTHENTICATION_MAX_AGE,\n tokenMaxAge = TOKEN_MAX_AGE,\n accessTokenMode = AccessTokenMode.stateless,\n\n metadata,\n loopbackMetadata = atprotoLoopbackClientMetadata,\n\n // Services\n safeFetch = safeFetchWrap(),\n lexResolver = new LexResolver({ fetch: safeFetch }),\n\n // compound store implementation\n store,\n\n // Required stores\n accountStore = asAccountStore(store),\n deviceStore = asDeviceStore(store),\n lexiconStore = asLexiconStore(store),\n tokenStore = asTokenStore(store),\n requestStore = asRequestStore(store),\n\n // Optional stores\n clientStore = ifClientStore(store),\n replayStore = ifReplayStore(store),\n\n clientJwksCache = new SimpleStoreMemory({\n maxSize: 50_000_000,\n ttl: 600e3,\n }),\n clientMetadataCache = new SimpleStoreMemory({\n maxSize: 50_000_000,\n ttl: 600e3,\n }),\n\n // OAuthHooks &\n // OAuthVerifierOptions &\n // DeviceManagerOptions &\n // Customization\n ...rest\n }: OAuthProviderOptions) {\n super({ replayStore, ...rest })\n\n // @NOTE: hooks don't really need a type parser, as all zod can actually\n // check at runtime is the fact that the values are functions. The only way\n // we would benefit from zod here would be to wrap the functions with a\n // validator for the provided function's return types, which we don't\n // really need if types are respected.\n this.hooks = rest\n\n this.accessTokenMode = accessTokenMode\n this.authenticationMaxAge = authenticationMaxAge\n this.metadata = buildMetadata(this.issuer, this.keyset, metadata)\n this.customization = customizationSchema.parse(rest)\n\n this.deviceManager = new DeviceManager(deviceStore, {\n ...rest,\n cookie: {\n ...rest.cookie,\n // \"secure\" defaults to \"true\" in DeviceManager. For the oauth routes to\n // work from localhost on Safari, we need to explicitly set secure to\n // false for localhost usage. This is not really an issue with Chrome\n // and Firefox, but Safari enforces it strictly.\n secure: !this.issuer.startsWith('http:'),\n },\n })\n this.accountManager = new AccountManager(\n this.issuer,\n accountStore,\n this.hooks,\n this.customization,\n )\n this.clientManager = new ClientManager(\n this.metadata,\n this.keyset,\n this.hooks,\n clientStore || null,\n loopbackMetadata || null,\n safeFetch,\n clientJwksCache,\n clientMetadataCache,\n )\n this.lexiconManager = new LexiconManager(lexiconStore, lexResolver)\n this.requestManager = new RequestManager(\n requestStore,\n this.lexiconManager,\n this.signer,\n this.metadata,\n this.hooks,\n )\n this.tokenManager = new TokenManager(\n tokenStore,\n this.lexiconManager,\n this.signer,\n this.hooks,\n this.accessTokenMode,\n tokenMaxAge,\n )\n }\n\n get jwks() {\n return this.keyset.publicJwks\n }\n\n /**\n * @returns true if the user's consent is required for the requested scopes\n */\n public checkConsentRequired(\n parameters: OAuthAuthorizationRequestParameters,\n clientData?: AuthorizedClientData,\n ) {\n // Client was never authorized before\n if (!clientData) return true\n\n // Client explicitly asked for consent\n if (parameters.prompt === 'consent') return true\n\n // No scope requested, and client is known by user, no consent required\n const requestedScopes = parameters.scope?.split(' ')\n if (requestedScopes == null) return false\n\n // Ensure that all requested scopes were previously authorized by the user\n const { authorizedScopes } = clientData\n return !requestedScopes.every((scope) => authorizedScopes.includes(scope))\n }\n\n public checkLoginRequired(deviceAccount: DeviceAccount) {\n const authAge = Date.now() - deviceAccount.updatedAt.getTime()\n return authAge > this.authenticationMaxAge\n }\n\n protected async authenticateClient(\n clientCredentials: OAuthClientCredentials,\n dpopProof: null | DpopProof,\n options?: {\n allowMissingDpopProof?: boolean\n },\n ): Promise<{\n client: Client\n clientAuth: ClientAuth\n }> {\n const client = await this.clientManager.getClient(\n clientCredentials.client_id,\n )\n\n if (\n client.metadata.dpop_bound_access_tokens &&\n !dpopProof &&\n !options?.allowMissingDpopProof\n ) {\n throw new InvalidDpopProofError('DPoP proof required')\n }\n\n if (dpopProof && !client.metadata.dpop_bound_access_tokens) {\n throw new InvalidDpopProofError('DPoP proof not allowed for this client')\n }\n\n const clientAuth = await client.authenticate(clientCredentials, {\n authorizationServerIdentifier: this.issuer,\n })\n\n if (clientAuth.method === 'private_key_jwt') {\n // Clients MUST NOT use their client assertion key to sign DPoP proofs\n if (dpopProof && clientAuth.jkt === dpopProof.jkt) {\n throw new InvalidRequestError(\n 'The DPoP proof must be signed with a different key than the client assertion',\n )\n }\n\n // https://www.rfc-editor.org/rfc/rfc7523.html#section-3\n // > 7. [...] The authorization server MAY ensure that JWTs are not\n // > replayed by maintaining the set of used \"jti\" values for the\n // > length of time for which the JWT would be considered valid based\n // > on the applicable \"exp\" instant.\n\n const unique = await this.replayManager.uniqueAuth(\n clientAuth.jti,\n client.id,\n clientAuth.exp,\n )\n if (!unique) {\n throw new InvalidGrantError(`${clientAuth.method} jti reused`)\n }\n }\n\n return { client, clientAuth }\n }\n\n async decodeJAR(\n client: Client,\n input: OAuthAuthorizationRequestJar,\n ): Promise<OAuthAuthorizationRequestParameters> {\n const { payload } = await client.decodeRequestObject(\n input.request,\n this.issuer,\n )\n\n const { jti } = payload\n if (!jti) {\n throw new InvalidRequestError(\n 'Request object payload must contain a \"jti\" claim',\n )\n }\n if (!(await this.replayManager.uniqueJar(jti, client.id))) {\n throw new InvalidRequestError('Request object was replayed')\n }\n\n const parameters = await oauthAuthorizationRequestParametersSchema\n .parseAsync(payload)\n .catch((err) => {\n const msg = formatError(err, 'Invalid parameters in JAR')\n throw new InvalidRequestError(msg, err)\n })\n\n return parameters\n }\n\n /**\n * @see {@link https://datatracker.ietf.org/doc/html/rfc9126}\n */\n public async pushedAuthorizationRequest(\n credentials: OAuthClientCredentials,\n authorizationRequest: OAuthAuthorizationRequestPar,\n dpopProof: null | DpopProof,\n ): Promise<OAuthParResponse> {\n try {\n const { client, clientAuth } = await this.authenticateClient(\n credentials,\n dpopProof,\n // Allow missing DPoP header for PAR requests as rfc9449 allows it\n // (though the dpop_jkt parameter must be present in that case, see\n // check bellow).\n { allowMissingDpopProof: true },\n )\n\n const parameters =\n 'request' in authorizationRequest // Handle JAR\n ? await this.decodeJAR(client, authorizationRequest)\n : authorizationRequest\n\n if (!parameters.dpop_jkt) {\n if (client.metadata.dpop_bound_access_tokens) {\n if (dpopProof) parameters.dpop_jkt = dpopProof.jkt\n else {\n // @NOTE When both PAR and DPoP are used, either the DPoP header, or\n // the dpop_jkt parameter must be present. We do not enforce this\n // for legacy reasons.\n // https://datatracker.ietf.org/doc/html/rfc9449#section-10.1\n }\n }\n } else {\n if (!client.metadata.dpop_bound_access_tokens) {\n throw new InvalidRequestError(\n 'DPoP bound access tokens are not enabled for this client',\n )\n }\n\n // Proof is optional if the dpop_jkt is provided, but if it is provided,\n // it must match the DPoP proof JKT.\n if (dpopProof && dpopProof.jkt !== parameters.dpop_jkt) {\n throw new InvalidDpopKeyBindingError()\n }\n }\n\n const { requestUri, expiresAt } =\n await this.requestManager.createAuthorizationRequest(\n client,\n clientAuth,\n parameters,\n null,\n )\n\n return {\n request_uri: requestUri,\n expires_in: dateToRelativeSeconds(expiresAt),\n }\n } catch (err) {\n // https://datatracker.ietf.org/doc/html/rfc9126#section-2.3-1\n // > Since initial processing of the pushed authorization request does not\n // > involve resource owner interaction, error codes related to user\n // > interaction, such as \"access_denied\", are never returned.\n if (err instanceof AuthorizationError && !isPARResponseError(err.error)) {\n throw new InvalidRequestError(err.error_description, err)\n }\n throw err\n }\n }\n\n private async processAuthorizationRequest(\n client: Client,\n deviceId: DeviceId,\n query: OAuthAuthorizationRequestQuery,\n ) {\n // PAR\n if ('request_uri' in query) {\n const requestUri = parseRequestUri(query.request_uri, {\n path: ['query', 'request_uri'],\n })\n return this.requestManager.get(requestUri, deviceId, client.id)\n }\n\n // JAR\n if ('request' in query) {\n // @NOTE Since JAR are signed with the client's private key, a JAR *could*\n // technically be used to authenticate the client when requests are\n // created without PAR (i.e. created on the fly by the authorize\n // endpoint). This implementation actually used to support this\n // (un-spec'd) behavior. That support was removed:\n // - Because it was not actually used\n // - Because it was not part of any standard\n // - Because it makes extending the client authentication mechanism more\n // complex since any extension would not only need to affect the\n // \"private_key_jwt\" auth method but also the JAR \"request\" object.\n const parameters = await this.decodeJAR(client, query)\n\n return this.requestManager.createAuthorizationRequest(\n client,\n null,\n parameters,\n deviceId,\n )\n }\n\n // \"Regular\" authorization request (created on the fly by directing the user\n // to the authorization endpoint with all the parameters in the url).\n return this.requestManager.createAuthorizationRequest(\n client,\n null,\n query,\n deviceId,\n )\n }\n\n /**\n * @see {@link https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-4.1.1}\n */\n public async authorize(\n query: OAuthAuthorizationRequestQuery,\n { deviceId, deviceMetadata }: DeviceInfo,\n ): Promise<AuthorizationResultRedirect | AuthorizationResultAuthorizePage> {\n const { issuer } = this\n\n // If there is a chance to redirect the user to the client, let's do\n // it by wrapping the error in an AuthorizationError.\n const throwAuthorizationError =\n 'redirect_uri' in query\n ? (err: unknown): never => {\n // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-4.1.2.1\n throw AuthorizationError.from(query, err)\n }\n : null\n\n const client = await this.clientManager\n .getClient(query.client_id)\n .catch(throwAuthorizationError)\n\n const { parameters, requestUri } = await this.processAuthorizationRequest(\n client,\n deviceId,\n query,\n ).catch(throwAuthorizationError)\n\n try {\n const sessions = (\n await this.accountManager.listDeviceAccounts(deviceId)\n ).map((deviceAccount) => ({\n account: deviceAccount.account,\n\n // @TODO Return the session expiration date instead of a boolean to\n // avoid having to rely on a leeway when \"accepting\" the request.\n loginRequired:\n parameters.prompt === 'login' ||\n this.checkLoginRequired(deviceAccount),\n consentRequired: this.checkConsentRequired(\n parameters,\n deviceAccount.authorizedClients.get(client.id),\n ),\n }))\n\n // https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest\n\n // prompt=select_account\n //\n // > The Authorization Server SHOULD prompt the End-User to select a user\n // > account. This enables an End-User who has multiple accounts at the\n // > Authorization Server to select amongst the multiple accounts that\n // > they might have current sessions for. If it cannot obtain an account\n // > selection choice made by the End-User, it MUST return an error,\n // > typically account_selection_required.\n if (parameters.prompt === 'select_account' && !sessions.length) {\n throw new AccountSelectionRequiredError(parameters)\n }\n\n const ssoSessions = sessions\n .filter(hasActiveAccount)\n .filter(matchesHint, parameters)\n\n // prompt=none\n //\n // > The Authorization Server MUST NOT display any authentication or\n // > consent user interface pages. An error is returned if an End-User is\n // > not already authenticated or the Client does not have pre-configured\n // > consent for the requested Claims or does not fulfill other conditions\n // > for processing the request. The error code will typically be\n // > login_required, interaction_required, or another code defined in\n // > Section 3.1.2.6. This can be used as a method to check for existing\n // > authentication and/or consent.\n if (parameters.prompt === 'none') {\n if (ssoSessions.length > 1) {\n throw new AccountSelectionRequiredError(parameters)\n }\n if (ssoSessions.length < 1) {\n throw new LoginRequiredError(parameters)\n }\n\n const ssoSession = ssoSessions[0]!\n if (ssoSession.loginRequired) {\n throw new LoginRequiredError(parameters)\n }\n if (ssoSession.consentRequired) {\n throw new ConsentRequiredError(parameters)\n }\n\n const code = await this.requestManager.setAuthorized(\n requestUri,\n client,\n ssoSession.account,\n deviceId,\n deviceMetadata,\n )\n\n return { issuer, parameters, redirect: { code } }\n }\n\n // Automatic SSO when a hint was provided that matches a single session\n if (parameters.prompt == null && parameters.login_hint != null) {\n if (ssoSessions.length === 1) {\n const ssoSession = ssoSessions[0]!\n if (!ssoSession.loginRequired && !ssoSession.consentRequired) {\n const code = await this.requestManager.setAuthorized(\n requestUri,\n client,\n ssoSession.account,\n deviceId,\n deviceMetadata,\n )\n\n return { issuer, parameters, redirect: { code } }\n }\n }\n }\n\n return {\n issuer,\n client,\n parameters,\n requestUri,\n sessions: sessions\n // Strip un-necessary information (like consentRequired)\n .map(({ account, loginRequired }) => ({ account, loginRequired })),\n selectedDid:\n parameters.prompt == null ||\n parameters.prompt === 'login' ||\n parameters.prompt === 'consent'\n ? sessions.find(matchesHint, parameters)?.account.did\n : undefined,\n loginHint: await resolveLoginHint(\n parameters.login_hint,\n this.accountManager,\n ),\n permissionSets: await this.lexiconManager\n .getPermissionSetsFromScope(parameters.scope)\n .catch((cause) => {\n throw new AuthorizationError(\n parameters,\n 'Unable to retrieve permission sets',\n 'invalid_scope',\n cause,\n )\n }),\n }\n } catch (err) {\n try {\n await this.requestManager.delete(requestUri)\n } catch {\n // There are two error here. Better keep the outer one.\n //\n // @TODO Maybe move this entire code to the /authorize endpoint\n // (allowing to log this error)\n }\n\n throw AuthorizationError.from(parameters, err)\n }\n }\n\n public async token(\n clientCredentials: OAuthClientCredentials,\n clientMetadata: RequestMetadata,\n request: OAuthTokenRequest,\n dpopProof: null | DpopProof,\n ): Promise<OAuthTokenResponse> {\n const { client, clientAuth } = await this.authenticateClient(\n clientCredentials,\n dpopProof,\n )\n\n if (!this.metadata.grant_types_supported?.includes(request.grant_type)) {\n throw new InvalidGrantError(\n `Grant type \"${request.grant_type}\" is not supported by the server`,\n )\n }\n\n if (!client.metadata.grant_types.includes(request.grant_type)) {\n throw new InvalidGrantError(\n `\"${request.grant_type}\" grant type is not allowed for this client`,\n )\n }\n\n if (request.grant_type === 'authorization_code') {\n return this.authorizationCodeGrant(\n client,\n clientAuth,\n clientMetadata,\n request,\n dpopProof,\n )\n }\n\n if (request.grant_type === 'refresh_token') {\n return this.refreshTokenGrant(\n client,\n clientAuth,\n clientMetadata,\n request,\n dpopProof,\n )\n }\n\n throw new InvalidGrantError(\n `Grant type \"${request.grant_type}\" not supported`,\n )\n }\n\n protected async compareClientAuth(\n client: Client,\n clientAuth: ClientAuth,\n dpopProof: null | DpopProof,\n initial: {\n parameters: OAuthAuthorizationRequestParameters\n clientId: ClientId\n clientAuth: null | ClientAuth | ClientAuthLegacy\n },\n ): Promise<void> {\n // Fool proofing, ensure that the client is authenticating using the right method\n if (clientAuth.method !== client.metadata.token_endpoint_auth_method) {\n throw new InvalidGrantError(\n `Client authentication method mismatch (expected ${client.metadata.token_endpoint_auth_method}, got ${clientAuth.method})`,\n )\n }\n\n if (initial.clientId !== client.id) {\n throw new InvalidGrantError(`Token was not issued to this client`)\n }\n\n const { parameters } = initial\n if (parameters.dpop_jkt) {\n if (!dpopProof) {\n throw new InvalidGrantError(`DPoP proof is required for this request`)\n } else if (parameters.dpop_jkt !== dpopProof.jkt) {\n throw new InvalidGrantError(\n `DPoP proof does not match the expected JKT`,\n )\n }\n }\n\n if (!initial.clientAuth) {\n // If the client did not use PAR, it was not authenticated when the request\n // was initially created (see authorize() method in OAuthProvider). Since\n // PAR is not mandatory, and since the token exchange currently taking place\n // *is* authenticated (`clientAuth`), we allow \"upgrading\" the\n // authentication method (the token created will be bound to the current\n // clientAuth).\n return\n }\n\n switch (initial.clientAuth.method) {\n case CLIENT_ASSERTION_TYPE_JWT_BEARER: // LEGACY\n case 'private_key_jwt':\n if (clientAuth.method !== 'private_key_jwt') {\n throw new InvalidGrantError(\n `Client authentication method mismatch (expected ${initial.clientAuth.method})`,\n )\n }\n if (\n clientAuth.kid !== initial.clientAuth.kid ||\n clientAuth.alg !== initial.clientAuth.alg ||\n clientAuth.jkt !== initial.clientAuth.jkt\n ) {\n throw new InvalidGrantError(\n `The session was initiated with a different key than the client assertion currently used`,\n )\n }\n break\n case 'none':\n // @NOTE We allow the client to \"upgrade\" to a confidential client if\n // the session was initially created without client authentication.\n break\n default:\n throw new InvalidGrantError(\n // @ts-expect-error (future proof, backwards compatibility)\n `Invalid method \"${initial.clientAuth.method}\"`,\n )\n }\n }\n\n protected async authorizationCodeGrant(\n client: Client,\n clientAuth: ClientAuth,\n clientMetadata: RequestMetadata,\n input: OAuthAuthorizationCodeGrantTokenRequest,\n dpopProof: null | DpopProof,\n ): Promise<OAuthTokenResponse> {\n const code = await codeSchema\n .parseAsync(input.code, { path: ['code'] })\n .catch((err) => {\n const msg = formatError(err, 'Invalid code')\n throw new InvalidGrantError(msg, err)\n })\n\n const data = await this.requestManager\n .consumeCode(code)\n .catch(async (err) => {\n // Code not found in request manager: check for replays\n const tokenInfo = await this.tokenManager.findByCode(code)\n if (tokenInfo) {\n // try/finally to ensure that both code path get executed (sequentially)\n try {\n // \"code\" was replayed, delete existing session\n await this.tokenManager.deleteToken(tokenInfo.id)\n } finally {\n // As an additional security measure, we also sign the device out,\n // so that the device cannot be used to access the account anymore\n // without a new authentication.\n const { deviceId, did } = tokenInfo.data\n if (deviceId) {\n await this.accountManager.removeDeviceAccount(deviceId, did)\n }\n }\n }\n\n throw InvalidGrantError.from(err, `Invalid code`)\n })\n\n // @NOTE at this point, the request data was removed from the store and only\n // exists in memory here (in the \"data\" variable). Because of this, any\n // error thrown after this point will permanently cause the request data to\n // be lost.\n\n await this.compareClientAuth(client, clientAuth, dpopProof, data)\n\n // If the DPoP proof was not provided earlier (PAR / authorize), let's add\n // it now.\n const parameters =\n dpopProof &&\n client.metadata.dpop_bound_access_tokens &&\n !data.parameters.dpop_jkt\n ? { ...data.parameters, dpop_jkt: dpopProof.jkt }\n : data.parameters\n\n await this.validateCodeGrant(parameters, input)\n\n const { account } = await this.accountManager.getAccount(data.did)\n\n return this.tokenManager.createToken(\n client,\n clientAuth,\n clientMetadata,\n account,\n data.deviceId,\n parameters,\n code,\n )\n }\n\n protected async validateCodeGrant(\n parameters: OAuthAuthorizationRequestParameters,\n input: OAuthAuthorizationCodeGrantTokenRequest,\n ): Promise<void> {\n if (parameters.redirect_uri !== input.redirect_uri) {\n throw new InvalidGrantError(\n 'The redirect_uri parameter must match the one used in the authorization request',\n )\n }\n\n if (parameters.code_challenge) {\n if (!input.code_verifier) {\n throw new InvalidGrantError('code_verifier is required')\n }\n if (input.code_verifier.length < 43) {\n throw new InvalidGrantError('code_verifier too short')\n }\n switch (parameters.code_challenge_method) {\n case undefined: // default is \"plain\"\n case 'plain':\n if (parameters.code_challenge !== input.code_verifier) {\n throw new InvalidGrantError('Invalid code_verifier')\n }\n break\n\n case 'S256': {\n const inputChallenge = Buffer.from(\n parameters.code_challenge,\n 'base64',\n )\n const computedChallenge = createHash('sha256')\n .update(input.code_verifier)\n .digest()\n if (inputChallenge.compare(computedChallenge) !== 0) {\n throw new InvalidGrantError('Invalid code_verifier')\n }\n break\n }\n\n default:\n // Should never happen (because request validation should catch this)\n throw new Error(`Unsupported code_challenge_method`)\n }\n const unique = await this.replayManager.uniqueCodeChallenge(\n parameters.code_challenge,\n )\n if (!unique) {\n throw new InvalidGrantError('Code challenge already used')\n }\n } else if (input.code_verifier !== undefined) {\n throw new InvalidRequestError(\"code_challenge parameter wasn't provided\")\n }\n }\n\n protected async refreshTokenGrant(\n client: Client,\n clientAuth: ClientAuth,\n clientMetadata: RequestMetadata,\n input: OAuthRefreshTokenGrantTokenRequest,\n dpopProof: null | DpopProof,\n ): Promise<OAuthTokenResponse> {\n const refreshToken = await refreshTokenSchema\n .parseAsync(input.refresh_token, { path: ['refresh_token'] })\n .catch((err) => {\n const msg = formatError(err, 'Invalid refresh token')\n throw new InvalidGrantError(msg, err)\n })\n\n const tokenInfo = await this.tokenManager.consumeRefreshToken(refreshToken)\n\n try {\n const { data } = tokenInfo\n const now = new Date()\n\n await this.compareClientAuth(client, clientAuth, dpopProof, data)\n await this.validateRefreshGrant(client, data, now)\n\n return await this.tokenManager.rotateToken(\n client,\n clientAuth,\n clientMetadata,\n tokenInfo,\n now,\n )\n } catch (err) {\n await this.tokenManager.deleteToken(tokenInfo.id)\n\n throw err\n }\n }\n\n protected async validateRefreshGrant(\n client: Client,\n data: TokenData,\n now = new Date(),\n ): Promise<void> {\n if (!client.metadata.grant_types.includes('refresh_token')) {\n throw new InvalidGrantError(`Refresh token grant not allowed`)\n }\n\n const sessionAge = now.getTime() - data.createdAt.getTime()\n\n if (sessionAge > client.sessionLifetime) {\n throw new InvalidGrantError(`Session expired`)\n }\n\n const refreshAge = now.getTime() - data.updatedAt.getTime()\n if (refreshAge > client.refreshLifetime) {\n throw new InvalidGrantError(`Refresh token expired`)\n }\n }\n\n /**\n * @see {@link https://datatracker.ietf.org/doc/html/rfc7009#section-2.1 rfc7009}\n */\n public async revoke(\n clientCredentials: OAuthClientCredentials,\n { token }: OAuthTokenIdentification,\n dpopProof: null | DpopProof,\n ) {\n // > The authorization server first validates the client credentials (in\n // > case of a confidential client)\n const { client, clientAuth } = await this.authenticateClient(\n clientCredentials,\n dpopProof,\n )\n\n const tokenInfo = await this.tokenManager.findToken(token)\n if (tokenInfo) {\n // > [...] and then verifies whether the token was issued to the client\n // > making the revocation request.\n const { data } = tokenInfo\n await this.compareClientAuth(client, clientAuth, dpopProof, data)\n\n // > In the next step, the authorization server invalidates the token. The\n // > invalidation takes place immediately, and the token cannot be used\n // > again after the revocation.\n await this.tokenManager.deleteToken(tokenInfo.id)\n }\n }\n\n protected override async decodeToken(\n tokenType: OAuthTokenType,\n token: OAuthAccessToken,\n dpopProof: null | DpopProof,\n ): Promise<AccessTokenPayload> {\n const tokenPayload = await super.decodeToken(tokenType, token, dpopProof)\n\n if (this.accessTokenMode !== AccessTokenMode.stateless) {\n // @NOTE in non stateless mode, some claims can be omitted (most notably\n // \"scope\"). We load the token claims here (allowing to ensure that the\n // token is still valid, and to retrieve a (potentially updated) set of\n // claims).\n\n const tokenClaims = await this.tokenManager.loadTokenClaims(\n tokenType,\n tokenPayload,\n )\n\n Object.assign(tokenPayload, tokenClaims)\n }\n\n return tokenPayload\n }\n}\n\nfunction matchesHint(\n this: OAuthAuthorizationRequestParameters,\n { account }: { account: Account },\n): boolean {\n const hint = this.login_hint\n if (!hint) return false\n\n return account.did === hint || account.handle === hint\n}\n\nfunction hasActiveAccount({ account }: { account: Account }): boolean {\n return !account.deactivated\n}\n"]}
1
+ {"version":3,"file":"oauth-provider.js","sourceRoot":"","sources":["../src/oauth-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto'\nimport type { Redis, RedisOptions } from 'ioredis'\nimport type { Jwks } from '@atproto/jwk'\nimport { LexResolver } from '@atproto/lex-resolver'\nimport type { Account } from '@atproto/oauth-provider-api'\nimport {\n CLIENT_ASSERTION_TYPE_JWT_BEARER,\n type OAuthAccessToken,\n type OAuthAuthorizationCodeGrantTokenRequest,\n type OAuthAuthorizationRequestJar,\n type OAuthAuthorizationRequestPar,\n type OAuthAuthorizationRequestParameters,\n type OAuthAuthorizationRequestQuery,\n type OAuthAuthorizationServerMetadata,\n type OAuthClientCredentials,\n type OAuthClientMetadata,\n type OAuthParResponse,\n type OAuthRefreshTokenGrantTokenRequest,\n type OAuthTokenIdentification,\n type OAuthTokenRequest,\n type OAuthTokenResponse,\n type OAuthTokenType,\n atprotoLoopbackClientMetadata,\n oauthAuthorizationRequestParametersSchema,\n} from '@atproto/oauth-types'\nimport { safeFetchWrap } from '@atproto-labs/fetch-node'\nimport type { SimpleStore } from '@atproto-labs/simple-store'\nimport { SimpleStoreMemory } from '@atproto-labs/simple-store-memory'\nimport { AccessTokenMode } from './access-token/access-token-mode.js'\nimport { AccountManager } from './account/account-manager.js'\nimport {\n type AccountStore,\n type AuthorizedClientData,\n type DeviceAccount,\n asAccountStore,\n} from './account/account-store.js'\nimport { resolveLoginHint } from './account/login-hint.js'\nimport type { ClientAuth, ClientAuthLegacy } from './client/client-auth.js'\nimport type { ClientId } from './client/client-id.js'\nimport {\n ClientManager,\n type LoopbackMetadataGetter,\n} from './client/client-manager.js'\nimport { type ClientStore, ifClientStore } from './client/client-store.js'\nimport type { Client } from './client/client.js'\nimport type { Branding, BrandingConfig } from './customization/branding.js'\nimport {\n type Customization,\n type CustomizationConfig,\n customizationSchema,\n} from './customization/customization.js'\nimport type { DeviceId } from './device/device-id.js'\nimport {\n type DeviceInfo,\n DeviceManager,\n type DeviceManagerOptions,\n} from './device/device-manager.js'\nimport { type DeviceStore, asDeviceStore } from './device/device-store.js'\nimport { AccountSelectionRequiredError } from './errors/account-selection-required-error.js'\nimport { AuthorizationError } from './errors/authorization-error.js'\nimport { ConsentRequiredError } from './errors/consent-required-error.js'\nimport { InvalidDpopKeyBindingError } from './errors/invalid-dpop-key-binding-error.js'\nimport { InvalidDpopProofError } from './errors/invalid-dpop-proof-error.js'\nimport { InvalidGrantError } from './errors/invalid-grant-error.js'\nimport { InvalidRequestError } from './errors/invalid-request-error.js'\nimport { LoginRequiredError } from './errors/login-required-error.js'\nimport { LexiconManager } from './lexicon/lexicon-manager.js'\nimport { type LexiconStore, asLexiconStore } from './lexicon/lexicon-store.js'\nimport type { HcaptchaConfig } from './lib/hcaptcha.js'\nimport type { RequestMetadata } from './lib/http/request.js'\nimport { dateToRelativeSeconds } from './lib/util/date.js'\nimport { formatError } from './lib/util/error.js'\nimport type { MultiLangString } from './lib/util/locale.js'\nimport {\n type CustomMetadata,\n buildMetadata,\n} from './metadata/build-metadata.js'\nimport { AUTHENTICATION_MAX_AGE, TOKEN_MAX_AGE } from './oauth-constants.js'\nimport type { OAuthHooks } from './oauth-hooks.js'\nimport {\n type DpopProof,\n OAuthVerifier,\n type OAuthVerifierOptions,\n type VerifyTokenPayloadOptions,\n} from './oauth-verifier.js'\nimport { type ReplayStore, ifReplayStore } from './replay/replay-store.js'\nimport { codeSchema } from './request/code.js'\nimport { RequestManager } from './request/request-manager.js'\nimport { type RequestStore, asRequestStore } from './request/request-store.js'\nimport { parseRequestUri } from './request/request-uri.js'\nimport type { AuthorizationRedirectParameters } from './result/authorization-redirect-parameters.js'\nimport type { AuthorizationResultAuthorizePage } from './result/authorization-result-authorize-page.js'\nimport type { AuthorizationResultRedirect } from './result/authorization-result-redirect.js'\nimport type { ErrorHandler } from './router/error-handler.js'\nimport type { AccessTokenPayload } from './signer/access-token-payload.js'\nimport { refreshTokenSchema } from './token/refresh-token.js'\nimport type { TokenData } from './token/token-data.js'\nimport { TokenManager } from './token/token-manager.js'\nimport { type TokenStore, asTokenStore } from './token/token-store.js'\nimport { isPARResponseError } from './types/par-response-error.js'\n\n// Re-export dependencies that are part of the public API of this package, so\n// that consumers don't have to install them separately.\nexport { safeFetchWrap } from '@atproto-labs/fetch-node'\nexport type * from '@atproto/jwk'\nexport { Keyset } from '@atproto/jwk'\nexport type * from '@atproto/jwk-jose'\nexport { JoseKey } from '@atproto/jwk-jose'\nexport type * from '@atproto/lex-resolver'\nexport { LexResolver, LexResolverError } from '@atproto/lex-resolver'\n\nexport { AccessTokenMode }\nexport type {\n AccessTokenPayload,\n AuthorizationRedirectParameters,\n AuthorizationResultAuthorizePage as AuthorizationResultAuthorize,\n AuthorizationResultRedirect,\n Branding,\n BrandingConfig,\n CustomMetadata,\n Customization,\n CustomizationConfig,\n ErrorHandler,\n HcaptchaConfig,\n LoopbackMetadataGetter,\n MultiLangString,\n OAuthAuthorizationServerMetadata,\n VerifyTokenPayloadOptions,\n}\n\nexport type ClientJwksCache = SimpleStore<string, Jwks>\nexport type ClientMetadataCache = SimpleStore<string, OAuthClientMetadata>\nexport type OAuthStore = AccountStore &\n ClientStore &\n DeviceStore &\n LexiconStore &\n ReplayStore &\n RequestStore &\n TokenStore\n\ntype OAuthProviderConfig = {\n /**\n * Maximum age a device/account session can be before requiring\n * re-authentication.\n */\n authenticationMaxAge?: number\n\n /**\n * Maximum age access & id tokens can be before requiring a refresh.\n */\n tokenMaxAge?: number\n\n /**\n * If set to {@link AccessTokenMode.stateless}, the generated access tokens\n * will contain all the necessary information to validate the token without\n * needing to query the database. This is useful for cases where the Resource\n * Server is on a different host/server than the Authorization Server.\n *\n * When set to {@link AccessTokenMode.light}, the access tokens will contain\n * only the necessary information to validate the token, but the token id\n * will need to be queried from the database to retrieve the full token\n * information (scope, audience, etc.)\n *\n * @see {@link AccessTokenMode}\n * @default {AccessTokenMode.stateless}\n */\n accessTokenMode?: AccessTokenMode\n\n /**\n * Additional metadata to be included in the discovery document.\n */\n metadata?: CustomMetadata\n\n /**\n * A Lexicon resolver instance to use for fetching lexicon schemas.\n */\n lexResolver?: LexResolver\n\n /**\n * A custom fetch function that can be used to fetch the client metadata from\n * the internet. By default, the fetch function is a safeFetchWrap() function\n * that protects against SSRF attacks, large responses & known bad domains. If\n * you want to disable all protections, you can provide `globalThis.fetch` as\n * fetch function.\n */\n safeFetch?: typeof globalThis.fetch\n\n /**\n * A redis instance to use for replay protection. If not provided, replay\n * protection will use memory storage.\n */\n redis?: Redis | RedisOptions | string\n\n /**\n * This will be used as the default store for all the stores. If a store is\n * not provided, this store will be used instead. If the `store` does not\n * implement a specific store, a runtime error will be thrown. Make sure that\n * this store implements all the interfaces not provided in the other\n * `<name>Store` options.\n */\n store?: Partial<OAuthStore>\n\n accountStore?: AccountStore\n clientStore?: ClientStore\n deviceStore?: DeviceStore\n lexiconStore?: LexiconStore\n replayStore?: ReplayStore\n requestStore?: RequestStore\n tokenStore?: TokenStore\n\n /**\n * In order to speed up the client fetching process, you can provide a cache\n * to store HTTP responses.\n *\n * @note the cached entries should automatically expire after a certain time (typically 10 minutes)\n */\n clientJwksCache?: ClientJwksCache\n\n /**\n * In order to speed up the client fetching process, you can provide a cache\n * to store HTTP responses.\n *\n * @note the cached entries should automatically expire after a certain time (typically 10 minutes)\n */\n clientMetadataCache?: ClientMetadataCache\n\n /**\n * In order to enable loopback clients, you can provide a function that\n * returns the client metadata for a given loopback URL. This is useful for\n * development and testing purposes. This function is not called for internet\n * clients.\n *\n * @default is as specified by ATPROTO\n */\n loopbackMetadata?: null | false | LoopbackMetadataGetter\n}\n\nexport type OAuthProviderOptions = OAuthProviderConfig &\n OAuthVerifierOptions &\n OAuthHooks &\n DeviceManagerOptions &\n CustomizationConfig\n\nexport class OAuthProvider extends OAuthVerifier {\n protected readonly accessTokenMode: AccessTokenMode\n protected readonly hooks: OAuthHooks\n\n public readonly metadata: OAuthAuthorizationServerMetadata\n public readonly customization: Customization\n\n public readonly authenticationMaxAge: number\n\n public readonly accountManager: AccountManager\n public readonly deviceManager: DeviceManager\n public readonly clientManager: ClientManager\n public readonly lexiconManager: LexiconManager\n public readonly requestManager: RequestManager\n public readonly tokenManager: TokenManager\n\n public constructor({\n // OAuthProviderConfig\n authenticationMaxAge = AUTHENTICATION_MAX_AGE,\n tokenMaxAge = TOKEN_MAX_AGE,\n accessTokenMode = AccessTokenMode.stateless,\n\n metadata,\n loopbackMetadata = atprotoLoopbackClientMetadata,\n\n // Services\n safeFetch = safeFetchWrap(),\n lexResolver = new LexResolver({ fetch: safeFetch }),\n\n // compound store implementation\n store,\n\n // Required stores\n accountStore = asAccountStore(store),\n deviceStore = asDeviceStore(store),\n lexiconStore = asLexiconStore(store),\n tokenStore = asTokenStore(store),\n requestStore = asRequestStore(store),\n\n // Optional stores\n clientStore = ifClientStore(store),\n replayStore = ifReplayStore(store),\n\n clientJwksCache = new SimpleStoreMemory({\n maxSize: 50_000_000,\n ttl: 600e3,\n }),\n clientMetadataCache = new SimpleStoreMemory({\n maxSize: 50_000_000,\n ttl: 600e3,\n }),\n\n // OAuthHooks &\n // OAuthVerifierOptions &\n // DeviceManagerOptions &\n // Customization\n ...rest\n }: OAuthProviderOptions) {\n super({ replayStore, ...rest })\n\n // @NOTE: hooks don't really need a type parser, as all zod can actually\n // check at runtime is the fact that the values are functions. The only way\n // we would benefit from zod here would be to wrap the functions with a\n // validator for the provided function's return types, which we don't\n // really need if types are respected.\n this.hooks = rest\n\n this.accessTokenMode = accessTokenMode\n this.authenticationMaxAge = authenticationMaxAge\n this.metadata = buildMetadata(this.issuer, this.keyset, metadata)\n this.customization = customizationSchema.parse(rest)\n\n this.deviceManager = new DeviceManager(deviceStore, {\n ...rest,\n cookie: {\n ...rest.cookie,\n // \"secure\" defaults to \"true\" in DeviceManager. For the oauth routes to\n // work from localhost on Safari, we need to explicitly set secure to\n // false for localhost usage. This is not really an issue with Chrome\n // and Firefox, but Safari enforces it strictly.\n secure: !this.issuer.startsWith('http:'),\n },\n })\n this.accountManager = new AccountManager(\n this.issuer,\n accountStore,\n this.hooks,\n this.customization,\n )\n this.clientManager = new ClientManager(\n this.metadata,\n this.keyset,\n this.hooks,\n clientStore || null,\n loopbackMetadata || null,\n safeFetch,\n clientJwksCache,\n clientMetadataCache,\n )\n this.lexiconManager = new LexiconManager(lexiconStore, lexResolver)\n this.requestManager = new RequestManager(\n requestStore,\n this.lexiconManager,\n this.signer,\n this.metadata,\n this.hooks,\n )\n this.tokenManager = new TokenManager(\n tokenStore,\n this.lexiconManager,\n this.signer,\n this.hooks,\n this.accessTokenMode,\n tokenMaxAge,\n )\n }\n\n get jwks() {\n return this.keyset.publicJwks\n }\n\n /**\n * @returns true if the user's consent is required for the requested scopes\n */\n public checkConsentRequired(\n parameters: OAuthAuthorizationRequestParameters,\n clientData?: AuthorizedClientData,\n ) {\n // Client was never authorized before\n if (!clientData) return true\n\n // Client explicitly asked for consent\n if (parameters.prompt === 'consent') return true\n\n // No scope requested, and client is known by user, no consent required\n const requestedScopes = parameters.scope?.split(' ')\n if (requestedScopes == null) return false\n\n // Ensure that all requested scopes were previously authorized by the user\n const { authorizedScopes } = clientData\n return !requestedScopes.every((scope) => authorizedScopes.includes(scope))\n }\n\n public checkLoginRequired(deviceAccount: DeviceAccount) {\n const authAge = Date.now() - deviceAccount.updatedAt.getTime()\n return authAge > this.authenticationMaxAge\n }\n\n protected async authenticateClient(\n clientCredentials: OAuthClientCredentials,\n dpopProof: null | DpopProof,\n options?: {\n allowMissingDpopProof?: boolean\n },\n ): Promise<{\n client: Client\n clientAuth: ClientAuth\n }> {\n const client = await this.clientManager.getClient(\n clientCredentials.client_id,\n )\n\n if (\n client.metadata.dpop_bound_access_tokens &&\n !dpopProof &&\n !options?.allowMissingDpopProof\n ) {\n throw new InvalidDpopProofError('DPoP proof required')\n }\n\n if (dpopProof && !client.metadata.dpop_bound_access_tokens) {\n throw new InvalidDpopProofError('DPoP proof not allowed for this client')\n }\n\n const clientAuth = await client.authenticate(clientCredentials, {\n authorizationServerIdentifier: this.issuer,\n })\n\n if (clientAuth.method === 'private_key_jwt') {\n // Clients MUST NOT use their client assertion key to sign DPoP proofs\n if (dpopProof && clientAuth.jkt === dpopProof.jkt) {\n throw new InvalidRequestError(\n 'The DPoP proof must be signed with a different key than the client assertion',\n )\n }\n\n // https://www.rfc-editor.org/rfc/rfc7523.html#section-3\n // > 7. [...] The authorization server MAY ensure that JWTs are not\n // > replayed by maintaining the set of used \"jti\" values for the\n // > length of time for which the JWT would be considered valid based\n // > on the applicable \"exp\" instant.\n\n const unique = await this.replayManager.uniqueAuth(\n clientAuth.jti,\n client.id,\n clientAuth.exp,\n )\n if (!unique) {\n throw new InvalidGrantError(`${clientAuth.method} jti reused`)\n }\n }\n\n return { client, clientAuth }\n }\n\n async decodeJAR(\n client: Client,\n input: OAuthAuthorizationRequestJar,\n ): Promise<OAuthAuthorizationRequestParameters> {\n const { payload } = await client.decodeRequestObject(\n input.request,\n this.issuer,\n )\n\n const { jti } = payload\n if (!jti) {\n throw new InvalidRequestError(\n 'Request object payload must contain a \"jti\" claim',\n )\n }\n if (!(await this.replayManager.uniqueJar(jti, client.id))) {\n throw new InvalidRequestError('Request object was replayed')\n }\n\n const parameters = await oauthAuthorizationRequestParametersSchema\n .parseAsync(payload)\n .catch((err) => {\n const msg = formatError(err, 'Invalid parameters in JAR')\n throw new InvalidRequestError(msg, err)\n })\n\n return parameters\n }\n\n /**\n * @see {@link https://datatracker.ietf.org/doc/html/rfc9126}\n */\n public async pushedAuthorizationRequest(\n credentials: OAuthClientCredentials,\n authorizationRequest: OAuthAuthorizationRequestPar,\n dpopProof: null | DpopProof,\n ): Promise<OAuthParResponse> {\n try {\n const { client, clientAuth } = await this.authenticateClient(\n credentials,\n dpopProof,\n // Allow missing DPoP header for PAR requests as rfc9449 allows it\n // (though the dpop_jkt parameter must be present in that case, see\n // check bellow).\n { allowMissingDpopProof: true },\n )\n\n const parameters =\n 'request' in authorizationRequest // Handle JAR\n ? await this.decodeJAR(client, authorizationRequest)\n : authorizationRequest\n\n if (!parameters.dpop_jkt) {\n if (client.metadata.dpop_bound_access_tokens) {\n if (dpopProof) parameters.dpop_jkt = dpopProof.jkt\n else {\n // @NOTE When both PAR and DPoP are used, either the DPoP header, or\n // the dpop_jkt parameter must be present. We do not enforce this\n // for legacy reasons.\n // https://datatracker.ietf.org/doc/html/rfc9449#section-10.1\n }\n }\n } else {\n if (!client.metadata.dpop_bound_access_tokens) {\n throw new InvalidRequestError(\n 'DPoP bound access tokens are not enabled for this client',\n )\n }\n\n // Proof is optional if the dpop_jkt is provided, but if it is provided,\n // it must match the DPoP proof JKT.\n if (dpopProof && dpopProof.jkt !== parameters.dpop_jkt) {\n throw new InvalidDpopKeyBindingError()\n }\n }\n\n const { requestUri, expiresAt } =\n await this.requestManager.createAuthorizationRequest(\n client,\n clientAuth,\n parameters,\n null,\n )\n\n return {\n request_uri: requestUri,\n expires_in: dateToRelativeSeconds(expiresAt),\n }\n } catch (err) {\n // https://datatracker.ietf.org/doc/html/rfc9126#section-2.3-1\n // > Since initial processing of the pushed authorization request does not\n // > involve resource owner interaction, error codes related to user\n // > interaction, such as \"access_denied\", are never returned.\n if (err instanceof AuthorizationError && !isPARResponseError(err.error)) {\n throw new InvalidRequestError(err.error_description, err)\n }\n throw err\n }\n }\n\n private async processAuthorizationRequest(\n client: Client,\n deviceId: DeviceId,\n query: OAuthAuthorizationRequestQuery,\n ) {\n // PAR\n if ('request_uri' in query) {\n const requestUri = parseRequestUri(query.request_uri, {\n path: ['query', 'request_uri'],\n })\n return this.requestManager.get(requestUri, deviceId, client.id)\n }\n\n // JAR\n if ('request' in query) {\n // @NOTE Since JAR are signed with the client's private key, a JAR *could*\n // technically be used to authenticate the client when requests are\n // created without PAR (i.e. created on the fly by the authorize\n // endpoint). This implementation actually used to support this\n // (un-spec'd) behavior. That support was removed:\n // - Because it was not actually used\n // - Because it was not part of any standard\n // - Because it makes extending the client authentication mechanism more\n // complex since any extension would not only need to affect the\n // \"private_key_jwt\" auth method but also the JAR \"request\" object.\n const parameters = await this.decodeJAR(client, query)\n\n return this.requestManager.createAuthorizationRequest(\n client,\n null,\n parameters,\n deviceId,\n )\n }\n\n // \"Regular\" authorization request (created on the fly by directing the user\n // to the authorization endpoint with all the parameters in the url).\n return this.requestManager.createAuthorizationRequest(\n client,\n null,\n query,\n deviceId,\n )\n }\n\n /**\n * @see {@link https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-4.1.1}\n */\n public async authorize(\n query: OAuthAuthorizationRequestQuery,\n { deviceId, deviceMetadata }: DeviceInfo,\n ): Promise<AuthorizationResultRedirect | AuthorizationResultAuthorizePage> {\n const { issuer } = this\n\n // If there is a chance to redirect the user to the client, let's do\n // it by wrapping the error in an AuthorizationError.\n const throwAuthorizationError =\n 'redirect_uri' in query\n ? (err: unknown): never => {\n // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-4.1.2.1\n throw AuthorizationError.from(query, err)\n }\n : null\n\n const client = await this.clientManager\n .getClient(query.client_id)\n .catch(throwAuthorizationError)\n\n const { parameters, requestUri } = await this.processAuthorizationRequest(\n client,\n deviceId,\n query,\n ).catch(throwAuthorizationError)\n\n try {\n const sessions = (\n await this.accountManager.listDeviceAccounts(deviceId)\n ).map((deviceAccount) => ({\n account: deviceAccount.account,\n\n // @TODO Return the session expiration date instead of a boolean to\n // avoid having to rely on a leeway when \"accepting\" the request.\n loginRequired:\n parameters.prompt === 'login' ||\n this.checkLoginRequired(deviceAccount),\n consentRequired: this.checkConsentRequired(\n parameters,\n deviceAccount.authorizedClients.get(client.id),\n ),\n }))\n\n // https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest\n\n // prompt=select_account\n //\n // > The Authorization Server SHOULD prompt the End-User to select a user\n // > account. This enables an End-User who has multiple accounts at the\n // > Authorization Server to select amongst the multiple accounts that\n // > they might have current sessions for. If it cannot obtain an account\n // > selection choice made by the End-User, it MUST return an error,\n // > typically account_selection_required.\n if (parameters.prompt === 'select_account' && !sessions.length) {\n throw new AccountSelectionRequiredError(parameters)\n }\n\n const ssoSessions = sessions\n .filter(hasActiveAccount)\n .filter(matchesHint, parameters)\n\n // prompt=none\n //\n // > The Authorization Server MUST NOT display any authentication or\n // > consent user interface pages. An error is returned if an End-User is\n // > not already authenticated or the Client does not have pre-configured\n // > consent for the requested Claims or does not fulfill other conditions\n // > for processing the request. The error code will typically be\n // > login_required, interaction_required, or another code defined in\n // > Section 3.1.2.6. This can be used as a method to check for existing\n // > authentication and/or consent.\n if (parameters.prompt === 'none') {\n if (ssoSessions.length > 1) {\n throw new AccountSelectionRequiredError(parameters)\n }\n if (ssoSessions.length < 1) {\n throw new LoginRequiredError(parameters)\n }\n\n const ssoSession = ssoSessions[0]!\n if (ssoSession.loginRequired) {\n throw new LoginRequiredError(parameters)\n }\n if (ssoSession.consentRequired) {\n throw new ConsentRequiredError(parameters)\n }\n\n const code = await this.requestManager.setAuthorized(\n requestUri,\n client,\n ssoSession.account,\n deviceId,\n deviceMetadata,\n )\n\n return { issuer, parameters, redirect: { code } }\n }\n\n // Automatic SSO when a hint was provided that matches a single session\n if (parameters.prompt == null && parameters.login_hint != null) {\n if (ssoSessions.length === 1) {\n const ssoSession = ssoSessions[0]!\n if (!ssoSession.loginRequired && !ssoSession.consentRequired) {\n const code = await this.requestManager.setAuthorized(\n requestUri,\n client,\n ssoSession.account,\n deviceId,\n deviceMetadata,\n )\n\n return { issuer, parameters, redirect: { code } }\n }\n }\n }\n\n return {\n issuer,\n client,\n parameters,\n requestUri,\n sessions: sessions\n // Strip un-necessary information (like consentRequired)\n .map(({ account, loginRequired }) => ({ account, loginRequired })),\n selectedDid:\n parameters.prompt == null ||\n parameters.prompt === 'login' ||\n parameters.prompt === 'consent'\n ? sessions.find(matchesHint, parameters)?.account.did\n : undefined,\n loginHint: await resolveLoginHint(\n parameters.login_hint,\n this.accountManager,\n ),\n permissionSets: await this.lexiconManager\n .getPermissionSetsFromScope(parameters.scope)\n .catch((cause) => {\n throw new AuthorizationError(\n parameters,\n 'Unable to retrieve permission sets',\n 'invalid_scope',\n cause,\n )\n }),\n }\n } catch (err) {\n try {\n await this.requestManager.delete(requestUri)\n } catch {\n // There are two error here. Better keep the outer one.\n //\n // @TODO Maybe move this entire code to the /authorize endpoint\n // (allowing to log this error)\n }\n\n throw AuthorizationError.from(parameters, err)\n }\n }\n\n public async token(\n clientCredentials: OAuthClientCredentials,\n clientMetadata: RequestMetadata,\n request: OAuthTokenRequest,\n dpopProof: null | DpopProof,\n ): Promise<OAuthTokenResponse> {\n const { client, clientAuth } = await this.authenticateClient(\n clientCredentials,\n dpopProof,\n )\n\n if (!this.metadata.grant_types_supported?.includes(request.grant_type)) {\n throw new InvalidGrantError(\n `Grant type \"${request.grant_type}\" is not supported by the server`,\n )\n }\n\n if (!client.metadata.grant_types.includes(request.grant_type)) {\n throw new InvalidGrantError(\n `\"${request.grant_type}\" grant type is not allowed for this client`,\n )\n }\n\n if (request.grant_type === 'authorization_code') {\n return this.authorizationCodeGrant(\n client,\n clientAuth,\n clientMetadata,\n request,\n dpopProof,\n )\n }\n\n if (request.grant_type === 'refresh_token') {\n return this.refreshTokenGrant(\n client,\n clientAuth,\n clientMetadata,\n request,\n dpopProof,\n )\n }\n\n throw new InvalidGrantError(\n `Grant type \"${request.grant_type}\" not supported`,\n )\n }\n\n protected async compareClientAuth(\n client: Client,\n clientAuth: ClientAuth,\n dpopProof: null | DpopProof,\n initial: {\n parameters: OAuthAuthorizationRequestParameters\n clientId: ClientId\n clientAuth: null | ClientAuth | ClientAuthLegacy\n },\n ): Promise<void> {\n // Fool proofing, ensure that the client is authenticating using the right method\n if (clientAuth.method !== client.metadata.token_endpoint_auth_method) {\n throw new InvalidGrantError(\n `Client authentication method mismatch (expected ${client.metadata.token_endpoint_auth_method}, got ${clientAuth.method})`,\n )\n }\n\n if (initial.clientId !== client.id) {\n throw new InvalidGrantError(`Token was not issued to this client`)\n }\n\n const { parameters } = initial\n if (parameters.dpop_jkt) {\n if (!dpopProof) {\n throw new InvalidGrantError(`DPoP proof is required for this request`)\n } else if (parameters.dpop_jkt !== dpopProof.jkt) {\n throw new InvalidGrantError(\n `DPoP proof does not match the expected JKT`,\n )\n }\n }\n\n if (!initial.clientAuth) {\n // If the client did not use PAR, it was not authenticated when the request\n // was initially created (see authorize() method in OAuthProvider). Since\n // PAR is not mandatory, and since the token exchange currently taking place\n // *is* authenticated (`clientAuth`), we allow \"upgrading\" the\n // authentication method (the token created will be bound to the current\n // clientAuth).\n return\n }\n\n switch (initial.clientAuth.method) {\n case CLIENT_ASSERTION_TYPE_JWT_BEARER: // LEGACY\n case 'private_key_jwt':\n if (clientAuth.method !== 'private_key_jwt') {\n throw new InvalidGrantError(\n `Client authentication method mismatch (expected ${initial.clientAuth.method})`,\n )\n }\n if (\n clientAuth.kid !== initial.clientAuth.kid ||\n clientAuth.alg !== initial.clientAuth.alg ||\n clientAuth.jkt !== initial.clientAuth.jkt\n ) {\n throw new InvalidGrantError(\n `The session was initiated with a different key than the client assertion currently used`,\n )\n }\n break\n case 'none':\n // @NOTE We allow the client to \"upgrade\" to a confidential client if\n // the session was initially created without client authentication.\n break\n default:\n throw new InvalidGrantError(\n // @ts-expect-error (future proof, backwards compatibility)\n `Invalid method \"${initial.clientAuth.method}\"`,\n )\n }\n }\n\n protected async authorizationCodeGrant(\n client: Client,\n clientAuth: ClientAuth,\n clientMetadata: RequestMetadata,\n input: OAuthAuthorizationCodeGrantTokenRequest,\n dpopProof: null | DpopProof,\n ): Promise<OAuthTokenResponse> {\n const code = await codeSchema\n .parseAsync(input.code, { path: ['code'] })\n .catch((err) => {\n const msg = formatError(err, 'Invalid code')\n throw new InvalidGrantError(msg, err)\n })\n\n const data = await this.requestManager\n .consumeCode(code)\n .catch(async (err) => {\n // Code not found in request manager: check for replays\n const tokenInfo = await this.tokenManager.findByCode(code)\n if (tokenInfo) {\n // try/finally to ensure that both code path get executed (sequentially)\n try {\n // \"code\" was replayed, delete existing session\n await this.tokenManager.deleteToken(tokenInfo.id)\n } finally {\n // As an additional security measure, we also sign the device out,\n // so that the device cannot be used to access the account anymore\n // without a new authentication.\n const { deviceId, did } = tokenInfo.data\n if (deviceId) {\n await this.accountManager.removeDeviceAccount(deviceId, did)\n }\n }\n }\n\n throw InvalidGrantError.from(err, `Invalid code`)\n })\n\n // @NOTE at this point, the request data was removed from the store and only\n // exists in memory here (in the \"data\" variable). Because of this, any\n // error thrown after this point will permanently cause the request data to\n // be lost.\n\n await this.compareClientAuth(client, clientAuth, dpopProof, data)\n\n // If the DPoP proof was not provided earlier (PAR / authorize), let's add\n // it now.\n const parameters =\n dpopProof &&\n client.metadata.dpop_bound_access_tokens &&\n !data.parameters.dpop_jkt\n ? { ...data.parameters, dpop_jkt: dpopProof.jkt }\n : data.parameters\n\n await this.validateCodeGrant(parameters, input)\n\n const { account } = await this.accountManager.getAccount(data.did)\n\n return this.tokenManager.createToken(\n client,\n clientAuth,\n clientMetadata,\n account,\n data.deviceId,\n parameters,\n code,\n )\n }\n\n protected async validateCodeGrant(\n parameters: OAuthAuthorizationRequestParameters,\n input: OAuthAuthorizationCodeGrantTokenRequest,\n ): Promise<void> {\n if (parameters.redirect_uri !== input.redirect_uri) {\n throw new InvalidGrantError(\n 'The redirect_uri parameter must match the one used in the authorization request',\n )\n }\n\n if (parameters.code_challenge) {\n if (!input.code_verifier) {\n throw new InvalidGrantError('code_verifier is required')\n }\n if (input.code_verifier.length < 43) {\n throw new InvalidGrantError('code_verifier too short')\n }\n switch (parameters.code_challenge_method) {\n case undefined: // default is \"plain\"\n case 'plain':\n if (parameters.code_challenge !== input.code_verifier) {\n throw new InvalidGrantError('Invalid code_verifier')\n }\n break\n\n case 'S256': {\n const inputChallenge = Buffer.from(\n parameters.code_challenge,\n 'base64',\n )\n const computedChallenge = createHash('sha256')\n .update(input.code_verifier)\n .digest()\n if (inputChallenge.compare(computedChallenge) !== 0) {\n throw new InvalidGrantError('Invalid code_verifier')\n }\n break\n }\n\n default:\n // Should never happen (because request validation should catch this)\n throw new Error(`Unsupported code_challenge_method`)\n }\n const unique = await this.replayManager.uniqueCodeChallenge(\n parameters.code_challenge,\n )\n if (!unique) {\n throw new InvalidGrantError('Code challenge already used')\n }\n } else if (input.code_verifier !== undefined) {\n throw new InvalidRequestError(\"code_challenge parameter wasn't provided\")\n }\n }\n\n protected async refreshTokenGrant(\n client: Client,\n clientAuth: ClientAuth,\n clientMetadata: RequestMetadata,\n input: OAuthRefreshTokenGrantTokenRequest,\n dpopProof: null | DpopProof,\n ): Promise<OAuthTokenResponse> {\n const refreshToken = await refreshTokenSchema\n .parseAsync(input.refresh_token, { path: ['refresh_token'] })\n .catch((err) => {\n const msg = formatError(err, 'Invalid refresh token')\n throw new InvalidGrantError(msg, err)\n })\n\n const tokenInfo = await this.tokenManager.consumeRefreshToken(refreshToken)\n\n try {\n const { data } = tokenInfo\n const now = new Date()\n\n await this.compareClientAuth(client, clientAuth, dpopProof, data)\n await this.validateRefreshGrant(client, data, now)\n\n return await this.tokenManager.rotateToken(\n client,\n clientAuth,\n clientMetadata,\n tokenInfo,\n now,\n )\n } catch (err) {\n await this.tokenManager.deleteToken(tokenInfo.id)\n\n throw err\n }\n }\n\n protected async validateRefreshGrant(\n client: Client,\n data: TokenData,\n now = new Date(),\n ): Promise<void> {\n if (!client.metadata.grant_types.includes('refresh_token')) {\n throw new InvalidGrantError(`Refresh token grant not allowed`)\n }\n\n const sessionAge = now.getTime() - data.createdAt.getTime()\n\n if (sessionAge > client.sessionLifetime) {\n throw new InvalidGrantError(`Session expired`)\n }\n\n const refreshAge = now.getTime() - data.updatedAt.getTime()\n if (refreshAge > client.refreshLifetime) {\n throw new InvalidGrantError(`Refresh token expired`)\n }\n }\n\n /**\n * @see {@link https://datatracker.ietf.org/doc/html/rfc7009#section-2.1 rfc7009}\n */\n public async revoke(\n clientCredentials: OAuthClientCredentials,\n { token }: OAuthTokenIdentification,\n dpopProof: null | DpopProof,\n ) {\n // > The authorization server first validates the client credentials (in\n // > case of a confidential client)\n const { client, clientAuth } = await this.authenticateClient(\n clientCredentials,\n dpopProof,\n )\n\n const tokenInfo = await this.tokenManager.findToken(token)\n if (tokenInfo) {\n // > [...] and then verifies whether the token was issued to the client\n // > making the revocation request.\n const { data } = tokenInfo\n await this.compareClientAuth(client, clientAuth, dpopProof, data)\n\n // > In the next step, the authorization server invalidates the token. The\n // > invalidation takes place immediately, and the token cannot be used\n // > again after the revocation.\n await this.tokenManager.deleteToken(tokenInfo.id)\n }\n }\n\n protected override async decodeToken(\n tokenType: OAuthTokenType,\n token: OAuthAccessToken,\n dpopProof: null | DpopProof,\n ): Promise<AccessTokenPayload> {\n const tokenPayload = await super.decodeToken(tokenType, token, dpopProof)\n\n if (this.accessTokenMode !== AccessTokenMode.stateless) {\n // @NOTE in non stateless mode, some claims can be omitted (most notably\n // \"scope\"). We load the token claims here (allowing to ensure that the\n // token is still valid, and to retrieve a (potentially updated) set of\n // claims).\n\n const tokenClaims = await this.tokenManager.loadTokenClaims(\n tokenType,\n tokenPayload,\n )\n\n Object.assign(tokenPayload, tokenClaims)\n }\n\n return tokenPayload\n }\n}\n\nfunction matchesHint(\n this: OAuthAuthorizationRequestParameters,\n { account }: { account: Account },\n): boolean {\n const hint = this.login_hint\n if (!hint) return false\n\n return account.did === hint || account.handle === hint\n}\n\nfunction hasActiveAccount({ account }: { account: Account }): boolean {\n return !account.deactivated\n}\n"]}
@@ -10,6 +10,11 @@ export declare const getAssets: (entryName: string) => {
10
10
  } | null, assetsMiddleware: import("../../lib/http/types.js").Middleware;
11
11
  type HydrationData = Simplify<UiHydrationData>;
12
12
  export type SendWebAppOptions = SecurityHeadersOptions & WriteResponseOptions;
13
+ /**
14
+ * Pre-computes page rendering assets and data and returns a function that can
15
+ * be used to send the @atproto/oauth-provider-ui web app {@link page} specified
16
+ * by the {@link P} type parameter.
17
+ */
13
18
  export declare function sendWebAppFactory<P extends keyof HydrationData>(page: P, customization: Customization, defaults?: SendWebAppOptions): (req: IncomingMessage, res: ServerResponse, options: SendWebAppOptions & {
14
19
  data: Omit<HydrationData[P], '__customizationData'>;
15
20
  }) => Promise<void>;
@@ -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;AAEhE,OAAO,KAAK,EAAE,aAAa,IAAI,eAAe,EAAE,MAAM,2CAA2C,CAAA;AAGjG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAA;AAIzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACtE,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oCAAoC,CAAA;AAE3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAOtD,eAAO,MAAQ,SAAS;;;UAAE,gBAAgB,8CAEzC,CAAA;AAED,KAAK,aAAa,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAA;AAqB9C,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,SAiCzB,eAAe,OACf,cAAc,WACV,iBAAiB,GAAG;IAC3B,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAA;CACpD,KACA,OAAO,CAAC,IAAI,CAAC,CAqBjB"}
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;AAKjG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAA;AAIzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACtE,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,oCAAoC,CAAA;AAE3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAOtD,eAAO,MAAQ,SAAS;;;UAAE,gBAAgB,8CAEzC,CAAA;AAED,KAAK,aAAa,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAA;AAmB9C,MAAM,MAAM,iBAAiB,GAAG,sBAAsB,GAAG,oBAAoB,CAAA;AAE7E;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,aAAa,EAC7D,IAAI,EAAE,CAAC,EACP,aAAa,EAAE,aAAa,EAC5B,QAAQ,GAAE,iBAAsB,SAwBzB,eAAe,OACf,cAAc,WACV,iBAAiB,GAAG;IAC3B,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAA;CACpD,KACA,OAAO,CAAC,IAAI,CAAC,CAqBjB"}
@@ -1,4 +1,6 @@
1
1
  import { createRequire } from 'node:module';
2
+ import { buildCustomizationCoep } from '../../customization/build-customization-coep.js';
3
+ import { buildCustomizationCsp } from '../../customization/build-customization-csp.js';
2
4
  import { buildCustomizationCss } from '../../customization/build-customization-css.js';
3
5
  import { buildCustomizationData } from '../../customization/build-customization-data.js';
4
6
  import { mergeCsp } from '../../lib/csp/index.js';
@@ -14,44 +16,41 @@ export const { getAssets, assetsMiddleware } = parseAssetsManifest(require.resol
14
16
  const SPA_CSP = {
15
17
  // API calls are made to the same origin
16
18
  'connect-src': ["'self'"],
17
- // Allow loading of PDS logo & User avatars
18
- 'img-src': ['data:', 'https:'],
19
19
  // Prevent embedding in iframes
20
20
  'frame-ancestors': ["'none'"],
21
21
  };
22
+ // Allow loading of avatars and (trusted) OAuth client images
23
+ const AVATAR_CSP = {
24
+ // @TODO Find a way to make this narrower (e.g. by proxying avatars through
25
+ // our own domain and using "'self'" here, or by using the customization data
26
+ // to allow-list specific origins), or by only allowing "data:" uris. Note
27
+ // that the current https: value also prevents avatars and client images from
28
+ // working in dev (which we also may want to find a solution to).
29
+ 'img-src': ['https:'],
30
+ };
22
31
  /**
23
- * @see {@link https://docs.hcaptcha.com/#content-security-policy-settings}
32
+ * Pre-computes page rendering assets and data and returns a function that can
33
+ * be used to send the @atproto/oauth-provider-ui web app {@link page} specified
34
+ * by the {@link P} type parameter.
24
35
  */
25
- const HCAPTCHA_CSP = {
26
- 'script-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
27
- 'frame-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
28
- 'style-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
29
- 'connect-src': ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
30
- };
31
36
  export function sendWebAppFactory(page, customization, defaults = {}) {
32
- // Pre-computed options:
33
- const customizationData = buildCustomizationData(customization);
34
- const customizationCss = cssCode(buildCustomizationCss(customization));
35
37
  const assets = getAssets(page);
36
38
  if (!assets)
37
39
  throw new Error(`No assets found for page: ${page}`);
38
- const { scripts, styles } = assets;
39
- const csp = mergeCsp(SPA_CSP, customization.hcaptcha ? HCAPTCHA_CSP : undefined);
40
- const coep = customization.hcaptcha
41
- ? // hCaptcha's implementation of COEP is currently broken. Let's disable it
42
- // to avoid breaking the entire page.
43
- //
44
- // https://github.com/hCaptcha/react-hcaptcha/issues/259
45
- // https://github.com/hCaptcha/react-hcaptcha/issues/380
46
- CrossOriginEmbedderPolicy.unsafeNone
47
- : // Since we are loading avatars form other origins, which might not have
48
- // CORP headers, we need to use the "credentialless" value, which allows
49
- // loading cross-origin resources without credentials (cookies, client
50
- // certificates, etc.). This is a more secure alternative to
51
- // "unsafe-none". Ideally, we would want to set COEP to "require-corp" and
52
- // ensure that all cross-origin resources have the appropriate CORP
53
- // headers.
54
- CrossOriginEmbedderPolicy.credentialless;
40
+ // Pre-computing as much as possible during the initialization phase
41
+ const customizationCoep = buildCustomizationCoep(customization);
42
+ const customizationCsp = buildCustomizationCsp(customization);
43
+ const customizationCss = cssCode(buildCustomizationCss(customization));
44
+ const customizationData = buildCustomizationData(customization);
45
+ // Since we are loading avatars form other origins, which might not have
46
+ // CORP headers, we need to use the "credentialless" value, which allows
47
+ // loading cross-origin resources without credentials (cookies, client
48
+ // certificates, etc.). This is a more secure alternative to
49
+ // "unsafe-none". Ideally, we would want to set COEP to "require-corp" and
50
+ // ensure that all cross-origin resources have the appropriate CORP
51
+ // headers.
52
+ const coep = customizationCoep ?? CrossOriginEmbedderPolicy.credentialless;
53
+ const csp = mergeCsp(SPA_CSP, AVATAR_CSP, ...customizationCsp);
55
54
  return async function sendWebApp(req, res, options) {
56
55
  await setupCsrfToken(req, res);
57
56
  const script = declareHydrationData({
@@ -60,12 +59,12 @@ export function sendWebAppFactory(page, customization, defaults = {}) {
60
59
  });
61
60
  return writeHtml(res, mergeDefaults(defaults, options, {
62
61
  bodyAttrs: { class: 'text-foreground bg-background' },
63
- csp: options?.csp ? mergeCsp(csp, options.csp) : csp,
64
- coep: options?.coep ?? coep,
62
+ csp: mergeCsp(csp, options.csp),
63
+ coep: options.coep ?? coep,
65
64
  meta: [{ name: 'robots', content: 'noindex' }],
66
65
  body: html `<div id="root"></div>`,
67
- scripts: [script, ...scripts],
68
- styles: [...styles, customizationCss],
66
+ scripts: [script, ...assets.scripts],
67
+ styles: [...assets.styles, customizationCss],
69
68
  }));
70
69
  };
71
70
  }
@@ -1 +1 @@
1
- {"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../src/router/assets/assets.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAA;AACtF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iDAAiD,CAAA;AAExF,OAAO,EAAkB,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAA;AACvE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAA;AAEvD,OAAO,EACL,yBAAyB,GAE1B,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAExD,OAAO,EAAyB,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE1C,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;AAE9C,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,mBAAmB,CAChE,OAAO,CAAC,OAAO,CAAC,iDAAiD,CAAC,CACnE,CAAA;AAID,MAAM,OAAO,GAAc;IACzB,wCAAwC;IACxC,aAAa,EAAE,CAAC,QAAQ,CAAC;IACzB,2CAA2C;IAC3C,SAAS,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC9B,+BAA+B;IAC/B,iBAAiB,EAAE,CAAC,QAAQ,CAAC;CAC9B,CAAA;AAED;;GAEG;AACH,MAAM,YAAY,GAAc;IAC9B,YAAY,EAAE,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;IAChE,WAAW,EAAE,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;IAC/D,WAAW,EAAE,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;IAC/D,aAAa,EAAE,CAAC,sBAAsB,EAAE,wBAAwB,CAAC;CAClE,CAAA;AAID,MAAM,UAAU,iBAAiB,CAC/B,IAAO,EACP,aAA4B,EAC5B,QAAQ,GAAsB,EAAE;IAEhC,wBAAwB;IACxB,MAAM,iBAAiB,GAAG,sBAAsB,CAAC,aAAa,CAAC,CAAA;IAC/D,MAAM,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC,CAAA;IAEtE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,EAAE,CAAC,CAAA;IAEjE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAElC,MAAM,GAAG,GAAG,QAAQ,CAClB,OAAO,EACP,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAClD,CAAA;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ;QACjC,CAAC,CAAC,0EAA0E;YAC1E,qCAAqC;YACrC,EAAE;YACF,wDAAwD;YACxD,wDAAwD;YACxD,yBAAyB,CAAC,UAAU;QACtC,CAAC,CAAC,wEAAwE;YACxE,wEAAwE;YACxE,sEAAsE;YACtE,4DAA4D;YAC5D,0EAA0E;YAC1E,mEAAmE;YACnE,WAAW;YACX,yBAAyB,CAAC,cAAc,CAAA;IAE5C,OAAO,KAAK,UAAU,UAAU,CAC9B,GAAoB,EACpB,GAAmB,EACnB,OAEC;QAED,MAAM,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QAE9B,MAAM,MAAM,GAAG,oBAAoB,CAAC;YAClC,GAAG,OAAO,CAAC,IAAI;YACf,mBAAmB,EAAE,iBAAiB;SACvC,CAAC,CAAA;QAEF,OAAO,SAAS,CACd,GAAG,EACH,aAAa,CAAmB,QAAQ,EAAE,OAAO,EAAE;YACjD,SAAS,EAAE,EAAE,KAAK,EAAE,+BAA+B,EAAE;YACrD,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG;YACpD,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,IAAI;YAC3B,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;YAC9C,IAAI,EAAE,IAAI,CAAA,uBAAuB;YACjC,OAAO,EAAE,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC;YAC7B,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,gBAAgB,CAAC;SACtC,CAAC,CACH,CAAA;IACH,CAAC,CAAA;AACH,CAAC","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 type { Customization } from '../../customization/customization.js'\nimport { type CspConfig, mergeCsp } from '../../lib/csp/index.js'\nimport { declareHydrationData } from '../../lib/html/hydration-data.js'\nimport { cssCode, html } from '../../lib/html/index.js'\nimport type { WriteResponseOptions } from '../../lib/http/response.js'\nimport {\n CrossOriginEmbedderPolicy,\n type SecurityHeadersOptions,\n} from '../../lib/http/security-headers.js'\nimport { mergeDefaults } from '../../lib/util/object.js'\nimport type { Simplify } from '../../lib/util/type.js'\nimport { type WriteHtmlOptions, writeHtml } from '../../lib/write-html.js'\nimport { parseAssetsManifest } from './assets-manifest.js'\nimport { setupCsrfToken } from './csrf.js'\n\nconst require = createRequire(import.meta.url)\n\nexport const { getAssets, assetsMiddleware } = parseAssetsManifest(\n require.resolve('@atproto/oauth-provider-ui/bundle-manifest.json'),\n)\n\ntype HydrationData = Simplify<UiHydrationData>\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\n const assets = getAssets(page)\n if (!assets) throw new Error(`No assets found for page: ${page}`)\n\n const { scripts, styles } = assets\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-foreground bg-background' },\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"]}
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 { buildCustomizationCoep } from '../../customization/build-customization-coep.js'\nimport { buildCustomizationCsp } from '../../customization/build-customization-csp.js'\nimport { buildCustomizationCss } from '../../customization/build-customization-css.js'\nimport { buildCustomizationData } from '../../customization/build-customization-data.js'\nimport type { Customization } from '../../customization/customization.js'\nimport { type CspConfig, mergeCsp } from '../../lib/csp/index.js'\nimport { declareHydrationData } from '../../lib/html/hydration-data.js'\nimport { cssCode, html } from '../../lib/html/index.js'\nimport type { WriteResponseOptions } from '../../lib/http/response.js'\nimport {\n CrossOriginEmbedderPolicy,\n type SecurityHeadersOptions,\n} from '../../lib/http/security-headers.js'\nimport { mergeDefaults } from '../../lib/util/object.js'\nimport type { Simplify } from '../../lib/util/type.js'\nimport { type WriteHtmlOptions, writeHtml } from '../../lib/write-html.js'\nimport { parseAssetsManifest } from './assets-manifest.js'\nimport { setupCsrfToken } from './csrf.js'\n\nconst require = createRequire(import.meta.url)\n\nexport const { getAssets, assetsMiddleware } = parseAssetsManifest(\n require.resolve('@atproto/oauth-provider-ui/bundle-manifest.json'),\n)\n\ntype HydrationData = Simplify<UiHydrationData>\n\nconst SPA_CSP: CspConfig = {\n // API calls are made to the same origin\n 'connect-src': [\"'self'\"],\n // Prevent embedding in iframes\n 'frame-ancestors': [\"'none'\"],\n}\n\n// Allow loading of avatars and (trusted) OAuth client images\nconst AVATAR_CSP: CspConfig = {\n // @TODO Find a way to make this narrower (e.g. by proxying avatars through\n // our own domain and using \"'self'\" here, or by using the customization data\n // to allow-list specific origins), or by only allowing \"data:\" uris. Note\n // that the current https: value also prevents avatars and client images from\n // working in dev (which we also may want to find a solution to).\n 'img-src': ['https:'],\n}\n\nexport type SendWebAppOptions = SecurityHeadersOptions & WriteResponseOptions\n\n/**\n * Pre-computes page rendering assets and data and returns a function that can\n * be used to send the @atproto/oauth-provider-ui web app {@link page} specified\n * by the {@link P} type parameter.\n */\nexport function sendWebAppFactory<P extends keyof HydrationData>(\n page: P,\n customization: Customization,\n defaults: SendWebAppOptions = {},\n) {\n const assets = getAssets(page)\n if (!assets) throw new Error(`No assets found for page: ${page}`)\n\n // Pre-computing as much as possible during the initialization phase\n\n const customizationCoep = buildCustomizationCoep(customization)\n const customizationCsp = buildCustomizationCsp(customization)\n const customizationCss = cssCode(buildCustomizationCss(customization))\n const customizationData = buildCustomizationData(customization)\n\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 const coep = customizationCoep ?? CrossOriginEmbedderPolicy.credentialless\n\n const csp = mergeCsp(SPA_CSP, AVATAR_CSP, ...customizationCsp)\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-foreground bg-background' },\n csp: mergeCsp(csp, options.csp),\n coep: options.coep ?? coep,\n meta: [{ name: 'robots', content: 'noindex' }],\n body: html`<div id=\"root\"></div>`,\n scripts: [script, ...assets.scripts],\n styles: [...assets.styles, customizationCss],\n }),\n )\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/oauth-provider",
3
- "version": "0.22.7",
3
+ "version": "0.22.9",
4
4
  "license": "MIT",
5
5
  "description": "Generic OAuth2 and OpenID Connect provider for Node.js. Currently only supports features needed for Atproto.",
6
6
  "keywords": [
@@ -72,27 +72,26 @@
72
72
  "ioredis": "^5.3.2",
73
73
  "jose": "^5.2.0",
74
74
  "zod": "^3.23.8",
75
- "@atproto-labs/fetch-node": "^0.3.7",
76
- "@atproto-labs/pipe": "^0.2.4",
77
75
  "@atproto-labs/simple-store": "^0.5.1",
78
76
  "@atproto-labs/simple-store-memory": "^0.2.6",
79
- "@atproto/did": "^0.5.5",
77
+ "@atproto-labs/pipe": "^0.2.4",
78
+ "@atproto-labs/fetch-node": "^0.4.0",
80
79
  "@atproto/common": "^0.8.3",
81
- "@atproto/jwk": "^0.7.4",
80
+ "@atproto/did": "^0.5.5",
82
81
  "@atproto/jwk-jose": "^0.2.4",
83
- "@atproto/lex-document": "^0.1.11",
84
- "@atproto/oauth-types": "^0.7.6",
82
+ "@atproto/lex-resolver": "^0.3.0",
85
83
  "@atproto/oauth-provider-api": "0.8.3",
86
- "@atproto/lex-resolver": "^0.2.12",
87
- "@atproto/oauth-provider-ui": "0.10.3",
88
- "@atproto/oauth-scopes": "^0.5.12",
89
- "@atproto/syntax": "^0.7.6"
84
+ "@atproto/oauth-types": "^0.7.6",
85
+ "@atproto/lex-document": "^0.1.12",
86
+ "@atproto/jwk": "^0.7.4",
87
+ "@atproto/oauth-provider-ui": "0.10.4",
88
+ "@atproto/syntax": "^0.7.6",
89
+ "@atproto/oauth-scopes": "^0.5.12"
90
90
  },
91
91
  "devDependencies": {
92
92
  "@types/cookie": "^0.6.0",
93
93
  "@types/forwarded": "0.1.4",
94
94
  "@types/http-errors": "^2.0.4",
95
- "@types/send": "^0.17.4",
96
95
  "vitest": "^4.1.10",
97
96
  "@atproto-labs/rolldown-plugin-bundle-manifest": "^0.0.0"
98
97
  },