@opendatalabs/personal-server-ts-server 1.33.7 → 1.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__fixtures__/bound-record-store.d.ts +19 -0
- package/dist/__fixtures__/bound-record-store.d.ts.map +1 -0
- package/dist/__fixtures__/bound-record-store.js +60 -0
- package/dist/__fixtures__/bound-record-store.js.map +1 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-authorization-strategy.d.ts +41 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-authorization-strategy.d.ts.map +1 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-authorization-strategy.js +34 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-authorization-strategy.js.map +1 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-context-client.d.ts +112 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-context-client.d.ts.map +1 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-context-client.js +226 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-context-client.js.map +1 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-types.d.ts +135 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-types.d.ts.map +1 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-types.js +21 -0
- package/dist/__fixtures__/cg-pdpp-client/pdpp-types.js.map +1 -0
- package/dist/api-auth.d.ts +18 -2
- package/dist/api-auth.d.ts.map +1 -1
- package/dist/api-auth.js +114 -22
- package/dist/api-auth.js.map +1 -1
- package/dist/app.d.ts +60 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +139 -1
- package/dist/app.js.map +1 -1
- package/dist/bootstrap.d.ts +10 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +358 -7
- package/dist/bootstrap.js.map +1 -1
- package/dist/enclave-main.d.ts +4 -0
- package/dist/enclave-main.d.ts.map +1 -1
- package/dist/enclave-main.js +152 -1
- package/dist/enclave-main.js.map +1 -1
- package/dist/middleware/body-limit.d.ts +1 -1
- package/dist/middleware/body-limit.d.ts.map +1 -1
- package/dist/middleware/body-limit.js +8 -3
- package/dist/middleware/body-limit.js.map +1 -1
- package/dist/middleware/cors.d.ts.map +1 -1
- package/dist/middleware/cors.js +1 -0
- package/dist/middleware/cors.js.map +1 -1
- package/dist/package.json +9 -1
- package/dist/pdpp/bootstrap.d.ts +72 -0
- package/dist/pdpp/bootstrap.d.ts.map +1 -0
- package/dist/pdpp/bootstrap.js +270 -0
- package/dist/pdpp/bootstrap.js.map +1 -0
- package/dist/pdpp/chain-enforcement.d.ts +95 -0
- package/dist/pdpp/chain-enforcement.d.ts.map +1 -0
- package/dist/pdpp/chain-enforcement.js +145 -0
- package/dist/pdpp/chain-enforcement.js.map +1 -0
- package/dist/pdpp/client-document-fetch.d.ts +63 -0
- package/dist/pdpp/client-document-fetch.d.ts.map +1 -0
- package/dist/pdpp/client-document-fetch.js +254 -0
- package/dist/pdpp/client-document-fetch.js.map +1 -0
- package/dist/pdpp/declaration-registry.d.ts +83 -0
- package/dist/pdpp/declaration-registry.d.ts.map +1 -0
- package/dist/pdpp/declaration-registry.js +251 -0
- package/dist/pdpp/declaration-registry.js.map +1 -0
- package/dist/pdpp/deployment.d.ts +70 -0
- package/dist/pdpp/deployment.d.ts.map +1 -0
- package/dist/pdpp/deployment.js +104 -0
- package/dist/pdpp/deployment.js.map +1 -0
- package/dist/pdpp/record-schema.d.ts +2 -0
- package/dist/pdpp/record-schema.d.ts.map +1 -0
- package/dist/pdpp/record-schema.js +2 -0
- package/dist/pdpp/record-schema.js.map +1 -0
- package/dist/pdpp/records-bootstrap.d.ts +111 -0
- package/dist/pdpp/records-bootstrap.d.ts.map +1 -0
- package/dist/pdpp/records-bootstrap.js +353 -0
- package/dist/pdpp/records-bootstrap.js.map +1 -0
- package/dist/pdpp/source-id-compat.d.ts +5 -0
- package/dist/pdpp/source-id-compat.d.ts.map +1 -0
- package/dist/pdpp/source-id-compat.js +16 -0
- package/dist/pdpp/source-id-compat.js.map +1 -0
- package/dist/pdpp/test-connections.d.ts +6 -0
- package/dist/pdpp/test-connections.d.ts.map +1 -0
- package/dist/pdpp/test-connections.js +37 -0
- package/dist/pdpp/test-connections.js.map +1 -0
- package/dist/routes/auth-device.d.ts.map +1 -1
- package/dist/routes/auth-device.js +3 -0
- package/dist/routes/auth-device.js.map +1 -1
- package/dist/routes/chunked-scope-import.d.ts +41 -0
- package/dist/routes/chunked-scope-import.d.ts.map +1 -0
- package/dist/routes/chunked-scope-import.js +901 -0
- package/dist/routes/chunked-scope-import.js.map +1 -0
- package/dist/routes/data.d.ts +23 -1
- package/dist/routes/data.d.ts.map +1 -1
- package/dist/routes/data.js +112 -1
- package/dist/routes/data.js.map +1 -1
- package/dist/routes/grants.d.ts.map +1 -1
- package/dist/routes/grants.js +2 -0
- package/dist/routes/grants.js.map +1 -1
- package/dist/routes/mcp.d.ts.map +1 -1
- package/dist/routes/mcp.js +21 -12
- package/dist/routes/mcp.js.map +1 -1
- package/dist/routes/pdpp-auth.d.ts +157 -0
- package/dist/routes/pdpp-auth.d.ts.map +1 -0
- package/dist/routes/pdpp-auth.js +953 -0
- package/dist/routes/pdpp-auth.js.map +1 -0
- package/dist/routes/pdpp-blobs.d.ts +26 -0
- package/dist/routes/pdpp-blobs.d.ts.map +1 -0
- package/dist/routes/pdpp-blobs.js +179 -0
- package/dist/routes/pdpp-blobs.js.map +1 -0
- package/dist/routes/pdpp-connections.d.ts +28 -0
- package/dist/routes/pdpp-connections.d.ts.map +1 -0
- package/dist/routes/pdpp-connections.js +144 -0
- package/dist/routes/pdpp-connections.js.map +1 -0
- package/dist/routes/pdpp-declarations.d.ts +58 -0
- package/dist/routes/pdpp-declarations.d.ts.map +1 -0
- package/dist/routes/pdpp-declarations.js +94 -0
- package/dist/routes/pdpp-declarations.js.map +1 -0
- package/dist/routes/pdpp-instance-bindings.d.ts +26 -0
- package/dist/routes/pdpp-instance-bindings.d.ts.map +1 -0
- package/dist/routes/pdpp-instance-bindings.js +124 -0
- package/dist/routes/pdpp-instance-bindings.js.map +1 -0
- package/dist/routes/pdpp-records.d.ts +158 -0
- package/dist/routes/pdpp-records.d.ts.map +1 -0
- package/dist/routes/pdpp-records.js +1537 -0
- package/dist/routes/pdpp-records.js.map +1 -0
- package/dist/routes/pdpp-well-known.d.ts +13 -0
- package/dist/routes/pdpp-well-known.d.ts.map +1 -0
- package/dist/routes/pdpp-well-known.js +20 -0
- package/dist/routes/pdpp-well-known.js.map +1 -0
- package/dist/storage/declaration-witness.d.ts +56 -0
- package/dist/storage/declaration-witness.d.ts.map +1 -0
- package/dist/storage/declaration-witness.js +273 -0
- package/dist/storage/declaration-witness.js.map +1 -0
- package/dist/storage/hierarchy.d.ts +25 -1
- package/dist/storage/hierarchy.d.ts.map +1 -1
- package/dist/storage/hierarchy.js +210 -16
- package/dist/storage/hierarchy.js.map +1 -1
- package/dist/storage/import-operations.d.ts +11 -0
- package/dist/storage/import-operations.d.ts.map +1 -0
- package/dist/storage/import-operations.js +261 -0
- package/dist/storage/import-operations.js.map +1 -0
- package/dist/storage/index-manager.d.ts +24 -2
- package/dist/storage/index-manager.d.ts.map +1 -1
- package/dist/storage/index-manager.js +279 -30
- package/dist/storage/index-manager.js.map +1 -1
- package/dist/storage/index-schema.d.ts +1 -1
- package/dist/storage/index-schema.d.ts.map +1 -1
- package/dist/storage/index-schema.js +189 -8
- package/dist/storage/index-schema.js.map +1 -1
- package/dist/storage/legacy-scope-authority.d.ts +14 -0
- package/dist/storage/legacy-scope-authority.d.ts.map +1 -0
- package/dist/storage/legacy-scope-authority.js +298 -0
- package/dist/storage/legacy-scope-authority.js.map +1 -0
- package/dist/storage/node-data-storage.d.ts +6 -0
- package/dist/storage/node-data-storage.d.ts.map +1 -1
- package/dist/storage/node-data-storage.js +161 -2
- package/dist/storage/node-data-storage.js.map +1 -1
- package/dist/storage/pdpp-grant-binding-sqlite-store.d.ts +17 -0
- package/dist/storage/pdpp-grant-binding-sqlite-store.d.ts.map +1 -0
- package/dist/storage/pdpp-grant-binding-sqlite-store.js +159 -0
- package/dist/storage/pdpp-grant-binding-sqlite-store.js.map +1 -0
- package/dist/storage/pdpp-records-sqlite-store.d.ts +112 -0
- package/dist/storage/pdpp-records-sqlite-store.d.ts.map +1 -0
- package/dist/storage/pdpp-records-sqlite-store.js +1440 -0
- package/dist/storage/pdpp-records-sqlite-store.js.map +1 -0
- package/dist/storage/pdpp-stream-completion.d.ts +5 -0
- package/dist/storage/pdpp-stream-completion.d.ts.map +1 -0
- package/dist/storage/pdpp-stream-completion.js +10 -0
- package/dist/storage/pdpp-stream-completion.js.map +1 -0
- package/dist/storage/scope-deletion-history.d.ts +8 -0
- package/dist/storage/scope-deletion-history.d.ts.map +1 -0
- package/dist/storage/scope-deletion-history.js +40 -0
- package/dist/storage/scope-deletion-history.js.map +1 -0
- package/dist/ui/ps-lite-debug.js +3697 -876
- package/package.json +12 -4
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot the PDPP Authorization Server for a real Personal Server.
|
|
3
|
+
*
|
|
4
|
+
* This is the seam between "the AS exists as a library" and "this running
|
|
5
|
+
* server is a PDPP authorization server". It opens the persistent store,
|
|
6
|
+
* derives the declaration trust policy from what the deployment actually
|
|
7
|
+
* serves, and hands the route module the owner-proof wiring so consent
|
|
8
|
+
* decisions authenticate against the same wallet signature every other owner
|
|
9
|
+
* route uses.
|
|
10
|
+
*
|
|
11
|
+
* Returns undefined when PDPP is disabled and no connection registry is
|
|
12
|
+
* configured. It also returns undefined when no declarations or connection
|
|
13
|
+
* methods remain, so `/pdpp/v1` is mounted only when it can issue tokens.
|
|
14
|
+
*/
|
|
15
|
+
import { createHash } from "node:crypto";
|
|
16
|
+
import { readFile } from "node:fs/promises";
|
|
17
|
+
import { join, resolve } from "node:path";
|
|
18
|
+
import { AuthorizationSessionStore, declaredSourceId, openPdppAuthStore, PdppTokenService, resolveUrlHostedClientIdentity, UnsupportedAuthStateError, } from "@opendatalabs/personal-server-ts-core/pdpp";
|
|
19
|
+
import { boundedClientDocumentFetcher } from "./client-document-fetch.js";
|
|
20
|
+
import { resolveRetainedSourceId } from "./source-id-compat.js";
|
|
21
|
+
import { deriveSupportedConnectors, } from "./deployment.js";
|
|
22
|
+
import { openDeclarationRegistry, } from "./declaration-registry.js";
|
|
23
|
+
export async function createPdppAuthDeps(options) {
|
|
24
|
+
const { config, logger } = options;
|
|
25
|
+
const hasConnectionRegistry = (config.pdpp.connectionMethods?.length ?? 0) > 0;
|
|
26
|
+
if (!config.pdpp.enabled && !hasConnectionRegistry)
|
|
27
|
+
return undefined;
|
|
28
|
+
// The AS binds grants to a subject and authenticates decisions against the
|
|
29
|
+
// server owner. Without a known owner there is no subject to bind to and no
|
|
30
|
+
// signature to check, so refuse to mount rather than invent either.
|
|
31
|
+
if (!options.serverOwner) {
|
|
32
|
+
logger.warn("PDPP enabled but no server owner is configured — authorization server not mounted");
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
// The connector inventory is what this PS holds. It gates runtime
|
|
36
|
+
// submissions only. A configured declaration is admitted without it: the
|
|
37
|
+
// operator (Desktop, after verifying the signed artifact) chose it, and a
|
|
38
|
+
// fresh server that holds no legacy data yet must still mount it.
|
|
39
|
+
const { scopes } = options.indexManager.listDistinctScopes();
|
|
40
|
+
const supportedConnectors = deriveSupportedConnectors(scopes.map((s) => s.scope));
|
|
41
|
+
const declarations = await readDeclarations(config.pdpp.enabled ? config.pdpp.declarationPaths : [], logger);
|
|
42
|
+
const declarationSourceByPath = new Map(declarations
|
|
43
|
+
.filter((declaration) => declaration.path)
|
|
44
|
+
.map((declaration) => [resolve(declaration.path), declaration.sourceId]));
|
|
45
|
+
const configuredMethods = (config.pdpp.enabled ? config.pdpp.methods : []).flatMap((method) => {
|
|
46
|
+
const sourceId = declarationSourceByPath.get(resolve(method.declaration_path));
|
|
47
|
+
if (!sourceId) {
|
|
48
|
+
logger.warn({
|
|
49
|
+
declarationPath: method.declaration_path,
|
|
50
|
+
methodId: method.method_id,
|
|
51
|
+
}, "PDPP method does not reference a retained declaration — method is inactive");
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
return [{ sourceId, methodId: method.method_id }];
|
|
55
|
+
});
|
|
56
|
+
const connectionMethods = new Map();
|
|
57
|
+
for (const method of config.pdpp.connectionMethods ?? []) {
|
|
58
|
+
const methods = connectionMethods.get(method.source_id) ?? [];
|
|
59
|
+
methods.push(method.method_id);
|
|
60
|
+
connectionMethods.set(method.source_id, methods);
|
|
61
|
+
}
|
|
62
|
+
const connectionSourceIds = new Set(connectionMethods.keys());
|
|
63
|
+
// The durable registry the submission route writes to, seeded from the
|
|
64
|
+
// configured paths. Seeds and submissions share one validator; only
|
|
65
|
+
// submissions are held to the connector gate. A submitted declaration
|
|
66
|
+
// becomes resolvable in this lifetime and survives the next restart.
|
|
67
|
+
const declarationRegistry = openDeclarationRegistry({
|
|
68
|
+
path: join(options.storageRoot, "pdpp-declarations.db"),
|
|
69
|
+
supportedConnectors,
|
|
70
|
+
logger,
|
|
71
|
+
seed: declarations.map((d) => ({
|
|
72
|
+
sourceId: d.sourceId,
|
|
73
|
+
document: d.document,
|
|
74
|
+
})),
|
|
75
|
+
});
|
|
76
|
+
const registry = {
|
|
77
|
+
resolve: declarationRegistry.resolve,
|
|
78
|
+
retained: config.pdpp.enabled ? declarationRegistry.list() : [],
|
|
79
|
+
retainedDocuments: new Map(declarationRegistry
|
|
80
|
+
.list()
|
|
81
|
+
.map((snapshot) => [
|
|
82
|
+
snapshot.source_id,
|
|
83
|
+
declarationRegistry.documentFor(snapshot.source_id) ?? "",
|
|
84
|
+
])),
|
|
85
|
+
};
|
|
86
|
+
const retainedSourceIds = new Set(registry.retained.map((declaration) => declaration.source_id));
|
|
87
|
+
const activeConfiguredMethods = configuredMethods.filter((method) => retainedSourceIds.has(method.sourceId));
|
|
88
|
+
for (const method of activeConfiguredMethods) {
|
|
89
|
+
const methods = connectionMethods.get(method.sourceId) ?? [];
|
|
90
|
+
if (!methods.includes(method.methodId))
|
|
91
|
+
methods.push(method.methodId);
|
|
92
|
+
connectionMethods.set(method.sourceId, methods);
|
|
93
|
+
}
|
|
94
|
+
for (const sourceId of connectionMethods.keys()) {
|
|
95
|
+
connectionSourceIds.add(sourceId);
|
|
96
|
+
}
|
|
97
|
+
if (registry.retained.length === 0 && connectionSourceIds.size === 0) {
|
|
98
|
+
logger.warn({ supportedConnectors, configured: config.pdpp.declarationPaths.length }, "PDPP enabled but no declarations were retained — authorization server not mounted");
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
let store;
|
|
102
|
+
try {
|
|
103
|
+
store = openPdppAuthStore(join(options.storageRoot, "pdpp-auth.db"));
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
if (err instanceof UnsupportedAuthStateError) {
|
|
107
|
+
// §9 AS item 21: persisted authorization state whose contract this build
|
|
108
|
+
// cannot validate must not be reinterpreted. Refusing to mount is the
|
|
109
|
+
// conservative half of "migrate or require fresh consent" — the server
|
|
110
|
+
// keeps running, but it issues nothing against state it cannot read.
|
|
111
|
+
logger.error({ err: err.message }, "PDPP authorization state is unsupported — authorization server not mounted");
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
const tokens = new PdppTokenService(store);
|
|
117
|
+
const sessions = new AuthorizationSessionStore();
|
|
118
|
+
const subjectId = options.serverOwner.toLowerCase();
|
|
119
|
+
logger.info({
|
|
120
|
+
declarations: registry.retained.map((d) => d.source_id),
|
|
121
|
+
supportedConnectors,
|
|
122
|
+
requirePkce: config.pdpp.requirePkce,
|
|
123
|
+
}, "PDPP Authorization Server mounted at /pdpp/v1");
|
|
124
|
+
return {
|
|
125
|
+
logger,
|
|
126
|
+
store,
|
|
127
|
+
tokens,
|
|
128
|
+
sessions,
|
|
129
|
+
retainedDeclarations: registry.retained,
|
|
130
|
+
retainedDocuments: registry.retainedDocuments,
|
|
131
|
+
configuredMethods: activeConfiguredMethods,
|
|
132
|
+
connectionMethods,
|
|
133
|
+
resolveConnectionSourceId: (requested) => resolveRetainedSourceId(requested, connectionSourceIds),
|
|
134
|
+
resolveDeclaration: config.pdpp.enabled ? registry.resolve : () => null,
|
|
135
|
+
declarationRegistry,
|
|
136
|
+
supportedConnectors,
|
|
137
|
+
// The AS's own issuer identity, for its metadata document. Carried as the
|
|
138
|
+
// same thunk-or-string `serverOrigin` already is, so a deployment that
|
|
139
|
+
// resolves its origin late still advertises the live one.
|
|
140
|
+
issuer: options.serverOrigin,
|
|
141
|
+
// The records bootstrap replaces this with a live registry lookup once
|
|
142
|
+
// the shared SQLite store is available. Until then, no connection is
|
|
143
|
+
// eligible for consent.
|
|
144
|
+
inventoryFor: () => ({ eligibleFor: () => [] }),
|
|
145
|
+
/**
|
|
146
|
+
* Bind the session's subject to an *authenticated* owner.
|
|
147
|
+
*
|
|
148
|
+
* This PS is single-owner, so there is only ever one subject — but "there
|
|
149
|
+
* is one subject" and "any caller may open a session bound to it" are
|
|
150
|
+
* different claims, and the second is the one that was wrong. Previously
|
|
151
|
+
* this ignored the request entirely and returned the configured owner, so
|
|
152
|
+
* an unauthenticated caller could create sessions against the owner's
|
|
153
|
+
* subject: consent-screen spam and unbounded session allocation, even
|
|
154
|
+
* though approval still required a real owner token.
|
|
155
|
+
*
|
|
156
|
+
* Now the caller must present an active PDPP owner token, and the subject
|
|
157
|
+
* it resolves to must be the configured owner. Single-owner stays a
|
|
158
|
+
* deployment property; it stops being an authentication bypass.
|
|
159
|
+
*/
|
|
160
|
+
currentSubjectId: (c) => {
|
|
161
|
+
const header = c.req.header("authorization");
|
|
162
|
+
if (!header?.toLowerCase().startsWith("bearer "))
|
|
163
|
+
return null;
|
|
164
|
+
const presented = header.slice(7).trim();
|
|
165
|
+
if (presented.length === 0)
|
|
166
|
+
return null;
|
|
167
|
+
const context = tokens.resolveToken(presented);
|
|
168
|
+
if (!context.active || context.tokenKind !== "owner")
|
|
169
|
+
return null;
|
|
170
|
+
// A token for some other subject is not authority here, even though a
|
|
171
|
+
// single-owner deployment should never mint one.
|
|
172
|
+
if (context.subjectId !== subjectId)
|
|
173
|
+
return null;
|
|
174
|
+
return subjectId;
|
|
175
|
+
},
|
|
176
|
+
// Redirect targets are validated by exact match against this. A client
|
|
177
|
+
// absent from the config gets null, which fails the request closed — an
|
|
178
|
+
// unregistered client cannot receive an authorization code.
|
|
179
|
+
registeredClient: (clientId) => {
|
|
180
|
+
const registered = config.pdpp.clients.find((candidate) => candidate.clientId === clientId);
|
|
181
|
+
return registered
|
|
182
|
+
? {
|
|
183
|
+
client_id: registered.clientId,
|
|
184
|
+
redirect_uris: registered.redirectUris,
|
|
185
|
+
}
|
|
186
|
+
: null;
|
|
187
|
+
},
|
|
188
|
+
// Operator grant-lifetime policy, per registered client. Only a client
|
|
189
|
+
// with a `grantLifetimeSeconds` in config gets a computed expiry; every
|
|
190
|
+
// other client (including one resolved via `resolveClientIdentity`) gets
|
|
191
|
+
// `undefined` here, which preserves the existing no-expiry behavior
|
|
192
|
+
// exactly. This is deployment policy read from static config, never from
|
|
193
|
+
// the request — there is no client-supplied expiry field to honor.
|
|
194
|
+
grantExpiryFor: (_request, clientId) => {
|
|
195
|
+
const registered = config.pdpp.clients.find((candidate) => candidate.clientId === clientId);
|
|
196
|
+
const lifetimeSeconds = registered?.grantLifetimeSeconds;
|
|
197
|
+
if (!lifetimeSeconds)
|
|
198
|
+
return undefined;
|
|
199
|
+
return new Date(Date.now() + lifetimeSeconds * 1000).toISOString();
|
|
200
|
+
},
|
|
201
|
+
// §6 URL-hosted identity for a client NOT in `clients` above. Left
|
|
202
|
+
// unset (undefined, not a function that always fails) when the
|
|
203
|
+
// allowlist is empty, so this deployment performs no outbound fetch and
|
|
204
|
+
// the route's registration-only fallback runs exactly as it did before
|
|
205
|
+
// this path existed.
|
|
206
|
+
resolveClientIdentity: config.pdpp.urlHostedClientHosts.length > 0
|
|
207
|
+
? (clientId) => resolveUrlHostedClientIdentity({
|
|
208
|
+
clientId,
|
|
209
|
+
fetcher: boundedClientDocumentFetcher,
|
|
210
|
+
policy: { trustedHosts: config.pdpp.urlHostedClientHosts },
|
|
211
|
+
})
|
|
212
|
+
: undefined,
|
|
213
|
+
requirePkce: config.pdpp.requirePkce,
|
|
214
|
+
ownerAuth: {
|
|
215
|
+
serverOrigin: options.serverOrigin,
|
|
216
|
+
serverOwner: options.serverOwner,
|
|
217
|
+
devToken: options.devToken,
|
|
218
|
+
accessToken: options.accessToken,
|
|
219
|
+
tokenStore: options.tokenStore,
|
|
220
|
+
},
|
|
221
|
+
// The verified signer is the owner; normalize to the same subject the
|
|
222
|
+
// grants use so a token minted here resolves sessions created above.
|
|
223
|
+
ownerSubjectId: () => subjectId,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Read each configured declaration document.
|
|
228
|
+
*
|
|
229
|
+
* A path that cannot be read is logged and skipped rather than fatal: one
|
|
230
|
+
* bad declaration should not stop a server booting, and the registry will
|
|
231
|
+
* refuse to mount if nothing survives.
|
|
232
|
+
*/
|
|
233
|
+
async function readDeclarations(entries, logger) {
|
|
234
|
+
const out = [];
|
|
235
|
+
for (const entry of entries) {
|
|
236
|
+
const path = typeof entry === "string" ? entry : entry.path;
|
|
237
|
+
try {
|
|
238
|
+
const document = await readFile(path, "utf-8");
|
|
239
|
+
if (typeof entry !== "string") {
|
|
240
|
+
const actual = createHash("sha256")
|
|
241
|
+
.update(document, "utf8")
|
|
242
|
+
.digest("hex");
|
|
243
|
+
if (actual !== entry.sha256) {
|
|
244
|
+
logger.warn({ path, expected: entry.sha256, actual }, "PDPP declaration does not match its pinned digest — skipped");
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// The source id is the declaration's own claim; `parseDeclaration`
|
|
249
|
+
// cross-checks it, so read it here only to key the retention.
|
|
250
|
+
//
|
|
251
|
+
// Asking Core for the id rather than picking a field keeps the boot path
|
|
252
|
+
// shape-agnostic. Reading `source_id` directly meant a normative §5
|
|
253
|
+
// document -- which nests it under `source.id` -- was skipped here before
|
|
254
|
+
// the parser (which handles both) ever saw it, so the AS never mounted
|
|
255
|
+
// and the only evidence was a warning about a missing field the document
|
|
256
|
+
// was never supposed to have.
|
|
257
|
+
const sourceId = declaredSourceId(document);
|
|
258
|
+
if (sourceId === null) {
|
|
259
|
+
logger.warn({ path }, "PDPP declaration declares no source id — skipped");
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
out.push({ sourceId, document, path });
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
logger.warn({ path, err: err.message }, "PDPP declaration could not be read — skipped");
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return out;
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/pdpp/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAK1C,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,4CAA4C,CAAC;AAGpD,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EACL,yBAAyB,GAE1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,uBAAuB,GAExB,MAAM,2BAA2B,CAAC;AAkDnC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAkC;IAElC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACnC,MAAM,qBAAqB,GACzB,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,qBAAqB;QAAE,OAAO,SAAS,CAAC;IAErE,2EAA2E;IAC3E,4EAA4E;IAC5E,oEAAoE;IACpE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CACT,mFAAmF,CACpF,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,kEAAkE;IAClE,yEAAyE;IACzE,0EAA0E;IAC1E,kEAAkE;IAClE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC;IAC7D,MAAM,mBAAmB,GAAG,yBAAyB,CACnD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAC3B,CAAC;IAEF,MAAM,YAAY,GAAG,MAAM,gBAAgB,CACzC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,EACvD,MAAM,CACP,CAAC;IACF,MAAM,uBAAuB,GAAG,IAAI,GAAG,CACrC,YAAY;SACT,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC;SACzC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAK,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,CAC5E,CAAC;IACF,MAAM,iBAAiB,GAAG,CACxB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAC/C,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QACnB,MAAM,QAAQ,GAAG,uBAAuB,CAAC,GAAG,CAC1C,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,CACjC,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CACT;gBACE,eAAe,EAAE,MAAM,CAAC,gBAAgB;gBACxC,QAAQ,EAAE,MAAM,CAAC,SAAS;aAC3B,EACD,4EAA4E,CAC7E,CAAC;YACF,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAoB,CAAC;IACtD,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,EAAE,CAAC;QACzD,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/B,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC;IAE9D,uEAAuE;IACvE,oEAAoE;IACpE,sEAAsE;IACtE,qEAAqE;IACrE,MAAM,mBAAmB,GAAG,uBAAuB,CAAC;QAClD,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,sBAAsB,CAAC;QACvD,mBAAmB;QACnB,MAAM;QACN,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7B,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;SACrB,CAAC,CAAC;KACJ,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG;QACf,OAAO,EAAE,mBAAmB,CAAC,OAAO;QACpC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;QAC/D,iBAAiB,EAAE,IAAI,GAAG,CACxB,mBAAmB;aAChB,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;YACjB,QAAQ,CAAC,SAAS;YAClB,mBAAmB,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE;SAC1D,CAAC,CACL;KACF,CAAC;IAEF,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAC/B,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAC9D,CAAC;IACF,MAAM,uBAAuB,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAClE,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CACvC,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,uBAAuB,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACtE,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,KAAK,MAAM,QAAQ,IAAI,iBAAiB,CAAC,IAAI,EAAE,EAAE,CAAC;QAChD,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,mBAAmB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACrE,MAAM,CAAC,IAAI,CACT,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,EACxE,mFAAmF,CACpF,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,KAAK,CAAC;IACV,IAAI,CAAC;QACH,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,yBAAyB,EAAE,CAAC;YAC7C,yEAAyE;YACzE,sEAAsE;YACtE,uEAAuE;YACvE,qEAAqE;YACrE,MAAM,CAAC,KAAK,CACV,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,EACpB,4EAA4E,CAC7E,CAAC;YACF,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,yBAAyB,EAAE,CAAC;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IAEpD,MAAM,CAAC,IAAI,CACT;QACE,YAAY,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACvD,mBAAmB;QACnB,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW;KACrC,EACD,+CAA+C,CAChD,CAAC;IAEF,OAAO;QACL,MAAM;QACN,KAAK;QACL,MAAM;QACN,QAAQ;QACR,oBAAoB,EAAE,QAAQ,CAAC,QAAQ;QACvC,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;QAC7C,iBAAiB,EAAE,uBAAuB;QAC1C,iBAAiB;QACjB,yBAAyB,EAAE,CAAC,SAAS,EAAE,EAAE,CACvC,uBAAuB,CAAC,SAAS,EAAE,mBAAmB,CAAC;QACzD,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI;QACvE,mBAAmB;QACnB,mBAAmB;QACnB,0EAA0E;QAC1E,uEAAuE;QACvE,0DAA0D;QAC1D,MAAM,EAAE,OAAO,CAAC,YAAY;QAC5B,uEAAuE;QACvE,qEAAqE;QACrE,wBAAwB;QACxB,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C;;;;;;;;;;;;;;WAcG;QACH,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE;YACtB,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;YAC7C,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC9D,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACzC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAExC,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YAC/C,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,SAAS,KAAK,OAAO;gBAAE,OAAO,IAAI,CAAC;YAClE,sEAAsE;YACtE,iDAAiD;YACjD,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC;YACjD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,uEAAuE;QACvE,wEAAwE;QACxE,4DAA4D;QAC5D,gBAAgB,EAAE,CAAC,QAAQ,EAAE,EAAE;YAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CACzC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,KAAK,QAAQ,CAC/C,CAAC;YACF,OAAO,UAAU;gBACf,CAAC,CAAC;oBACE,SAAS,EAAE,UAAU,CAAC,QAAQ;oBAC9B,aAAa,EAAE,UAAU,CAAC,YAAY;iBACvC;gBACH,CAAC,CAAC,IAAI,CAAC;QACX,CAAC;QACD,uEAAuE;QACvE,wEAAwE;QACxE,yEAAyE;QACzE,oEAAoE;QACpE,yEAAyE;QACzE,mEAAmE;QACnE,cAAc,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE;YACrC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CACzC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,KAAK,QAAQ,CAC/C,CAAC;YACF,MAAM,eAAe,GAAG,UAAU,EAAE,oBAAoB,CAAC;YACzD,IAAI,CAAC,eAAe;gBAAE,OAAO,SAAS,CAAC;YACvC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACrE,CAAC;QACD,mEAAmE;QACnE,+DAA+D;QAC/D,wEAAwE;QACxE,uEAAuE;QACvE,qBAAqB;QACrB,qBAAqB,EACnB,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC;YACzC,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CACX,8BAA8B,CAAC;gBAC7B,QAAQ;gBACR,OAAO,EAAE,4BAA4B;gBACrC,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE;aAC3D,CAAC;YACN,CAAC,CAAC,SAAS;QACf,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW;QACpC,SAAS,EAAE;YACT,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B;QACD,sEAAsE;QACtE,qEAAqE;QACrE,cAAc,EAAE,GAAG,EAAE,CAAC,SAAS;KAChC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,gBAAgB,CAC7B,OAAiD,EACjD,MAAc;IAEd,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QAC5D,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC;qBAChC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC;qBACxB,MAAM,CAAC,KAAK,CAAC,CAAC;gBACjB,IAAI,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;oBAC5B,MAAM,CAAC,IAAI,CACT,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,EACxC,6DAA6D,CAC9D,CAAC;oBACF,SAAS;gBACX,CAAC;YACH,CAAC;YACD,mEAAmE;YACnE,8DAA8D;YAC9D,EAAE;YACF,yEAAyE;YACzE,oEAAoE;YACpE,0EAA0E;YAC1E,uEAAuE;YACvE,yEAAyE;YACzE,8BAA8B;YAC9B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAC5C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtB,MAAM,CAAC,IAAI,CACT,EAAE,IAAI,EAAE,EACR,kDAAkD,CACnD,CAAC;gBACF,SAAS;YACX,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CACT,EAAE,IAAI,EAAE,GAAG,EAAG,GAAa,CAAC,OAAO,EAAE,EACrC,8CAA8C,CAC/C,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enforcing the Vana chain permission on PDPP client reads.
|
|
3
|
+
*
|
|
4
|
+
* ## The gap this closes
|
|
5
|
+
*
|
|
6
|
+
* A PDPP access token proves the owner consented. It does not prove the Vana
|
|
7
|
+
* permission that authorizes the read is still live. Those are two authorities
|
|
8
|
+
* over two different objects, and the bearer read path checked only the first:
|
|
9
|
+
* it resolved a locally-issued token in-process and served records. So a
|
|
10
|
+
* permission revoked on chain kept reading fine through PDPP, and the ledger's
|
|
11
|
+
* authority was silently not enforced for any PDPP client.
|
|
12
|
+
*
|
|
13
|
+
* This adapter is the join. It looks up the retained binding for the presented
|
|
14
|
+
* PDPP grant, reads the chain grant live, and hands both to
|
|
15
|
+
* `verifyPdppGrantBinding`, which checks every axis at once: the record, the
|
|
16
|
+
* deployment, the owner, the grantee app, and revocation.
|
|
17
|
+
*
|
|
18
|
+
* ## Why the verification is not re-implemented here
|
|
19
|
+
*
|
|
20
|
+
* `packages/core/src/grants/pdpp-binding.ts` already does it, and correctly:
|
|
21
|
+
* bindings are keyed by the chain's own identity tuple rather than a derived
|
|
22
|
+
* hash, the record is append-only, and revocation is read live instead of
|
|
23
|
+
* mirrored into storage. Re-deriving any of that here would create a second
|
|
24
|
+
* opinion about what a valid binding is, and the two would drift. This file
|
|
25
|
+
* only supplies inputs and translates the outcome.
|
|
26
|
+
*
|
|
27
|
+
* `verifyPdppGrantBinding` checks revocation but NOT expiry — that axis is
|
|
28
|
+
* added here, immediately after it passes, using the same
|
|
29
|
+
* `parseGrantExpiresAtSeconds` the legacy chain-grant read path
|
|
30
|
+
* (`verifyDataReadPolicy`) uses. Without it, this bearer path would silently
|
|
31
|
+
* keep serving an expired-but-not-revoked grant that the legacy path already
|
|
32
|
+
* denies — a gap, not a design choice.
|
|
33
|
+
*
|
|
34
|
+
* ## Fail closed, and the retryable distinction
|
|
35
|
+
*
|
|
36
|
+
* Every denial path answers "no". The only judgment this file makes is whether
|
|
37
|
+
* a "no" is *definite* or merely *unknown*:
|
|
38
|
+
*
|
|
39
|
+
* - No binding, wrong owner, wrong grantee, revoked, expired → definite.
|
|
40
|
+
* Asking again changes nothing.
|
|
41
|
+
* - Gateway unreachable, RPC timeout, malformed response → unknown.
|
|
42
|
+
*
|
|
43
|
+
* Unknown must still deny. Not knowing is not permission, and an outage that
|
|
44
|
+
* opened reads would be an authorization bypass that nobody notices, because
|
|
45
|
+
* the reads all look successful. What unknown gets is a *retryable* answer, so
|
|
46
|
+
* the route can say "try again" rather than "your grant is dead" to a client
|
|
47
|
+
* whose grant is probably fine.
|
|
48
|
+
*
|
|
49
|
+
* A missing binding is deliberately in the definite-denial bucket, not the
|
|
50
|
+
* unknown one. "Not bound yet" and "never bound" are indistinguishable from
|
|
51
|
+
* here, so treating absence as a temporary condition would let an unbound
|
|
52
|
+
* grant read for as long as a caller kept retrying.
|
|
53
|
+
*/
|
|
54
|
+
import { type PdppGrantBindingStore } from "@opendatalabs/personal-server-ts-core/grants";
|
|
55
|
+
import type { GatewayGrantResponse } from "@opendatalabs/vana-sdk/browser";
|
|
56
|
+
import type { Logger } from "pino";
|
|
57
|
+
import type { PdppChainEnforcementPort } from "../routes/pdpp-records.js";
|
|
58
|
+
export interface ChainEnforcementOptions {
|
|
59
|
+
/** Retained bindings, written at grant creation. */
|
|
60
|
+
bindings: PdppGrantBindingStore;
|
|
61
|
+
/**
|
|
62
|
+
* Reads the chain grant as it stands NOW. Returning null means "this
|
|
63
|
+
* permission does not exist", which `verifyPdppGrantBinding` treats as
|
|
64
|
+
* revoked; THROWING means "I could not find out", which is retryable.
|
|
65
|
+
*
|
|
66
|
+
* The two are different answers and must not be collapsed: a gateway that
|
|
67
|
+
* returns null on a network error would turn every outage into a permanent
|
|
68
|
+
* revocation for every client.
|
|
69
|
+
*/
|
|
70
|
+
readChainGrant(permissionId: string): Promise<GatewayGrantResponse | null>;
|
|
71
|
+
/** The owner this server is configured for, at read time. */
|
|
72
|
+
serverOwner: `0x${string}`;
|
|
73
|
+
/** The deployment the PS is configured against. */
|
|
74
|
+
deployment: {
|
|
75
|
+
chainId: number;
|
|
76
|
+
contractAddress: `0x${string}`;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* The app's grantee wallet address for a given PDPP `client_id`.
|
|
80
|
+
*
|
|
81
|
+
* Resolved per request rather than taken from the binding, because this is
|
|
82
|
+
* the half that proves the CALLER is the bound app rather than merely
|
|
83
|
+
* knowing its grant id. Returning null denies.
|
|
84
|
+
*/
|
|
85
|
+
granteeAddressFor(clientId: string): `0x${string}` | null;
|
|
86
|
+
logger: Logger;
|
|
87
|
+
/**
|
|
88
|
+
* Deterministic clock for expiry comparisons. Defaults to the real clock;
|
|
89
|
+
* tests inject a fixed value so expiry assertions aren't a race against
|
|
90
|
+
* wall time.
|
|
91
|
+
*/
|
|
92
|
+
now?: () => Date;
|
|
93
|
+
}
|
|
94
|
+
export declare function chainPermissionEnforcement(options: ChainEnforcementOptions): PdppChainEnforcementPort;
|
|
95
|
+
//# sourceMappingURL=chain-enforcement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain-enforcement.d.ts","sourceRoot":"","sources":["../../src/pdpp/chain-enforcement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,8CAA8C,CAAC;AAEtD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAEV,wBAAwB,EACzB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,uBAAuB;IACtC,oDAAoD;IACpD,QAAQ,EAAE,qBAAqB,CAAC;IAChC;;;;;;;;OAQG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;IAC3E,6DAA6D;IAC7D,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;IAC3B,mDAAmD;IACnD,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,KAAK,MAAM,EAAE,CAAA;KAAE,CAAC;IAChE;;;;;;OAMG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,uBAAuB,GAC/B,wBAAwB,CAmG1B"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enforcing the Vana chain permission on PDPP client reads.
|
|
3
|
+
*
|
|
4
|
+
* ## The gap this closes
|
|
5
|
+
*
|
|
6
|
+
* A PDPP access token proves the owner consented. It does not prove the Vana
|
|
7
|
+
* permission that authorizes the read is still live. Those are two authorities
|
|
8
|
+
* over two different objects, and the bearer read path checked only the first:
|
|
9
|
+
* it resolved a locally-issued token in-process and served records. So a
|
|
10
|
+
* permission revoked on chain kept reading fine through PDPP, and the ledger's
|
|
11
|
+
* authority was silently not enforced for any PDPP client.
|
|
12
|
+
*
|
|
13
|
+
* This adapter is the join. It looks up the retained binding for the presented
|
|
14
|
+
* PDPP grant, reads the chain grant live, and hands both to
|
|
15
|
+
* `verifyPdppGrantBinding`, which checks every axis at once: the record, the
|
|
16
|
+
* deployment, the owner, the grantee app, and revocation.
|
|
17
|
+
*
|
|
18
|
+
* ## Why the verification is not re-implemented here
|
|
19
|
+
*
|
|
20
|
+
* `packages/core/src/grants/pdpp-binding.ts` already does it, and correctly:
|
|
21
|
+
* bindings are keyed by the chain's own identity tuple rather than a derived
|
|
22
|
+
* hash, the record is append-only, and revocation is read live instead of
|
|
23
|
+
* mirrored into storage. Re-deriving any of that here would create a second
|
|
24
|
+
* opinion about what a valid binding is, and the two would drift. This file
|
|
25
|
+
* only supplies inputs and translates the outcome.
|
|
26
|
+
*
|
|
27
|
+
* `verifyPdppGrantBinding` checks revocation but NOT expiry — that axis is
|
|
28
|
+
* added here, immediately after it passes, using the same
|
|
29
|
+
* `parseGrantExpiresAtSeconds` the legacy chain-grant read path
|
|
30
|
+
* (`verifyDataReadPolicy`) uses. Without it, this bearer path would silently
|
|
31
|
+
* keep serving an expired-but-not-revoked grant that the legacy path already
|
|
32
|
+
* denies — a gap, not a design choice.
|
|
33
|
+
*
|
|
34
|
+
* ## Fail closed, and the retryable distinction
|
|
35
|
+
*
|
|
36
|
+
* Every denial path answers "no". The only judgment this file makes is whether
|
|
37
|
+
* a "no" is *definite* or merely *unknown*:
|
|
38
|
+
*
|
|
39
|
+
* - No binding, wrong owner, wrong grantee, revoked, expired → definite.
|
|
40
|
+
* Asking again changes nothing.
|
|
41
|
+
* - Gateway unreachable, RPC timeout, malformed response → unknown.
|
|
42
|
+
*
|
|
43
|
+
* Unknown must still deny. Not knowing is not permission, and an outage that
|
|
44
|
+
* opened reads would be an authorization bypass that nobody notices, because
|
|
45
|
+
* the reads all look successful. What unknown gets is a *retryable* answer, so
|
|
46
|
+
* the route can say "try again" rather than "your grant is dead" to a client
|
|
47
|
+
* whose grant is probably fine.
|
|
48
|
+
*
|
|
49
|
+
* A missing binding is deliberately in the definite-denial bucket, not the
|
|
50
|
+
* unknown one. "Not bound yet" and "never bound" are indistinguishable from
|
|
51
|
+
* here, so treating absence as a temporary condition would let an unbound
|
|
52
|
+
* grant read for as long as a caller kept retrying.
|
|
53
|
+
*/
|
|
54
|
+
import { verifyPdppGrantBinding, } from "@opendatalabs/personal-server-ts-core/grants";
|
|
55
|
+
import { parseGrantExpiresAtSeconds } from "@opendatalabs/personal-server-ts-core/policy";
|
|
56
|
+
export function chainPermissionEnforcement(options) {
|
|
57
|
+
const { bindings, deployment, logger, serverOwner } = options;
|
|
58
|
+
return {
|
|
59
|
+
async authorize({ clientId, pdppGrantId }) {
|
|
60
|
+
const binding = bindings.getByPdppGrantId(pdppGrantId);
|
|
61
|
+
if (!binding) {
|
|
62
|
+
// Definite: absence of a binding is not a pending state.
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
reason: "No chain binding for this grant",
|
|
66
|
+
retryable: false,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const granteeAddress = options.granteeAddressFor(clientId);
|
|
70
|
+
if (!granteeAddress) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
reason: "No grantee address for this client",
|
|
74
|
+
retryable: false,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
let chainGrant;
|
|
78
|
+
try {
|
|
79
|
+
chainGrant = await options.readChainGrant(binding.permission.permissionId);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
// Unknown, not denied. Logged at warn because a persistent unknown is
|
|
83
|
+
// an outage worth paging on, and it is invisible in the response.
|
|
84
|
+
logger.warn({
|
|
85
|
+
err: err.message,
|
|
86
|
+
permissionId: binding.permission.permissionId,
|
|
87
|
+
pdppGrantId,
|
|
88
|
+
}, "PDPP chain enforcement: could not read chain grant");
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
reason: "Chain grant could not be read",
|
|
92
|
+
retryable: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
verifyPdppGrantBinding({
|
|
97
|
+
binding,
|
|
98
|
+
chainGrant,
|
|
99
|
+
deployment,
|
|
100
|
+
pdppGrantId,
|
|
101
|
+
// The caller proves it is the app by being the bound grantee. On the
|
|
102
|
+
// bearer path the token IS the proof of which client is calling, so
|
|
103
|
+
// the resolved address for that client_id stands in for a signature.
|
|
104
|
+
requestSigner: granteeAddress,
|
|
105
|
+
serverOwner,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
// Every failure here is definite: owner mismatch, grantee mismatch,
|
|
110
|
+
// wrong deployment, or revocation. None improve on retry.
|
|
111
|
+
return {
|
|
112
|
+
ok: false,
|
|
113
|
+
reason: err.message,
|
|
114
|
+
retryable: false,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// `verifyPdppGrantBinding` does not check expiry — it only checks
|
|
118
|
+
// revocation. The legacy `/v1/data/:scope` chain-grant read path
|
|
119
|
+
// (`verifyDataReadPolicy`) enforces `grant.expiresAt`; this bearer path
|
|
120
|
+
// must not silently skip a check that path already makes. `chainGrant`
|
|
121
|
+
// is non-null here (a null grant already returned above via
|
|
122
|
+
// `verifyPdppGrantBinding`'s "not found = revoked" check).
|
|
123
|
+
const expiresAtSec = parseGrantExpiresAtSeconds(chainGrant.expiresAt);
|
|
124
|
+
if (expiresAtSec === null) {
|
|
125
|
+
return {
|
|
126
|
+
ok: false,
|
|
127
|
+
reason: "Grant expiry is invalid",
|
|
128
|
+
retryable: false,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (expiresAtSec > 0) {
|
|
132
|
+
const nowSec = Math.floor((options.now?.() ?? new Date()).getTime() / 1000);
|
|
133
|
+
if (expiresAtSec < nowSec) {
|
|
134
|
+
return {
|
|
135
|
+
ok: false,
|
|
136
|
+
reason: "Grant has expired",
|
|
137
|
+
retryable: false,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { ok: true };
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=chain-enforcement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain-enforcement.js","sourceRoot":"","sources":["../../src/pdpp/chain-enforcement.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded production fetcher for a URL-hosted client identity document
|
|
3
|
+
* (Core §6). Implements `ClientDocumentFetcher` from
|
|
4
|
+
* `@opendatalabs/personal-server-ts-core/pdpp`.
|
|
5
|
+
*
|
|
6
|
+
* Invariants:
|
|
7
|
+
* - HTTPS only.
|
|
8
|
+
* - Every address actually dialed is checked: a hostname's DNS answers via
|
|
9
|
+
* a custom `lookup` on the `undici` dispatcher (defends DNS rebinding —
|
|
10
|
+
* `net`/`tls`/`undici` dial exactly the address `lookup` returns, so
|
|
11
|
+
* there is no separate resolution to race), and a literal-IP URL
|
|
12
|
+
* hostname separately, since that never reaches `dns.lookup` at all.
|
|
13
|
+
* - No redirect is followed; a redirect or an oversized/rejected body is
|
|
14
|
+
* drained (`discardBody`), never left dangling on the socket.
|
|
15
|
+
* - One `AbortSignal`/timeout spans connect + headers + body + cleanup.
|
|
16
|
+
* - The body is read incrementally and dropped past the byte cap.
|
|
17
|
+
* - No credentials are forwarded.
|
|
18
|
+
*/
|
|
19
|
+
import { Agent } from "undici";
|
|
20
|
+
import type { ClientDocumentFetcher } from "@opendatalabs/personal-server-ts-core/pdpp";
|
|
21
|
+
export declare const FETCH_TIMEOUT_MS = 5000;
|
|
22
|
+
export declare const MAX_RESPONSE_BYTES: number;
|
|
23
|
+
/** Thrown by the connect-time guard; surfaces as a `fetch_failed` result. */
|
|
24
|
+
export declare class BlockedAddressError extends Error {
|
|
25
|
+
}
|
|
26
|
+
export declare function isBlockedAddress(address: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Build a dispatcher that only ever connects to an address that passes the
|
|
29
|
+
* guard, bundled with the exact predicate it was built with so a caller
|
|
30
|
+
* can't pass a mismatched one to the pre-dial literal-IP check in
|
|
31
|
+
* {@link createBoundedFetcher}. `tlsOpts` is exposed solely so tests can
|
|
32
|
+
* trust a local self-signed certificate; `isBlocked` lets tests run against
|
|
33
|
+
* loopback without disabling the guard mechanism itself. Production code
|
|
34
|
+
* must call {@link boundedClientDocumentFetcher}, which passes neither.
|
|
35
|
+
*/
|
|
36
|
+
declare function buildGuardedAgent(tlsOpts?: {
|
|
37
|
+
ca?: string | Buffer;
|
|
38
|
+
isBlocked?: (address: string) => boolean;
|
|
39
|
+
}): {
|
|
40
|
+
dispatcher: Agent;
|
|
41
|
+
isBlocked: (address: string) => boolean;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Build a bounded `ClientDocumentFetcher`. HTTPS-only, no redirects, one
|
|
45
|
+
* connect+headers+body timeout, a streamed byte cap, and address validation
|
|
46
|
+
* on every DNS answer *and* on a literal-IP hostname (which never reaches
|
|
47
|
+
* `dns.lookup`, so the dispatcher's guarded `lookup` alone would miss it).
|
|
48
|
+
*
|
|
49
|
+
* Takes {@link buildGuardedAgent}'s return value as a whole (not just its
|
|
50
|
+
* `dispatcher`) so the pre-dial literal-IP check always uses the exact same
|
|
51
|
+
* predicate the dispatcher's `lookup` guard was built with — there is no
|
|
52
|
+
* call shape that lets the two diverge.
|
|
53
|
+
*/
|
|
54
|
+
declare function createBoundedFetcher({ dispatcher, isBlocked, }: ReturnType<typeof buildGuardedAgent>): ClientDocumentFetcher;
|
|
55
|
+
/** The production fetcher: no test-only overrides reach this path. */
|
|
56
|
+
export declare const boundedClientDocumentFetcher: ClientDocumentFetcher;
|
|
57
|
+
/** Test-only seam: same bounds, with a dispatcher that trusts a test CA. */
|
|
58
|
+
export declare const __testing: {
|
|
59
|
+
createBoundedFetcher: typeof createBoundedFetcher;
|
|
60
|
+
buildGuardedAgent: typeof buildGuardedAgent;
|
|
61
|
+
};
|
|
62
|
+
export {};
|
|
63
|
+
//# sourceMappingURL=client-document-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-document-fetch.d.ts","sourceRoot":"","sources":["../../src/pdpp/client-document-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAAE,KAAK,EAAwB,MAAM,QAAQ,CAAC;AAGrD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AAExF,eAAO,MAAM,gBAAgB,OAAQ,CAAC;AACtC,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAE5C,6EAA6E;AAC7E,qBAAa,mBAAoB,SAAQ,KAAK;CAAG;AAyCjD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIzD;AAwED;;;;;;;;GAQG;AACH,iBAAS,iBAAiB,CAAC,OAAO,CAAC,EAAE;IACnC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;CAC1C,GAAG;IAAE,UAAU,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,CAQjE;AAwCD;;;;;;;;;;GAUG;AACH,iBAAS,oBAAoB,CAAC,EAC5B,UAAU,EACV,SAAS,GACV,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,GAAG,qBAAqB,CAwD9D;AAmBD,sEAAsE;AACtE,eAAO,MAAM,4BAA4B,EAAE,qBACZ,CAAC;AAEhC,4EAA4E;AAC5E,eAAO,MAAM,SAAS;;;CAA8C,CAAC"}
|