@tinycloud/node-sdk 3.1.0-beta.1 → 3.1.0-beta.11
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/{core-Bm76PnOz.d.cts → core-CJiLya1s.d.cts} +80 -6
- package/dist/{core-Bm76PnOz.d.ts → core-CJiLya1s.d.ts} +80 -6
- package/dist/core.cjs +348 -137
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +354 -138
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +406 -169
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +412 -171
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/core.cjs
CHANGED
|
@@ -336,6 +336,10 @@ var defaultSignStrategy = { type: "auto-sign" };
|
|
|
336
336
|
// src/authorization/NodeUserAuthorization.ts
|
|
337
337
|
var DECRYPT_ACTION = import_sdk_core3.ENCRYPTION.DECRYPT;
|
|
338
338
|
var NETWORK_CREATE_ACTION = import_sdk_core3.ENCRYPTION.NETWORK_CREATE;
|
|
339
|
+
function describeHostFailure(result) {
|
|
340
|
+
const text = result.error?.trim();
|
|
341
|
+
return text ? `${result.status} - ${text}` : `${result.status}`;
|
|
342
|
+
}
|
|
339
343
|
function canonicalizeOpenKeyManifestJson(value) {
|
|
340
344
|
const json = JSON.stringify(value);
|
|
341
345
|
if (json === void 0) {
|
|
@@ -864,10 +868,12 @@ var NodeUserAuthorization = class {
|
|
|
864
868
|
return;
|
|
865
869
|
}
|
|
866
870
|
try {
|
|
867
|
-
const created =
|
|
868
|
-
if (!created) {
|
|
869
|
-
const err =
|
|
870
|
-
|
|
871
|
+
const created = await this.hostSpace();
|
|
872
|
+
if (!created.success) {
|
|
873
|
+
const err = Object.assign(
|
|
874
|
+
new Error(`Failed to create space ${primarySpaceId}: ${describeHostFailure(created)}`),
|
|
875
|
+
{ cause: created }
|
|
876
|
+
);
|
|
871
877
|
throw err;
|
|
872
878
|
}
|
|
873
879
|
} catch (error) {
|
|
@@ -883,8 +889,9 @@ var NodeUserAuthorization = class {
|
|
|
883
889
|
this._tinyCloudSession.delegationHeader
|
|
884
890
|
);
|
|
885
891
|
if (!retryResult.success) {
|
|
886
|
-
const err =
|
|
887
|
-
`Failed to activate session after creating space: ${retryResult
|
|
892
|
+
const err = Object.assign(
|
|
893
|
+
new Error(`Failed to activate session after creating space: ${describeHostFailure(retryResult)}`),
|
|
894
|
+
{ cause: retryResult }
|
|
888
895
|
);
|
|
889
896
|
handler.onSpaceCreationFailed?.(creationContext, err);
|
|
890
897
|
throw err;
|
|
@@ -901,10 +908,12 @@ var NodeUserAuthorization = class {
|
|
|
901
908
|
return;
|
|
902
909
|
}
|
|
903
910
|
try {
|
|
904
|
-
const created =
|
|
905
|
-
if (!created) {
|
|
906
|
-
const err =
|
|
907
|
-
|
|
911
|
+
const created = await this.hostSpace();
|
|
912
|
+
if (!created.success) {
|
|
913
|
+
const err = Object.assign(
|
|
914
|
+
new Error(`Failed to create space ${primarySpaceId}: ${describeHostFailure(created)}`),
|
|
915
|
+
{ cause: created }
|
|
916
|
+
);
|
|
908
917
|
throw err;
|
|
909
918
|
}
|
|
910
919
|
} catch (error) {
|
|
@@ -920,8 +929,9 @@ var NodeUserAuthorization = class {
|
|
|
920
929
|
this._tinyCloudSession.delegationHeader
|
|
921
930
|
);
|
|
922
931
|
if (!retryResult.success) {
|
|
923
|
-
const err =
|
|
924
|
-
`Failed to activate session after creating space: ${retryResult
|
|
932
|
+
const err = Object.assign(
|
|
933
|
+
new Error(`Failed to activate session after creating space: ${describeHostFailure(retryResult)}`),
|
|
934
|
+
{ cause: retryResult }
|
|
925
935
|
);
|
|
926
936
|
handler.onSpaceCreationFailed?.(creationContext, err);
|
|
927
937
|
throw err;
|
|
@@ -929,7 +939,10 @@ var NodeUserAuthorization = class {
|
|
|
929
939
|
handler.onSpaceCreated?.(creationContext);
|
|
930
940
|
return;
|
|
931
941
|
}
|
|
932
|
-
throw
|
|
942
|
+
throw Object.assign(
|
|
943
|
+
new Error(`Failed to activate session: ${describeHostFailure(result)}`),
|
|
944
|
+
{ cause: result }
|
|
945
|
+
);
|
|
933
946
|
}
|
|
934
947
|
recordActivationSkippedSpaces(result, primarySpaceId) {
|
|
935
948
|
if (result.success) {
|
|
@@ -1719,14 +1732,14 @@ var NodeUserAuthorization = class {
|
|
|
1719
1732
|
* Request signature via event emitter with timeout.
|
|
1720
1733
|
*/
|
|
1721
1734
|
requestSignatureViaEmitter(request, emitter, timeout) {
|
|
1722
|
-
return new Promise((resolve,
|
|
1735
|
+
return new Promise((resolve, reject2) => {
|
|
1723
1736
|
const timeoutId = setTimeout(() => {
|
|
1724
|
-
|
|
1737
|
+
reject2(new Error("Sign request timed out"));
|
|
1725
1738
|
}, timeout);
|
|
1726
1739
|
const respond = async (response) => {
|
|
1727
1740
|
clearTimeout(timeoutId);
|
|
1728
1741
|
if (!response.approved) {
|
|
1729
|
-
|
|
1742
|
+
reject2(
|
|
1730
1743
|
new Error(response.reason ?? "Sign request rejected via emitter")
|
|
1731
1744
|
);
|
|
1732
1745
|
} else {
|
|
@@ -2309,6 +2322,25 @@ function jsonFromVerifier(value) {
|
|
|
2309
2322
|
function verifierRecapEntries(entries) {
|
|
2310
2323
|
return entries.map((entry) => Array.isArray(entry.caveats) ? { ...entry, caveats: entry.caveats.map((caveat) => jsonFromVerifier(caveat)) } : entry);
|
|
2311
2324
|
}
|
|
2325
|
+
function exactVerifiedRecap(verified) {
|
|
2326
|
+
const exactRecap = Array.isArray(verified.verifiedRecap) ? verifierRecapEntries(verified.verifiedRecap) : verified.verifiedRecap;
|
|
2327
|
+
if (!Array.isArray(exactRecap) || !exactRecap.every(
|
|
2328
|
+
(entry) => entry !== null && typeof entry === "object" && typeof entry.service === "string" && typeof entry.space === "string" && typeof entry.path === "string" && Array.isArray(entry.actions) && entry.actions.every((action) => typeof action === "string") && Array.isArray(entry.caveats) && entry.caveats.every(
|
|
2329
|
+
(caveat) => caveat !== null && typeof caveat === "object" && !Array.isArray(caveat)
|
|
2330
|
+
)
|
|
2331
|
+
)) {
|
|
2332
|
+
throw new UnsupportedSessionRestoreError(
|
|
2333
|
+
"it cannot reconstruct caveat-preserving persisted ReCap authority"
|
|
2334
|
+
);
|
|
2335
|
+
}
|
|
2336
|
+
return exactRecap.map((entry) => ({
|
|
2337
|
+
service: entry.service,
|
|
2338
|
+
space: entry.space,
|
|
2339
|
+
path: entry.path,
|
|
2340
|
+
actions: [...entry.actions],
|
|
2341
|
+
caveats: cloneRecapCaveats(entry.caveats)
|
|
2342
|
+
}));
|
|
2343
|
+
}
|
|
2312
2344
|
var ServiceGraphLifetime = class {
|
|
2313
2345
|
constructor(invokeFn, invokeAnyFn, fetchFn) {
|
|
2314
2346
|
this.invokeFn = invokeFn;
|
|
@@ -2404,7 +2436,7 @@ function persistedExpiry(value) {
|
|
|
2404
2436
|
function sameInstant(left, right) {
|
|
2405
2437
|
return left.getTime() === right.getTime();
|
|
2406
2438
|
}
|
|
2407
|
-
function
|
|
2439
|
+
function describeHostFailure2(result) {
|
|
2408
2440
|
const text = result.error?.trim();
|
|
2409
2441
|
return text ? `${result.status} - ${text}` : `${result.status}`;
|
|
2410
2442
|
}
|
|
@@ -3150,12 +3182,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3150
3182
|
if (!auth) {
|
|
3151
3183
|
throw new Error("Account bootstrap requires an active wallet session");
|
|
3152
3184
|
}
|
|
3185
|
+
const accountSpaceId = this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE);
|
|
3153
3186
|
const skipped = auth.lastActivationSkippedSpaceIds;
|
|
3187
|
+
if (skipped.includes(accountSpaceId)) return { action: "run", mode: "fresh" };
|
|
3154
3188
|
if (skipped.some((spaceId) => enshrinedSpaceIds.has(spaceId))) {
|
|
3155
|
-
return { action: "run", mode: "
|
|
3189
|
+
return { action: "run", mode: "repair" };
|
|
3156
3190
|
}
|
|
3157
3191
|
try {
|
|
3158
|
-
const accountSpaceId = this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE);
|
|
3159
3192
|
const markerPermission = {
|
|
3160
3193
|
service: "tinycloud.kv",
|
|
3161
3194
|
space: accountSpaceId,
|
|
@@ -3167,7 +3200,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3167
3200
|
}
|
|
3168
3201
|
const marker = await this.readBootstrapCompletionMarker();
|
|
3169
3202
|
if (marker.ok) {
|
|
3170
|
-
if (this.isAcceptedBootstrapCompletionMarker(marker.data.data)) {
|
|
3203
|
+
if (this.isAcceptedBootstrapCompletionMarker(marker.data.data, steps.map((step) => step.id))) {
|
|
3171
3204
|
return { action: "skip" };
|
|
3172
3205
|
}
|
|
3173
3206
|
return { action: "run", mode: "repair" };
|
|
@@ -3211,15 +3244,22 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3211
3244
|
marker
|
|
3212
3245
|
);
|
|
3213
3246
|
if (!written.ok) {
|
|
3214
|
-
throw
|
|
3247
|
+
throw Object.assign(
|
|
3248
|
+
new Error(`Failed to write bootstrap completion marker: ${written.error.message}`),
|
|
3249
|
+
{ cause: written.error }
|
|
3250
|
+
);
|
|
3215
3251
|
}
|
|
3216
3252
|
}
|
|
3217
|
-
|
|
3253
|
+
/**
|
|
3254
|
+
* A marker written before a canonical space was added triggers one bounded repair.
|
|
3255
|
+
*/
|
|
3256
|
+
isAcceptedBootstrapCompletionMarker(value, canonicalStepIds) {
|
|
3218
3257
|
if (typeof value !== "object" || value === null) return false;
|
|
3219
3258
|
const entries = Object.entries(value);
|
|
3220
3259
|
const markerValue = (name) => entries.find(([key]) => key === name)?.[1];
|
|
3221
3260
|
const version = markerValue("v");
|
|
3222
|
-
|
|
3261
|
+
const stepIds = markerValue("stepIds");
|
|
3262
|
+
return typeof version === "number" && Number.isInteger(version) && ACCEPTED_MARKER_VERSIONS.some((acceptedVersion) => acceptedVersion === version) && Array.isArray(stepIds) && canonicalStepIds.every((stepId) => stepIds.includes(stepId));
|
|
3223
3263
|
}
|
|
3224
3264
|
markerReadIsUnhostedSpace(meta) {
|
|
3225
3265
|
return meta?.status === 404;
|
|
@@ -3257,17 +3297,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3257
3297
|
rawAbilities
|
|
3258
3298
|
});
|
|
3259
3299
|
} catch (err) {
|
|
3260
|
-
throw
|
|
3261
|
-
|
|
3300
|
+
throw Object.assign(
|
|
3301
|
+
new Error(
|
|
3302
|
+
`Account bootstrap aborted: signature rejected for space "${step.space}". Cause: ${err instanceof Error ? err.message : String(err)}`
|
|
3303
|
+
),
|
|
3304
|
+
{ cause: err }
|
|
3262
3305
|
);
|
|
3263
3306
|
}
|
|
3264
3307
|
sessions.set(step.space, session);
|
|
3265
3308
|
}
|
|
3266
3309
|
for (const step of steps) {
|
|
3267
3310
|
if (step.kind !== "host") continue;
|
|
3268
|
-
const hosted = await auth.
|
|
3269
|
-
if (!hosted) {
|
|
3270
|
-
throw
|
|
3311
|
+
const hosted = await auth.hostOwnedSpaceResult(step.spaceId, "bootstrap-host");
|
|
3312
|
+
if (!hosted.success) {
|
|
3313
|
+
throw Object.assign(
|
|
3314
|
+
new Error(`Failed to host bootstrap space ${step.spaceId}: ${describeHostFailure2(hosted)}`),
|
|
3315
|
+
{ cause: hosted }
|
|
3316
|
+
);
|
|
3271
3317
|
}
|
|
3272
3318
|
}
|
|
3273
3319
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
@@ -3279,8 +3325,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3279
3325
|
}
|
|
3280
3326
|
const activated = await (0, import_sdk_core8.activateSessionWithHost)(host, session.delegationHeader);
|
|
3281
3327
|
if (!activated.success || activated.skipped?.includes(step.spaceId)) {
|
|
3282
|
-
throw
|
|
3283
|
-
|
|
3328
|
+
throw Object.assign(
|
|
3329
|
+
new Error(
|
|
3330
|
+
`Failed to activate bootstrap session for ${step.spaceId}: ${activated.success ? "space was skipped" : describeHostFailure2(activated)}`
|
|
3331
|
+
),
|
|
3332
|
+
{ cause: activated }
|
|
3284
3333
|
);
|
|
3285
3334
|
}
|
|
3286
3335
|
this.registerBootstrapRuntimeGrant(
|
|
@@ -3293,33 +3342,43 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3293
3342
|
if (step.kind === "account-index-schema") {
|
|
3294
3343
|
const ensured = await this.account.index.ensure();
|
|
3295
3344
|
if (!ensured.ok) {
|
|
3296
|
-
throw new Error(`Failed to create account index schema: ${ensured.error.message}`);
|
|
3345
|
+
throw Object.assign(new Error(`Failed to create account index schema: ${ensured.error.message}`), { cause: ensured.error });
|
|
3297
3346
|
}
|
|
3298
3347
|
}
|
|
3299
3348
|
if (step.kind === "seed-spaces") {
|
|
3300
|
-
const
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3349
|
+
const inputs = step.spaces.map((space) => ({
|
|
3350
|
+
spaceId: space.spaceId,
|
|
3351
|
+
name: space.name,
|
|
3352
|
+
ownerDid: this.did,
|
|
3353
|
+
type: "owned",
|
|
3354
|
+
permissions: ["*"],
|
|
3355
|
+
status: "active"
|
|
3356
|
+
}));
|
|
3357
|
+
if (mode === "fresh") {
|
|
3358
|
+
const registered = await this.account.spaces.registerBatch(inputs);
|
|
3359
|
+
if (!registered.ok) {
|
|
3360
|
+
throw Object.assign(
|
|
3361
|
+
new Error(`Failed to seed account spaces: ${registered.error.message}`),
|
|
3362
|
+
{ cause: registered.error }
|
|
3363
|
+
);
|
|
3364
|
+
}
|
|
3365
|
+
const batchError = registered.data.recoveredFromBatchError;
|
|
3366
|
+
if (batchError) {
|
|
3367
|
+
warnings.push({
|
|
3368
|
+
stepId: step.id,
|
|
3369
|
+
kind: "batch-write-reconciled",
|
|
3370
|
+
code: batchError.code,
|
|
3371
|
+
message: batchError.message
|
|
3372
|
+
});
|
|
3373
|
+
}
|
|
3374
|
+
} else {
|
|
3375
|
+
const ensured = await this.account.spaces.registerMissing(inputs);
|
|
3376
|
+
if (!ensured.ok) {
|
|
3377
|
+
throw Object.assign(
|
|
3378
|
+
new Error(`Failed to seed account spaces: ${ensured.error.message}`),
|
|
3379
|
+
{ cause: ensured.error }
|
|
3380
|
+
);
|
|
3381
|
+
}
|
|
3323
3382
|
}
|
|
3324
3383
|
}
|
|
3325
3384
|
if (step.kind === "seed-applications") {
|
|
@@ -3330,7 +3389,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3330
3389
|
{ assumeUnregistered: true }
|
|
3331
3390
|
);
|
|
3332
3391
|
if (!registered.ok) {
|
|
3333
|
-
throw new Error(`Failed to seed bootstrap applications: ${registered.error.message}`);
|
|
3392
|
+
throw Object.assign(new Error(`Failed to seed bootstrap applications: ${registered.error.message}`), { cause: registered.error });
|
|
3334
3393
|
}
|
|
3335
3394
|
}
|
|
3336
3395
|
if (step.kind === "encryption-network-create") {
|
|
@@ -3348,8 +3407,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3348
3407
|
]
|
|
3349
3408
|
});
|
|
3350
3409
|
if (!migrated.ok) {
|
|
3351
|
-
throw
|
|
3352
|
-
`Failed to create secret_records schema: ${migrated.error.message}`
|
|
3410
|
+
throw Object.assign(
|
|
3411
|
+
new Error(`Failed to create secret_records schema: ${migrated.error.message}`),
|
|
3412
|
+
{ cause: migrated.error }
|
|
3353
3413
|
);
|
|
3354
3414
|
}
|
|
3355
3415
|
}
|
|
@@ -3616,6 +3676,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3616
3676
|
);
|
|
3617
3677
|
return;
|
|
3618
3678
|
}
|
|
3679
|
+
if ((0, import_sdk_core8.isStorageFullError)(error) || (0, import_sdk_core8.isStorageFullError)(error?.cause) || message.includes(import_sdk_core8.STORAGE_FULL_MESSAGE) || message.includes(import_sdk_core8.STORAGE_WRITE_TOO_LARGE_MESSAGE)) {
|
|
3680
|
+
console.warn("TinyCloud account registry sync stopped: storage is full", error);
|
|
3681
|
+
return;
|
|
3682
|
+
}
|
|
3619
3683
|
lastError = error;
|
|
3620
3684
|
if (attempt < delays.length - 1) {
|
|
3621
3685
|
await new Promise((resolve) => setTimeout(resolve, delays[attempt]));
|
|
@@ -3690,14 +3754,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3690
3754
|
}
|
|
3691
3755
|
if (!activation.success && activation.status !== 404) {
|
|
3692
3756
|
throw Object.assign(
|
|
3693
|
-
new Error(`Failed to check owned space ${spaceId}: ${
|
|
3757
|
+
new Error(`Failed to check owned space ${spaceId}: ${describeHostFailure2(activation)}`),
|
|
3694
3758
|
{ cause: activation }
|
|
3695
3759
|
);
|
|
3696
3760
|
}
|
|
3697
3761
|
const created = await this.auth.hostOwnedSpaceResult(spaceId);
|
|
3698
3762
|
if (!created.success) {
|
|
3699
3763
|
throw Object.assign(
|
|
3700
|
-
new Error(`Failed to create owned space ${spaceId}: ${
|
|
3764
|
+
new Error(`Failed to create owned space ${spaceId}: ${describeHostFailure2(created)}`),
|
|
3701
3765
|
{ cause: created }
|
|
3702
3766
|
);
|
|
3703
3767
|
}
|
|
@@ -3706,7 +3770,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3706
3770
|
if (!retry.success || retry.skipped?.includes(spaceId)) {
|
|
3707
3771
|
throw Object.assign(
|
|
3708
3772
|
new Error(
|
|
3709
|
-
`Failed to activate session after creating owned space ${spaceId}: ${retry.success ? "space was skipped" :
|
|
3773
|
+
`Failed to activate session after creating owned space ${spaceId}: ${retry.success ? "space was skipped" : describeHostFailure2(retry)}`
|
|
3710
3774
|
),
|
|
3711
3775
|
{ cause: retry }
|
|
3712
3776
|
);
|
|
@@ -3743,19 +3807,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3743
3807
|
if (!host) {
|
|
3744
3808
|
throw new Error("Owned space hosting requires a TinyCloud host");
|
|
3745
3809
|
}
|
|
3746
|
-
const hosted = await this.auth.
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3810
|
+
const hosted = await this.auth.hostOwnedSpaceResult(spaceId);
|
|
3811
|
+
if (!hosted.success) {
|
|
3812
|
+
throw Object.assign(
|
|
3813
|
+
new Error(`Failed to host owned space ${spaceId}: ${describeHostFailure2(hosted)}`),
|
|
3814
|
+
{ cause: hosted }
|
|
3815
|
+
);
|
|
3751
3816
|
}
|
|
3752
3817
|
const activation = await (0, import_sdk_core8.activateSessionWithHost)(
|
|
3753
3818
|
host,
|
|
3754
3819
|
session.delegationHeader
|
|
3755
3820
|
);
|
|
3756
3821
|
if (!activation.success || activation.skipped?.includes(spaceId)) {
|
|
3757
|
-
throw
|
|
3758
|
-
|
|
3822
|
+
throw Object.assign(
|
|
3823
|
+
new Error(
|
|
3824
|
+
`Failed to activate session for owned space ${spaceId}: ${activation.success ? "space was skipped" : describeHostFailure2(activation)}`
|
|
3825
|
+
),
|
|
3826
|
+
{ cause: activation }
|
|
3759
3827
|
);
|
|
3760
3828
|
}
|
|
3761
3829
|
try {
|
|
@@ -3951,23 +4019,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3951
4019
|
throw new InvalidRestoredSessionError(error instanceof Error ? error.message : String(error));
|
|
3952
4020
|
}
|
|
3953
4021
|
})();
|
|
3954
|
-
|
|
3955
|
-
if (!Array.isArray(exactRecap) || !exactRecap.every(
|
|
3956
|
-
(entry) => entry !== null && typeof entry === "object" && typeof entry.service === "string" && typeof entry.space === "string" && typeof entry.path === "string" && Array.isArray(entry.actions) && entry.actions.every((action) => typeof action === "string") && Array.isArray(entry.caveats) && entry.caveats.every(
|
|
3957
|
-
(caveat) => caveat !== null && typeof caveat === "object" && !Array.isArray(caveat)
|
|
3958
|
-
)
|
|
3959
|
-
)) {
|
|
3960
|
-
throw new UnsupportedSessionRestoreError(
|
|
3961
|
-
"it cannot reconstruct caveat-preserving persisted ReCap authority"
|
|
3962
|
-
);
|
|
3963
|
-
}
|
|
3964
|
-
stagedRecap = exactRecap.map((entry) => ({
|
|
3965
|
-
service: entry.service,
|
|
3966
|
-
space: entry.space,
|
|
3967
|
-
path: entry.path,
|
|
3968
|
-
actions: [...entry.actions],
|
|
3969
|
-
caveats: cloneRecapCaveats(entry.caveats)
|
|
3970
|
-
}));
|
|
4022
|
+
stagedRecap = exactVerifiedRecap(verified);
|
|
3971
4023
|
const signedExpiry = verified.expiresAt === void 0 ? void 0 : persistedExpiry(verified.expiresAt);
|
|
3972
4024
|
const persistedPolicyExpiry = sessionData.expiresAt === void 0 ? void 0 : persistedExpiry(sessionData.expiresAt);
|
|
3973
4025
|
if (signedExpiry && persistedPolicyExpiry && !sameInstant(signedExpiry, persistedPolicyExpiry)) {
|
|
@@ -4771,7 +4823,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4771
4823
|
if (cached) return cached;
|
|
4772
4824
|
const response = await fetch(`${this.config.host}/info`);
|
|
4773
4825
|
if (!response.ok) {
|
|
4774
|
-
throw
|
|
4826
|
+
throw await (0, import_sdk_core8.httpResponseError)(response, "Failed to fetch node info");
|
|
4775
4827
|
}
|
|
4776
4828
|
const info = await response.json();
|
|
4777
4829
|
if (typeof info.nodeId !== "string" || info.nodeId.length === 0) {
|
|
@@ -4821,9 +4873,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4821
4873
|
);
|
|
4822
4874
|
if (response.status === 404) return null;
|
|
4823
4875
|
if (!response.ok) {
|
|
4824
|
-
throw
|
|
4825
|
-
`Failed to fetch encryption network ${networkId}: HTTP ${response.status} ${await response.text()}`
|
|
4826
|
-
);
|
|
4876
|
+
throw await (0, import_sdk_core8.httpResponseError)(response, `Failed to fetch encryption network ${networkId}`);
|
|
4827
4877
|
}
|
|
4828
4878
|
const body = await response.json();
|
|
4829
4879
|
return "descriptor" in body && body.descriptor ? body.descriptor : body;
|
|
@@ -5324,7 +5374,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5324
5374
|
headers: { accept: "application/json", "content-type": "application/json", authorization },
|
|
5325
5375
|
body: (0, import_sdk_core8.canonicalizeEncryptionJson)(request)
|
|
5326
5376
|
});
|
|
5327
|
-
if (!response.ok) throw
|
|
5377
|
+
if (!response.ok) throw await (0, import_sdk_core8.httpResponseError)(response, "V3 share delivery authorization failed");
|
|
5328
5378
|
const verified = (0, import_sdk_core8.validateShareDeliveryAuthorizationV3Bytes)(new Uint8Array(await response.arrayBuffer()), {
|
|
5329
5379
|
request,
|
|
5330
5380
|
senderKeyDid: this.credentialHolderDid,
|
|
@@ -5546,9 +5596,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5546
5596
|
);
|
|
5547
5597
|
}
|
|
5548
5598
|
if (!response.ok) {
|
|
5549
|
-
throw
|
|
5550
|
-
`Failed to create encryption network ${networkId}: HTTP ${response.status} ${await response.text()}`
|
|
5551
|
-
);
|
|
5599
|
+
throw await (0, import_sdk_core8.httpResponseError)(response, `Failed to create encryption network ${networkId}`);
|
|
5552
5600
|
}
|
|
5553
5601
|
const created = await response.json();
|
|
5554
5602
|
return created.descriptor;
|
|
@@ -5832,6 +5880,42 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5832
5880
|
(left, right) => left.service.localeCompare(right.service) || (left.space ?? "").localeCompare(right.space ?? "") || left.path.localeCompare(right.path) || left.actions.join("\0").localeCompare(right.actions.join("\0"))
|
|
5833
5881
|
);
|
|
5834
5882
|
}
|
|
5883
|
+
/**
|
|
5884
|
+
* Verify a wallet-signed session grant (a CACAO built from a SIWE and its
|
|
5885
|
+
* EIP-191 signature) issued to this instance's live session key. The
|
|
5886
|
+
* verifier rebuilds the CACAO from `siwe` and `signature`, so the grant is
|
|
5887
|
+
* accepted only when its authorization bytes and CID are exactly that CACAO,
|
|
5888
|
+
* its signer is `address`, its audience is this session key, it is valid
|
|
5889
|
+
* now, and its ReCap covers `spaceId` or names only raw encryption networks
|
|
5890
|
+
* (a decrypt-only grant has no space). Returns the signed ReCap and expiry.
|
|
5891
|
+
* Bindings without `validateSessionGrant` fall back to the session verifier,
|
|
5892
|
+
* which also refuses decrypt-only grants.
|
|
5893
|
+
*/
|
|
5894
|
+
verifySessionGrant(grant) {
|
|
5895
|
+
const bindings = this.wasmBindings;
|
|
5896
|
+
const validate = typeof bindings.validateSessionGrant === "function" ? bindings.validateSessionGrant.bind(bindings) : bindings.validatePersistedSession?.bind(bindings);
|
|
5897
|
+
if (validate === void 0) {
|
|
5898
|
+
throw new UnsupportedSessionRestoreError("it cannot verify persisted SIWE authority");
|
|
5899
|
+
}
|
|
5900
|
+
const verified = validate({
|
|
5901
|
+
delegationHeader: { Authorization: grant.delegationHeader.Authorization },
|
|
5902
|
+
delegationCid: grant.delegationCid,
|
|
5903
|
+
spaceId: grant.spaceId,
|
|
5904
|
+
jwk: this.sessionKeyJwk,
|
|
5905
|
+
address: (0, import_sdk_core8.canonicalizeAddress)(grant.address),
|
|
5906
|
+
chainId: grant.chainId,
|
|
5907
|
+
siwe: grant.siwe,
|
|
5908
|
+
signature: grant.signature
|
|
5909
|
+
});
|
|
5910
|
+
if (typeof verified.expiresAt !== "string") {
|
|
5911
|
+
throw new Error("Session grant has no signed expiry.");
|
|
5912
|
+
}
|
|
5913
|
+
const expiresAt = new Date(verified.expiresAt);
|
|
5914
|
+
if (!Number.isFinite(expiresAt.getTime())) {
|
|
5915
|
+
throw new Error("Session grant has an invalid signed expiry.");
|
|
5916
|
+
}
|
|
5917
|
+
return { recap: exactVerifiedRecap(verified), expiresAt };
|
|
5918
|
+
}
|
|
5835
5919
|
/**
|
|
5836
5920
|
* Install a portable runtime permission delegation into this SDK instance so
|
|
5837
5921
|
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
@@ -5856,8 +5940,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5856
5940
|
delegation.delegationHeader
|
|
5857
5941
|
);
|
|
5858
5942
|
if (!activateResult.success) {
|
|
5859
|
-
throw
|
|
5860
|
-
`Failed to activate runtime permission delegation: ${activateResult
|
|
5943
|
+
throw Object.assign(
|
|
5944
|
+
new Error(`Failed to activate runtime permission delegation: ${describeHostFailure2(activateResult)}`),
|
|
5945
|
+
{ cause: activateResult }
|
|
5861
5946
|
);
|
|
5862
5947
|
}
|
|
5863
5948
|
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
@@ -5953,8 +6038,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5953
6038
|
delegatedSession.delegationHeader
|
|
5954
6039
|
);
|
|
5955
6040
|
if (!activateResult.success) {
|
|
5956
|
-
throw
|
|
5957
|
-
`Failed to activate runtime permission delegation: ${activateResult
|
|
6041
|
+
throw Object.assign(
|
|
6042
|
+
new Error(`Failed to activate runtime permission delegation: ${describeHostFailure2(activateResult)}`),
|
|
6043
|
+
{ cause: activateResult }
|
|
5958
6044
|
);
|
|
5959
6045
|
}
|
|
5960
6046
|
const delegation = this.runtimeDelegationFromSession(
|
|
@@ -5962,7 +6048,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5962
6048
|
delegatedEntries,
|
|
5963
6049
|
spaceId,
|
|
5964
6050
|
session,
|
|
5965
|
-
expiresAt
|
|
6051
|
+
expiresAt,
|
|
6052
|
+
{ siwe: prepared.siwe, signature }
|
|
5966
6053
|
);
|
|
5967
6054
|
this.runtimePermissionGrants.push({
|
|
5968
6055
|
session: {
|
|
@@ -6139,7 +6226,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6139
6226
|
delegationSession.delegationHeader
|
|
6140
6227
|
);
|
|
6141
6228
|
if (!activateResult.success) {
|
|
6142
|
-
throw
|
|
6229
|
+
throw Object.assign(
|
|
6230
|
+
new Error(`Failed to activate public space delegation: ${describeHostFailure2(activateResult)}`),
|
|
6231
|
+
{ cause: activateResult }
|
|
6232
|
+
);
|
|
6143
6233
|
}
|
|
6144
6234
|
if (this._capabilityRegistry && this.session) {
|
|
6145
6235
|
const sessionKey = {
|
|
@@ -6492,8 +6582,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6492
6582
|
delegationHeader
|
|
6493
6583
|
);
|
|
6494
6584
|
if (!activateResult.success) {
|
|
6495
|
-
throw
|
|
6496
|
-
`Failed to activate delegation with host: ${activateResult
|
|
6585
|
+
throw Object.assign(
|
|
6586
|
+
new Error(`Failed to activate delegation with host: ${describeHostFailure2(activateResult)}`),
|
|
6587
|
+
{ cause: activateResult }
|
|
6497
6588
|
);
|
|
6498
6589
|
}
|
|
6499
6590
|
return {
|
|
@@ -6529,8 +6620,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6529
6620
|
delegationHeader
|
|
6530
6621
|
);
|
|
6531
6622
|
if (!activateResult.success) {
|
|
6532
|
-
throw
|
|
6533
|
-
`Failed to activate delegation with host: ${activateResult
|
|
6623
|
+
throw Object.assign(
|
|
6624
|
+
new Error(`Failed to activate delegation with host: ${describeHostFailure2(activateResult)}`),
|
|
6625
|
+
{ cause: activateResult }
|
|
6534
6626
|
);
|
|
6535
6627
|
}
|
|
6536
6628
|
return {
|
|
@@ -6743,7 +6835,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6743
6835
|
}
|
|
6744
6836
|
return grants;
|
|
6745
6837
|
}
|
|
6746
|
-
runtimeDelegationFromSession(delegatedSession, entries, spaceId, session, expiresAt) {
|
|
6838
|
+
runtimeDelegationFromSession(delegatedSession, entries, spaceId, session, expiresAt, siweProof) {
|
|
6747
6839
|
const resources = this.delegatedResourcesForEntries(entries, spaceId);
|
|
6748
6840
|
const primary = resources[0];
|
|
6749
6841
|
return {
|
|
@@ -6758,7 +6850,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6758
6850
|
delegateDID: session.verificationMethod,
|
|
6759
6851
|
ownerAddress: session.address,
|
|
6760
6852
|
chainId: session.chainId,
|
|
6761
|
-
host: this.config.host
|
|
6853
|
+
host: this.config.host,
|
|
6854
|
+
siweProof
|
|
6762
6855
|
};
|
|
6763
6856
|
}
|
|
6764
6857
|
runtimeGrantFromDelegation(delegation, session) {
|
|
@@ -6951,6 +7044,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6951
7044
|
if (grantedAction === requestedAction) {
|
|
6952
7045
|
return true;
|
|
6953
7046
|
}
|
|
7047
|
+
if ((0, import_sdk_core8.isExplicitOnlyAction)(requestedAction)) {
|
|
7048
|
+
return false;
|
|
7049
|
+
}
|
|
6954
7050
|
if (grantedAction.endsWith("/*")) {
|
|
6955
7051
|
const prefix = grantedAction.slice(0, -2);
|
|
6956
7052
|
return requestedAction.startsWith(`${prefix}/`);
|
|
@@ -7137,7 +7233,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7137
7233
|
delegationSession.delegationHeader
|
|
7138
7234
|
);
|
|
7139
7235
|
if (!activateResult.success) {
|
|
7140
|
-
throw
|
|
7236
|
+
throw Object.assign(
|
|
7237
|
+
new Error(`Failed to activate delegation: ${describeHostFailure2(activateResult)}`),
|
|
7238
|
+
{ cause: activateResult }
|
|
7239
|
+
);
|
|
7141
7240
|
}
|
|
7142
7241
|
const result = {
|
|
7143
7242
|
cid: delegationSession.delegationCid,
|
|
@@ -7287,7 +7386,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7287
7386
|
invokerSession.delegationHeader
|
|
7288
7387
|
);
|
|
7289
7388
|
if (!activateResult.success) {
|
|
7290
|
-
throw
|
|
7389
|
+
throw Object.assign(
|
|
7390
|
+
new Error(`Failed to activate delegated session: ${describeHostFailure2(activateResult)}`),
|
|
7391
|
+
{ cause: activateResult }
|
|
7392
|
+
);
|
|
7291
7393
|
}
|
|
7292
7394
|
const session = {
|
|
7293
7395
|
address: mySession.address,
|
|
@@ -7404,7 +7506,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7404
7506
|
subDelegationSession.delegationHeader
|
|
7405
7507
|
);
|
|
7406
7508
|
if (!activateResult.success) {
|
|
7407
|
-
throw
|
|
7509
|
+
throw Object.assign(
|
|
7510
|
+
new Error(`Failed to activate sub-delegation: ${describeHostFailure2(activateResult)}`),
|
|
7511
|
+
{ cause: activateResult }
|
|
7512
|
+
);
|
|
7408
7513
|
}
|
|
7409
7514
|
return {
|
|
7410
7515
|
cid: subDelegationSession.delegationCid,
|
|
@@ -7445,6 +7550,16 @@ var import_sdk_core12 = require("@tinycloud/sdk-core");
|
|
|
7445
7550
|
|
|
7446
7551
|
// src/delegation.ts
|
|
7447
7552
|
var import_sdk_core9 = require("@tinycloud/sdk-core");
|
|
7553
|
+
var RuntimeDelegationRejectedError = class extends Error {
|
|
7554
|
+
constructor(reason, message) {
|
|
7555
|
+
super(message);
|
|
7556
|
+
this.name = "RuntimeDelegationRejectedError";
|
|
7557
|
+
this.reason = reason;
|
|
7558
|
+
}
|
|
7559
|
+
};
|
|
7560
|
+
function reject(reason, message) {
|
|
7561
|
+
throw new RuntimeDelegationRejectedError(reason, message);
|
|
7562
|
+
}
|
|
7448
7563
|
var SERVICE_BY_SHORT_NAME = {
|
|
7449
7564
|
kv: "tinycloud.kv",
|
|
7450
7565
|
sql: "tinycloud.sql",
|
|
@@ -7591,6 +7706,15 @@ function signedAuthorityFromCompactUcan(authorization) {
|
|
|
7591
7706
|
abilities
|
|
7592
7707
|
));
|
|
7593
7708
|
}
|
|
7709
|
+
return canonicalSignedAuthority({
|
|
7710
|
+
issuer: payload.iss,
|
|
7711
|
+
audience: payload.aud,
|
|
7712
|
+
expiry,
|
|
7713
|
+
proofs: [...payload.prf],
|
|
7714
|
+
...remainingRedelegationDepth === void 0 ? {} : { remainingRedelegationDepth }
|
|
7715
|
+
}, permissions);
|
|
7716
|
+
}
|
|
7717
|
+
function canonicalSignedAuthority(signed, permissions) {
|
|
7594
7718
|
if (permissions.length === 0) {
|
|
7595
7719
|
throw new Error("Validated runtime delegation has no signed capabilities.");
|
|
7596
7720
|
}
|
|
@@ -7602,15 +7726,84 @@ function signedAuthorityFromCompactUcan(authorization) {
|
|
|
7602
7726
|
actions: [...permission.actions],
|
|
7603
7727
|
...permission.caveats === void 0 ? {} : { caveats: permission.caveats }
|
|
7604
7728
|
}));
|
|
7605
|
-
return {
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7729
|
+
return { ...signed, permissions: canonicalPermissions, resources: canonicalResources };
|
|
7730
|
+
}
|
|
7731
|
+
var RAW_ENCRYPTION_PREFIX = "urn:tinycloud:encryption:";
|
|
7732
|
+
var PKH_SPACE = /^tinycloud:pkh:eip155:(\d+):(0x[0-9a-fA-F]{40}):(.+)$/;
|
|
7733
|
+
function comparableSpace(space) {
|
|
7734
|
+
const match = PKH_SPACE.exec(space);
|
|
7735
|
+
return match ? `tinycloud:pkh:eip155:${match[1]}:${match[2].toLowerCase()}:${match[3]}` : space;
|
|
7736
|
+
}
|
|
7737
|
+
function signedAuthorityFromSessionGrant(node, delegation, authorization, cid) {
|
|
7738
|
+
const proof = delegation.siweProof;
|
|
7739
|
+
if (proof === void 0 || proof === null || typeof proof !== "object" || typeof proof.siwe !== "string" || typeof proof.signature !== "string") {
|
|
7740
|
+
reject(
|
|
7741
|
+
"proof_missing",
|
|
7742
|
+
"Runtime delegation is a wallet-signed session grant stored without its signed SIWE proof, so its authority cannot be verified."
|
|
7743
|
+
);
|
|
7744
|
+
}
|
|
7745
|
+
if (typeof node.verifySessionGrant !== "function") {
|
|
7746
|
+
reject("unsupported", "This runtime cannot verify wallet-signed session grants.");
|
|
7747
|
+
}
|
|
7748
|
+
const owner = `did:pkh:eip155:${delegation.chainId}:${delegation.ownerAddress}`;
|
|
7749
|
+
if (typeof node.did !== "string" || !didPrincipalsMatch(owner, node.did)) {
|
|
7750
|
+
reject("owner_mismatch", "Runtime delegation is not signed by this session's owner.");
|
|
7751
|
+
}
|
|
7752
|
+
let verified;
|
|
7753
|
+
try {
|
|
7754
|
+
verified = node.verifySessionGrant({
|
|
7755
|
+
delegationHeader: { Authorization: authorization },
|
|
7756
|
+
delegationCid: cid,
|
|
7757
|
+
spaceId: delegation.spaceId,
|
|
7758
|
+
address: delegation.ownerAddress,
|
|
7759
|
+
chainId: delegation.chainId,
|
|
7760
|
+
siwe: proof.siwe,
|
|
7761
|
+
signature: proof.signature
|
|
7762
|
+
});
|
|
7763
|
+
} catch (error) {
|
|
7764
|
+
reject("proof_invalid", error instanceof Error ? error.message : String(error));
|
|
7765
|
+
}
|
|
7766
|
+
const space = comparableSpace(delegation.spaceId);
|
|
7767
|
+
const spaceOwner = PKH_SPACE.exec(delegation.spaceId);
|
|
7768
|
+
if (!spaceOwner || !didPrincipalsMatch(`did:pkh:eip155:${spaceOwner[1]}:${spaceOwner[2]}`, owner)) {
|
|
7769
|
+
reject("authority_invalid", "Runtime delegation space is not owned by its signer.");
|
|
7770
|
+
}
|
|
7771
|
+
const groups = /* @__PURE__ */ new Map();
|
|
7772
|
+
for (const entry of verified.recap) {
|
|
7773
|
+
const service = entry.service.startsWith("tinycloud.") ? entry.service : `tinycloud.${entry.service}`;
|
|
7774
|
+
const raw = entry.space === "encryption";
|
|
7775
|
+
if (raw) {
|
|
7776
|
+
if (service !== "tinycloud.encryption" || !entry.path.startsWith(RAW_ENCRYPTION_PREFIX)) {
|
|
7777
|
+
reject("authority_invalid", "Runtime delegation has an unsupported signed raw resource.");
|
|
7778
|
+
}
|
|
7779
|
+
const networkOwner = entry.path.slice(RAW_ENCRYPTION_PREFIX.length, entry.path.lastIndexOf(":"));
|
|
7780
|
+
if (!didPrincipalsMatch(networkOwner, owner)) {
|
|
7781
|
+
reject("authority_invalid", "Runtime delegation names an encryption network its signer does not own.");
|
|
7782
|
+
}
|
|
7783
|
+
} else if (service === "tinycloud.encryption" || comparableSpace(entry.space) !== space) {
|
|
7784
|
+
reject("authority_invalid", "Runtime delegation has signed authority outside its space.");
|
|
7785
|
+
}
|
|
7786
|
+
const caveats = signedCaveats(entry.caveats ?? []);
|
|
7787
|
+
const key = JSON.stringify([service, raw ? "" : entry.space, entry.path, (0, import_sdk_core9.canonicalizeRecapCaveats)(caveats)]);
|
|
7788
|
+
const group = groups.get(key) ?? {
|
|
7789
|
+
service,
|
|
7790
|
+
...raw ? {} : { space: entry.space },
|
|
7791
|
+
path: entry.path,
|
|
7792
|
+
actions: [],
|
|
7793
|
+
...caveats === void 0 ? {} : { caveats }
|
|
7794
|
+
};
|
|
7795
|
+
for (const action of entry.actions) {
|
|
7796
|
+
if (!group.actions.includes(action)) group.actions.push(action);
|
|
7797
|
+
}
|
|
7798
|
+
groups.set(key, group);
|
|
7799
|
+
}
|
|
7800
|
+
return canonicalSignedAuthority({
|
|
7801
|
+
issuer: owner,
|
|
7802
|
+
// The verifier bound the SIWE audience to this runtime's own session key.
|
|
7803
|
+
audience: node.sessionDid,
|
|
7804
|
+
expiry: verified.expiresAt,
|
|
7805
|
+
proofs: []
|
|
7806
|
+
}, [...groups.values()]);
|
|
7614
7807
|
}
|
|
7615
7808
|
function canonicalResourcesFromPortableDelegation(delegation) {
|
|
7616
7809
|
if (delegation.resources !== void 0 && delegation.resources.length > 0) {
|
|
@@ -7646,46 +7839,58 @@ function resourcesMatch(actual, expected) {
|
|
|
7646
7839
|
async function activateValidatedRuntimeDelegation(node, delegation, options) {
|
|
7647
7840
|
const host = normalizedHost(options.host);
|
|
7648
7841
|
if (delegation.host !== void 0 && normalizedHost(delegation.host) !== host) {
|
|
7649
|
-
|
|
7842
|
+
reject(
|
|
7843
|
+
"host_mismatch",
|
|
7650
7844
|
`Runtime delegation host '${delegation.host}' does not match expected host '${options.host}'.`
|
|
7651
7845
|
);
|
|
7652
7846
|
}
|
|
7653
7847
|
if (!(delegation.expiry instanceof Date) || Number.isNaN(delegation.expiry.getTime())) {
|
|
7654
|
-
|
|
7848
|
+
reject("authority_invalid", "Runtime delegation has an invalid expiry.");
|
|
7655
7849
|
}
|
|
7656
7850
|
if (delegation.expiry.getTime() <= Date.now()) {
|
|
7657
|
-
|
|
7851
|
+
reject("expired", "Runtime delegation is expired.");
|
|
7658
7852
|
}
|
|
7659
7853
|
const authorization = delegation.delegationHeader?.Authorization;
|
|
7660
7854
|
if (typeof authorization !== "string" || authorization.length === 0) {
|
|
7661
|
-
|
|
7855
|
+
reject("authority_invalid", "Runtime delegation is missing authorization bytes.");
|
|
7662
7856
|
}
|
|
7663
7857
|
const cid = node.computeDelegationCid(authorization);
|
|
7664
7858
|
if (cid !== delegation.cid) {
|
|
7665
|
-
|
|
7859
|
+
reject("cid_mismatch", "Runtime delegation CID does not match authorization bytes.");
|
|
7860
|
+
}
|
|
7861
|
+
const compact = authorizationWithoutBearer(authorization).split(".").length === 3;
|
|
7862
|
+
let signed;
|
|
7863
|
+
try {
|
|
7864
|
+
signed = compact ? signedAuthorityFromCompactUcan(authorization) : signedAuthorityFromSessionGrant(node, delegation, authorization, cid);
|
|
7865
|
+
} catch (error) {
|
|
7866
|
+
if (error instanceof RuntimeDelegationRejectedError) throw error;
|
|
7867
|
+
reject("authority_invalid", error instanceof Error ? error.message : String(error));
|
|
7666
7868
|
}
|
|
7667
|
-
const signed = signedAuthorityFromCompactUcan(authorization);
|
|
7668
7869
|
if (signed.expiry.getTime() <= Date.now()) {
|
|
7669
|
-
|
|
7870
|
+
reject("expired", "Runtime delegation is expired.");
|
|
7670
7871
|
}
|
|
7671
7872
|
if (delegation.expiry.getTime() !== signed.expiry.getTime()) {
|
|
7672
|
-
|
|
7873
|
+
reject("authority_invalid", "Runtime delegation expiry does not match signed authority.");
|
|
7673
7874
|
}
|
|
7674
7875
|
if (!didPrincipalsMatch(signed.audience, node.sessionDid)) {
|
|
7675
|
-
|
|
7876
|
+
reject(
|
|
7877
|
+
"audience_mismatch",
|
|
7676
7878
|
`Runtime delegation targets ${signed.audience} but this session is ${node.sessionDid}.`
|
|
7677
7879
|
);
|
|
7678
7880
|
}
|
|
7679
7881
|
if (!didPrincipalsMatch(delegation.delegateDID, signed.audience)) {
|
|
7680
|
-
|
|
7882
|
+
reject("audience_mismatch", "Runtime delegation audience does not match signed authority.");
|
|
7883
|
+
}
|
|
7884
|
+
if (compact && !resourcesMatch(canonicalResourcesFromPortableDelegation(delegation), signed.resources)) {
|
|
7885
|
+
reject("resources_mismatch", "Runtime delegation resources do not match signed authority.");
|
|
7681
7886
|
}
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
throw new Error("Runtime delegation resources do not match signed authority.");
|
|
7887
|
+
if (options.authorize !== void 0 && !options.authorize(signed.permissions)) {
|
|
7888
|
+
throw new Error("Runtime delegation is not authorized for this runtime.");
|
|
7685
7889
|
}
|
|
7686
7890
|
const previouslyInstalled = node.getRuntimePermissionDelegations().find((candidate) => candidate.cid === cid);
|
|
7687
7891
|
if (previouslyInstalled !== void 0 && previouslyInstalled.delegationHeader.Authorization !== authorization) {
|
|
7688
|
-
|
|
7892
|
+
reject(
|
|
7893
|
+
"cid_mismatch",
|
|
7689
7894
|
"A different authorization is already installed for this runtime delegation CID."
|
|
7690
7895
|
);
|
|
7691
7896
|
}
|
|
@@ -7715,22 +7920,28 @@ async function activateValidatedRuntimeDelegation(node, delegation, options) {
|
|
|
7715
7920
|
})),
|
|
7716
7921
|
expiry: new Date(signed.expiry),
|
|
7717
7922
|
delegateDID: signed.audience,
|
|
7718
|
-
host
|
|
7923
|
+
host,
|
|
7924
|
+
...compact ? {} : { siweProof: delegation.siweProof }
|
|
7719
7925
|
};
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7926
|
+
try {
|
|
7927
|
+
if (node.isSessionOnly === true && typeof node.did === "string" && (0, import_sdk_core9.principalDidEquals)(node.did, node.sessionDid) && typeof node.useDelegation === "function") {
|
|
7928
|
+
await node.useDelegation(installedCandidate);
|
|
7929
|
+
} else {
|
|
7930
|
+
await node.useRuntimeDelegation(installedCandidate);
|
|
7931
|
+
}
|
|
7932
|
+
} catch (error) {
|
|
7933
|
+
reject("activation_rejected", error instanceof Error ? error.message : String(error));
|
|
7724
7934
|
}
|
|
7725
7935
|
const installed = node.getRuntimePermissionDelegations().find((candidate) => candidate.cid === cid);
|
|
7726
7936
|
if (!installed) {
|
|
7727
|
-
|
|
7937
|
+
reject("activation_rejected", "Runtime delegation activation did not install the validated authority.");
|
|
7728
7938
|
}
|
|
7729
7939
|
if (installed.delegationHeader.Authorization !== authorization || !didPrincipalsMatch(installed.delegateDID, signed.audience) || installed.expiry.getTime() !== signed.expiry.getTime() || !resourcesMatch(
|
|
7730
7940
|
canonicalResourcesFromPortableDelegation(installed),
|
|
7731
7941
|
signed.resources
|
|
7732
7942
|
) || normalizedHost(installed.host ?? "") !== host) {
|
|
7733
|
-
|
|
7943
|
+
reject(
|
|
7944
|
+
"activation_rejected",
|
|
7734
7945
|
"Runtime delegation activation installed authority that differs from the validated authority."
|
|
7735
7946
|
);
|
|
7736
7947
|
}
|