@tinycloud/node-sdk 3.0.0-beta.8 → 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-WJQ9KiSD.d.cts → core-DufYfxi-.d.cts} +31 -70
- package/dist/{core-WJQ9KiSD.d.ts → core-DufYfxi-.d.ts} +31 -70
- package/dist/core.cjs +171 -108
- 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 +171 -108
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +173 -108
- 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 +172 -108
- 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
|
}
|
|
@@ -19874,6 +19897,29 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19874
19897
|
const authHosts = this.auth?.hosts ?? [];
|
|
19875
19898
|
return authHosts.length > 0 ? authHosts : [this.config.host];
|
|
19876
19899
|
}
|
|
19900
|
+
/** The registry-resolved Node endpoint and the identity returned by that exact Node. */
|
|
19901
|
+
async activeNodeIdentity() {
|
|
19902
|
+
const host = this.hosts[0];
|
|
19903
|
+
if (host === void 0) throw new Error("TinyCloud node host has not been resolved");
|
|
19904
|
+
const parsed = new URL(host);
|
|
19905
|
+
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && (parsed.hostname === "127.0.0.1" || parsed.hostname === "localhost")) || parsed.origin !== host) {
|
|
19906
|
+
throw new Error("TinyCloud node host is not a canonical origin");
|
|
19907
|
+
}
|
|
19908
|
+
const nodeDid = await this.fetchNodeId();
|
|
19909
|
+
if (!nodeDid.startsWith("did:key:z")) throw new Error("TinyCloud node identity is not a did:key");
|
|
19910
|
+
return Object.freeze({ origin: parsed.origin, nodeDid });
|
|
19911
|
+
}
|
|
19912
|
+
/** Publish the active owner Node as a session-signed registry record. */
|
|
19913
|
+
async publishActiveNodeLocation(registryUrl, fetchFn = globalThis.fetch.bind(globalThis)) {
|
|
19914
|
+
const node = await this.activeNodeIdentity();
|
|
19915
|
+
return (0, import_sdk_core7.publishLocationRecord)({
|
|
19916
|
+
registryUrl,
|
|
19917
|
+
subject: this.credentialHolderDid,
|
|
19918
|
+
nodeOrigin: node.origin,
|
|
19919
|
+
signer: { type: "did:key", signBytes: (bytes) => this.signSessionBytes(bytes) },
|
|
19920
|
+
fetch: fetchFn
|
|
19921
|
+
});
|
|
19922
|
+
}
|
|
19877
19923
|
/**
|
|
19878
19924
|
* Get the primary identity DID for this user.
|
|
19879
19925
|
* - If wallet connected and signed in: returns PKH DID (did:pkh:eip155:{chainId}:{address})
|
|
@@ -19915,16 +19961,26 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19915
19961
|
*/
|
|
19916
19962
|
getVerifiedSessionCapabilities() {
|
|
19917
19963
|
const session = this.currentTinyCloudSession();
|
|
19918
|
-
|
|
19919
|
-
|
|
19920
|
-
|
|
19921
|
-
|
|
19922
|
-
).map((entry) =>
|
|
19923
|
-
|
|
19924
|
-
|
|
19925
|
-
|
|
19926
|
-
|
|
19927
|
-
|
|
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
|
+
);
|
|
19928
19984
|
}
|
|
19929
19985
|
/**
|
|
19930
19986
|
* Get the Ethereum address for this user.
|
|
@@ -20379,9 +20435,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20379
20435
|
* We must keep the full owner-scoped URI so a synthetic primary grant can
|
|
20380
20436
|
* never cover an operation on a different owner's space.
|
|
20381
20437
|
*
|
|
20382
|
-
*
|
|
20383
|
-
*
|
|
20384
|
-
*
|
|
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.
|
|
20385
20441
|
* One op per action.
|
|
20386
20442
|
*
|
|
20387
20443
|
* Returns `[]` for session-only / restored-without-siwe modes and for any
|
|
@@ -20402,7 +20458,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20402
20458
|
operations = entries.flatMap((entry) => {
|
|
20403
20459
|
const service = this.invocationServiceName(entry.service);
|
|
20404
20460
|
return entry.actions.map((action) => ({
|
|
20405
|
-
...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 },
|
|
20406
20462
|
service,
|
|
20407
20463
|
path: entry.path,
|
|
20408
20464
|
action,
|
|
@@ -20564,7 +20620,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20564
20620
|
return;
|
|
20565
20621
|
} catch (error) {
|
|
20566
20622
|
const message = error instanceof Error ? error.message : String(error);
|
|
20567
|
-
if (/Unauthorized Action|\
|
|
20623
|
+
if (/Unauthorized Action|\b(?:401|403)\b/.test(message)) {
|
|
20568
20624
|
console.warn(
|
|
20569
20625
|
"TinyCloud account registry sync stopped: authorization verdict is not retryable",
|
|
20570
20626
|
error
|
|
@@ -20814,9 +20870,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20814
20870
|
*/
|
|
20815
20871
|
async restoreSession(sessionData) {
|
|
20816
20872
|
await this.wasmBindings.ensureInitialized?.();
|
|
20817
|
-
|
|
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
|
+
}
|
|
20818
20879
|
if (sessionData.chainId !== void 0 && (!Number.isSafeInteger(sessionData.chainId) || sessionData.chainId <= 0)) {
|
|
20819
|
-
throw new
|
|
20880
|
+
throw new InvalidRestoredSessionError("Persisted session chain ID must be a positive safe integer.");
|
|
20820
20881
|
}
|
|
20821
20882
|
const stagedManager = this.wasmBindings.createSessionManager();
|
|
20822
20883
|
const stagedReplace = stagedManager.replaceSessionKey;
|
|
@@ -20828,32 +20889,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20828
20889
|
let stagedKeyId;
|
|
20829
20890
|
let stagedJwk;
|
|
20830
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
|
+
}
|
|
20831
20902
|
try {
|
|
20832
|
-
const keyIds = liveKeys.call(this.sessionManager);
|
|
20833
|
-
if (!Array.isArray(keyIds) || !keyIds.every((keyId) => typeof keyId === "string")) {
|
|
20834
|
-
throw new UnsupportedSessionRestoreError("it cannot reliably enumerate every live session signer");
|
|
20835
|
-
}
|
|
20836
|
-
for (const keyId of keyIds) {
|
|
20837
|
-
if (keyId === this.sessionKeyId) continue;
|
|
20838
|
-
const jwk = this.sessionManager.jwk(keyId);
|
|
20839
|
-
if (!jwk) throw new Error("missing live session key");
|
|
20840
|
-
stagedReplace.call(stagedManager, clonePersistedSessionJwk(JSON.parse(jwk)), keyId);
|
|
20841
|
-
}
|
|
20842
20903
|
stagedKeyId = stagedReplace.call(stagedManager, restoredJwk, this.sessionKeyId);
|
|
20843
|
-
|
|
20844
|
-
|
|
20845
|
-
stagedJwk = clonePersistedSessionJwk(JSON.parse(stagedJwkJson));
|
|
20846
|
-
canonicalVerificationMethod = stagedManager.getDID(stagedKeyId);
|
|
20847
|
-
} catch (error) {
|
|
20848
|
-
if (error instanceof UnsupportedSessionRestoreError) throw error;
|
|
20849
|
-
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.");
|
|
20850
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);
|
|
20851
20911
|
const restoredVerificationMethod = canonicalRestoredVerificationMethod(
|
|
20852
20912
|
canonicalVerificationMethod,
|
|
20853
20913
|
sessionData.verificationMethod
|
|
20854
20914
|
);
|
|
20855
20915
|
if (!restoredVerificationMethod) {
|
|
20856
|
-
throw new
|
|
20916
|
+
throw new InvalidRestoredSessionError(
|
|
20857
20917
|
"Persisted session verification method does not match its private Ed25519 session key."
|
|
20858
20918
|
);
|
|
20859
20919
|
}
|
|
@@ -20865,26 +20925,37 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20865
20925
|
];
|
|
20866
20926
|
const hasPersistedProof = proofValues.every((value) => value !== void 0);
|
|
20867
20927
|
if (!hasPersistedProof && (proofValues.some((value) => value !== void 0) || sessionData.expiresAt !== void 0)) {
|
|
20868
|
-
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.");
|
|
20869
20935
|
}
|
|
20870
|
-
const restoredAddress = hasPersistedProof ? (0, import_sdk_core7.canonicalizeAddress)(sessionData.address) : void 0;
|
|
20871
20936
|
let stagedSessionExpiry = /* @__PURE__ */ new Date(0);
|
|
20872
20937
|
let stagedRecap = [];
|
|
20873
20938
|
if (hasPersistedProof) {
|
|
20874
20939
|
if (typeof this.wasmBindings.validatePersistedSession !== "function") {
|
|
20875
20940
|
throw new UnsupportedSessionRestoreError("it cannot verify persisted SIWE authority");
|
|
20876
20941
|
}
|
|
20877
|
-
const verified =
|
|
20878
|
-
|
|
20879
|
-
|
|
20880
|
-
|
|
20881
|
-
|
|
20882
|
-
|
|
20883
|
-
|
|
20884
|
-
|
|
20885
|
-
|
|
20886
|
-
|
|
20887
|
-
|
|
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;
|
|
20888
20959
|
if (!Array.isArray(exactRecap) || !exactRecap.every(
|
|
20889
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(
|
|
20890
20961
|
(caveat) => caveat !== null && typeof caveat === "object" && !Array.isArray(caveat)
|
|
@@ -20904,7 +20975,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20904
20975
|
const signedExpiry = verified.expiresAt === void 0 ? void 0 : persistedExpiry(verified.expiresAt);
|
|
20905
20976
|
const persistedPolicyExpiry = sessionData.expiresAt === void 0 ? void 0 : persistedExpiry(sessionData.expiresAt);
|
|
20906
20977
|
if (signedExpiry && persistedPolicyExpiry && !sameInstant(signedExpiry, persistedPolicyExpiry)) {
|
|
20907
|
-
throw new
|
|
20978
|
+
throw new InvalidRestoredSessionError("Persisted session expiry does not match its signed SIWE authority.");
|
|
20908
20979
|
}
|
|
20909
20980
|
stagedSessionExpiry = signedExpiry ?? persistedPolicyExpiry ?? persistedExpiry(void 0);
|
|
20910
20981
|
}
|
|
@@ -21001,7 +21072,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21001
21072
|
operations = recap.flatMap((entry) => {
|
|
21002
21073
|
const service = this.invocationServiceName(entry.service);
|
|
21003
21074
|
return entry.actions.map((action) => ({
|
|
21004
|
-
...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 },
|
|
21005
21076
|
service,
|
|
21006
21077
|
path: entry.path,
|
|
21007
21078
|
action,
|
|
@@ -21097,7 +21168,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21097
21168
|
const delegations = input.recap.map((entry) => ({
|
|
21098
21169
|
cid: session.delegationCid,
|
|
21099
21170
|
delegateDID: session.verificationMethod,
|
|
21100
|
-
spaceId: entry.space,
|
|
21171
|
+
spaceId: this.spaceIdsEqual(entry.space, session.spaceId) ? session.spaceId : entry.space,
|
|
21101
21172
|
path: entry.path,
|
|
21102
21173
|
actions: [...entry.actions],
|
|
21103
21174
|
caveats: cloneRecapCaveats(entry.caveats),
|
|
@@ -21787,16 +21858,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21787
21858
|
);
|
|
21788
21859
|
graph.assertActive();
|
|
21789
21860
|
if (!response.ok) {
|
|
21790
|
-
|
|
21791
|
-
|
|
21792
|
-
|
|
21793
|
-
|
|
21794
|
-
|
|
21795
|
-
const nested = typeof record?.error === "object" && record.error !== null ? record.error : void 0;
|
|
21796
|
-
permissionHint = (0, import_sdk_services.parsePermissionHint)(record?.permissionHint) ?? (0, import_sdk_services.parsePermissionHint)(nested?.permissionHint);
|
|
21797
|
-
} catch {
|
|
21798
|
-
}
|
|
21799
|
-
}
|
|
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;
|
|
21800
21866
|
throw new import_sdk_core7.DecryptTransportResponseError(response.status, permissionHint);
|
|
21801
21867
|
}
|
|
21802
21868
|
return await response.json();
|
|
@@ -22230,16 +22296,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22230
22296
|
fetch: globalThis.fetch.bind(globalThis)
|
|
22231
22297
|
});
|
|
22232
22298
|
}
|
|
22233
|
-
/** @deprecated Policy/v2 delivery transport is retired. Use authorizeShareDeliveryV3. */
|
|
22234
|
-
async authorizeShareDelivery(input) {
|
|
22235
|
-
void input;
|
|
22236
|
-
throw new Error("Policy/v2 share delivery is retired; use authorizeShareDeliveryV3");
|
|
22237
|
-
}
|
|
22238
22299
|
/** Authorize one short-lived v3 delivery against the signed v3 envelope and registered roots. */
|
|
22239
22300
|
async authorizeShareDeliveryV3(input) {
|
|
22240
22301
|
const session = this.currentTinyCloudSession();
|
|
22241
22302
|
const serviceSession = this._serviceContext?.session;
|
|
22242
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));
|
|
22243
22309
|
const body = {
|
|
22244
22310
|
envelope: input.envelope,
|
|
22245
22311
|
sealedEnvelope: input.sealedEnvelope,
|
|
@@ -22248,7 +22314,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22248
22314
|
recipientEmail: input.recipientEmail,
|
|
22249
22315
|
shareUrl: input.shareUrl,
|
|
22250
22316
|
documentName: input.documentName,
|
|
22251
|
-
jti: base64UrlEncode(
|
|
22317
|
+
jti: base64UrlEncode(jtiDigest.slice(0, 16)),
|
|
22252
22318
|
expiresAt: new Date(input.expiresAt).toISOString().replace(/\.\d{3}Z$/, "Z")
|
|
22253
22319
|
};
|
|
22254
22320
|
const requestBodyDigest = base64UrlEncode(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode((0, import_sdk_core7.canonicalizeEncryptionJson)(body)))));
|
|
@@ -22263,9 +22329,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22263
22329
|
const verified = (0, import_sdk_core7.validateShareDeliveryAuthorizationV3Bytes)(new Uint8Array(await response.arrayBuffer()), {
|
|
22264
22330
|
request,
|
|
22265
22331
|
senderKeyDid: this.credentialHolderDid,
|
|
22266
|
-
|
|
22332
|
+
deliveryAudience: input.deliveryAudience
|
|
22267
22333
|
});
|
|
22268
|
-
void input.nodeProof;
|
|
22269
22334
|
const requestDigest = new Uint8Array(await crypto.subtle.digest(
|
|
22270
22335
|
"SHA-256",
|
|
22271
22336
|
new TextEncoder().encode(`${import_sdk_core7.CREDENTIAL_INVITATION_REQUEST_DOMAIN}${(0, import_sdk_core7.canonicalizeEncryptionJson)(verified.request)}`)
|
|
@@ -22732,7 +22797,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22732
22797
|
continue;
|
|
22733
22798
|
}
|
|
22734
22799
|
let space;
|
|
22735
|
-
if (service !== "tinycloud.encryption") {
|
|
22800
|
+
if (service !== "tinycloud.encryption" || operation.resource === void 0) {
|
|
22736
22801
|
if (typeof operation.spaceId !== "string") continue;
|
|
22737
22802
|
try {
|
|
22738
22803
|
space = this.resolvePermissionSpace(operation.spaceId, session);
|
|
@@ -23277,11 +23342,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23277
23342
|
);
|
|
23278
23343
|
return { delegation: delegation2, prompted: true };
|
|
23279
23344
|
}
|
|
23280
|
-
const granted = (
|
|
23281
|
-
|
|
23282
|
-
session.siwe
|
|
23283
|
-
);
|
|
23284
|
-
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);
|
|
23285
23347
|
if (!subset) {
|
|
23286
23348
|
const runtimeOperations = this.permissionEntriesToOperations(expandedEntries, session);
|
|
23287
23349
|
const runtimeGrant = this.findGrantForOperations(
|
|
@@ -23601,7 +23663,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23601
23663
|
return abilities;
|
|
23602
23664
|
}
|
|
23603
23665
|
isEncryptionPermissionEntry(entry) {
|
|
23604
|
-
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);
|
|
23605
23667
|
}
|
|
23606
23668
|
permissionsToRawAbilities(entries) {
|
|
23607
23669
|
const rawAbilities = {};
|
|
@@ -23625,7 +23687,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23625
23687
|
return entries.flatMap((entry) => {
|
|
23626
23688
|
const service = this.shortServiceName(entry.service);
|
|
23627
23689
|
return entry.actions.map((action) => ({
|
|
23628
|
-
...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
|
|
23690
|
+
...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
|
|
23629
23691
|
service,
|
|
23630
23692
|
path: entry.path,
|
|
23631
23693
|
action,
|
|
@@ -23633,13 +23695,21 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23633
23695
|
}));
|
|
23634
23696
|
});
|
|
23635
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
|
+
}
|
|
23636
23709
|
sessionCoversPermissionEntries(session, entries) {
|
|
23637
23710
|
try {
|
|
23638
|
-
const granted = (
|
|
23639
|
-
|
|
23640
|
-
session.siwe
|
|
23641
|
-
);
|
|
23642
|
-
return (0, import_sdk_core7.isCapabilitySubset)(entries, granted).subset;
|
|
23711
|
+
const granted = this.projectSignedRecapCapabilities(session.siwe);
|
|
23712
|
+
return this.signedCapabilitySubset(entries, granted).subset;
|
|
23643
23713
|
} catch {
|
|
23644
23714
|
return false;
|
|
23645
23715
|
}
|
|
@@ -23649,7 +23719,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23649
23719
|
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
23650
23720
|
const service = this.shortServiceName(entry.service);
|
|
23651
23721
|
return entry.actions.map((action) => ({
|
|
23652
|
-
...this.isEncryptionNetworkOperation(service, entry.path) ? { resource: entry.path } : { spaceId },
|
|
23722
|
+
...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
|
|
23653
23723
|
service,
|
|
23654
23724
|
path: entry.path,
|
|
23655
23725
|
action,
|
|
@@ -23738,7 +23808,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23738
23808
|
return resources.flatMap((resource) => {
|
|
23739
23809
|
const service = this.invocationServiceName(resource.service);
|
|
23740
23810
|
return resource.actions.map((action) => ({
|
|
23741
|
-
...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 },
|
|
23742
23812
|
service,
|
|
23743
23813
|
path: resource.path,
|
|
23744
23814
|
action,
|
|
@@ -23799,7 +23869,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23799
23869
|
};
|
|
23800
23870
|
for (const resource of resources) {
|
|
23801
23871
|
const service = this.invocationServiceName(resource.service);
|
|
23802
|
-
if (this.isEncryptionNetworkOperation(service, resource.path)) {
|
|
23872
|
+
if (this.isEncryptionNetworkOperation(service, resource.path, resource.space)) {
|
|
23803
23873
|
rawAbilities[_a = resource.path] ?? (rawAbilities[_a] = []);
|
|
23804
23874
|
addActions(rawAbilities[resource.path], resource.actions);
|
|
23805
23875
|
continue;
|
|
@@ -23868,21 +23938,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23868
23938
|
}
|
|
23869
23939
|
return granted.spaceId !== void 0 && requested.spaceId !== void 0 && this.spaceIdsEqual(granted.spaceId, requested.spaceId) && this.pathContains(granted.path, requested.path);
|
|
23870
23940
|
}
|
|
23871
|
-
// Space IDs are `tinycloud:pkh:eip155:<chain>:<0xADDR>:<name>`.
|
|
23872
|
-
// EIP-155 address
|
|
23873
|
-
//
|
|
23874
|
-
// the EIP-55 checksummed form — so a byte-for-byte compare spuriously rejects
|
|
23875
|
-
// an otherwise-valid grant. Lowercase ONLY the `eip155:<chain>:0x<addr>`
|
|
23876
|
-
// segment and leave everything else (crucially the case-sensitive space NAME)
|
|
23877
|
-
// 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.
|
|
23878
23944
|
spaceIdsEqual(a, b) {
|
|
23879
23945
|
return this.normalizeSpaceAddress(a) === this.normalizeSpaceAddress(b);
|
|
23880
23946
|
}
|
|
23881
23947
|
normalizeSpaceAddress(space) {
|
|
23882
|
-
|
|
23883
|
-
|
|
23884
|
-
(_match, prefix, addr) => prefix + addr.toLowerCase()
|
|
23885
|
-
);
|
|
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]}`;
|
|
23886
23950
|
}
|
|
23887
23951
|
actionContains(grantedAction, requestedAction) {
|
|
23888
23952
|
if (grantedAction === requestedAction) {
|
|
@@ -23899,10 +23963,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23899
23963
|
}
|
|
23900
23964
|
/** Prefer the v2 caveat-preserving parser while retaining old custom WASM. */
|
|
23901
23965
|
parseRecapWithCaveats(siwe) {
|
|
23902
|
-
|
|
23966
|
+
const verified = this.wasmBindings.parseVerifiedRecapFromSiwe?.(siwe);
|
|
23967
|
+
return verified == null ? this.wasmBindings.parseRecapFromSiwe(siwe) : verifierRecapEntries(verified);
|
|
23903
23968
|
}
|
|
23904
|
-
isEncryptionNetworkOperation(service, path) {
|
|
23905
|
-
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:");
|
|
23906
23971
|
}
|
|
23907
23972
|
operationFromInvokeAnyEntry(entry) {
|
|
23908
23973
|
const service = this.invocationServiceName(entry.service);
|
|
@@ -23915,7 +23980,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23915
23980
|
...entry.caveats === void 0 ? {} : { caveats: cloneRecapCaveats(entry.caveats) }
|
|
23916
23981
|
};
|
|
23917
23982
|
}
|
|
23918
|
-
if (this.isEncryptionNetworkOperation(service, entry.path)) {
|
|
23983
|
+
if (entry.spaceId === void 0 && this.isEncryptionNetworkOperation(service, entry.path)) {
|
|
23919
23984
|
return {
|
|
23920
23985
|
resource: entry.path,
|
|
23921
23986
|
service,
|
|
@@ -24200,8 +24265,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24200
24265
|
const jwk = mySession.jwk;
|
|
24201
24266
|
const { abilities, rawAbilities } = this.buildActivationAbilities(delegation);
|
|
24202
24267
|
const now = /* @__PURE__ */ new Date();
|
|
24203
|
-
const
|
|
24204
|
-
const expirationTime = delegation.expiry < maxExpiry ? delegation.expiry : maxExpiry;
|
|
24268
|
+
const expirationTime = delegation.expiry;
|
|
24205
24269
|
const prepared = this.wasmBindings.prepareSession({
|
|
24206
24270
|
abilities,
|
|
24207
24271
|
address: this.wasmBindings.ensureEip55(mySession.address),
|
|
@@ -24305,8 +24369,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24305
24369
|
);
|
|
24306
24370
|
}
|
|
24307
24371
|
const now = /* @__PURE__ */ new Date();
|
|
24308
|
-
const
|
|
24309
|
-
const requestedExpiry = new Date(now.getTime() + expiryMs);
|
|
24372
|
+
const requestedExpiry = params.expiryMs === void 0 ? parentDelegation.expiry : new Date(now.getTime() + params.expiryMs);
|
|
24310
24373
|
const actualExpiry = requestedExpiry > parentDelegation.expiry ? parentDelegation.expiry : requestedExpiry;
|
|
24311
24374
|
const abilities = {};
|
|
24312
24375
|
const rawAbilities = {};
|
|
@@ -24979,6 +25042,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
24979
25042
|
FileSessionStorage,
|
|
24980
25043
|
HooksService,
|
|
24981
25044
|
IdentityParseError,
|
|
25045
|
+
InvalidRestoredSessionError,
|
|
24982
25046
|
KVService,
|
|
24983
25047
|
ManifestValidationError,
|
|
24984
25048
|
MemorySessionStorage,
|
|
@@ -25058,6 +25122,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
|
|
|
25058
25122
|
expandActionShortNames,
|
|
25059
25123
|
expandPermissionEntries,
|
|
25060
25124
|
expandPermissionEntry,
|
|
25125
|
+
extractSiweExpiration,
|
|
25061
25126
|
generateRandomReceiverKey,
|
|
25062
25127
|
getTinyCloudDebugLogs,
|
|
25063
25128
|
grantAuthRequest,
|