@tinycloud/node-sdk 2.2.0-beta.9 → 2.2.1-beta.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-DcJ27GsA.d.cts → core-CNyXnUx9.d.cts} +80 -6
- package/dist/{core-DcJ27GsA.d.ts → core-CNyXnUx9.d.ts} +80 -6
- package/dist/core.cjs +725 -92
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +743 -99
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +819 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +822 -100
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -17031,6 +17031,7 @@ var require_utils2 = __commonJS({
|
|
|
17031
17031
|
import {
|
|
17032
17032
|
invoke,
|
|
17033
17033
|
invokeAny,
|
|
17034
|
+
computeCid,
|
|
17034
17035
|
prepareSession,
|
|
17035
17036
|
completeSessionSetup,
|
|
17036
17037
|
ensureEip55,
|
|
@@ -17054,6 +17055,7 @@ var _NodeWasmBindings = class _NodeWasmBindings {
|
|
|
17054
17055
|
constructor() {
|
|
17055
17056
|
this.invoke = invoke;
|
|
17056
17057
|
this.invokeAny = invokeAny;
|
|
17058
|
+
this.computeCid = computeCid;
|
|
17057
17059
|
this.prepareSession = prepareSession;
|
|
17058
17060
|
this.completeSessionSetup = completeSessionSetup;
|
|
17059
17061
|
this.ensureEip55 = ensureEip55;
|
|
@@ -17159,6 +17161,7 @@ import {
|
|
|
17159
17161
|
DuckDbService as DuckDbService2,
|
|
17160
17162
|
HooksService as HooksService2,
|
|
17161
17163
|
DataVaultService,
|
|
17164
|
+
EncryptionService,
|
|
17162
17165
|
SecretsService,
|
|
17163
17166
|
createVaultCrypto,
|
|
17164
17167
|
ServiceContext as ServiceContext2,
|
|
@@ -17170,12 +17173,17 @@ import {
|
|
|
17170
17173
|
UnsupportedFeatureError,
|
|
17171
17174
|
makePublicSpaceId,
|
|
17172
17175
|
ACCOUNT_REGISTRY_SPACE,
|
|
17176
|
+
ENCRYPTION_PERMISSION_SERVICE as ENCRYPTION_PERMISSION_SERVICE2,
|
|
17173
17177
|
PermissionNotInManifestError,
|
|
17174
17178
|
SessionExpiredError,
|
|
17175
17179
|
expandPermissionEntries as expandPermissionEntriesCore,
|
|
17176
17180
|
isCapabilitySubset,
|
|
17177
17181
|
parseRecapCapabilities,
|
|
17178
|
-
SERVICE_LONG_TO_SHORT
|
|
17182
|
+
SERVICE_LONG_TO_SHORT,
|
|
17183
|
+
EXPIRY as EXPIRY3,
|
|
17184
|
+
canonicalHashHex,
|
|
17185
|
+
canonicalizeEncryptionJson,
|
|
17186
|
+
verifyDidKeyEd25519Signature
|
|
17179
17187
|
} from "@tinycloud/sdk-core";
|
|
17180
17188
|
|
|
17181
17189
|
// src/authorization/NodeUserAuthorization.ts
|
|
@@ -17186,10 +17194,12 @@ import {
|
|
|
17186
17194
|
checkNodeInfo,
|
|
17187
17195
|
AutoApproveSpaceCreationHandler,
|
|
17188
17196
|
DEFAULT_MANIFEST_SPACE,
|
|
17197
|
+
ENCRYPTION_PERMISSION_SERVICE,
|
|
17189
17198
|
composeManifestRequest,
|
|
17190
17199
|
resourceCapabilitiesToAbilitiesMap,
|
|
17191
17200
|
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
17192
|
-
resolveTinyCloudHosts
|
|
17201
|
+
resolveTinyCloudHosts,
|
|
17202
|
+
EXPIRY
|
|
17193
17203
|
} from "@tinycloud/sdk-core";
|
|
17194
17204
|
|
|
17195
17205
|
// src/authorization/strategies.ts
|
|
@@ -17320,7 +17330,7 @@ var NodeUserAuthorization = class {
|
|
|
17320
17330
|
]
|
|
17321
17331
|
}
|
|
17322
17332
|
};
|
|
17323
|
-
this.sessionExpirationMs = config.sessionExpirationMs ??
|
|
17333
|
+
this.sessionExpirationMs = config.sessionExpirationMs ?? EXPIRY.SESSION_MS;
|
|
17324
17334
|
this.autoCreateSpace = config.autoCreateSpace ?? false;
|
|
17325
17335
|
this.spaceCreationHandler = config.spaceCreationHandler;
|
|
17326
17336
|
this.tinycloudHosts = config.tinycloudHosts;
|
|
@@ -17373,6 +17383,23 @@ var NodeUserAuthorization = class {
|
|
|
17373
17383
|
get tinyCloudSession() {
|
|
17374
17384
|
return this._tinyCloudSession;
|
|
17375
17385
|
}
|
|
17386
|
+
/**
|
|
17387
|
+
* Rehydrate the auth-layer session from previously-persisted delegation
|
|
17388
|
+
* data. Used by {@link TinyCloudNode.restoreSession} so that downstream
|
|
17389
|
+
* surfaces that read from `tinyCloudSession` (notably
|
|
17390
|
+
* `grantRuntimePermissions`, which extracts the SIWE expiry from it) work
|
|
17391
|
+
* without re-running the full sign-in flow.
|
|
17392
|
+
*
|
|
17393
|
+
* Caller must supply the same fields that `signIn` would have written —
|
|
17394
|
+
* `siwe` is the load-bearing one because `extractSiweExpiration` returns
|
|
17395
|
+
* undefined for missing SIWEs and the SDK then treats the session as
|
|
17396
|
+
* expired-at-epoch-zero.
|
|
17397
|
+
*/
|
|
17398
|
+
setRestoredTinyCloudSession(session) {
|
|
17399
|
+
this._tinyCloudSession = session;
|
|
17400
|
+
this._address = session.address;
|
|
17401
|
+
this._chainId = session.chainId;
|
|
17402
|
+
}
|
|
17376
17403
|
async resolveTinyCloudHostsForSignIn(address, chainId) {
|
|
17377
17404
|
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
17378
17405
|
return;
|
|
@@ -17443,21 +17470,64 @@ var NodeUserAuthorization = class {
|
|
|
17443
17470
|
}
|
|
17444
17471
|
return this.wasm.makeSpaceId(address, chainId, space);
|
|
17445
17472
|
}
|
|
17473
|
+
defaultEncryptionNetworkId(address, chainId) {
|
|
17474
|
+
return `urn:tinycloud:encryption:did:pkh:eip155:${chainId}:${address}:default`;
|
|
17475
|
+
}
|
|
17446
17476
|
resolveSignInCapabilities(address, chainId) {
|
|
17447
17477
|
const request = this.getCapabilityRequest();
|
|
17448
17478
|
if (request === void 0) {
|
|
17479
|
+
const defaultNetworkId = this.defaultEncryptionNetworkId(address, chainId);
|
|
17480
|
+
const secretsSpaceId = this.wasm.makeSpaceId(address, chainId, "secrets");
|
|
17449
17481
|
return {
|
|
17450
17482
|
abilities: this.defaultActions,
|
|
17451
|
-
spaceId: this.wasm.makeSpaceId(address, chainId, this.spacePrefix)
|
|
17483
|
+
spaceId: this.wasm.makeSpaceId(address, chainId, this.spacePrefix),
|
|
17484
|
+
spaceAbilities: {
|
|
17485
|
+
[secretsSpaceId]: {
|
|
17486
|
+
kv: {
|
|
17487
|
+
"vault/secrets/": [
|
|
17488
|
+
"tinycloud.kv/get",
|
|
17489
|
+
"tinycloud.kv/put",
|
|
17490
|
+
"tinycloud.kv/del",
|
|
17491
|
+
"tinycloud.kv/list",
|
|
17492
|
+
"tinycloud.kv/metadata"
|
|
17493
|
+
]
|
|
17494
|
+
}
|
|
17495
|
+
}
|
|
17496
|
+
},
|
|
17497
|
+
rawAbilities: {
|
|
17498
|
+
[defaultNetworkId]: [
|
|
17499
|
+
"tinycloud.encryption/decrypt",
|
|
17500
|
+
"tinycloud.encryption/network.create"
|
|
17501
|
+
]
|
|
17502
|
+
}
|
|
17452
17503
|
};
|
|
17453
17504
|
}
|
|
17454
|
-
const
|
|
17505
|
+
const rawAbilities = {};
|
|
17506
|
+
const spaceResources = request.resources.filter((entry) => {
|
|
17507
|
+
if (entry.service !== ENCRYPTION_PERMISSION_SERVICE) {
|
|
17508
|
+
return true;
|
|
17509
|
+
}
|
|
17510
|
+
const existing = rawAbilities[entry.path];
|
|
17511
|
+
if (existing === void 0) {
|
|
17512
|
+
rawAbilities[entry.path] = [...entry.actions];
|
|
17513
|
+
} else {
|
|
17514
|
+
const seen = new Set(existing);
|
|
17515
|
+
for (const action of entry.actions) {
|
|
17516
|
+
if (!seen.has(action)) {
|
|
17517
|
+
existing.push(action);
|
|
17518
|
+
seen.add(action);
|
|
17519
|
+
}
|
|
17520
|
+
}
|
|
17521
|
+
}
|
|
17522
|
+
return false;
|
|
17523
|
+
});
|
|
17524
|
+
const primarySpaceName = spaceResources.find((entry) => entry.space !== "account")?.space ?? DEFAULT_MANIFEST_SPACE;
|
|
17455
17525
|
const primarySpaceId = this.resolveSpaceName(
|
|
17456
17526
|
primarySpaceName,
|
|
17457
17527
|
address,
|
|
17458
17528
|
chainId
|
|
17459
17529
|
);
|
|
17460
|
-
const bySpace = resourceCapabilitiesToSpaceAbilitiesMap(
|
|
17530
|
+
const bySpace = resourceCapabilitiesToSpaceAbilitiesMap(spaceResources);
|
|
17461
17531
|
const spaceAbilities = {};
|
|
17462
17532
|
for (const [space, abilities] of Object.entries(bySpace)) {
|
|
17463
17533
|
spaceAbilities[this.resolveSpaceName(space, address, chainId)] = abilities;
|
|
@@ -17465,7 +17535,8 @@ var NodeUserAuthorization = class {
|
|
|
17465
17535
|
return {
|
|
17466
17536
|
abilities: spaceAbilities[primarySpaceId] ?? resourceCapabilitiesToAbilitiesMap([]),
|
|
17467
17537
|
spaceId: primarySpaceId,
|
|
17468
|
-
spaceAbilities
|
|
17538
|
+
spaceAbilities,
|
|
17539
|
+
rawAbilities: Object.keys(rawAbilities).length > 0 ? rawAbilities : void 0
|
|
17469
17540
|
};
|
|
17470
17541
|
}
|
|
17471
17542
|
/**
|
|
@@ -17690,6 +17761,7 @@ var NodeUserAuthorization = class {
|
|
|
17690
17761
|
const prepared = this.wasm.prepareSession({
|
|
17691
17762
|
abilities: capabilityPlan.abilities,
|
|
17692
17763
|
...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
|
|
17764
|
+
...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
|
|
17693
17765
|
address,
|
|
17694
17766
|
chainId,
|
|
17695
17767
|
domain: this.domain,
|
|
@@ -17835,6 +17907,7 @@ var NodeUserAuthorization = class {
|
|
|
17835
17907
|
const prepared = this.wasm.prepareSession({
|
|
17836
17908
|
abilities: capabilityPlan.abilities,
|
|
17837
17909
|
...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
|
|
17910
|
+
...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
|
|
17838
17911
|
address,
|
|
17839
17912
|
chainId,
|
|
17840
17913
|
domain: this.domain,
|
|
@@ -18182,7 +18255,8 @@ function createWasmKeyProvider(sessionManager) {
|
|
|
18182
18255
|
// src/delegateToHelpers.ts
|
|
18183
18256
|
import {
|
|
18184
18257
|
parseExpiry,
|
|
18185
|
-
SiweMessage
|
|
18258
|
+
SiweMessage,
|
|
18259
|
+
EXPIRY as EXPIRY2
|
|
18186
18260
|
} from "@tinycloud/sdk-core";
|
|
18187
18261
|
function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
18188
18262
|
const byService = /* @__PURE__ */ new Map();
|
|
@@ -18214,9 +18288,10 @@ function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
|
18214
18288
|
}
|
|
18215
18289
|
return entries;
|
|
18216
18290
|
}
|
|
18291
|
+
var DEFAULT_DELEGATION_EXPIRY_MS = EXPIRY2.SESSION_MS;
|
|
18217
18292
|
function resolveExpiryMs(expiry) {
|
|
18218
18293
|
if (expiry === void 0) {
|
|
18219
|
-
return
|
|
18294
|
+
return DEFAULT_DELEGATION_EXPIRY_MS;
|
|
18220
18295
|
}
|
|
18221
18296
|
if (typeof expiry === "number") {
|
|
18222
18297
|
if (!Number.isFinite(expiry) || expiry <= 0) {
|
|
@@ -18245,10 +18320,11 @@ function extractSiweExpiration(siwe) {
|
|
|
18245
18320
|
// src/NodeSecretsService.ts
|
|
18246
18321
|
import {
|
|
18247
18322
|
ErrorCodes,
|
|
18323
|
+
resolveSecretListPrefix,
|
|
18324
|
+
resolveSecretPath,
|
|
18325
|
+
expandPermissionEntries,
|
|
18248
18326
|
resolveManifest
|
|
18249
18327
|
} from "@tinycloud/sdk-core";
|
|
18250
|
-
var SECRET_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
|
|
18251
|
-
var SECRET_PREFIX = "secrets/";
|
|
18252
18328
|
var SECRETS_SPACE = "secrets";
|
|
18253
18329
|
function ok() {
|
|
18254
18330
|
return { ok: true, data: void 0 };
|
|
@@ -18265,27 +18341,39 @@ function secretsError(code, message, cause) {
|
|
|
18265
18341
|
};
|
|
18266
18342
|
}
|
|
18267
18343
|
function displayActionUrn(action) {
|
|
18268
|
-
|
|
18344
|
+
switch (action) {
|
|
18345
|
+
case "get":
|
|
18346
|
+
return "tinycloud.kv/get";
|
|
18347
|
+
case "put":
|
|
18348
|
+
return "tinycloud.kv/put";
|
|
18349
|
+
case "del":
|
|
18350
|
+
return "tinycloud.kv/del";
|
|
18351
|
+
case "list":
|
|
18352
|
+
return "tinycloud.kv/list";
|
|
18353
|
+
}
|
|
18269
18354
|
}
|
|
18270
|
-
function
|
|
18271
|
-
return
|
|
18355
|
+
function secretActionName(action) {
|
|
18356
|
+
return action;
|
|
18272
18357
|
}
|
|
18273
|
-
function secretPermissionEntries(name, action) {
|
|
18274
|
-
|
|
18275
|
-
|
|
18276
|
-
|
|
18277
|
-
|
|
18278
|
-
|
|
18279
|
-
|
|
18358
|
+
function secretPermissionEntries(name, options, action, encryptionNetworkId) {
|
|
18359
|
+
const entries = [];
|
|
18360
|
+
const path = action === "list" ? resolveSecretListPrefix(options) : resolveSecretPath(name, options).permissionPaths.vault;
|
|
18361
|
+
entries.push({
|
|
18362
|
+
service: "tinycloud.kv",
|
|
18363
|
+
space: SECRETS_SPACE,
|
|
18364
|
+
path,
|
|
18365
|
+
actions: [secretActionName(action)],
|
|
18366
|
+
skipPrefix: true
|
|
18367
|
+
});
|
|
18368
|
+
if (action === "get" && encryptionNetworkId !== void 0) {
|
|
18369
|
+
entries.push({
|
|
18370
|
+
service: "tinycloud.encryption",
|
|
18371
|
+
path: encryptionNetworkId,
|
|
18372
|
+
actions: ["decrypt"],
|
|
18280
18373
|
skipPrefix: true
|
|
18281
|
-
}
|
|
18282
|
-
|
|
18283
|
-
|
|
18284
|
-
function secretResourcePath(base2, name) {
|
|
18285
|
-
return `${base2}/${SECRET_PREFIX}${name}`;
|
|
18286
|
-
}
|
|
18287
|
-
function isSecretsSpace(space) {
|
|
18288
|
-
return space === SECRETS_SPACE || space.endsWith(`:${SECRETS_SPACE}`);
|
|
18374
|
+
});
|
|
18375
|
+
}
|
|
18376
|
+
return entries;
|
|
18289
18377
|
}
|
|
18290
18378
|
var NodeSecretsService = class {
|
|
18291
18379
|
constructor(config) {
|
|
@@ -18313,48 +18401,62 @@ var NodeSecretsService = class {
|
|
|
18313
18401
|
this.shouldRestoreUnlock = false;
|
|
18314
18402
|
this.service.lock();
|
|
18315
18403
|
}
|
|
18316
|
-
get(name) {
|
|
18317
|
-
|
|
18404
|
+
async get(name, options) {
|
|
18405
|
+
const permission = await this.ensurePermission(name, options, "get");
|
|
18406
|
+
if (!permission.ok) return permission;
|
|
18407
|
+
return options === void 0 ? this.service.get(name) : this.service.get(name, options);
|
|
18318
18408
|
}
|
|
18319
|
-
async put(name, value) {
|
|
18320
|
-
const permission = await this.
|
|
18409
|
+
async put(name, value, options) {
|
|
18410
|
+
const permission = await this.ensurePermission(name, options, "put");
|
|
18321
18411
|
if (!permission.ok) return permission;
|
|
18322
|
-
return this.service.put(name, value);
|
|
18412
|
+
return options === void 0 ? this.service.put(name, value) : this.service.put(name, value, options);
|
|
18323
18413
|
}
|
|
18324
|
-
async delete(name) {
|
|
18325
|
-
const permission = await this.
|
|
18414
|
+
async delete(name, options) {
|
|
18415
|
+
const permission = await this.ensurePermission(name, options, "del");
|
|
18326
18416
|
if (!permission.ok) return permission;
|
|
18327
|
-
return this.service.delete(name);
|
|
18417
|
+
return options === void 0 ? this.service.delete(name) : this.service.delete(name, options);
|
|
18328
18418
|
}
|
|
18329
|
-
list() {
|
|
18330
|
-
|
|
18419
|
+
async list(options) {
|
|
18420
|
+
const permission = await this.ensurePermission("", options, "list");
|
|
18421
|
+
if (!permission.ok) return permission;
|
|
18422
|
+
return options === void 0 ? this.service.list() : this.service.list(options);
|
|
18331
18423
|
}
|
|
18332
18424
|
get service() {
|
|
18333
18425
|
return this.config.getService();
|
|
18334
18426
|
}
|
|
18335
|
-
async
|
|
18336
|
-
|
|
18427
|
+
async ensurePermission(name, options, action) {
|
|
18428
|
+
const target = name || "secrets";
|
|
18429
|
+
let permissionEntries;
|
|
18430
|
+
try {
|
|
18431
|
+
permissionEntries = secretPermissionEntries(
|
|
18432
|
+
name,
|
|
18433
|
+
options,
|
|
18434
|
+
action,
|
|
18435
|
+
action === "get" ? this.config.getEncryptionNetworkId?.() : void 0
|
|
18436
|
+
);
|
|
18437
|
+
} catch (error) {
|
|
18337
18438
|
return secretsError(
|
|
18338
18439
|
ErrorCodes.INVALID_INPUT,
|
|
18339
|
-
|
|
18440
|
+
error instanceof Error ? error.message : String(error),
|
|
18441
|
+
error instanceof Error ? error : void 0
|
|
18340
18442
|
);
|
|
18341
18443
|
}
|
|
18342
|
-
if (this.
|
|
18444
|
+
if (this.hasPermission(permissionEntries)) {
|
|
18343
18445
|
return ok();
|
|
18344
18446
|
}
|
|
18345
18447
|
if (!this.config.canEscalate()) {
|
|
18346
18448
|
return secretsError(
|
|
18347
18449
|
ErrorCodes.PERMISSION_DENIED,
|
|
18348
|
-
`Cannot autosign ${displayActionUrn(action)} for ${
|
|
18450
|
+
`Cannot autosign ${displayActionUrn(action)} for ${target}; TinyCloudNode needs wallet mode with a signer or privateKey.`
|
|
18349
18451
|
);
|
|
18350
18452
|
}
|
|
18351
18453
|
try {
|
|
18352
|
-
await this.config.grantPermissions(
|
|
18454
|
+
await this.config.grantPermissions(permissionEntries);
|
|
18353
18455
|
return this.restoreUnlockAfterEscalation();
|
|
18354
18456
|
} catch (error) {
|
|
18355
18457
|
return secretsError(
|
|
18356
18458
|
ErrorCodes.PERMISSION_DENIED,
|
|
18357
|
-
error instanceof Error ? error.message : `Autosign escalation for ${displayActionUrn(action)} on ${
|
|
18459
|
+
error instanceof Error ? error.message : `Autosign escalation for ${displayActionUrn(action)} on ${target} failed.`,
|
|
18358
18460
|
error instanceof Error ? error : void 0
|
|
18359
18461
|
);
|
|
18360
18462
|
}
|
|
@@ -18365,26 +18467,117 @@ var NodeSecretsService = class {
|
|
|
18365
18467
|
}
|
|
18366
18468
|
return this.service.unlock(this.unlockSigner);
|
|
18367
18469
|
}
|
|
18368
|
-
|
|
18470
|
+
hasPermission(permissionEntries) {
|
|
18471
|
+
if (this.config.hasPermissions?.(permissionEntries)) {
|
|
18472
|
+
return true;
|
|
18473
|
+
}
|
|
18369
18474
|
const manifest = this.config.getManifest();
|
|
18370
18475
|
if (manifest === void 0) {
|
|
18371
18476
|
return false;
|
|
18372
18477
|
}
|
|
18373
18478
|
const manifests = Array.isArray(manifest) ? manifest : [manifest];
|
|
18374
|
-
const
|
|
18375
|
-
return
|
|
18376
|
-
|
|
18377
|
-
|
|
18378
|
-
|
|
18379
|
-
(resource) => resource.service ===
|
|
18380
|
-
)
|
|
18381
|
-
)
|
|
18382
|
-
|
|
18479
|
+
const requestedEntries = expandPermissionEntries(permissionEntries);
|
|
18480
|
+
return requestedEntries.every(
|
|
18481
|
+
(entry) => manifests.some((candidate) => {
|
|
18482
|
+
const resolved = resolveManifest(candidate);
|
|
18483
|
+
return resolved.resources.some(
|
|
18484
|
+
(resource) => resource.service === entry.service && resource.space === entry.space && resource.path === entry.path && entry.actions.every((action) => resource.actions.includes(action))
|
|
18485
|
+
);
|
|
18486
|
+
})
|
|
18487
|
+
);
|
|
18383
18488
|
}
|
|
18384
18489
|
};
|
|
18385
18490
|
|
|
18386
18491
|
// src/TinyCloudNode.ts
|
|
18387
18492
|
var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
18493
|
+
var DEFAULT_ENCRYPTION_NETWORK_NAME = "default";
|
|
18494
|
+
var NETWORK_CREATE_ACTION = "tinycloud.encryption/network.create";
|
|
18495
|
+
var DECRYPT_ACTION = "tinycloud.encryption/decrypt";
|
|
18496
|
+
var NETWORK_ADMIN_TYPE = "tinycloud.encryption.network-admin/v1";
|
|
18497
|
+
var DEFAULT_SESSION_EXPIRATION_MS = EXPIRY3.SESSION_MS;
|
|
18498
|
+
function base64UrlEncode(bytes) {
|
|
18499
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
18500
|
+
let output = "";
|
|
18501
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
18502
|
+
const a = bytes[i];
|
|
18503
|
+
const b = bytes[i + 1];
|
|
18504
|
+
const c = bytes[i + 2];
|
|
18505
|
+
const triplet = a << 16 | (b ?? 0) << 8 | (c ?? 0);
|
|
18506
|
+
output += alphabet[triplet >> 18 & 63];
|
|
18507
|
+
output += alphabet[triplet >> 12 & 63];
|
|
18508
|
+
if (i + 1 < bytes.length) output += alphabet[triplet >> 6 & 63];
|
|
18509
|
+
if (i + 2 < bytes.length) output += alphabet[triplet & 63];
|
|
18510
|
+
}
|
|
18511
|
+
return output;
|
|
18512
|
+
}
|
|
18513
|
+
function base64UrlDecode(value) {
|
|
18514
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
18515
|
+
const bytes = [];
|
|
18516
|
+
let buffer = 0;
|
|
18517
|
+
let bits = 0;
|
|
18518
|
+
for (const char of value) {
|
|
18519
|
+
const index = alphabet.indexOf(char);
|
|
18520
|
+
if (index < 0) {
|
|
18521
|
+
throw new Error("invalid base64url input");
|
|
18522
|
+
}
|
|
18523
|
+
buffer = buffer << 6 | index;
|
|
18524
|
+
bits += 6;
|
|
18525
|
+
if (bits >= 8) {
|
|
18526
|
+
bits -= 8;
|
|
18527
|
+
bytes.push(buffer >> bits & 255);
|
|
18528
|
+
}
|
|
18529
|
+
}
|
|
18530
|
+
return new Uint8Array(bytes);
|
|
18531
|
+
}
|
|
18532
|
+
async function signJwtInputWithJwk(signingInput, jwk) {
|
|
18533
|
+
const bytes = new TextEncoder().encode(signingInput);
|
|
18534
|
+
try {
|
|
18535
|
+
const subtle = globalThis.crypto?.subtle;
|
|
18536
|
+
if (!subtle) {
|
|
18537
|
+
throw new Error("WebCrypto subtle API is unavailable");
|
|
18538
|
+
}
|
|
18539
|
+
const key2 = await subtle.importKey(
|
|
18540
|
+
"jwk",
|
|
18541
|
+
jwk,
|
|
18542
|
+
{ name: "Ed25519" },
|
|
18543
|
+
false,
|
|
18544
|
+
["sign"]
|
|
18545
|
+
);
|
|
18546
|
+
return new Uint8Array(await subtle.sign({ name: "Ed25519" }, key2, bytes));
|
|
18547
|
+
} catch {
|
|
18548
|
+
const nodeCrypto = await import("crypto");
|
|
18549
|
+
const key2 = nodeCrypto.createPrivateKey({ key: jwk, format: "jwk" });
|
|
18550
|
+
return new Uint8Array(nodeCrypto.sign(null, Buffer.from(bytes), key2));
|
|
18551
|
+
}
|
|
18552
|
+
}
|
|
18553
|
+
async function rewriteInvocationAudience(authorization, audience, jwk) {
|
|
18554
|
+
const [headerPart, payloadPart] = authorization.split(".");
|
|
18555
|
+
if (!headerPart || !payloadPart) {
|
|
18556
|
+
throw new Error("invalid invocation authorization");
|
|
18557
|
+
}
|
|
18558
|
+
const header = JSON.parse(new TextDecoder().decode(base64UrlDecode(headerPart)));
|
|
18559
|
+
const payload = JSON.parse(new TextDecoder().decode(base64UrlDecode(payloadPart)));
|
|
18560
|
+
payload.aud = audience;
|
|
18561
|
+
const signingInput = `${base64UrlEncode(
|
|
18562
|
+
new TextEncoder().encode(JSON.stringify(header))
|
|
18563
|
+
)}.${base64UrlEncode(new TextEncoder().encode(JSON.stringify(payload)))}`;
|
|
18564
|
+
const signature2 = await signJwtInputWithJwk(signingInput, jwk);
|
|
18565
|
+
return `${signingInput}.${base64UrlEncode(signature2)}`;
|
|
18566
|
+
}
|
|
18567
|
+
function authorizationHeader(headers) {
|
|
18568
|
+
if (Array.isArray(headers)) {
|
|
18569
|
+
const entry = headers.find(([name]) => name.toLowerCase() === "authorization");
|
|
18570
|
+
if (!entry) {
|
|
18571
|
+
throw new Error("network invocation did not include an Authorization header");
|
|
18572
|
+
}
|
|
18573
|
+
return entry[1];
|
|
18574
|
+
}
|
|
18575
|
+
const value = headers.Authorization ?? headers.authorization;
|
|
18576
|
+
if (!value) {
|
|
18577
|
+
throw new Error("network invocation did not include an Authorization header");
|
|
18578
|
+
}
|
|
18579
|
+
return value;
|
|
18580
|
+
}
|
|
18388
18581
|
var _TinyCloudNode = class _TinyCloudNode {
|
|
18389
18582
|
/**
|
|
18390
18583
|
* Create a new TinyCloudNode instance.
|
|
@@ -18429,12 +18622,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18429
18622
|
throw new Error("WASM binding does not support invokeAny");
|
|
18430
18623
|
}
|
|
18431
18624
|
const grant = this.findGrantForOperations(
|
|
18432
|
-
entries.
|
|
18433
|
-
|
|
18434
|
-
|
|
18435
|
-
|
|
18436
|
-
action: entry.action
|
|
18437
|
-
}))
|
|
18625
|
+
entries.flatMap((entry) => {
|
|
18626
|
+
const operation = this.operationFromInvokeAnyEntry(entry);
|
|
18627
|
+
return operation ? [operation] : [];
|
|
18628
|
+
})
|
|
18438
18629
|
);
|
|
18439
18630
|
return this.wasmBindings.invokeAny(grant?.session ?? session, entries, facts);
|
|
18440
18631
|
};
|
|
@@ -18527,7 +18718,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18527
18718
|
sessionStorage: config.sessionStorage ?? new MemorySessionStorage(),
|
|
18528
18719
|
domain: this.siweDomain,
|
|
18529
18720
|
spacePrefix: config.prefix,
|
|
18530
|
-
sessionExpirationMs: config.sessionExpirationMs ??
|
|
18721
|
+
sessionExpirationMs: config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
|
|
18531
18722
|
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
18532
18723
|
tinycloudRegistryUrl: config.tinycloudRegistryUrl,
|
|
18533
18724
|
tinycloudFallbackHosts: config.tinycloudFallbackHosts,
|
|
@@ -18662,6 +18853,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18662
18853
|
this._duckdb = void 0;
|
|
18663
18854
|
this._hooks = void 0;
|
|
18664
18855
|
this._vault = void 0;
|
|
18856
|
+
this._encryption = void 0;
|
|
18665
18857
|
this._baseSecrets = void 0;
|
|
18666
18858
|
this._secrets = void 0;
|
|
18667
18859
|
this._spaceService = void 0;
|
|
@@ -18670,6 +18862,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18670
18862
|
await this.tc.signIn(options);
|
|
18671
18863
|
this.syncResolvedHostFromAuth();
|
|
18672
18864
|
this.initializeServices();
|
|
18865
|
+
if (this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
18866
|
+
await this.ensureOwnedSpaceHosted(this.ownedSpaceId("secrets"));
|
|
18867
|
+
}
|
|
18673
18868
|
await this.writeManifestRegistryRecords();
|
|
18674
18869
|
this.notificationHandler.success("Successfully signed in");
|
|
18675
18870
|
}
|
|
@@ -18752,6 +18947,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18752
18947
|
this._duckdb = void 0;
|
|
18753
18948
|
this._hooks = void 0;
|
|
18754
18949
|
this._vault = void 0;
|
|
18950
|
+
this._encryption = void 0;
|
|
18755
18951
|
this._baseSecrets = void 0;
|
|
18756
18952
|
this._secrets = void 0;
|
|
18757
18953
|
this._spaceService = void 0;
|
|
@@ -18793,6 +18989,33 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18793
18989
|
this._vault.initialize(this._serviceContext);
|
|
18794
18990
|
this._serviceContext.registerService("vault", this._vault);
|
|
18795
18991
|
this.initializeV2Services(serviceSession);
|
|
18992
|
+
if (sessionData.siwe && sessionData.address && sessionData.chainId) {
|
|
18993
|
+
const tcSession = {
|
|
18994
|
+
address: sessionData.address,
|
|
18995
|
+
chainId: sessionData.chainId,
|
|
18996
|
+
sessionKey: JSON.stringify(sessionData.jwk),
|
|
18997
|
+
spaceId: sessionData.spaceId,
|
|
18998
|
+
delegationCid: sessionData.delegationCid,
|
|
18999
|
+
delegationHeader: sessionData.delegationHeader,
|
|
19000
|
+
verificationMethod: sessionData.verificationMethod,
|
|
19001
|
+
jwk: sessionData.jwk,
|
|
19002
|
+
siwe: sessionData.siwe,
|
|
19003
|
+
signature: sessionData.signature ?? ""
|
|
19004
|
+
};
|
|
19005
|
+
if (this.auth) {
|
|
19006
|
+
this.auth.setRestoredTinyCloudSession(tcSession);
|
|
19007
|
+
} else {
|
|
19008
|
+
this._restoredTcSession = tcSession;
|
|
19009
|
+
}
|
|
19010
|
+
}
|
|
19011
|
+
}
|
|
19012
|
+
/**
|
|
19013
|
+
* Resolve the currently-active TinyCloudSession, preferring the auth
|
|
19014
|
+
* layer's value (wallet mode) and falling back to the node-level
|
|
19015
|
+
* rehydration set by {@link restoreSession} (session-only mode).
|
|
19016
|
+
*/
|
|
19017
|
+
currentTinyCloudSession() {
|
|
19018
|
+
return this.auth?.tinyCloudSession ?? this._restoredTcSession;
|
|
18796
19019
|
}
|
|
18797
19020
|
/**
|
|
18798
19021
|
* Connect a wallet to upgrade from session-only mode to wallet mode.
|
|
@@ -18837,7 +19060,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18837
19060
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
18838
19061
|
domain: this.siweDomain,
|
|
18839
19062
|
spacePrefix: prefix,
|
|
18840
|
-
sessionExpirationMs: this.config.sessionExpirationMs ??
|
|
19063
|
+
sessionExpirationMs: this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
|
|
18841
19064
|
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
18842
19065
|
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
18843
19066
|
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
@@ -18881,7 +19104,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18881
19104
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
18882
19105
|
domain: this.siweDomain,
|
|
18883
19106
|
spacePrefix: prefix,
|
|
18884
|
-
sessionExpirationMs: this.config.sessionExpirationMs ??
|
|
19107
|
+
sessionExpirationMs: this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
|
|
18885
19108
|
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
18886
19109
|
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
18887
19110
|
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
@@ -18904,7 +19127,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18904
19127
|
* @internal
|
|
18905
19128
|
*/
|
|
18906
19129
|
initializeServices() {
|
|
18907
|
-
const session = this.
|
|
19130
|
+
const session = this.currentTinyCloudSession();
|
|
18908
19131
|
if (!session) {
|
|
18909
19132
|
return;
|
|
18910
19133
|
}
|
|
@@ -18962,6 +19185,180 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18962
19185
|
}
|
|
18963
19186
|
return kvService;
|
|
18964
19187
|
}
|
|
19188
|
+
getDefaultEncryptionNetworkId(name = DEFAULT_ENCRYPTION_NETWORK_NAME) {
|
|
19189
|
+
return `urn:tinycloud:encryption:${this.did}:${name}`;
|
|
19190
|
+
}
|
|
19191
|
+
requireServiceSession() {
|
|
19192
|
+
const session = this._serviceContext?.session;
|
|
19193
|
+
if (!session) {
|
|
19194
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
19195
|
+
}
|
|
19196
|
+
return session;
|
|
19197
|
+
}
|
|
19198
|
+
createEncryptionCrypto() {
|
|
19199
|
+
const wasm = this.wasmBindings;
|
|
19200
|
+
const columnEncrypt = (key2, plaintext) => {
|
|
19201
|
+
const encrypted = wasm.vault_encrypt(key2, plaintext);
|
|
19202
|
+
const out = new Uint8Array(1 + encrypted.length);
|
|
19203
|
+
out[0] = 1;
|
|
19204
|
+
out.set(encrypted, 1);
|
|
19205
|
+
return out;
|
|
19206
|
+
};
|
|
19207
|
+
const columnDecrypt = (key2, blob) => {
|
|
19208
|
+
if (blob[0] !== 1) {
|
|
19209
|
+
return blob;
|
|
19210
|
+
}
|
|
19211
|
+
return wasm.vault_decrypt(key2, blob.slice(1));
|
|
19212
|
+
};
|
|
19213
|
+
return {
|
|
19214
|
+
sha256: (data) => wasm.vault_sha256(data),
|
|
19215
|
+
randomBytes: (length) => wasm.vault_random_bytes(length),
|
|
19216
|
+
x25519FromSeed: (seed) => wasm.vault_x25519_from_seed(seed),
|
|
19217
|
+
x25519Dh: (privateKey, publicKey) => wasm.vault_x25519_dh(privateKey, publicKey),
|
|
19218
|
+
authEncrypt: (key2, plaintext) => wasm.vault_encrypt(key2, plaintext),
|
|
19219
|
+
authDecrypt: (key2, ciphertext) => wasm.vault_decrypt(key2, ciphertext),
|
|
19220
|
+
sealToNetworkKey: (networkPublicKey, symmetricKey) => {
|
|
19221
|
+
const seed = wasm.vault_random_bytes(32);
|
|
19222
|
+
const ephemeral = wasm.vault_x25519_from_seed(seed);
|
|
19223
|
+
const shared = wasm.vault_x25519_dh(
|
|
19224
|
+
ephemeral.privateKey,
|
|
19225
|
+
networkPublicKey
|
|
19226
|
+
);
|
|
19227
|
+
const encrypted = columnEncrypt(shared, symmetricKey);
|
|
19228
|
+
const out = new Uint8Array(ephemeral.publicKey.length + encrypted.length);
|
|
19229
|
+
out.set(ephemeral.publicKey, 0);
|
|
19230
|
+
out.set(encrypted, ephemeral.publicKey.length);
|
|
19231
|
+
return out;
|
|
19232
|
+
},
|
|
19233
|
+
openWithReceiverKey: (receiverPrivateKey, wrappedKey) => {
|
|
19234
|
+
const peerPublic = wrappedKey.slice(0, 32);
|
|
19235
|
+
const ciphertext = wrappedKey.slice(32);
|
|
19236
|
+
const shared = wasm.vault_x25519_dh(receiverPrivateKey, peerPublic);
|
|
19237
|
+
return columnDecrypt(shared, ciphertext);
|
|
19238
|
+
},
|
|
19239
|
+
verifyNodeSignature: (nodeId, message, signature2) => verifyDidKeyEd25519Signature(nodeId, message, signature2)
|
|
19240
|
+
};
|
|
19241
|
+
}
|
|
19242
|
+
async fetchNodeId() {
|
|
19243
|
+
const response = await fetch(`${this.config.host}/info`);
|
|
19244
|
+
if (!response.ok) {
|
|
19245
|
+
throw new Error(`Failed to fetch node info: HTTP ${response.status}`);
|
|
19246
|
+
}
|
|
19247
|
+
const info = await response.json();
|
|
19248
|
+
if (typeof info.nodeId !== "string" || info.nodeId.length === 0) {
|
|
19249
|
+
throw new Error("Node /info response did not include nodeId");
|
|
19250
|
+
}
|
|
19251
|
+
return info.nodeId;
|
|
19252
|
+
}
|
|
19253
|
+
async signRawNetworkAuthorization(input) {
|
|
19254
|
+
if (!this.wasmBindings.invokeAny) {
|
|
19255
|
+
throw new Error("WASM binding does not support raw-resource invokeAny");
|
|
19256
|
+
}
|
|
19257
|
+
if (!this.wasmBindings.computeCid) {
|
|
19258
|
+
throw new Error("WASM binding does not support invocation CID computation");
|
|
19259
|
+
}
|
|
19260
|
+
const session = this.requireServiceSession();
|
|
19261
|
+
const headers = this.invokeAnyWithRuntimePermissions(
|
|
19262
|
+
session,
|
|
19263
|
+
[
|
|
19264
|
+
{
|
|
19265
|
+
resource: input.networkId,
|
|
19266
|
+
service: "encryption",
|
|
19267
|
+
path: input.networkId,
|
|
19268
|
+
action: input.action
|
|
19269
|
+
}
|
|
19270
|
+
],
|
|
19271
|
+
[input.facts]
|
|
19272
|
+
);
|
|
19273
|
+
const authorization = authorizationHeader(headers);
|
|
19274
|
+
const audienceBound = await rewriteInvocationAudience(
|
|
19275
|
+
authorization,
|
|
19276
|
+
input.targetNode,
|
|
19277
|
+
session.jwk
|
|
19278
|
+
);
|
|
19279
|
+
return {
|
|
19280
|
+
authorization: audienceBound,
|
|
19281
|
+
invocationCid: this.wasmBindings.computeCid(
|
|
19282
|
+
new TextEncoder().encode(audienceBound),
|
|
19283
|
+
0x55n
|
|
19284
|
+
)
|
|
19285
|
+
};
|
|
19286
|
+
}
|
|
19287
|
+
createEncryptionService() {
|
|
19288
|
+
const crypto2 = this.createEncryptionCrypto();
|
|
19289
|
+
const transport = {
|
|
19290
|
+
postDecrypt: async ({ networkId, authorization, canonicalBody }) => {
|
|
19291
|
+
const response = await fetch(
|
|
19292
|
+
`${this.config.host}/encryption/networks/${encodeURIComponent(networkId)}/decrypt`,
|
|
19293
|
+
{
|
|
19294
|
+
method: "POST",
|
|
19295
|
+
headers: {
|
|
19296
|
+
Authorization: authorization,
|
|
19297
|
+
"Content-Type": "application/json"
|
|
19298
|
+
},
|
|
19299
|
+
body: canonicalBody
|
|
19300
|
+
}
|
|
19301
|
+
);
|
|
19302
|
+
if (!response.ok) {
|
|
19303
|
+
throw new Error(
|
|
19304
|
+
`decrypt failed ${response.status}: ${await response.text()}`
|
|
19305
|
+
);
|
|
19306
|
+
}
|
|
19307
|
+
return await response.json();
|
|
19308
|
+
}
|
|
19309
|
+
};
|
|
19310
|
+
return new EncryptionService({
|
|
19311
|
+
crypto: crypto2,
|
|
19312
|
+
signer: {
|
|
19313
|
+
signDecryptInvocation: async (input) => {
|
|
19314
|
+
const signed2 = await this.signRawNetworkAuthorization({
|
|
19315
|
+
targetNode: input.targetNode,
|
|
19316
|
+
networkId: input.networkId,
|
|
19317
|
+
action: DECRYPT_ACTION,
|
|
19318
|
+
facts: input.facts
|
|
19319
|
+
});
|
|
19320
|
+
return {
|
|
19321
|
+
...signed2,
|
|
19322
|
+
canonicalBody: canonicalizeEncryptionJson(
|
|
19323
|
+
input.body
|
|
19324
|
+
)
|
|
19325
|
+
};
|
|
19326
|
+
}
|
|
19327
|
+
},
|
|
19328
|
+
transport,
|
|
19329
|
+
node: {
|
|
19330
|
+
fetchByNetworkId: (networkId) => this.getEncryptionNetwork(networkId)
|
|
19331
|
+
},
|
|
19332
|
+
wellKnown: {
|
|
19333
|
+
fetchWellKnown: async (principal, discoveryKey) => {
|
|
19334
|
+
if (!this._address || principal !== this.did) {
|
|
19335
|
+
return null;
|
|
19336
|
+
}
|
|
19337
|
+
if (!this.config.host) {
|
|
19338
|
+
return null;
|
|
19339
|
+
}
|
|
19340
|
+
const publicSpaceId = makePublicSpaceId(this._address, this._chainId);
|
|
19341
|
+
const result = await TinyCloud.readPublicSpace(this.config.host, publicSpaceId, discoveryKey);
|
|
19342
|
+
if (!result.ok) {
|
|
19343
|
+
return null;
|
|
19344
|
+
}
|
|
19345
|
+
const body = result.data;
|
|
19346
|
+
return "descriptor" in body && body.descriptor ? body.descriptor : body;
|
|
19347
|
+
}
|
|
19348
|
+
}
|
|
19349
|
+
});
|
|
19350
|
+
}
|
|
19351
|
+
getEncryptionService() {
|
|
19352
|
+
if (!this._serviceContext) {
|
|
19353
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
19354
|
+
}
|
|
19355
|
+
if (!this._encryption) {
|
|
19356
|
+
this._encryption = this.createEncryptionService();
|
|
19357
|
+
this._encryption.initialize(this._serviceContext);
|
|
19358
|
+
this._serviceContext.registerService("encryption", this._encryption);
|
|
19359
|
+
}
|
|
19360
|
+
return this._encryption;
|
|
19361
|
+
}
|
|
18965
19362
|
createVaultService(spaceId, kv) {
|
|
18966
19363
|
const wasm = this.wasmBindings;
|
|
18967
19364
|
const vaultCrypto = createVaultCrypto({
|
|
@@ -18977,6 +19374,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18977
19374
|
return new DataVaultService({
|
|
18978
19375
|
spaceId,
|
|
18979
19376
|
crypto: vaultCrypto,
|
|
19377
|
+
encryption: {
|
|
19378
|
+
networkId: this.getDefaultEncryptionNetworkId(),
|
|
19379
|
+
service: this.getEncryptionService(),
|
|
19380
|
+
decryptCapabilityProof: () => ({
|
|
19381
|
+
proofs: [this.requireServiceSession().delegationCid]
|
|
19382
|
+
})
|
|
19383
|
+
},
|
|
18980
19384
|
tc: {
|
|
18981
19385
|
kv,
|
|
18982
19386
|
ensurePublicSpace: async () => {
|
|
@@ -19157,7 +19561,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19157
19561
|
* @internal
|
|
19158
19562
|
*/
|
|
19159
19563
|
getSessionExpiry() {
|
|
19160
|
-
const expirationMs = this.config.sessionExpirationMs ??
|
|
19564
|
+
const expirationMs = this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS;
|
|
19161
19565
|
return new Date(Date.now() + expirationMs);
|
|
19162
19566
|
}
|
|
19163
19567
|
/**
|
|
@@ -19214,7 +19618,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19214
19618
|
if (!this.signer) {
|
|
19215
19619
|
return void 0;
|
|
19216
19620
|
}
|
|
19217
|
-
const session = this.
|
|
19621
|
+
const session = this.currentTinyCloudSession();
|
|
19218
19622
|
if (!session) {
|
|
19219
19623
|
return void 0;
|
|
19220
19624
|
}
|
|
@@ -19314,6 +19718,34 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19314
19718
|
}
|
|
19315
19719
|
return this._sql;
|
|
19316
19720
|
}
|
|
19721
|
+
/**
|
|
19722
|
+
* Get an SQL service scoped to a specific space.
|
|
19723
|
+
*
|
|
19724
|
+
* Mirrors {@link SpaceService}'s per-space KV factory: clones the active
|
|
19725
|
+
* service context and overrides its session's spaceId so that subsequent
|
|
19726
|
+
* `sql/<dbName>/<action>` invocations route to that space. Useful when
|
|
19727
|
+
* the caller already holds a delegation covering the target space (e.g.
|
|
19728
|
+
* via {@link grantRuntimePermissions} or {@link useRuntimeDelegation})
|
|
19729
|
+
* but the SDK's per-space SQL surface isn't otherwise exposed.
|
|
19730
|
+
*
|
|
19731
|
+
* Does NOT auto-create the space.
|
|
19732
|
+
*
|
|
19733
|
+
* @param spaceId - Full space URI (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`).
|
|
19734
|
+
*/
|
|
19735
|
+
sqlForSpace(spaceId) {
|
|
19736
|
+
if (!this._serviceContext || !this._serviceContext.session) {
|
|
19737
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
19738
|
+
}
|
|
19739
|
+
const sql = new SQLService2({});
|
|
19740
|
+
const spaceScopedContext = new ServiceContext2({
|
|
19741
|
+
invoke: this._serviceContext.invoke,
|
|
19742
|
+
fetch: this._serviceContext.fetch,
|
|
19743
|
+
hosts: this._serviceContext.hosts
|
|
19744
|
+
});
|
|
19745
|
+
spaceScopedContext.setSession({ ...this._serviceContext.session, spaceId });
|
|
19746
|
+
sql.initialize(spaceScopedContext);
|
|
19747
|
+
return sql;
|
|
19748
|
+
}
|
|
19317
19749
|
/**
|
|
19318
19750
|
* DuckDB database operations on this user's space.
|
|
19319
19751
|
*/
|
|
@@ -19337,6 +19769,79 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19337
19769
|
}
|
|
19338
19770
|
return this._vault;
|
|
19339
19771
|
}
|
|
19772
|
+
/**
|
|
19773
|
+
* Network-scoped encryption/decrypt service.
|
|
19774
|
+
*/
|
|
19775
|
+
get encryption() {
|
|
19776
|
+
return this.getEncryptionService();
|
|
19777
|
+
}
|
|
19778
|
+
async getEncryptionNetwork(nameOrNetworkId = this.getDefaultEncryptionNetworkId()) {
|
|
19779
|
+
const networkId = nameOrNetworkId.startsWith("urn:tinycloud:encryption:") ? nameOrNetworkId : this.getDefaultEncryptionNetworkId(nameOrNetworkId);
|
|
19780
|
+
const response = await fetch(
|
|
19781
|
+
`${this.config.host}/encryption/networks/${encodeURIComponent(networkId)}`
|
|
19782
|
+
);
|
|
19783
|
+
if (response.status === 404) {
|
|
19784
|
+
return null;
|
|
19785
|
+
}
|
|
19786
|
+
if (!response.ok) {
|
|
19787
|
+
throw new Error(
|
|
19788
|
+
`Failed to fetch encryption network ${networkId}: HTTP ${response.status} ${await response.text()}`
|
|
19789
|
+
);
|
|
19790
|
+
}
|
|
19791
|
+
const body = await response.json();
|
|
19792
|
+
return "descriptor" in body && body.descriptor ? body.descriptor : body;
|
|
19793
|
+
}
|
|
19794
|
+
async createEncryptionNetwork(name = DEFAULT_ENCRYPTION_NETWORK_NAME) {
|
|
19795
|
+
const targetNode = await this.fetchNodeId();
|
|
19796
|
+
const principal = this.did;
|
|
19797
|
+
const networkId = this.getDefaultEncryptionNetworkId(name);
|
|
19798
|
+
const body = {
|
|
19799
|
+
name,
|
|
19800
|
+
principal,
|
|
19801
|
+
threshold: { n: 1, t: 1 }
|
|
19802
|
+
};
|
|
19803
|
+
const crypto2 = this.createEncryptionCrypto();
|
|
19804
|
+
const facts = {
|
|
19805
|
+
type: NETWORK_ADMIN_TYPE,
|
|
19806
|
+
targetNode,
|
|
19807
|
+
networkId,
|
|
19808
|
+
bodyHash: canonicalHashHex(
|
|
19809
|
+
crypto2.sha256,
|
|
19810
|
+
body
|
|
19811
|
+
),
|
|
19812
|
+
action: NETWORK_CREATE_ACTION
|
|
19813
|
+
};
|
|
19814
|
+
const signed2 = await this.signRawNetworkAuthorization({
|
|
19815
|
+
targetNode,
|
|
19816
|
+
networkId,
|
|
19817
|
+
action: NETWORK_CREATE_ACTION,
|
|
19818
|
+
facts
|
|
19819
|
+
});
|
|
19820
|
+
const response = await fetch(`${this.config.host}/encryption/networks`, {
|
|
19821
|
+
method: "POST",
|
|
19822
|
+
headers: {
|
|
19823
|
+
Authorization: signed2.authorization,
|
|
19824
|
+
"Content-Type": "application/json"
|
|
19825
|
+
},
|
|
19826
|
+
body: canonicalizeEncryptionJson(
|
|
19827
|
+
body
|
|
19828
|
+
)
|
|
19829
|
+
});
|
|
19830
|
+
if (!response.ok) {
|
|
19831
|
+
throw new Error(
|
|
19832
|
+
`Failed to create encryption network ${networkId}: HTTP ${response.status} ${await response.text()}`
|
|
19833
|
+
);
|
|
19834
|
+
}
|
|
19835
|
+
const created = await response.json();
|
|
19836
|
+
return created.descriptor;
|
|
19837
|
+
}
|
|
19838
|
+
async ensureEncryptionNetwork(name = DEFAULT_ENCRYPTION_NETWORK_NAME) {
|
|
19839
|
+
const existing = await this.getEncryptionNetwork(name);
|
|
19840
|
+
if (existing) {
|
|
19841
|
+
return existing;
|
|
19842
|
+
}
|
|
19843
|
+
return this.createEncryptionNetwork(name);
|
|
19844
|
+
}
|
|
19340
19845
|
/**
|
|
19341
19846
|
* App-facing secrets API backed by the `secrets` space vault.
|
|
19342
19847
|
*/
|
|
@@ -19348,8 +19853,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19348
19853
|
this._secrets = new NodeSecretsService({
|
|
19349
19854
|
getService: () => this.getBaseSecrets(),
|
|
19350
19855
|
getManifest: () => this.manifest,
|
|
19856
|
+
hasPermissions: (permissions) => this.hasRuntimePermissions(permissions),
|
|
19351
19857
|
grantPermissions: (additional) => this.grantRuntimePermissions(additional),
|
|
19352
19858
|
canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
|
|
19859
|
+
getEncryptionNetworkId: () => this.getDefaultEncryptionNetworkId(),
|
|
19353
19860
|
getUnlockSigner: () => this.signer ?? void 0
|
|
19354
19861
|
});
|
|
19355
19862
|
}
|
|
@@ -19439,7 +19946,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19439
19946
|
* every requested permission.
|
|
19440
19947
|
*/
|
|
19441
19948
|
hasRuntimePermissions(permissions) {
|
|
19442
|
-
const session = this.
|
|
19949
|
+
const session = this.currentTinyCloudSession();
|
|
19443
19950
|
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
19444
19951
|
return false;
|
|
19445
19952
|
}
|
|
@@ -19459,7 +19966,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19459
19966
|
if (permissions === void 0) {
|
|
19460
19967
|
return this.runtimePermissionGrants.map((grant) => grant.delegation);
|
|
19461
19968
|
}
|
|
19462
|
-
const session = this.
|
|
19969
|
+
const session = this.currentTinyCloudSession();
|
|
19463
19970
|
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
19464
19971
|
return [];
|
|
19465
19972
|
}
|
|
@@ -19473,7 +19980,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19473
19980
|
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
19474
19981
|
*/
|
|
19475
19982
|
async useRuntimeDelegation(delegation) {
|
|
19476
|
-
const session = this.
|
|
19983
|
+
const session = this.currentTinyCloudSession();
|
|
19477
19984
|
if (!session) {
|
|
19478
19985
|
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
19479
19986
|
}
|
|
@@ -19512,7 +20019,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19512
20019
|
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
19513
20020
|
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
19514
20021
|
}
|
|
19515
|
-
const session = this.
|
|
20022
|
+
const session = this.currentTinyCloudSession();
|
|
19516
20023
|
if (!session) {
|
|
19517
20024
|
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
19518
20025
|
}
|
|
@@ -19536,13 +20043,22 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19536
20043
|
"grantRuntimePermissions requires wallet mode with a signer or privateKey."
|
|
19537
20044
|
);
|
|
19538
20045
|
}
|
|
20046
|
+
const rawEntries = expanded.filter(
|
|
20047
|
+
(entry) => this.isEncryptionPermissionEntry(entry)
|
|
20048
|
+
);
|
|
20049
|
+
const spaceEntries = expanded.filter(
|
|
20050
|
+
(entry) => !this.isEncryptionPermissionEntry(entry)
|
|
20051
|
+
);
|
|
19539
20052
|
const bySpace = /* @__PURE__ */ new Map();
|
|
19540
|
-
for (const entry of
|
|
20053
|
+
for (const entry of spaceEntries) {
|
|
19541
20054
|
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
19542
20055
|
const current = bySpace.get(spaceId) ?? [];
|
|
19543
20056
|
current.push(entry);
|
|
19544
20057
|
bySpace.set(spaceId, current);
|
|
19545
20058
|
}
|
|
20059
|
+
if (bySpace.size === 0 && rawEntries.length > 0) {
|
|
20060
|
+
bySpace.set(session.spaceId, []);
|
|
20061
|
+
}
|
|
19546
20062
|
const now = /* @__PURE__ */ new Date();
|
|
19547
20063
|
const requestedExpiryMs = resolveExpiryMs(options?.expiry);
|
|
19548
20064
|
let expiresAt = new Date(now.getTime() + requestedExpiryMs);
|
|
@@ -19550,10 +20066,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19550
20066
|
expiresAt = sessionExpiry;
|
|
19551
20067
|
}
|
|
19552
20068
|
const delegations = [];
|
|
20069
|
+
let rawEntriesAttached = false;
|
|
19553
20070
|
for (const [spaceId, entries] of bySpace) {
|
|
20071
|
+
const rawForDelegation = !rawEntriesAttached ? rawEntries : [];
|
|
20072
|
+
if (rawForDelegation.length > 0) {
|
|
20073
|
+
rawEntriesAttached = true;
|
|
20074
|
+
}
|
|
20075
|
+
const delegatedEntries = [...entries, ...rawForDelegation];
|
|
19554
20076
|
const abilities = this.permissionsToAbilities(entries);
|
|
19555
20077
|
const prepared = this.wasmBindings.prepareSession({
|
|
19556
20078
|
abilities,
|
|
20079
|
+
...rawForDelegation.length > 0 ? { rawAbilities: this.permissionsToRawAbilities(rawForDelegation) } : {},
|
|
19557
20080
|
address: this.wasmBindings.ensureEip55(session.address),
|
|
19558
20081
|
chainId: session.chainId,
|
|
19559
20082
|
domain: this.siweDomain,
|
|
@@ -19578,7 +20101,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19578
20101
|
}
|
|
19579
20102
|
const delegation = this.runtimeDelegationFromSession(
|
|
19580
20103
|
delegatedSession,
|
|
19581
|
-
|
|
20104
|
+
delegatedEntries,
|
|
19582
20105
|
spaceId,
|
|
19583
20106
|
session,
|
|
19584
20107
|
expiresAt
|
|
@@ -19592,7 +20115,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19592
20115
|
jwk: session.jwk
|
|
19593
20116
|
},
|
|
19594
20117
|
delegation,
|
|
19595
|
-
operations: this.permissionOperations(
|
|
20118
|
+
operations: this.permissionOperations(delegatedEntries, spaceId),
|
|
19596
20119
|
expiresAt
|
|
19597
20120
|
});
|
|
19598
20121
|
delegations.push(delegation);
|
|
@@ -19740,7 +20263,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19740
20263
|
];
|
|
19741
20264
|
const abilities = { kv: { "": kvActions } };
|
|
19742
20265
|
const now = /* @__PURE__ */ new Date();
|
|
19743
|
-
const expiryMs =
|
|
20266
|
+
const expiryMs = EXPIRY3.EPHEMERAL_MS;
|
|
19744
20267
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
19745
20268
|
const prepared = this.wasmBindings.prepareSession({
|
|
19746
20269
|
abilities,
|
|
@@ -19910,7 +20433,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19910
20433
|
* `forceWalletSign` is not set.
|
|
19911
20434
|
*/
|
|
19912
20435
|
async delegateTo(did, permissions, options) {
|
|
19913
|
-
const session = this.
|
|
20436
|
+
const session = this.currentTinyCloudSession();
|
|
19914
20437
|
if (!session) {
|
|
19915
20438
|
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
19916
20439
|
}
|
|
@@ -20024,11 +20547,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20024
20547
|
* the current session; we build one multi-resource abilities map
|
|
20025
20548
|
* and emit one signed UCAN covering them all.
|
|
20026
20549
|
*
|
|
20027
|
-
*
|
|
20028
|
-
*
|
|
20029
|
-
* spaces in a single delegation is not supported by the underlying
|
|
20030
|
-
* Rust create_delegation call and the resulting UCAN would be
|
|
20031
|
-
* under-specified.
|
|
20550
|
+
* Non-encryption entries must share the same target space. Encryption
|
|
20551
|
+
* entries are raw network URNs and do not participate in space grouping.
|
|
20032
20552
|
*
|
|
20033
20553
|
* @internal
|
|
20034
20554
|
*/
|
|
@@ -20040,15 +20560,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20040
20560
|
}
|
|
20041
20561
|
const resolvedSpaces = /* @__PURE__ */ new Set();
|
|
20042
20562
|
for (const entry of entries) {
|
|
20563
|
+
if (this.isEncryptionPermissionEntry(entry)) {
|
|
20564
|
+
continue;
|
|
20565
|
+
}
|
|
20043
20566
|
const spaceId2 = this.resolvePermissionSpace(entry.space, session);
|
|
20044
20567
|
resolvedSpaces.add(spaceId2);
|
|
20045
20568
|
}
|
|
20046
|
-
if (resolvedSpaces.size
|
|
20569
|
+
if (resolvedSpaces.size > 1) {
|
|
20047
20570
|
throw new Error(
|
|
20048
20571
|
`delegateTo: all permission entries must target the same space, got ${resolvedSpaces.size}: ${JSON.stringify([...resolvedSpaces])}`
|
|
20049
20572
|
);
|
|
20050
20573
|
}
|
|
20051
|
-
const spaceId = [...resolvedSpaces][0];
|
|
20574
|
+
const spaceId = resolvedSpaces.size === 1 ? [...resolvedSpaces][0] : session.spaceId;
|
|
20052
20575
|
const abilities = {};
|
|
20053
20576
|
for (const entry of entries) {
|
|
20054
20577
|
const shortService = SERVICE_LONG_TO_SHORT[entry.service];
|
|
@@ -20195,11 +20718,32 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20195
20718
|
}
|
|
20196
20719
|
return abilities;
|
|
20197
20720
|
}
|
|
20721
|
+
isEncryptionPermissionEntry(entry) {
|
|
20722
|
+
return entry.service === ENCRYPTION_PERMISSION_SERVICE2 && entry.path.startsWith("urn:tinycloud:encryption:");
|
|
20723
|
+
}
|
|
20724
|
+
permissionsToRawAbilities(entries) {
|
|
20725
|
+
const rawAbilities = {};
|
|
20726
|
+
for (const entry of entries) {
|
|
20727
|
+
if (!this.isEncryptionPermissionEntry(entry)) {
|
|
20728
|
+
continue;
|
|
20729
|
+
}
|
|
20730
|
+
const existing = rawAbilities[entry.path] ?? [];
|
|
20731
|
+
const seen = new Set(existing);
|
|
20732
|
+
for (const action of entry.actions) {
|
|
20733
|
+
if (!seen.has(action)) {
|
|
20734
|
+
existing.push(action);
|
|
20735
|
+
seen.add(action);
|
|
20736
|
+
}
|
|
20737
|
+
}
|
|
20738
|
+
rawAbilities[entry.path] = existing;
|
|
20739
|
+
}
|
|
20740
|
+
return rawAbilities;
|
|
20741
|
+
}
|
|
20198
20742
|
permissionOperations(entries, spaceId) {
|
|
20199
20743
|
return entries.flatMap((entry) => {
|
|
20200
20744
|
const service = this.shortServiceName(entry.service);
|
|
20201
20745
|
return entry.actions.map((action) => ({
|
|
20202
|
-
spaceId,
|
|
20746
|
+
...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
|
|
20203
20747
|
service,
|
|
20204
20748
|
path: entry.path,
|
|
20205
20749
|
action
|
|
@@ -20222,7 +20766,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20222
20766
|
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
20223
20767
|
const service = this.shortServiceName(entry.service);
|
|
20224
20768
|
return entry.actions.map((action) => ({
|
|
20225
|
-
spaceId,
|
|
20769
|
+
...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
|
|
20226
20770
|
service,
|
|
20227
20771
|
path: entry.path,
|
|
20228
20772
|
action
|
|
@@ -20279,24 +20823,40 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20279
20823
|
expiresAt: delegation.expiry
|
|
20280
20824
|
};
|
|
20281
20825
|
}
|
|
20826
|
+
installRuntimeGrantFromServiceSession(delegation, session, expiresAt) {
|
|
20827
|
+
const operations = this.operationsFromDelegation(delegation);
|
|
20828
|
+
if (operations.length === 0) {
|
|
20829
|
+
return;
|
|
20830
|
+
}
|
|
20831
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
20832
|
+
(grant) => grant.delegation.cid !== delegation.cid && grant.session.delegationCid !== session.delegationCid
|
|
20833
|
+
);
|
|
20834
|
+
this.runtimePermissionGrants.push({
|
|
20835
|
+
session,
|
|
20836
|
+
delegation,
|
|
20837
|
+
operations,
|
|
20838
|
+
expiresAt
|
|
20839
|
+
});
|
|
20840
|
+
}
|
|
20282
20841
|
delegatedResourcesForEntries(entries, spaceId) {
|
|
20283
20842
|
return entries.map((entry) => ({
|
|
20284
20843
|
service: this.shortServiceName(entry.service),
|
|
20285
|
-
space: spaceId,
|
|
20844
|
+
space: this.isEncryptionPermissionEntry(entry) ? "encryption" : spaceId,
|
|
20286
20845
|
path: entry.path,
|
|
20287
20846
|
actions: [...entry.actions]
|
|
20288
20847
|
}));
|
|
20289
20848
|
}
|
|
20290
20849
|
operationsFromDelegation(delegation) {
|
|
20291
20850
|
const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
|
|
20292
|
-
return resources.flatMap(
|
|
20293
|
-
|
|
20294
|
-
|
|
20295
|
-
service:
|
|
20851
|
+
return resources.flatMap((resource) => {
|
|
20852
|
+
const service = this.invocationServiceName(resource.service);
|
|
20853
|
+
return resource.actions.map((action) => ({
|
|
20854
|
+
...this.isEncryptionNetworkOperation(service, resource.path) ? { resource: resource.path } : { spaceId: resource.space },
|
|
20855
|
+
service,
|
|
20296
20856
|
path: resource.path,
|
|
20297
20857
|
action
|
|
20298
|
-
}))
|
|
20299
|
-
);
|
|
20858
|
+
}));
|
|
20859
|
+
});
|
|
20300
20860
|
}
|
|
20301
20861
|
flatDelegationResources(delegation) {
|
|
20302
20862
|
const byService = /* @__PURE__ */ new Map();
|
|
@@ -20345,7 +20905,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20345
20905
|
);
|
|
20346
20906
|
}
|
|
20347
20907
|
operationCovers(granted, requested) {
|
|
20348
|
-
|
|
20908
|
+
if (granted.service !== requested.service || !this.actionContains(granted.action, requested.action)) {
|
|
20909
|
+
return false;
|
|
20910
|
+
}
|
|
20911
|
+
if (granted.resource !== void 0 || requested.resource !== void 0) {
|
|
20912
|
+
return granted.resource !== void 0 && requested.resource !== void 0 && granted.resource === requested.resource && this.pathContains(granted.path, requested.path);
|
|
20913
|
+
}
|
|
20914
|
+
return granted.spaceId !== void 0 && requested.spaceId !== void 0 && granted.spaceId === requested.spaceId && this.pathContains(granted.path, requested.path);
|
|
20349
20915
|
}
|
|
20350
20916
|
actionContains(grantedAction, requestedAction) {
|
|
20351
20917
|
if (grantedAction === requestedAction) {
|
|
@@ -20360,6 +20926,37 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20360
20926
|
invocationServiceName(service) {
|
|
20361
20927
|
return service.startsWith("tinycloud.") ? this.shortServiceName(service) : service;
|
|
20362
20928
|
}
|
|
20929
|
+
isEncryptionNetworkOperation(service, path) {
|
|
20930
|
+
return service === "encryption" && path.startsWith("urn:tinycloud:encryption:");
|
|
20931
|
+
}
|
|
20932
|
+
operationFromInvokeAnyEntry(entry) {
|
|
20933
|
+
const service = this.invocationServiceName(entry.service);
|
|
20934
|
+
if (typeof entry.resource === "string") {
|
|
20935
|
+
return {
|
|
20936
|
+
resource: entry.resource,
|
|
20937
|
+
service,
|
|
20938
|
+
path: entry.path,
|
|
20939
|
+
action: entry.action
|
|
20940
|
+
};
|
|
20941
|
+
}
|
|
20942
|
+
if (this.isEncryptionNetworkOperation(service, entry.path)) {
|
|
20943
|
+
return {
|
|
20944
|
+
resource: entry.path,
|
|
20945
|
+
service,
|
|
20946
|
+
path: entry.path,
|
|
20947
|
+
action: entry.action
|
|
20948
|
+
};
|
|
20949
|
+
}
|
|
20950
|
+
if (typeof entry.spaceId === "string") {
|
|
20951
|
+
return {
|
|
20952
|
+
spaceId: entry.spaceId,
|
|
20953
|
+
service,
|
|
20954
|
+
path: entry.path,
|
|
20955
|
+
action: entry.action
|
|
20956
|
+
};
|
|
20957
|
+
}
|
|
20958
|
+
return void 0;
|
|
20959
|
+
}
|
|
20363
20960
|
pathContains(grantedPath, requestedPath) {
|
|
20364
20961
|
if (grantedPath === "" || grantedPath === "/") {
|
|
20365
20962
|
return true;
|
|
@@ -20598,6 +21195,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20598
21195
|
// Not used in session-only mode
|
|
20599
21196
|
};
|
|
20600
21197
|
this.trackReceivedDelegation(delegation, this.sessionKeyJwk);
|
|
21198
|
+
this.installRuntimeGrantFromServiceSession(
|
|
21199
|
+
delegation,
|
|
21200
|
+
{
|
|
21201
|
+
delegationHeader: session2.delegationHeader,
|
|
21202
|
+
delegationCid: session2.delegationCid,
|
|
21203
|
+
spaceId: session2.spaceId,
|
|
21204
|
+
verificationMethod: session2.verificationMethod,
|
|
21205
|
+
jwk: session2.jwk
|
|
21206
|
+
},
|
|
21207
|
+
delegation.expiry
|
|
21208
|
+
);
|
|
20601
21209
|
return new DelegatedAccess(session2, delegation, targetHost, this.wasmBindings.invoke);
|
|
20602
21210
|
}
|
|
20603
21211
|
const mySession = this.auth?.tinyCloudSession;
|
|
@@ -20609,6 +21217,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20609
21217
|
const kvActions = delegation.actions.filter((a) => a.startsWith("tinycloud.kv/"));
|
|
20610
21218
|
const sqlActions = delegation.actions.filter((a) => a.startsWith("tinycloud.sql/"));
|
|
20611
21219
|
const duckdbActions = delegation.actions.filter((a) => a.startsWith("tinycloud.duckdb/"));
|
|
21220
|
+
const encryptionActions = delegation.actions.filter(
|
|
21221
|
+
(a) => a.startsWith("tinycloud.encryption/")
|
|
21222
|
+
);
|
|
21223
|
+
const rawAbilities = {};
|
|
20612
21224
|
if (kvActions.length > 0) {
|
|
20613
21225
|
abilities.kv = { [delegation.path]: kvActions };
|
|
20614
21226
|
}
|
|
@@ -20618,6 +21230,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20618
21230
|
if (duckdbActions.length > 0) {
|
|
20619
21231
|
abilities.duckdb = { [delegation.path]: duckdbActions };
|
|
20620
21232
|
}
|
|
21233
|
+
if (encryptionActions.length > 0 && delegation.path.startsWith("urn:tinycloud:encryption:")) {
|
|
21234
|
+
rawAbilities[delegation.path] = encryptionActions;
|
|
21235
|
+
}
|
|
20621
21236
|
const now = /* @__PURE__ */ new Date();
|
|
20622
21237
|
const maxExpiry = new Date(now.getTime() + 60 * 60 * 1e3);
|
|
20623
21238
|
const expirationTime = delegation.expiry < maxExpiry ? delegation.expiry : maxExpiry;
|
|
@@ -20630,7 +21245,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20630
21245
|
expirationTime: expirationTime.toISOString(),
|
|
20631
21246
|
spaceId: delegation.spaceId,
|
|
20632
21247
|
jwk,
|
|
20633
|
-
parents: [delegation.cid]
|
|
21248
|
+
parents: [delegation.cid],
|
|
21249
|
+
...Object.keys(rawAbilities).length > 0 ? { rawAbilities } : {}
|
|
20634
21250
|
});
|
|
20635
21251
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
20636
21252
|
const invokerSession = this.wasmBindings.completeSessionSetup({
|
|
@@ -20657,6 +21273,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20657
21273
|
signature: signature2
|
|
20658
21274
|
};
|
|
20659
21275
|
this.trackReceivedDelegation(delegation, jwk);
|
|
21276
|
+
this.installRuntimeGrantFromServiceSession(
|
|
21277
|
+
delegation,
|
|
21278
|
+
{
|
|
21279
|
+
delegationHeader: session.delegationHeader,
|
|
21280
|
+
delegationCid: session.delegationCid,
|
|
21281
|
+
spaceId: session.spaceId,
|
|
21282
|
+
verificationMethod: session.verificationMethod,
|
|
21283
|
+
jwk: session.jwk
|
|
21284
|
+
},
|
|
21285
|
+
expirationTime
|
|
21286
|
+
);
|
|
20660
21287
|
return new DelegatedAccess(session, delegation, targetHost, this.wasmBindings.invoke);
|
|
20661
21288
|
}
|
|
20662
21289
|
/**
|
|
@@ -20911,7 +21538,7 @@ import {
|
|
|
20911
21538
|
loadManifest,
|
|
20912
21539
|
isCapabilitySubset as isCapabilitySubset2,
|
|
20913
21540
|
expandActionShortNames,
|
|
20914
|
-
expandPermissionEntries,
|
|
21541
|
+
expandPermissionEntries as expandPermissionEntries2,
|
|
20915
21542
|
expandPermissionEntry,
|
|
20916
21543
|
parseExpiry as parseExpiry2,
|
|
20917
21544
|
resourceCapabilitiesToSpaceAbilitiesMap as resourceCapabilitiesToSpaceAbilitiesMap2
|
|
@@ -20934,7 +21561,11 @@ function deserializeDelegation(data) {
|
|
|
20934
21561
|
}
|
|
20935
21562
|
|
|
20936
21563
|
// src/index.ts
|
|
20937
|
-
import {
|
|
21564
|
+
import {
|
|
21565
|
+
DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
|
|
21566
|
+
KVService as KVService3,
|
|
21567
|
+
PrefixedKVService
|
|
21568
|
+
} from "@tinycloud/sdk-core";
|
|
20938
21569
|
import { SQLService as SQLService3, SQLAction, DatabaseHandle } from "@tinycloud/sdk-core";
|
|
20939
21570
|
import {
|
|
20940
21571
|
DuckDbService as DuckDbService3,
|
|
@@ -20946,7 +21577,53 @@ import {
|
|
|
20946
21577
|
VaultHeaders,
|
|
20947
21578
|
VaultPublicSpaceKVActions,
|
|
20948
21579
|
createVaultCrypto as createVaultCrypto2,
|
|
20949
|
-
SecretsService as SecretsService2
|
|
21580
|
+
SecretsService as SecretsService2,
|
|
21581
|
+
SECRET_NAME_RE,
|
|
21582
|
+
canonicalizeSecretScope,
|
|
21583
|
+
resolveSecretListPrefix as resolveSecretListPrefix2,
|
|
21584
|
+
resolveSecretPath as resolveSecretPath2
|
|
21585
|
+
} from "@tinycloud/sdk-core";
|
|
21586
|
+
import {
|
|
21587
|
+
EncryptionService as EncryptionService2,
|
|
21588
|
+
parseNetworkId,
|
|
21589
|
+
buildNetworkId,
|
|
21590
|
+
isNetworkId,
|
|
21591
|
+
networkDiscoveryKey,
|
|
21592
|
+
NetworkIdError,
|
|
21593
|
+
ENCRYPTION_NETWORK_URN_PREFIX,
|
|
21594
|
+
NETWORK_NAME_PATTERN,
|
|
21595
|
+
canonicalizeEncryptionJson as canonicalizeEncryptionJson2,
|
|
21596
|
+
canonicalHashHex as canonicalHashHex2,
|
|
21597
|
+
hexEncode,
|
|
21598
|
+
hexDecode,
|
|
21599
|
+
encryptionBase64Encode,
|
|
21600
|
+
encryptionBase64Decode,
|
|
21601
|
+
encryptionUtf8Encode,
|
|
21602
|
+
encryptionUtf8Decode,
|
|
21603
|
+
encryptToNetwork,
|
|
21604
|
+
decryptEnvelopeWithKey,
|
|
21605
|
+
validateEnvelope,
|
|
21606
|
+
generateRandomReceiverKey,
|
|
21607
|
+
deriveSignedReceiverKey,
|
|
21608
|
+
buildCanonicalDecryptRequest,
|
|
21609
|
+
buildDecryptFacts,
|
|
21610
|
+
buildDecryptAttenuation,
|
|
21611
|
+
buildDecryptInvocation,
|
|
21612
|
+
checkDecryptInvocationInput,
|
|
21613
|
+
verifyDecryptResponse,
|
|
21614
|
+
canonicalSignedResponse,
|
|
21615
|
+
openWrappedKey,
|
|
21616
|
+
discoverNetwork,
|
|
21617
|
+
ensureNetworkUsableForDecrypt,
|
|
21618
|
+
DEFAULT_ENCRYPTION_ALG,
|
|
21619
|
+
ENVELOPE_VERSION,
|
|
21620
|
+
DEFAULT_KEY_VERSION,
|
|
21621
|
+
DECRYPT_FACT_TYPE,
|
|
21622
|
+
DECRYPT_RESULT_TYPE,
|
|
21623
|
+
DECRYPT_ACTION as DECRYPT_ACTION2,
|
|
21624
|
+
ENCRYPTION_SERVICE,
|
|
21625
|
+
ENCRYPTION_SERVICE_SHORT,
|
|
21626
|
+
encryptionError
|
|
20950
21627
|
} from "@tinycloud/sdk-core";
|
|
20951
21628
|
import { HooksService as HooksService3 } from "@tinycloud/sdk-core";
|
|
20952
21629
|
import {
|
|
@@ -20982,8 +21659,14 @@ export {
|
|
|
20982
21659
|
AutoApproveSpaceCreationHandler2 as AutoApproveSpaceCreationHandler,
|
|
20983
21660
|
CapabilityKeyRegistry2 as CapabilityKeyRegistry,
|
|
20984
21661
|
CapabilityKeyRegistryErrorCodes,
|
|
21662
|
+
DECRYPT_ACTION2 as DECRYPT_ACTION,
|
|
21663
|
+
DECRYPT_FACT_TYPE,
|
|
21664
|
+
DECRYPT_RESULT_TYPE,
|
|
21665
|
+
DEFAULT_ENCRYPTION_ALG,
|
|
21666
|
+
DEFAULT_KEY_VERSION,
|
|
20985
21667
|
DEFAULT_MANIFEST_SPACE2 as DEFAULT_MANIFEST_SPACE,
|
|
20986
21668
|
DEFAULT_MANIFEST_VERSION,
|
|
21669
|
+
DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
|
|
20987
21670
|
DataVaultService2 as DataVaultService,
|
|
20988
21671
|
DatabaseHandle,
|
|
20989
21672
|
DelegatedAccess,
|
|
@@ -20992,17 +21675,25 @@ export {
|
|
|
20992
21675
|
DuckDbAction,
|
|
20993
21676
|
DuckDbDatabaseHandle,
|
|
20994
21677
|
DuckDbService3 as DuckDbService,
|
|
21678
|
+
ENCRYPTION_NETWORK_URN_PREFIX,
|
|
21679
|
+
ENCRYPTION_SERVICE,
|
|
21680
|
+
ENCRYPTION_SERVICE_SHORT,
|
|
21681
|
+
ENVELOPE_VERSION,
|
|
21682
|
+
EncryptionService2 as EncryptionService,
|
|
20995
21683
|
FileSessionStorage,
|
|
20996
21684
|
HooksService3 as HooksService,
|
|
20997
21685
|
KVService3 as KVService,
|
|
20998
21686
|
ManifestValidationError,
|
|
20999
21687
|
MemorySessionStorage,
|
|
21688
|
+
NETWORK_NAME_PATTERN,
|
|
21689
|
+
NetworkIdError,
|
|
21000
21690
|
NodeUserAuthorization,
|
|
21001
21691
|
NodeWasmBindings,
|
|
21002
21692
|
PermissionNotInManifestError2 as PermissionNotInManifestError,
|
|
21003
21693
|
PrefixedKVService,
|
|
21004
21694
|
PrivateKeySigner,
|
|
21005
21695
|
ProtocolMismatchError,
|
|
21696
|
+
SECRET_NAME_RE,
|
|
21006
21697
|
SQLAction,
|
|
21007
21698
|
SQLService3 as SQLService,
|
|
21008
21699
|
SecretsService2 as SecretsService,
|
|
@@ -21021,7 +21712,17 @@ export {
|
|
|
21021
21712
|
VaultPublicSpaceKVActions,
|
|
21022
21713
|
VersionCheckError,
|
|
21023
21714
|
WasmKeyProvider,
|
|
21715
|
+
buildCanonicalDecryptRequest,
|
|
21716
|
+
buildDecryptAttenuation,
|
|
21717
|
+
buildDecryptFacts,
|
|
21718
|
+
buildDecryptInvocation,
|
|
21719
|
+
buildNetworkId,
|
|
21024
21720
|
buildSpaceUri,
|
|
21721
|
+
canonicalHashHex2 as canonicalHashHex,
|
|
21722
|
+
canonicalSignedResponse,
|
|
21723
|
+
canonicalizeEncryptionJson2 as canonicalizeEncryptionJson,
|
|
21724
|
+
canonicalizeSecretScope,
|
|
21725
|
+
checkDecryptInvocationInput,
|
|
21025
21726
|
checkNodeInfo2 as checkNodeInfo,
|
|
21026
21727
|
composeManifestRequest2 as composeManifestRequest,
|
|
21027
21728
|
createCapabilityKeyRegistry,
|
|
@@ -21029,21 +21730,42 @@ export {
|
|
|
21029
21730
|
createSpaceService,
|
|
21030
21731
|
createVaultCrypto2 as createVaultCrypto,
|
|
21031
21732
|
createWasmKeyProvider,
|
|
21733
|
+
decryptEnvelopeWithKey,
|
|
21032
21734
|
defaultSignStrategy,
|
|
21033
21735
|
defaultSpaceCreationHandler,
|
|
21736
|
+
deriveSignedReceiverKey,
|
|
21034
21737
|
deserializeDelegation,
|
|
21738
|
+
discoverNetwork,
|
|
21739
|
+
encryptToNetwork,
|
|
21740
|
+
encryptionBase64Decode,
|
|
21741
|
+
encryptionBase64Encode,
|
|
21742
|
+
encryptionError,
|
|
21743
|
+
encryptionUtf8Decode,
|
|
21744
|
+
encryptionUtf8Encode,
|
|
21745
|
+
ensureNetworkUsableForDecrypt,
|
|
21035
21746
|
expandActionShortNames,
|
|
21036
|
-
expandPermissionEntries,
|
|
21747
|
+
expandPermissionEntries2 as expandPermissionEntries,
|
|
21037
21748
|
expandPermissionEntry,
|
|
21749
|
+
generateRandomReceiverKey,
|
|
21750
|
+
hexDecode,
|
|
21751
|
+
hexEncode,
|
|
21038
21752
|
isCapabilitySubset2 as isCapabilitySubset,
|
|
21753
|
+
isNetworkId,
|
|
21039
21754
|
loadManifest,
|
|
21040
21755
|
makePublicSpaceId2 as makePublicSpaceId,
|
|
21756
|
+
networkDiscoveryKey,
|
|
21757
|
+
openWrappedKey,
|
|
21041
21758
|
parseExpiry2 as parseExpiry,
|
|
21759
|
+
parseNetworkId,
|
|
21042
21760
|
parseSpaceUri,
|
|
21043
21761
|
resolveManifest2 as resolveManifest,
|
|
21762
|
+
resolveSecretListPrefix2 as resolveSecretListPrefix,
|
|
21763
|
+
resolveSecretPath2 as resolveSecretPath,
|
|
21044
21764
|
resourceCapabilitiesToSpaceAbilitiesMap2 as resourceCapabilitiesToSpaceAbilitiesMap,
|
|
21045
21765
|
serializeDelegation,
|
|
21046
|
-
|
|
21766
|
+
validateEnvelope,
|
|
21767
|
+
validateManifest,
|
|
21768
|
+
verifyDecryptResponse
|
|
21047
21769
|
};
|
|
21048
21770
|
/*! Bundled license information:
|
|
21049
21771
|
|