@atproto/oauth-provider 0.22.5 → 0.22.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/dist/lib/http/stream.d.ts +9 -3
- package/dist/lib/http/stream.d.ts.map +1 -1
- package/dist/lib/http/stream.js +34 -5
- package/dist/lib/http/stream.js.map +1 -1
- package/dist/router/assets/assets-manifest.d.ts.map +1 -1
- package/dist/router/assets/assets-manifest.js +2 -1
- package/dist/router/assets/assets-manifest.js.map +1 -1
- package/package.json +14 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# @atproto/oauth-provider
|
|
2
2
|
|
|
3
|
+
## 0.22.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#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
|
|
8
|
+
at 100 KiB. The bound is on the decoded body, so a compressed request is
|
|
9
|
+
measured after decompression, and a `content-length` above it is rejected
|
|
10
|
+
without reading the body. Oversized bodies fail with a 413.
|
|
11
|
+
- Updated dependencies [[`f88aa58`](https://github.com/bluesky-social/atproto/commit/f88aa5842df9aba9f208a6073272b43ef9bd089d)]:
|
|
12
|
+
- @atproto-labs/fetch-node@0.4.0
|
|
13
|
+
- @atproto/oauth-provider-ui@0.10.3
|
|
14
|
+
- @atproto/lex-resolver@0.2.13
|
|
15
|
+
|
|
16
|
+
## 0.22.7
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- [#5488](https://github.com/bluesky-social/atproto/pull/5488) [`fe4087e`](https://github.com/bluesky-social/atproto/commit/fe4087ecb7a7cc53c7081c9f97d49121e5251c36) Thanks [@dependabot](https://github.com/apps/dependabot)! - Bump the dev-dependencies group across 1 directory with 30 updates
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [[`7a23156`](https://github.com/bluesky-social/atproto/commit/7a23156efa16433b83f90fd35e155c68b3a0253a), [`fe4087e`](https://github.com/bluesky-social/atproto/commit/fe4087ecb7a7cc53c7081c9f97d49121e5251c36), [`9c35046`](https://github.com/bluesky-social/atproto/commit/9c35046f17ac577fc64f8b5caccb8521d3b2584a), [`fe4087e`](https://github.com/bluesky-social/atproto/commit/fe4087ecb7a7cc53c7081c9f97d49121e5251c36)]:
|
|
23
|
+
- @atproto/lex-resolver@0.2.12
|
|
24
|
+
- @atproto/did@0.5.5
|
|
25
|
+
- @atproto/oauth-provider-ui@0.10.3
|
|
26
|
+
- @atproto/oauth-provider-api@0.8.3
|
|
27
|
+
- @atproto/common@0.8.3
|
|
28
|
+
- @atproto/oauth-scopes@0.5.12
|
|
29
|
+
- @atproto/oauth-types@0.7.6
|
|
30
|
+
|
|
31
|
+
## 0.22.6
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- Updated dependencies [[`ed0b7d3`](https://github.com/bluesky-social/atproto/commit/ed0b7d38811bb24952a3f1da988b02e39934d222)]:
|
|
36
|
+
- @atproto/syntax@0.7.6
|
|
37
|
+
- @atproto/lex-document@0.1.11
|
|
38
|
+
- @atproto/lex-resolver@0.2.11
|
|
39
|
+
- @atproto/oauth-provider-api@0.8.2
|
|
40
|
+
- @atproto/oauth-provider-ui@0.10.2
|
|
41
|
+
- @atproto/oauth-scopes@0.5.11
|
|
42
|
+
- @atproto/common@0.8.2
|
|
43
|
+
|
|
3
44
|
## 0.22.5
|
|
4
45
|
|
|
5
46
|
### Patch Changes
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import type { IncomingMessage } from 'node:http';
|
|
2
|
-
import type
|
|
2
|
+
import { type Readable } from 'node:stream';
|
|
3
3
|
import { type KnownNames, type ParserResult } from './parser.js';
|
|
4
|
-
|
|
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,
|
|
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"}
|
package/dist/lib/http/stream.js
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
|
+
import { pipeline } from 'node:stream';
|
|
1
2
|
import createHttpError from 'http-errors';
|
|
2
|
-
import {
|
|
3
|
+
import { MaxSizeChecker, createDecoders, streamToNodeBuffer, } from '@atproto/common';
|
|
3
4
|
import { parseContentType, parsers, } from './parser.js';
|
|
4
|
-
|
|
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
|
-
|
|
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":"
|
|
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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets-manifest.d.ts","sourceRoot":"","sources":["../../../src/router/assets/assets-manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assets-manifest.d.ts","sourceRoot":"","sources":["../../../src/router/assets/assets-manifest.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAA;AAChE,OAAO,EACL,KAAK,UAAU,EAIhB,MAAM,yBAAyB,CAAA;AAsBhC,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM;2BA0DxB,MAAM;;;;;EAqBrC"}
|
|
@@ -2,8 +2,9 @@ import { createReadStream } from 'node:fs';
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { Readable } from 'node:stream';
|
|
5
|
+
import { ASSETS_ENDPOINT_PREFIX } from '@atproto/oauth-provider-api';
|
|
5
6
|
import { validateFetchDest, validateFetchSite, writeStream, } from '../../lib/http/index.js';
|
|
6
|
-
const ASSETS_URL_PREFIX =
|
|
7
|
+
const ASSETS_URL_PREFIX = `${ASSETS_ENDPOINT_PREFIX}/`;
|
|
7
8
|
export function parseAssetsManifest(manifestPath) {
|
|
8
9
|
// Using `require` instead of `JSON.parse(readFileSync())` so that node's
|
|
9
10
|
// watch mode can pick up changes to the manifest file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets-manifest.js","sourceRoot":"","sources":["../../../src/router/assets/assets-manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"assets-manifest.js","sourceRoot":"","sources":["../../../src/router/assets/assets-manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import { createReadStream } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { join } from 'node:path'\nimport { Readable } from 'node:stream'\nimport { ASSETS_ENDPOINT_PREFIX } from '@atproto/oauth-provider-api'\nimport type { Manifest } from '@atproto-labs/rolldown-plugin-bundle-manifest'\nimport type { AssetRef } from '../../lib/html/build-document.js'\nimport {\n type Middleware,\n validateFetchDest,\n validateFetchSite,\n writeStream,\n} from '../../lib/http/index.js'\n\ntype Asset =\n | {\n type: 'asset'\n mime?: string\n sha256: string\n stream: () => Readable\n }\n | {\n type: 'chunk'\n mime: string\n sha256: string\n dynamicImports: string[]\n isDynamicEntry: boolean\n isEntry: boolean\n name: string\n stream: () => Readable\n }\n\nconst ASSETS_URL_PREFIX = `${ASSETS_ENDPOINT_PREFIX}/`\n\nexport function parseAssetsManifest(manifestPath: string) {\n // Using `require` instead of `JSON.parse(readFileSync())` so that node's\n // watch mode can pick up changes to the manifest file.\n const require = createRequire(import.meta.url)\n\n // eslint-disable-next-line import-x/no-dynamic-require\n const manifest = require(manifestPath) as Manifest\n\n const assets = new Map<string, Asset>(\n Object.entries(manifest).map(([filename, { data, ...item }]) => {\n const buffer = data ? Buffer.from(data, 'base64') : null\n const filepath = join(manifestPath, '..', filename)\n const stream = buffer\n ? () => Readable.from(buffer)\n : () => createReadStream(filepath)\n return [filename, { ...item, stream }]\n }),\n )\n\n const assetsMiddleware: Middleware = (req, res, next) => {\n if (req.method !== 'GET' && req.method !== 'HEAD') return next()\n if (!req.url?.startsWith(ASSETS_URL_PREFIX)) return next()\n\n const filename = decodeURIComponent(req.url.slice(ASSETS_URL_PREFIX.length))\n if (!filename) return next()\n\n const asset = assets.get(filename)\n if (!asset) return next()\n\n try {\n // Allow \"null\" (ie. no header) to allow loading assets outside of a\n // fetch context (not from a web page).\n validateFetchSite(req, [null, 'none', 'cross-site', 'same-origin'])\n validateFetchDest(req, [null, 'document', 'style', 'script'])\n } catch (err) {\n return next(err)\n }\n\n if (req.headers['if-none-match'] === asset.sha256) {\n return void res.writeHead(304).end()\n }\n\n res.setHeader('ETag', asset.sha256)\n res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')\n\n writeStream(res, asset.stream(), {\n contentType: asset.mime,\n onError: (cause) => {\n next(new Error(`Error serving asset \"${filename}\"`, { cause }))\n },\n })\n }\n\n return {\n getAssets,\n assetsMiddleware,\n }\n\n function getAssets(entryName: string) {\n const scripts = getScripts(entryName)\n if (!scripts.length) return null\n const styles = getStyles(entryName)\n return { scripts, styles }\n }\n\n function getScripts(entryName: string) {\n return Array.from(assets)\n .filter(\n ([, asset]) =>\n asset.type === 'chunk' && asset.isEntry && asset.name === entryName,\n )\n .map(assetEntryUrl)\n }\n\n function getStyles(_entryName: string) {\n return Array.from(assets)\n .filter(([, asset]) => asset.mime === 'text/css')\n .map(assetEntryUrl)\n }\n}\n\nfunction assetEntryUrl([filename]: [string, Asset]): AssetRef {\n return { url: assetUrl(filename) }\n}\n\nfunction assetUrl(filename: string) {\n return `${ASSETS_URL_PREFIX}${encodeURIComponent(filename)}`\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/oauth-provider",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.8",
|
|
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,25 +72,25 @@
|
|
|
72
72
|
"ioredis": "^5.3.2",
|
|
73
73
|
"jose": "^5.2.0",
|
|
74
74
|
"zod": "^3.23.8",
|
|
75
|
-
"@atproto-labs/
|
|
75
|
+
"@atproto-labs/pipe": "^0.2.4",
|
|
76
|
+
"@atproto-labs/fetch-node": "^0.4.0",
|
|
77
|
+
"@atproto/common": "^0.8.3",
|
|
76
78
|
"@atproto-labs/simple-store-memory": "^0.2.6",
|
|
77
|
-
"@atproto/
|
|
79
|
+
"@atproto-labs/simple-store": "^0.5.1",
|
|
78
80
|
"@atproto/jwk": "^0.7.4",
|
|
79
|
-
"@atproto/common": "^0.8.1",
|
|
80
81
|
"@atproto/jwk-jose": "^0.2.4",
|
|
81
|
-
"@atproto/
|
|
82
|
-
"@atproto/
|
|
83
|
-
"@atproto/
|
|
84
|
-
"@atproto/oauth-
|
|
85
|
-
"@atproto/
|
|
86
|
-
"@atproto-
|
|
87
|
-
"@atproto/oauth-scopes": "^0.5.
|
|
88
|
-
"@atproto/syntax": "^0.7.
|
|
89
|
-
"@atproto-labs/simple-store": "^0.5.1"
|
|
82
|
+
"@atproto/did": "^0.5.5",
|
|
83
|
+
"@atproto/lex-document": "^0.1.11",
|
|
84
|
+
"@atproto/lex-resolver": "^0.2.13",
|
|
85
|
+
"@atproto/oauth-types": "^0.7.6",
|
|
86
|
+
"@atproto/oauth-provider-api": "0.8.3",
|
|
87
|
+
"@atproto/oauth-provider-ui": "0.10.3",
|
|
88
|
+
"@atproto/oauth-scopes": "^0.5.12",
|
|
89
|
+
"@atproto/syntax": "^0.7.6"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
92
|
"@types/cookie": "^0.6.0",
|
|
93
|
-
"@types/forwarded": "0.1.
|
|
93
|
+
"@types/forwarded": "0.1.4",
|
|
94
94
|
"@types/http-errors": "^2.0.4",
|
|
95
95
|
"@types/send": "^0.17.4",
|
|
96
96
|
"vitest": "^4.1.10",
|