@tinycloud/node-sdk 3.8.0-beta.9 → 3.8.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/README.md +6 -0
- package/dist/{TinyCloudNode-C0LgPzzJ.d.cts → TinyCloudNode-BhWBbCay.d.cts} +50 -5
- package/dist/{TinyCloudNode-jPL2UqH5.d.ts → TinyCloudNode-BjJJIifr.d.ts} +50 -5
- 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-DvHTgPC4.d.ts → authority-BzqKNzOr.d.ts} +1 -1
- package/dist/{authority-Dkhr6n-f.d.cts → authority-WCJA3phs.d.cts} +1 -1
- package/dist/core.cjs +265 -31
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +4 -4
- package/dist/core.d.ts +4 -4
- package/dist/core.js +266 -32
- 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 +215 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +220 -33
- package/dist/index.js.map +1 -1
- package/dist/replication/authority.d.cts +3 -3
- package/dist/replication/authority.d.ts +3 -3
- 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");
|
|
@@ -371,6 +375,18 @@ function appKeyHostBinding(domain, appId) {
|
|
|
371
375
|
const reversed = labels.reverse().join(".");
|
|
372
376
|
return appId === reversed || appId.startsWith(`${reversed}.`);
|
|
373
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
|
+
}
|
|
374
390
|
|
|
375
391
|
// src/replication/authority-sign-in.ts
|
|
376
392
|
var import_sdk_core2 = require("@tinycloud/sdk-core");
|
|
@@ -502,6 +518,7 @@ function cloneAbilitiesMap(actions) {
|
|
|
502
518
|
var NodeUserAuthorization = class {
|
|
503
519
|
constructor(config) {
|
|
504
520
|
this.activeSessionKeyId = "default";
|
|
521
|
+
this.preparedSessionCounter = 0;
|
|
505
522
|
/** Incremented by resetSession; a sign-in started earlier publishes nothing. */
|
|
506
523
|
this.sessionGeneration = 0;
|
|
507
524
|
/**
|
|
@@ -1084,7 +1101,8 @@ var NodeUserAuthorization = class {
|
|
|
1084
1101
|
return true;
|
|
1085
1102
|
}
|
|
1086
1103
|
const parsed = entry.path.includes("/") ? (0, import_resource.parseEncryptionResource)(entry.path) : { ...(0, import_sdk_services2.parseNetworkId)(entry.path), kind: "network" };
|
|
1087
|
-
|
|
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) {
|
|
1088
1106
|
throw new import_sdk_core5.ManifestValidationError("named keys go in manifest.keys");
|
|
1089
1107
|
}
|
|
1090
1108
|
for (const action of entry.actions) {
|
|
@@ -1127,8 +1145,7 @@ var NodeUserAuthorization = class {
|
|
|
1127
1145
|
/**
|
|
1128
1146
|
* Build SIWE overrides from the top-level nonce and siweConfig.
|
|
1129
1147
|
* - Top-level `nonce` is seeded first so `siweConfig.nonce` wins if both are set.
|
|
1130
|
-
* -
|
|
1131
|
-
* - resources are appended to the default resources
|
|
1148
|
+
* - resources are inserted after WASM preparation, before the final ReCap
|
|
1132
1149
|
* - uri triggers a warning (overwriting delegation target)
|
|
1133
1150
|
* - all other fields override directly
|
|
1134
1151
|
* - per-call nonce overrides siweConfig.nonce when provided
|
|
@@ -1146,9 +1163,6 @@ var NodeUserAuthorization = class {
|
|
|
1146
1163
|
if (statement) {
|
|
1147
1164
|
overrides.statement = this.statement ? `${statement} ${this.statement}` : statement;
|
|
1148
1165
|
}
|
|
1149
|
-
if (resources && resources.length > 0) {
|
|
1150
|
-
overrides.resources = resources;
|
|
1151
|
-
}
|
|
1152
1166
|
if (uri) {
|
|
1153
1167
|
console.warn(
|
|
1154
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."
|
|
@@ -1160,6 +1174,29 @@ var NodeUserAuthorization = class {
|
|
|
1160
1174
|
}
|
|
1161
1175
|
return overrides;
|
|
1162
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
|
+
}
|
|
1163
1200
|
/**
|
|
1164
1201
|
* Add an extension to the authorization flow.
|
|
1165
1202
|
*/
|
|
@@ -1407,7 +1444,7 @@ var NodeUserAuthorization = class {
|
|
|
1407
1444
|
spaceAbilities[spaceId] = (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)(resources);
|
|
1408
1445
|
}
|
|
1409
1446
|
const abilities = spaceAbilities[options.spaceId] ?? (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)([]);
|
|
1410
|
-
const prepared = this.
|
|
1447
|
+
const prepared = this.prepareSessionWithResources({
|
|
1411
1448
|
abilities,
|
|
1412
1449
|
spaceAbilities,
|
|
1413
1450
|
...options.rawAbilities !== void 0 ? { rawAbilities: options.rawAbilities } : {},
|
|
@@ -1488,8 +1525,8 @@ var NodeUserAuthorization = class {
|
|
|
1488
1525
|
this.assertSignInCurrent(generation);
|
|
1489
1526
|
await this.refreshNamedKeyFeatureForSignIn(address, chainId);
|
|
1490
1527
|
this.assertSignInCurrent(generation);
|
|
1491
|
-
const keyId = `session-${Date.now()}`;
|
|
1492
|
-
this.sessionManager.
|
|
1528
|
+
const keyId = `session-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
1529
|
+
this.sessionManager.createSessionKey(keyId);
|
|
1493
1530
|
this.activeSessionKeyId = keyId;
|
|
1494
1531
|
const jwkString = this.sessionManager.jwk(keyId);
|
|
1495
1532
|
if (!jwkString) {
|
|
@@ -1500,7 +1537,7 @@ var NodeUserAuthorization = class {
|
|
|
1500
1537
|
const spaceId = capabilityPlan.spaceId;
|
|
1501
1538
|
const now = /* @__PURE__ */ new Date();
|
|
1502
1539
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
1503
|
-
const prepared = this.
|
|
1540
|
+
const prepared = this.prepareSessionWithResources({
|
|
1504
1541
|
abilities: capabilityPlan.abilities,
|
|
1505
1542
|
...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
|
|
1506
1543
|
...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
|
|
@@ -1635,9 +1672,8 @@ var NodeUserAuthorization = class {
|
|
|
1635
1672
|
const address = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
|
|
1636
1673
|
const chainId = await this.signer.getChainId();
|
|
1637
1674
|
await this.refreshNamedKeyFeatureForSignIn(address, chainId);
|
|
1638
|
-
const keyId = `session-${Date.now()}`;
|
|
1639
|
-
this.sessionManager.
|
|
1640
|
-
this.activeSessionKeyId = keyId;
|
|
1675
|
+
const keyId = `openkey-session-${Date.now()}-${++this.preparedSessionCounter}`;
|
|
1676
|
+
this.sessionManager.createSessionKey(keyId);
|
|
1641
1677
|
const jwkString = this.sessionManager.jwk(keyId);
|
|
1642
1678
|
if (!jwkString) {
|
|
1643
1679
|
throw new Error("Failed to create session key");
|
|
@@ -1647,7 +1683,7 @@ var NodeUserAuthorization = class {
|
|
|
1647
1683
|
const spaceId = capabilityPlan.spaceId;
|
|
1648
1684
|
const now = /* @__PURE__ */ new Date();
|
|
1649
1685
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
1650
|
-
const prepared = this.
|
|
1686
|
+
const prepared = this.prepareSessionWithResources({
|
|
1651
1687
|
abilities: capabilityPlan.abilities,
|
|
1652
1688
|
...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
|
|
1653
1689
|
...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
|
|
@@ -1718,6 +1754,7 @@ var NodeUserAuthorization = class {
|
|
|
1718
1754
|
await this.sessionStorage.save(address, persistedData);
|
|
1719
1755
|
this._session = clientSession;
|
|
1720
1756
|
this._tinyCloudSession = tinyCloudSession;
|
|
1757
|
+
this.activeSessionKeyId = keyId;
|
|
1721
1758
|
this._address = address;
|
|
1722
1759
|
this._chainId = chainId;
|
|
1723
1760
|
await this.refreshNodeInfo();
|
|
@@ -1764,6 +1801,11 @@ var NodeUserAuthorization = class {
|
|
|
1764
1801
|
* @param options Optional overrides for the OpenKey request.
|
|
1765
1802
|
*/
|
|
1766
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) {
|
|
1767
1809
|
refuseCaveated(this.getCapabilityRequest()?.manifests);
|
|
1768
1810
|
if (options?.host !== void 0) {
|
|
1769
1811
|
const overrideHost = options.host.trim();
|
|
@@ -1775,7 +1817,7 @@ var NodeUserAuthorization = class {
|
|
|
1775
1817
|
const signingAddress = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
|
|
1776
1818
|
const signingChainId = await this.signer.getChainId();
|
|
1777
1819
|
await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
|
|
1778
|
-
const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
|
|
1820
|
+
const { prepared, keyId, jwk, address, chainId } = await this.prepareSessionForSigning();
|
|
1779
1821
|
const presentation = this.buildPresentationEnvelope(options?.reason);
|
|
1780
1822
|
const hostHint = this.primaryTinyCloudHost;
|
|
1781
1823
|
const originalRequest = {
|
|
@@ -1787,12 +1829,32 @@ var NodeUserAuthorization = class {
|
|
|
1787
1829
|
keyId: options?.openkeyKeyId,
|
|
1788
1830
|
presentation
|
|
1789
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;
|
|
1790
1852
|
let result;
|
|
1791
1853
|
let signed;
|
|
1792
1854
|
let signature;
|
|
1793
1855
|
for (let attempt = 0; ; ) {
|
|
1794
1856
|
try {
|
|
1795
|
-
result ?? (result = await
|
|
1857
|
+
result ?? (result = await authorization);
|
|
1796
1858
|
signed = await this.verifyOpenKeyResult(result, prepared);
|
|
1797
1859
|
signature = result.signature;
|
|
1798
1860
|
break;
|
|
@@ -2213,6 +2275,50 @@ var NodeUserAuthorization = class {
|
|
|
2213
2275
|
}
|
|
2214
2276
|
};
|
|
2215
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
|
+
|
|
2216
2322
|
// src/recordingServiceContext.ts
|
|
2217
2323
|
var import_sdk_services3 = require("@tinycloud/sdk-services");
|
|
2218
2324
|
var import_requestLog = require("@tinycloud/sdk-services/telemetry/requestLog");
|
|
@@ -2854,6 +2960,7 @@ function deserializeDelegation(data) {
|
|
|
2854
2960
|
|
|
2855
2961
|
// src/TinyCloudNode.ts
|
|
2856
2962
|
var import_siwe2 = require("siwe");
|
|
2963
|
+
var import_share_envelope = require("@tinycloud/share-envelope");
|
|
2857
2964
|
var import_sdk_core11 = require("@tinycloud/sdk-core");
|
|
2858
2965
|
var import_sdk_services4 = require("@tinycloud/sdk-services");
|
|
2859
2966
|
var import_requestLog2 = require("@tinycloud/sdk-services/telemetry/requestLog");
|
|
@@ -3832,6 +3939,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3832
3939
|
constructor(config = {}) {
|
|
3833
3940
|
this.signer = null;
|
|
3834
3941
|
this.auth = null;
|
|
3942
|
+
this.consumedOpenKeyPendings = /* @__PURE__ */ new WeakSet();
|
|
3835
3943
|
this.tc = null;
|
|
3836
3944
|
this._chainId = 1;
|
|
3837
3945
|
this.replicaPurgeFailedHandlers = /* @__PURE__ */ new Set();
|
|
@@ -4772,6 +4880,37 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4772
4880
|
}
|
|
4773
4881
|
await this.signInWith(() => this.auth.signInWithOpenKey(authorizeFn, options));
|
|
4774
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
|
+
}
|
|
4775
4914
|
async signInWith(performSignIn) {
|
|
4776
4915
|
refuseCaveated(this.auth?.capabilityRequest?.manifests);
|
|
4777
4916
|
const epoch = this.sessionEpoch;
|
|
@@ -6413,6 +6552,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6413
6552
|
invoke: graph.invoke,
|
|
6414
6553
|
invokeAny: graph.invokeAny,
|
|
6415
6554
|
signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
|
|
6555
|
+
sessionInvocationSigner: this.sessionInvocationSignerFor(input.serviceSession),
|
|
6416
6556
|
fetch: graph.fetch
|
|
6417
6557
|
});
|
|
6418
6558
|
const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
|
|
@@ -6628,6 +6768,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6628
6768
|
if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
|
|
6629
6769
|
return signBytesWithJwk(bytes, session.jwk);
|
|
6630
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
|
+
}
|
|
6631
6796
|
/** Author a proofless Policy/v3 owner root with the authenticated holder key. */
|
|
6632
6797
|
async createUnifiedOwnerRoot(input) {
|
|
6633
6798
|
const ownerDid = this.credentialHolderDid;
|
|
@@ -7162,7 +7327,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7162
7327
|
graph.assertActive();
|
|
7163
7328
|
const signed = await this.signRawNetworkAuthorization({
|
|
7164
7329
|
targetNode: input.targetNode,
|
|
7165
|
-
networkId: input.networkId
|
|
7330
|
+
networkId: input.body.keyPath === void 0 ? input.networkId : `${input.networkId}/${input.body.keyPath}`,
|
|
7166
7331
|
action: DECRYPT_ACTION2,
|
|
7167
7332
|
facts: input.facts
|
|
7168
7333
|
}, { graph, session });
|
|
@@ -7335,6 +7500,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7335
7500
|
invoke: graph.invoke,
|
|
7336
7501
|
invokeAny: graph.invokeAny,
|
|
7337
7502
|
signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
|
|
7503
|
+
sessionInvocationSigner: this.sessionInvocationSignerFor(serviceSession),
|
|
7338
7504
|
fetch: graph.fetch
|
|
7339
7505
|
});
|
|
7340
7506
|
this._spaceService = new import_sdk_core11.SpaceService({
|
|
@@ -8118,7 +8284,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8118
8284
|
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
8119
8285
|
return false;
|
|
8120
8286
|
}
|
|
8121
|
-
const expanded =
|
|
8287
|
+
const expanded = (0, import_sdk_core11.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core11.pkhDid)(session.address, session.chainId));
|
|
8122
8288
|
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
8123
8289
|
return true;
|
|
8124
8290
|
}
|
|
@@ -8138,7 +8304,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8138
8304
|
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
8139
8305
|
return [];
|
|
8140
8306
|
}
|
|
8141
|
-
const expanded =
|
|
8307
|
+
const expanded = (0, import_sdk_core11.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core11.pkhDid)(session.address, session.chainId));
|
|
8142
8308
|
return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
|
|
8143
8309
|
(grant) => grant.delegation
|
|
8144
8310
|
);
|
|
@@ -8313,7 +8479,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8313
8479
|
throw new import_sdk_core11.SessionExpiredError(sessionExpiry);
|
|
8314
8480
|
}
|
|
8315
8481
|
}
|
|
8316
|
-
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
|
+
}
|
|
8317
8504
|
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
8318
8505
|
return [];
|
|
8319
8506
|
}
|
|
@@ -8321,7 +8508,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8321
8508
|
if (existingGrants.length > 0) {
|
|
8322
8509
|
return existingGrants.map((grant) => grant.delegation);
|
|
8323
8510
|
}
|
|
8324
|
-
if (!this.signer) {
|
|
8511
|
+
if (!this.signer && options?.signMessage === void 0) {
|
|
8325
8512
|
throw new Error(
|
|
8326
8513
|
"grantRuntimePermissions requires wallet mode with a signer or privateKey."
|
|
8327
8514
|
);
|
|
@@ -8363,13 +8550,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8363
8550
|
return this.wasmBindings.prepareSession({
|
|
8364
8551
|
abilities,
|
|
8365
8552
|
...rawForDelegation.length > 0 ? { rawAbilities: this.permissionsToRawAbilities(rawForDelegation) } : {},
|
|
8366
|
-
address: this.wasmBindings.ensureEip55(
|
|
8367
|
-
chainId:
|
|
8553
|
+
address: this.wasmBindings.ensureEip55(captured.address),
|
|
8554
|
+
chainId: captured.chainId,
|
|
8368
8555
|
domain: this.siweDomain,
|
|
8369
8556
|
issuedAt: now.toISOString(),
|
|
8370
8557
|
expirationTime: expiresAt.toISOString(),
|
|
8371
8558
|
spaceId,
|
|
8372
|
-
jwk:
|
|
8559
|
+
jwk: captured.jwk
|
|
8373
8560
|
});
|
|
8374
8561
|
} catch (error) {
|
|
8375
8562
|
if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && /invalid ReCap resource URI/i.test(error instanceof Error ? error.message : String(error))) {
|
|
@@ -8381,8 +8568,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8381
8568
|
throw error;
|
|
8382
8569
|
}
|
|
8383
8570
|
})();
|
|
8384
|
-
|
|
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?.();
|
|
8575
|
+
if (options?.signMessage !== void 0) {
|
|
8576
|
+
this.assertRuntimeGrantMessage(prepared.siwe, session);
|
|
8577
|
+
}
|
|
8578
|
+
const signature = options?.signMessage !== void 0 ? await options.signMessage(prepared.siwe) : await this.signer.signMessage(prepared.siwe);
|
|
8579
|
+
if (options?.signMessage !== void 0 && !await (0, import_sdk_core11.verifyEip191MessageSignature)(prepared.siwe, signature, session.address)) {
|
|
8580
|
+
throw new Error("The signature does not match the account that owns this session.");
|
|
8581
|
+
}
|
|
8385
8582
|
graph.assertActive();
|
|
8583
|
+
assertCapturedKey?.();
|
|
8386
8584
|
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
8387
8585
|
...prepared,
|
|
8388
8586
|
signature
|
|
@@ -8411,18 +8609,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8411
8609
|
delegatedSession,
|
|
8412
8610
|
delegatedEntries,
|
|
8413
8611
|
spaceId,
|
|
8414
|
-
|
|
8612
|
+
captured,
|
|
8415
8613
|
expiresAt,
|
|
8416
8614
|
{ siwe: prepared.siwe, signature }
|
|
8417
8615
|
);
|
|
8418
8616
|
graph.assertActive();
|
|
8617
|
+
assertCapturedKey?.();
|
|
8419
8618
|
this.runtimePermissionGrants.push({
|
|
8420
8619
|
session: {
|
|
8421
8620
|
delegationHeader: delegatedSession.delegationHeader,
|
|
8422
8621
|
delegationCid: delegatedSession.delegationCid,
|
|
8423
8622
|
spaceId,
|
|
8424
|
-
verificationMethod:
|
|
8425
|
-
jwk:
|
|
8623
|
+
verificationMethod: captured.verificationMethod,
|
|
8624
|
+
jwk: captured.jwk
|
|
8426
8625
|
},
|
|
8427
8626
|
delegation,
|
|
8428
8627
|
operations: this.permissionOperations(delegatedEntries, spaceId),
|
|
@@ -8751,7 +8950,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8751
8950
|
"delegateTo requires a non-empty permissions array"
|
|
8752
8951
|
);
|
|
8753
8952
|
}
|
|
8754
|
-
const expandedEntries =
|
|
8953
|
+
const expandedEntries = (0, import_sdk_core11.expandDelegationPermissionEntries)(permissions);
|
|
8954
|
+
const namedKeyEntries = expandedEntries.filter((entry) => entry.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && entry.path.includes("/"));
|
|
8955
|
+
if (namedKeyEntries.length > 0) {
|
|
8956
|
+
if (expandedEntries.some((entry) => entry.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && !entry.path.includes("/"))) {
|
|
8957
|
+
throw new import_sdk_core11.ManifestValidationError("named-key delegation cannot include bare-network permissions");
|
|
8958
|
+
}
|
|
8959
|
+
if (options?.forceWalletSign) {
|
|
8960
|
+
throw new import_sdk_core11.ManifestValidationError("named-key delegation requires a signed session grant");
|
|
8961
|
+
}
|
|
8962
|
+
const granted = this.projectSignedRecapCapabilities(session.siwe);
|
|
8963
|
+
const { subset, missing } = this.signedCapabilitySubset(namedKeyEntries, granted);
|
|
8964
|
+
if (!subset) throw new import_sdk_core11.PermissionNotInManifestError(missing, granted);
|
|
8965
|
+
}
|
|
8755
8966
|
const now = /* @__PURE__ */ new Date();
|
|
8756
8967
|
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
8757
8968
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
@@ -9185,6 +9396,25 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
9185
9396
|
expandPermissionEntries(permissions) {
|
|
9186
9397
|
return (0, import_sdk_core11.expandPermissionEntries)(permissions);
|
|
9187
9398
|
}
|
|
9399
|
+
/**
|
|
9400
|
+
* Checks the SIWE text a caller-supplied signer is asked to sign: it must be in canonical form (parsing and
|
|
9401
|
+
* re-serializing it gives the same bytes) and name the session's account and chain. The caller then checks the
|
|
9402
|
+
* signature against these exact bytes.
|
|
9403
|
+
*/
|
|
9404
|
+
assertRuntimeGrantMessage(siwe, session) {
|
|
9405
|
+
let parsed;
|
|
9406
|
+
try {
|
|
9407
|
+
parsed = new import_siwe2.SiweMessage(siwe);
|
|
9408
|
+
} catch {
|
|
9409
|
+
throw new Error("The prepared sign-in message is not a valid SIWE message.");
|
|
9410
|
+
}
|
|
9411
|
+
if (parsed.prepareMessage() !== siwe) {
|
|
9412
|
+
throw new Error("The prepared sign-in message is not in canonical form.");
|
|
9413
|
+
}
|
|
9414
|
+
if (parsed.chainId !== session.chainId || (0, import_sdk_core11.canonicalizeAddress)(parsed.address) !== (0, import_sdk_core11.canonicalizeAddress)(session.address)) {
|
|
9415
|
+
throw new Error("The prepared sign-in message is for a different account or chain than this session.");
|
|
9416
|
+
}
|
|
9417
|
+
}
|
|
9188
9418
|
/**
|
|
9189
9419
|
* The current WASM child-delegation APIs accept action-only maps. Refuse any
|
|
9190
9420
|
* constrained branch rather than signing a broader action-only child UCAN.
|
|
@@ -10167,6 +10397,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10167
10397
|
PermissionNotInManifestError,
|
|
10168
10398
|
PrefixedKVService,
|
|
10169
10399
|
ProtocolMismatchError,
|
|
10400
|
+
RuntimeDelegationRejectedError,
|
|
10170
10401
|
SECRET_NAME_RE,
|
|
10171
10402
|
SQLAction,
|
|
10172
10403
|
SQLService,
|
|
@@ -10189,6 +10420,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10189
10420
|
VersionCheckError,
|
|
10190
10421
|
WasmKeyProvider,
|
|
10191
10422
|
activateCompactRuntimeDelegation,
|
|
10423
|
+
activateValidatedRuntimeDelegation,
|
|
10192
10424
|
addressStorageKey,
|
|
10193
10425
|
buildSpaceUri,
|
|
10194
10426
|
canonicalizeAddress,
|
|
@@ -10218,6 +10450,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10218
10450
|
getNodeReplicationLoaders,
|
|
10219
10451
|
getTinyCloudDebugLogs,
|
|
10220
10452
|
installTinyCloudDebugGlobals,
|
|
10453
|
+
isAppKeyHostBound,
|
|
10221
10454
|
isCapabilitySubset,
|
|
10222
10455
|
isEvmAddress,
|
|
10223
10456
|
loadManifest,
|
|
@@ -10239,6 +10472,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10239
10472
|
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
10240
10473
|
serializeDelegation,
|
|
10241
10474
|
tinyCloudDebugLogger,
|
|
10242
|
-
validateManifest
|
|
10475
|
+
validateManifest,
|
|
10476
|
+
wireOpenKeyAuthorize
|
|
10243
10477
|
});
|
|
10244
10478
|
//# sourceMappingURL=core.cjs.map
|