@tinycloud/node-sdk 3.8.0-beta.2 → 3.8.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/{TinyCloudNode-B6VOBrCb.d.ts → TinyCloudNode-DaD5vJhL.d.cts} +49 -6
- package/dist/{TinyCloudNode-CVO41O12.d.cts → TinyCloudNode-k3TbBwwj.d.ts} +49 -6
- package/dist/{WasmKeyProvider-5Ee7fcAw.d.cts → WasmKeyProvider-BKCPRC-c.d.cts} +21 -1
- package/dist/{WasmKeyProvider-5Ee7fcAw.d.ts → WasmKeyProvider-BKCPRC-c.d.ts} +21 -1
- package/dist/{authority-DGi1hIMK.d.ts → authority-C_fWaxAu.d.ts} +1 -1
- package/dist/{authority-DgVV80bI.d.cts → authority-DJdbZM6k.d.cts} +1 -1
- package/dist/core.cjs +375 -40
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +5 -4
- package/dist/core.d.ts +5 -4
- package/dist/core.js +370 -35
- package/dist/core.js.map +1 -1
- package/dist/credentials-core.d.cts +1 -1
- package/dist/credentials-core.d.ts +1 -1
- package/dist/credentials.d.cts +1 -1
- package/dist/credentials.d.ts +1 -1
- package/dist/{delegation-0LKZkmP2.d.cts → delegation-Ckc3UETl.d.cts} +1 -1
- package/dist/{delegation-0LKZkmP2.d.ts → delegation-Ckc3UETl.d.ts} +1 -1
- package/dist/encryption-keys.d.cts +2 -2
- package/dist/encryption-keys.d.ts +2 -2
- package/dist/index.cjs +343 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +333 -38
- package/dist/index.js.map +1 -1
- package/dist/replication/authority.cjs +3 -0
- package/dist/replication/authority.cjs.map +1 -1
- package/dist/replication/authority.d.cts +4 -3
- package/dist/replication/authority.d.ts +4 -3
- package/dist/replication/authority.js +3 -0
- package/dist/replication/authority.js.map +1 -1
- package/dist/replication/runtime.cjs +1 -0
- package/dist/replication/runtime.cjs.map +1 -1
- package/dist/replication/runtime.js +1 -0
- package/dist/replication/runtime.js.map +1 -1
- package/dist/share-receive.cjs +775 -0
- package/dist/share-receive.cjs.map +1 -0
- package/dist/share-receive.d.cts +32 -0
- package/dist/share-receive.d.ts +32 -0
- package/dist/share-receive.js +777 -0
- package/dist/share-receive.js.map +1 -0
- package/package.json +11 -4
package/dist/index.js
CHANGED
|
@@ -17099,6 +17099,9 @@ function assertValidReplicationConfig(replication) {
|
|
|
17099
17099
|
if (replication?.syncScope !== void 0 && replication.syncScope !== "prefixes") {
|
|
17100
17100
|
throw new TypeError('replication.syncScope must be "prefixes"');
|
|
17101
17101
|
}
|
|
17102
|
+
if (replication?.contentFetch !== void 0 && replication.contentFetch !== "eager" && replication.contentFetch !== "lazy") {
|
|
17103
|
+
throw new TypeError('replication.contentFetch must be "eager" or "lazy"');
|
|
17104
|
+
}
|
|
17102
17105
|
if (replication === void 0 || !replication.enabled) return;
|
|
17103
17106
|
if (replication.storage === void 0 || replication.storage === null) {
|
|
17104
17107
|
throw new TypeError("replication.enabled requires replication.storage");
|
|
@@ -17151,6 +17154,7 @@ function resolvedOptions(options) {
|
|
|
17151
17154
|
maxStalenessMs: options.maxStalenessMs ?? 12e4,
|
|
17152
17155
|
staleSyncTimeoutMs: options.staleSyncTimeoutMs ?? 5e3,
|
|
17153
17156
|
allowSecrets: options.allowSecrets === true,
|
|
17157
|
+
contentFetch: options.contentFetch ?? "eager",
|
|
17154
17158
|
verify: options.verify === true
|
|
17155
17159
|
};
|
|
17156
17160
|
}
|
|
@@ -18686,6 +18690,7 @@ function deserializeDelegation(data) {
|
|
|
18686
18690
|
|
|
18687
18691
|
// src/TinyCloudNode.ts
|
|
18688
18692
|
import { generateNonce, SiweMessage as SiweMessage3 } from "siwe";
|
|
18693
|
+
import { didKeyFromEd25519PublicKey } from "@tinycloud/share-envelope";
|
|
18689
18694
|
|
|
18690
18695
|
// src/replication/module-registry.ts
|
|
18691
18696
|
var nodeLoaders;
|
|
@@ -18734,10 +18739,13 @@ import {
|
|
|
18734
18739
|
ENCRYPTION_PERMISSION_SERVICE as ENCRYPTION_PERMISSION_SERVICE2,
|
|
18735
18740
|
CaveatedDelegationUnsupportedError as CaveatedDelegationUnsupportedError2,
|
|
18736
18741
|
PermissionNotInManifestError,
|
|
18742
|
+
ManifestValidationError as ManifestValidationError2,
|
|
18737
18743
|
SessionExpiredError,
|
|
18738
18744
|
canonicalizeRecapCaveats as canonicalizeRecapCaveats2,
|
|
18739
18745
|
recapCaveatsEqual as recapCaveatsEqual2,
|
|
18740
18746
|
expandPermissionEntries as expandPermissionEntriesCore,
|
|
18747
|
+
expandRuntimePermissionEntries,
|
|
18748
|
+
expandDelegationPermissionEntries,
|
|
18741
18749
|
isCapabilitySubset as isCapabilitySubset2,
|
|
18742
18750
|
isExplicitOnlyAction,
|
|
18743
18751
|
parseRecapCapabilities,
|
|
@@ -18768,6 +18776,7 @@ import {
|
|
|
18768
18776
|
withoutShareLink,
|
|
18769
18777
|
verifyEip191MessageSignature,
|
|
18770
18778
|
signCompactUcanRootAuthorization,
|
|
18779
|
+
signCompactUcanAuthorization,
|
|
18771
18780
|
markDelegationTerminal,
|
|
18772
18781
|
isStorageFullError,
|
|
18773
18782
|
STORAGE_FULL_MESSAGE,
|
|
@@ -18783,9 +18792,9 @@ import {
|
|
|
18783
18792
|
tinyCloudDebugLogger
|
|
18784
18793
|
} from "@tinycloud/sdk-services";
|
|
18785
18794
|
import { RequestLog, observeReplicaReads, readOnlyRequestLog } from "@tinycloud/sdk-services/telemetry/requestLog";
|
|
18795
|
+
import { parseEncryptionResource as parseEncryptionResource2 } from "@tinycloud/sdk-services/encryption/resource";
|
|
18786
18796
|
|
|
18787
18797
|
// src/authorization/NodeUserAuthorization.ts
|
|
18788
|
-
init_authority_sign_in();
|
|
18789
18798
|
import { createHash } from "crypto";
|
|
18790
18799
|
import { SiweMessage } from "siwe";
|
|
18791
18800
|
import {
|
|
@@ -18794,10 +18803,10 @@ import {
|
|
|
18794
18803
|
activateSessionWithHost,
|
|
18795
18804
|
checkNodeInfo,
|
|
18796
18805
|
AutoApproveSpaceCreationHandler,
|
|
18806
|
+
ManifestValidationError,
|
|
18797
18807
|
DEFAULT_MANIFEST_SPACE,
|
|
18798
18808
|
ENCRYPTION_PERMISSION_SERVICE,
|
|
18799
18809
|
composeManifestRequest,
|
|
18800
|
-
parseNetworkId,
|
|
18801
18810
|
principalDidEquals as principalDidEquals2,
|
|
18802
18811
|
resourceCapabilitiesToAbilitiesMap,
|
|
18803
18812
|
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
@@ -18825,6 +18834,47 @@ import {
|
|
|
18825
18834
|
HOOKS,
|
|
18826
18835
|
ENCRYPTION
|
|
18827
18836
|
} from "@tinycloud/sdk-core";
|
|
18837
|
+
import { parseEncryptionResource } from "@tinycloud/sdk-services/encryption/resource";
|
|
18838
|
+
import { parseNetworkId } from "@tinycloud/sdk-services";
|
|
18839
|
+
|
|
18840
|
+
// src/authorization/appKeyHostBinding.ts
|
|
18841
|
+
var DOMAIN_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
18842
|
+
var IPV4 = /^\d+\.\d+\.\d+\.\d+$/;
|
|
18843
|
+
var APP_ID = /^[a-z0-9][a-z0-9._-]{0,63}$/;
|
|
18844
|
+
function appKeyHostBinding(domain, appId) {
|
|
18845
|
+
if (!APP_ID.test(appId)) return false;
|
|
18846
|
+
if (domain.endsWith(":")) return false;
|
|
18847
|
+
let url;
|
|
18848
|
+
try {
|
|
18849
|
+
url = new URL(`https://${domain}`);
|
|
18850
|
+
} catch {
|
|
18851
|
+
return false;
|
|
18852
|
+
}
|
|
18853
|
+
if (url.protocol !== "https:" || url.port !== "" || url.username !== "" || url.password !== "") return false;
|
|
18854
|
+
if (url.pathname !== "/" || url.search !== "" || url.hash !== "") return false;
|
|
18855
|
+
const host = url.hostname;
|
|
18856
|
+
if (host.startsWith("[") || host.endsWith(".") || IPV4.test(host)) return false;
|
|
18857
|
+
const labels = host.split(".");
|
|
18858
|
+
if (labels.length < 2 || labels[labels.length - 1] === "localhost") return false;
|
|
18859
|
+
if (!labels.every((label) => DOMAIN_LABEL.test(label))) return false;
|
|
18860
|
+
const reversed = labels.reverse().join(".");
|
|
18861
|
+
return appId === reversed || appId.startsWith(`${reversed}.`);
|
|
18862
|
+
}
|
|
18863
|
+
function isAppKeyHostBound(keysAppId, origin) {
|
|
18864
|
+
if (typeof origin === "string" && !origin.includes("://")) {
|
|
18865
|
+
return appKeyHostBinding(origin, keysAppId);
|
|
18866
|
+
}
|
|
18867
|
+
let url;
|
|
18868
|
+
try {
|
|
18869
|
+
url = typeof origin === "string" ? new URL(origin) : origin;
|
|
18870
|
+
} catch {
|
|
18871
|
+
return false;
|
|
18872
|
+
}
|
|
18873
|
+
return appKeyHostBinding(url.host, keysAppId);
|
|
18874
|
+
}
|
|
18875
|
+
|
|
18876
|
+
// src/authorization/NodeUserAuthorization.ts
|
|
18877
|
+
init_authority_sign_in();
|
|
18828
18878
|
|
|
18829
18879
|
// src/authorization/caveatRefusal.ts
|
|
18830
18880
|
import {
|
|
@@ -18982,6 +19032,7 @@ function cloneAbilitiesMap(actions) {
|
|
|
18982
19032
|
var NodeUserAuthorization = class {
|
|
18983
19033
|
constructor(config) {
|
|
18984
19034
|
this.activeSessionKeyId = "default";
|
|
19035
|
+
this.preparedSessionCounter = 0;
|
|
18985
19036
|
/** Incremented by resetSession; a sign-in started earlier publishes nothing. */
|
|
18986
19037
|
this.sessionGeneration = 0;
|
|
18987
19038
|
/**
|
|
@@ -19338,6 +19389,23 @@ var NodeUserAuthorization = class {
|
|
|
19338
19389
|
);
|
|
19339
19390
|
return this._capabilityRequest;
|
|
19340
19391
|
}
|
|
19392
|
+
async refreshNamedKeyFeatureForSignIn(address, chainId) {
|
|
19393
|
+
const request = this.getCapabilityRequest();
|
|
19394
|
+
const siweDomain = this.siweConfig?.domain ?? this.domain;
|
|
19395
|
+
const hasNamedKeys = request?.manifests.some((manifest) => manifest.keys?.length && appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id));
|
|
19396
|
+
if (hasNamedKeys) {
|
|
19397
|
+
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
19398
|
+
await this.refreshNodeInfo();
|
|
19399
|
+
}
|
|
19400
|
+
}
|
|
19401
|
+
/** Manifest key paths that this sign-in cannot grant. */
|
|
19402
|
+
get unavailableKeyPaths() {
|
|
19403
|
+
const request = this.getCapabilityRequest();
|
|
19404
|
+
const siweDomain = this.siweConfig?.domain ?? this.domain;
|
|
19405
|
+
return (request?.manifests ?? []).flatMap(
|
|
19406
|
+
(manifest) => this._nodeFeatures.includes("encryption-named-keys-v1") && appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id) ? [] : (manifest.keys ?? []).map((entry) => "path" in entry ? entry.path : entry.prefix)
|
|
19407
|
+
);
|
|
19408
|
+
}
|
|
19341
19409
|
resolveSpaceName(space, address, chainId) {
|
|
19342
19410
|
if (space.startsWith("tinycloud:")) {
|
|
19343
19411
|
return space;
|
|
@@ -19529,15 +19597,32 @@ var NodeUserAuthorization = class {
|
|
|
19529
19597
|
}
|
|
19530
19598
|
const rawAbilities = {};
|
|
19531
19599
|
const currentDid = pkhDid(address, chainId);
|
|
19600
|
+
if (this._nodeFeatures.includes("encryption-named-keys-v1")) {
|
|
19601
|
+
const siweDomain = this.siweConfig?.domain ?? this.domain;
|
|
19602
|
+
for (const manifest of request.manifests) {
|
|
19603
|
+
if (!appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id)) continue;
|
|
19604
|
+
for (const declaration of manifest.keys ?? []) {
|
|
19605
|
+
const path = "path" in declaration ? declaration.path : declaration.prefix;
|
|
19606
|
+
const resource = `urn:tinycloud:encryption:${currentDid}:default/${path}`;
|
|
19607
|
+
for (const ability of declaration.abilities) {
|
|
19608
|
+
addRawAbility(rawAbilities, resource, `tinycloud.encryption/${ability}`);
|
|
19609
|
+
}
|
|
19610
|
+
}
|
|
19611
|
+
}
|
|
19612
|
+
}
|
|
19532
19613
|
const spaceResources = request.resources.filter((entry) => {
|
|
19533
19614
|
if (entry.service !== ENCRYPTION_PERMISSION_SERVICE) {
|
|
19534
19615
|
return true;
|
|
19535
19616
|
}
|
|
19617
|
+
const parsed = entry.path.includes("/") ? parseEncryptionResource(entry.path) : { ...parseNetworkId(entry.path), kind: "network" };
|
|
19618
|
+
const sharePrefix = parsed.kind === "prefix" && parsed.network === "default" && parsed.prefix === "share" && entry.actions.length === 1 && entry.actions[0] === DECRYPT_ACTION && didPrincipalMatches(parsed.ownerDid, currentDid);
|
|
19619
|
+
if (parsed.kind !== "network" && !sharePrefix) {
|
|
19620
|
+
throw new ManifestValidationError("named keys go in manifest.keys");
|
|
19621
|
+
}
|
|
19536
19622
|
for (const action of entry.actions) {
|
|
19537
19623
|
addRawAbility(rawAbilities, entry.path, action);
|
|
19538
19624
|
}
|
|
19539
|
-
if (entry.actions.includes(DECRYPT_ACTION)) {
|
|
19540
|
-
const parsed = parseNetworkId(entry.path);
|
|
19625
|
+
if (entry.actions.includes(DECRYPT_ACTION) && parsed.kind === "network") {
|
|
19541
19626
|
if (didPrincipalMatches(parsed.ownerDid, currentDid)) {
|
|
19542
19627
|
addRawAbility(rawAbilities, entry.path, NETWORK_CREATE_ACTION);
|
|
19543
19628
|
}
|
|
@@ -19574,8 +19659,7 @@ var NodeUserAuthorization = class {
|
|
|
19574
19659
|
/**
|
|
19575
19660
|
* Build SIWE overrides from the top-level nonce and siweConfig.
|
|
19576
19661
|
* - Top-level `nonce` is seeded first so `siweConfig.nonce` wins if both are set.
|
|
19577
|
-
* -
|
|
19578
|
-
* - resources are appended to the default resources
|
|
19662
|
+
* - resources are inserted after WASM preparation, before the final ReCap
|
|
19579
19663
|
* - uri triggers a warning (overwriting delegation target)
|
|
19580
19664
|
* - all other fields override directly
|
|
19581
19665
|
* - per-call nonce overrides siweConfig.nonce when provided
|
|
@@ -19593,9 +19677,6 @@ var NodeUserAuthorization = class {
|
|
|
19593
19677
|
if (statement) {
|
|
19594
19678
|
overrides.statement = this.statement ? `${statement} ${this.statement}` : statement;
|
|
19595
19679
|
}
|
|
19596
|
-
if (resources && resources.length > 0) {
|
|
19597
|
-
overrides.resources = resources;
|
|
19598
|
-
}
|
|
19599
19680
|
if (uri) {
|
|
19600
19681
|
console.warn(
|
|
19601
19682
|
"[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."
|
|
@@ -19607,6 +19688,29 @@ var NodeUserAuthorization = class {
|
|
|
19607
19688
|
}
|
|
19608
19689
|
return overrides;
|
|
19609
19690
|
}
|
|
19691
|
+
prepareSessionWithResources(params) {
|
|
19692
|
+
const resources = this.siweConfig?.resources;
|
|
19693
|
+
if (resources?.some((resource) => typeof resource !== "string" || !/^urn:tinycloud:recipients:[A-Za-z0-9_-]+$/.test(resource))) {
|
|
19694
|
+
throw new Error("SIWE metadata resources must be base64url recipients URIs");
|
|
19695
|
+
}
|
|
19696
|
+
const prepared = this.wasm.prepareSession(params);
|
|
19697
|
+
if (!resources?.length) return prepared;
|
|
19698
|
+
const recapLines = /^- urn:recap:[^\r\n]+$/gim;
|
|
19699
|
+
const recaps = prepared.siwe.match(recapLines);
|
|
19700
|
+
const recap = recaps?.[0];
|
|
19701
|
+
if (recaps?.length !== 1 || !prepared.siwe.endsWith(recap)) {
|
|
19702
|
+
throw new Error("Prepared SIWE must end with exactly one ReCap");
|
|
19703
|
+
}
|
|
19704
|
+
const insertedLines = resources.map((resource) => `- ${resource}`);
|
|
19705
|
+
const siwe = prepared.siwe.slice(0, -recap.length) + insertedLines.join("\n") + "\n" + recap;
|
|
19706
|
+
const expectedFields = extractImmutableSiweFields(prepared.siwe);
|
|
19707
|
+
expectedFields.nonRecapResources = [expectedFields.nonRecapResources, ...insertedLines].filter(Boolean).join("\n");
|
|
19708
|
+
const actualRecaps = siwe.match(recapLines);
|
|
19709
|
+
if (actualRecaps?.length !== 1 || actualRecaps[0] !== recap || diffImmutableSiweFields(expectedFields, extractImmutableSiweFields(siwe)).length) {
|
|
19710
|
+
throw new Error("SIWE metadata insertion changed the prepared message");
|
|
19711
|
+
}
|
|
19712
|
+
return { ...prepared, siwe };
|
|
19713
|
+
}
|
|
19610
19714
|
/**
|
|
19611
19715
|
* Add an extension to the authorization flow.
|
|
19612
19716
|
*/
|
|
@@ -19854,7 +19958,7 @@ var NodeUserAuthorization = class {
|
|
|
19854
19958
|
spaceAbilities[spaceId] = resourceCapabilitiesToAbilitiesMap(resources);
|
|
19855
19959
|
}
|
|
19856
19960
|
const abilities = spaceAbilities[options.spaceId] ?? resourceCapabilitiesToAbilitiesMap([]);
|
|
19857
|
-
const prepared = this.
|
|
19961
|
+
const prepared = this.prepareSessionWithResources({
|
|
19858
19962
|
abilities,
|
|
19859
19963
|
spaceAbilities,
|
|
19860
19964
|
...options.rawAbilities !== void 0 ? { rawAbilities: options.rawAbilities } : {},
|
|
@@ -19933,8 +20037,10 @@ var NodeUserAuthorization = class {
|
|
|
19933
20037
|
this._chainId = chainId;
|
|
19934
20038
|
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
19935
20039
|
this.assertSignInCurrent(generation);
|
|
19936
|
-
|
|
19937
|
-
this.
|
|
20040
|
+
await this.refreshNamedKeyFeatureForSignIn(address, chainId);
|
|
20041
|
+
this.assertSignInCurrent(generation);
|
|
20042
|
+
const keyId = `session-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
20043
|
+
this.sessionManager.createSessionKey(keyId);
|
|
19938
20044
|
this.activeSessionKeyId = keyId;
|
|
19939
20045
|
const jwkString = this.sessionManager.jwk(keyId);
|
|
19940
20046
|
if (!jwkString) {
|
|
@@ -19945,7 +20051,7 @@ var NodeUserAuthorization = class {
|
|
|
19945
20051
|
const spaceId = capabilityPlan.spaceId;
|
|
19946
20052
|
const now = /* @__PURE__ */ new Date();
|
|
19947
20053
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
19948
|
-
const prepared = this.
|
|
20054
|
+
const prepared = this.prepareSessionWithResources({
|
|
19949
20055
|
abilities: capabilityPlan.abilities,
|
|
19950
20056
|
...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
|
|
19951
20057
|
...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
|
|
@@ -20079,9 +20185,9 @@ var NodeUserAuthorization = class {
|
|
|
20079
20185
|
refuseCaveated(this.getCapabilityRequest()?.manifests);
|
|
20080
20186
|
const address = canonicalizeAddress(await this.signer.getAddress());
|
|
20081
20187
|
const chainId = await this.signer.getChainId();
|
|
20082
|
-
|
|
20083
|
-
|
|
20084
|
-
this.
|
|
20188
|
+
await this.refreshNamedKeyFeatureForSignIn(address, chainId);
|
|
20189
|
+
const keyId = `openkey-session-${Date.now()}-${++this.preparedSessionCounter}`;
|
|
20190
|
+
this.sessionManager.createSessionKey(keyId);
|
|
20085
20191
|
const jwkString = this.sessionManager.jwk(keyId);
|
|
20086
20192
|
if (!jwkString) {
|
|
20087
20193
|
throw new Error("Failed to create session key");
|
|
@@ -20091,7 +20197,7 @@ var NodeUserAuthorization = class {
|
|
|
20091
20197
|
const spaceId = capabilityPlan.spaceId;
|
|
20092
20198
|
const now = /* @__PURE__ */ new Date();
|
|
20093
20199
|
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
20094
|
-
const prepared = this.
|
|
20200
|
+
const prepared = this.prepareSessionWithResources({
|
|
20095
20201
|
abilities: capabilityPlan.abilities,
|
|
20096
20202
|
...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
|
|
20097
20203
|
...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
|
|
@@ -20162,6 +20268,7 @@ var NodeUserAuthorization = class {
|
|
|
20162
20268
|
await this.sessionStorage.save(address, persistedData);
|
|
20163
20269
|
this._session = clientSession;
|
|
20164
20270
|
this._tinyCloudSession = tinyCloudSession;
|
|
20271
|
+
this.activeSessionKeyId = keyId;
|
|
20165
20272
|
this._address = address;
|
|
20166
20273
|
this._chainId = chainId;
|
|
20167
20274
|
await this.refreshNodeInfo();
|
|
@@ -20208,6 +20315,11 @@ var NodeUserAuthorization = class {
|
|
|
20208
20315
|
* @param options Optional overrides for the OpenKey request.
|
|
20209
20316
|
*/
|
|
20210
20317
|
async signInWithOpenKey(authorizeFn, options) {
|
|
20318
|
+
const pending = await this.prepareOpenKeySignIn(options);
|
|
20319
|
+
return this.completeOpenKeySignIn(pending, authorizeFn(pending.request), options);
|
|
20320
|
+
}
|
|
20321
|
+
/** Finish address, host and SIWE preparation before an approval click. */
|
|
20322
|
+
async prepareOpenKeySignIn(options) {
|
|
20211
20323
|
refuseCaveated(this.getCapabilityRequest()?.manifests);
|
|
20212
20324
|
if (options?.host !== void 0) {
|
|
20213
20325
|
const overrideHost = options.host.trim();
|
|
@@ -20219,7 +20331,7 @@ var NodeUserAuthorization = class {
|
|
|
20219
20331
|
const signingAddress = canonicalizeAddress(await this.signer.getAddress());
|
|
20220
20332
|
const signingChainId = await this.signer.getChainId();
|
|
20221
20333
|
await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
|
|
20222
|
-
const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
|
|
20334
|
+
const { prepared, keyId, jwk, address, chainId } = await this.prepareSessionForSigning();
|
|
20223
20335
|
const presentation = this.buildPresentationEnvelope(options?.reason);
|
|
20224
20336
|
const hostHint = this.primaryTinyCloudHost;
|
|
20225
20337
|
const originalRequest = {
|
|
@@ -20231,12 +20343,32 @@ var NodeUserAuthorization = class {
|
|
|
20231
20343
|
keyId: options?.openkeyKeyId,
|
|
20232
20344
|
presentation
|
|
20233
20345
|
};
|
|
20346
|
+
return {
|
|
20347
|
+
request: originalRequest,
|
|
20348
|
+
prepared,
|
|
20349
|
+
keyId,
|
|
20350
|
+
jwk,
|
|
20351
|
+
address,
|
|
20352
|
+
chainId,
|
|
20353
|
+
generation: this.sessionGeneration,
|
|
20354
|
+
createdAt: Date.now()
|
|
20355
|
+
};
|
|
20356
|
+
}
|
|
20357
|
+
/** Complete a prepared approval. The caller starts authorization before awaiting this method. */
|
|
20358
|
+
async completeOpenKeySignIn(pending, authorization, options) {
|
|
20359
|
+
if (Date.now() - pending.createdAt > 5 * 6e4) {
|
|
20360
|
+
throw new Error("Prepared OpenKey sign-in expired; prepare again");
|
|
20361
|
+
}
|
|
20362
|
+
if (pending.generation !== this.sessionGeneration) {
|
|
20363
|
+
throw new Error("Prepared OpenKey sign-in expired after sign-out");
|
|
20364
|
+
}
|
|
20365
|
+
const { request: originalRequest, prepared, keyId, jwk } = pending;
|
|
20234
20366
|
let result;
|
|
20235
20367
|
let signed2;
|
|
20236
20368
|
let signature2;
|
|
20237
20369
|
for (let attempt = 0; ; ) {
|
|
20238
20370
|
try {
|
|
20239
|
-
result ?? (result = await
|
|
20371
|
+
result ?? (result = await authorization);
|
|
20240
20372
|
signed2 = await this.verifyOpenKeyResult(result, prepared);
|
|
20241
20373
|
signature2 = result.signature;
|
|
20242
20374
|
break;
|
|
@@ -21147,6 +21279,7 @@ var ROOT_DELEGATION_ACTIONS = [
|
|
|
21147
21279
|
DUCKDB2.ALL
|
|
21148
21280
|
];
|
|
21149
21281
|
var DEFAULT_SESSION_EXPIRATION_MS = EXPIRY3.SESSION_MS;
|
|
21282
|
+
var OWNER_REVOCATION_WINDOW_MS = 10 * 6e4;
|
|
21150
21283
|
function unifiedRootAttenuation(capabilities) {
|
|
21151
21284
|
const attenuation = {};
|
|
21152
21285
|
for (const capability of capabilities) {
|
|
@@ -21644,6 +21777,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21644
21777
|
constructor(config = {}) {
|
|
21645
21778
|
this.signer = null;
|
|
21646
21779
|
this.auth = null;
|
|
21780
|
+
this.consumedOpenKeyPendings = /* @__PURE__ */ new WeakSet();
|
|
21647
21781
|
this.tc = null;
|
|
21648
21782
|
this._chainId = 1;
|
|
21649
21783
|
this.replicaPurgeFailedHandlers = /* @__PURE__ */ new Set();
|
|
@@ -21678,6 +21812,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21678
21812
|
return void 0;
|
|
21679
21813
|
}
|
|
21680
21814
|
};
|
|
21815
|
+
this._keysUnavailable = [];
|
|
21681
21816
|
this._baseVaults = /* @__PURE__ */ new Map();
|
|
21682
21817
|
this._baseSecrets = /* @__PURE__ */ new Map();
|
|
21683
21818
|
this._secrets = /* @__PURE__ */ new Map();
|
|
@@ -22505,6 +22640,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22505
22640
|
this._hooks = void 0;
|
|
22506
22641
|
this._vault = void 0;
|
|
22507
22642
|
this._encryption = void 0;
|
|
22643
|
+
this._namedKeyClient = void 0;
|
|
22644
|
+
this._keysUnavailable = [];
|
|
22508
22645
|
this._baseVaults.clear();
|
|
22509
22646
|
this._baseSecrets.clear();
|
|
22510
22647
|
this._secrets.clear();
|
|
@@ -22581,6 +22718,37 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22581
22718
|
}
|
|
22582
22719
|
await this.signInWith(() => this.auth.signInWithOpenKey(authorizeFn, options));
|
|
22583
22720
|
}
|
|
22721
|
+
/** Prepare the OpenKey request before the approval click. */
|
|
22722
|
+
async prepareOpenKeySignIn() {
|
|
22723
|
+
if (!this.signer || !this.tc || !this.auth) {
|
|
22724
|
+
throw new Error("Cannot prepare OpenKey sign-in in session-only mode. Provide a signer in config.");
|
|
22725
|
+
}
|
|
22726
|
+
await this.signOutInFlight;
|
|
22727
|
+
await this.accountRegistryTail;
|
|
22728
|
+
await this.wasmBindings.ensureInitialized?.();
|
|
22729
|
+
return this.auth.prepareOpenKeySignIn();
|
|
22730
|
+
}
|
|
22731
|
+
/** Start OpenKey authorization synchronously, then complete normal session setup. */
|
|
22732
|
+
signInWithPreparedOpenKey(pending, authorizeFn) {
|
|
22733
|
+
if (!this.signer || !this.tc || !this.auth || this.signOutInFlight) {
|
|
22734
|
+
throw new Error("Prepared OpenKey sign-in is unavailable");
|
|
22735
|
+
}
|
|
22736
|
+
if (this.consumedOpenKeyPendings.has(pending)) {
|
|
22737
|
+
throw new Error("Prepared OpenKey sign-in was already used");
|
|
22738
|
+
}
|
|
22739
|
+
if (Date.now() - pending.createdAt > 5 * 6e4) {
|
|
22740
|
+
throw new Error("Prepared OpenKey sign-in expired; prepare again");
|
|
22741
|
+
}
|
|
22742
|
+
this.consumedOpenKeyPendings.add(pending);
|
|
22743
|
+
const authorization = authorizeFn(pending.request);
|
|
22744
|
+
void authorization.catch(() => void 0);
|
|
22745
|
+
return this.signInWith(() => {
|
|
22746
|
+
if (this._address !== pending.address || this._chainId !== pending.chainId) {
|
|
22747
|
+
throw new Error("OpenKey account changed after sign-in preparation");
|
|
22748
|
+
}
|
|
22749
|
+
return this.auth.completeOpenKeySignIn(pending, authorization);
|
|
22750
|
+
});
|
|
22751
|
+
}
|
|
22584
22752
|
async signInWith(performSignIn) {
|
|
22585
22753
|
refuseCaveated(this.auth?.capabilityRequest?.manifests);
|
|
22586
22754
|
const epoch = this.sessionEpoch;
|
|
@@ -22627,6 +22795,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22627
22795
|
this._hooks = void 0;
|
|
22628
22796
|
this._vault = void 0;
|
|
22629
22797
|
this._encryption = void 0;
|
|
22798
|
+
this._namedKeyClient = void 0;
|
|
22799
|
+
this._keysUnavailable = [];
|
|
22630
22800
|
this._baseVaults.clear();
|
|
22631
22801
|
this._baseSecrets.clear();
|
|
22632
22802
|
this._secrets.clear();
|
|
@@ -22679,6 +22849,26 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22679
22849
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
22680
22850
|
await this.ensureRequestedEncryptionNetworks();
|
|
22681
22851
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
22852
|
+
this._keysUnavailable = this.auth?.unavailableKeyPaths ?? [];
|
|
22853
|
+
if (this._keysUnavailable.length > 0) {
|
|
22854
|
+
this.notificationHandler.warning(`Named keys unavailable: ${this._keysUnavailable.join(", ")}`);
|
|
22855
|
+
}
|
|
22856
|
+
if (this.nodeFeatures.includes("encryption-named-keys-v1")) {
|
|
22857
|
+
for (const manifest of this.auth?.capabilityRequest?.manifests ?? []) {
|
|
22858
|
+
for (const declaration of manifest.keys ?? []) {
|
|
22859
|
+
if ("path" in declaration && declaration.abilities.includes("key.create") && !this._keysUnavailable.includes(declaration.path)) {
|
|
22860
|
+
try {
|
|
22861
|
+
await this.keys.ensureKey(declaration.path);
|
|
22862
|
+
} catch (error) {
|
|
22863
|
+
this._keysUnavailable.push(declaration.path);
|
|
22864
|
+
const code = error && typeof error === "object" && "code" in error && typeof error.code === "string" && /^[A-Z_]+$/.test(error.code) ? error.code : "UNKNOWN";
|
|
22865
|
+
this.notificationHandler.warning(`Named key unavailable: ${declaration.path} (${code})`);
|
|
22866
|
+
}
|
|
22867
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
22868
|
+
}
|
|
22869
|
+
}
|
|
22870
|
+
}
|
|
22871
|
+
}
|
|
22682
22872
|
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
22683
22873
|
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(SECRETS_SPACE2));
|
|
22684
22874
|
}
|
|
@@ -23466,7 +23656,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
23466
23656
|
const networkIds = /* @__PURE__ */ new Set();
|
|
23467
23657
|
for (const resource of request.resources) {
|
|
23468
23658
|
if (resource.service === ENCRYPTION_PERMISSION_SERVICE2 && resource.path.startsWith("urn:tinycloud:encryption:") && resource.actions.includes(DECRYPT_ACTION2)) {
|
|
23469
|
-
|
|
23659
|
+
const parsed = resource.path.includes("/") ? parseEncryptionResource2(resource.path) : { ...parseNetworkId2(resource.path), kind: "network" };
|
|
23660
|
+
if (parsed.kind === "network") networkIds.add(resource.path);
|
|
23470
23661
|
}
|
|
23471
23662
|
}
|
|
23472
23663
|
return [...networkIds];
|
|
@@ -24016,6 +24207,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24016
24207
|
this._hooks = stagedGraph.hooks;
|
|
24017
24208
|
this._vault = stagedGraph.vault;
|
|
24018
24209
|
this._encryption = stagedGraph.encryption;
|
|
24210
|
+
this._namedKeyClient = void 0;
|
|
24211
|
+
this._keysUnavailable = [];
|
|
24019
24212
|
this._capabilityRegistry = stagedGraph.capabilityRegistry;
|
|
24020
24213
|
this._keyProvider = stagedGraph.keyProvider;
|
|
24021
24214
|
this._sharingService = stagedGraph.sharingService;
|
|
@@ -24197,6 +24390,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24197
24390
|
invoke: graph.invoke,
|
|
24198
24391
|
invokeAny: graph.invokeAny,
|
|
24199
24392
|
signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
|
|
24393
|
+
sessionInvocationSigner: this.sessionInvocationSignerFor(input.serviceSession),
|
|
24200
24394
|
fetch: graph.fetch
|
|
24201
24395
|
});
|
|
24202
24396
|
const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
|
|
@@ -24412,6 +24606,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24412
24606
|
if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
|
|
24413
24607
|
return signBytesWithJwk(bytes, session.jwk);
|
|
24414
24608
|
}
|
|
24609
|
+
/**
|
|
24610
|
+
* Signs proofless invocations with `session`'s own did:key, for the node's
|
|
24611
|
+
* issued-delegation list and revocation by the delegator. The audience is
|
|
24612
|
+
* this Node's DID; each invocation lives 60 seconds.
|
|
24613
|
+
*/
|
|
24614
|
+
sessionInvocationSignerFor(session) {
|
|
24615
|
+
return {
|
|
24616
|
+
did: () => session.verificationMethod.split("#", 1)[0],
|
|
24617
|
+
sign: async (attenuation) => {
|
|
24618
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
24619
|
+
const invocation = await signCompactUcanAuthorization({
|
|
24620
|
+
issuerDid: session.verificationMethod.split("#", 1)[0],
|
|
24621
|
+
audienceDid: await this.fetchNodeId(),
|
|
24622
|
+
attenuation,
|
|
24623
|
+
facts: [{}],
|
|
24624
|
+
proofs: [],
|
|
24625
|
+
notBefore: now,
|
|
24626
|
+
expiresAt: now + 60,
|
|
24627
|
+
nonce: `urn:uuid:${crypto.randomUUID()}`,
|
|
24628
|
+
sign: (bytes) => signBytesWithJwk(bytes, session.jwk)
|
|
24629
|
+
});
|
|
24630
|
+
return invocation.authorization;
|
|
24631
|
+
}
|
|
24632
|
+
};
|
|
24633
|
+
}
|
|
24415
24634
|
/** Author a proofless Policy/v3 owner root with the authenticated holder key. */
|
|
24416
24635
|
async createUnifiedOwnerRoot(input) {
|
|
24417
24636
|
const ownerDid = this.credentialHolderDid;
|
|
@@ -24946,7 +25165,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24946
25165
|
graph.assertActive();
|
|
24947
25166
|
const signed2 = await this.signRawNetworkAuthorization({
|
|
24948
25167
|
targetNode: input.targetNode,
|
|
24949
|
-
networkId: input.networkId
|
|
25168
|
+
networkId: input.body.keyPath === void 0 ? input.networkId : `${input.networkId}/${input.body.keyPath}`,
|
|
24950
25169
|
action: DECRYPT_ACTION2,
|
|
24951
25170
|
facts: input.facts
|
|
24952
25171
|
}, { graph, session });
|
|
@@ -25119,6 +25338,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25119
25338
|
invoke: graph.invoke,
|
|
25120
25339
|
invokeAny: graph.invokeAny,
|
|
25121
25340
|
signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
|
|
25341
|
+
sessionInvocationSigner: this.sessionInvocationSignerFor(serviceSession),
|
|
25122
25342
|
fetch: graph.fetch
|
|
25123
25343
|
});
|
|
25124
25344
|
this._spaceService = new SpaceService({
|
|
@@ -25369,7 +25589,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25369
25589
|
* Sign a wallet (CACAO) revocation of the delegation `cid` for the node's
|
|
25370
25590
|
* `POST /revoke`, and return its Authorization header value. The node
|
|
25371
25591
|
* accepts it when the owner delegated `cid` or owns a space its abilities
|
|
25372
|
-
* target, whichever key issued it. Valid for
|
|
25592
|
+
* target, whichever key issued it. Valid for 10 minutes. Requires the
|
|
25373
25593
|
* owner wallet signer.
|
|
25374
25594
|
*/
|
|
25375
25595
|
async signOwnerRevocation(cid) {
|
|
@@ -25385,7 +25605,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25385
25605
|
chainId: session.chainId,
|
|
25386
25606
|
nonce: generateNonce(),
|
|
25387
25607
|
issuedAt: issuedAt.toISOString(),
|
|
25388
|
-
expirationTime: new Date(issuedAt.getTime() +
|
|
25608
|
+
expirationTime: new Date(issuedAt.getTime() + OWNER_REVOCATION_WINDOW_MS).toISOString()
|
|
25389
25609
|
}).prepareMessage();
|
|
25390
25610
|
const signature2 = await this.signer.signMessage(siwe);
|
|
25391
25611
|
return this.wasmBindings.siweToDelegationHeaders({ siwe, signature: signature2 }).Authorization;
|
|
@@ -25612,6 +25832,40 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25612
25832
|
get encryption() {
|
|
25613
25833
|
return this.getEncryptionService();
|
|
25614
25834
|
}
|
|
25835
|
+
/** Named keys bound to the current session. */
|
|
25836
|
+
get keys() {
|
|
25837
|
+
return new Proxy({}, {
|
|
25838
|
+
get: (_target, property) => {
|
|
25839
|
+
if (property === "refreshNodeInfo") {
|
|
25840
|
+
return () => {
|
|
25841
|
+
void this._namedKeyClient?.then((client) => client.refreshNodeInfo());
|
|
25842
|
+
};
|
|
25843
|
+
}
|
|
25844
|
+
if (typeof property !== "string" || ![
|
|
25845
|
+
"getPublicKey",
|
|
25846
|
+
"describeKey",
|
|
25847
|
+
"createKey",
|
|
25848
|
+
"blockKey",
|
|
25849
|
+
"unblockKey",
|
|
25850
|
+
"ensureKey",
|
|
25851
|
+
"encrypt",
|
|
25852
|
+
"decrypt",
|
|
25853
|
+
"decryptMany"
|
|
25854
|
+
].includes(property)) return void 0;
|
|
25855
|
+
return (...args) => {
|
|
25856
|
+
this._namedKeyClient ?? (this._namedKeyClient = import("./encryption-keys.js").then(({ createNamedKeyClient }) => createNamedKeyClient(this)));
|
|
25857
|
+
return this._namedKeyClient.then((client) => {
|
|
25858
|
+
const method = client[property];
|
|
25859
|
+
return method.apply(client, args);
|
|
25860
|
+
});
|
|
25861
|
+
};
|
|
25862
|
+
}
|
|
25863
|
+
});
|
|
25864
|
+
}
|
|
25865
|
+
/** Manifest key paths unavailable during the latest `signIn()` attempt. */
|
|
25866
|
+
get keysUnavailable() {
|
|
25867
|
+
return this._keysUnavailable;
|
|
25868
|
+
}
|
|
25615
25869
|
async getEncryptionNetwork(nameOrNetworkId = this.getDefaultEncryptionNetworkId()) {
|
|
25616
25870
|
const networkId = nameOrNetworkId.startsWith("urn:tinycloud:encryption:") ? nameOrNetworkId : this.getDefaultEncryptionNetworkId(nameOrNetworkId);
|
|
25617
25871
|
return this.fetchEncryptionNetworkAt(
|
|
@@ -25868,7 +26122,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25868
26122
|
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
25869
26123
|
return false;
|
|
25870
26124
|
}
|
|
25871
|
-
const expanded =
|
|
26125
|
+
const expanded = expandRuntimePermissionEntries(permissions, pkhDid2(session.address, session.chainId));
|
|
25872
26126
|
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
25873
26127
|
return true;
|
|
25874
26128
|
}
|
|
@@ -25888,7 +26142,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
25888
26142
|
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
25889
26143
|
return [];
|
|
25890
26144
|
}
|
|
25891
|
-
const expanded =
|
|
26145
|
+
const expanded = expandRuntimePermissionEntries(permissions, pkhDid2(session.address, session.chainId));
|
|
25892
26146
|
return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
|
|
25893
26147
|
(grant) => grant.delegation
|
|
25894
26148
|
);
|
|
@@ -26063,7 +26317,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26063
26317
|
throw new SessionExpiredError(sessionExpiry);
|
|
26064
26318
|
}
|
|
26065
26319
|
}
|
|
26066
|
-
const expanded =
|
|
26320
|
+
const expanded = expandRuntimePermissionEntries(permissions, pkhDid2(session.address, session.chainId));
|
|
26321
|
+
const bindsShareKey = expanded.some((entry) => entry.service === ENCRYPTION_PERMISSION_SERVICE2 && entry.actions.includes("tinycloud.encryption/key.create"));
|
|
26322
|
+
const captured = bindsShareKey ? { ...session, jwk: { ...options?.expectedSessionKey ?? session.jwk } } : session;
|
|
26323
|
+
const assertCapturedKey = bindsShareKey ? () => {
|
|
26324
|
+
const live = session.jwk;
|
|
26325
|
+
const key2 = captured.jwk;
|
|
26326
|
+
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 !== key2.kty || live?.crv !== key2.crv || live?.x !== key2.x || live?.y !== key2.y || live?.d !== key2.d) {
|
|
26327
|
+
throw new Error("Runtime permission request cancelled because the session key changed.");
|
|
26328
|
+
}
|
|
26329
|
+
} : void 0;
|
|
26330
|
+
const sessionKeyDid = bindsShareKey ? this.sessionDid : void 0;
|
|
26331
|
+
if (bindsShareKey) {
|
|
26332
|
+
const key2 = captured.jwk;
|
|
26333
|
+
if (key2.kty !== "OKP" || key2.crv !== "Ed25519" || typeof key2.x !== "string") {
|
|
26334
|
+
throw new Error("Runtime permission session key does not match its signed identity.");
|
|
26335
|
+
}
|
|
26336
|
+
const keyDid = didKeyFromEd25519PublicKey(base64UrlDecode(key2.x));
|
|
26337
|
+
if (!didPrincipalMatches2(keyDid, sessionKeyDid) || !didPrincipalMatches2(keyDid, captured.verificationMethod) || !didPrincipalMatches2(keyDid, new SiweMessage3(session.siwe).uri)) {
|
|
26338
|
+
throw new Error("Runtime permission session key does not match its signed identity.");
|
|
26339
|
+
}
|
|
26340
|
+
assertCapturedKey();
|
|
26341
|
+
}
|
|
26067
26342
|
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
26068
26343
|
return [];
|
|
26069
26344
|
}
|
|
@@ -26113,13 +26388,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26113
26388
|
return this.wasmBindings.prepareSession({
|
|
26114
26389
|
abilities,
|
|
26115
26390
|
...rawForDelegation.length > 0 ? { rawAbilities: this.permissionsToRawAbilities(rawForDelegation) } : {},
|
|
26116
|
-
address: this.wasmBindings.ensureEip55(
|
|
26117
|
-
chainId:
|
|
26391
|
+
address: this.wasmBindings.ensureEip55(captured.address),
|
|
26392
|
+
chainId: captured.chainId,
|
|
26118
26393
|
domain: this.siweDomain,
|
|
26119
26394
|
issuedAt: now.toISOString(),
|
|
26120
26395
|
expirationTime: expiresAt.toISOString(),
|
|
26121
26396
|
spaceId,
|
|
26122
|
-
jwk:
|
|
26397
|
+
jwk: captured.jwk
|
|
26123
26398
|
});
|
|
26124
26399
|
} catch (error) {
|
|
26125
26400
|
if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && /invalid ReCap resource URI/i.test(error instanceof Error ? error.message : String(error))) {
|
|
@@ -26131,8 +26406,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26131
26406
|
throw error;
|
|
26132
26407
|
}
|
|
26133
26408
|
})();
|
|
26409
|
+
if (bindsShareKey && !didPrincipalMatches2(new SiweMessage3(prepared.siwe).uri, sessionKeyDid)) {
|
|
26410
|
+
throw new Error("Prepared runtime permission targets a different session key.");
|
|
26411
|
+
}
|
|
26412
|
+
assertCapturedKey?.();
|
|
26134
26413
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
26135
26414
|
graph.assertActive();
|
|
26415
|
+
assertCapturedKey?.();
|
|
26136
26416
|
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
26137
26417
|
...prepared,
|
|
26138
26418
|
signature: signature2
|
|
@@ -26161,18 +26441,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26161
26441
|
delegatedSession,
|
|
26162
26442
|
delegatedEntries,
|
|
26163
26443
|
spaceId,
|
|
26164
|
-
|
|
26444
|
+
captured,
|
|
26165
26445
|
expiresAt,
|
|
26166
26446
|
{ siwe: prepared.siwe, signature: signature2 }
|
|
26167
26447
|
);
|
|
26168
26448
|
graph.assertActive();
|
|
26449
|
+
assertCapturedKey?.();
|
|
26169
26450
|
this.runtimePermissionGrants.push({
|
|
26170
26451
|
session: {
|
|
26171
26452
|
delegationHeader: delegatedSession.delegationHeader,
|
|
26172
26453
|
delegationCid: delegatedSession.delegationCid,
|
|
26173
26454
|
spaceId,
|
|
26174
|
-
verificationMethod:
|
|
26175
|
-
jwk:
|
|
26455
|
+
verificationMethod: captured.verificationMethod,
|
|
26456
|
+
jwk: captured.jwk
|
|
26176
26457
|
},
|
|
26177
26458
|
delegation,
|
|
26178
26459
|
operations: this.permissionOperations(delegatedEntries, spaceId),
|
|
@@ -26501,7 +26782,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26501
26782
|
"delegateTo requires a non-empty permissions array"
|
|
26502
26783
|
);
|
|
26503
26784
|
}
|
|
26504
|
-
const expandedEntries =
|
|
26785
|
+
const expandedEntries = expandDelegationPermissionEntries(permissions);
|
|
26786
|
+
const namedKeyEntries = expandedEntries.filter((entry) => entry.service === ENCRYPTION_PERMISSION_SERVICE2 && entry.path.includes("/"));
|
|
26787
|
+
if (namedKeyEntries.length > 0) {
|
|
26788
|
+
if (expandedEntries.some((entry) => entry.service === ENCRYPTION_PERMISSION_SERVICE2 && !entry.path.includes("/"))) {
|
|
26789
|
+
throw new ManifestValidationError2("named-key delegation cannot include bare-network permissions");
|
|
26790
|
+
}
|
|
26791
|
+
if (options?.forceWalletSign) {
|
|
26792
|
+
throw new ManifestValidationError2("named-key delegation requires a signed session grant");
|
|
26793
|
+
}
|
|
26794
|
+
const granted = this.projectSignedRecapCapabilities(session.siwe);
|
|
26795
|
+
const { subset, missing } = this.signedCapabilitySubset(namedKeyEntries, granted);
|
|
26796
|
+
if (!subset) throw new PermissionNotInManifestError(missing, granted);
|
|
26797
|
+
}
|
|
26505
26798
|
const now = /* @__PURE__ */ new Date();
|
|
26506
26799
|
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
26507
26800
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
@@ -28051,7 +28344,7 @@ var FileSessionStorage = class {
|
|
|
28051
28344
|
};
|
|
28052
28345
|
|
|
28053
28346
|
// src/authorization/openKeyBridge.ts
|
|
28054
|
-
function wireOpenKeyAuthorize(openkey) {
|
|
28347
|
+
function wireOpenKeyAuthorize(openkey, opts) {
|
|
28055
28348
|
return async (input) => {
|
|
28056
28349
|
const result = await openkey.authorizeTinyCloud({
|
|
28057
28350
|
protocolVersion: 1,
|
|
@@ -28062,7 +28355,7 @@ function wireOpenKeyAuthorize(openkey) {
|
|
|
28062
28355
|
// Forward the presentation envelope verbatim — the OpenKey SDK
|
|
28063
28356
|
// validates and size-bounds it before use.
|
|
28064
28357
|
presentation: input.presentation
|
|
28065
|
-
});
|
|
28358
|
+
}, opts);
|
|
28066
28359
|
if (result.protocolVersion !== 1) {
|
|
28067
28360
|
throw new Error(
|
|
28068
28361
|
`wireOpenKeyAuthorize: OpenKey returned unsupported protocolVersion ${result.protocolVersion}`
|
|
@@ -28104,7 +28397,7 @@ import {
|
|
|
28104
28397
|
CaveatedDelegationUnsupportedError as CaveatedDelegationUnsupportedError3,
|
|
28105
28398
|
PermissionNotInManifestError as PermissionNotInManifestError2,
|
|
28106
28399
|
SessionExpiredError as SessionExpiredError2,
|
|
28107
|
-
ManifestValidationError,
|
|
28400
|
+
ManifestValidationError as ManifestValidationError3,
|
|
28108
28401
|
composeManifestRequest as composeManifestRequest2,
|
|
28109
28402
|
resolveManifest as resolveManifest2,
|
|
28110
28403
|
validateManifest,
|
|
@@ -29249,7 +29542,8 @@ var SqliteReplicaHandle = class {
|
|
|
29249
29542
|
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
29250
29543
|
const engine = new (__privateGet(this, _replica)).Replica({
|
|
29251
29544
|
store: __privateGet(this, _store),
|
|
29252
|
-
transportFor
|
|
29545
|
+
transportFor,
|
|
29546
|
+
...this.spec.contentFetch === void 0 ? {} : { contentFetch: this.spec.contentFetch }
|
|
29253
29547
|
});
|
|
29254
29548
|
const running = engine.sync({ signal: abort.signal });
|
|
29255
29549
|
const registration = { promise: running, abort: () => abort.abort() };
|
|
@@ -30768,7 +31062,7 @@ export {
|
|
|
30768
31062
|
InvalidRestoredSessionError,
|
|
30769
31063
|
KVService4 as KVService,
|
|
30770
31064
|
MAX_SECRET_SCOPE_LENGTH,
|
|
30771
|
-
ManifestValidationError,
|
|
31065
|
+
ManifestValidationError3 as ManifestValidationError,
|
|
30772
31066
|
MemorySessionStorage,
|
|
30773
31067
|
NETWORK_NAME_PATTERN,
|
|
30774
31068
|
NetworkIdError,
|
|
@@ -30865,6 +31159,7 @@ export {
|
|
|
30865
31159
|
hexDecode,
|
|
30866
31160
|
hexEncode,
|
|
30867
31161
|
installTinyCloudDebugGlobals,
|
|
31162
|
+
isAppKeyHostBound,
|
|
30868
31163
|
isCapabilitySubset4 as isCapabilitySubset,
|
|
30869
31164
|
isEvmAddress,
|
|
30870
31165
|
isNetworkId,
|