@tinycloud/node-sdk 3.8.0-beta.7 → 3.8.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-jPL2UqH5.d.ts → TinyCloudNode-DaD5vJhL.d.cts} +38 -5
- package/dist/{TinyCloudNode-C0LgPzzJ.d.cts → TinyCloudNode-k3TbBwwj.d.ts} +38 -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-C_fWaxAu.d.ts} +1 -1
- package/dist/{authority-Dkhr6n-f.d.cts → authority-DJdbZM6k.d.cts} +1 -1
- package/dist/core.cjs +238 -29
- 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 +239 -30
- 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 +194 -30
- 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 +199 -32
- 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 +3 -3
- package/dist/replication/authority.d.ts +3 -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");
|
|
@@ -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
|
}
|
|
@@ -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,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8381
8568
|
throw error;
|
|
8382
8569
|
}
|
|
8383
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?.();
|
|
8384
8575
|
const signature = await this.signer.signMessage(prepared.siwe);
|
|
8385
8576
|
graph.assertActive();
|
|
8577
|
+
assertCapturedKey?.();
|
|
8386
8578
|
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
8387
8579
|
...prepared,
|
|
8388
8580
|
signature
|
|
@@ -8411,18 +8603,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8411
8603
|
delegatedSession,
|
|
8412
8604
|
delegatedEntries,
|
|
8413
8605
|
spaceId,
|
|
8414
|
-
|
|
8606
|
+
captured,
|
|
8415
8607
|
expiresAt,
|
|
8416
8608
|
{ siwe: prepared.siwe, signature }
|
|
8417
8609
|
);
|
|
8418
8610
|
graph.assertActive();
|
|
8611
|
+
assertCapturedKey?.();
|
|
8419
8612
|
this.runtimePermissionGrants.push({
|
|
8420
8613
|
session: {
|
|
8421
8614
|
delegationHeader: delegatedSession.delegationHeader,
|
|
8422
8615
|
delegationCid: delegatedSession.delegationCid,
|
|
8423
8616
|
spaceId,
|
|
8424
|
-
verificationMethod:
|
|
8425
|
-
jwk:
|
|
8617
|
+
verificationMethod: captured.verificationMethod,
|
|
8618
|
+
jwk: captured.jwk
|
|
8426
8619
|
},
|
|
8427
8620
|
delegation,
|
|
8428
8621
|
operations: this.permissionOperations(delegatedEntries, spaceId),
|
|
@@ -8751,7 +8944,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8751
8944
|
"delegateTo requires a non-empty permissions array"
|
|
8752
8945
|
);
|
|
8753
8946
|
}
|
|
8754
|
-
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
|
+
}
|
|
8755
8960
|
const now = /* @__PURE__ */ new Date();
|
|
8756
8961
|
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
8757
8962
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
@@ -10167,6 +10372,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10167
10372
|
PermissionNotInManifestError,
|
|
10168
10373
|
PrefixedKVService,
|
|
10169
10374
|
ProtocolMismatchError,
|
|
10375
|
+
RuntimeDelegationRejectedError,
|
|
10170
10376
|
SECRET_NAME_RE,
|
|
10171
10377
|
SQLAction,
|
|
10172
10378
|
SQLService,
|
|
@@ -10189,6 +10395,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10189
10395
|
VersionCheckError,
|
|
10190
10396
|
WasmKeyProvider,
|
|
10191
10397
|
activateCompactRuntimeDelegation,
|
|
10398
|
+
activateValidatedRuntimeDelegation,
|
|
10192
10399
|
addressStorageKey,
|
|
10193
10400
|
buildSpaceUri,
|
|
10194
10401
|
canonicalizeAddress,
|
|
@@ -10218,6 +10425,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10218
10425
|
getNodeReplicationLoaders,
|
|
10219
10426
|
getTinyCloudDebugLogs,
|
|
10220
10427
|
installTinyCloudDebugGlobals,
|
|
10428
|
+
isAppKeyHostBound,
|
|
10221
10429
|
isCapabilitySubset,
|
|
10222
10430
|
isEvmAddress,
|
|
10223
10431
|
loadManifest,
|
|
@@ -10239,6 +10447,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
10239
10447
|
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
10240
10448
|
serializeDelegation,
|
|
10241
10449
|
tinyCloudDebugLogger,
|
|
10242
|
-
validateManifest
|
|
10450
|
+
validateManifest,
|
|
10451
|
+
wireOpenKeyAuthorize
|
|
10243
10452
|
});
|
|
10244
10453
|
//# sourceMappingURL=core.cjs.map
|