@powerhousedao/switchboard 6.2.2-dev.9 → 6.2.2-staging.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/.gitignore +41 -0
- package/.npmignore +2 -0
- package/.tsbuild/test/attachment-reference-read-model.test.d.ts +2 -0
- package/.tsbuild/test/attachment-reference-read-model.test.d.ts.map +1 -0
- package/.tsbuild/test/attachments/download-target.test.d.ts +2 -0
- package/.tsbuild/test/attachments/download-target.test.d.ts.map +1 -0
- package/.tsbuild/test/reactor-feature-flags.test.d.ts +2 -0
- package/.tsbuild/test/reactor-feature-flags.test.d.ts.map +1 -0
- package/.tsbuild/tsconfig.tsbuildinfo +1 -1
- package/Auth.md +107 -1
- package/CHANGELOG.md +587 -0
- package/README.md +44 -2
- package/dist/index.mjs +10 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{server-Cgud_ONM.mjs → server-DYraD11D.mjs} +364 -48
- package/dist/server-DYraD11D.mjs.map +1 -0
- package/dist/server.d.mts +9 -5
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +3 -3
- package/package.json +14 -13
- package/test/attachment-reference-read-model.test.ts +425 -0
- package/test/attachments/auth.test.ts +138 -8
- package/test/attachments/download-target.test.ts +450 -0
- package/test/attachments/index.test.ts +37 -2
- package/test/attachments/routes-integration.test.ts +98 -1
- package/test/reactor-feature-flags.test.ts +61 -0
- package/test/worker-pool.test.ts +27 -0
- package/tsconfig.json +3 -0
- package/dist/server-Cgud_ONM.mjs.map +0 -1
package/Auth.md
CHANGED
|
@@ -112,7 +112,7 @@ interface VerifiableCredential {
|
|
|
112
112
|
1. **Token Decoding**: Extract credential information from JWT
|
|
113
113
|
2. **Credential Validation**: Verify against W3C standards
|
|
114
114
|
3. **Issuer Verification**: Check credential issuer authenticity
|
|
115
|
-
4. **
|
|
115
|
+
4. **Credential Existence Check**: Validate credential still exists and is valid — against a remote Renown/Switchboard or this switchboard's own read model (see [Which Renown Instance Is Used](#which-renown-instance-is-used))
|
|
116
116
|
5. **User Extraction**: Create user object from verified credentials
|
|
117
117
|
|
|
118
118
|
### 5. **Authorization**
|
|
@@ -173,6 +173,54 @@ export AUTH_ENABLED=true
|
|
|
173
173
|
export ADMINS="0x111,0x222,0x333"
|
|
174
174
|
```
|
|
175
175
|
|
|
176
|
+
`AUTH_ENABLED` does two things: it selects the authorization policy
|
|
177
|
+
(`ADMIN_ONLY` instead of `OPEN`) **and** it makes the middleware verify the
|
|
178
|
+
bearer so `ctx.user` is populated. `RESOLVE_CALLER_IDENTITY` separates the
|
|
179
|
+
second from the first:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Read the bearer and populate ctx.user, whatever the policy is
|
|
183
|
+
export RESOLVE_CALLER_IDENTITY=true
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
| | `AUTH_ENABLED` unset | `AUTH_ENABLED=true` |
|
|
187
|
+
| -------------------------------- | -------------------------- | ------------------------------- |
|
|
188
|
+
| `RESOLVE_CALLER_IDENTITY` unset | no user, `OPEN` | user resolved, `ADMIN_ONLY` |
|
|
189
|
+
| `RESOLVE_CALLER_IDENTITY=true` | **user resolved, `OPEN`** | user resolved, `ADMIN_ONLY` |
|
|
190
|
+
|
|
191
|
+
It defaults to whatever `AUTH_ENABLED` is, so a deployment that never sets it
|
|
192
|
+
behaves exactly as before. The bold cell is the combination `AUTH_ENABLED`
|
|
193
|
+
alone cannot express, and the one a custom subgraph needs when it does its own
|
|
194
|
+
authorization: its resolvers learn who is calling without every non-admin
|
|
195
|
+
being locked out of switchboard.
|
|
196
|
+
|
|
197
|
+
It **resolves** an identity and enforces nothing — a request with no token is
|
|
198
|
+
still admitted, with no user. Verification is otherwise identical to
|
|
199
|
+
`AUTH_ENABLED=true`, Renown credential check included, so an invalid token is
|
|
200
|
+
still a 401.
|
|
201
|
+
|
|
202
|
+
That last property is the hole `REQUIRE_AUTHENTICATED_CALLER` closes: it
|
|
203
|
+
turns the same resolved identity into enforcement.
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Admit authenticated callers, reject anonymous ones with a 401
|
|
207
|
+
export REQUIRE_AUTHENTICATED_CALLER=true
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
It defaults to off, so nothing changes for existing deployments. When on,
|
|
211
|
+
every GraphQL request without a resolved caller — subgraphs, the supergraph,
|
|
212
|
+
and the SSE subscription endpoint alike — is answered with a `401`
|
|
213
|
+
(`{"error": "Authentication required"}`) before any resolver runs. It is the
|
|
214
|
+
one switch that expresses "authenticated callers allowed, anonymous not":
|
|
215
|
+
under `OPEN` the policy itself answers `true` to everything, and
|
|
216
|
+
`ADMIN_ONLY` locks out every non-admin, so neither can do this on its own.
|
|
217
|
+
CORS preflights (`OPTIONS`) are still admitted, as they never carry a token.
|
|
218
|
+
|
|
219
|
+
It requires a caller to be resolvable at all, so it refuses to boot without
|
|
220
|
+
`RESOLVE_CALLER_IDENTITY=true` or `AUTH_ENABLED=true` — with identity
|
|
221
|
+
resolution off, no bearer is ever read and it would reject every caller,
|
|
222
|
+
including authenticated ones.
|
|
223
|
+
|
|
176
224
|
#### Configuration File Method
|
|
177
225
|
|
|
178
226
|
```json
|
|
@@ -184,6 +232,64 @@ export ADMINS="0x111,0x222,0x333"
|
|
|
184
232
|
}
|
|
185
233
|
```
|
|
186
234
|
|
|
235
|
+
#### Which Renown Instance Is Used
|
|
236
|
+
|
|
237
|
+
Step 4 of the verification process re-checks that the signer's Renown credential
|
|
238
|
+
still exists. `auth.renown` says which instance answers that question:
|
|
239
|
+
|
|
240
|
+
```json
|
|
241
|
+
{
|
|
242
|
+
"auth": {
|
|
243
|
+
"enabled": true,
|
|
244
|
+
"admins": ["0x111"],
|
|
245
|
+
"renown": {
|
|
246
|
+
"source": "remote",
|
|
247
|
+
"url": "https://renown.acme.io",
|
|
248
|
+
"switchboardUrl": "https://sb.acme.io/graphql"
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
| Field | Env override | Meaning |
|
|
255
|
+
| --- | --- | --- |
|
|
256
|
+
| `source` | `RENOWN_SOURCE` | `remote` (default) queries another instance; `self` reads this switchboard's own `renown-read-model` subgraph in-process. |
|
|
257
|
+
| `url` | `RENOWN_URL` | Renown base URL, used for discovery and the REST fallback. Defaults to `https://www.renown.id`. |
|
|
258
|
+
| `switchboardUrl` | `SWITCHBOARD_URL` | A switchboard's GraphQL endpoint to read credentials from directly, skipping discovery. |
|
|
259
|
+
|
|
260
|
+
Env vars win over the config file field by field; a blank value counts as unset.
|
|
261
|
+
With `source: "remote"` the order is `switchboardUrl`, then discovery via `url`,
|
|
262
|
+
then the Renown REST API at `url`. With `source: "self"` both URLs are ignored
|
|
263
|
+
for verification — but `url` still applies to this switchboard's own identity
|
|
264
|
+
(below).
|
|
265
|
+
|
|
266
|
+
Either way the credential's EIP-712 proof is re-verified and expiry and
|
|
267
|
+
delegation binding are re-checked, so a locally stored credential is held to the
|
|
268
|
+
same standard as a remote one. Successful checks are cached per identity for
|
|
269
|
+
`CREDENTIAL_VERIFICATION_CACHE_TTL_MS` (60s default) in both modes, so
|
|
270
|
+
revocation still lags by up to that TTL.
|
|
271
|
+
|
|
272
|
+
`self` requires a loaded package that provides the `renown-read-model` subgraph
|
|
273
|
+
(`@powerhousedao/renown-package`). Startup fails if none does, rather than booting
|
|
274
|
+
a switchboard that rejects every authenticated request.
|
|
275
|
+
|
|
276
|
+
Where the pieces live: `@renown/sdk` owns the read-model contract
|
|
277
|
+
(`RENOWN_READ_MODEL_SUBGRAPH`, `createLocalCredentialVerifier`), this app wires
|
|
278
|
+
it to the running reactor after the API is up, and `reactor-api` only supplies
|
|
279
|
+
the generic `GraphQLManager.executeSubgraphQuery` plus an injectable
|
|
280
|
+
`verifyCredential` — core has no knowledge of the renown package. A host that
|
|
281
|
+
sets `source: "self"` without injecting a verifier is refused at boot rather
|
|
282
|
+
than silently verified against a remote Renown.
|
|
283
|
+
|
|
284
|
+
#### The Switchboard's Own Identity
|
|
285
|
+
|
|
286
|
+
Separately from verifying incoming credentials, a switchboard has its own
|
|
287
|
+
identity — the `ph login` keypair it uses to authenticate *outbound* to remote
|
|
288
|
+
drives and services. It authenticates against `auth.renown.url` too, so one
|
|
289
|
+
setting covers both directions. Pass `identity.baseUrl` when starting the server
|
|
290
|
+
to point it somewhere else; unset everywhere, it falls back to
|
|
291
|
+
`https://www.renown.id`.
|
|
292
|
+
|
|
187
293
|
### 2. **Frontend Integration**
|
|
188
294
|
|
|
189
295
|
#### Using the useAuth Hook
|