@tinycloud/sdk-core 2.11.0 → 3.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{unified-BlXXf3l7.d.cts → credential-admission-C_cO1QqB.d.cts} +353 -1
- package/dist/{unified-HWqC-h7O.d.ts → credential-admission-cvHe-HUC.d.ts} +353 -1
- package/dist/delegations/index.cjs +10 -10
- package/dist/delegations/index.cjs.map +1 -1
- package/dist/delegations/index.d.cts +2 -2
- package/dist/delegations/index.d.ts +2 -2
- package/dist/delegations/index.js +10 -10
- package/dist/delegations/index.js.map +1 -1
- package/dist/index.cjs +534 -167
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -242
- package/dist/index.d.ts +6 -242
- package/dist/index.js +536 -169
- package/dist/index.js.map +1 -1
- package/dist/policy/index.cjs +420 -14
- package/dist/policy/index.cjs.map +1 -1
- package/dist/policy/index.d.cts +2 -2
- package/dist/policy/index.d.ts +2 -2
- package/dist/policy/index.js +420 -14
- package/dist/policy/index.js.map +1 -1
- package/dist/{recipient-types.schema-CieclU3Z.d.cts → recipient-types.schema-G8NEKRoo.d.cts} +8 -8
- package/dist/{recipient-types.schema-CieclU3Z.d.ts → recipient-types.schema-G8NEKRoo.d.ts} +8 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -138,6 +138,7 @@ __export(index_exports, {
|
|
|
138
138
|
OPENKEY_ACTION_ID_SEPARATOR: () => OPENKEY_ACTION_ID_SEPARATOR,
|
|
139
139
|
POLICY_CAPABILITY_V1_DOMAIN: () => POLICY_CAPABILITY_V1_DOMAIN,
|
|
140
140
|
POLICY_CAPABILITY_V1_SCHEMA: () => POLICY_CAPABILITY_V1_SCHEMA,
|
|
141
|
+
POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE: () => POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE,
|
|
141
142
|
POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA: () => POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA,
|
|
142
143
|
POLICY_ENGINE_CHALLENGE_REQUEST_SCHEMA: () => POLICY_ENGINE_CHALLENGE_REQUEST_SCHEMA,
|
|
143
144
|
POLICY_ENGINE_CHALLENGE_RESPONSE_SCHEMA: () => POLICY_ENGINE_CHALLENGE_RESPONSE_SCHEMA,
|
|
@@ -145,11 +146,15 @@ __export(index_exports, {
|
|
|
145
146
|
POLICY_ENGINE_GRANT_PRESENTATION_DENIAL_CODES: () => POLICY_ENGINE_GRANT_PRESENTATION_DENIAL_CODES,
|
|
146
147
|
POLICY_ENGINE_RECORD_SCHEMA: () => POLICY_ENGINE_RECORD_SCHEMA,
|
|
147
148
|
POLICY_ENGINE_RESOLVE_REQUEST_SCHEMA: () => POLICY_ENGINE_RESOLVE_REQUEST_SCHEMA,
|
|
149
|
+
POLICY_PRESENTATION_V3_DOMAIN: () => POLICY_PRESENTATION_V3_DOMAIN,
|
|
150
|
+
POLICY_PRESENTATION_V3_SCHEMA: () => POLICY_PRESENTATION_V3_SCHEMA,
|
|
148
151
|
POLICY_SCHEMA: () => POLICY_SCHEMA,
|
|
149
152
|
POLICY_SESSION_UCAN_V1_PROFILE: () => POLICY_SESSION_UCAN_V1_PROFILE,
|
|
150
153
|
POLICY_STATUS_SCHEMA: () => POLICY_STATUS_SCHEMA,
|
|
151
154
|
POLICY_V1_DOMAIN: () => POLICY_V1_DOMAIN,
|
|
152
155
|
POLICY_V1_SCHEMA: () => POLICY_V1_SCHEMA,
|
|
156
|
+
POLICY_V2_DOMAIN: () => POLICY_V2_DOMAIN,
|
|
157
|
+
POLICY_V2_SCHEMA: () => POLICY_V2_SCHEMA,
|
|
153
158
|
PORTABLE_DELEGATION_SCHEMA: () => PORTABLE_DELEGATION_SCHEMA,
|
|
154
159
|
PermissionNotInManifestError: () => PermissionNotInManifestError,
|
|
155
160
|
PrefixedKVService: () => import_sdk_services8.PrefixedKVService,
|
|
@@ -217,6 +222,7 @@ __export(index_exports, {
|
|
|
217
222
|
actionContains: () => actionContains,
|
|
218
223
|
activateSessionWithHost: () => activateSessionWithHost,
|
|
219
224
|
addressStorageKey: () => addressStorageKey,
|
|
225
|
+
admitPolicyCredentialV3: () => admitPolicyCredentialV3,
|
|
220
226
|
applyPrefix: () => applyPrefix,
|
|
221
227
|
bootstrapEncryptionNetworkId: () => import_bootstrap4.bootstrapEncryptionNetworkId,
|
|
222
228
|
bootstrapSpaceId: () => import_bootstrap4.bootstrapSpaceId,
|
|
@@ -226,6 +232,7 @@ __export(index_exports, {
|
|
|
226
232
|
buildDecryptFacts: () => import_sdk_services8.buildDecryptFacts,
|
|
227
233
|
buildDecryptInvocation: () => import_sdk_services8.buildDecryptInvocation,
|
|
228
234
|
buildNetworkId: () => import_sdk_services8.buildNetworkId,
|
|
235
|
+
buildPolicyCredentialPresentationV3: () => buildPolicyCredentialPresentationV3,
|
|
229
236
|
buildSpaceUri: () => buildSpaceUri,
|
|
230
237
|
canonicalDigest: () => canonicalDigest,
|
|
231
238
|
canonicalHashHex: () => import_sdk_services8.canonicalHashHex,
|
|
@@ -365,6 +372,7 @@ __export(index_exports, {
|
|
|
365
372
|
policyCidFromCanonicalBytes: () => policyCidFromCanonicalBytes,
|
|
366
373
|
policyDigestHex: () => policyDigestHex,
|
|
367
374
|
policyIdForDigestHex: () => policyIdForDigestHex,
|
|
375
|
+
policyV2DigestHex: () => policyV2DigestHex,
|
|
368
376
|
principalDid: () => principalDid,
|
|
369
377
|
principalDidEquals: () => principalDidEquals,
|
|
370
378
|
projectUnifiedPolicyCapabilities: () => projectUnifiedPolicyCapabilities,
|
|
@@ -388,6 +396,7 @@ __export(index_exports, {
|
|
|
388
396
|
shareCapabilityAllows: () => shareCapabilityAllows,
|
|
389
397
|
shareDeliveryTrustedKid: () => shareDeliveryTrustedKid,
|
|
390
398
|
signCompactUcanAuthorization: () => signCompactUcanAuthorization,
|
|
399
|
+
signCompactUcanRootAuthorization: () => signCompactUcanRootAuthorization,
|
|
391
400
|
signLocationRecord: () => signLocationRecord,
|
|
392
401
|
signShareEnvelope: () => signShareEnvelope,
|
|
393
402
|
signedObjectIdFor: () => signedObjectIdFor,
|
|
@@ -411,6 +420,7 @@ __export(index_exports, {
|
|
|
411
420
|
validateOwnerSharePolicyRegistration: () => validateOwnerSharePolicyRegistration,
|
|
412
421
|
validateOwnerSharePolicyRegistrationBytes: () => validateOwnerSharePolicyRegistrationBytes,
|
|
413
422
|
validatePersistedSessionData: () => validatePersistedSessionData,
|
|
423
|
+
validatePolicyCredentialRequirementV1: () => validatePolicyCredentialRequirementV1,
|
|
414
424
|
validatePolicyEngineRecordSigned: () => validatePolicyEngineRecordSigned,
|
|
415
425
|
validatePolicyEngineRecordSignedShape: () => validatePolicyEngineRecordSignedShape,
|
|
416
426
|
validatePolicyEngineRecordUnsigned: () => validatePolicyEngineRecordUnsigned,
|
|
@@ -421,6 +431,7 @@ __export(index_exports, {
|
|
|
421
431
|
validatePolicyStatusUnsigned: () => validatePolicyStatusUnsigned,
|
|
422
432
|
validatePolicyUnsigned: () => validatePolicyUnsigned,
|
|
423
433
|
validateShareDeliveryAuthorizationBytes: () => validateShareDeliveryAuthorizationBytes,
|
|
434
|
+
validateUnifiedPolicyV2: () => validateUnifiedPolicyV2,
|
|
424
435
|
verifyDecryptResponse: () => import_sdk_services8.verifyDecryptResponse,
|
|
425
436
|
verifyDidKeyEd25519Signature: () => verifyDidKeyEd25519Signature,
|
|
426
437
|
verifyEip191MessageSignature: () => verifyEip191MessageSignature,
|
|
@@ -740,6 +751,7 @@ var CREDENTIAL_ERROR_CODES = [
|
|
|
740
751
|
"REQUEST_SUBSTITUTED",
|
|
741
752
|
"SIGNATURE_REJECTED",
|
|
742
753
|
"UNSUPPORTED_PROFILE",
|
|
754
|
+
"UNSUPPORTED_VERSION",
|
|
743
755
|
"VERIFICATION_FAILED",
|
|
744
756
|
"VERIFIED_NOT_SAVED"
|
|
745
757
|
];
|
|
@@ -751,6 +763,7 @@ var RECOVERABLE = /* @__PURE__ */ new Set([
|
|
|
751
763
|
"REQUEST_EXPIRED",
|
|
752
764
|
"SIGNATURE_REJECTED",
|
|
753
765
|
"UNSUPPORTED_PROFILE",
|
|
766
|
+
"UNSUPPORTED_VERSION",
|
|
754
767
|
"VERIFIED_NOT_SAVED"
|
|
755
768
|
]);
|
|
756
769
|
var CredentialError = class extends Error {
|
|
@@ -1038,11 +1051,11 @@ async function createStoredCredentialRecord(input) {
|
|
|
1038
1051
|
const recordId = await canonicalDigest({ credentialDigest: input.verified.credentialDigest, holderDid: input.ownerDid });
|
|
1039
1052
|
return Object.freeze({ type: "TinyCloudStoredCredential", version: 1, ownerDid: input.ownerDid, recordId, requirementDigest: input.requirementDigest, descriptorDigest: input.verified.descriptorDigest, profile: input.verified.profile, credentialType: input.verified.credentialType, issuerDid: input.verified.issuerDid, issuerKid: input.verified.issuerKid, holderDid: input.verified.holderDid, claims: input.verified.claims, claimsDigest: input.verified.claimsDigest, credentialDigest: input.verified.credentialDigest, credential: input.verified.credential, schema: input.verified.schema, credentialId: input.verified.credentialId, issuedAt: input.verified.issuedAt, notBefore: input.verified.notBefore, expiresAt: input.verified.expiresAt, status: input.verified.status, verifiedAt: input.verified.verifiedAt, storedAt });
|
|
1040
1053
|
}
|
|
1041
|
-
async function createStorageReceipt(
|
|
1042
|
-
return Object.freeze({ type: "TinyCloudCredentialStorageReceipt", version: 1, ownerDid:
|
|
1054
|
+
async function createStorageReceipt(record2, etag) {
|
|
1055
|
+
return Object.freeze({ type: "TinyCloudCredentialStorageReceipt", version: 1, ownerDid: record2.ownerDid, recordId: record2.recordId, recordDigest: await canonicalDigest(record2), storedAt: record2.storedAt, ...etag === void 0 ? {} : { etag } });
|
|
1043
1056
|
}
|
|
1044
|
-
async function verifyStorageReceipt(
|
|
1045
|
-
return receipt.type === "TinyCloudCredentialStorageReceipt" && receipt.version === 1 && receipt.ownerDid === activeOwnerDid &&
|
|
1057
|
+
async function verifyStorageReceipt(record2, receipt, activeOwnerDid, activeHolderDid) {
|
|
1058
|
+
return receipt.type === "TinyCloudCredentialStorageReceipt" && receipt.version === 1 && receipt.ownerDid === activeOwnerDid && record2.ownerDid === activeOwnerDid && record2.holderDid === activeHolderDid && receipt.recordId === record2.recordId && receipt.storedAt === record2.storedAt && receipt.recordDigest === await canonicalDigest(record2);
|
|
1046
1059
|
}
|
|
1047
1060
|
|
|
1048
1061
|
// src/credentials/verification.ts
|
|
@@ -3601,13 +3614,13 @@ function base64UrlDecode(value) {
|
|
|
3601
3614
|
return decoded;
|
|
3602
3615
|
}
|
|
3603
3616
|
function hexToBytes(value) {
|
|
3604
|
-
const
|
|
3605
|
-
if (
|
|
3617
|
+
const hex3 = value.slice(2);
|
|
3618
|
+
if (hex3.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex3)) {
|
|
3606
3619
|
throw new SignatureMaterialError("hex signature must have even length");
|
|
3607
3620
|
}
|
|
3608
|
-
const output = new Uint8Array(
|
|
3621
|
+
const output = new Uint8Array(hex3.length / 2);
|
|
3609
3622
|
for (let index = 0; index < output.length; index++) {
|
|
3610
|
-
output[index] = Number.parseInt(
|
|
3623
|
+
output[index] = Number.parseInt(hex3.slice(index * 2, index * 2 + 2), 16);
|
|
3611
3624
|
}
|
|
3612
3625
|
return output;
|
|
3613
3626
|
}
|
|
@@ -3847,6 +3860,34 @@ var ROOT_REVOCATION_V1_DOMAIN = "xyz.tinycloud.policy/RootRevocation/v1\0";
|
|
|
3847
3860
|
var LAST_V2_CREATE_AT = "2026-09-30T00:00:00Z";
|
|
3848
3861
|
var MAX_LEGACY_ENVELOPE_EXPIRES_AT = "2026-12-29T00:00:00Z";
|
|
3849
3862
|
var LAST_V2_READ_AT = "2027-01-05T00:00:00Z";
|
|
3863
|
+
async function requestPolicyChallengeV3(input) {
|
|
3864
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3865
|
+
const response = await fetchFn(new URL("/share/v3/policy/challenges", input.nodeOrigin), {
|
|
3866
|
+
method: "POST",
|
|
3867
|
+
redirect: "error",
|
|
3868
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
3869
|
+
body: JSON.stringify({ policyCid: input.policyCid, recipientDid: input.recipientDid, requestedCapabilities: input.requestedCapabilities.map(normalizeUnifiedPolicyCapability) })
|
|
3870
|
+
});
|
|
3871
|
+
if (!response.ok) throw new Error(`policy challenge rejected (${response.status})`);
|
|
3872
|
+
const value = object2(await response.json(), "policy challenge");
|
|
3873
|
+
if (typeof value.challengeId !== "string" || typeof value.nonce !== "string" || value.policyCid !== input.policyCid || value.recipientDid !== input.recipientDid)
|
|
3874
|
+
throw new Error("policy challenge binding is invalid");
|
|
3875
|
+
return value;
|
|
3876
|
+
}
|
|
3877
|
+
function compactAttenuationForPolicyCapabilities(input) {
|
|
3878
|
+
const attenuation = {};
|
|
3879
|
+
for (const raw of input) {
|
|
3880
|
+
const capability = normalizeUnifiedPolicyCapability(raw);
|
|
3881
|
+
if (attenuation[capability.resource] !== void 0)
|
|
3882
|
+
throw new Error("policy capabilities contain a duplicate resource");
|
|
3883
|
+
attenuation[capability.resource] = capability.kind === "encryption" ? { [capability.action]: [{}] } : Object.fromEntries(capability.actions.map((action) => [action, [{
|
|
3884
|
+
type: "xyz.tinycloud.resource/selector",
|
|
3885
|
+
kind: capability.selector,
|
|
3886
|
+
value: capability.resource
|
|
3887
|
+
}]]));
|
|
3888
|
+
}
|
|
3889
|
+
return attenuation;
|
|
3890
|
+
}
|
|
3850
3891
|
function verifyPolicyRootStatusCheckpointV3(input) {
|
|
3851
3892
|
const checkpoint = input.checkpoint;
|
|
3852
3893
|
const allowed = /* @__PURE__ */ new Set(["schema", "targetCid", "targetRole", "ownerDid", "nodeAudience", "state", "sequence", "checkedAt", "freshUntil", "revokedAt", "revocationCid", "previousCheckpointDigestHex", "issuerDid", "signature"]);
|
|
@@ -4016,11 +4057,15 @@ function nonEmptyString(value, label) {
|
|
|
4016
4057
|
return value;
|
|
4017
4058
|
}
|
|
4018
4059
|
function parseKvResource(resource) {
|
|
4019
|
-
const
|
|
4020
|
-
|
|
4060
|
+
const marker = resource.indexOf("/kv/");
|
|
4061
|
+
const encodedSpace = marker < 1 ? "" : resource.slice(0, marker);
|
|
4062
|
+
const legacy = encodedSpace.startsWith("tinycloud://");
|
|
4063
|
+
const space = legacy ? encodedSpace.slice("tinycloud://".length) : encodedSpace;
|
|
4064
|
+
const path = marker < 1 ? "" : resource.slice(marker + 4);
|
|
4065
|
+
if (marker < 1 || (legacy ? /[:/?#%]/.test(space) : !encodedSpace.startsWith("tinycloud:") || /[/?#%]/.test(encodedSpace)) || path.startsWith("/") || path.endsWith("/") || path.includes("//") || path.split("/").some((part) => part === "." || part === ".." || part.length === 0)) {
|
|
4021
4066
|
throw new Error("KV resource is not canonical");
|
|
4022
4067
|
}
|
|
4023
|
-
return { space
|
|
4068
|
+
return { space, path };
|
|
4024
4069
|
}
|
|
4025
4070
|
function parseEncryptionResource(resource) {
|
|
4026
4071
|
if (!resource.startsWith("urn:tinycloud:encryption:")) throw new Error("encryption capability is invalid");
|
|
@@ -4165,7 +4210,7 @@ function unifiedPolicyCapabilityFromNative(input) {
|
|
|
4165
4210
|
throw new Error("native capability is not supported");
|
|
4166
4211
|
const caveat = object2(value.caveat, "native.caveat");
|
|
4167
4212
|
exactKeys(caveat, ["type", "kind", "value"], "native selector caveat");
|
|
4168
|
-
if (caveat.type !== "xyz.tinycloud.resource/selector" || caveat.kind !== "exact" && caveat.kind !== "prefix" || caveat.value !== `tinycloud://${value.space}/kv/${value.path}`)
|
|
4213
|
+
if (caveat.type !== "xyz.tinycloud.resource/selector" || caveat.kind !== "exact" && caveat.kind !== "prefix" || caveat.value !== `${value.space.startsWith("tinycloud:") ? value.space : `tinycloud://${value.space}`}/kv/${value.path}`)
|
|
4169
4214
|
throw new Error("native selector caveat does not match capability");
|
|
4170
4215
|
return normalizeUnifiedPolicyCapability({
|
|
4171
4216
|
kind: "kv",
|
|
@@ -4224,9 +4269,7 @@ var CompactPayloadSchema = import_zod2.z.object({
|
|
|
4224
4269
|
nnc: import_zod2.z.string().min(1),
|
|
4225
4270
|
prf: import_zod2.z.array(import_zod2.z.string().min(1))
|
|
4226
4271
|
}).strict();
|
|
4227
|
-
async function
|
|
4228
|
-
if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore > 60)
|
|
4229
|
-
throw new Error("compact invocation lifetime must be between one and 60 seconds");
|
|
4272
|
+
async function signCompactUcan(input) {
|
|
4230
4273
|
const principal = input.issuerDid.split("#", 1)[0];
|
|
4231
4274
|
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
4232
4275
|
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
@@ -4248,6 +4291,16 @@ async function signCompactUcanAuthorization(input) {
|
|
|
4248
4291
|
if (signature.length !== 64) throw new Error("compact Authorization signature must be Ed25519");
|
|
4249
4292
|
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url2(signature)}`);
|
|
4250
4293
|
}
|
|
4294
|
+
async function signCompactUcanAuthorization(input) {
|
|
4295
|
+
if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore > 60)
|
|
4296
|
+
throw new Error("compact invocation lifetime must be between one and 60 seconds");
|
|
4297
|
+
return signCompactUcan(input);
|
|
4298
|
+
}
|
|
4299
|
+
async function signCompactUcanRootAuthorization(input) {
|
|
4300
|
+
if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore > 31 * 24 * 60 * 60)
|
|
4301
|
+
throw new Error("compact policy root lifetime must be between one second and 31 days");
|
|
4302
|
+
return signCompactUcan({ ...input, proofs: [] });
|
|
4303
|
+
}
|
|
4251
4304
|
function createCompactPolicyInvocation(input) {
|
|
4252
4305
|
const session = parsePolicySessionUcan(input.sessionAuthorization);
|
|
4253
4306
|
if (session.cid !== input.sessionCid || session.aud !== input.recipientDid)
|
|
@@ -4394,14 +4447,14 @@ function decodeBase64Url2(value) {
|
|
|
4394
4447
|
if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1)
|
|
4395
4448
|
throw new Error("value is not canonical base64url");
|
|
4396
4449
|
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
4397
|
-
const binary = typeof
|
|
4450
|
+
const binary = typeof atob === "function" ? atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "=")) : Buffer.from(normalized, "base64").toString("binary");
|
|
4398
4451
|
const bytes2 = Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
4399
|
-
const encoded = typeof
|
|
4452
|
+
const encoded = typeof btoa === "function" ? btoa(String.fromCharCode(...bytes2)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_") : Buffer.from(bytes2).toString("base64url");
|
|
4400
4453
|
if (encoded !== value) throw new Error("value is not canonical base64url");
|
|
4401
4454
|
return bytes2;
|
|
4402
4455
|
}
|
|
4403
4456
|
function encodeBase64Url2(value) {
|
|
4404
|
-
return typeof
|
|
4457
|
+
return typeof btoa === "function" ? btoa(String.fromCharCode(...value)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_") : Buffer.from(value).toString("base64url");
|
|
4405
4458
|
}
|
|
4406
4459
|
function equalBytes(left, right) {
|
|
4407
4460
|
return left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
@@ -4426,6 +4479,320 @@ function base32Lower(bytes2) {
|
|
|
4426
4479
|
return output;
|
|
4427
4480
|
}
|
|
4428
4481
|
|
|
4482
|
+
// src/policy/credential-admission.ts
|
|
4483
|
+
var import_ed255194 = require("@noble/curves/ed25519");
|
|
4484
|
+
var import_sha2562 = require("@noble/hashes/sha256");
|
|
4485
|
+
var POLICY_V2_SCHEMA = "xyz.tinycloud.policy/policy/v2";
|
|
4486
|
+
var POLICY_V2_DOMAIN = "xyz.tinycloud.policy/policy/v2\0";
|
|
4487
|
+
var POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE = "TinyCloudPolicyCredentialRequirement";
|
|
4488
|
+
var POLICY_PRESENTATION_V3_SCHEMA = "xyz.tinycloud.policy/presentation/v3";
|
|
4489
|
+
var POLICY_PRESENTATION_V3_DOMAIN = "xyz.tinycloud.policy/Presentation/v3\0";
|
|
4490
|
+
function record(value, label) {
|
|
4491
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
4492
|
+
throw new Error(`${label} must be an object`);
|
|
4493
|
+
}
|
|
4494
|
+
return value;
|
|
4495
|
+
}
|
|
4496
|
+
function exactKeys2(value, keys, label) {
|
|
4497
|
+
const expected = [...keys].sort();
|
|
4498
|
+
const actual = Object.keys(value).sort();
|
|
4499
|
+
if (actual.length !== expected.length || actual.some((key, index) => key !== expected[index])) {
|
|
4500
|
+
throw new Error(`${label} contains an unknown or missing field`);
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
function nonEmpty(value, label) {
|
|
4504
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
4505
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
4506
|
+
}
|
|
4507
|
+
return value;
|
|
4508
|
+
}
|
|
4509
|
+
function policyNodeOrigin(value) {
|
|
4510
|
+
let url;
|
|
4511
|
+
try {
|
|
4512
|
+
url = new URL(value);
|
|
4513
|
+
} catch {
|
|
4514
|
+
throw new Error("policy node origin is invalid");
|
|
4515
|
+
}
|
|
4516
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.pathname !== "/" || url.search !== "" || url.hash !== "") {
|
|
4517
|
+
throw new Error("policy node origin is invalid");
|
|
4518
|
+
}
|
|
4519
|
+
return url.origin;
|
|
4520
|
+
}
|
|
4521
|
+
function versionPair(value, label) {
|
|
4522
|
+
const item = record(value, label);
|
|
4523
|
+
exactKeys2(item, ["id", "version"], label);
|
|
4524
|
+
if (item.version !== 1) throw new Error(`${label} version is unsupported`);
|
|
4525
|
+
return Object.freeze({ id: nonEmpty(item.id, `${label}.id`), version: 1 });
|
|
4526
|
+
}
|
|
4527
|
+
function validatePolicyCredentialRequirementV1(value) {
|
|
4528
|
+
const item = record(value, "policy credential requirement");
|
|
4529
|
+
exactKeys2(
|
|
4530
|
+
item,
|
|
4531
|
+
[
|
|
4532
|
+
"type",
|
|
4533
|
+
"version",
|
|
4534
|
+
"requirementDigest",
|
|
4535
|
+
"descriptorDigest",
|
|
4536
|
+
"issuerDid",
|
|
4537
|
+
"issuerKid",
|
|
4538
|
+
"profile",
|
|
4539
|
+
"credentialType"
|
|
4540
|
+
],
|
|
4541
|
+
"policy credential requirement"
|
|
4542
|
+
);
|
|
4543
|
+
if (item.type !== POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE || item.version !== 1 || !isDigest(item.requirementDigest) || !isDigest(item.descriptorDigest)) {
|
|
4544
|
+
throw new Error("policy credential requirement is invalid");
|
|
4545
|
+
}
|
|
4546
|
+
return Object.freeze({
|
|
4547
|
+
type: POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE,
|
|
4548
|
+
version: 1,
|
|
4549
|
+
requirementDigest: item.requirementDigest,
|
|
4550
|
+
descriptorDigest: item.descriptorDigest,
|
|
4551
|
+
issuerDid: nonEmpty(item.issuerDid, "policy credential issuer"),
|
|
4552
|
+
issuerKid: nonEmpty(item.issuerKid, "policy credential issuer key"),
|
|
4553
|
+
profile: versionPair(item.profile, "policy credential profile"),
|
|
4554
|
+
credentialType: versionPair(
|
|
4555
|
+
item.credentialType,
|
|
4556
|
+
"policy credential type"
|
|
4557
|
+
)
|
|
4558
|
+
});
|
|
4559
|
+
}
|
|
4560
|
+
function hex2(bytes2) {
|
|
4561
|
+
return [...bytes2].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
4562
|
+
}
|
|
4563
|
+
function policyV2DigestHex(input) {
|
|
4564
|
+
const canonicalPolicy = {
|
|
4565
|
+
...input,
|
|
4566
|
+
credentialRequirement: validatePolicyCredentialRequirementV1(
|
|
4567
|
+
input.credentialRequirement
|
|
4568
|
+
),
|
|
4569
|
+
capabilityCeiling: input.capabilityCeiling.map(
|
|
4570
|
+
normalizeUnifiedPolicyCapability
|
|
4571
|
+
)
|
|
4572
|
+
};
|
|
4573
|
+
return hex2(
|
|
4574
|
+
(0, import_sha2562.sha256)(
|
|
4575
|
+
new TextEncoder().encode(
|
|
4576
|
+
POLICY_V2_DOMAIN + jcsCanonicalize(canonicalPolicy)
|
|
4577
|
+
)
|
|
4578
|
+
)
|
|
4579
|
+
);
|
|
4580
|
+
}
|
|
4581
|
+
function date(value, label) {
|
|
4582
|
+
const text2 = nonEmpty(value, label);
|
|
4583
|
+
if (!Number.isFinite(Date.parse(text2))) throw new Error(`${label} is invalid`);
|
|
4584
|
+
return text2;
|
|
4585
|
+
}
|
|
4586
|
+
function rfc3339Seconds(value) {
|
|
4587
|
+
return new Date(Math.floor(value.getTime() / 1e3) * 1e3).toISOString().replace(/\.000Z$/, "Z");
|
|
4588
|
+
}
|
|
4589
|
+
function validateUnifiedPolicyV2(value, expectedPolicyCid) {
|
|
4590
|
+
const item = record(value, "Policy/v2");
|
|
4591
|
+
const allowed = [
|
|
4592
|
+
"schema",
|
|
4593
|
+
"policyId",
|
|
4594
|
+
"ownerDid",
|
|
4595
|
+
"createdAt",
|
|
4596
|
+
"contentSource",
|
|
4597
|
+
"capabilityCeiling",
|
|
4598
|
+
"credentialRequirement",
|
|
4599
|
+
"signature",
|
|
4600
|
+
...item.expiresAt === void 0 ? [] : ["expiresAt"]
|
|
4601
|
+
];
|
|
4602
|
+
exactKeys2(item, allowed, "Policy/v2");
|
|
4603
|
+
if (item.schema !== POLICY_V2_SCHEMA || !Array.isArray(item.capabilityCeiling)) {
|
|
4604
|
+
throw new Error("Policy/v2 is invalid");
|
|
4605
|
+
}
|
|
4606
|
+
const ownerDid = nonEmpty(item.ownerDid, "Policy/v2 ownerDid");
|
|
4607
|
+
const signature = record(item.signature, "Policy/v2 signature");
|
|
4608
|
+
exactKeys2(signature, ["suite", "signerDid", "value"], "Policy/v2 signature");
|
|
4609
|
+
if (signature.suite !== "Ed25519" || signature.signerDid !== ownerDid || typeof signature.value !== "string" || signature.value.length === 0) {
|
|
4610
|
+
throw new Error("Policy/v2 signature binding is invalid");
|
|
4611
|
+
}
|
|
4612
|
+
const policy = Object.freeze({
|
|
4613
|
+
schema: POLICY_V2_SCHEMA,
|
|
4614
|
+
policyId: nonEmpty(item.policyId, "Policy/v2 policyId"),
|
|
4615
|
+
ownerDid,
|
|
4616
|
+
createdAt: date(item.createdAt, "Policy/v2 createdAt"),
|
|
4617
|
+
...item.expiresAt === void 0 ? {} : { expiresAt: date(item.expiresAt, "Policy/v2 expiresAt") },
|
|
4618
|
+
contentSource: item.contentSource,
|
|
4619
|
+
capabilityCeiling: Object.freeze(
|
|
4620
|
+
item.capabilityCeiling.map(normalizeUnifiedPolicyCapability)
|
|
4621
|
+
),
|
|
4622
|
+
credentialRequirement: validatePolicyCredentialRequirementV1(
|
|
4623
|
+
item.credentialRequirement
|
|
4624
|
+
),
|
|
4625
|
+
signature: Object.freeze({
|
|
4626
|
+
suite: "Ed25519",
|
|
4627
|
+
signerDid: ownerDid,
|
|
4628
|
+
value: signature.value
|
|
4629
|
+
})
|
|
4630
|
+
});
|
|
4631
|
+
const unsigned = { ...policy };
|
|
4632
|
+
delete unsigned.policyId;
|
|
4633
|
+
delete unsigned.signature;
|
|
4634
|
+
const digestHex = policyV2DigestHex(unsigned);
|
|
4635
|
+
if (policy.policyId !== policyIdForDigestHex(digestHex)) {
|
|
4636
|
+
throw new Error("Policy/v2 policyId binding is invalid");
|
|
4637
|
+
}
|
|
4638
|
+
if (expectedPolicyCid !== void 0) {
|
|
4639
|
+
const cid2 = policyCidFromCanonicalBytes(
|
|
4640
|
+
new TextEncoder().encode(jcsCanonicalize(policy))
|
|
4641
|
+
);
|
|
4642
|
+
if (cid2 !== expectedPolicyCid) throw new Error("Policy/v2 CID binding is invalid");
|
|
4643
|
+
}
|
|
4644
|
+
return policy;
|
|
4645
|
+
}
|
|
4646
|
+
function didKeyBytes(did) {
|
|
4647
|
+
const principal = did.split("#", 1)[0];
|
|
4648
|
+
if (!principal.startsWith("did:key:")) throw new Error("holder DID must be did:key");
|
|
4649
|
+
const material = base58btc.decode(principal.slice("did:key:".length));
|
|
4650
|
+
if (material.length !== 34 || material[0] !== 237 || material[1] !== 1) {
|
|
4651
|
+
throw new Error("holder DID must contain an Ed25519 key");
|
|
4652
|
+
}
|
|
4653
|
+
return material.slice(2);
|
|
4654
|
+
}
|
|
4655
|
+
function envelopeFromVerified(verified) {
|
|
4656
|
+
const {
|
|
4657
|
+
verifiedAt: _verifiedAt,
|
|
4658
|
+
credentialDigest: _credentialDigest,
|
|
4659
|
+
statusCheckedAt: _statusCheckedAt,
|
|
4660
|
+
...envelope
|
|
4661
|
+
} = verified;
|
|
4662
|
+
return envelope;
|
|
4663
|
+
}
|
|
4664
|
+
async function buildPolicyCredentialPresentationV3(input) {
|
|
4665
|
+
const policy = validateUnifiedPolicyV2(input.policy, input.policyCid);
|
|
4666
|
+
const requirement = validateCredentialRequirement(input.requirement);
|
|
4667
|
+
const commitment = policy.credentialRequirement;
|
|
4668
|
+
const requirementDigest = await credentialRequirementDigest(requirement);
|
|
4669
|
+
const credentialDigest = await sha256Base64Url(input.credential.credential);
|
|
4670
|
+
if (requirementDigest !== commitment.requirementDigest || input.credential.descriptorDigest !== commitment.descriptorDigest || input.credential.credentialDigest !== credentialDigest || input.credential.issuerDid !== commitment.issuerDid || input.credential.issuerKid !== commitment.issuerKid || jcsCanonicalize(input.credential.profile) !== jcsCanonicalize(commitment.profile) || jcsCanonicalize(input.credential.credentialType) !== jcsCanonicalize(commitment.credentialType)) {
|
|
4671
|
+
throw new Error("credential does not match the signed Policy/v2 requirement");
|
|
4672
|
+
}
|
|
4673
|
+
const requestedCapabilities = input.requestedCapabilities.map(
|
|
4674
|
+
normalizeUnifiedPolicyCapability
|
|
4675
|
+
);
|
|
4676
|
+
if (requestedCapabilities.length === 0 || requestedCapabilities.some(
|
|
4677
|
+
(requested) => !policy.capabilityCeiling.some(
|
|
4678
|
+
(authority) => unifiedPolicyCapabilityContains(authority, requested)
|
|
4679
|
+
)
|
|
4680
|
+
)) {
|
|
4681
|
+
throw new Error("requested capabilities exceed the signed Policy/v2 ceiling");
|
|
4682
|
+
}
|
|
4683
|
+
const challenge = input.challenge;
|
|
4684
|
+
const holderDid = input.credential.holderDid;
|
|
4685
|
+
if (challenge.policyCid !== input.policyCid || challenge.recipientDid !== holderDid || input.credential.subjectDid !== holderDid || typeof challenge.nodeAudience !== "string" || challenge.nodeAudience.length === 0 || typeof challenge.expiresAt !== "string" || !Number.isFinite(Date.parse(challenge.expiresAt))) {
|
|
4686
|
+
throw new Error("policy challenge binding is invalid");
|
|
4687
|
+
}
|
|
4688
|
+
didKeyBytes(holderDid);
|
|
4689
|
+
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
4690
|
+
const challengeExpiry = Date.parse(challenge.expiresAt);
|
|
4691
|
+
const credentialExpiry = Date.parse(input.credential.expiresAt);
|
|
4692
|
+
const expiresAtMs = Math.min(
|
|
4693
|
+
now.getTime() + 6e4,
|
|
4694
|
+
challengeExpiry,
|
|
4695
|
+
credentialExpiry
|
|
4696
|
+
);
|
|
4697
|
+
if (expiresAtMs <= now.getTime()) throw new Error("policy challenge is expired");
|
|
4698
|
+
const unsigned = Object.freeze({
|
|
4699
|
+
schema: POLICY_PRESENTATION_V3_SCHEMA,
|
|
4700
|
+
jti: input.jti ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
4701
|
+
challengeId: challenge.challengeId,
|
|
4702
|
+
nonce: challenge.nonce,
|
|
4703
|
+
policyCid: input.policyCid,
|
|
4704
|
+
nodeAudience: challenge.nodeAudience,
|
|
4705
|
+
holderDid,
|
|
4706
|
+
subjectDid: input.credential.subjectDid,
|
|
4707
|
+
credentialSpaceOwnerDid: nonEmpty(
|
|
4708
|
+
input.credentialSpaceOwnerDid,
|
|
4709
|
+
"credential space owner DID"
|
|
4710
|
+
),
|
|
4711
|
+
credentialDigest,
|
|
4712
|
+
requirementDigest,
|
|
4713
|
+
descriptorDigest: input.credential.descriptorDigest,
|
|
4714
|
+
requestedCapabilities: Object.freeze(requestedCapabilities),
|
|
4715
|
+
issuedAt: rfc3339Seconds(now),
|
|
4716
|
+
expiresAt: rfc3339Seconds(new Date(expiresAtMs))
|
|
4717
|
+
});
|
|
4718
|
+
const digest4 = (0, import_sha2562.sha256)(
|
|
4719
|
+
new TextEncoder().encode(
|
|
4720
|
+
POLICY_PRESENTATION_V3_DOMAIN + jcsCanonicalize(unsigned)
|
|
4721
|
+
)
|
|
4722
|
+
);
|
|
4723
|
+
const signature = await input.sign(digest4);
|
|
4724
|
+
if (signature.length !== 64 || !import_ed255194.ed25519.verify(signature, digest4, didKeyBytes(holderDid))) {
|
|
4725
|
+
throw new Error("policy presentation signature is invalid");
|
|
4726
|
+
}
|
|
4727
|
+
return Object.freeze({
|
|
4728
|
+
...unsigned,
|
|
4729
|
+
signature: Object.freeze({
|
|
4730
|
+
suite: "Ed25519",
|
|
4731
|
+
signerDid: holderDid,
|
|
4732
|
+
value: encodeBase64Url(signature)
|
|
4733
|
+
})
|
|
4734
|
+
});
|
|
4735
|
+
}
|
|
4736
|
+
async function admitPolicyCredentialV3(input) {
|
|
4737
|
+
const policy = validateUnifiedPolicyV2(input.policy, input.policyCid);
|
|
4738
|
+
const nodeOrigin = policyNodeOrigin(input.nodeOrigin);
|
|
4739
|
+
const accountAuthorizationCid = nonEmpty(
|
|
4740
|
+
input.accountAuthorizationCid,
|
|
4741
|
+
"account authorization CID"
|
|
4742
|
+
);
|
|
4743
|
+
const credentialSpaceId = nonEmpty(
|
|
4744
|
+
input.credentialSpaceId,
|
|
4745
|
+
"credential space ID"
|
|
4746
|
+
);
|
|
4747
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
4748
|
+
const challenge = await requestPolicyChallengeV3({
|
|
4749
|
+
nodeOrigin,
|
|
4750
|
+
policyCid: input.policyCid,
|
|
4751
|
+
recipientDid: input.credential.holderDid,
|
|
4752
|
+
requestedCapabilities: input.requestedCapabilities,
|
|
4753
|
+
fetch: fetchFn
|
|
4754
|
+
});
|
|
4755
|
+
const presentation = await buildPolicyCredentialPresentationV3({
|
|
4756
|
+
...input,
|
|
4757
|
+
policy,
|
|
4758
|
+
challenge
|
|
4759
|
+
});
|
|
4760
|
+
const response = await fetchFn(
|
|
4761
|
+
new URL("/share/v3/policy/delegations", nodeOrigin),
|
|
4762
|
+
{
|
|
4763
|
+
method: "POST",
|
|
4764
|
+
redirect: "error",
|
|
4765
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
4766
|
+
body: JSON.stringify({
|
|
4767
|
+
policyCid: input.policyCid,
|
|
4768
|
+
challengeId: challenge.challengeId,
|
|
4769
|
+
nonce: challenge.nonce,
|
|
4770
|
+
requirement: validateCredentialRequirement(input.requirement),
|
|
4771
|
+
credential: envelopeFromVerified(input.credential),
|
|
4772
|
+
accountAuthorizationCid,
|
|
4773
|
+
credentialSpaceId,
|
|
4774
|
+
presentation
|
|
4775
|
+
})
|
|
4776
|
+
}
|
|
4777
|
+
);
|
|
4778
|
+
if (!response.ok) throw new Error(`policy delegation rejected (${response.status})`);
|
|
4779
|
+
const value = record(await response.json(), "policy delegation");
|
|
4780
|
+
if (value.admitted !== true || typeof value.sessionCid !== "string" || typeof value.authorization !== "string") {
|
|
4781
|
+
throw new Error("policy delegation response is invalid");
|
|
4782
|
+
}
|
|
4783
|
+
const session = parsePolicySessionUcan(value.authorization, [
|
|
4784
|
+
input.policyRootCid,
|
|
4785
|
+
input.enforcementRootCid
|
|
4786
|
+
]);
|
|
4787
|
+
const expectedAttenuation = compactAttenuationForPolicyCapabilities(
|
|
4788
|
+
input.requestedCapabilities
|
|
4789
|
+
);
|
|
4790
|
+
if (session.cid !== value.sessionCid || session.aud !== input.credential.holderDid || session.fact.policyCid !== input.policyCid || session.fact.recipientDid !== input.credential.holderDid || session.fact.policyDelegationCid !== input.policyRootCid || session.fact.enforcementDelegationCid !== input.enforcementRootCid || jcsCanonicalize(session.att) !== jcsCanonicalize(expectedAttenuation)) {
|
|
4791
|
+
throw new Error("policy delegation signed binding is invalid");
|
|
4792
|
+
}
|
|
4793
|
+
return Object.freeze({ challenge, presentation, session });
|
|
4794
|
+
}
|
|
4795
|
+
|
|
4429
4796
|
// src/requester/index.ts
|
|
4430
4797
|
var REQUESTER_NEAR_EXPIRY_SECONDS = 30;
|
|
4431
4798
|
var REQUESTER_ENGINE_RETRY_ATTEMPTS = 3;
|
|
@@ -4677,15 +5044,15 @@ var TranscriptRequester = class _TranscriptRequester {
|
|
|
4677
5044
|
"bootstrap owner-node binding does not match trusted discovery/config"
|
|
4678
5045
|
);
|
|
4679
5046
|
}
|
|
4680
|
-
const
|
|
4681
|
-
if (
|
|
5047
|
+
const record2 = await verifyRecordBeforeEgress(bootstrap, options2);
|
|
5048
|
+
if (record2.endpoint !== bootstrap.policyEngine.endpoint) {
|
|
4682
5049
|
throw new TranscriptRequesterError(
|
|
4683
5050
|
"requester-engine-record-endpoint-mismatch",
|
|
4684
5051
|
"policy engine record endpoint does not match bootstrap endpoint",
|
|
4685
5052
|
"bootstrap-invalid"
|
|
4686
5053
|
);
|
|
4687
5054
|
}
|
|
4688
|
-
if (
|
|
5055
|
+
if (record2.audience !== bootstrap.policyEngine.audience) {
|
|
4689
5056
|
throw new TranscriptRequesterError(
|
|
4690
5057
|
"requester-engine-record-audience-mismatch",
|
|
4691
5058
|
"policy engine record audience does not match bootstrap audience",
|
|
@@ -4716,7 +5083,7 @@ var TranscriptRequester = class _TranscriptRequester {
|
|
|
4716
5083
|
requestedCapabilities,
|
|
4717
5084
|
nativeAuthorityCeiling,
|
|
4718
5085
|
requestedCapabilitiesHash(requestedCapabilities),
|
|
4719
|
-
parseStrictRfc33392(
|
|
5086
|
+
parseStrictRfc33392(record2.expiresAt),
|
|
4720
5087
|
policyEngineAddresses,
|
|
4721
5088
|
ownerNodeAddresses,
|
|
4722
5089
|
options2
|
|
@@ -5585,9 +5952,9 @@ function parseNodeDataResponse(response, schema, label) {
|
|
|
5585
5952
|
function nodeErrorMessage(body) {
|
|
5586
5953
|
if (typeof body === "string") return body;
|
|
5587
5954
|
if (body !== null && typeof body === "object") {
|
|
5588
|
-
const
|
|
5589
|
-
const code3 = typeof
|
|
5590
|
-
const message = typeof
|
|
5955
|
+
const record2 = body;
|
|
5956
|
+
const code3 = typeof record2.code === "string" ? record2.code : void 0;
|
|
5957
|
+
const message = typeof record2.message === "string" ? record2.message : void 0;
|
|
5591
5958
|
if (code3 !== void 0)
|
|
5592
5959
|
return message === void 0 ? code3 : `${code3}: ${message}`;
|
|
5593
5960
|
}
|
|
@@ -7909,17 +8276,17 @@ function parseRecapCapabilities(parseWasm, siwe) {
|
|
|
7909
8276
|
}
|
|
7910
8277
|
|
|
7911
8278
|
// src/delegations/SharingService.ts
|
|
7912
|
-
var
|
|
8279
|
+
var import_ed255197 = require("@noble/curves/ed25519");
|
|
7913
8280
|
|
|
7914
8281
|
// src/delegations/ShareRecipientClient.ts
|
|
7915
8282
|
var import_sdk_services2 = require("@tinycloud/sdk-services");
|
|
7916
|
-
var
|
|
7917
|
-
var
|
|
8283
|
+
var import_ed255196 = require("@noble/curves/ed25519");
|
|
8284
|
+
var import_sha2565 = require("@noble/hashes/sha256");
|
|
7918
8285
|
|
|
7919
8286
|
// src/delegations/share-envelope.ts
|
|
7920
|
-
var
|
|
8287
|
+
var import_ed255195 = require("@noble/curves/ed25519");
|
|
7921
8288
|
var import_blake33 = require("@noble/hashes/blake3");
|
|
7922
|
-
var
|
|
8289
|
+
var import_sha2563 = require("@noble/hashes/sha256");
|
|
7923
8290
|
var ENVELOPE_SCHEMA = "xyz.tinycloud.share/envelope";
|
|
7924
8291
|
var INLINE_PREFIX = "tc2:";
|
|
7925
8292
|
var RAW_CID_CODEC = 85;
|
|
@@ -8138,7 +8505,7 @@ function createSharePolicy(input) {
|
|
|
8138
8505
|
};
|
|
8139
8506
|
}
|
|
8140
8507
|
function contentDigest(bytes2) {
|
|
8141
|
-
return bytesToBase64Url((0,
|
|
8508
|
+
return bytesToBase64Url((0, import_sha2563.sha256)(bytes2));
|
|
8142
8509
|
}
|
|
8143
8510
|
function computeShareCid(bytes2) {
|
|
8144
8511
|
const digest4 = create(BLAKE3_256_CODE, (0, import_blake33.blake3)(bytes2));
|
|
@@ -8158,7 +8525,7 @@ function envelopeSigningBytes(envelope) {
|
|
|
8158
8525
|
}
|
|
8159
8526
|
function signShareEnvelope(input) {
|
|
8160
8527
|
if (input.signerPrivateKey.length !== 32) throw new ShareEnvelopeError("invalid-envelope", "Ed25519 private key must be 32 bytes");
|
|
8161
|
-
const publicKey =
|
|
8528
|
+
const publicKey = import_ed255195.ed25519.getPublicKey(input.signerPrivateKey);
|
|
8162
8529
|
const unsigned = {
|
|
8163
8530
|
schema: ENVELOPE_SCHEMA,
|
|
8164
8531
|
version: 2,
|
|
@@ -8173,7 +8540,7 @@ function signShareEnvelope(input) {
|
|
|
8173
8540
|
expiresAt: new Date(input.expiresAt).toISOString(),
|
|
8174
8541
|
signer: { did: input.signerDid, publicKey: bytesToBase64Url(publicKey) }
|
|
8175
8542
|
};
|
|
8176
|
-
return { ...unsigned, signature: bytesToBase64Url(
|
|
8543
|
+
return { ...unsigned, signature: bytesToBase64Url(import_ed255195.ed25519.sign(envelopeSigningBytes(unsigned), input.signerPrivateKey)) };
|
|
8177
8544
|
}
|
|
8178
8545
|
function verifyShareEnvelope(envelope, options2 = {}) {
|
|
8179
8546
|
try {
|
|
@@ -8205,7 +8572,7 @@ function verifyShareEnvelope(envelope, options2 = {}) {
|
|
|
8205
8572
|
const signature = base64UrlToBytes(envelope.signature);
|
|
8206
8573
|
const unsigned = { ...envelope };
|
|
8207
8574
|
delete unsigned.signature;
|
|
8208
|
-
if (publicKey.length !== 32 || signature.length !== 64 || !
|
|
8575
|
+
if (publicKey.length !== 32 || signature.length !== 64 || !import_ed255195.ed25519.verify(signature, envelopeSigningBytes(unsigned), publicKey)) throw new ShareEnvelopeError("signature-invalid", "share envelope signature is invalid");
|
|
8209
8576
|
if (options2.trustedSignerDids !== void 0 && envelope.recipientKind !== void 0 && !options2.trustedSignerDids.includes(envelope.signer.did)) throw new ShareEnvelopeError("signature-invalid", "share signer is not trusted");
|
|
8210
8577
|
return envelope;
|
|
8211
8578
|
} catch (error) {
|
|
@@ -8253,7 +8620,7 @@ function encodeInlineShareUrl(input) {
|
|
|
8253
8620
|
}
|
|
8254
8621
|
var PUBLISHED_AAD = new TextEncoder().encode("tinycloud-share-envelope-v1");
|
|
8255
8622
|
function publishedCid(bytes2) {
|
|
8256
|
-
return CID.create(1, code, create(sha2562.code, (0,
|
|
8623
|
+
return CID.create(1, code, create(sha2562.code, (0, import_sha2563.sha256)(bytes2))).toString();
|
|
8257
8624
|
}
|
|
8258
8625
|
function isPublishedCid(value) {
|
|
8259
8626
|
try {
|
|
@@ -8293,7 +8660,7 @@ function publishedArtifact(envelope, plaintext, policy) {
|
|
|
8293
8660
|
content: {
|
|
8294
8661
|
mimeType: "application/octet-stream",
|
|
8295
8662
|
size: plaintext.byteLength,
|
|
8296
|
-
digest: bytesToBase64Url((0,
|
|
8663
|
+
digest: bytesToBase64Url((0, import_sha2563.sha256)(plaintext))
|
|
8297
8664
|
},
|
|
8298
8665
|
// Addressed policy metadata is confidential even though this function
|
|
8299
8666
|
// is called after the outer envelope has been opened. Keep the
|
|
@@ -8397,9 +8764,9 @@ function parsePolicyMetadata(policyBytes, target, expectedExpiry) {
|
|
|
8397
8764
|
assertKeys(source, ["kind", "space", "database", "path", "statement", "arguments", "argumentsDigest", "action"], "published SQL content source");
|
|
8398
8765
|
if (typeof source.space !== "string" || typeof source.database !== "string" || typeof source.path !== "string" || typeof source.statement !== "string" || !source.arguments || typeof source.arguments !== "object" || Array.isArray(source.arguments) || typeof source.argumentsDigest !== "string" || source.action !== "tinycloud.sql/read") throw new ShareEnvelopeError("invalid-envelope", "published SQL content source is invalid");
|
|
8399
8766
|
for (const argument of Object.values(source.arguments)) if (!Number.isSafeInteger(argument)) throw new ShareEnvelopeError("invalid-envelope", "published SQL arguments are invalid");
|
|
8400
|
-
if (bytesToBase64Url((0,
|
|
8767
|
+
if (bytesToBase64Url((0, import_sha2563.sha256)(new TextEncoder().encode(canonicalJson(source.arguments)))) !== source.argumentsDigest) throw new ShareEnvelopeError("invalid-envelope", "published SQL argument digest is invalid");
|
|
8401
8768
|
} else throw new ShareEnvelopeError("invalid-envelope", "policy content source kind is invalid");
|
|
8402
|
-
if (typeof policy.contentSourceDigest !== "string" || bytesToBase64Url((0,
|
|
8769
|
+
if (typeof policy.contentSourceDigest !== "string" || bytesToBase64Url((0, import_sha2563.sha256)(new TextEncoder().encode(canonicalJson(source)))) !== policy.contentSourceDigest) throw new ShareEnvelopeError("invalid-envelope", "policy content source digest is invalid");
|
|
8403
8770
|
return { recipientKind, actions, resource };
|
|
8404
8771
|
}
|
|
8405
8772
|
function parseCanonicalPublishedV2(value, options2) {
|
|
@@ -8447,7 +8814,7 @@ function parseCanonicalPublishedV2(value, options2) {
|
|
|
8447
8814
|
const signingBytes = new Uint8Array(domain.length + body.length);
|
|
8448
8815
|
signingBytes.set(domain);
|
|
8449
8816
|
signingBytes.set(body, domain.length);
|
|
8450
|
-
if (signatureBytes.length !== 64 || !
|
|
8817
|
+
if (signatureBytes.length !== 64 || !import_ed255195.ed25519.verify(signatureBytes, signingBytes, signerKey)) throw new ShareEnvelopeError("signature-invalid", "published v2 envelope signature is invalid");
|
|
8451
8818
|
const content = options2.plaintext ?? new Uint8Array();
|
|
8452
8819
|
const normalized = {
|
|
8453
8820
|
schema: ENVELOPE_SCHEMA,
|
|
@@ -8457,7 +8824,7 @@ function parseCanonicalPublishedV2(value, options2) {
|
|
|
8457
8824
|
recipientKind: normalizedMatcher.kind,
|
|
8458
8825
|
resource,
|
|
8459
8826
|
actions,
|
|
8460
|
-
content: { mimeType: typeof contentSource.mimeType === "string" ? contentSource.mimeType : "application/octet-stream", size: content.byteLength, digest: bytesToBase64Url((0,
|
|
8827
|
+
content: { mimeType: typeof contentSource.mimeType === "string" ? contentSource.mimeType : "application/octet-stream", size: content.byteLength, digest: bytesToBase64Url((0, import_sha2563.sha256)(content)) },
|
|
8461
8828
|
encrypted: true,
|
|
8462
8829
|
expiresAt: value.expiry,
|
|
8463
8830
|
signer: { did: signature.signerDid, publicKey: bytesToBase64Url(signerKey) },
|
|
@@ -8556,7 +8923,7 @@ function parsePublishedShareEnvelope(bytes2, options2 = {}) {
|
|
|
8556
8923
|
if (envelope.authorizationTarget.kind !== "bearerKey" && (options2.trustedSignerDids === void 0 || !options2.trustedSignerDids.includes(envelope.signature.signerDid))) throw new ShareEnvelopeError("signature-invalid", "a trusted authority is required for addressed shares");
|
|
8557
8924
|
const signature = base64UrlToBytes(envelope.signature.value);
|
|
8558
8925
|
const publicKey = publishedPublicKey(envelope.signature.signerDid);
|
|
8559
|
-
if (signature.length !== 64 || !
|
|
8926
|
+
if (signature.length !== 64 || !import_ed255195.ed25519.verify(signature, publishedEnvelopeSigningBytes(envelope), publicKey)) throw new ShareEnvelopeError("signature-invalid", "published envelope signature is invalid");
|
|
8560
8927
|
return { envelope, artifact: publishedArtifact(envelope, options2.plaintext ?? new Uint8Array(), policy) };
|
|
8561
8928
|
}
|
|
8562
8929
|
function parseLegacyPublishedShareEnvelope(bytes2, options2 = {}) {
|
|
@@ -8595,7 +8962,7 @@ function parseLegacyPublishedShareEnvelope(bytes2, options2 = {}) {
|
|
|
8595
8962
|
const signingBytes = new Uint8Array(domain.length + body.length);
|
|
8596
8963
|
signingBytes.set(domain);
|
|
8597
8964
|
signingBytes.set(body, domain.length);
|
|
8598
|
-
if (signatureBytes.length !== 64 || !
|
|
8965
|
+
if (signatureBytes.length !== 64 || !import_ed255195.ed25519.verify(signatureBytes, signingBytes, signerKey)) throw new ShareEnvelopeError("signature-invalid", "published v1 envelope signature is invalid");
|
|
8599
8966
|
const content = options2.plaintext ?? new Uint8Array();
|
|
8600
8967
|
const artifact = {
|
|
8601
8968
|
envelope: {
|
|
@@ -8606,7 +8973,7 @@ function parseLegacyPublishedShareEnvelope(bytes2, options2 = {}) {
|
|
|
8606
8973
|
resource: { kind: resource.kind, path: resource.path },
|
|
8607
8974
|
recipientKind: authorizationTarget.kind === "bearer" ? "bearer" : authorizationTarget.kind === "exact-email" ? "exactEmail" : authorizationTarget.kind === "email-domain" ? "emailDomain" : void 0,
|
|
8608
8975
|
actions: ["read"],
|
|
8609
|
-
content: { mimeType: "application/octet-stream", size: content.byteLength, digest: bytesToBase64Url((0,
|
|
8976
|
+
content: { mimeType: "application/octet-stream", size: content.byteLength, digest: bytesToBase64Url((0, import_sha2563.sha256)(content)) },
|
|
8610
8977
|
encrypted: true,
|
|
8611
8978
|
expiresAt: envelope.expiry,
|
|
8612
8979
|
signer: { did: signature.signerDid, publicKey: bytesToBase64Url(signerKey) },
|
|
@@ -8793,13 +9160,13 @@ function shareCapabilityAllows(capability, action, path) {
|
|
|
8793
9160
|
}
|
|
8794
9161
|
|
|
8795
9162
|
// src/delegations/ShareCache.ts
|
|
8796
|
-
var
|
|
9163
|
+
var import_sha2564 = require("@noble/hashes/sha256");
|
|
8797
9164
|
function cacheKey(key) {
|
|
8798
9165
|
if (!key.cid || !key.expiresAt) throw new Error("share cache keys require CID and expiry");
|
|
8799
9166
|
return `${key.cid}\0${key.expiresAt}`;
|
|
8800
9167
|
}
|
|
8801
9168
|
function digest2(bytes2) {
|
|
8802
|
-
return (0,
|
|
9169
|
+
return (0, import_sha2564.sha256)(bytes2);
|
|
8803
9170
|
}
|
|
8804
9171
|
function equalBytes2(left, right) {
|
|
8805
9172
|
if (left.byteLength !== right.byteLength) return false;
|
|
@@ -9176,7 +9543,7 @@ function randomJti() {
|
|
|
9176
9543
|
return bytesToBase64Url2(bytes2);
|
|
9177
9544
|
}
|
|
9178
9545
|
function digestCanonical(value) {
|
|
9179
|
-
return bytesToBase64Url2((0,
|
|
9546
|
+
return bytesToBase64Url2((0, import_sha2565.sha256)(new TextEncoder().encode(canonicalJsonForProof(value))));
|
|
9180
9547
|
}
|
|
9181
9548
|
function actionWire(action) {
|
|
9182
9549
|
return action === "get" ? "tinycloud.kv/get" : action === "metadata" ? "tinycloud.kv/metadata" : action === "list" ? "tinycloud.kv/list" : "tinycloud.kv/put";
|
|
@@ -9412,9 +9779,9 @@ var ShareRecipientClient = class {
|
|
|
9412
9779
|
const authority = Object.entries(session.att).find(([parentResource, abilities]) => {
|
|
9413
9780
|
if (!(action in abilities)) return false;
|
|
9414
9781
|
if (serviceName === "encryption") return parentResource.startsWith("urn:tinycloud:encryption:") && parentResource === cleanPath;
|
|
9415
|
-
const
|
|
9416
|
-
if (
|
|
9417
|
-
const parentPath =
|
|
9782
|
+
const marker = parentResource.indexOf("/kv/");
|
|
9783
|
+
if (marker < 1) return false;
|
|
9784
|
+
const parentPath = parentResource.slice(marker + 4);
|
|
9418
9785
|
const caveats = abilities[action] ?? [];
|
|
9419
9786
|
const prefix = caveats.some((value) => isRecord(value) && value.kind === "prefix");
|
|
9420
9787
|
return cleanPath === parentPath || prefix && cleanPath.startsWith(`${parentPath}/`);
|
|
@@ -9440,10 +9807,10 @@ var ShareRecipientClient = class {
|
|
|
9440
9807
|
policySessionProjection(delegation) {
|
|
9441
9808
|
const session = parsePolicySessionUcan(delegation.delegationHeader.Authorization);
|
|
9442
9809
|
if (session.cid !== delegation.cid || session.aud !== delegation.delegateDID) throw new ShareAccessError("SHARE_SESSION_INVALID");
|
|
9443
|
-
const kvResource = Object.keys(session.att).find((resource) =>
|
|
9444
|
-
const
|
|
9445
|
-
if (
|
|
9446
|
-
return { spaceId:
|
|
9810
|
+
const kvResource = Object.keys(session.att).find((resource) => resource.indexOf("/kv/") > 0);
|
|
9811
|
+
const marker = kvResource?.indexOf("/kv/") ?? -1;
|
|
9812
|
+
if (kvResource === void 0 || marker < 1) throw new ShareAccessError("SHARE_SESSION_INVALID");
|
|
9813
|
+
return { spaceId: kvResource.slice(0, marker) };
|
|
9447
9814
|
}
|
|
9448
9815
|
createKV(origin2, session, invokeOverride) {
|
|
9449
9816
|
const invoke = invokeOverride ?? this.options.invoke ?? nativeInvoke;
|
|
@@ -9493,7 +9860,7 @@ var ShareRecipientClient = class {
|
|
|
9493
9860
|
if (bytes2.byteLength > (this.options.maxContentBytes ?? DEFAULT_MAX_CONTENT_BYTES)) throw new ShareAccessError("SHARE_TOO_LARGE");
|
|
9494
9861
|
const contentType = input.contentType ?? envelope.content.mimeType;
|
|
9495
9862
|
if (contentType !== envelope.content.mimeType && !/^text\/(?:plain|markdown)(?:;|$)/i.test(contentType)) throw new ShareAccessError("SHARE_CONTENT_TYPE_INVALID");
|
|
9496
|
-
const result = await this.invokeNative({ envelope, session, action: "put", resource: path, body: bytes2, bodyDigest: bytesToBase64Url2((0,
|
|
9863
|
+
const result = await this.invokeNative({ envelope, session, action: "put", resource: path, body: bytes2, bodyDigest: bytesToBase64Url2((0, import_sha2565.sha256)(bytes2)), contentType, ifMatch: input.etag, mediaType: "application/vnd.tinycloud.share+json" });
|
|
9497
9864
|
if (result.status === 412 || result.status === 409) throw new ShareConflict(path, result.headers?.etag);
|
|
9498
9865
|
if (result.status === 401 || result.status === 403) throw new ShareAccessError("SHARE_DENIED");
|
|
9499
9866
|
if (result.status < 200 || result.status >= 300) throw new ShareAccessError("SHARE_WRITE_FAILED");
|
|
@@ -9645,44 +10012,44 @@ var ShareRecipientClient = class {
|
|
|
9645
10012
|
}
|
|
9646
10013
|
const parsed = ShareNativeResponseSchema.safeParse(value);
|
|
9647
10014
|
if (!parsed.success) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
|
|
9648
|
-
const
|
|
10015
|
+
const record2 = parsed.data;
|
|
9649
10016
|
const expectedAction = actionWire(input.action);
|
|
9650
|
-
if (
|
|
10017
|
+
if (record2.action !== expectedAction || record2.version !== 2 || record2.resource !== input.resource) {
|
|
9651
10018
|
throw new ShareAccessError("SHARE_RESPONSE_MISMATCH");
|
|
9652
10019
|
}
|
|
9653
|
-
if (
|
|
9654
|
-
if (
|
|
10020
|
+
if (record2.etag !== void 0 && record2.etag !== null && headers.etag !== void 0 && record2.etag !== headers.etag) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
|
|
10021
|
+
if (record2.etag !== void 0 && record2.etag !== null) headers.etag = record2.etag;
|
|
9655
10022
|
if (input.action === "list") {
|
|
9656
|
-
if (
|
|
9657
|
-
const rawEntries =
|
|
10023
|
+
if (record2.entries === void 0) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
|
|
10024
|
+
const rawEntries = record2.entries;
|
|
9658
10025
|
if (rawEntries.length > MAX_NATIVE_ENTRIES) throw new ShareAccessError("SHARE_TOO_LARGE");
|
|
9659
10026
|
const entries = [...rawEntries];
|
|
9660
10027
|
const headerCursor = response.headers.get("x-tinycloud-next-cursor");
|
|
9661
|
-
if (
|
|
9662
|
-
const nextCursor =
|
|
10028
|
+
if (record2.nextCursor !== void 0 && record2.nextCursor !== null && headerCursor !== null && record2.nextCursor !== headerCursor) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
|
|
10029
|
+
const nextCursor = record2.nextCursor ?? headerCursor ?? void 0;
|
|
9663
10030
|
if (nextCursor !== void 0 && new TextEncoder().encode(nextCursor).byteLength > MAX_NATIVE_CURSOR_BYTES) throw new ShareAccessError("SHARE_TOO_LARGE");
|
|
9664
|
-
return { status: response.status, headers, type:
|
|
10031
|
+
return { status: response.status, headers, type: record2.type, version: record2.version, action: record2.action, resource: record2.resource, keys: entries.map((entry) => entry.path), entries, truncated: nextCursor !== void 0, nextCursor };
|
|
9665
10032
|
}
|
|
9666
10033
|
if (input.action === "get") {
|
|
9667
|
-
if (
|
|
10034
|
+
if (record2.content === void 0 || record2.bodyDigest === void 0) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
|
|
9668
10035
|
let bytes2;
|
|
9669
10036
|
try {
|
|
9670
|
-
bytes2 = base64UrlToBytes2(
|
|
10037
|
+
bytes2 = base64UrlToBytes2(record2.content);
|
|
9671
10038
|
} catch {
|
|
9672
10039
|
throw new ShareAccessError("SHARE_RESPONSE_INVALID");
|
|
9673
10040
|
}
|
|
9674
|
-
if (bytes2.byteLength > (this.options.maxContentBytes ?? DEFAULT_MAX_CONTENT_BYTES) || !this.digestMatches(
|
|
9675
|
-
return { status: response.status, headers, bytes: bytes2, bodyDigest:
|
|
10041
|
+
if (bytes2.byteLength > (this.options.maxContentBytes ?? DEFAULT_MAX_CONTENT_BYTES) || !this.digestMatches(record2.bodyDigest, bytes2)) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
|
|
10042
|
+
return { status: response.status, headers, bytes: bytes2, bodyDigest: record2.bodyDigest, type: record2.type, version: record2.version, action: record2.action, resource: record2.resource };
|
|
9676
10043
|
}
|
|
9677
10044
|
if (input.action === "metadata") {
|
|
9678
|
-
if (
|
|
9679
|
-
return { status: response.status, headers, metadata:
|
|
10045
|
+
if (record2.metadata === void 0) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
|
|
10046
|
+
return { status: response.status, headers, metadata: record2.metadata, etag: record2.etag ?? void 0, type: record2.type, version: record2.version, action: record2.action, resource: record2.resource };
|
|
9680
10047
|
}
|
|
9681
|
-
const responseEtag =
|
|
9682
|
-
const responseBodyDigest =
|
|
10048
|
+
const responseEtag = record2.etag;
|
|
10049
|
+
const responseBodyDigest = record2.bodyDigest;
|
|
9683
10050
|
if (responseEtag === void 0 || responseEtag === null || responseEtag.length === 0 || headers.etag !== void 0 && responseEtag !== headers.etag) throw new ShareAccessError("SHARE_RESPONSE_INVALID");
|
|
9684
10051
|
if (input.bodyDigest === void 0 || responseBodyDigest === void 0 || responseBodyDigest !== input.bodyDigest || !this.digestMatches(responseBodyDigest, input.body ?? new Uint8Array())) throw new ShareAccessError("SHARE_RESPONSE_INTEGRITY");
|
|
9685
|
-
return { status: response.status, headers, bodyDigest: responseBodyDigest, type:
|
|
10052
|
+
return { status: response.status, headers, bodyDigest: responseBodyDigest, type: record2.type, version: record2.version, action: record2.action, resource: record2.resource };
|
|
9686
10053
|
}
|
|
9687
10054
|
validateNativeResult(input, result) {
|
|
9688
10055
|
if (!isNativeSuccess(result)) throw new ShareAccessError("SHARE_RESPONSE_MISMATCH");
|
|
@@ -9739,7 +10106,7 @@ var ShareRecipientClient = class {
|
|
|
9739
10106
|
}]);
|
|
9740
10107
|
}
|
|
9741
10108
|
digestMatches(value, bytes2) {
|
|
9742
|
-
const digest4 = bytesToBase64Url2((0,
|
|
10109
|
+
const digest4 = bytesToBase64Url2((0, import_sha2565.sha256)(bytes2));
|
|
9743
10110
|
return value === digest4 || value === `sha-256=:${digest4}:`;
|
|
9744
10111
|
}
|
|
9745
10112
|
assertNativeRequestBounds(envelope, session, operation, path, limit, cursor) {
|
|
@@ -9957,7 +10324,7 @@ var ShareRecipientClient = class {
|
|
|
9957
10324
|
nodeAudience: binding.nodeAudience,
|
|
9958
10325
|
...isV2 ? {
|
|
9959
10326
|
enforcerDid: challenge.enforcerDid,
|
|
9960
|
-
credentialDigest: typeof presentation.credentialDigest === "string" ? presentation.credentialDigest : bytesToBase64Url2((0,
|
|
10327
|
+
credentialDigest: typeof presentation.credentialDigest === "string" ? presentation.credentialDigest : bytesToBase64Url2((0, import_sha2565.sha256)(new TextEncoder().encode(credential)))
|
|
9961
10328
|
} : {},
|
|
9962
10329
|
action,
|
|
9963
10330
|
...binding.actions === void 0 ? {} : { actions: [...binding.actions] },
|
|
@@ -10023,7 +10390,7 @@ var ShareRecipientClient = class {
|
|
|
10023
10390
|
}
|
|
10024
10391
|
if (isJwsProof && detached.kid !== `${signerDid}#${encoded}` || isEd25519Proof && detached.signerDid !== signerDid || signature.length !== 64) throw new ShareAccessError("SHARE_SESSION_INVALID", "Node proof binding is invalid");
|
|
10025
10392
|
const bytes2 = new TextEncoder().encode(`${domain}${canonicalJsonForProof(message)}`);
|
|
10026
|
-
if (!
|
|
10393
|
+
if (!import_ed255196.ed25519.verify(signature, bytes2, key)) throw new ShareAccessError("SHARE_SESSION_INVALID", "Node proof signature is invalid");
|
|
10027
10394
|
}
|
|
10028
10395
|
assertChallengeRequestBinding(request, challenge) {
|
|
10029
10396
|
const source = isRecord(request.body) ? request.body : request;
|
|
@@ -11227,7 +11594,7 @@ function shareKeyMatchesDid(key, didUrl) {
|
|
|
11227
11594
|
if (!publicKey) return false;
|
|
11228
11595
|
const jwkBytes = decodeBase64UrlBytes(key.x);
|
|
11229
11596
|
const privateKey = decodeBase64UrlBytes(key.d);
|
|
11230
|
-
const derivedPublicKey =
|
|
11597
|
+
const derivedPublicKey = import_ed255197.ed25519.getPublicKey(privateKey);
|
|
11231
11598
|
return privateKey.length === 32 && publicKey.length === jwkBytes.length && publicKey.every((byte, index) => byte === jwkBytes[index]) && derivedPublicKey.length === jwkBytes.length && derivedPublicKey.every((byte, index) => byte === jwkBytes[index]);
|
|
11232
11599
|
} catch {
|
|
11233
11600
|
return false;
|
|
@@ -11277,8 +11644,8 @@ function verifySignedChild(result, expected, computeCid) {
|
|
|
11277
11644
|
}
|
|
11278
11645
|
|
|
11279
11646
|
// src/delegations/owner-policy.ts
|
|
11280
|
-
var
|
|
11281
|
-
var
|
|
11647
|
+
var import_ed255198 = require("@noble/curves/ed25519");
|
|
11648
|
+
var import_sha2566 = require("@noble/hashes/sha256");
|
|
11282
11649
|
var MAX_CONTENT_BYTES = 100 * 1024 * 1024;
|
|
11283
11650
|
var ENFORCEMENT_DOMAIN = "xyz.tinycloud.share/policy-enforcement/v2\0";
|
|
11284
11651
|
var POLICY_DOMAIN = "xyz.tinycloud.share/policy/v2\0";
|
|
@@ -11305,10 +11672,10 @@ function fromB64(value) {
|
|
|
11305
11672
|
throw new Error("base64url decoding is unavailable");
|
|
11306
11673
|
}
|
|
11307
11674
|
function cid(bytesValue) {
|
|
11308
|
-
return CID.createV1(code, create(sha2562.code, (0,
|
|
11675
|
+
return CID.createV1(code, create(sha2562.code, (0, import_sha2566.sha256)(bytesValue))).toString(base32.encoder);
|
|
11309
11676
|
}
|
|
11310
11677
|
function digest3(bytesValue) {
|
|
11311
|
-
return b64((0,
|
|
11678
|
+
return b64((0, import_sha2566.sha256)(bytesValue));
|
|
11312
11679
|
}
|
|
11313
11680
|
function didKeyFromEd25519PublicKey(publicKey) {
|
|
11314
11681
|
if (publicKey.length !== 32) throw new Error("share key public key must be 32 bytes");
|
|
@@ -11380,9 +11747,9 @@ function dagCborEncode(value) {
|
|
|
11380
11747
|
}
|
|
11381
11748
|
function assertObject(value, keys, label) {
|
|
11382
11749
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
|
|
11383
|
-
const
|
|
11384
|
-
if (Object.keys(
|
|
11385
|
-
return
|
|
11750
|
+
const record2 = value;
|
|
11751
|
+
if (Object.keys(record2).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record2, key))) throw new Error(`${label} has unknown or missing fields`);
|
|
11752
|
+
return record2;
|
|
11386
11753
|
}
|
|
11387
11754
|
async function createDelegatedShareKey(options2) {
|
|
11388
11755
|
if (!globalThis.crypto?.subtle) throw new Error("WebCrypto Ed25519 is required for delegated share keys");
|
|
@@ -11493,7 +11860,7 @@ function validateOwnerSharePolicyRegistration(value, expected) {
|
|
|
11493
11860
|
const publicKey = encodedKid.length === 34 ? encodedKid.slice(2) : encodedKid;
|
|
11494
11861
|
const signatureBytes = fromB64(proof.signature);
|
|
11495
11862
|
const signedBytes = new TextEncoder().encode(`${OWNER_SHARE_REGISTRATION_DOMAIN}${canonicalizeSignedObjectUnsigned(registrationCore)}`);
|
|
11496
|
-
if (signatureBytes.length !== 64 || !
|
|
11863
|
+
if (signatureBytes.length !== 64 || !import_ed255198.ed25519.verify(signatureBytes, signedBytes, publicKey)) throw new Error("owner-share registration proof signature is invalid");
|
|
11497
11864
|
return { registration, proof };
|
|
11498
11865
|
}
|
|
11499
11866
|
function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
|
|
@@ -11507,7 +11874,7 @@ function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
|
|
|
11507
11874
|
}
|
|
11508
11875
|
|
|
11509
11876
|
// src/delegations/share-delivery.ts
|
|
11510
|
-
var
|
|
11877
|
+
var import_ed255199 = require("@noble/curves/ed25519");
|
|
11511
11878
|
var SHARE_DELIVERY_AUTHORIZATION_DOMAIN = "xyz.tinycloud.share/delivery-authorization/v2\0";
|
|
11512
11879
|
function isCanonicalHttpsOrigin(value) {
|
|
11513
11880
|
let url;
|
|
@@ -11556,9 +11923,9 @@ var AUTHORIZATION_KEYS = [
|
|
|
11556
11923
|
];
|
|
11557
11924
|
function assertObject2(value, keys, label) {
|
|
11558
11925
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
|
|
11559
|
-
const
|
|
11560
|
-
if (Object.keys(
|
|
11561
|
-
return
|
|
11926
|
+
const record2 = value;
|
|
11927
|
+
if (Object.keys(record2).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record2, key))) throw new Error(`${label} has unknown or missing fields`);
|
|
11928
|
+
return record2;
|
|
11562
11929
|
}
|
|
11563
11930
|
function fromB642(value) {
|
|
11564
11931
|
if (!/^[A-Za-z0-9_-]+$/.test(value)) throw new Error("share delivery value is not canonical base64url");
|
|
@@ -11595,7 +11962,7 @@ function validateShareDeliveryAuthorizationBytes(bytesValue, expected) {
|
|
|
11595
11962
|
if (publicKey.length !== 32) throw new Error("share delivery authorization proof key is invalid");
|
|
11596
11963
|
const signatureBytes = fromB642(proof.signature);
|
|
11597
11964
|
const signedBytes = new TextEncoder().encode(`${SHARE_DELIVERY_AUTHORIZATION_DOMAIN}${canonicalizeSignedObjectUnsigned(authorization)}`);
|
|
11598
|
-
if (signatureBytes.length !== 64 || !
|
|
11965
|
+
if (signatureBytes.length !== 64 || !import_ed255199.ed25519.verify(signatureBytes, signedBytes, publicKey)) throw new Error("share delivery authorization proof signature is invalid");
|
|
11599
11966
|
return { authorization, proof };
|
|
11600
11967
|
}
|
|
11601
11968
|
function shareDeliveryTrustedKid(publicKey) {
|
|
@@ -11612,8 +11979,8 @@ var MemorySenderShareRecordStorage = class {
|
|
|
11612
11979
|
constructor() {
|
|
11613
11980
|
this.records = /* @__PURE__ */ new Map();
|
|
11614
11981
|
}
|
|
11615
|
-
async put(
|
|
11616
|
-
this.records.set(
|
|
11982
|
+
async put(record2) {
|
|
11983
|
+
this.records.set(record2.shareId, record2);
|
|
11617
11984
|
}
|
|
11618
11985
|
async list() {
|
|
11619
11986
|
return [...this.records.values()];
|
|
@@ -11649,7 +12016,7 @@ var SenderShareStore = class {
|
|
|
11649
12016
|
async save(receipt, key) {
|
|
11650
12017
|
const registration = receipt.registration;
|
|
11651
12018
|
if (registration.shareKeyDid !== key.did) throw new Error("share key does not match the registered receipt");
|
|
11652
|
-
const
|
|
12019
|
+
const record2 = {
|
|
11653
12020
|
shareId: registration.shareId,
|
|
11654
12021
|
registrationCid: registration.registrationCid,
|
|
11655
12022
|
policyCid: registration.policyCid,
|
|
@@ -11665,15 +12032,15 @@ var SenderShareStore = class {
|
|
|
11665
12032
|
registeredAt: registration.registeredAt,
|
|
11666
12033
|
expiresAt: registration.expiresAt
|
|
11667
12034
|
};
|
|
11668
|
-
await this.records.put(
|
|
11669
|
-
await this.keys.put(
|
|
11670
|
-
return
|
|
12035
|
+
await this.records.put(record2);
|
|
12036
|
+
await this.keys.put(record2.shareId, { cryptoKey: key.cryptoKey, publicKey: key.publicKey, extractable: key.extractable });
|
|
12037
|
+
return record2;
|
|
11671
12038
|
}
|
|
11672
12039
|
/** List shares created in any session, most recent first. */
|
|
11673
12040
|
async list(options2) {
|
|
11674
12041
|
const now = this.now().getTime();
|
|
11675
12042
|
const records = await this.records.list();
|
|
11676
|
-
return records.filter((
|
|
12043
|
+
return records.filter((record2) => (options2?.includeRevoked ?? false) || record2.revokedAt === void 0).filter((record2) => (options2?.includeExpired ?? false) || Date.parse(record2.expiresAt) > now).sort((left, right) => Date.parse(right.registeredAt) - Date.parse(left.registeredAt));
|
|
11677
12044
|
}
|
|
11678
12045
|
async get(shareId) {
|
|
11679
12046
|
return this.records.get(shareId);
|
|
@@ -11696,15 +12063,15 @@ var SenderShareStore = class {
|
|
|
11696
12063
|
* returned CID, then call {@link markRevoked} once that succeeds.
|
|
11697
12064
|
*/
|
|
11698
12065
|
async revocationTarget(shareId, scope) {
|
|
11699
|
-
const
|
|
11700
|
-
if (
|
|
11701
|
-
return scope === "direct" ?
|
|
12066
|
+
const record2 = await this.records.get(shareId);
|
|
12067
|
+
if (record2 === void 0) throw new Error(`Unknown share: ${shareId}`);
|
|
12068
|
+
return scope === "direct" ? record2.enforcementDelegationCid : record2.ownerDelegationCid;
|
|
11702
12069
|
}
|
|
11703
12070
|
/** Mark a share revoked locally after the caller's node-side revoke call succeeds. */
|
|
11704
12071
|
async markRevoked(shareId, revokedAt = this.now().toISOString()) {
|
|
11705
|
-
const
|
|
11706
|
-
if (
|
|
11707
|
-
const revoked = { ...
|
|
12072
|
+
const record2 = await this.records.get(shareId);
|
|
12073
|
+
if (record2 === void 0) throw new Error(`Unknown share: ${shareId}`);
|
|
12074
|
+
const revoked = { ...record2, revokedAt };
|
|
11708
12075
|
await this.records.put(revoked);
|
|
11709
12076
|
return revoked;
|
|
11710
12077
|
}
|
|
@@ -13498,27 +13865,27 @@ var AccountService = class {
|
|
|
13498
13865
|
const kvResult = this.accountKV();
|
|
13499
13866
|
if (!kvResult.ok) return kvResult;
|
|
13500
13867
|
let registered;
|
|
13501
|
-
for (const
|
|
13502
|
-
const manifestHash = hashJson(
|
|
13503
|
-
if (!options2.assumeUnregistered && await this.indexHasApplicationHash(
|
|
13868
|
+
for (const record2 of request.registryRecords) {
|
|
13869
|
+
const manifestHash = hashJson(record2.manifests);
|
|
13870
|
+
if (!options2.assumeUnregistered && await this.indexHasApplicationHash(record2.app_id, manifestHash)) {
|
|
13504
13871
|
registered = {
|
|
13505
|
-
appId:
|
|
13506
|
-
manifests:
|
|
13872
|
+
appId: record2.app_id,
|
|
13873
|
+
manifests: record2.manifests,
|
|
13507
13874
|
manifestHash,
|
|
13508
|
-
name:
|
|
13509
|
-
description:
|
|
13875
|
+
name: record2.manifests[0]?.name,
|
|
13876
|
+
description: record2.manifests[0]?.description
|
|
13510
13877
|
};
|
|
13511
13878
|
continue;
|
|
13512
13879
|
}
|
|
13513
13880
|
const stored = {
|
|
13514
|
-
app_id:
|
|
13515
|
-
manifests:
|
|
13881
|
+
app_id: record2.app_id,
|
|
13882
|
+
manifests: record2.manifests,
|
|
13516
13883
|
manifest_hash: manifestHash,
|
|
13517
13884
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
13518
13885
|
};
|
|
13519
|
-
const written = await kvResult.data.put(
|
|
13886
|
+
const written = await kvResult.data.put(record2.key, stored);
|
|
13520
13887
|
if (!written.ok) return accountErr(written.error);
|
|
13521
|
-
registered = applicationFromRecord(
|
|
13888
|
+
registered = applicationFromRecord(record2.key, stored);
|
|
13522
13889
|
await this.upsertApplicationIndexQuietly(registered);
|
|
13523
13890
|
}
|
|
13524
13891
|
return (0, import_sdk_services6.ok)(registered);
|
|
@@ -13592,11 +13959,11 @@ var AccountService = class {
|
|
|
13592
13959
|
if (!kvResult.ok) return kvResult;
|
|
13593
13960
|
const stored = spaces.map((space) => spaceRecordFromInput(space));
|
|
13594
13961
|
const registered = stored.map(
|
|
13595
|
-
(
|
|
13962
|
+
(record2) => spaceFromRecord(spaceKey(record2.space_id), record2)
|
|
13596
13963
|
);
|
|
13597
|
-
const items = stored.map((
|
|
13598
|
-
key: spaceKey(
|
|
13599
|
-
value:
|
|
13964
|
+
const items = stored.map((record2) => ({
|
|
13965
|
+
key: spaceKey(record2.space_id),
|
|
13966
|
+
value: record2
|
|
13600
13967
|
}));
|
|
13601
13968
|
const batchResult = await kvResult.data.batchPut(items);
|
|
13602
13969
|
if (batchResult.ok) {
|
|
@@ -13607,10 +13974,10 @@ var AccountService = class {
|
|
|
13607
13974
|
return accountErr(batchResult.error);
|
|
13608
13975
|
}
|
|
13609
13976
|
const reconcileFailures = [];
|
|
13610
|
-
for (const
|
|
13611
|
-
const written = await kvResult.data.put(spaceKey(
|
|
13977
|
+
for (const record2 of stored) {
|
|
13978
|
+
const written = await kvResult.data.put(spaceKey(record2.space_id), record2);
|
|
13612
13979
|
if (!written.ok) {
|
|
13613
|
-
reconcileFailures.push(`${
|
|
13980
|
+
reconcileFailures.push(`${record2.space_id}: ${written.error.message}`);
|
|
13614
13981
|
}
|
|
13615
13982
|
}
|
|
13616
13983
|
if (reconcileFailures.length > 0) {
|
|
@@ -14230,16 +14597,16 @@ function applicationKey(appId) {
|
|
|
14230
14597
|
function appIdFromKey(key) {
|
|
14231
14598
|
return key.startsWith(ACCOUNT_REGISTRY_PATH) ? key.slice(ACCOUNT_REGISTRY_PATH.length) : key;
|
|
14232
14599
|
}
|
|
14233
|
-
function applicationFromRecord(key,
|
|
14234
|
-
const manifests = Array.isArray(
|
|
14600
|
+
function applicationFromRecord(key, record2) {
|
|
14601
|
+
const manifests = Array.isArray(record2.manifests) ? record2.manifests : [];
|
|
14235
14602
|
const first = manifests[0];
|
|
14236
14603
|
return {
|
|
14237
|
-
appId:
|
|
14604
|
+
appId: record2.app_id ?? record2.appId ?? first?.app_id ?? appIdFromKey(key),
|
|
14238
14605
|
manifests,
|
|
14239
|
-
updatedAt:
|
|
14606
|
+
updatedAt: record2.updated_at ?? record2.updatedAt,
|
|
14240
14607
|
name: first?.name,
|
|
14241
14608
|
description: first?.description,
|
|
14242
|
-
manifestHash:
|
|
14609
|
+
manifestHash: record2.manifest_hash ?? record2.manifestHash ?? hashJson(manifests)
|
|
14243
14610
|
};
|
|
14244
14611
|
}
|
|
14245
14612
|
function indexedApplicationFromRow(row) {
|
|
@@ -14282,17 +14649,17 @@ function spaceRecordFromInput(space) {
|
|
|
14282
14649
|
expires_at: accountSpace.expiresAt instanceof Date ? accountSpace.expiresAt.toISOString() : accountSpace.expiresAt
|
|
14283
14650
|
};
|
|
14284
14651
|
}
|
|
14285
|
-
function spaceFromRecord(key,
|
|
14286
|
-
const expiresAt =
|
|
14652
|
+
function spaceFromRecord(key, record2) {
|
|
14653
|
+
const expiresAt = record2.expires_at ?? record2.expiresAt;
|
|
14287
14654
|
return {
|
|
14288
|
-
spaceId:
|
|
14289
|
-
name:
|
|
14290
|
-
ownerDid:
|
|
14291
|
-
type:
|
|
14292
|
-
permissions: Array.isArray(
|
|
14293
|
-
status:
|
|
14294
|
-
registeredAt:
|
|
14295
|
-
updatedAt:
|
|
14655
|
+
spaceId: record2.space_id ?? record2.spaceId ?? spaceIdFromKey(key),
|
|
14656
|
+
name: record2.name ?? spaceIdFromKey(key).split(":").pop() ?? spaceIdFromKey(key),
|
|
14657
|
+
ownerDid: record2.owner_did ?? record2.ownerDid ?? record2.owner ?? "",
|
|
14658
|
+
type: record2.type ?? "discovered",
|
|
14659
|
+
permissions: Array.isArray(record2.permissions) ? record2.permissions : [],
|
|
14660
|
+
status: record2.status ?? "active",
|
|
14661
|
+
registeredAt: record2.registered_at ?? record2.registeredAt,
|
|
14662
|
+
updatedAt: record2.updated_at ?? record2.updatedAt,
|
|
14296
14663
|
expiresAt: expiresAt ? new Date(expiresAt) : void 0
|
|
14297
14664
|
};
|
|
14298
14665
|
}
|
|
@@ -16998,7 +17365,7 @@ function portForProtocol(protocol) {
|
|
|
16998
17365
|
}
|
|
16999
17366
|
|
|
17000
17367
|
// src/location.ts
|
|
17001
|
-
var
|
|
17368
|
+
var import_ed2551910 = require("@noble/curves/ed25519");
|
|
17002
17369
|
var import_viem5 = require("viem");
|
|
17003
17370
|
var DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL = "https://registry.tinycloud.xyz";
|
|
17004
17371
|
var DEFAULT_TINYCLOUD_FALLBACK_HOST = "https://node.tinycloud.xyz";
|
|
@@ -17063,13 +17430,13 @@ var CloudLocationResolutionError = class extends Error {
|
|
|
17063
17430
|
this.attempts = attempts;
|
|
17064
17431
|
}
|
|
17065
17432
|
};
|
|
17066
|
-
function locationPayloadForRecord(
|
|
17433
|
+
function locationPayloadForRecord(record2) {
|
|
17067
17434
|
return {
|
|
17068
|
-
version:
|
|
17069
|
-
subject:
|
|
17070
|
-
multiaddrs: [...
|
|
17071
|
-
updated_at:
|
|
17072
|
-
sequence:
|
|
17435
|
+
version: record2.version,
|
|
17436
|
+
subject: record2.subject,
|
|
17437
|
+
multiaddrs: [...record2.multiaddrs],
|
|
17438
|
+
updated_at: record2.updated_at,
|
|
17439
|
+
sequence: record2.sequence
|
|
17073
17440
|
};
|
|
17074
17441
|
}
|
|
17075
17442
|
function canonicalLocationPayload(payload) {
|
|
@@ -17128,13 +17495,13 @@ function validateLocationRecord(input) {
|
|
|
17128
17495
|
return { ...payload, signature };
|
|
17129
17496
|
}
|
|
17130
17497
|
async function verifyLocationRecord(input) {
|
|
17131
|
-
const
|
|
17132
|
-
const payload = canonicalLocationPayload(locationPayloadForRecord(
|
|
17133
|
-
if (
|
|
17134
|
-
return verifyPkhSignature(
|
|
17498
|
+
const record2 = validateLocationRecord(input);
|
|
17499
|
+
const payload = canonicalLocationPayload(locationPayloadForRecord(record2));
|
|
17500
|
+
if (record2.subject.startsWith("did:pkh:")) {
|
|
17501
|
+
return verifyPkhSignature(record2.subject, payload, record2.signature);
|
|
17135
17502
|
}
|
|
17136
|
-
if (
|
|
17137
|
-
return verifyDidKeySignature(
|
|
17503
|
+
if (record2.subject.startsWith("did:key:")) {
|
|
17504
|
+
return verifyDidKeySignature(record2.subject, payload, record2.signature);
|
|
17138
17505
|
}
|
|
17139
17506
|
return false;
|
|
17140
17507
|
}
|
|
@@ -17320,18 +17687,18 @@ async function fetchRegistryLocalLinkCandidates(options2, fetchFn, existingCandi
|
|
|
17320
17687
|
}
|
|
17321
17688
|
const registryUrl = options2.registryUrl ?? DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL;
|
|
17322
17689
|
try {
|
|
17323
|
-
const
|
|
17324
|
-
if (!
|
|
17690
|
+
const record2 = await fetchLocationRecord(registryUrl, options2.subject, fetchFn);
|
|
17691
|
+
if (!record2) {
|
|
17325
17692
|
return [];
|
|
17326
17693
|
}
|
|
17327
17694
|
const shouldVerify = options2.verifyRecords ?? true;
|
|
17328
|
-
if (shouldVerify && !await verifyLocationRecord(
|
|
17695
|
+
if (shouldVerify && !await verifyLocationRecord(record2)) {
|
|
17329
17696
|
debugLog(
|
|
17330
17697
|
`registry record signature invalid for ${options2.subject}; skipping local-link lookup`
|
|
17331
17698
|
);
|
|
17332
17699
|
return [];
|
|
17333
17700
|
}
|
|
17334
|
-
return extractLocalLinkUrls(
|
|
17701
|
+
return extractLocalLinkUrls(record2).filter((url) => !existingCandidates.some((c) => c.url === url)).map((url) => ({
|
|
17335
17702
|
source: "local-link",
|
|
17336
17703
|
url,
|
|
17337
17704
|
timeoutMs: LOCAL_LINK_PROBE_TIMEOUT_MS
|
|
@@ -17340,12 +17707,12 @@ async function fetchRegistryLocalLinkCandidates(options2, fetchFn, existingCandi
|
|
|
17340
17707
|
return [];
|
|
17341
17708
|
}
|
|
17342
17709
|
}
|
|
17343
|
-
function extractLocalLinkUrls(
|
|
17344
|
-
if (!
|
|
17710
|
+
function extractLocalLinkUrls(record2) {
|
|
17711
|
+
if (!record2) {
|
|
17345
17712
|
return [];
|
|
17346
17713
|
}
|
|
17347
17714
|
const urls = [];
|
|
17348
|
-
for (const addr of
|
|
17715
|
+
for (const addr of record2.multiaddrs) {
|
|
17349
17716
|
let url;
|
|
17350
17717
|
try {
|
|
17351
17718
|
url = multiaddrToHttpUrl(addr);
|
|
@@ -17444,12 +17811,12 @@ async function resolveCentralized(subject, options2, verifyRecords) {
|
|
|
17444
17811
|
if (!options2.centralizedRegistryUrl) {
|
|
17445
17812
|
return null;
|
|
17446
17813
|
}
|
|
17447
|
-
const
|
|
17814
|
+
const record2 = await fetchLocationRecord(
|
|
17448
17815
|
options2.centralizedRegistryUrl,
|
|
17449
17816
|
subject,
|
|
17450
17817
|
options2.fetch
|
|
17451
17818
|
);
|
|
17452
|
-
return toCandidate(subject, "centralized",
|
|
17819
|
+
return toCandidate(subject, "centralized", record2, verifyRecords);
|
|
17453
17820
|
});
|
|
17454
17821
|
}
|
|
17455
17822
|
async function resolveFallback(subject, multiaddrs) {
|
|
@@ -17481,18 +17848,18 @@ async function toCandidate(subject, source, input, verifyRecord) {
|
|
|
17481
17848
|
}
|
|
17482
17849
|
const maybeRecord = input;
|
|
17483
17850
|
if (maybeRecord.version === 1 && maybeRecord.signature !== void 0) {
|
|
17484
|
-
const
|
|
17485
|
-
if (
|
|
17851
|
+
const record2 = validateLocationRecord(input);
|
|
17852
|
+
if (record2.subject !== subject) {
|
|
17486
17853
|
throw new LocationRecordValidationError(
|
|
17487
17854
|
"location record subject does not match requested subject"
|
|
17488
17855
|
);
|
|
17489
17856
|
}
|
|
17490
|
-
if (verifyRecord && !await verifyLocationRecord(
|
|
17857
|
+
if (verifyRecord && !await verifyLocationRecord(record2)) {
|
|
17491
17858
|
throw new LocationRecordValidationError(
|
|
17492
17859
|
"location record signature is invalid"
|
|
17493
17860
|
);
|
|
17494
17861
|
}
|
|
17495
|
-
return { source, multiaddrs: [...
|
|
17862
|
+
return { source, multiaddrs: [...record2.multiaddrs], record: record2 };
|
|
17496
17863
|
}
|
|
17497
17864
|
const candidateInput = input;
|
|
17498
17865
|
if (!Array.isArray(candidateInput.multiaddrs)) {
|
|
@@ -17502,18 +17869,18 @@ async function toCandidate(subject, source, input, verifyRecord) {
|
|
|
17502
17869
|
}
|
|
17503
17870
|
validateMultiaddrs(candidateInput.multiaddrs);
|
|
17504
17871
|
if (candidateInput.record !== void 0) {
|
|
17505
|
-
const
|
|
17506
|
-
if (
|
|
17872
|
+
const record2 = validateLocationRecord(candidateInput.record);
|
|
17873
|
+
if (record2.subject !== subject) {
|
|
17507
17874
|
throw new LocationRecordValidationError(
|
|
17508
17875
|
"location record subject does not match requested subject"
|
|
17509
17876
|
);
|
|
17510
17877
|
}
|
|
17511
|
-
if (verifyRecord && !await verifyLocationRecord(
|
|
17878
|
+
if (verifyRecord && !await verifyLocationRecord(record2)) {
|
|
17512
17879
|
throw new LocationRecordValidationError(
|
|
17513
17880
|
"location record signature is invalid"
|
|
17514
17881
|
);
|
|
17515
17882
|
}
|
|
17516
|
-
return { source, multiaddrs: [...candidateInput.multiaddrs], record };
|
|
17883
|
+
return { source, multiaddrs: [...candidateInput.multiaddrs], record: record2 };
|
|
17517
17884
|
}
|
|
17518
17885
|
return { source, multiaddrs: [...candidateInput.multiaddrs] };
|
|
17519
17886
|
}
|
|
@@ -17570,7 +17937,7 @@ function verifyDidKeySignature(did, payload, signature) {
|
|
|
17570
17937
|
"did:key signature must be a base64url Ed25519 signature"
|
|
17571
17938
|
);
|
|
17572
17939
|
}
|
|
17573
|
-
return
|
|
17940
|
+
return import_ed2551910.ed25519.verify(
|
|
17574
17941
|
signatureBytes,
|
|
17575
17942
|
new TextEncoder().encode(payload),
|
|
17576
17943
|
publicKey
|
|
@@ -17578,7 +17945,7 @@ function verifyDidKeySignature(did, payload, signature) {
|
|
|
17578
17945
|
}
|
|
17579
17946
|
function verifyDidKeyEd25519Signature(did, payload, signature) {
|
|
17580
17947
|
const publicKey = ed25519PublicKeyFromDidKey2(did);
|
|
17581
|
-
return
|
|
17948
|
+
return import_ed2551910.ed25519.verify(signature, payload, publicKey);
|
|
17582
17949
|
}
|
|
17583
17950
|
function ed25519PublicKeyFromDidKey2(did) {
|
|
17584
17951
|
const identifier = did.slice("did:key:".length);
|