@tinycloud/node-sdk 3.0.0-beta.9 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{core-BTuD37zN.d.cts → core-DufYfxi-.d.cts} +23 -8
- package/dist/{core-BTuD37zN.d.ts → core-DufYfxi-.d.ts} +23 -8
- package/dist/core.cjs +149 -101
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +148 -101
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +151 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -2
- package/dist/index.d.ts +24 -2
- package/dist/index.js +149 -101
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -17060,6 +17060,7 @@ __export(index_exports, {
|
|
|
17060
17060
|
FileSessionStorage: () => FileSessionStorage,
|
|
17061
17061
|
HooksService: () => import_sdk_core18.HooksService,
|
|
17062
17062
|
IdentityParseError: () => import_sdk_core11.IdentityParseError,
|
|
17063
|
+
InvalidRestoredSessionError: () => InvalidRestoredSessionError,
|
|
17063
17064
|
KVService: () => import_sdk_core13.KVService,
|
|
17064
17065
|
ManifestValidationError: () => import_sdk_core12.ManifestValidationError,
|
|
17065
17066
|
MemorySessionStorage: () => MemorySessionStorage,
|
|
@@ -17139,6 +17140,7 @@ __export(index_exports, {
|
|
|
17139
17140
|
expandActionShortNames: () => import_sdk_core12.expandActionShortNames,
|
|
17140
17141
|
expandPermissionEntries: () => import_sdk_core12.expandPermissionEntries,
|
|
17141
17142
|
expandPermissionEntry: () => import_sdk_core12.expandPermissionEntry,
|
|
17143
|
+
extractSiweExpiration: () => extractSiweExpiration,
|
|
17142
17144
|
generateRandomReceiverKey: () => import_sdk_core17.generateRandomReceiverKey,
|
|
17143
17145
|
getTinyCloudDebugLogs: () => import_sdk_core11.getTinyCloudDebugLogs,
|
|
17144
17146
|
grantAuthRequest: () => grantAuthRequest,
|
|
@@ -19312,6 +19314,22 @@ function cloneRecapCaveats(caveats) {
|
|
|
19312
19314
|
throw new Error("Verified persisted session ReCap contains invalid caveats.");
|
|
19313
19315
|
}
|
|
19314
19316
|
}
|
|
19317
|
+
function jsonFromVerifier(value) {
|
|
19318
|
+
if (value === void 0) return null;
|
|
19319
|
+
if (Array.isArray(value)) return value.map(jsonFromVerifier);
|
|
19320
|
+
if (value instanceof Map) {
|
|
19321
|
+
const entries = [...value.entries()];
|
|
19322
|
+
if (!entries.every(([key2]) => typeof key2 === "string")) return value;
|
|
19323
|
+
return Object.fromEntries(entries.map(([key2, nested]) => [key2, jsonFromVerifier(nested)]));
|
|
19324
|
+
}
|
|
19325
|
+
if (value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
|
|
19326
|
+
return Object.fromEntries(Object.entries(value).map(([key2, nested]) => [key2, jsonFromVerifier(nested)]));
|
|
19327
|
+
}
|
|
19328
|
+
return value;
|
|
19329
|
+
}
|
|
19330
|
+
function verifierRecapEntries(entries) {
|
|
19331
|
+
return entries.map((entry) => Array.isArray(entry.caveats) ? { ...entry, caveats: entry.caveats.map((caveat) => jsonFromVerifier(caveat)) } : entry);
|
|
19332
|
+
}
|
|
19315
19333
|
var ServiceGraphLifetime = class {
|
|
19316
19334
|
constructor(invokeFn, invokeAnyFn, fetchFn) {
|
|
19317
19335
|
this.invokeFn = invokeFn;
|
|
@@ -19384,18 +19402,23 @@ var UnsupportedSessionRestoreError = class extends Error {
|
|
|
19384
19402
|
this.name = "UnsupportedSessionRestoreError";
|
|
19385
19403
|
}
|
|
19386
19404
|
};
|
|
19405
|
+
var InvalidRestoredSessionError = class extends Error {
|
|
19406
|
+
constructor(message = "Persisted session authority is invalid or expired.") {
|
|
19407
|
+
super(message);
|
|
19408
|
+
this.code = "AUTH_EXPIRED";
|
|
19409
|
+
this.name = "InvalidRestoredSessionError";
|
|
19410
|
+
}
|
|
19411
|
+
};
|
|
19387
19412
|
function canonicalRestoredVerificationMethod(canonicalVerificationMethod, persistedVerificationMethod) {
|
|
19388
19413
|
if (typeof persistedVerificationMethod !== "string") return void 0;
|
|
19389
19414
|
const principal = canonicalVerificationMethod.split("#", 1)[0];
|
|
19390
19415
|
return persistedVerificationMethod === principal || persistedVerificationMethod === canonicalVerificationMethod ? canonicalVerificationMethod : void 0;
|
|
19391
19416
|
}
|
|
19392
19417
|
function persistedExpiry(value) {
|
|
19393
|
-
if (typeof value !== "string")
|
|
19394
|
-
throw new Error("Persisted session without a SIWE expiration must include expiresAt.");
|
|
19395
|
-
}
|
|
19418
|
+
if (typeof value !== "string") throw new InvalidRestoredSessionError("Persisted session must include expiresAt.");
|
|
19396
19419
|
const expiry = new Date(value);
|
|
19397
19420
|
if (!Number.isFinite(expiry.getTime()) || expiry.getTime() <= Date.now()) {
|
|
19398
|
-
throw new
|
|
19421
|
+
throw new InvalidRestoredSessionError();
|
|
19399
19422
|
}
|
|
19400
19423
|
return expiry;
|
|
19401
19424
|
}
|
|
@@ -19938,16 +19961,26 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19938
19961
|
*/
|
|
19939
19962
|
getVerifiedSessionCapabilities() {
|
|
19940
19963
|
const session = this.currentTinyCloudSession();
|
|
19941
|
-
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
).map((entry) =>
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
|
|
19949
|
-
|
|
19950
|
-
|
|
19964
|
+
return session?.siwe ? this.projectSignedRecapCapabilities(session.siwe) : [];
|
|
19965
|
+
}
|
|
19966
|
+
/** Normalize signed capabilities without collapsing nested encryption into raw authority. */
|
|
19967
|
+
projectSignedRecapCapabilities(siwe) {
|
|
19968
|
+
const projected = this.parseRecapWithCaveats(siwe).map((entry) => {
|
|
19969
|
+
const normalized = (0, import_sdk_core7.parseRecapCapabilities)(() => [entry], siwe)[0];
|
|
19970
|
+
if (normalized.service !== "tinycloud.encryption") return normalized;
|
|
19971
|
+
if (!this.isEncryptionNetworkOperation("encryption", entry.path, entry.space)) {
|
|
19972
|
+
return { ...normalized, space: entry.space };
|
|
19973
|
+
}
|
|
19974
|
+
return {
|
|
19975
|
+
service: normalized.service,
|
|
19976
|
+
path: normalized.path,
|
|
19977
|
+
actions: normalized.actions,
|
|
19978
|
+
...normalized.caveats === void 0 ? {} : { caveats: normalized.caveats }
|
|
19979
|
+
};
|
|
19980
|
+
});
|
|
19981
|
+
return projected.sort(
|
|
19982
|
+
(left, right) => (left.space ?? "").localeCompare(right.space ?? "") || left.service.localeCompare(right.service) || left.path.localeCompare(right.path)
|
|
19983
|
+
);
|
|
19951
19984
|
}
|
|
19952
19985
|
/**
|
|
19953
19986
|
* Get the Ethereum address for this user.
|
|
@@ -20402,9 +20435,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20402
20435
|
* We must keep the full owner-scoped URI so a synthetic primary grant can
|
|
20403
20436
|
* never cover an operation on a different owner's space.
|
|
20404
20437
|
*
|
|
20405
|
-
*
|
|
20406
|
-
*
|
|
20407
|
-
*
|
|
20438
|
+
* Only top-level encryption network entries (`space: "encryption"` or
|
|
20439
|
+
* absent) become `resource` ops. A network-shaped path nested under a
|
|
20440
|
+
* data space remains a `spaceId` op, not raw network authority.
|
|
20408
20441
|
* One op per action.
|
|
20409
20442
|
*
|
|
20410
20443
|
* Returns `[]` for session-only / restored-without-siwe modes and for any
|
|
@@ -20425,7 +20458,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20425
20458
|
operations = entries.flatMap((entry) => {
|
|
20426
20459
|
const service = this.invocationServiceName(entry.service);
|
|
20427
20460
|
return entry.actions.map((action) => ({
|
|
20428
|
-
...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId: entry.space },
|
|
20461
|
+
...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId: entry.space },
|
|
20429
20462
|
service,
|
|
20430
20463
|
path: entry.path,
|
|
20431
20464
|
action,
|
|
@@ -20587,7 +20620,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20587
20620
|
return;
|
|
20588
20621
|
} catch (error) {
|
|
20589
20622
|
const message = error instanceof Error ? error.message : String(error);
|
|
20590
|
-
if (/Unauthorized Action|\
|
|
20623
|
+
if (/Unauthorized Action|\b(?:401|403)\b/.test(message)) {
|
|
20591
20624
|
console.warn(
|
|
20592
20625
|
"TinyCloud account registry sync stopped: authorization verdict is not retryable",
|
|
20593
20626
|
error
|
|
@@ -20837,9 +20870,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20837
20870
|
*/
|
|
20838
20871
|
async restoreSession(sessionData) {
|
|
20839
20872
|
await this.wasmBindings.ensureInitialized?.();
|
|
20840
|
-
|
|
20873
|
+
let restoredJwk;
|
|
20874
|
+
try {
|
|
20875
|
+
restoredJwk = clonePersistedSessionJwk(sessionData.jwk);
|
|
20876
|
+
} catch {
|
|
20877
|
+
throw new InvalidRestoredSessionError("Persisted session has an invalid private Ed25519 session key.");
|
|
20878
|
+
}
|
|
20841
20879
|
if (sessionData.chainId !== void 0 && (!Number.isSafeInteger(sessionData.chainId) || sessionData.chainId <= 0)) {
|
|
20842
|
-
throw new
|
|
20880
|
+
throw new InvalidRestoredSessionError("Persisted session chain ID must be a positive safe integer.");
|
|
20843
20881
|
}
|
|
20844
20882
|
const stagedManager = this.wasmBindings.createSessionManager();
|
|
20845
20883
|
const stagedReplace = stagedManager.replaceSessionKey;
|
|
@@ -20851,32 +20889,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20851
20889
|
let stagedKeyId;
|
|
20852
20890
|
let stagedJwk;
|
|
20853
20891
|
let canonicalVerificationMethod;
|
|
20892
|
+
const keyIds = liveKeys.call(this.sessionManager);
|
|
20893
|
+
if (!Array.isArray(keyIds) || !keyIds.every((keyId) => typeof keyId === "string")) {
|
|
20894
|
+
throw new UnsupportedSessionRestoreError("it cannot reliably enumerate every live session signer");
|
|
20895
|
+
}
|
|
20896
|
+
for (const keyId of keyIds) {
|
|
20897
|
+
if (keyId === this.sessionKeyId) continue;
|
|
20898
|
+
const jwk = this.sessionManager.jwk(keyId);
|
|
20899
|
+
if (!jwk) throw new Error("missing live session key");
|
|
20900
|
+
stagedReplace.call(stagedManager, clonePersistedSessionJwk(JSON.parse(jwk)), keyId);
|
|
20901
|
+
}
|
|
20854
20902
|
try {
|
|
20855
|
-
const keyIds = liveKeys.call(this.sessionManager);
|
|
20856
|
-
if (!Array.isArray(keyIds) || !keyIds.every((keyId) => typeof keyId === "string")) {
|
|
20857
|
-
throw new UnsupportedSessionRestoreError("it cannot reliably enumerate every live session signer");
|
|
20858
|
-
}
|
|
20859
|
-
for (const keyId of keyIds) {
|
|
20860
|
-
if (keyId === this.sessionKeyId) continue;
|
|
20861
|
-
const jwk = this.sessionManager.jwk(keyId);
|
|
20862
|
-
if (!jwk) throw new Error("missing live session key");
|
|
20863
|
-
stagedReplace.call(stagedManager, clonePersistedSessionJwk(JSON.parse(jwk)), keyId);
|
|
20864
|
-
}
|
|
20865
20903
|
stagedKeyId = stagedReplace.call(stagedManager, restoredJwk, this.sessionKeyId);
|
|
20866
|
-
|
|
20867
|
-
|
|
20868
|
-
stagedJwk = clonePersistedSessionJwk(JSON.parse(stagedJwkJson));
|
|
20869
|
-
canonicalVerificationMethod = stagedManager.getDID(stagedKeyId);
|
|
20870
|
-
} catch (error) {
|
|
20871
|
-
if (error instanceof UnsupportedSessionRestoreError) throw error;
|
|
20872
|
-
throw new Error("Persisted session has an invalid private Ed25519 session key.");
|
|
20904
|
+
} catch {
|
|
20905
|
+
throw new InvalidRestoredSessionError("Persisted session has an invalid private Ed25519 session key.");
|
|
20873
20906
|
}
|
|
20907
|
+
const stagedJwkJson = stagedManager.jwk(stagedKeyId);
|
|
20908
|
+
if (!stagedJwkJson) throw new Error("missing restored session key");
|
|
20909
|
+
stagedJwk = clonePersistedSessionJwk(JSON.parse(stagedJwkJson));
|
|
20910
|
+
canonicalVerificationMethod = stagedManager.getDID(stagedKeyId);
|
|
20874
20911
|
const restoredVerificationMethod = canonicalRestoredVerificationMethod(
|
|
20875
20912
|
canonicalVerificationMethod,
|
|
20876
20913
|
sessionData.verificationMethod
|
|
20877
20914
|
);
|
|
20878
20915
|
if (!restoredVerificationMethod) {
|
|
20879
|
-
throw new
|
|
20916
|
+
throw new InvalidRestoredSessionError(
|
|
20880
20917
|
"Persisted session verification method does not match its private Ed25519 session key."
|
|
20881
20918
|
);
|
|
20882
20919
|
}
|
|
@@ -20888,26 +20925,37 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20888
20925
|
];
|
|
20889
20926
|
const hasPersistedProof = proofValues.every((value) => value !== void 0);
|
|
20890
20927
|
if (!hasPersistedProof && (proofValues.some((value) => value !== void 0) || sessionData.expiresAt !== void 0)) {
|
|
20891
|
-
throw new
|
|
20928
|
+
throw new InvalidRestoredSessionError("Persisted session authority metadata is incomplete.");
|
|
20929
|
+
}
|
|
20930
|
+
let restoredAddress;
|
|
20931
|
+
try {
|
|
20932
|
+
restoredAddress = hasPersistedProof ? (0, import_sdk_core7.canonicalizeAddress)(sessionData.address) : void 0;
|
|
20933
|
+
} catch {
|
|
20934
|
+
throw new InvalidRestoredSessionError("Persisted session has an invalid wallet address.");
|
|
20892
20935
|
}
|
|
20893
|
-
const restoredAddress = hasPersistedProof ? (0, import_sdk_core7.canonicalizeAddress)(sessionData.address) : void 0;
|
|
20894
20936
|
let stagedSessionExpiry = /* @__PURE__ */ new Date(0);
|
|
20895
20937
|
let stagedRecap = [];
|
|
20896
20938
|
if (hasPersistedProof) {
|
|
20897
20939
|
if (typeof this.wasmBindings.validatePersistedSession !== "function") {
|
|
20898
20940
|
throw new UnsupportedSessionRestoreError("it cannot verify persisted SIWE authority");
|
|
20899
20941
|
}
|
|
20900
|
-
const verified =
|
|
20901
|
-
|
|
20902
|
-
|
|
20903
|
-
|
|
20904
|
-
|
|
20905
|
-
|
|
20906
|
-
|
|
20907
|
-
|
|
20908
|
-
|
|
20909
|
-
|
|
20910
|
-
|
|
20942
|
+
const verified = (() => {
|
|
20943
|
+
try {
|
|
20944
|
+
return this.wasmBindings.validatePersistedSession({
|
|
20945
|
+
delegationHeader: sessionData.delegationHeader,
|
|
20946
|
+
delegationCid: sessionData.delegationCid,
|
|
20947
|
+
spaceId: sessionData.spaceId,
|
|
20948
|
+
jwk: stagedJwk,
|
|
20949
|
+
address: restoredAddress,
|
|
20950
|
+
chainId: sessionData.chainId,
|
|
20951
|
+
siwe: sessionData.siwe,
|
|
20952
|
+
signature: sessionData.signature
|
|
20953
|
+
});
|
|
20954
|
+
} catch (error) {
|
|
20955
|
+
throw new InvalidRestoredSessionError(error instanceof Error ? error.message : String(error));
|
|
20956
|
+
}
|
|
20957
|
+
})();
|
|
20958
|
+
const exactRecap = Array.isArray(verified.verifiedRecap) ? verifierRecapEntries(verified.verifiedRecap) : verified.verifiedRecap;
|
|
20911
20959
|
if (!Array.isArray(exactRecap) || !exactRecap.every(
|
|
20912
20960
|
(entry) => entry !== null && typeof entry === "object" && typeof entry.service === "string" && typeof entry.space === "string" && typeof entry.path === "string" && Array.isArray(entry.actions) && entry.actions.every((action) => typeof action === "string") && Array.isArray(entry.caveats) && entry.caveats.every(
|
|
20913
20961
|
(caveat) => caveat !== null && typeof caveat === "object" && !Array.isArray(caveat)
|
|
@@ -20927,7 +20975,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20927
20975
|
const signedExpiry = verified.expiresAt === void 0 ? void 0 : persistedExpiry(verified.expiresAt);
|
|
20928
20976
|
const persistedPolicyExpiry = sessionData.expiresAt === void 0 ? void 0 : persistedExpiry(sessionData.expiresAt);
|
|
20929
20977
|
if (signedExpiry && persistedPolicyExpiry && !sameInstant(signedExpiry, persistedPolicyExpiry)) {
|
|
20930
|
-
throw new
|
|
20978
|
+
throw new InvalidRestoredSessionError("Persisted session expiry does not match its signed SIWE authority.");
|
|
20931
20979
|
}
|
|
20932
20980
|
stagedSessionExpiry = signedExpiry ?? persistedPolicyExpiry ?? persistedExpiry(void 0);
|
|
20933
20981
|
}
|
|
@@ -21024,7 +21072,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21024
21072
|
operations = recap.flatMap((entry) => {
|
|
21025
21073
|
const service = this.invocationServiceName(entry.service);
|
|
21026
21074
|
return entry.actions.map((action) => ({
|
|
21027
|
-
...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId: entry.space },
|
|
21075
|
+
...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId: entry.space },
|
|
21028
21076
|
service,
|
|
21029
21077
|
path: entry.path,
|
|
21030
21078
|
action,
|
|
@@ -21120,7 +21168,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21120
21168
|
const delegations = input.recap.map((entry) => ({
|
|
21121
21169
|
cid: session.delegationCid,
|
|
21122
21170
|
delegateDID: session.verificationMethod,
|
|
21123
|
-
spaceId: entry.space,
|
|
21171
|
+
spaceId: this.spaceIdsEqual(entry.space, session.spaceId) ? session.spaceId : entry.space,
|
|
21124
21172
|
path: entry.path,
|
|
21125
21173
|
actions: [...entry.actions],
|
|
21126
21174
|
caveats: cloneRecapCaveats(entry.caveats),
|
|
@@ -21810,16 +21858,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21810
21858
|
);
|
|
21811
21859
|
graph.assertActive();
|
|
21812
21860
|
if (!response.ok) {
|
|
21813
|
-
|
|
21814
|
-
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
|
|
21818
|
-
const nested = typeof record?.error === "object" && record.error !== null ? record.error : void 0;
|
|
21819
|
-
permissionHint = (0, import_sdk_services.parsePermissionHint)(record?.permissionHint) ?? (0, import_sdk_services.parsePermissionHint)(nested?.permissionHint);
|
|
21820
|
-
} catch {
|
|
21821
|
-
}
|
|
21822
|
-
}
|
|
21861
|
+
const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services.parsePermissionHint)({
|
|
21862
|
+
service: "tinycloud.encryption",
|
|
21863
|
+
path: networkId,
|
|
21864
|
+
actions: ["tinycloud.encryption/decrypt"]
|
|
21865
|
+
}) : void 0;
|
|
21823
21866
|
throw new import_sdk_core7.DecryptTransportResponseError(response.status, permissionHint);
|
|
21824
21867
|
}
|
|
21825
21868
|
return await response.json();
|
|
@@ -22258,13 +22301,20 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22258
22301
|
const session = this.currentTinyCloudSession();
|
|
22259
22302
|
const serviceSession = this._serviceContext?.session;
|
|
22260
22303
|
if (!session || !serviceSession) throw new Error("Share delivery requires an authenticated session");
|
|
22304
|
+
const idempotencyBytes = new TextEncoder().encode(input.idempotencyKey);
|
|
22305
|
+
if (idempotencyBytes.byteLength === 0 || idempotencyBytes.byteLength > 512) {
|
|
22306
|
+
throw new Error("Share delivery idempotency key is invalid");
|
|
22307
|
+
}
|
|
22308
|
+
const jtiDigest = new Uint8Array(await crypto.subtle.digest("SHA-256", idempotencyBytes));
|
|
22261
22309
|
const body = {
|
|
22262
22310
|
envelope: input.envelope,
|
|
22311
|
+
sealedEnvelope: input.sealedEnvelope,
|
|
22312
|
+
envelopeKey: input.envelopeKey,
|
|
22263
22313
|
shareCid: input.shareCid,
|
|
22264
22314
|
recipientEmail: input.recipientEmail,
|
|
22265
22315
|
shareUrl: input.shareUrl,
|
|
22266
22316
|
documentName: input.documentName,
|
|
22267
|
-
jti: base64UrlEncode(
|
|
22317
|
+
jti: base64UrlEncode(jtiDigest.slice(0, 16)),
|
|
22268
22318
|
expiresAt: new Date(input.expiresAt).toISOString().replace(/\.\d{3}Z$/, "Z")
|
|
22269
22319
|
};
|
|
22270
22320
|
const requestBodyDigest = base64UrlEncode(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode((0, import_sdk_core7.canonicalizeEncryptionJson)(body)))));
|
|
@@ -22747,7 +22797,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22747
22797
|
continue;
|
|
22748
22798
|
}
|
|
22749
22799
|
let space;
|
|
22750
|
-
if (service !== "tinycloud.encryption") {
|
|
22800
|
+
if (service !== "tinycloud.encryption" || operation.resource === void 0) {
|
|
22751
22801
|
if (typeof operation.spaceId !== "string") continue;
|
|
22752
22802
|
try {
|
|
22753
22803
|
space = this.resolvePermissionSpace(operation.spaceId, session);
|
|
@@ -23292,11 +23342,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23292
23342
|
);
|
|
23293
23343
|
return { delegation: delegation2, prompted: true };
|
|
23294
23344
|
}
|
|
23295
|
-
const granted = (
|
|
23296
|
-
|
|
23297
|
-
session.siwe
|
|
23298
|
-
);
|
|
23299
|
-
const { subset, missing } = (0, import_sdk_core7.isCapabilitySubset)(expandedEntries, granted);
|
|
23345
|
+
const granted = this.projectSignedRecapCapabilities(session.siwe);
|
|
23346
|
+
const { subset, missing } = this.signedCapabilitySubset(expandedEntries, granted);
|
|
23300
23347
|
if (!subset) {
|
|
23301
23348
|
const runtimeOperations = this.permissionEntriesToOperations(expandedEntries, session);
|
|
23302
23349
|
const runtimeGrant = this.findGrantForOperations(
|
|
@@ -23616,7 +23663,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23616
23663
|
return abilities;
|
|
23617
23664
|
}
|
|
23618
23665
|
isEncryptionPermissionEntry(entry) {
|
|
23619
|
-
return entry.service === import_sdk_core7.ENCRYPTION_PERMISSION_SERVICE &&
|
|
23666
|
+
return entry.service === import_sdk_core7.ENCRYPTION_PERMISSION_SERVICE && this.isEncryptionNetworkOperation("encryption", entry.path, entry.space);
|
|
23620
23667
|
}
|
|
23621
23668
|
permissionsToRawAbilities(entries) {
|
|
23622
23669
|
const rawAbilities = {};
|
|
@@ -23640,7 +23687,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23640
23687
|
return entries.flatMap((entry) => {
|
|
23641
23688
|
const service = this.shortServiceName(entry.service);
|
|
23642
23689
|
return entry.actions.map((action) => ({
|
|
23643
|
-
...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
|
|
23690
|
+
...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
|
|
23644
23691
|
service,
|
|
23645
23692
|
path: entry.path,
|
|
23646
23693
|
action,
|
|
@@ -23648,13 +23695,21 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23648
23695
|
}));
|
|
23649
23696
|
});
|
|
23650
23697
|
}
|
|
23698
|
+
/** Raw network authority cannot be covered by a nested encryption space. */
|
|
23699
|
+
signedCapabilitySubset(requested, granted) {
|
|
23700
|
+
const rawGranted = granted.filter((entry) => this.isEncryptionPermissionEntry(entry)).map((entry) => ({ ...entry, space: "encryption" }));
|
|
23701
|
+
const spaceGranted = granted.filter((entry) => !this.isEncryptionPermissionEntry(entry));
|
|
23702
|
+
const missing = requested.filter((entry) => {
|
|
23703
|
+
const raw = this.isEncryptionPermissionEntry(entry);
|
|
23704
|
+
const comparable = raw ? { ...entry, space: "encryption" } : entry;
|
|
23705
|
+
return !(0, import_sdk_core7.isCapabilitySubset)([comparable], raw ? rawGranted : spaceGranted).subset;
|
|
23706
|
+
});
|
|
23707
|
+
return { subset: missing.length === 0, missing };
|
|
23708
|
+
}
|
|
23651
23709
|
sessionCoversPermissionEntries(session, entries) {
|
|
23652
23710
|
try {
|
|
23653
|
-
const granted = (
|
|
23654
|
-
|
|
23655
|
-
session.siwe
|
|
23656
|
-
);
|
|
23657
|
-
return (0, import_sdk_core7.isCapabilitySubset)(entries, granted).subset;
|
|
23711
|
+
const granted = this.projectSignedRecapCapabilities(session.siwe);
|
|
23712
|
+
return this.signedCapabilitySubset(entries, granted).subset;
|
|
23658
23713
|
} catch {
|
|
23659
23714
|
return false;
|
|
23660
23715
|
}
|
|
@@ -23664,7 +23719,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23664
23719
|
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
23665
23720
|
const service = this.shortServiceName(entry.service);
|
|
23666
23721
|
return entry.actions.map((action) => ({
|
|
23667
|
-
...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
|
|
23722
|
+
...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
|
|
23668
23723
|
service,
|
|
23669
23724
|
path: entry.path,
|
|
23670
23725
|
action,
|
|
@@ -23753,7 +23808,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23753
23808
|
return resources.flatMap((resource) => {
|
|
23754
23809
|
const service = this.invocationServiceName(resource.service);
|
|
23755
23810
|
return resource.actions.map((action) => ({
|
|
23756
|
-
...this.isEncryptionNetworkOperation(service, resource.path) ? { resource: resource.path } : { spaceId: resource.space },
|
|
23811
|
+
...this.isEncryptionNetworkOperation(service, resource.path, resource.space) ? { resource: resource.path } : { spaceId: resource.space },
|
|
23757
23812
|
service,
|
|
23758
23813
|
path: resource.path,
|
|
23759
23814
|
action,
|
|
@@ -23814,7 +23869,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23814
23869
|
};
|
|
23815
23870
|
for (const resource of resources) {
|
|
23816
23871
|
const service = this.invocationServiceName(resource.service);
|
|
23817
|
-
if (this.isEncryptionNetworkOperation(service, resource.path)) {
|
|
23872
|
+
if (this.isEncryptionNetworkOperation(service, resource.path, resource.space)) {
|
|
23818
23873
|
rawAbilities[_a = resource.path] ?? (rawAbilities[_a] = []);
|
|
23819
23874
|
addActions(rawAbilities[resource.path], resource.actions);
|
|
23820
23875
|
continue;
|
|
@@ -23883,21 +23938,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23883
23938
|
}
|
|
23884
23939
|
return granted.spaceId !== void 0 && requested.spaceId !== void 0 && this.spaceIdsEqual(granted.spaceId, requested.spaceId) && this.pathContains(granted.path, requested.path);
|
|
23885
23940
|
}
|
|
23886
|
-
// Space IDs are `tinycloud:pkh:eip155:<chain>:<0xADDR>:<name>`.
|
|
23887
|
-
// EIP-155 address
|
|
23888
|
-
//
|
|
23889
|
-
// the EIP-55 checksummed form — so a byte-for-byte compare spuriously rejects
|
|
23890
|
-
// an otherwise-valid grant. Lowercase ONLY the `eip155:<chain>:0x<addr>`
|
|
23891
|
-
// segment and leave everything else (crucially the case-sensitive space NAME)
|
|
23892
|
-
// byte-exact. Mirrors the CLI's `normalizeSpaceForCompare` (OPENKEY_SCOPE_MISMATCH fix).
|
|
23941
|
+
// Space IDs are `tinycloud:pkh:eip155:<chain>:<0xADDR>:<name>`. Compare
|
|
23942
|
+
// only the embedded EIP-155 address without case sensitivity; chain, name,
|
|
23943
|
+
// and all non-PKH space identifiers remain byte-exact.
|
|
23893
23944
|
spaceIdsEqual(a, b) {
|
|
23894
23945
|
return this.normalizeSpaceAddress(a) === this.normalizeSpaceAddress(b);
|
|
23895
23946
|
}
|
|
23896
23947
|
normalizeSpaceAddress(space) {
|
|
23897
|
-
|
|
23898
|
-
|
|
23899
|
-
(_match, prefix, addr) => prefix + addr.toLowerCase()
|
|
23900
|
-
);
|
|
23948
|
+
const match = /^(tinycloud:pkh:eip155:\d+:)(0x[0-9a-fA-F]{40})(:.+)$/.exec(space);
|
|
23949
|
+
return match === null ? space : `${match[1]}${match[2].toLowerCase()}${match[3]}`;
|
|
23901
23950
|
}
|
|
23902
23951
|
actionContains(grantedAction, requestedAction) {
|
|
23903
23952
|
if (grantedAction === requestedAction) {
|
|
@@ -23914,10 +23963,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23914
23963
|
}
|
|
23915
23964
|
/** Prefer the v2 caveat-preserving parser while retaining old custom WASM. */
|
|
23916
23965
|
parseRecapWithCaveats(siwe) {
|
|
23917
|
-
|
|
23966
|
+
const verified = this.wasmBindings.parseVerifiedRecapFromSiwe?.(siwe);
|
|
23967
|
+
return verified == null ? this.wasmBindings.parseRecapFromSiwe(siwe) : verifierRecapEntries(verified);
|
|
23918
23968
|
}
|
|
23919
|
-
isEncryptionNetworkOperation(service, path) {
|
|
23920
|
-
return service === "encryption" && path.startsWith("urn:tinycloud:encryption:");
|
|
23969
|
+
isEncryptionNetworkOperation(service, path, space) {
|
|
23970
|
+
return service === "encryption" && (space === void 0 || space === "encryption") && path.startsWith("urn:tinycloud:encryption:");
|
|
23921
23971
|
}
|
|
23922
23972
|
operationFromInvokeAnyEntry(entry) {
|
|
23923
23973
|
const service = this.invocationServiceName(entry.service);
|
|
@@ -23930,7 +23980,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23930
23980
|
...entry.caveats === void 0 ? {} : { caveats: cloneRecapCaveats(entry.caveats) }
|
|
23931
23981
|
};
|
|
23932
23982
|
}
|
|
23933
|
-
if (this.isEncryptionNetworkOperation(service, entry.path)) {
|
|
23983
|
+
if (entry.spaceId === void 0 && this.isEncryptionNetworkOperation(service, entry.path)) {
|
|
23934
23984
|
return {
|
|
23935
23985
|
resource: entry.path,
|
|
23936
23986
|
service,
|
|
@@ -24215,8 +24265,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24215
24265
|
const jwk = mySession.jwk;
|
|
24216
24266
|
const { abilities, rawAbilities } = this.buildActivationAbilities(delegation);
|
|
24217
24267
|
const now = /* @__PURE__ */ new Date();
|
|
24218
|
-
const
|
|
24219
|
-
const expirationTime = delegation.expiry < maxExpiry ? delegation.expiry : maxExpiry;
|
|
24268
|
+
const expirationTime = delegation.expiry;
|
|
24220
24269
|
const prepared = this.wasmBindings.prepareSession({
|
|
24221
24270
|
abilities,
|
|
24222
24271
|
address: this.wasmBindings.ensureEip55(mySession.address),
|
|
@@ -24320,8 +24369,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24320
24369
|
);
|
|
24321
24370
|
}
|
|
24322
24371
|
const now = /* @__PURE__ */ new Date();
|
|
24323
|
-
const
|
|
24324
|
-
const requestedExpiry = new Date(now.getTime() + expiryMs);
|
|
24372
|
+
const requestedExpiry = params.expiryMs === void 0 ? parentDelegation.expiry : new Date(now.getTime() + params.expiryMs);
|
|
24325
24373
|
const actualExpiry = requestedExpiry > parentDelegation.expiry ? parentDelegation.expiry : requestedExpiry;
|
|
24326
24374
|
const abilities = {};
|
|
24327
24375
|
const rawAbilities = {};
|
|
@@ -24994,6 +25042,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
24994
25042
|
FileSessionStorage,
|
|
24995
25043
|
HooksService,
|
|
24996
25044
|
IdentityParseError,
|
|
25045
|
+
InvalidRestoredSessionError,
|
|
24997
25046
|
KVService,
|
|
24998
25047
|
ManifestValidationError,
|
|
24999
25048
|
MemorySessionStorage,
|
|
@@ -25073,6 +25122,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
25073
25122
|
expandActionShortNames,
|
|
25074
25123
|
expandPermissionEntries,
|
|
25075
25124
|
expandPermissionEntry,
|
|
25125
|
+
extractSiweExpiration,
|
|
25076
25126
|
generateRandomReceiverKey,
|
|
25077
25127
|
getTinyCloudDebugLogs,
|
|
25078
25128
|
grantAuthRequest,
|