@tinycloud/node-sdk 3.8.0-beta.2 → 3.8.0-beta.21
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/README.md +6 -0
- package/dist/{TinyCloudNode-B6VOBrCb.d.ts → TinyCloudNode-DaD5vJhL.d.cts} +49 -6
- package/dist/{TinyCloudNode-CVO41O12.d.cts → TinyCloudNode-k3TbBwwj.d.ts} +49 -6
- package/dist/{WasmKeyProvider-5Ee7fcAw.d.cts → WasmKeyProvider-BKCPRC-c.d.cts} +21 -1
- package/dist/{WasmKeyProvider-5Ee7fcAw.d.ts → WasmKeyProvider-BKCPRC-c.d.ts} +21 -1
- package/dist/{authority-DGi1hIMK.d.ts → authority-C_fWaxAu.d.ts} +1 -1
- package/dist/{authority-DgVV80bI.d.cts → authority-DJdbZM6k.d.cts} +1 -1
- package/dist/core.cjs +375 -40
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +5 -4
- package/dist/core.d.ts +5 -4
- package/dist/core.js +370 -35
- package/dist/core.js.map +1 -1
- package/dist/credentials-core.d.cts +1 -1
- package/dist/credentials-core.d.ts +1 -1
- package/dist/credentials.d.cts +1 -1
- package/dist/credentials.d.ts +1 -1
- package/dist/{delegation-0LKZkmP2.d.cts → delegation-Ckc3UETl.d.cts} +1 -1
- package/dist/{delegation-0LKZkmP2.d.ts → delegation-Ckc3UETl.d.ts} +1 -1
- package/dist/encryption-keys.d.cts +2 -2
- package/dist/encryption-keys.d.ts +2 -2
- package/dist/index.cjs +343 -51
- 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 +333 -38
- package/dist/index.js.map +1 -1
- package/dist/replication/authority.cjs +3 -0
- package/dist/replication/authority.cjs.map +1 -1
- package/dist/replication/authority.d.cts +4 -3
- package/dist/replication/authority.d.ts +4 -3
- package/dist/replication/authority.js +3 -0
- package/dist/replication/authority.js.map +1 -1
- package/dist/replication/runtime.cjs +1 -0
- package/dist/replication/runtime.cjs.map +1 -1
- package/dist/replication/runtime.js +1 -0
- package/dist/replication/runtime.js.map +1 -1
- package/dist/share-receive.cjs +775 -0
- package/dist/share-receive.cjs.map +1 -0
- package/dist/share-receive.d.cts +32 -0
- package/dist/share-receive.d.ts +32 -0
- package/dist/share-receive.js +777 -0
- package/dist/share-receive.js.map +1 -0
- package/package.json +11 -4
package/dist/core.cjs
CHANGED
|
@@ -58,6 +58,7 @@ __export(core_exports, {
|
|
|
58
58
|
PermissionNotInManifestError: () => import_sdk_core14.PermissionNotInManifestError,
|
|
59
59
|
PrefixedKVService: () => import_sdk_core15.PrefixedKVService,
|
|
60
60
|
ProtocolMismatchError: () => import_sdk_core22.ProtocolMismatchError,
|
|
61
|
+
RuntimeDelegationRejectedError: () => RuntimeDelegationRejectedError,
|
|
61
62
|
SECRET_NAME_RE: () => import_sdk_core18.SECRET_NAME_RE,
|
|
62
63
|
SQLAction: () => import_sdk_core16.SQLAction,
|
|
63
64
|
SQLService: () => import_sdk_core16.SQLService,
|
|
@@ -80,6 +81,7 @@ __export(core_exports, {
|
|
|
80
81
|
VersionCheckError: () => import_sdk_core22.VersionCheckError,
|
|
81
82
|
WasmKeyProvider: () => WasmKeyProvider,
|
|
82
83
|
activateCompactRuntimeDelegation: () => activateCompactRuntimeDelegation,
|
|
84
|
+
activateValidatedRuntimeDelegation: () => activateValidatedRuntimeDelegation,
|
|
83
85
|
addressStorageKey: () => import_sdk_core13.addressStorageKey,
|
|
84
86
|
buildSpaceUri: () => import_sdk_core21.buildSpaceUri,
|
|
85
87
|
canonicalizeAddress: () => import_sdk_core13.canonicalizeAddress,
|
|
@@ -109,6 +111,7 @@ __export(core_exports, {
|
|
|
109
111
|
getNodeReplicationLoaders: () => getNodeReplicationLoaders,
|
|
110
112
|
getTinyCloudDebugLogs: () => import_sdk_core13.getTinyCloudDebugLogs,
|
|
111
113
|
installTinyCloudDebugGlobals: () => import_sdk_core13.installTinyCloudDebugGlobals,
|
|
114
|
+
isAppKeyHostBound: () => isAppKeyHostBound,
|
|
112
115
|
isCapabilitySubset: () => import_sdk_core14.isCapabilitySubset,
|
|
113
116
|
isEvmAddress: () => import_sdk_core13.isEvmAddress,
|
|
114
117
|
loadManifest: () => import_sdk_core14.loadManifest,
|
|
@@ -130,7 +133,8 @@ __export(core_exports, {
|
|
|
130
133
|
resourceCapabilitiesToSpaceAbilitiesMap: () => import_sdk_core14.resourceCapabilitiesToSpaceAbilitiesMap,
|
|
131
134
|
serializeDelegation: () => serializeDelegation,
|
|
132
135
|
tinyCloudDebugLogger: () => import_sdk_core13.tinyCloudDebugLogger,
|
|
133
|
-
validateManifest: () => import_sdk_core14.validateManifest
|
|
136
|
+
validateManifest: () => import_sdk_core14.validateManifest,
|
|
137
|
+
wireOpenKeyAuthorize: () => wireOpenKeyAuthorize
|
|
134
138
|
});
|
|
135
139
|
module.exports = __toCommonJS(core_exports);
|
|
136
140
|
var import_sdk_core12 = require("@tinycloud/sdk-core");
|
|
@@ -345,6 +349,44 @@ var FileSessionStorage = class {
|
|
|
345
349
|
var import_node_crypto = require("crypto");
|
|
346
350
|
var import_siwe = require("siwe");
|
|
347
351
|
var import_sdk_core5 = require("@tinycloud/sdk-core");
|
|
352
|
+
var import_resource = require("@tinycloud/sdk-services/encryption/resource");
|
|
353
|
+
var import_sdk_services2 = require("@tinycloud/sdk-services");
|
|
354
|
+
|
|
355
|
+
// src/authorization/appKeyHostBinding.ts
|
|
356
|
+
var DOMAIN_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
357
|
+
var IPV4 = /^\d+\.\d+\.\d+\.\d+$/;
|
|
358
|
+
var APP_ID = /^[a-z0-9][a-z0-9._-]{0,63}$/;
|
|
359
|
+
function appKeyHostBinding(domain, appId) {
|
|
360
|
+
if (!APP_ID.test(appId)) return false;
|
|
361
|
+
if (domain.endsWith(":")) return false;
|
|
362
|
+
let url;
|
|
363
|
+
try {
|
|
364
|
+
url = new URL(`https://${domain}`);
|
|
365
|
+
} catch {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
if (url.protocol !== "https:" || url.port !== "" || url.username !== "" || url.password !== "") return false;
|
|
369
|
+
if (url.pathname !== "/" || url.search !== "" || url.hash !== "") return false;
|
|
370
|
+
const host = url.hostname;
|
|
371
|
+
if (host.startsWith("[") || host.endsWith(".") || IPV4.test(host)) return false;
|
|
372
|
+
const labels = host.split(".");
|
|
373
|
+
if (labels.length < 2 || labels[labels.length - 1] === "localhost") return false;
|
|
374
|
+
if (!labels.every((label) => DOMAIN_LABEL.test(label))) return false;
|
|
375
|
+
const reversed = labels.reverse().join(".");
|
|
376
|
+
return appId === reversed || appId.startsWith(`${reversed}.`);
|
|
377
|
+
}
|
|
378
|
+
function isAppKeyHostBound(keysAppId, origin) {
|
|
379
|
+
if (typeof origin === "string" && !origin.includes("://")) {
|
|
380
|
+
return appKeyHostBinding(origin, keysAppId);
|
|
381
|
+
}
|
|
382
|
+
let url;
|
|
383
|
+
try {
|
|
384
|
+
url = typeof origin === "string" ? new URL(origin) : origin;
|
|
385
|
+
} catch {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
return appKeyHostBinding(url.host, keysAppId);
|
|
389
|
+
}
|
|
348
390
|
|
|
349
391
|
// src/replication/authority-sign-in.ts
|
|
350
392
|
var import_sdk_core2 = require("@tinycloud/sdk-core");
|
|
@@ -476,6 +518,7 @@ function cloneAbilitiesMap(actions) {
|
|
|
476
518
|
var NodeUserAuthorization = class {
|
|
477
519
|
constructor(config) {
|
|
478
520
|
this.activeSessionKeyId = "default";
|
|
521
|
+
this.preparedSessionCounter = 0;
|
|
479
522
|
/** Incremented by resetSession; a sign-in started earlier publishes nothing. */
|
|
480
523
|
this.sessionGeneration = 0;
|
|
481
524
|
/**
|
|
@@ -832,6 +875,23 @@ var NodeUserAuthorization = class {
|
|
|
832
875
|
);
|
|
833
876
|
return this._capabilityRequest;
|
|
834
877
|
}
|
|
878
|
+
async refreshNamedKeyFeatureForSignIn(address, chainId) {
|
|
879
|
+
const request = this.getCapabilityRequest();
|
|
880
|
+
const siweDomain = this.siweConfig?.domain ?? this.domain;
|
|
881
|
+
const hasNamedKeys = request?.manifests.some((manifest) => manifest.keys?.length && appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id));
|
|
882
|
+
if (hasNamedKeys) {
|
|
883
|
+
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
884
|
+
await this.refreshNodeInfo();
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
/** Manifest key paths that this sign-in cannot grant. */
|
|
888
|
+
get unavailableKeyPaths() {
|
|
889
|
+
const request = this.getCapabilityRequest();
|
|
890
|
+
const siweDomain = this.siweConfig?.domain ?? this.domain;
|
|
891
|
+
return (request?.manifests ?? []).flatMap(
|
|
892
|
+
(manifest) => this._nodeFeatures.includes("encryption-named-keys-v1") && appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id) ? [] : (manifest.keys ?? []).map((entry) => "path" in entry ? entry.path : entry.prefix)
|
|
893
|
+
);
|
|
894
|
+
}
|
|
835
895
|
resolveSpaceName(space, address, chainId) {
|
|
836
896
|
if (space.startsWith("tinycloud:")) {
|
|
837
897
|
return space;
|
|
@@ -1023,15 +1083,32 @@ var NodeUserAuthorization = class {
|
|
|
1023
1083
|
}
|
|
1024
1084
|
const rawAbilities = {};
|
|
1025
1085
|
const currentDid = (0, import_sdk_core5.pkhDid)(address, chainId);
|
|
1086
|
+
if (this._nodeFeatures.includes("encryption-named-keys-v1")) {
|
|
1087
|
+
const siweDomain = this.siweConfig?.domain ?? this.domain;
|
|
1088
|
+
for (const manifest of request.manifests) {
|
|
1089
|
+
if (!appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id)) continue;
|
|
1090
|
+
for (const declaration of manifest.keys ?? []) {
|
|
1091
|
+
const path = "path" in declaration ? declaration.path : declaration.prefix;
|
|
1092
|
+
const resource = `urn:tinycloud:encryption:${currentDid}:default/${path}`;
|
|
1093
|
+
for (const ability of declaration.abilities) {
|
|
1094
|
+
addRawAbility(rawAbilities, resource, `tinycloud.encryption/${ability}`);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1026
1099
|
const spaceResources = request.resources.filter((entry) => {
|
|
1027
1100
|
if (entry.service !== import_sdk_core5.ENCRYPTION_PERMISSION_SERVICE) {
|
|
1028
1101
|
return true;
|
|
1029
1102
|
}
|
|
1103
|
+
const parsed = entry.path.includes("/") ? (0, import_resource.parseEncryptionResource)(entry.path) : { ...(0, import_sdk_services2.parseNetworkId)(entry.path), kind: "network" };
|
|
1104
|
+
const sharePrefix = parsed.kind === "prefix" && parsed.network === "default" && parsed.prefix === "share" && entry.actions.length === 1 && entry.actions[0] === DECRYPT_ACTION && didPrincipalMatches(parsed.ownerDid, currentDid);
|
|
1105
|
+
if (parsed.kind !== "network" && !sharePrefix) {
|
|
1106
|
+
throw new import_sdk_core5.ManifestValidationError("named keys go in manifest.keys");
|
|
1107
|
+
}
|
|
1030
1108
|
for (const action of entry.actions) {
|
|
1031
1109
|
addRawAbility(rawAbilities, entry.path, action);
|
|
1032
1110
|
}
|
|
1033
|
-
if (entry.actions.includes(DECRYPT_ACTION)) {
|
|
1034
|
-
const parsed = (0, import_sdk_core5.parseNetworkId)(entry.path);
|
|
1111
|
+
if (entry.actions.includes(DECRYPT_ACTION) && parsed.kind === "network") {
|
|
1035
1112
|
if (didPrincipalMatches(parsed.ownerDid, currentDid)) {
|
|
1036
1113
|
addRawAbility(rawAbilities, entry.path, NETWORK_CREATE_ACTION);
|
|
1037
1114
|
}
|
|
@@ -1068,8 +1145,7 @@ var NodeUserAuthorization = class {
|
|
|
1068
1145
|
/**
|
|
1069
1146
|
* Build SIWE overrides from the top-level nonce and siweConfig.
|
|
1070
1147
|
* - Top-level `nonce` is seeded first so `siweConfig.nonce` wins if both are set.
|
|
1071
|
-
* -
|
|
1072
|
-
* - resources are appended to the default resources
|
|
1148
|
+
* - resources are inserted after WASM preparation, before the final ReCap
|
|
1073
1149
|
* - uri triggers a warning (overwriting delegation target)
|
|
1074
1150
|
* - all other fields override directly
|
|
1075
1151
|
* - per-call nonce overrides siweConfig.nonce when provided
|
|
@@ -1087,9 +1163,6 @@ var NodeUserAuthorization = class {
|
|
|
1087
1163
|
if (statement) {
|
|
1088
1164
|
overrides.statement = this.statement ? `${statement} ${this.statement}` : statement;
|
|
1089
1165
|
}
|
|
1090
|
-
if (resources && resources.length > 0) {
|
|
1091
|
-
overrides.resources = resources;
|
|
1092
|
-
}
|
|
1093
1166
|
if (uri) {
|
|
1094
1167
|
console.warn(
|
|
1095
1168
|
"[tinycloud] siweConfig.uri is overwriting the delegation target URI. This may break delegation chain validation if the URI does not match the session key DID."
|
|
@@ -1101,6 +1174,29 @@ var NodeUserAuthorization = class {
|
|
|
1101
1174
|
}
|
|
1102
1175
|
return overrides;
|
|
1103
1176
|
}
|
|
1177
|
+
prepareSessionWithResources(params) {
|
|
1178
|
+
const resources = this.siweConfig?.resources;
|
|
1179
|
+
if (resources?.some((resource) => typeof resource !== "string" || !/^urn:tinycloud:recipients:[A-Za-z0-9_-]+$/.test(resource))) {
|
|
1180
|
+
throw new Error("SIWE metadata resources must be base64url recipients URIs");
|
|
1181
|
+
}
|
|
1182
|
+
const prepared = this.wasm.prepareSession(params);
|
|
1183
|
+
if (!resources?.length) return prepared;
|
|
1184
|
+
const recapLines = /^- urn:recap:[^\r\n]+$/gim;
|
|
1185
|
+
const recaps = prepared.siwe.match(recapLines);
|
|
1186
|
+
const recap = recaps?.[0];
|
|
1187
|
+
if (recaps?.length !== 1 || !prepared.siwe.endsWith(recap)) {
|
|
1188
|
+
throw new Error("Prepared SIWE must end with exactly one ReCap");
|
|
1189
|
+
}
|
|
1190
|
+
const insertedLines = resources.map((resource) => `- ${resource}`);
|
|
1191
|
+
const siwe = prepared.siwe.slice(0, -recap.length) + insertedLines.join("\n") + "\n" + recap;
|
|
1192
|
+
const expectedFields = (0, import_sdk_core5.extractImmutableSiweFields)(prepared.siwe);
|
|
1193
|
+
expectedFields.nonRecapResources = [expectedFields.nonRecapResources, ...insertedLines].filter(Boolean).join("\n");
|
|
1194
|
+
const actualRecaps = siwe.match(recapLines);
|
|
1195
|
+
if (actualRecaps?.length !== 1 || actualRecaps[0] !== recap || (0, import_sdk_core5.diffImmutableSiweFields)(expectedFields, (0, import_sdk_core5.extractImmutableSiweFields)(siwe)).length) {
|
|
1196
|
+
throw new Error("SIWE metadata insertion changed the prepared message");
|
|
1197
|
+
}
|
|
1198
|
+
return { ...prepared, siwe };
|
|
1199
|
+
}
|
|
1104
1200
|
/**
|
|
1105
1201
|
* Add an extension to the authorization flow.
|
|
1106
1202
|
*/
|
|
@@ -1348,7 +1444,7 @@ var NodeUserAuthorization = class {
|
|
|
1348
1444
|
spaceAbilities[spaceId] = (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)(resources);
|
|
1349
1445
|
}
|
|
1350
1446
|
const abilities = spaceAbilities[options.spaceId] ?? (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)([]);
|
|
1351
|
-
const prepared = this.
|
|
1447
|
+
const prepared = this.prepareSessionWithResources({
|
|
1352
1448
|
abilities,
|
|
1353
1449
|
spaceAbilities,
|
|
1354
1450
|
...options.rawAbilities !== void 0 ? { rawAbilities: options.rawAbilities } : {},
|
|
@@ -1427,8 +1523,10 @@ var NodeUserAuthorization = class {
|
|
|
1427
1523
|
this._chainId = chainId;
|
|
1428
1524
|
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
1429
1525
|
this.assertSignInCurrent(generation);
|
|
1430
|
-
|
|
1431
|
-
this.
|
|
1526
|
+
await this.refreshNamedKeyFeatureForSignIn(address, chainId);
|
|
1527
|
+
this.assertSignInCurrent(generation);
|
|
1528
|
+
const keyId = `session-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
1529
|
+
this.sessionManager.createSessionKey(keyId);
|
|
1432
1530
|
this.activeSessionKeyId = keyId;
|
|
1433
1531
|
const jwkString = this.sessionManager.jwk(keyId);
|
|
1434
1532
|
if (!jwkString) {
|
|
@@ -1439,7 +1537,7 @@ var NodeUserAuthorization = class {
|
|
|
1439
1537
|
const spaceId = capabilityPlan.spaceId;
|
|
1440
1538
|
const now = /* @__PURE__ */ new Date();
|
|
1441
1539
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
1442
|
-
const prepared = this.
|
|
1540
|
+
const prepared = this.prepareSessionWithResources({
|
|
1443
1541
|
abilities: capabilityPlan.abilities,
|
|
1444
1542
|
...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
|
|
1445
1543
|
...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
|
|
@@ -1573,9 +1671,9 @@ var NodeUserAuthorization = class {
|
|
|
1573
1671
|
refuseCaveated(this.getCapabilityRequest()?.manifests);
|
|
1574
1672
|
const address = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
|
|
1575
1673
|
const chainId = await this.signer.getChainId();
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
this.
|
|
1674
|
+
await this.refreshNamedKeyFeatureForSignIn(address, chainId);
|
|
1675
|
+
const keyId = `openkey-session-${Date.now()}-${++this.preparedSessionCounter}`;
|
|
1676
|
+
this.sessionManager.createSessionKey(keyId);
|
|
1579
1677
|
const jwkString = this.sessionManager.jwk(keyId);
|
|
1580
1678
|
if (!jwkString) {
|
|
1581
1679
|
throw new Error("Failed to create session key");
|
|
@@ -1585,7 +1683,7 @@ var NodeUserAuthorization = class {
|
|
|
1585
1683
|
const spaceId = capabilityPlan.spaceId;
|
|
1586
1684
|
const now = /* @__PURE__ */ new Date();
|
|
1587
1685
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
1588
|
-
const prepared = this.
|
|
1686
|
+
const prepared = this.prepareSessionWithResources({
|
|
1589
1687
|
abilities: capabilityPlan.abilities,
|
|
1590
1688
|
...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
|
|
1591
1689
|
...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
|
|
@@ -1656,6 +1754,7 @@ var NodeUserAuthorization = class {
|
|
|
1656
1754
|
await this.sessionStorage.save(address, persistedData);
|
|
1657
1755
|
this._session = clientSession;
|
|
1658
1756
|
this._tinyCloudSession = tinyCloudSession;
|
|
1757
|
+
this.activeSessionKeyId = keyId;
|
|
1659
1758
|
this._address = address;
|
|
1660
1759
|
this._chainId = chainId;
|
|
1661
1760
|
await this.refreshNodeInfo();
|
|
@@ -1702,6 +1801,11 @@ var NodeUserAuthorization = class {
|
|
|
1702
1801
|
* @param options Optional overrides for the OpenKey request.
|
|
1703
1802
|
*/
|
|
1704
1803
|
async signInWithOpenKey(authorizeFn, options) {
|
|
1804
|
+
const pending = await this.prepareOpenKeySignIn(options);
|
|
1805
|
+
return this.completeOpenKeySignIn(pending, authorizeFn(pending.request), options);
|
|
1806
|
+
}
|
|
1807
|
+
/** Finish address, host and SIWE preparation before an approval click. */
|
|
1808
|
+
async prepareOpenKeySignIn(options) {
|
|
1705
1809
|
refuseCaveated(this.getCapabilityRequest()?.manifests);
|
|
1706
1810
|
if (options?.host !== void 0) {
|
|
1707
1811
|
const overrideHost = options.host.trim();
|
|
@@ -1713,7 +1817,7 @@ var NodeUserAuthorization = class {
|
|
|
1713
1817
|
const signingAddress = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
|
|
1714
1818
|
const signingChainId = await this.signer.getChainId();
|
|
1715
1819
|
await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
|
|
1716
|
-
const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
|
|
1820
|
+
const { prepared, keyId, jwk, address, chainId } = await this.prepareSessionForSigning();
|
|
1717
1821
|
const presentation = this.buildPresentationEnvelope(options?.reason);
|
|
1718
1822
|
const hostHint = this.primaryTinyCloudHost;
|
|
1719
1823
|
const originalRequest = {
|
|
@@ -1725,12 +1829,32 @@ var NodeUserAuthorization = class {
|
|
|
1725
1829
|
keyId: options?.openkeyKeyId,
|
|
1726
1830
|
presentation
|
|
1727
1831
|
};
|
|
1832
|
+
return {
|
|
1833
|
+
request: originalRequest,
|
|
1834
|
+
prepared,
|
|
1835
|
+
keyId,
|
|
1836
|
+
jwk,
|
|
1837
|
+
address,
|
|
1838
|
+
chainId,
|
|
1839
|
+
generation: this.sessionGeneration,
|
|
1840
|
+
createdAt: Date.now()
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
/** Complete a prepared approval. The caller starts authorization before awaiting this method. */
|
|
1844
|
+
async completeOpenKeySignIn(pending, authorization, options) {
|
|
1845
|
+
if (Date.now() - pending.createdAt > 5 * 6e4) {
|
|
1846
|
+
throw new Error("Prepared OpenKey sign-in expired; prepare again");
|
|
1847
|
+
}
|
|
1848
|
+
if (pending.generation !== this.sessionGeneration) {
|
|
1849
|
+
throw new Error("Prepared OpenKey sign-in expired after sign-out");
|
|
1850
|
+
}
|
|
1851
|
+
const { request: originalRequest, prepared, keyId, jwk } = pending;
|
|
1728
1852
|
let result;
|
|
1729
1853
|
let signed;
|
|
1730
1854
|
let signature;
|
|
1731
1855
|
for (let attempt = 0; ; ) {
|
|
1732
1856
|
try {
|
|
1733
|
-
result ?? (result = await
|
|
1857
|
+
result ?? (result = await authorization);
|
|
1734
1858
|
signed = await this.verifyOpenKeyResult(result, prepared);
|
|
1735
1859
|
signature = result.signature;
|
|
1736
1860
|
break;
|
|
@@ -2151,8 +2275,52 @@ var NodeUserAuthorization = class {
|
|
|
2151
2275
|
}
|
|
2152
2276
|
};
|
|
2153
2277
|
|
|
2278
|
+
// src/authorization/openKeyBridge.ts
|
|
2279
|
+
function wireOpenKeyAuthorize(openkey, opts) {
|
|
2280
|
+
return async (input) => {
|
|
2281
|
+
const result = await openkey.authorizeTinyCloud({
|
|
2282
|
+
protocolVersion: 1,
|
|
2283
|
+
siwe: input.siwe,
|
|
2284
|
+
keyId: input.keyId,
|
|
2285
|
+
jwk: input.jwk,
|
|
2286
|
+
host: input.host,
|
|
2287
|
+
// Forward the presentation envelope verbatim — the OpenKey SDK
|
|
2288
|
+
// validates and size-bounds it before use.
|
|
2289
|
+
presentation: input.presentation
|
|
2290
|
+
}, opts);
|
|
2291
|
+
if (result.protocolVersion !== 1) {
|
|
2292
|
+
throw new Error(
|
|
2293
|
+
`wireOpenKeyAuthorize: OpenKey returned unsupported protocolVersion ${result.protocolVersion}`
|
|
2294
|
+
);
|
|
2295
|
+
}
|
|
2296
|
+
if (typeof result.signedMessage !== "string" || !result.signedMessage) {
|
|
2297
|
+
throw new Error(
|
|
2298
|
+
"wireOpenKeyAuthorize: OpenKey returned no signedMessage \u2014 cannot complete a TinyCloud session"
|
|
2299
|
+
);
|
|
2300
|
+
}
|
|
2301
|
+
if (!Array.isArray(result.selectedActionKeys)) {
|
|
2302
|
+
throw new Error(
|
|
2303
|
+
"wireOpenKeyAuthorize: OpenKey returned no selectedActionKeys"
|
|
2304
|
+
);
|
|
2305
|
+
}
|
|
2306
|
+
if (!Array.isArray(result.permissions)) {
|
|
2307
|
+
throw new Error(
|
|
2308
|
+
"wireOpenKeyAuthorize: OpenKey returned no permissions"
|
|
2309
|
+
);
|
|
2310
|
+
}
|
|
2311
|
+
return {
|
|
2312
|
+
protocolVersion: 1,
|
|
2313
|
+
address: result.address,
|
|
2314
|
+
signature: result.signature,
|
|
2315
|
+
signedMessage: result.signedMessage,
|
|
2316
|
+
selectedActionKeys: result.selectedActionKeys,
|
|
2317
|
+
permissions: result.permissions
|
|
2318
|
+
};
|
|
2319
|
+
};
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2154
2322
|
// src/recordingServiceContext.ts
|
|
2155
|
-
var
|
|
2323
|
+
var import_sdk_services3 = require("@tinycloud/sdk-services");
|
|
2156
2324
|
var import_requestLog = require("@tinycloud/sdk-services/telemetry/requestLog");
|
|
2157
2325
|
|
|
2158
2326
|
// src/recordingRegistry.ts
|
|
@@ -2197,9 +2365,9 @@ function replicationEvent(sample, op) {
|
|
|
2197
2365
|
}
|
|
2198
2366
|
function createServiceContext(config) {
|
|
2199
2367
|
const { requestSink, ...base } = config;
|
|
2200
|
-
return requestSink === void 0 ? new
|
|
2368
|
+
return requestSink === void 0 ? new import_sdk_services3.ServiceContext(base) : new RecordingServiceContext(base, requestSink);
|
|
2201
2369
|
}
|
|
2202
|
-
var RecordingServiceContext = class extends
|
|
2370
|
+
var RecordingServiceContext = class extends import_sdk_services3.ServiceContext {
|
|
2203
2371
|
constructor(config, sink) {
|
|
2204
2372
|
const pending = {};
|
|
2205
2373
|
super({
|
|
@@ -2792,9 +2960,11 @@ function deserializeDelegation(data) {
|
|
|
2792
2960
|
|
|
2793
2961
|
// src/TinyCloudNode.ts
|
|
2794
2962
|
var import_siwe2 = require("siwe");
|
|
2963
|
+
var import_share_envelope = require("@tinycloud/share-envelope");
|
|
2795
2964
|
var import_sdk_core11 = require("@tinycloud/sdk-core");
|
|
2796
|
-
var
|
|
2965
|
+
var import_sdk_services4 = require("@tinycloud/sdk-services");
|
|
2797
2966
|
var import_requestLog2 = require("@tinycloud/sdk-services/telemetry/requestLog");
|
|
2967
|
+
var import_resource2 = require("@tinycloud/sdk-services/encryption/resource");
|
|
2798
2968
|
|
|
2799
2969
|
// src/account/AccountService.ts
|
|
2800
2970
|
var import_sdk_core7 = require("@tinycloud/sdk-core");
|
|
@@ -3271,6 +3441,7 @@ var ROOT_DELEGATION_ACTIONS = [
|
|
|
3271
3441
|
import_sdk_core11.DUCKDB.ALL
|
|
3272
3442
|
];
|
|
3273
3443
|
var DEFAULT_SESSION_EXPIRATION_MS = import_sdk_core11.EXPIRY.SESSION_MS;
|
|
3444
|
+
var OWNER_REVOCATION_WINDOW_MS = 10 * 6e4;
|
|
3274
3445
|
function unifiedRootAttenuation(capabilities) {
|
|
3275
3446
|
const attenuation = {};
|
|
3276
3447
|
for (const capability of capabilities) {
|
|
@@ -3768,6 +3939,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3768
3939
|
constructor(config = {}) {
|
|
3769
3940
|
this.signer = null;
|
|
3770
3941
|
this.auth = null;
|
|
3942
|
+
this.consumedOpenKeyPendings = /* @__PURE__ */ new WeakSet();
|
|
3771
3943
|
this.tc = null;
|
|
3772
3944
|
this._chainId = 1;
|
|
3773
3945
|
this.replicaPurgeFailedHandlers = /* @__PURE__ */ new Set();
|
|
@@ -3802,6 +3974,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3802
3974
|
return void 0;
|
|
3803
3975
|
}
|
|
3804
3976
|
};
|
|
3977
|
+
this._keysUnavailable = [];
|
|
3805
3978
|
this._baseVaults = /* @__PURE__ */ new Map();
|
|
3806
3979
|
this._baseSecrets = /* @__PURE__ */ new Map();
|
|
3807
3980
|
this._secrets = /* @__PURE__ */ new Map();
|
|
@@ -4629,6 +4802,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4629
4802
|
this._hooks = void 0;
|
|
4630
4803
|
this._vault = void 0;
|
|
4631
4804
|
this._encryption = void 0;
|
|
4805
|
+
this._namedKeyClient = void 0;
|
|
4806
|
+
this._keysUnavailable = [];
|
|
4632
4807
|
this._baseVaults.clear();
|
|
4633
4808
|
this._baseSecrets.clear();
|
|
4634
4809
|
this._secrets.clear();
|
|
@@ -4705,6 +4880,37 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4705
4880
|
}
|
|
4706
4881
|
await this.signInWith(() => this.auth.signInWithOpenKey(authorizeFn, options));
|
|
4707
4882
|
}
|
|
4883
|
+
/** Prepare the OpenKey request before the approval click. */
|
|
4884
|
+
async prepareOpenKeySignIn() {
|
|
4885
|
+
if (!this.signer || !this.tc || !this.auth) {
|
|
4886
|
+
throw new Error("Cannot prepare OpenKey sign-in in session-only mode. Provide a signer in config.");
|
|
4887
|
+
}
|
|
4888
|
+
await this.signOutInFlight;
|
|
4889
|
+
await this.accountRegistryTail;
|
|
4890
|
+
await this.wasmBindings.ensureInitialized?.();
|
|
4891
|
+
return this.auth.prepareOpenKeySignIn();
|
|
4892
|
+
}
|
|
4893
|
+
/** Start OpenKey authorization synchronously, then complete normal session setup. */
|
|
4894
|
+
signInWithPreparedOpenKey(pending, authorizeFn) {
|
|
4895
|
+
if (!this.signer || !this.tc || !this.auth || this.signOutInFlight) {
|
|
4896
|
+
throw new Error("Prepared OpenKey sign-in is unavailable");
|
|
4897
|
+
}
|
|
4898
|
+
if (this.consumedOpenKeyPendings.has(pending)) {
|
|
4899
|
+
throw new Error("Prepared OpenKey sign-in was already used");
|
|
4900
|
+
}
|
|
4901
|
+
if (Date.now() - pending.createdAt > 5 * 6e4) {
|
|
4902
|
+
throw new Error("Prepared OpenKey sign-in expired; prepare again");
|
|
4903
|
+
}
|
|
4904
|
+
this.consumedOpenKeyPendings.add(pending);
|
|
4905
|
+
const authorization = authorizeFn(pending.request);
|
|
4906
|
+
void authorization.catch(() => void 0);
|
|
4907
|
+
return this.signInWith(() => {
|
|
4908
|
+
if (this._address !== pending.address || this._chainId !== pending.chainId) {
|
|
4909
|
+
throw new Error("OpenKey account changed after sign-in preparation");
|
|
4910
|
+
}
|
|
4911
|
+
return this.auth.completeOpenKeySignIn(pending, authorization);
|
|
4912
|
+
});
|
|
4913
|
+
}
|
|
4708
4914
|
async signInWith(performSignIn) {
|
|
4709
4915
|
refuseCaveated(this.auth?.capabilityRequest?.manifests);
|
|
4710
4916
|
const epoch = this.sessionEpoch;
|
|
@@ -4751,6 +4957,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4751
4957
|
this._hooks = void 0;
|
|
4752
4958
|
this._vault = void 0;
|
|
4753
4959
|
this._encryption = void 0;
|
|
4960
|
+
this._namedKeyClient = void 0;
|
|
4961
|
+
this._keysUnavailable = [];
|
|
4754
4962
|
this._baseVaults.clear();
|
|
4755
4963
|
this._baseSecrets.clear();
|
|
4756
4964
|
this._secrets.clear();
|
|
@@ -4803,6 +5011,26 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4803
5011
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4804
5012
|
await this.ensureRequestedEncryptionNetworks();
|
|
4805
5013
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
5014
|
+
this._keysUnavailable = this.auth?.unavailableKeyPaths ?? [];
|
|
5015
|
+
if (this._keysUnavailable.length > 0) {
|
|
5016
|
+
this.notificationHandler.warning(`Named keys unavailable: ${this._keysUnavailable.join(", ")}`);
|
|
5017
|
+
}
|
|
5018
|
+
if (this.nodeFeatures.includes("encryption-named-keys-v1")) {
|
|
5019
|
+
for (const manifest of this.auth?.capabilityRequest?.manifests ?? []) {
|
|
5020
|
+
for (const declaration of manifest.keys ?? []) {
|
|
5021
|
+
if ("path" in declaration && declaration.abilities.includes("key.create") && !this._keysUnavailable.includes(declaration.path)) {
|
|
5022
|
+
try {
|
|
5023
|
+
await this.keys.ensureKey(declaration.path);
|
|
5024
|
+
} catch (error) {
|
|
5025
|
+
this._keysUnavailable.push(declaration.path);
|
|
5026
|
+
const code = error && typeof error === "object" && "code" in error && typeof error.code === "string" && /^[A-Z_]+$/.test(error.code) ? error.code : "UNKNOWN";
|
|
5027
|
+
this.notificationHandler.warning(`Named key unavailable: ${declaration.path} (${code})`);
|
|
5028
|
+
}
|
|
5029
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
}
|
|
5033
|
+
}
|
|
4806
5034
|
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
4807
5035
|
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(import_sdk_core11.SECRETS_SPACE));
|
|
4808
5036
|
}
|
|
@@ -5379,7 +5607,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5379
5607
|
if (!this.currentSessionCoversAccountRegistry()) {
|
|
5380
5608
|
if (!_TinyCloudNode.accountRegistrySkipLogged) {
|
|
5381
5609
|
_TinyCloudNode.accountRegistrySkipLogged = true;
|
|
5382
|
-
|
|
5610
|
+
import_sdk_services4.tinyCloudDebugLogger.log("registry.skip");
|
|
5383
5611
|
}
|
|
5384
5612
|
return;
|
|
5385
5613
|
}
|
|
@@ -5590,7 +5818,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5590
5818
|
const networkIds = /* @__PURE__ */ new Set();
|
|
5591
5819
|
for (const resource of request.resources) {
|
|
5592
5820
|
if (resource.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && resource.path.startsWith("urn:tinycloud:encryption:") && resource.actions.includes(DECRYPT_ACTION2)) {
|
|
5593
|
-
|
|
5821
|
+
const parsed = resource.path.includes("/") ? (0, import_resource2.parseEncryptionResource)(resource.path) : { ...(0, import_sdk_core11.parseNetworkId)(resource.path), kind: "network" };
|
|
5822
|
+
if (parsed.kind === "network") networkIds.add(resource.path);
|
|
5594
5823
|
}
|
|
5595
5824
|
}
|
|
5596
5825
|
return [...networkIds];
|
|
@@ -6140,6 +6369,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6140
6369
|
this._hooks = stagedGraph.hooks;
|
|
6141
6370
|
this._vault = stagedGraph.vault;
|
|
6142
6371
|
this._encryption = stagedGraph.encryption;
|
|
6372
|
+
this._namedKeyClient = void 0;
|
|
6373
|
+
this._keysUnavailable = [];
|
|
6143
6374
|
this._capabilityRegistry = stagedGraph.capabilityRegistry;
|
|
6144
6375
|
this._keyProvider = stagedGraph.keyProvider;
|
|
6145
6376
|
this._sharingService = stagedGraph.sharingService;
|
|
@@ -6321,6 +6552,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6321
6552
|
invoke: graph.invoke,
|
|
6322
6553
|
invokeAny: graph.invokeAny,
|
|
6323
6554
|
signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
|
|
6555
|
+
sessionInvocationSigner: this.sessionInvocationSignerFor(input.serviceSession),
|
|
6324
6556
|
fetch: graph.fetch
|
|
6325
6557
|
});
|
|
6326
6558
|
const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
|
|
@@ -6536,6 +6768,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6536
6768
|
if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
|
|
6537
6769
|
return signBytesWithJwk(bytes, session.jwk);
|
|
6538
6770
|
}
|
|
6771
|
+
/**
|
|
6772
|
+
* Signs proofless invocations with `session`'s own did:key, for the node's
|
|
6773
|
+
* issued-delegation list and revocation by the delegator. The audience is
|
|
6774
|
+
* this Node's DID; each invocation lives 60 seconds.
|
|
6775
|
+
*/
|
|
6776
|
+
sessionInvocationSignerFor(session) {
|
|
6777
|
+
return {
|
|
6778
|
+
did: () => session.verificationMethod.split("#", 1)[0],
|
|
6779
|
+
sign: async (attenuation) => {
|
|
6780
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
6781
|
+
const invocation = await (0, import_sdk_core11.signCompactUcanAuthorization)({
|
|
6782
|
+
issuerDid: session.verificationMethod.split("#", 1)[0],
|
|
6783
|
+
audienceDid: await this.fetchNodeId(),
|
|
6784
|
+
attenuation,
|
|
6785
|
+
facts: [{}],
|
|
6786
|
+
proofs: [],
|
|
6787
|
+
notBefore: now,
|
|
6788
|
+
expiresAt: now + 60,
|
|
6789
|
+
nonce: `urn:uuid:${crypto.randomUUID()}`,
|
|
6790
|
+
sign: (bytes) => signBytesWithJwk(bytes, session.jwk)
|
|
6791
|
+
});
|
|
6792
|
+
return invocation.authorization;
|
|
6793
|
+
}
|
|
6794
|
+
};
|
|
6795
|
+
}
|
|
6539
6796
|
/** Author a proofless Policy/v3 owner root with the authenticated holder key. */
|
|
6540
6797
|
async createUnifiedOwnerRoot(input) {
|
|
6541
6798
|
const ownerDid = this.credentialHolderDid;
|
|
@@ -7049,7 +7306,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7049
7306
|
);
|
|
7050
7307
|
graph.assertActive();
|
|
7051
7308
|
if (!response.ok) {
|
|
7052
|
-
const permissionHint = response.status === 401 || response.status === 403 ? (0,
|
|
7309
|
+
const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services4.parsePermissionHint)({
|
|
7053
7310
|
service: "tinycloud.encryption",
|
|
7054
7311
|
path: networkId,
|
|
7055
7312
|
actions: ["tinycloud.encryption/decrypt"]
|
|
@@ -7070,7 +7327,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7070
7327
|
graph.assertActive();
|
|
7071
7328
|
const signed = await this.signRawNetworkAuthorization({
|
|
7072
7329
|
targetNode: input.targetNode,
|
|
7073
|
-
networkId: input.networkId
|
|
7330
|
+
networkId: input.body.keyPath === void 0 ? input.networkId : `${input.networkId}/${input.body.keyPath}`,
|
|
7074
7331
|
action: DECRYPT_ACTION2,
|
|
7075
7332
|
facts: input.facts
|
|
7076
7333
|
}, { graph, session });
|
|
@@ -7243,6 +7500,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7243
7500
|
invoke: graph.invoke,
|
|
7244
7501
|
invokeAny: graph.invokeAny,
|
|
7245
7502
|
signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
|
|
7503
|
+
sessionInvocationSigner: this.sessionInvocationSignerFor(serviceSession),
|
|
7246
7504
|
fetch: graph.fetch
|
|
7247
7505
|
});
|
|
7248
7506
|
this._spaceService = new import_sdk_core11.SpaceService({
|
|
@@ -7493,7 +7751,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7493
7751
|
* Sign a wallet (CACAO) revocation of the delegation `cid` for the node's
|
|
7494
7752
|
* `POST /revoke`, and return its Authorization header value. The node
|
|
7495
7753
|
* accepts it when the owner delegated `cid` or owns a space its abilities
|
|
7496
|
-
* target, whichever key issued it. Valid for
|
|
7754
|
+
* target, whichever key issued it. Valid for 10 minutes. Requires the
|
|
7497
7755
|
* owner wallet signer.
|
|
7498
7756
|
*/
|
|
7499
7757
|
async signOwnerRevocation(cid) {
|
|
@@ -7509,7 +7767,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7509
7767
|
chainId: session.chainId,
|
|
7510
7768
|
nonce: (0, import_siwe2.generateNonce)(),
|
|
7511
7769
|
issuedAt: issuedAt.toISOString(),
|
|
7512
|
-
expirationTime: new Date(issuedAt.getTime() +
|
|
7770
|
+
expirationTime: new Date(issuedAt.getTime() + OWNER_REVOCATION_WINDOW_MS).toISOString()
|
|
7513
7771
|
}).prepareMessage();
|
|
7514
7772
|
const signature = await this.signer.signMessage(siwe);
|
|
7515
7773
|
return this.wasmBindings.siweToDelegationHeaders({ siwe, signature }).Authorization;
|
|
@@ -7736,6 +7994,40 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7736
7994
|
get encryption() {
|
|
7737
7995
|
return this.getEncryptionService();
|
|
7738
7996
|
}
|
|
7997
|
+
/** Named keys bound to the current session. */
|
|
7998
|
+
get keys() {
|
|
7999
|
+
return new Proxy({}, {
|
|
8000
|
+
get: (_target, property) => {
|
|
8001
|
+
if (property === "refreshNodeInfo") {
|
|
8002
|
+
return () => {
|
|
8003
|
+
void this._namedKeyClient?.then((client) => client.refreshNodeInfo());
|
|
8004
|
+
};
|
|
8005
|
+
}
|
|
8006
|
+
if (typeof property !== "string" || ![
|
|
8007
|
+
"getPublicKey",
|
|
8008
|
+
"describeKey",
|
|
8009
|
+
"createKey",
|
|
8010
|
+
"blockKey",
|
|
8011
|
+
"unblockKey",
|
|
8012
|
+
"ensureKey",
|
|
8013
|
+
"encrypt",
|
|
8014
|
+
"decrypt",
|
|
8015
|
+
"decryptMany"
|
|
8016
|
+
].includes(property)) return void 0;
|
|
8017
|
+
return (...args) => {
|
|
8018
|
+
this._namedKeyClient ?? (this._namedKeyClient = import("./encryption-keys.cjs").then(({ createNamedKeyClient }) => createNamedKeyClient(this)));
|
|
8019
|
+
return this._namedKeyClient.then((client) => {
|
|
8020
|
+
const method = client[property];
|
|
8021
|
+
return method.apply(client, args);
|
|
8022
|
+
});
|
|
8023
|
+
};
|
|
8024
|
+
}
|
|
8025
|
+
});
|
|
8026
|
+
}
|
|
8027
|
+
/** Manifest key paths unavailable during the latest `signIn()` attempt. */
|
|
8028
|
+
get keysUnavailable() {
|
|
8029
|
+
return this._keysUnavailable;
|
|
8030
|
+
}
|
|
7739
8031
|
async getEncryptionNetwork(nameOrNetworkId = this.getDefaultEncryptionNetworkId()) {
|
|
7740
8032
|
const networkId = nameOrNetworkId.startsWith("urn:tinycloud:encryption:") ? nameOrNetworkId : this.getDefaultEncryptionNetworkId(nameOrNetworkId);
|
|
7741
8033
|
return this.fetchEncryptionNetworkAt(
|
|
@@ -7863,7 +8155,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7863
8155
|
);
|
|
7864
8156
|
if (result.status !== "ok") {
|
|
7865
8157
|
if (result.status === "permission_required") {
|
|
7866
|
-
const hint = (0,
|
|
8158
|
+
const hint = (0, import_sdk_services4.parsePermissionHint)(result.hint);
|
|
7867
8159
|
if (hint === void 0) return { status: "read_failed" };
|
|
7868
8160
|
return {
|
|
7869
8161
|
status: "permission_required",
|
|
@@ -7992,7 +8284,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7992
8284
|
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
7993
8285
|
return false;
|
|
7994
8286
|
}
|
|
7995
|
-
const expanded =
|
|
8287
|
+
const expanded = (0, import_sdk_core11.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core11.pkhDid)(session.address, session.chainId));
|
|
7996
8288
|
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
7997
8289
|
return true;
|
|
7998
8290
|
}
|
|
@@ -8012,7 +8304,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8012
8304
|
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
8013
8305
|
return [];
|
|
8014
8306
|
}
|
|
8015
|
-
const expanded =
|
|
8307
|
+
const expanded = (0, import_sdk_core11.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core11.pkhDid)(session.address, session.chainId));
|
|
8016
8308
|
return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
|
|
8017
8309
|
(grant) => grant.delegation
|
|
8018
8310
|
);
|
|
@@ -8187,7 +8479,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8187
8479
|
throw new import_sdk_core11.SessionExpiredError(sessionExpiry);
|
|
8188
8480
|
}
|
|
8189
8481
|
}
|
|
8190
|
-
const expanded =
|
|
8482
|
+
const expanded = (0, import_sdk_core11.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core11.pkhDid)(session.address, session.chainId));
|
|
8483
|
+
const bindsShareKey = expanded.some((entry) => entry.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && entry.actions.includes("tinycloud.encryption/key.create"));
|
|
8484
|
+
const captured = bindsShareKey ? { ...session, jwk: { ...options?.expectedSessionKey ?? session.jwk } } : session;
|
|
8485
|
+
const assertCapturedKey = bindsShareKey ? () => {
|
|
8486
|
+
const live = session.jwk;
|
|
8487
|
+
const key = captured.jwk;
|
|
8488
|
+
if (this.currentTinyCloudSession() !== session || session.verificationMethod !== captured.verificationMethod || session.delegationCid !== captured.delegationCid || session.spaceId !== captured.spaceId || session.address !== captured.address || session.chainId !== captured.chainId || live?.kty !== key.kty || live?.crv !== key.crv || live?.x !== key.x || live?.y !== key.y || live?.d !== key.d) {
|
|
8489
|
+
throw new Error("Runtime permission request cancelled because the session key changed.");
|
|
8490
|
+
}
|
|
8491
|
+
} : void 0;
|
|
8492
|
+
const sessionKeyDid = bindsShareKey ? this.sessionDid : void 0;
|
|
8493
|
+
if (bindsShareKey) {
|
|
8494
|
+
const key = captured.jwk;
|
|
8495
|
+
if (key.kty !== "OKP" || key.crv !== "Ed25519" || typeof key.x !== "string") {
|
|
8496
|
+
throw new Error("Runtime permission session key does not match its signed identity.");
|
|
8497
|
+
}
|
|
8498
|
+
const keyDid = (0, import_share_envelope.didKeyFromEd25519PublicKey)(base64UrlDecode(key.x));
|
|
8499
|
+
if (!didPrincipalMatches2(keyDid, sessionKeyDid) || !didPrincipalMatches2(keyDid, captured.verificationMethod) || !didPrincipalMatches2(keyDid, new import_siwe2.SiweMessage(session.siwe).uri)) {
|
|
8500
|
+
throw new Error("Runtime permission session key does not match its signed identity.");
|
|
8501
|
+
}
|
|
8502
|
+
assertCapturedKey();
|
|
8503
|
+
}
|
|
8191
8504
|
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
8192
8505
|
return [];
|
|
8193
8506
|
}
|
|
@@ -8237,13 +8550,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8237
8550
|
return this.wasmBindings.prepareSession({
|
|
8238
8551
|
abilities,
|
|
8239
8552
|
...rawForDelegation.length > 0 ? { rawAbilities: this.permissionsToRawAbilities(rawForDelegation) } : {},
|
|
8240
|
-
address: this.wasmBindings.ensureEip55(
|
|
8241
|
-
chainId:
|
|
8553
|
+
address: this.wasmBindings.ensureEip55(captured.address),
|
|
8554
|
+
chainId: captured.chainId,
|
|
8242
8555
|
domain: this.siweDomain,
|
|
8243
8556
|
issuedAt: now.toISOString(),
|
|
8244
8557
|
expirationTime: expiresAt.toISOString(),
|
|
8245
8558
|
spaceId,
|
|
8246
|
-
jwk:
|
|
8559
|
+
jwk: captured.jwk
|
|
8247
8560
|
});
|
|
8248
8561
|
} catch (error) {
|
|
8249
8562
|
if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && /invalid ReCap resource URI/i.test(error instanceof Error ? error.message : String(error))) {
|
|
@@ -8255,8 +8568,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8255
8568
|
throw error;
|
|
8256
8569
|
}
|
|
8257
8570
|
})();
|
|
8571
|
+
if (bindsShareKey && !didPrincipalMatches2(new import_siwe2.SiweMessage(prepared.siwe).uri, sessionKeyDid)) {
|
|
8572
|
+
throw new Error("Prepared runtime permission targets a different session key.");
|
|
8573
|
+
}
|
|
8574
|
+
assertCapturedKey?.();
|
|
8258
8575
|
const signature = await this.signer.signMessage(prepared.siwe);
|
|
8259
8576
|
graph.assertActive();
|
|
8577
|
+
assertCapturedKey?.();
|
|
8260
8578
|
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
8261
8579
|
...prepared,
|
|
8262
8580
|
signature
|
|
@@ -8285,18 +8603,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8285
8603
|
delegatedSession,
|
|
8286
8604
|
delegatedEntries,
|
|
8287
8605
|
spaceId,
|
|
8288
|
-
|
|
8606
|
+
captured,
|
|
8289
8607
|
expiresAt,
|
|
8290
8608
|
{ siwe: prepared.siwe, signature }
|
|
8291
8609
|
);
|
|
8292
8610
|
graph.assertActive();
|
|
8611
|
+
assertCapturedKey?.();
|
|
8293
8612
|
this.runtimePermissionGrants.push({
|
|
8294
8613
|
session: {
|
|
8295
8614
|
delegationHeader: delegatedSession.delegationHeader,
|
|
8296
8615
|
delegationCid: delegatedSession.delegationCid,
|
|
8297
8616
|
spaceId,
|
|
8298
|
-
verificationMethod:
|
|
8299
|
-
jwk:
|
|
8617
|
+
verificationMethod: captured.verificationMethod,
|
|
8618
|
+
jwk: captured.jwk
|
|
8300
8619
|
},
|
|
8301
8620
|
delegation,
|
|
8302
8621
|
operations: this.permissionOperations(delegatedEntries, spaceId),
|
|
@@ -8625,7 +8944,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8625
8944
|
"delegateTo requires a non-empty permissions array"
|
|
8626
8945
|
);
|
|
8627
8946
|
}
|
|
8628
|
-
const expandedEntries =
|
|
8947
|
+
const expandedEntries = (0, import_sdk_core11.expandDelegationPermissionEntries)(permissions);
|
|
8948
|
+
const namedKeyEntries = expandedEntries.filter((entry) => entry.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && entry.path.includes("/"));
|
|
8949
|
+
if (namedKeyEntries.length > 0) {
|
|
8950
|
+
if (expandedEntries.some((entry) => entry.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && !entry.path.includes("/"))) {
|
|
8951
|
+
throw new import_sdk_core11.ManifestValidationError("named-key delegation cannot include bare-network permissions");
|
|
8952
|
+
}
|
|
8953
|
+
if (options?.forceWalletSign) {
|
|
8954
|
+
throw new import_sdk_core11.ManifestValidationError("named-key delegation requires a signed session grant");
|
|
8955
|
+
}
|
|
8956
|
+
const granted = this.projectSignedRecapCapabilities(session.siwe);
|
|
8957
|
+
const { subset, missing } = this.signedCapabilitySubset(namedKeyEntries, granted);
|
|
8958
|
+
if (!subset) throw new import_sdk_core11.PermissionNotInManifestError(missing, granted);
|
|
8959
|
+
}
|
|
8629
8960
|
const now = /* @__PURE__ */ new Date();
|
|
8630
8961
|
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
8631
8962
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
@@ -10041,6 +10372,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10041
10372
|
PermissionNotInManifestError,
|
|
10042
10373
|
PrefixedKVService,
|
|
10043
10374
|
ProtocolMismatchError,
|
|
10375
|
+
RuntimeDelegationRejectedError,
|
|
10044
10376
|
SECRET_NAME_RE,
|
|
10045
10377
|
SQLAction,
|
|
10046
10378
|
SQLService,
|
|
@@ -10063,6 +10395,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10063
10395
|
VersionCheckError,
|
|
10064
10396
|
WasmKeyProvider,
|
|
10065
10397
|
activateCompactRuntimeDelegation,
|
|
10398
|
+
activateValidatedRuntimeDelegation,
|
|
10066
10399
|
addressStorageKey,
|
|
10067
10400
|
buildSpaceUri,
|
|
10068
10401
|
canonicalizeAddress,
|
|
@@ -10092,6 +10425,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10092
10425
|
getNodeReplicationLoaders,
|
|
10093
10426
|
getTinyCloudDebugLogs,
|
|
10094
10427
|
installTinyCloudDebugGlobals,
|
|
10428
|
+
isAppKeyHostBound,
|
|
10095
10429
|
isCapabilitySubset,
|
|
10096
10430
|
isEvmAddress,
|
|
10097
10431
|
loadManifest,
|
|
@@ -10113,6 +10447,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10113
10447
|
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
10114
10448
|
serializeDelegation,
|
|
10115
10449
|
tinyCloudDebugLogger,
|
|
10116
|
-
validateManifest
|
|
10450
|
+
validateManifest,
|
|
10451
|
+
wireOpenKeyAuthorize
|
|
10117
10452
|
});
|
|
10118
10453
|
//# sourceMappingURL=core.cjs.map
|