@tinycloud/node-sdk 2.11.0-beta.9 → 2.11.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/{core-Bkptd8qZ.d.cts → core-Bq8TMY7Y.d.cts} +188 -8
- package/dist/{core-Bkptd8qZ.d.ts → core-Bq8TMY7Y.d.ts} +188 -8
- package/dist/core.cjs +675 -67
- 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 +693 -75
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +752 -69
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -3
- package/dist/index.d.ts +85 -3
- package/dist/index.js +765 -76
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -17179,12 +17179,14 @@ import {
|
|
|
17179
17179
|
SharingService,
|
|
17180
17180
|
UnsupportedFeatureError,
|
|
17181
17181
|
makePublicSpaceId,
|
|
17182
|
-
ACCOUNT_REGISTRY_SPACE,
|
|
17182
|
+
ACCOUNT_REGISTRY_SPACE as ACCOUNT_REGISTRY_SPACE2,
|
|
17183
|
+
BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST,
|
|
17183
17184
|
BOOTSTRAP_SESSION_REQUESTS,
|
|
17184
17185
|
SECRET_RECORDS_SCHEMA,
|
|
17185
17186
|
SECRETS_SPACE as SECRETS_SPACE2,
|
|
17186
17187
|
TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
|
|
17187
17188
|
bootstrapSteps,
|
|
17189
|
+
ErrorCodes as ErrorCodes2,
|
|
17188
17190
|
ENCRYPTION_PERMISSION_SERVICE as ENCRYPTION_PERMISSION_SERVICE2,
|
|
17189
17191
|
CaveatedDelegationUnsupportedError,
|
|
17190
17192
|
PermissionNotInManifestError,
|
|
@@ -17211,13 +17213,16 @@ import {
|
|
|
17211
17213
|
parseNetworkId as parseNetworkId2,
|
|
17212
17214
|
resolveSecretPath as resolveSecretPath2,
|
|
17213
17215
|
validateOwnerSharePolicyRegistrationBytes,
|
|
17214
|
-
validateShareDeliveryAuthorizationBytes
|
|
17216
|
+
validateShareDeliveryAuthorizationBytes,
|
|
17217
|
+
verifyEip191MessageSignature
|
|
17215
17218
|
} from "@tinycloud/sdk-core";
|
|
17216
17219
|
import {
|
|
17217
17220
|
parsePermissionHint
|
|
17218
17221
|
} from "@tinycloud/sdk-services";
|
|
17219
17222
|
|
|
17220
17223
|
// src/authorization/NodeUserAuthorization.ts
|
|
17224
|
+
import { createHash } from "crypto";
|
|
17225
|
+
import { SiweMessage } from "siwe";
|
|
17221
17226
|
import {
|
|
17222
17227
|
fetchPeerId,
|
|
17223
17228
|
submitHostDelegation,
|
|
@@ -17236,6 +17241,13 @@ import {
|
|
|
17236
17241
|
canonicalizeAddress,
|
|
17237
17242
|
makePkhSpaceId,
|
|
17238
17243
|
pkhDid,
|
|
17244
|
+
extractImmutableSiweFields,
|
|
17245
|
+
diffImmutableSiweFields,
|
|
17246
|
+
extractRecapAttenuations,
|
|
17247
|
+
unauthorizedRecapCapabilities,
|
|
17248
|
+
parseCanonicalRecapResource,
|
|
17249
|
+
ACCOUNT_REGISTRY_SPACE,
|
|
17250
|
+
ACCOUNT_MANIFEST_PERMISSIONS,
|
|
17239
17251
|
KV,
|
|
17240
17252
|
SQL,
|
|
17241
17253
|
DUCKDB,
|
|
@@ -17322,6 +17334,27 @@ var MemorySessionStorage = class {
|
|
|
17322
17334
|
// src/authorization/NodeUserAuthorization.ts
|
|
17323
17335
|
var DECRYPT_ACTION = ENCRYPTION.DECRYPT;
|
|
17324
17336
|
var NETWORK_CREATE_ACTION = ENCRYPTION.NETWORK_CREATE;
|
|
17337
|
+
function canonicalizeOpenKeyManifestJson(value) {
|
|
17338
|
+
const json = JSON.stringify(value);
|
|
17339
|
+
if (json === void 0) {
|
|
17340
|
+
throw new TypeError("manifest is not JSON-serializable");
|
|
17341
|
+
}
|
|
17342
|
+
return canonicalizeJsonValue(JSON.parse(json));
|
|
17343
|
+
}
|
|
17344
|
+
function canonicalizeJsonValue(value) {
|
|
17345
|
+
if (value === null || typeof value !== "object") {
|
|
17346
|
+
return JSON.stringify(value);
|
|
17347
|
+
}
|
|
17348
|
+
if (Array.isArray(value)) {
|
|
17349
|
+
return `[${value.map(canonicalizeJsonValue).join(",")}]`;
|
|
17350
|
+
}
|
|
17351
|
+
return `{${Object.keys(value).sort().map(
|
|
17352
|
+
(key2) => `${JSON.stringify(key2)}:${canonicalizeJsonValue(value[key2])}`
|
|
17353
|
+
).join(",")}}`;
|
|
17354
|
+
}
|
|
17355
|
+
function canonicalOpenKeyManifestSha256Hex(value) {
|
|
17356
|
+
return createHash("sha256").update(canonicalizeOpenKeyManifestJson(value)).digest("hex");
|
|
17357
|
+
}
|
|
17325
17358
|
function didPrincipalMatches(actual, expected) {
|
|
17326
17359
|
try {
|
|
17327
17360
|
return principalDidEquals(actual, expected);
|
|
@@ -17339,6 +17372,16 @@ function addRawAbility(rawAbilities, resource, action) {
|
|
|
17339
17372
|
actions.push(action);
|
|
17340
17373
|
}
|
|
17341
17374
|
}
|
|
17375
|
+
function cloneAbilitiesMap(actions) {
|
|
17376
|
+
return Object.fromEntries(
|
|
17377
|
+
Object.entries(actions).map(([service, paths]) => [
|
|
17378
|
+
service,
|
|
17379
|
+
Object.fromEntries(
|
|
17380
|
+
Object.entries(paths).map(([path, pathActions]) => [path, [...pathActions]])
|
|
17381
|
+
)
|
|
17382
|
+
])
|
|
17383
|
+
);
|
|
17384
|
+
}
|
|
17342
17385
|
var NodeUserAuthorization = class {
|
|
17343
17386
|
constructor(config) {
|
|
17344
17387
|
this.activeSessionKeyId = "default";
|
|
@@ -17610,23 +17653,41 @@ var NodeUserAuthorization = class {
|
|
|
17610
17653
|
const defaultNetworkId = this.defaultEncryptionNetworkId(address, chainId);
|
|
17611
17654
|
const primarySpaceId2 = makePkhSpaceId(address, chainId, this.spacePrefix);
|
|
17612
17655
|
const secretsSpaceId = makePkhSpaceId(address, chainId, "secrets");
|
|
17613
|
-
|
|
17614
|
-
|
|
17615
|
-
|
|
17616
|
-
|
|
17617
|
-
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
|
|
17621
|
-
|
|
17622
|
-
|
|
17623
|
-
|
|
17624
|
-
|
|
17625
|
-
|
|
17626
|
-
|
|
17656
|
+
const primaryActions = this.includeAccountRegistryPermissions && this.spacePrefix === ACCOUNT_REGISTRY_SPACE ? cloneAbilitiesMap(this.defaultActions) : this.defaultActions;
|
|
17657
|
+
const spaceAbilities2 = {
|
|
17658
|
+
[primarySpaceId2]: primaryActions,
|
|
17659
|
+
[secretsSpaceId]: {
|
|
17660
|
+
kv: {
|
|
17661
|
+
"vault/secrets/": [
|
|
17662
|
+
KV.GET,
|
|
17663
|
+
KV.PUT,
|
|
17664
|
+
KV.DEL,
|
|
17665
|
+
KV.LIST,
|
|
17666
|
+
KV.METADATA
|
|
17667
|
+
]
|
|
17668
|
+
}
|
|
17669
|
+
}
|
|
17670
|
+
};
|
|
17671
|
+
if (this.includeAccountRegistryPermissions && this.spacePrefix !== ACCOUNT_REGISTRY_SPACE) {
|
|
17672
|
+
spaceAbilities2[makePkhSpaceId(address, chainId, ACCOUNT_REGISTRY_SPACE)] = resourceCapabilitiesToAbilitiesMap(ACCOUNT_MANIFEST_PERMISSIONS);
|
|
17673
|
+
} else if (this.includeAccountRegistryPermissions) {
|
|
17674
|
+
const accountAbilities = resourceCapabilitiesToAbilitiesMap(
|
|
17675
|
+
ACCOUNT_MANIFEST_PERMISSIONS
|
|
17676
|
+
);
|
|
17677
|
+
for (const [service, paths] of Object.entries(accountAbilities)) {
|
|
17678
|
+
const existingPaths = primaryActions[service] ?? (primaryActions[service] = {});
|
|
17679
|
+
for (const [path, actions] of Object.entries(paths)) {
|
|
17680
|
+
const existingActions = existingPaths[path] ?? (existingPaths[path] = []);
|
|
17681
|
+
for (const action of actions) {
|
|
17682
|
+
if (!existingActions.includes(action)) existingActions.push(action);
|
|
17627
17683
|
}
|
|
17628
17684
|
}
|
|
17629
|
-
}
|
|
17685
|
+
}
|
|
17686
|
+
}
|
|
17687
|
+
return {
|
|
17688
|
+
abilities: primaryActions,
|
|
17689
|
+
spaceId: primarySpaceId2,
|
|
17690
|
+
spaceAbilities: spaceAbilities2,
|
|
17630
17691
|
rawAbilities: {
|
|
17631
17692
|
[defaultNetworkId]: [DECRYPT_ACTION, NETWORK_CREATE_ACTION]
|
|
17632
17693
|
}
|
|
@@ -18207,6 +18268,398 @@ var NodeUserAuthorization = class {
|
|
|
18207
18268
|
await this.ensureSpaceExists();
|
|
18208
18269
|
return clientSession;
|
|
18209
18270
|
}
|
|
18271
|
+
/**
|
|
18272
|
+
* End-to-end sign-in via OpenKey `authorizeTinyCloud()` (Sol CRITICAL-4).
|
|
18273
|
+
*
|
|
18274
|
+
* This is the production entry point that wires
|
|
18275
|
+
* {@link prepareSessionForSigning} → OpenKey `authorizeTinyCloud()` →
|
|
18276
|
+
* {@link signInWithOpenKeyResult} into one call. Consumers pass in a
|
|
18277
|
+
* caller-provided `authorizeFn` (typically a thin wrapper around
|
|
18278
|
+
* `openkey.authorizeTinyCloud()`) so this method has no direct
|
|
18279
|
+
* dependency on the OpenKey SDK — it works with any transport that
|
|
18280
|
+
* conforms to the versioned protocol.
|
|
18281
|
+
*
|
|
18282
|
+
* The `authorizeFn` MUST:
|
|
18283
|
+
* 1. Send the prepared SIWE bytes to OpenKey.
|
|
18284
|
+
* 2. Return the exact `TinyCloudAuthorizationResultV1` shape (with
|
|
18285
|
+
* `signedMessage` — the bytes the signature actually verifies
|
|
18286
|
+
* against — plus `selectedActionKeys` and `permissions`).
|
|
18287
|
+
*
|
|
18288
|
+
* NodeUserAuthorization then completes the session with `signedMessage`
|
|
18289
|
+
* (never the prepared bytes), verifying the signature, the immutable
|
|
18290
|
+
* SIWE fields, and every subset invariant enforced by
|
|
18291
|
+
* {@link signInWithOpenKeyResult}. This preserves the exact-byte
|
|
18292
|
+
* guarantee: if the user did NOT narrow, the returned `signedMessage`
|
|
18293
|
+
* equals the prepared SIWE byte-for-byte; if the user narrowed, only
|
|
18294
|
+
* the ReCap block differs and every immutable header field survives.
|
|
18295
|
+
*
|
|
18296
|
+
* Legacy exact-byte {@link signIn} callers are unaffected — this method
|
|
18297
|
+
* is opt-in.
|
|
18298
|
+
*
|
|
18299
|
+
* @param authorizeFn Callback that invokes the versioned OpenKey
|
|
18300
|
+
* `authorizeTinyCloud()` protocol and returns the result. Receives
|
|
18301
|
+
* the prepared SIWE bytes plus a `host` hint the widget should bind
|
|
18302
|
+
* into its /authorize-sign-prepare context.
|
|
18303
|
+
* @param options Optional overrides for the OpenKey request.
|
|
18304
|
+
*/
|
|
18305
|
+
async signInWithOpenKey(authorizeFn, options) {
|
|
18306
|
+
if (options?.host !== void 0) {
|
|
18307
|
+
const overrideHost = options.host.trim();
|
|
18308
|
+
if (!overrideHost) {
|
|
18309
|
+
throw new Error("OpenKey authorization host must not be empty");
|
|
18310
|
+
}
|
|
18311
|
+
this.tinycloudHosts = [overrideHost];
|
|
18312
|
+
}
|
|
18313
|
+
const signingAddress = canonicalizeAddress(await this.signer.getAddress());
|
|
18314
|
+
const signingChainId = await this.signer.getChainId();
|
|
18315
|
+
await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
|
|
18316
|
+
const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
|
|
18317
|
+
const presentation = this.buildPresentationEnvelope(options?.reason);
|
|
18318
|
+
const hostHint = this.primaryTinyCloudHost;
|
|
18319
|
+
const result = await authorizeFn({
|
|
18320
|
+
protocolVersion: 1,
|
|
18321
|
+
siwe: prepared.siwe,
|
|
18322
|
+
jwk,
|
|
18323
|
+
host: hostHint,
|
|
18324
|
+
keyId: options?.openkeyKeyId,
|
|
18325
|
+
presentation
|
|
18326
|
+
});
|
|
18327
|
+
return this.signInWithOpenKeyResult(result, prepared, keyId, jwk);
|
|
18328
|
+
}
|
|
18329
|
+
/**
|
|
18330
|
+
* Build a `CapabilityPresentationEnvelopeV1` from `this._manifest`. The
|
|
18331
|
+
* envelope is display-only — the OpenKey widget renders it under an
|
|
18332
|
+
* honest trust label, and the server /authorize-sign-prepare route
|
|
18333
|
+
* decides whether to upgrade the label to `origin-bound` by fetching
|
|
18334
|
+
* the well-known manifest and comparing its digest to
|
|
18335
|
+
* `manifestDigest`.
|
|
18336
|
+
*
|
|
18337
|
+
* Returns `undefined` when no manifest is set — the widget renders as
|
|
18338
|
+
* "no manifest supplied" (unsigned).
|
|
18339
|
+
*
|
|
18340
|
+
* The digest is a deterministic SHA-256 over canonical JSON of the
|
|
18341
|
+
* first manifest payload; OpenKey parses the fetched well-known manifest
|
|
18342
|
+
* and applies the same canonicalization before comparing digests.
|
|
18343
|
+
*/
|
|
18344
|
+
buildPresentationEnvelope(reason) {
|
|
18345
|
+
const manifests = Array.isArray(this._manifest) ? this._manifest : this._manifest ? [this._manifest] : [];
|
|
18346
|
+
if (manifests.length === 0 && !reason) {
|
|
18347
|
+
return void 0;
|
|
18348
|
+
}
|
|
18349
|
+
const primary = manifests[0];
|
|
18350
|
+
let displayName;
|
|
18351
|
+
let manifestId;
|
|
18352
|
+
let manifestDigest;
|
|
18353
|
+
const envelopeManifests = [];
|
|
18354
|
+
for (const m of manifests) {
|
|
18355
|
+
envelopeManifests.push({
|
|
18356
|
+
name: m.name,
|
|
18357
|
+
appId: m.app_id,
|
|
18358
|
+
// Deep-copy to prevent later mutations from affecting the digest.
|
|
18359
|
+
payload: JSON.parse(JSON.stringify(m))
|
|
18360
|
+
});
|
|
18361
|
+
}
|
|
18362
|
+
if (primary) {
|
|
18363
|
+
displayName = primary.name;
|
|
18364
|
+
manifestId = primary.app_id;
|
|
18365
|
+
manifestDigest = canonicalOpenKeyManifestSha256Hex(primary);
|
|
18366
|
+
}
|
|
18367
|
+
return {
|
|
18368
|
+
protocolVersion: 1,
|
|
18369
|
+
displayName,
|
|
18370
|
+
reason: reason && reason.length > 0 ? reason : void 0,
|
|
18371
|
+
manifestId,
|
|
18372
|
+
manifestDigest,
|
|
18373
|
+
manifests: envelopeManifests.length > 0 ? envelopeManifests : void 0
|
|
18374
|
+
};
|
|
18375
|
+
}
|
|
18376
|
+
/**
|
|
18377
|
+
* Complete sign-in with a versioned OpenKey authorization result.
|
|
18378
|
+
*
|
|
18379
|
+
* Where `signInWithPreparedSession` completes with a signature over the
|
|
18380
|
+
* ORIGINAL prepared SIWE, this method completes with the SIWE bytes the
|
|
18381
|
+
* OpenKey widget actually presented and signed (`signedMessage`). It
|
|
18382
|
+
* exists because the versioned authorizeTinyCloud protocol lets the user
|
|
18383
|
+
* narrow capabilities; the returned bytes may differ from the original
|
|
18384
|
+
* request and are the only ones the signature actually verifies against.
|
|
18385
|
+
*
|
|
18386
|
+
* The `result` parameter is validated at the trust boundary via
|
|
18387
|
+
* `validateAuthorizationResultV1` (in sdk-core). Callers should validate
|
|
18388
|
+
* BEFORE calling this method so unknown/missing fields are rejected
|
|
18389
|
+
* before any session state is created.
|
|
18390
|
+
*
|
|
18391
|
+
* Validation performed here (defence-in-depth: even a "valid" v1 payload
|
|
18392
|
+
* must clear these checks before any session state is created):
|
|
18393
|
+
* 1. `result.address` matches the local signer's address.
|
|
18394
|
+
* 2. `result.signature` recovers to `result.address` when verified against
|
|
18395
|
+
* `result.signedMessage`.
|
|
18396
|
+
* 3. Every immutable SIWE header field (domain, address, URI, version,
|
|
18397
|
+
* chainId, nonce, issuedAt) in the original prepared SIWE is preserved
|
|
18398
|
+
* byte-for-byte in `result.signedMessage`. `statement` is NOT in this
|
|
18399
|
+
* list because the WASM renders it from the ReCap contents; it MUST
|
|
18400
|
+
* change when the ReCap is narrowed.
|
|
18401
|
+
* 4. Every capability in `result.signedMessage`'s ReCap block was present
|
|
18402
|
+
* in the original prepared SIWE — narrowing OK, broadening rejected.
|
|
18403
|
+
* 5. Every `result.selectedActionKeys` entry corresponds to a
|
|
18404
|
+
* (resource, action) pair in the returned SIWE.
|
|
18405
|
+
*/
|
|
18406
|
+
async signInWithOpenKeyResult(result, prepared, keyId, jwk) {
|
|
18407
|
+
if (result.protocolVersion !== 1) {
|
|
18408
|
+
throw new Error(`Unsupported OpenKey protocol version ${result.protocolVersion}`);
|
|
18409
|
+
}
|
|
18410
|
+
if (!result.signedMessage) {
|
|
18411
|
+
throw new Error("OpenKey result must include signedMessage");
|
|
18412
|
+
}
|
|
18413
|
+
if (!prepared.siwe) {
|
|
18414
|
+
throw new Error(
|
|
18415
|
+
"signInWithOpenKeyResult requires prepared.siwe (the SDK-generated SIWE the sign-in was proposed with)"
|
|
18416
|
+
);
|
|
18417
|
+
}
|
|
18418
|
+
const expectedAddress = canonicalizeAddress(await this.signer.getAddress());
|
|
18419
|
+
if (canonicalizeAddress(result.address) !== expectedAddress) {
|
|
18420
|
+
throw new Error(
|
|
18421
|
+
`OpenKey returned signature from ${result.address} but expected ${expectedAddress}`
|
|
18422
|
+
);
|
|
18423
|
+
}
|
|
18424
|
+
let parsedSignedSiwe;
|
|
18425
|
+
try {
|
|
18426
|
+
parsedSignedSiwe = new SiweMessage(result.signedMessage);
|
|
18427
|
+
} catch (err) {
|
|
18428
|
+
throw new Error(
|
|
18429
|
+
`OpenKey signedMessage is not a parseable SIWE: ${err.message}`
|
|
18430
|
+
);
|
|
18431
|
+
}
|
|
18432
|
+
const verifyResult = await parsedSignedSiwe.verify(
|
|
18433
|
+
{ signature: result.signature },
|
|
18434
|
+
{ suppressExceptions: true }
|
|
18435
|
+
);
|
|
18436
|
+
if (!verifyResult.success) {
|
|
18437
|
+
const errData = verifyResult.error;
|
|
18438
|
+
const type = errData && typeof errData === "object" && "type" in errData ? errData.type : void 0;
|
|
18439
|
+
const details = errData && typeof errData === "object" && "expected" in errData ? ` (expected=${errData.expected}, received=${errData.received})` : "";
|
|
18440
|
+
throw new Error(
|
|
18441
|
+
`OpenKey signature verification failed${type ? `: ${type}` : ""}${details}`
|
|
18442
|
+
);
|
|
18443
|
+
}
|
|
18444
|
+
if (canonicalizeAddress(parsedSignedSiwe.address) !== expectedAddress) {
|
|
18445
|
+
throw new Error(
|
|
18446
|
+
`OpenKey signedMessage.address (${parsedSignedSiwe.address}) does not match local signer address (${expectedAddress})`
|
|
18447
|
+
);
|
|
18448
|
+
}
|
|
18449
|
+
const originalHasRecap = /(?:^|\n)-\s+urn:recap:/i.test(prepared.siwe);
|
|
18450
|
+
const originalFields = extractImmutableSiweFields(prepared.siwe);
|
|
18451
|
+
const signedFields = extractImmutableSiweFields(result.signedMessage);
|
|
18452
|
+
const changedFields = diffImmutableSiweFields(originalFields, signedFields, {
|
|
18453
|
+
originalHasRecap
|
|
18454
|
+
});
|
|
18455
|
+
if (changedFields.length > 0) {
|
|
18456
|
+
throw new Error(
|
|
18457
|
+
`OpenKey signedMessage altered immutable SIWE fields: ${changedFields.join(", ")}`
|
|
18458
|
+
);
|
|
18459
|
+
}
|
|
18460
|
+
let originalCaps;
|
|
18461
|
+
let signedCaps;
|
|
18462
|
+
try {
|
|
18463
|
+
originalCaps = extractRecapAttenuations(prepared.siwe);
|
|
18464
|
+
} catch (err) {
|
|
18465
|
+
throw new Error(
|
|
18466
|
+
`Failed to decode prepared SIWE recap: ${err.message}`
|
|
18467
|
+
);
|
|
18468
|
+
}
|
|
18469
|
+
try {
|
|
18470
|
+
signedCaps = extractRecapAttenuations(result.signedMessage);
|
|
18471
|
+
} catch (err) {
|
|
18472
|
+
throw new Error(
|
|
18473
|
+
`Failed to decode OpenKey signedMessage recap: ${err.message}`
|
|
18474
|
+
);
|
|
18475
|
+
}
|
|
18476
|
+
const unauthorized = unauthorizedRecapCapabilities(signedCaps, originalCaps);
|
|
18477
|
+
if (unauthorized.length > 0) {
|
|
18478
|
+
const previewLimit = 5;
|
|
18479
|
+
const preview = unauthorized.slice(0, previewLimit).map((u) => `${u.resource}::${u.action}`).join(", ");
|
|
18480
|
+
const overflow = unauthorized.length > previewLimit ? ` (and ${unauthorized.length - previewLimit} more)` : "";
|
|
18481
|
+
throw new Error(
|
|
18482
|
+
`OpenKey signedMessage broadened authorization beyond the original request: ${preview}${overflow}`
|
|
18483
|
+
);
|
|
18484
|
+
}
|
|
18485
|
+
if (!result.signedMessage.includes(prepared.spaceId)) {
|
|
18486
|
+
throw new Error(
|
|
18487
|
+
`OpenKey signedMessage does not reference the expected spaceId ${prepared.spaceId}`
|
|
18488
|
+
);
|
|
18489
|
+
}
|
|
18490
|
+
const grantedPairs = /* @__PURE__ */ new Set();
|
|
18491
|
+
const grantedFourPartIndex = /* @__PURE__ */ new Map();
|
|
18492
|
+
for (const [resource, actions] of Object.entries(signedCaps)) {
|
|
18493
|
+
const { space, path } = parseCanonicalRecapResource(resource);
|
|
18494
|
+
for (const action of Object.keys(actions)) {
|
|
18495
|
+
grantedPairs.add(`${resource}\0${action}`);
|
|
18496
|
+
const slashIdx = action.indexOf("/");
|
|
18497
|
+
const service = slashIdx > 0 ? action.slice(0, slashIdx) : "";
|
|
18498
|
+
if (service) {
|
|
18499
|
+
grantedFourPartIndex.set(
|
|
18500
|
+
`${service}\0${space}\0${path}\0${action}`,
|
|
18501
|
+
`${resource}\0${action}`
|
|
18502
|
+
);
|
|
18503
|
+
}
|
|
18504
|
+
}
|
|
18505
|
+
}
|
|
18506
|
+
const isStructurallyRequired = (action) => action === "tinycloud.capabilities/read" || action === "capabilities/read";
|
|
18507
|
+
const nonRequiredGrantedPairs = /* @__PURE__ */ new Set();
|
|
18508
|
+
for (const pair of grantedPairs) {
|
|
18509
|
+
const idx = pair.indexOf("\0");
|
|
18510
|
+
const action = idx >= 0 ? pair.slice(idx + 1) : pair;
|
|
18511
|
+
if (!isStructurallyRequired(action)) {
|
|
18512
|
+
nonRequiredGrantedPairs.add(pair);
|
|
18513
|
+
}
|
|
18514
|
+
}
|
|
18515
|
+
const allSignedGrantedPairs = new Set(grantedPairs);
|
|
18516
|
+
const seenRawKeys = /* @__PURE__ */ new Set();
|
|
18517
|
+
for (const rawKey of result.selectedActionKeys) {
|
|
18518
|
+
if (seenRawKeys.has(rawKey)) {
|
|
18519
|
+
throw new Error(
|
|
18520
|
+
`OpenKey selectedActionKeys contains duplicate entry ${rawKey}`
|
|
18521
|
+
);
|
|
18522
|
+
}
|
|
18523
|
+
seenRawKeys.add(rawKey);
|
|
18524
|
+
}
|
|
18525
|
+
const selectedResourceActionPairs = /* @__PURE__ */ new Set();
|
|
18526
|
+
for (const rawKey of result.selectedActionKeys) {
|
|
18527
|
+
const parts = rawKey.split("\0");
|
|
18528
|
+
if (parts.length !== 4) {
|
|
18529
|
+
throw new Error(
|
|
18530
|
+
`OpenKey selectedActionKeys entry is malformed (expected canonical 4-part service\\0space\\0path\\0ability): ${rawKey}`
|
|
18531
|
+
);
|
|
18532
|
+
}
|
|
18533
|
+
const canonical = grantedFourPartIndex.get(rawKey);
|
|
18534
|
+
if (!canonical) {
|
|
18535
|
+
throw new Error(
|
|
18536
|
+
`OpenKey selectedActionKeys entry ${rawKey} is not covered by any granted capability`
|
|
18537
|
+
);
|
|
18538
|
+
}
|
|
18539
|
+
selectedResourceActionPairs.add(canonical);
|
|
18540
|
+
}
|
|
18541
|
+
if (nonRequiredGrantedPairs.size > 0) {
|
|
18542
|
+
const missingPairs = [];
|
|
18543
|
+
for (const pair of nonRequiredGrantedPairs) {
|
|
18544
|
+
if (!selectedResourceActionPairs.has(pair)) {
|
|
18545
|
+
missingPairs.push(pair);
|
|
18546
|
+
}
|
|
18547
|
+
}
|
|
18548
|
+
if (missingPairs.length > 0) {
|
|
18549
|
+
const previewLimit = 5;
|
|
18550
|
+
const preview = missingPairs.slice(0, previewLimit).map((p) => p.replace("\0", "::")).join(", ");
|
|
18551
|
+
const overflow = missingPairs.length > previewLimit ? ` (and ${missingPairs.length - previewLimit} more)` : "";
|
|
18552
|
+
throw new Error(
|
|
18553
|
+
`OpenKey selectedActionKeys is missing entries for signedMessage capabilities: ${preview}${overflow}`
|
|
18554
|
+
);
|
|
18555
|
+
}
|
|
18556
|
+
}
|
|
18557
|
+
if (allSignedGrantedPairs.size > 0 && result.permissions.length === 0) {
|
|
18558
|
+
throw new Error(
|
|
18559
|
+
"OpenKey permissions is empty but signedMessage carries capabilities \u2014 refusing to accept a session without an authoritative grant list"
|
|
18560
|
+
);
|
|
18561
|
+
}
|
|
18562
|
+
const permissionCanonicalKeys = /* @__PURE__ */ new Set();
|
|
18563
|
+
const permissionPairsCovered = /* @__PURE__ */ new Set();
|
|
18564
|
+
for (const perm of result.permissions) {
|
|
18565
|
+
const { service, space, path, actions } = perm;
|
|
18566
|
+
if (typeof service !== "string" || typeof space !== "string" || typeof path !== "string") {
|
|
18567
|
+
throw new Error(
|
|
18568
|
+
`OpenKey permissions entry has non-string service/space/path (service=${service}, space=${space}, path=${path})`
|
|
18569
|
+
);
|
|
18570
|
+
}
|
|
18571
|
+
if (!Array.isArray(actions) || actions.length === 0) {
|
|
18572
|
+
throw new Error(
|
|
18573
|
+
`OpenKey permissions entry (${service} ${space} ${path}) has empty actions \u2014 a capability-bearing entry must list at least one action`
|
|
18574
|
+
);
|
|
18575
|
+
}
|
|
18576
|
+
const canonicalKey = `${service}\0${space}\0${path}`;
|
|
18577
|
+
if (permissionCanonicalKeys.has(canonicalKey)) {
|
|
18578
|
+
throw new Error(
|
|
18579
|
+
`OpenKey permissions has duplicate entry for (${service} ${space} ${path})`
|
|
18580
|
+
);
|
|
18581
|
+
}
|
|
18582
|
+
permissionCanonicalKeys.add(canonicalKey);
|
|
18583
|
+
let expectedResource;
|
|
18584
|
+
if (space.startsWith("tinycloud:")) {
|
|
18585
|
+
const shortService = service.startsWith("tinycloud.") ? service.slice("tinycloud.".length) : service;
|
|
18586
|
+
expectedResource = path ? `${space}/${shortService}/${path}` : `${space}/${shortService}`;
|
|
18587
|
+
} else {
|
|
18588
|
+
if (path) {
|
|
18589
|
+
throw new Error(
|
|
18590
|
+
`OpenKey permissions entry (${service} ${space} ${path}) carries a path on a non-tinycloud: resource URI, which is not a recognized encoding`
|
|
18591
|
+
);
|
|
18592
|
+
}
|
|
18593
|
+
expectedResource = space;
|
|
18594
|
+
}
|
|
18595
|
+
let matchedResource;
|
|
18596
|
+
if (signedCaps[expectedResource] !== void 0) {
|
|
18597
|
+
matchedResource = expectedResource;
|
|
18598
|
+
} else {
|
|
18599
|
+
throw new Error(
|
|
18600
|
+
`OpenKey permissions entry (${service} ${space} ${path}) claims grants not confirmed in signedMessage capabilities`
|
|
18601
|
+
);
|
|
18602
|
+
}
|
|
18603
|
+
const grantedActionsForResource = new Set(
|
|
18604
|
+
Object.keys(signedCaps[matchedResource])
|
|
18605
|
+
);
|
|
18606
|
+
for (const action of actions) {
|
|
18607
|
+
if (typeof action !== "string" || !action) {
|
|
18608
|
+
throw new Error(
|
|
18609
|
+
`OpenKey permissions entry (${service} ${space} ${path}) has non-string action ${String(action)}`
|
|
18610
|
+
);
|
|
18611
|
+
}
|
|
18612
|
+
if (!grantedActionsForResource.has(action)) {
|
|
18613
|
+
throw new Error(
|
|
18614
|
+
`OpenKey permissions entry (${service} ${space} ${path}) claims action ${action} not present in signedMessage capabilities`
|
|
18615
|
+
);
|
|
18616
|
+
}
|
|
18617
|
+
permissionPairsCovered.add(`${matchedResource}\0${action}`);
|
|
18618
|
+
}
|
|
18619
|
+
}
|
|
18620
|
+
if (allSignedGrantedPairs.size > 0) {
|
|
18621
|
+
const missingFromPerms = [];
|
|
18622
|
+
for (const pair of allSignedGrantedPairs) {
|
|
18623
|
+
if (!permissionPairsCovered.has(pair)) {
|
|
18624
|
+
missingFromPerms.push(pair);
|
|
18625
|
+
}
|
|
18626
|
+
}
|
|
18627
|
+
if (missingFromPerms.length > 0) {
|
|
18628
|
+
const previewLimit = 5;
|
|
18629
|
+
const preview = missingFromPerms.slice(0, previewLimit).map((p) => p.replace("\0", "::")).join(", ");
|
|
18630
|
+
const overflow = missingFromPerms.length > previewLimit ? ` (and ${missingFromPerms.length - previewLimit} more)` : "";
|
|
18631
|
+
throw new Error(
|
|
18632
|
+
`OpenKey permissions is missing entries for signedMessage capabilities: ${preview}${overflow}`
|
|
18633
|
+
);
|
|
18634
|
+
}
|
|
18635
|
+
const extrasInPerms = [];
|
|
18636
|
+
for (const pair of permissionPairsCovered) {
|
|
18637
|
+
if (!allSignedGrantedPairs.has(pair)) {
|
|
18638
|
+
extrasInPerms.push(pair);
|
|
18639
|
+
}
|
|
18640
|
+
}
|
|
18641
|
+
if (extrasInPerms.length > 0) {
|
|
18642
|
+
const previewLimit = 5;
|
|
18643
|
+
const preview = extrasInPerms.slice(0, previewLimit).map((p) => p.replace("\0", "::")).join(", ");
|
|
18644
|
+
const overflow = extrasInPerms.length > previewLimit ? ` (and ${extrasInPerms.length - previewLimit} more)` : "";
|
|
18645
|
+
throw new Error(
|
|
18646
|
+
`OpenKey permissions contains entries not present in the signed authority: ${preview}${overflow}`
|
|
18647
|
+
);
|
|
18648
|
+
}
|
|
18649
|
+
}
|
|
18650
|
+
void nonRequiredGrantedPairs;
|
|
18651
|
+
return this.signInWithPreparedSession(
|
|
18652
|
+
{
|
|
18653
|
+
siwe: result.signedMessage,
|
|
18654
|
+
jwk: prepared.jwk,
|
|
18655
|
+
spaceId: prepared.spaceId,
|
|
18656
|
+
verificationMethod: prepared.verificationMethod
|
|
18657
|
+
},
|
|
18658
|
+
result.signature,
|
|
18659
|
+
keyId,
|
|
18660
|
+
jwk
|
|
18661
|
+
);
|
|
18662
|
+
}
|
|
18210
18663
|
/**
|
|
18211
18664
|
* Clear persisted session data.
|
|
18212
18665
|
*/
|
|
@@ -18462,7 +18915,7 @@ function createWasmKeyProvider(sessionManager) {
|
|
|
18462
18915
|
// src/delegateToHelpers.ts
|
|
18463
18916
|
import {
|
|
18464
18917
|
parseExpiry,
|
|
18465
|
-
SiweMessage,
|
|
18918
|
+
SiweMessage as SiweMessage2,
|
|
18466
18919
|
EXPIRY as EXPIRY2
|
|
18467
18920
|
} from "@tinycloud/sdk-core";
|
|
18468
18921
|
function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
@@ -18511,7 +18964,7 @@ function resolveExpiryMs(expiry) {
|
|
|
18511
18964
|
return parseExpiry(expiry);
|
|
18512
18965
|
}
|
|
18513
18966
|
function extractSiweExpiration(siwe) {
|
|
18514
|
-
const parsed = new
|
|
18967
|
+
const parsed = new SiweMessage2(siwe);
|
|
18515
18968
|
if (parsed.expirationTime === void 0 || parsed.expirationTime === null) {
|
|
18516
18969
|
return void 0;
|
|
18517
18970
|
}
|
|
@@ -18713,6 +19166,9 @@ var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
|
18713
19166
|
var DEFAULT_ENCRYPTION_NETWORK_NAME = "default";
|
|
18714
19167
|
var NETWORK_CREATE_ACTION2 = ENCRYPTION2.NETWORK_CREATE;
|
|
18715
19168
|
var DECRYPT_ACTION2 = ENCRYPTION2.DECRYPT;
|
|
19169
|
+
var BOOTSTRAP_COMPLETION_MARKER_KEY = "system/bootstrap/complete";
|
|
19170
|
+
var BOOTSTRAP_COMPLETION_MARKER_VERSION = 1;
|
|
19171
|
+
var ACCEPTED_MARKER_VERSIONS = [BOOTSTRAP_COMPLETION_MARKER_VERSION];
|
|
18716
19172
|
var NETWORK_ADMIN_TYPE = "tinycloud.encryption.network-admin/v1";
|
|
18717
19173
|
function isSecretPayload(value) {
|
|
18718
19174
|
return typeof value === "object" && value !== null && "value" in value && typeof value.value === "string" && "createdAt" in value && typeof value.createdAt === "string" && "updatedAt" in value && typeof value.updatedAt === "string";
|
|
@@ -18755,6 +19211,9 @@ function decodeAuthorizationBytes(authorization) {
|
|
|
18755
19211
|
function isOpenKeyAutoSignStrategy(strategy) {
|
|
18756
19212
|
return strategy?.openKeyAutoSign === true;
|
|
18757
19213
|
}
|
|
19214
|
+
function openKeyApproval(strategy) {
|
|
19215
|
+
return strategy?.openKeyRequestApproval;
|
|
19216
|
+
}
|
|
18758
19217
|
function isInteractiveSigner(config) {
|
|
18759
19218
|
if (config.privateKey) {
|
|
18760
19219
|
return false;
|
|
@@ -19120,9 +19579,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19120
19579
|
this._bootstrapSkipped = false;
|
|
19121
19580
|
/**
|
|
19122
19581
|
* Outcome of the last signIn()'s account-bootstrap attempt. `skipped` is
|
|
19123
|
-
* true when bootstrap did not complete (interactive signer,
|
|
19124
|
-
*
|
|
19125
|
-
*
|
|
19582
|
+
* true when bootstrap did not complete in this invocation (interactive signer,
|
|
19583
|
+
* auto-bootstrap disabled, already provisioned, or a decision/provisioning
|
|
19584
|
+
* step failed). `already-provisioned` means the bootstrap was not run here;
|
|
19585
|
+
* it does not mean a prior provisioning attempt failed to complete.
|
|
19586
|
+
* `reason` carries the cause so apps can surface a "finish account setup"
|
|
19587
|
+
* call-to-action. `warnings` is
|
|
19126
19588
|
* present when bootstrap completed, but one or more steps recovered from
|
|
19127
19589
|
* an ambiguous failure (e.g. a KV batch write reconciled via per-space
|
|
19128
19590
|
* fallback) — clean vs. recovered runs are otherwise byte-identical.
|
|
@@ -19305,7 +19767,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19305
19767
|
nonce: config.nonce,
|
|
19306
19768
|
siweConfig: config.siweConfig,
|
|
19307
19769
|
manifest: useBootstrapSignInRequest ? void 0 : config.manifest,
|
|
19308
|
-
capabilityRequest: useBootstrapSignInRequest ? BOOTSTRAP_SESSION_REQUESTS.default : config.capabilityRequest,
|
|
19770
|
+
capabilityRequest: useBootstrapSignInRequest ? config.includeAccountRegistryPermissions === false ? BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : BOOTSTRAP_SESSION_REQUESTS.default : config.capabilityRequest,
|
|
19309
19771
|
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : config.includeAccountRegistryPermissions
|
|
19310
19772
|
});
|
|
19311
19773
|
this.tc = new TinyCloud(this.auth, {
|
|
@@ -19395,6 +19857,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19395
19857
|
get sessionDid() {
|
|
19396
19858
|
return this.sessionManager.getDID(this.sessionKeyId);
|
|
19397
19859
|
}
|
|
19860
|
+
/** Bare did:key principal used as the credential subject and holder binding. */
|
|
19861
|
+
get credentialHolderDid() {
|
|
19862
|
+
return this.sessionDid.split("#", 1)[0];
|
|
19863
|
+
}
|
|
19864
|
+
/** Canonical verification method for the active credential holder key. */
|
|
19865
|
+
get credentialHolderKid() {
|
|
19866
|
+
const holder = this.credentialHolderDid;
|
|
19867
|
+
return `${holder}#${holder.slice("did:key:".length)}`;
|
|
19868
|
+
}
|
|
19398
19869
|
/**
|
|
19399
19870
|
* Return the current session's signed ReCap capabilities after the session
|
|
19400
19871
|
* has been authenticated or restored. This is intentionally distinct from
|
|
@@ -19445,7 +19916,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19445
19916
|
if (!this._address) {
|
|
19446
19917
|
return void 0;
|
|
19447
19918
|
}
|
|
19448
|
-
return this.wasmBindings.makeSpaceId(this._address, this._chainId,
|
|
19919
|
+
return this.wasmBindings.makeSpaceId(this._address, this._chainId, ACCOUNT_REGISTRY_SPACE2);
|
|
19449
19920
|
}
|
|
19450
19921
|
/**
|
|
19451
19922
|
* Account-level application and delegation helpers.
|
|
@@ -19548,6 +20019,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19548
20019
|
this._bootstrapSkipped = false;
|
|
19549
20020
|
this._bootstrapStatus = { skipped: false };
|
|
19550
20021
|
if (this.config.autoBootstrapAccount === false) {
|
|
20022
|
+
this._bootstrapStatus = { skipped: true, reason: "auto-bootstrap-disabled" };
|
|
19551
20023
|
return false;
|
|
19552
20024
|
}
|
|
19553
20025
|
if (!this.auth || !this._address) {
|
|
@@ -19562,11 +20034,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19562
20034
|
return false;
|
|
19563
20035
|
}
|
|
19564
20036
|
const steps = bootstrapSteps(this._address, this._chainId);
|
|
19565
|
-
if (!await this.isFreshBootstrapAccount(steps)) {
|
|
19566
|
-
return false;
|
|
19567
|
-
}
|
|
19568
20037
|
try {
|
|
19569
|
-
const
|
|
20038
|
+
const decision = await this.resolveBootstrapDecision(steps);
|
|
20039
|
+
if (decision.action === "skip") {
|
|
20040
|
+
this._bootstrapStatus = { skipped: true, reason: "already-provisioned" };
|
|
20041
|
+
return false;
|
|
20042
|
+
}
|
|
20043
|
+
const warnings = await this.runAccountBootstrap(steps, { mode: decision.mode });
|
|
20044
|
+
await this.writeBootstrapCompletionMarker(steps);
|
|
19570
20045
|
if (warnings.length > 0) {
|
|
19571
20046
|
this._bootstrapStatus = { skipped: false, warnings };
|
|
19572
20047
|
this.notificationHandler.warning(
|
|
@@ -19585,32 +20060,92 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19585
20060
|
}
|
|
19586
20061
|
return true;
|
|
19587
20062
|
}
|
|
19588
|
-
async
|
|
20063
|
+
async resolveBootstrapDecision(steps) {
|
|
19589
20064
|
const enshrinedSpaceIds = /* @__PURE__ */ new Set();
|
|
19590
20065
|
for (const step of steps) {
|
|
19591
20066
|
if (step.kind === "session") {
|
|
19592
20067
|
enshrinedSpaceIds.add(step.spaceId);
|
|
19593
20068
|
}
|
|
19594
20069
|
}
|
|
19595
|
-
const
|
|
20070
|
+
const auth = this.auth;
|
|
20071
|
+
if (!auth) {
|
|
20072
|
+
throw new Error("Account bootstrap requires an active wallet session");
|
|
20073
|
+
}
|
|
20074
|
+
const skipped = auth.lastActivationSkippedSpaceIds;
|
|
19596
20075
|
if (skipped.some((spaceId) => enshrinedSpaceIds.has(spaceId))) {
|
|
19597
|
-
return
|
|
20076
|
+
return { action: "run", mode: "fresh" };
|
|
19598
20077
|
}
|
|
19599
20078
|
try {
|
|
19600
|
-
const
|
|
19601
|
-
|
|
19602
|
-
|
|
20079
|
+
const accountSpaceId = this.ownedSpaceId(ACCOUNT_REGISTRY_SPACE2);
|
|
20080
|
+
const markerPermission = {
|
|
20081
|
+
service: "tinycloud.kv",
|
|
20082
|
+
space: accountSpaceId,
|
|
20083
|
+
path: BOOTSTRAP_COMPLETION_MARKER_KEY,
|
|
20084
|
+
actions: ["get"]
|
|
20085
|
+
};
|
|
20086
|
+
if (!this.hasRuntimePermissions([markerPermission])) {
|
|
20087
|
+
return { action: "run", mode: "repair" };
|
|
19603
20088
|
}
|
|
19604
|
-
|
|
20089
|
+
const marker = await this.readBootstrapCompletionMarker();
|
|
20090
|
+
if (marker.ok) {
|
|
20091
|
+
if (this.isAcceptedBootstrapCompletionMarker(marker.data.data)) {
|
|
20092
|
+
return { action: "skip" };
|
|
20093
|
+
}
|
|
20094
|
+
return { action: "run", mode: "repair" };
|
|
20095
|
+
}
|
|
20096
|
+
if (marker.error.code === ErrorCodes2.KV_NOT_FOUND && this.markerReadIsUnhostedSpace(marker.error.meta)) {
|
|
20097
|
+
return { action: "run", mode: "fresh" };
|
|
20098
|
+
}
|
|
20099
|
+
} catch (err) {
|
|
20100
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
20101
|
+
this.notificationHandler.warning(
|
|
20102
|
+
`Account bootstrap decision failed; attempting one bounded repair: ${reason}`
|
|
20103
|
+
);
|
|
20104
|
+
console.warn(`[TinyCloudNode] account bootstrap decision failed: ${reason}`);
|
|
20105
|
+
return { action: "run", mode: "repair" };
|
|
19605
20106
|
}
|
|
19606
|
-
|
|
19607
|
-
|
|
19608
|
-
|
|
19609
|
-
|
|
19610
|
-
|
|
20107
|
+
return { action: "run", mode: "repair" };
|
|
20108
|
+
}
|
|
20109
|
+
async readBootstrapCompletionMarker() {
|
|
20110
|
+
return this.kvForSpace(this.ownedSpaceId(ACCOUNT_REGISTRY_SPACE2)).get(
|
|
20111
|
+
BOOTSTRAP_COMPLETION_MARKER_KEY
|
|
20112
|
+
);
|
|
20113
|
+
}
|
|
20114
|
+
async writeBootstrapCompletionMarker(steps) {
|
|
20115
|
+
if (!this._address) {
|
|
20116
|
+
throw new Error("Bootstrap completion marker requires an active wallet session");
|
|
20117
|
+
}
|
|
20118
|
+
const canonicalStepIds = new Set(
|
|
20119
|
+
bootstrapSteps(this._address, this._chainId).map((step) => step.id)
|
|
20120
|
+
);
|
|
20121
|
+
const providedStepIds = new Set(steps.map((step) => step.id));
|
|
20122
|
+
if (canonicalStepIds.size !== providedStepIds.size || [...canonicalStepIds].some((stepId) => !providedStepIds.has(stepId))) {
|
|
20123
|
+
throw new Error("Bootstrap completion marker requires the canonical bootstrap step set");
|
|
20124
|
+
}
|
|
20125
|
+
const marker = {
|
|
20126
|
+
v: BOOTSTRAP_COMPLETION_MARKER_VERSION,
|
|
20127
|
+
stepIds: [...canonicalStepIds],
|
|
20128
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20129
|
+
};
|
|
20130
|
+
const written = await this.kvForSpace(this.ownedSpaceId(ACCOUNT_REGISTRY_SPACE2)).put(
|
|
20131
|
+
BOOTSTRAP_COMPLETION_MARKER_KEY,
|
|
20132
|
+
marker
|
|
20133
|
+
);
|
|
20134
|
+
if (!written.ok) {
|
|
20135
|
+
throw new Error(`Failed to write bootstrap completion marker: ${written.error.message}`);
|
|
19611
20136
|
}
|
|
19612
20137
|
}
|
|
19613
|
-
|
|
20138
|
+
isAcceptedBootstrapCompletionMarker(value) {
|
|
20139
|
+
if (typeof value !== "object" || value === null) return false;
|
|
20140
|
+
const entries = Object.entries(value);
|
|
20141
|
+
const markerValue = (name) => entries.find(([key2]) => key2 === name)?.[1];
|
|
20142
|
+
const version23 = markerValue("v");
|
|
20143
|
+
return typeof version23 === "number" && Number.isInteger(version23) && ACCEPTED_MARKER_VERSIONS.some((acceptedVersion) => acceptedVersion === version23);
|
|
20144
|
+
}
|
|
20145
|
+
markerReadIsUnhostedSpace(meta) {
|
|
20146
|
+
return meta?.status === 404;
|
|
20147
|
+
}
|
|
20148
|
+
async runAccountBootstrap(steps, { mode } = { mode: "fresh" }) {
|
|
19614
20149
|
if (!this.auth || !this._address) {
|
|
19615
20150
|
throw new Error("Account bootstrap requires an active wallet session");
|
|
19616
20151
|
}
|
|
@@ -19711,9 +20246,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19711
20246
|
if (step.kind === "seed-applications") {
|
|
19712
20247
|
const registered = await this.account.applications.register(
|
|
19713
20248
|
step.manifests.length > 0 ? [...step.manifests] : TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
|
|
19714
|
-
//
|
|
19715
|
-
// manifest-hash pre-read
|
|
19716
|
-
// it guards is an INSERT OR REPLACE and is safe to repeat.
|
|
20249
|
+
// The write is an INSERT OR REPLACE and is safe to repeat during a
|
|
20250
|
+
// repair, so skip the manifest-hash pre-read.
|
|
19717
20251
|
{ assumeUnregistered: true }
|
|
19718
20252
|
);
|
|
19719
20253
|
if (!registered.ok) {
|
|
@@ -19721,7 +20255,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19721
20255
|
}
|
|
19722
20256
|
}
|
|
19723
20257
|
if (step.kind === "encryption-network-create") {
|
|
19724
|
-
await this.ensureEncryptionNetwork(step.networkId, { assumeMissing:
|
|
20258
|
+
await this.ensureEncryptionNetwork(step.networkId, { assumeMissing: mode === "fresh" });
|
|
19725
20259
|
}
|
|
19726
20260
|
if (step.kind === "secret-records-schema") {
|
|
19727
20261
|
const db = this.sqlForSpace(step.spaceId).db(step.database);
|
|
@@ -19904,7 +20438,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19904
20438
|
if (!this.auth || !this.signer) {
|
|
19905
20439
|
throw new Error("Manifest registry write requires wallet mode");
|
|
19906
20440
|
}
|
|
19907
|
-
const accountSpaceId = this.ownedSpaceId(
|
|
20441
|
+
const accountSpaceId = this.ownedSpaceId(ACCOUNT_REGISTRY_SPACE2);
|
|
19908
20442
|
await this.ensureOwnedSpaceHostedById(accountSpaceId);
|
|
19909
20443
|
const result = await this.account.applications.register(request.manifests);
|
|
19910
20444
|
if (!result.ok) {
|
|
@@ -20160,6 +20694,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20160
20694
|
}
|
|
20161
20695
|
return hosted;
|
|
20162
20696
|
}
|
|
20697
|
+
/** Resolve and authenticate the owner encoded by an owned-space URI. */
|
|
20698
|
+
credentialSpaceOwnerDid(spaceId) {
|
|
20699
|
+
const ownerDid = this.ownerDidFromSpaceId(spaceId);
|
|
20700
|
+
if (ownerDid === void 0 || !didPrincipalMatches2(ownerDid, this.did)) {
|
|
20701
|
+
throw new Error("Credential space owner does not match the active TinyCloud owner");
|
|
20702
|
+
}
|
|
20703
|
+
return ownerDid;
|
|
20704
|
+
}
|
|
20163
20705
|
/**
|
|
20164
20706
|
* Check whether an owned space is already registered/hosted by consulting the
|
|
20165
20707
|
* account spaces registry.
|
|
@@ -20703,6 +21245,66 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20703
21245
|
if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
|
|
20704
21246
|
return signBytesWithJwk(bytes, session.jwk);
|
|
20705
21247
|
}
|
|
21248
|
+
/** Apply only an already-enabled signing policy to the exact credential request. */
|
|
21249
|
+
async autoSignCredentialBytes(bytes) {
|
|
21250
|
+
const strategy = this.config.signStrategy;
|
|
21251
|
+
if (strategy?.type === "auto-sign") return this.signSessionBytes(bytes);
|
|
21252
|
+
if (strategy?.type !== "callback" || !isOpenKeyAutoSignStrategy(strategy)) return void 0;
|
|
21253
|
+
const session = this.currentTinyCloudSession() ?? this._activeServiceSession;
|
|
21254
|
+
if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
|
|
21255
|
+
const request = {
|
|
21256
|
+
address: this.address ?? "",
|
|
21257
|
+
chainId: this.session?.chainId ?? this._chainId,
|
|
21258
|
+
message: new TextDecoder().decode(bytes),
|
|
21259
|
+
type: "message",
|
|
21260
|
+
purpose: "message"
|
|
21261
|
+
};
|
|
21262
|
+
const decision = await strategy.handler(request);
|
|
21263
|
+
if (!decision.approved) {
|
|
21264
|
+
if (decision.needsApproval) return void 0;
|
|
21265
|
+
throw new Error(decision.reason ?? "OpenKey automatic credential signing was rejected");
|
|
21266
|
+
}
|
|
21267
|
+
if (typeof decision.signature !== "string" || !await verifyEip191MessageSignature(
|
|
21268
|
+
request.message,
|
|
21269
|
+
decision.signature,
|
|
21270
|
+
request.address
|
|
21271
|
+
)) {
|
|
21272
|
+
throw new Error("OpenKey credential signature evidence is invalid");
|
|
21273
|
+
}
|
|
21274
|
+
return this.signSessionBytes(bytes);
|
|
21275
|
+
}
|
|
21276
|
+
/** Invoke the configured interactive approval strategy before session signing. */
|
|
21277
|
+
async approveCredentialBytes(bytes) {
|
|
21278
|
+
const strategy = this.config.signStrategy;
|
|
21279
|
+
const session = this.currentTinyCloudSession() ?? this._activeServiceSession;
|
|
21280
|
+
if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
|
|
21281
|
+
const request = {
|
|
21282
|
+
address: this.address ?? "",
|
|
21283
|
+
chainId: this.session?.chainId ?? this._chainId,
|
|
21284
|
+
message: new TextDecoder().decode(bytes),
|
|
21285
|
+
type: "message",
|
|
21286
|
+
purpose: "message"
|
|
21287
|
+
};
|
|
21288
|
+
const approval = isOpenKeyAutoSignStrategy(strategy) ? openKeyApproval(strategy) : strategy?.type === "callback" ? strategy.handler : void 0;
|
|
21289
|
+
if (approval) {
|
|
21290
|
+
const decision = await approval(request);
|
|
21291
|
+
if (!decision.approved) throw new Error(decision.reason ?? "Credential signing was rejected");
|
|
21292
|
+
if (decision.signature !== void 0 && !await verifyEip191MessageSignature(
|
|
21293
|
+
request.message,
|
|
21294
|
+
decision.signature,
|
|
21295
|
+
request.address
|
|
21296
|
+
)) {
|
|
21297
|
+
throw new Error("OpenKey credential signature evidence is invalid");
|
|
21298
|
+
}
|
|
21299
|
+
return this.signSessionBytes(bytes);
|
|
21300
|
+
}
|
|
21301
|
+
if (strategy?.type === "auto-reject") throw new Error("Credential signing was rejected");
|
|
21302
|
+
if (this.config.signer) {
|
|
21303
|
+
await this.config.signer.signMessage(request.message);
|
|
21304
|
+
return this.signSessionBytes(bytes);
|
|
21305
|
+
}
|
|
21306
|
+
throw new Error("Interactive OpenKey approval is not configured");
|
|
21307
|
+
}
|
|
20706
21308
|
/** Bind a session-signed invocation to the canonical service audience. */
|
|
20707
21309
|
async bindInvocationAudience(authorization, audience) {
|
|
20708
21310
|
const session = this.currentTinyCloudSession() ?? this._activeServiceSession;
|
|
@@ -20770,7 +21372,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20770
21372
|
nonce: this.config.nonce,
|
|
20771
21373
|
siweConfig: this.config.siweConfig,
|
|
20772
21374
|
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
20773
|
-
capabilityRequest: useBootstrapSignInRequest ? BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
21375
|
+
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
20774
21376
|
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
|
|
20775
21377
|
});
|
|
20776
21378
|
this.tc = new TinyCloud(this.auth, {
|
|
@@ -20823,7 +21425,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20823
21425
|
nonce: this.config.nonce,
|
|
20824
21426
|
siweConfig: this.config.siweConfig,
|
|
20825
21427
|
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
20826
|
-
capabilityRequest: useBootstrapSignInRequest ? BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
21428
|
+
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
20827
21429
|
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
|
|
20828
21430
|
});
|
|
20829
21431
|
this.tc = new TinyCloud(this.auth, {
|
|
@@ -23572,35 +24174,44 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23572
24174
|
if (parentDelegation.disableSubDelegation) {
|
|
23573
24175
|
throw new Error("Parent delegation does not allow sub-delegation");
|
|
23574
24176
|
}
|
|
23575
|
-
|
|
24177
|
+
const parentResources = parentDelegation.resources ?? [{
|
|
24178
|
+
service: parentDelegation.actions[0]?.split("/", 1)[0]?.replace(/^tinycloud\./, "") ?? "kv",
|
|
24179
|
+
space: parentDelegation.spaceId,
|
|
24180
|
+
path: parentDelegation.path,
|
|
24181
|
+
actions: parentDelegation.actions
|
|
24182
|
+
}];
|
|
24183
|
+
const requestedResources = params.resources ?? [{
|
|
24184
|
+
service: params.actions[0]?.split("/", 1)[0]?.replace(/^tinycloud\./, "") ?? "kv",
|
|
24185
|
+
space: parentDelegation.spaceId,
|
|
24186
|
+
path: params.path,
|
|
24187
|
+
actions: params.actions
|
|
24188
|
+
}];
|
|
24189
|
+
const resourceIsContained = (parent, child) => {
|
|
24190
|
+
const parentEncryption = parent.service === "encryption" || parent.service === "tinycloud.encryption";
|
|
24191
|
+
const childEncryption = child.service === "encryption" || child.service === "tinycloud.encryption";
|
|
24192
|
+
if (parentEncryption || childEncryption) return parentEncryption && childEncryption && parent.path === child.path && child.actions.every((action) => parent.actions.includes(action));
|
|
24193
|
+
const pathContained = parent.path === child.path || parent.path.endsWith("/") && child.path.startsWith(parent.path) || child.path.startsWith(`${parent.path}/`);
|
|
24194
|
+
return pathContained && child.actions.every((action) => parent.actions.includes(action));
|
|
24195
|
+
};
|
|
24196
|
+
if (requestedResources.length === 0 || requestedResources.some((child) => !parentResources.some((parent) => resourceIsContained(parent, child)))) {
|
|
23576
24197
|
throw new Error(
|
|
23577
|
-
|
|
24198
|
+
"Sub-delegation resources exceed the received delegation"
|
|
23578
24199
|
);
|
|
23579
24200
|
}
|
|
23580
|
-
const parentActions = new Set(parentDelegation.actions);
|
|
23581
|
-
for (const action of params.actions) {
|
|
23582
|
-
if (!parentActions.has(action)) {
|
|
23583
|
-
throw new Error(
|
|
23584
|
-
`Sub-delegation action "${action}" is not in parent's actions: ${parentDelegation.actions.join(", ")}`
|
|
23585
|
-
);
|
|
23586
|
-
}
|
|
23587
|
-
}
|
|
23588
24201
|
const now = /* @__PURE__ */ new Date();
|
|
23589
24202
|
const expiryMs = params.expiryMs ?? 60 * 60 * 1e3;
|
|
23590
24203
|
const requestedExpiry = new Date(now.getTime() + expiryMs);
|
|
23591
24204
|
const actualExpiry = requestedExpiry > parentDelegation.expiry ? parentDelegation.expiry : requestedExpiry;
|
|
23592
24205
|
const abilities = {};
|
|
23593
|
-
const
|
|
23594
|
-
const
|
|
23595
|
-
|
|
23596
|
-
|
|
23597
|
-
|
|
23598
|
-
|
|
23599
|
-
|
|
23600
|
-
abilities
|
|
23601
|
-
|
|
23602
|
-
if (duckdbActions.length > 0) {
|
|
23603
|
-
abilities.duckdb = { [params.path]: duckdbActions };
|
|
24206
|
+
const rawAbilities = {};
|
|
24207
|
+
for (const resource of requestedResources) {
|
|
24208
|
+
const service = resource.service.replace(/^tinycloud\./, "");
|
|
24209
|
+
if (service === "encryption") {
|
|
24210
|
+
rawAbilities[resource.path] = [...resource.actions];
|
|
24211
|
+
continue;
|
|
24212
|
+
}
|
|
24213
|
+
abilities[service] ?? (abilities[service] = {});
|
|
24214
|
+
abilities[service][resource.path] = [...resource.actions];
|
|
23604
24215
|
}
|
|
23605
24216
|
const targetHost = parentDelegation.host ?? this.config.host;
|
|
23606
24217
|
const prepared = this.wasmBindings.prepareSession({
|
|
@@ -23612,7 +24223,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23612
24223
|
expirationTime: actualExpiry.toISOString(),
|
|
23613
24224
|
spaceId: parentDelegation.spaceId,
|
|
23614
24225
|
delegateUri: params.delegateDID,
|
|
23615
|
-
parents: [parentDelegation.cid]
|
|
24226
|
+
parents: [parentDelegation.cid],
|
|
24227
|
+
...Object.keys(rawAbilities).length > 0 ? { rawAbilities } : {}
|
|
23616
24228
|
});
|
|
23617
24229
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
23618
24230
|
const subDelegationSession = this.wasmBindings.completeSessionSetup({
|
|
@@ -23630,14 +24242,20 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23630
24242
|
cid: subDelegationSession.delegationCid,
|
|
23631
24243
|
delegationHeader: subDelegationSession.delegationHeader,
|
|
23632
24244
|
spaceId: parentDelegation.spaceId,
|
|
23633
|
-
path:
|
|
23634
|
-
actions:
|
|
24245
|
+
path: requestedResources[0].path,
|
|
24246
|
+
actions: requestedResources[0].actions,
|
|
23635
24247
|
disableSubDelegation: params.disableSubDelegation ?? false,
|
|
23636
24248
|
expiry: actualExpiry,
|
|
23637
24249
|
delegateDID: params.delegateDID,
|
|
23638
24250
|
ownerAddress: parentDelegation.ownerAddress,
|
|
23639
24251
|
chainId: parentDelegation.chainId,
|
|
23640
|
-
host: targetHost
|
|
24252
|
+
host: targetHost,
|
|
24253
|
+
resources: requestedResources.map((resource) => ({
|
|
24254
|
+
service: resource.service.replace(/^tinycloud\./, ""),
|
|
24255
|
+
space: resource.service.replace(/^tinycloud\./, "") === "encryption" ? "encryption" : resource.space ?? parentDelegation.spaceId,
|
|
24256
|
+
path: resource.path,
|
|
24257
|
+
actions: [...resource.actions]
|
|
24258
|
+
}))
|
|
23641
24259
|
};
|
|
23642
24260
|
}
|
|
23643
24261
|
};
|
|
@@ -23810,10 +24428,54 @@ var FileSessionStorage = class {
|
|
|
23810
24428
|
}
|
|
23811
24429
|
};
|
|
23812
24430
|
|
|
24431
|
+
// src/authorization/openKeyBridge.ts
|
|
24432
|
+
function wireOpenKeyAuthorize(openkey) {
|
|
24433
|
+
return async (input) => {
|
|
24434
|
+
const result = await openkey.authorizeTinyCloud({
|
|
24435
|
+
protocolVersion: 1,
|
|
24436
|
+
siwe: input.siwe,
|
|
24437
|
+
keyId: input.keyId,
|
|
24438
|
+
jwk: input.jwk,
|
|
24439
|
+
host: input.host,
|
|
24440
|
+
// Forward the presentation envelope verbatim — the OpenKey SDK
|
|
24441
|
+
// validates and size-bounds it before use.
|
|
24442
|
+
presentation: input.presentation
|
|
24443
|
+
});
|
|
24444
|
+
if (result.protocolVersion !== 1) {
|
|
24445
|
+
throw new Error(
|
|
24446
|
+
`wireOpenKeyAuthorize: OpenKey returned unsupported protocolVersion ${result.protocolVersion}`
|
|
24447
|
+
);
|
|
24448
|
+
}
|
|
24449
|
+
if (typeof result.signedMessage !== "string" || !result.signedMessage) {
|
|
24450
|
+
throw new Error(
|
|
24451
|
+
"wireOpenKeyAuthorize: OpenKey returned no signedMessage \u2014 cannot complete a TinyCloud session"
|
|
24452
|
+
);
|
|
24453
|
+
}
|
|
24454
|
+
if (!Array.isArray(result.selectedActionKeys)) {
|
|
24455
|
+
throw new Error(
|
|
24456
|
+
"wireOpenKeyAuthorize: OpenKey returned no selectedActionKeys"
|
|
24457
|
+
);
|
|
24458
|
+
}
|
|
24459
|
+
if (!Array.isArray(result.permissions)) {
|
|
24460
|
+
throw new Error(
|
|
24461
|
+
"wireOpenKeyAuthorize: OpenKey returned no permissions"
|
|
24462
|
+
);
|
|
24463
|
+
}
|
|
24464
|
+
return {
|
|
24465
|
+
protocolVersion: 1,
|
|
24466
|
+
address: result.address,
|
|
24467
|
+
signature: result.signature,
|
|
24468
|
+
signedMessage: result.signedMessage,
|
|
24469
|
+
selectedActionKeys: result.selectedActionKeys,
|
|
24470
|
+
permissions: result.permissions
|
|
24471
|
+
};
|
|
24472
|
+
};
|
|
24473
|
+
}
|
|
24474
|
+
|
|
23813
24475
|
// src/index.ts
|
|
23814
24476
|
import {
|
|
23815
24477
|
ACCOUNT_REGISTRY_PATH,
|
|
23816
|
-
ACCOUNT_REGISTRY_SPACE as
|
|
24478
|
+
ACCOUNT_REGISTRY_SPACE as ACCOUNT_REGISTRY_SPACE3,
|
|
23817
24479
|
DEFAULT_MANIFEST_SPACE as DEFAULT_MANIFEST_SPACE2,
|
|
23818
24480
|
DEFAULT_MANIFEST_VERSION,
|
|
23819
24481
|
VAULT_PERMISSION_SERVICE,
|
|
@@ -23921,6 +24583,14 @@ function signedAuthorityFromCompactUcan(authorization) {
|
|
|
23921
24583
|
if (typeof payload.aud !== "string" || payload.aud.length === 0) {
|
|
23922
24584
|
throw new Error("Validated runtime delegation is missing a signed audience.");
|
|
23923
24585
|
}
|
|
24586
|
+
if (typeof payload.iss !== "string" || payload.iss.length === 0) {
|
|
24587
|
+
throw new Error("Validated runtime delegation is missing a signed issuer.");
|
|
24588
|
+
}
|
|
24589
|
+
if (!Array.isArray(payload.prf) || payload.prf.some(
|
|
24590
|
+
(proof) => typeof proof !== "string" || proof.length === 0
|
|
24591
|
+
)) {
|
|
24592
|
+
throw new Error("Validated runtime delegation has malformed signed proofs.");
|
|
24593
|
+
}
|
|
23924
24594
|
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp)) {
|
|
23925
24595
|
throw new Error("Validated runtime delegation is missing a signed expiry.");
|
|
23926
24596
|
}
|
|
@@ -23931,6 +24601,11 @@ function signedAuthorityFromCompactUcan(authorization) {
|
|
|
23931
24601
|
if (payload.att === null || typeof payload.att !== "object" || Array.isArray(payload.att)) {
|
|
23932
24602
|
throw new Error("Validated runtime delegation is missing a signed attenuation.");
|
|
23933
24603
|
}
|
|
24604
|
+
const fact = Array.isArray(payload.fct) && payload.fct.length > 0 && payload.fct[0] !== null && typeof payload.fct[0] === "object" && !Array.isArray(payload.fct[0]) ? payload.fct[0] : void 0;
|
|
24605
|
+
const remainingRedelegationDepth = fact?.remainingRedelegationDepth;
|
|
24606
|
+
if (remainingRedelegationDepth !== void 0 && (!Number.isInteger(remainingRedelegationDepth) || remainingRedelegationDepth < 0 || remainingRedelegationDepth > 8)) {
|
|
24607
|
+
throw new Error("Validated runtime delegation has invalid signed redelegation depth.");
|
|
24608
|
+
}
|
|
23934
24609
|
const permissions = [];
|
|
23935
24610
|
for (const [resource, abilities] of Object.entries(payload.att)) {
|
|
23936
24611
|
if (abilities === null || typeof abilities !== "object" || Array.isArray(abilities)) {
|
|
@@ -23981,8 +24656,11 @@ function signedAuthorityFromCompactUcan(authorization) {
|
|
|
23981
24656
|
...permission.caveats === void 0 ? {} : { caveats: permission.caveats }
|
|
23982
24657
|
}));
|
|
23983
24658
|
return {
|
|
24659
|
+
issuer: payload.iss,
|
|
23984
24660
|
audience: payload.aud,
|
|
23985
24661
|
expiry,
|
|
24662
|
+
proofs: [...payload.prf],
|
|
24663
|
+
...remainingRedelegationDepth === void 0 ? {} : { remainingRedelegationDepth },
|
|
23986
24664
|
permissions: canonicalPermissions,
|
|
23987
24665
|
resources: canonicalResources
|
|
23988
24666
|
};
|
|
@@ -24073,6 +24751,13 @@ async function activateValidatedRuntimeDelegation(node, delegation, options) {
|
|
|
24073
24751
|
delegationHeader: { Authorization: authorization },
|
|
24074
24752
|
ownerAddress: delegation.ownerAddress,
|
|
24075
24753
|
chainId: delegation.chainId,
|
|
24754
|
+
delegatorDID: signed2.issuer,
|
|
24755
|
+
...signed2.proofs.length === 1 ? { parentCid: signed2.proofs[0] } : {},
|
|
24756
|
+
...signed2.remainingRedelegationDepth === void 0 ? {} : {
|
|
24757
|
+
allowSubDelegation: signed2.remainingRedelegationDepth > 0,
|
|
24758
|
+
disableSubDelegation: signed2.remainingRedelegationDepth === 0
|
|
24759
|
+
},
|
|
24760
|
+
authHeader: authorization,
|
|
24076
24761
|
spaceId: signedSpace ?? delegation.spaceId,
|
|
24077
24762
|
path: primary.path,
|
|
24078
24763
|
actions: [...primary.actions],
|
|
@@ -24247,10 +24932,13 @@ import {
|
|
|
24247
24932
|
} from "@tinycloud/sdk-core";
|
|
24248
24933
|
import { ServiceContext as ServiceContext3 } from "@tinycloud/sdk-core";
|
|
24249
24934
|
export {
|
|
24935
|
+
ACCEPTED_MARKER_VERSIONS,
|
|
24250
24936
|
ACCOUNT_REGISTRY_PATH,
|
|
24251
|
-
|
|
24937
|
+
ACCOUNT_REGISTRY_SPACE3 as ACCOUNT_REGISTRY_SPACE,
|
|
24252
24938
|
AccountService,
|
|
24253
24939
|
AutoApproveSpaceCreationHandler2 as AutoApproveSpaceCreationHandler,
|
|
24940
|
+
BOOTSTRAP_COMPLETION_MARKER_KEY,
|
|
24941
|
+
BOOTSTRAP_COMPLETION_MARKER_VERSION,
|
|
24254
24942
|
CapabilityKeyRegistry2 as CapabilityKeyRegistry,
|
|
24255
24943
|
CapabilityKeyRegistryErrorCodes,
|
|
24256
24944
|
CaveatedDelegationUnsupportedError2 as CaveatedDelegationUnsupportedError,
|
|
@@ -24387,7 +25075,8 @@ export {
|
|
|
24387
25075
|
tinyCloudDebugLogger,
|
|
24388
25076
|
validateEnvelope,
|
|
24389
25077
|
validateManifest,
|
|
24390
|
-
verifyDecryptResponse
|
|
25078
|
+
verifyDecryptResponse,
|
|
25079
|
+
wireOpenKeyAuthorize
|
|
24391
25080
|
};
|
|
24392
25081
|
/*! Bundled license information:
|
|
24393
25082
|
|