@hatk/hatk 0.0.1-alpha.110 → 0.0.1-alpha.112
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/dist/backfill.d.ts +4 -0
- package/dist/backfill.d.ts.map +1 -1
- package/dist/backfill.js +23 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/dev-entry.d.ts.map +1 -1
- package/dist/dev-entry.js +2 -1
- package/dist/main.js +2 -1
- package/dist/oauth/server.d.ts +21 -3
- package/dist/oauth/server.d.ts.map +1 -1
- package/dist/oauth/server.js +48 -3
- package/dist/pds-proxy.d.ts.map +1 -1
- package/dist/pds-proxy.js +31 -6
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +12 -2
- package/package.json +1 -1
package/dist/backfill.d.ts
CHANGED
|
@@ -37,6 +37,10 @@ interface BackfillOpts {
|
|
|
37
37
|
/** Point DID resolution at a PLC directory. `runBackfill` does this too; call it
|
|
38
38
|
* at boot so resolvers that run before the first backfill have somewhere to go. */
|
|
39
39
|
export declare function configurePlc(url: string): void;
|
|
40
|
+
/** Set the PDS hosts whose repos {@link backfillRepo} leaves unimported; see
|
|
41
|
+
* `BackfillConfig.skipPds`. Matched on hostname, so a trailing slash or a
|
|
42
|
+
* scheme in the DID document makes no difference. */
|
|
43
|
+
export declare function configureSkipPds(hosts: string[] | undefined): void;
|
|
40
44
|
/** A repo's PDS endpoint, cached for the process. For serving blobs, where a
|
|
41
45
|
* stale answer after a migration costs one broken image, not a wrong row. */
|
|
42
46
|
export declare function pdsFor(did: string): Promise<string>;
|
package/dist/backfill.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../src/backfill.ts"],"names":[],"mappings":"AAkBA;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAE5E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAE/D;AAMD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAIjD,6CAA6C;AAC7C,UAAU,YAAY;IACpB,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAA;IACd,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,8FAA8F;IAC9F,MAAM,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACxB,wDAAwD;IACxD,MAAM,EAAE,cAAc,CAAA;CACvB;AAWD;oFACoF;AACpF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE9C;AAID;8EAC8E;AAC9E,wBAAsB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMzD;AAsFD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../src/backfill.ts"],"names":[],"mappings":"AAkBA;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAE5E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAE/D;AAMD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAIjD,6CAA6C;AAC7C,UAAU,YAAY;IACpB,wFAAwF;IACxF,MAAM,EAAE,MAAM,CAAA;IACd,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,8FAA8F;IAC9F,MAAM,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACxB,wDAAwD;IACxD,MAAM,EAAE,cAAc,CAAA;CACvB;AAWD;oFACoF;AACpF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE9C;AAID;;sDAEsD;AACtD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAElE;AAaD;8EAC8E;AAC9E,wBAAsB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMzD;AAsFD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2L/G;AA8BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAuIrE"}
|
package/dist/backfill.js
CHANGED
|
@@ -41,6 +41,23 @@ let plcUrl;
|
|
|
41
41
|
export function configurePlc(url) {
|
|
42
42
|
plcUrl = url;
|
|
43
43
|
}
|
|
44
|
+
let skippedPdsHosts = new Set();
|
|
45
|
+
/** Set the PDS hosts whose repos {@link backfillRepo} leaves unimported; see
|
|
46
|
+
* `BackfillConfig.skipPds`. Matched on hostname, so a trailing slash or a
|
|
47
|
+
* scheme in the DID document makes no difference. */
|
|
48
|
+
export function configureSkipPds(hosts) {
|
|
49
|
+
skippedPdsHosts = new Set((hosts ?? []).map((h) => h.toLowerCase()));
|
|
50
|
+
}
|
|
51
|
+
function isSkippedPds(pdsUrl) {
|
|
52
|
+
if (!skippedPdsHosts.size)
|
|
53
|
+
return false;
|
|
54
|
+
try {
|
|
55
|
+
return skippedPdsHosts.has(new URL(pdsUrl).hostname.toLowerCase());
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
44
61
|
const pdsCache = new Map();
|
|
45
62
|
/** A repo's PDS endpoint, cached for the process. For serving blobs, where a
|
|
46
63
|
* stale answer after a migration costs one broken image, not a wrong row. */
|
|
@@ -194,6 +211,11 @@ export async function backfillRepo(did, collections, fetchTimeout) {
|
|
|
194
211
|
const { pds: pdsUrl, handle } = await resolvePds(did);
|
|
195
212
|
resolvedPds = pdsUrl;
|
|
196
213
|
resolvedHandle = handle;
|
|
214
|
+
if (isSkippedPds(pdsUrl)) {
|
|
215
|
+
status = 'skipped';
|
|
216
|
+
await setRepoStatus(did, 'active', undefined, { handle });
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
197
219
|
timeout = setTimeout(() => controller.abort(), fetchTimeout * 1000);
|
|
198
220
|
let lastRev = await getRepoRev(did);
|
|
199
221
|
const baseUrl = `${resolvedPds}/xrpc/com.atproto.sync.getRepo?did=${encodeURIComponent(did)}`;
|
|
@@ -400,6 +422,7 @@ async function runWorkerPool(items, parallelism, fn) {
|
|
|
400
422
|
export async function runBackfill(opts) {
|
|
401
423
|
const { pdsUrl, collections, config } = opts;
|
|
402
424
|
plcUrl = opts.plcUrl;
|
|
425
|
+
configureSkipPds(config.skipPds);
|
|
403
426
|
const signalCollections = config.signalCollections || [...collections];
|
|
404
427
|
const elapsed = timer();
|
|
405
428
|
const mode = config.repos?.length ? 'pinned repos' : config.fullNetwork ? 'full network' : 'collection signal';
|
package/dist/config.d.ts
CHANGED
|
@@ -61,6 +61,14 @@ export interface BackfillConfig {
|
|
|
61
61
|
parallelism: number;
|
|
62
62
|
fetchTimeout: number;
|
|
63
63
|
maxRetries: number;
|
|
64
|
+
/**
|
|
65
|
+
* PDS hosts whose repos are never imported. A repo hosted on one is marked
|
|
66
|
+
* active with its handle and no records, so nothing queues it again, and
|
|
67
|
+
* whatever it writes from then on still arrives through the stream. For a
|
|
68
|
+
* bridge such as Bridgy Fed (`atproto.brid.gy`), whose repos mirror another
|
|
69
|
+
* network and can run to tens of thousands of records apiece.
|
|
70
|
+
*/
|
|
71
|
+
skipPds?: string[];
|
|
64
72
|
}
|
|
65
73
|
export interface ApnsPushConfig {
|
|
66
74
|
keyFile: string;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IACrC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;IACnC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;IAC1C,OAAO,CAAC,EAAE,WAAW,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,OAAO,EAAE,iBAAiB,EAAE,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,sBAAsB,EAAE,CAAA;CAC7C;AAED,MAAM,WAAW,sBAAsB;IACrC,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,wFAAwF;IACxF,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,mEAAmE;IACnE,UAAU,CAAC,EAAE,aAAa,EAAE,CAAA;IAC5B,WAAW,EAAE,OAAO,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,qFAAqF;AACrF,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,GAAG,CAAC,EAAE,aAAa,CAAA;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB;;;;;;;OAOG;IACH,SAAS,EAAE,eAAe,GAAG,IAAI,CAAA;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,SAAS,GAAG,IAAI,CAAA;IACrB,cAAc,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,kBAAkB,EAAE,MAAM,EAAE,CAAA;IAC5B,QAAQ,EAAE,cAAc,CAAA;IACxB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACnD,MAAM,EAAE,YAAY,GAAG,IAAI,CAAA;IAC3B,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,iFAAiF;IACjF,KAAK,EAAE,MAAM,GAAG,YAAY,CAAA;IAC5B;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAA;CACtB;AAED,4EAA4E;AAC5E,MAAM,MAAM,eAAe,GAAG,OAAO,CACnC,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,CAAC,CACzG,GAAG;IACF,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;IACtB,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG;QAAE,OAAO,EAAE,iBAAiB,EAAE,CAAA;KAAE,CAAC,GAAG,IAAI,CAAA;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAClC,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;IACxB,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IAClC,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAA;CAClC,CAAA;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CAErE;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -61,6 +61,7 @@ export async function loadConfig(configPath) {
|
|
|
61
61
|
parallelism: parseInt(env.BACKFILL_PARALLELISM || '') || backfillRaw.parallelism || 3,
|
|
62
62
|
fetchTimeout: parseInt(env.BACKFILL_FETCH_TIMEOUT || '') || backfillRaw.fetchTimeout || 300,
|
|
63
63
|
maxRetries: parseInt(env.BACKFILL_MAX_RETRIES || '') || backfillRaw.maxRetries || 5,
|
|
64
|
+
skipPds: backfillRaw.skipPds || undefined,
|
|
64
65
|
},
|
|
65
66
|
ftsRebuildInterval: parseInt(env.FTS_REBUILD_INTERVAL || '') || parsed.ftsRebuildInterval || 5000,
|
|
66
67
|
cdn: env.CDN_URL && env.CDN_KEY && env.CDN_SALT
|
package/dist/dev-entry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-entry.d.ts","sourceRoot":"","sources":["../src/dev-entry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dev-entry.d.ts","sourceRoot":"","sources":["../src/dev-entry.ts"],"names":[],"mappings":"AAqIA,eAAO,MAAM,OAAO,yCAKlB,CAAA;AAEF,yEAAyE;AACzE,wBAAsB,YAAY,kBAEjC;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA"}
|
package/dist/dev-entry.js
CHANGED
|
@@ -16,7 +16,7 @@ import { createHandler, registerCoreHandlers } from "./server.js";
|
|
|
16
16
|
import { setPrivateCollections } from "./private-collections.js";
|
|
17
17
|
import { auxCursorKey, startAuxIndexer, startIndexer, sweepReferences } from "./indexer.js";
|
|
18
18
|
import { getCursor } from "./database/db.js";
|
|
19
|
-
import { runBackfill, configurePlc } from "./backfill.js";
|
|
19
|
+
import { runBackfill, configurePlc, configureSkipPds } from "./backfill.js";
|
|
20
20
|
import { configureSpaceIdentity } from "./spaces/identity.js";
|
|
21
21
|
import { rebuildAllIndexes } from "./database/fts.js";
|
|
22
22
|
import { relayHttpUrl } from "./config.js";
|
|
@@ -31,6 +31,7 @@ const configDir = dirname(resolve(configPath));
|
|
|
31
31
|
const config = await loadConfig(configPath);
|
|
32
32
|
configureRelay(config.relay);
|
|
33
33
|
configurePlc(config.plc);
|
|
34
|
+
configureSkipPds(config.backfill.skipPds);
|
|
34
35
|
// Space reads resolve authorities too, and ctx.spaceCredential works without
|
|
35
36
|
// `spaces` indexing being configured.
|
|
36
37
|
configureSpaceIdentity(config.plc);
|
package/dist/main.js
CHANGED
|
@@ -31,7 +31,7 @@ import { setPrivateCollections } from "./private-collections.js";
|
|
|
31
31
|
import { serve } from "./adapter.js";
|
|
32
32
|
import { validateLexicons } from '@bigmoves/lexicon';
|
|
33
33
|
import { relayHttpUrl } from "./config.js";
|
|
34
|
-
import { runBackfill, configurePlc } from "./backfill.js";
|
|
34
|
+
import { runBackfill, configurePlc, configureSkipPds } from "./backfill.js";
|
|
35
35
|
import { initOAuth } from "./oauth/server.js";
|
|
36
36
|
import { parseSessionCookie, getSessionCookieName } from "./oauth/session.js";
|
|
37
37
|
import { loadOnLoginHook } from "./hooks.js";
|
|
@@ -47,6 +47,7 @@ registerHatkResolveHook();
|
|
|
47
47
|
const config = await loadConfig(configPath);
|
|
48
48
|
configureRelay(config.relay);
|
|
49
49
|
configurePlc(config.plc);
|
|
50
|
+
configureSkipPds(config.backfill.skipPds);
|
|
50
51
|
// Space reads resolve authorities too, and ctx.spaceCredential works without
|
|
51
52
|
// `spaces` indexing being configured.
|
|
52
53
|
configureSpaceIdentity(config.plc);
|
package/dist/oauth/server.d.ts
CHANGED
|
@@ -196,21 +196,39 @@ export interface ObtainedSession {
|
|
|
196
196
|
export declare function obtainSession(config: OAuthConfig, url: string, body: Record<string, unknown>, opts?: {
|
|
197
197
|
headers?: Record<string, string>;
|
|
198
198
|
}): Promise<ObtainedSession>;
|
|
199
|
-
|
|
199
|
+
type RefreshableSession = {
|
|
200
200
|
did: string;
|
|
201
201
|
pds_endpoint: string;
|
|
202
202
|
pds_auth_server?: string;
|
|
203
203
|
pds_token_endpoint?: string;
|
|
204
|
+
/** The access token the caller was refused with, when it has one. */
|
|
205
|
+
access_token?: string;
|
|
204
206
|
refresh_token: string;
|
|
205
207
|
dpop_jkt: string;
|
|
206
208
|
requested_scope?: string | null;
|
|
207
209
|
granted_scope?: string | null;
|
|
208
|
-
}
|
|
210
|
+
};
|
|
211
|
+
type RefreshedTokens = {
|
|
209
212
|
accessToken: string;
|
|
210
213
|
refreshToken?: string;
|
|
211
214
|
expiresAt?: number;
|
|
212
|
-
}
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* Renew a PDS session's access token, once per DID at a time.
|
|
218
|
+
*
|
|
219
|
+
* A refresh token is single-use, and the reference auth server treats a second
|
|
220
|
+
* use as theft: it answers `invalid_grant` and revokes the whole grant, the
|
|
221
|
+
* tokens just issued to the first use included. Two requests that find the
|
|
222
|
+
* access token expired together — an upload and the client's retry of it, say
|
|
223
|
+
* — would each spend the same refresh token, and the second would sign the
|
|
224
|
+
* user out. So a caller arriving while a refresh is in flight waits for that
|
|
225
|
+
* one, and a caller holding a session read before someone else's refresh
|
|
226
|
+
* finished is handed the tokens that refresh stored rather than replaying the
|
|
227
|
+
* spent one.
|
|
228
|
+
*/
|
|
229
|
+
export declare function refreshPdsSession(config: OAuthConfig, session: RefreshableSession): Promise<RefreshedTokens | null>;
|
|
213
230
|
export declare function authenticate(authHeader: string | null, dpopHeader: string | null, method: string, url: string): Promise<{
|
|
214
231
|
did: string;
|
|
215
232
|
} | null>;
|
|
233
|
+
export {};
|
|
216
234
|
//# sourceMappingURL=server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/oauth/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/oauth/server.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/server.js
CHANGED
|
@@ -5,7 +5,7 @@ import { initSession } from "./session.js";
|
|
|
5
5
|
import { resolveClient, validateRedirectUri, isLoopbackClient } from "./client.js";
|
|
6
6
|
import { negotiateScope } from "./service-describe.js";
|
|
7
7
|
import { discoverAuthServer, resolveHandle, fetchProtectedResourceMetadata, fetchAuthServerMetadata, } from "./discovery.js";
|
|
8
|
-
import { getServerKey, storeServerKey, storeOAuthRequest, getOAuthRequest, deleteOAuthRequest, storeAuthCode, consumeAuthCode, storeSession, deleteSession, checkAndStoreDpopJti, cleanupExpiredOAuth, storeRefreshToken, getRefreshToken, revokeRefreshToken, } from "./db.js";
|
|
8
|
+
import { getServerKey, storeServerKey, storeOAuthRequest, getOAuthRequest, deleteOAuthRequest, storeAuthCode, consumeAuthCode, storeSession, getSession, deleteSession, checkAndStoreDpopJti, cleanupExpiredOAuth, storeRefreshToken, getRefreshToken, revokeRefreshToken, } from "./db.js";
|
|
9
9
|
import { emit } from "../logger.js";
|
|
10
10
|
import { querySQL } from "../database/db.js";
|
|
11
11
|
import { fireOnLoginHook } from "../hooks.js";
|
|
@@ -944,10 +944,48 @@ export async function obtainSession(config, url, body, opts = {}) {
|
|
|
944
944
|
emit('oauth', 'session_obtained', { did, from: origin });
|
|
945
945
|
return { did, response: out };
|
|
946
946
|
}
|
|
947
|
-
|
|
947
|
+
/** The refresh in flight for each DID, which every caller arriving meanwhile shares. */
|
|
948
|
+
const refreshesInFlight = new Map();
|
|
949
|
+
/**
|
|
950
|
+
* Renew a PDS session's access token, once per DID at a time.
|
|
951
|
+
*
|
|
952
|
+
* A refresh token is single-use, and the reference auth server treats a second
|
|
953
|
+
* use as theft: it answers `invalid_grant` and revokes the whole grant, the
|
|
954
|
+
* tokens just issued to the first use included. Two requests that find the
|
|
955
|
+
* access token expired together — an upload and the client's retry of it, say
|
|
956
|
+
* — would each spend the same refresh token, and the second would sign the
|
|
957
|
+
* user out. So a caller arriving while a refresh is in flight waits for that
|
|
958
|
+
* one, and a caller holding a session read before someone else's refresh
|
|
959
|
+
* finished is handed the tokens that refresh stored rather than replaying the
|
|
960
|
+
* spent one.
|
|
961
|
+
*/
|
|
948
962
|
export async function refreshPdsSession(config, session) {
|
|
949
963
|
if (!session.refresh_token)
|
|
950
964
|
return null;
|
|
965
|
+
const inFlight = refreshesInFlight.get(session.did);
|
|
966
|
+
if (inFlight)
|
|
967
|
+
return inFlight;
|
|
968
|
+
const refresh = refreshUnlessRenewed(config, session).finally(() => refreshesInFlight.delete(session.did));
|
|
969
|
+
refreshesInFlight.set(session.did, refresh);
|
|
970
|
+
return refresh;
|
|
971
|
+
}
|
|
972
|
+
async function refreshUnlessRenewed(config, session) {
|
|
973
|
+
const stored = await getSession(session.did);
|
|
974
|
+
// A refresh that failed meanwhile ended the session; asking again would fail too.
|
|
975
|
+
if (!stored)
|
|
976
|
+
return null;
|
|
977
|
+
const renewed = stored.refresh_token !== session.refresh_token ||
|
|
978
|
+
(session.access_token !== undefined && stored.access_token !== session.access_token);
|
|
979
|
+
if (renewed) {
|
|
980
|
+
return {
|
|
981
|
+
accessToken: stored.access_token,
|
|
982
|
+
refreshToken: stored.refresh_token ?? undefined,
|
|
983
|
+
expiresAt: stored.token_expires_at == null ? undefined : Number(stored.token_expires_at),
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
return exchangeRefreshToken(config, session);
|
|
987
|
+
}
|
|
988
|
+
async function exchangeRefreshToken(config, session) {
|
|
951
989
|
// Prefer the endpoint the auth server advertised when this session was
|
|
952
990
|
// authorized. Sessions predating that column fall back to the auth server
|
|
953
991
|
// (or, older still, the PDS) with the path this used to hardcode.
|
|
@@ -965,8 +1003,9 @@ export async function refreshPdsSession(config, session) {
|
|
|
965
1003
|
body: body.toString(),
|
|
966
1004
|
});
|
|
967
1005
|
// Handle DPoP nonce retry
|
|
1006
|
+
let errBody = {};
|
|
968
1007
|
if (!tokenRes.ok) {
|
|
969
|
-
|
|
1008
|
+
errBody = await tokenRes.json().catch(() => ({}));
|
|
970
1009
|
if (errBody.error === 'use_dpop_nonce') {
|
|
971
1010
|
const nonce = tokenRes.headers.get('DPoP-Nonce');
|
|
972
1011
|
if (nonce) {
|
|
@@ -976,14 +1015,20 @@ export async function refreshPdsSession(config, session) {
|
|
|
976
1015
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded', DPoP: retryProof },
|
|
977
1016
|
body: body.toString(),
|
|
978
1017
|
});
|
|
1018
|
+
if (!tokenRes.ok)
|
|
1019
|
+
errBody = await tokenRes.json().catch(() => ({}));
|
|
979
1020
|
}
|
|
980
1021
|
}
|
|
981
1022
|
}
|
|
982
1023
|
if (!tokenRes.ok) {
|
|
1024
|
+
// The description is what tells a replayed refresh token from a revoked
|
|
1025
|
+
// or expired grant; the status is 400 for all of them.
|
|
983
1026
|
emit('oauth', 'pds_session_refresh_error', {
|
|
984
1027
|
status: tokenRes.status,
|
|
985
1028
|
did: session.did,
|
|
986
1029
|
pds_endpoint: session.pds_endpoint,
|
|
1030
|
+
error: errBody.error,
|
|
1031
|
+
error_description: errBody.error_description,
|
|
987
1032
|
});
|
|
988
1033
|
await deleteSession(session.did);
|
|
989
1034
|
return null;
|
package/dist/pds-proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pds-proxy.d.ts","sourceRoot":"","sources":["../src/pds-proxy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAU9C,qBAAa,UAAW,SAAQ,KAAK;IAE1B,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM;CAIlB;AAED,qBAAa,sBAAuB,SAAQ,UAAU;;CAIrD;AAED;;;;;;GAMG;AACH,qBAAa,uBAAwB,SAAQ,UAAU;;CAItD;
|
|
1
|
+
{"version":3,"file":"pds-proxy.d.ts","sourceRoot":"","sources":["../src/pds-proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/pds-proxy.js
CHANGED
|
@@ -57,14 +57,39 @@ function withheldByServer(session) {
|
|
|
57
57
|
return count(session.granted_scope) < count(session.requested_scope);
|
|
58
58
|
}
|
|
59
59
|
/** End the session so the user authorizes again — unless that could not help. */
|
|
60
|
-
async function refuseForScope(session) {
|
|
60
|
+
async function refuseForScope(session, pdsUrl, refusal) {
|
|
61
61
|
if (withheldByServer(session))
|
|
62
62
|
throw new ScopeWithheldProxyError();
|
|
63
|
+
emit('oauth', 'pds_session_ended', {
|
|
64
|
+
did: session.did,
|
|
65
|
+
nsid: nsidOf(pdsUrl),
|
|
66
|
+
status: refusal.status,
|
|
67
|
+
error: refusal.body.error,
|
|
68
|
+
message: refusal.body.message,
|
|
69
|
+
});
|
|
63
70
|
await deleteSession(session.did);
|
|
64
71
|
throw new ScopeMissingProxyError();
|
|
65
72
|
}
|
|
73
|
+
function nsidOf(pdsUrl) {
|
|
74
|
+
return new URL(pdsUrl).pathname.replace(/^\/xrpc\//, '');
|
|
75
|
+
}
|
|
66
76
|
/** Shared retry logic: DPoP nonce handling + token refresh. */
|
|
67
|
-
async function withDpopRetry(oauthConfig, session, doFetch) {
|
|
77
|
+
async function withDpopRetry(oauthConfig, session, pdsUrl, doFetch) {
|
|
78
|
+
const result = await fetchWithDpopRetry(oauthConfig, session, pdsUrl, doFetch);
|
|
79
|
+
// Callers pass on only the error name; the message is what says which blob
|
|
80
|
+
// was missing or which record was refused.
|
|
81
|
+
if (!result.ok) {
|
|
82
|
+
emit('pds', 'refused', {
|
|
83
|
+
did: session.did,
|
|
84
|
+
nsid: nsidOf(pdsUrl),
|
|
85
|
+
status: result.status,
|
|
86
|
+
error: result.body.error,
|
|
87
|
+
message: result.body.message,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
async function fetchWithDpopRetry(oauthConfig, session, pdsUrl, doFetch) {
|
|
68
93
|
let accessToken = session.access_token;
|
|
69
94
|
let result = await doFetch(accessToken);
|
|
70
95
|
if (result.ok)
|
|
@@ -81,7 +106,7 @@ async function withDpopRetry(oauthConfig, session, doFetch) {
|
|
|
81
106
|
}
|
|
82
107
|
// Step 2: handle insufficient scope — see refuseForScope
|
|
83
108
|
if (result.body.error === 'ScopeMissingError')
|
|
84
|
-
await refuseForScope(session);
|
|
109
|
+
await refuseForScope(session, pdsUrl, result);
|
|
85
110
|
// Step 3: handle expired PDS token — refresh and retry
|
|
86
111
|
if (isTokenError(result.body.error)) {
|
|
87
112
|
const refreshed = await refreshPdsSession(oauthConfig, session);
|
|
@@ -106,7 +131,7 @@ async function withDpopRetry(oauthConfig, session, doFetch) {
|
|
|
106
131
|
// space endpoints refuse, which is indistinguishable from expiry until
|
|
107
132
|
// the refresh rules expiry out.
|
|
108
133
|
if (!result.ok && isTokenError(result.body.error))
|
|
109
|
-
await refuseForScope(session);
|
|
134
|
+
await refuseForScope(session, pdsUrl, result);
|
|
110
135
|
}
|
|
111
136
|
}
|
|
112
137
|
return result;
|
|
@@ -147,7 +172,7 @@ async function proxyToPds(oauthConfig, session, method, pdsUrl, body) {
|
|
|
147
172
|
const serverKey = await getServerKey('appview-oauth-key');
|
|
148
173
|
const privateJwk = JSON.parse(serverKey.privateKey);
|
|
149
174
|
const publicJwk = JSON.parse(serverKey.publicKey);
|
|
150
|
-
return withDpopRetry(oauthConfig, session, async (token, nonce) => {
|
|
175
|
+
return withDpopRetry(oauthConfig, session, pdsUrl, async (token, nonce) => {
|
|
151
176
|
const proof = await createDpopProof(privateJwk, publicJwk, method, pdsUrl, token, nonce);
|
|
152
177
|
// A GET carries no body, and sending a JSON content-type without one makes
|
|
153
178
|
// some servers try to parse it. Queries reach here through pdsXrpc.
|
|
@@ -170,7 +195,7 @@ async function proxyToPdsRaw(oauthConfig, session, pdsUrl, body, contentType) {
|
|
|
170
195
|
const serverKey = await getServerKey('appview-oauth-key');
|
|
171
196
|
const privateJwk = JSON.parse(serverKey.privateKey);
|
|
172
197
|
const publicJwk = JSON.parse(serverKey.publicKey);
|
|
173
|
-
return withDpopRetry(oauthConfig, session, async (token, nonce) => {
|
|
198
|
+
return withDpopRetry(oauthConfig, session, pdsUrl, async (token, nonce) => {
|
|
174
199
|
const proof = await createDpopProof(privateJwk, publicJwk, 'POST', pdsUrl, token, nonce);
|
|
175
200
|
const res = await fetch(pdsUrl, {
|
|
176
201
|
method: 'POST',
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAmFA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAuE9C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CA2M3F;AAgDD,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AASD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxF,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,mFAAmF;IACnF,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B,+FAA+F;IAC/F,UAAU,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;CACrC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAmFA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAuE9C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CA2M3F;AAgDD,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AASD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxF,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,mFAAmF;IACnF,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B,+FAA+F;IAC/F,UAAU,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;CACrC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAsxC5F;AAGD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,WAAW,GAAG,IAAI,EACzB,MAAM,GAAE,MAAM,EAAO,EACrB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,GACpB,OAAO,WAAW,EAAE,MAAM,CAG5B"}
|
package/dist/server.js
CHANGED
|
@@ -375,7 +375,7 @@ export function createHandler(config) {
|
|
|
375
375
|
function invalidateAdminStats() {
|
|
376
376
|
adminStats = null;
|
|
377
377
|
}
|
|
378
|
-
|
|
378
|
+
const route = async (request, logRequest) => {
|
|
379
379
|
const url = new URL(request.url);
|
|
380
380
|
const acceptEncoding = request.headers.get('accept-encoding');
|
|
381
381
|
// CORS preflight
|
|
@@ -1536,9 +1536,10 @@ export function createHandler(config) {
|
|
|
1536
1536
|
}
|
|
1537
1537
|
finally {
|
|
1538
1538
|
if ((isXrpc || isAdmin) && elapsed) {
|
|
1539
|
-
|
|
1539
|
+
logRequest({
|
|
1540
1540
|
method: request.method,
|
|
1541
1541
|
path: url.pathname,
|
|
1542
|
+
viewer: viewer?.did,
|
|
1542
1543
|
duration_ms: elapsed(),
|
|
1543
1544
|
collection: url.searchParams.get('collection') || undefined,
|
|
1544
1545
|
query: url.searchParams.get('q') || undefined,
|
|
@@ -1547,6 +1548,15 @@ export function createHandler(config) {
|
|
|
1547
1548
|
}
|
|
1548
1549
|
}
|
|
1549
1550
|
};
|
|
1551
|
+
// The status is only known once a route has answered, and routes answer from
|
|
1552
|
+
// dozens of places, so the line is written here rather than inside.
|
|
1553
|
+
return async (request) => {
|
|
1554
|
+
let fields;
|
|
1555
|
+
const response = await route(request, (logged) => (fields = logged));
|
|
1556
|
+
if (fields)
|
|
1557
|
+
emit('server', 'request', { ...fields, status: response.status });
|
|
1558
|
+
return response;
|
|
1559
|
+
};
|
|
1550
1560
|
}
|
|
1551
1561
|
// Backward-compatible wrapper
|
|
1552
1562
|
export function startServer(port, collections, publicDir, oauth, admins = [], resolveViewer, onResync) {
|