@tinycloud/sdk-core 3.0.0-beta.6 → 3.0.0-beta.8
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/{credential-admission-BVUC6kdw.d.cts → credential-admission-CFjUChF8.d.cts} +56 -1
- package/dist/{credential-admission-BgvwOTIV.d.ts → credential-admission-DIEPgQ0o.d.ts} +56 -1
- package/dist/delegations/index.cjs +32 -60
- 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 +32 -60
- package/dist/delegations/index.js.map +1 -1
- package/dist/index.cjs +192 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +193 -67
- package/dist/index.js.map +1 -1
- package/dist/policy/index.cjs +159 -7
- 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 +159 -7
- package/dist/policy/index.js.map +1 -1
- package/dist/{recipient-types.schema-BdCeDExl.d.cts → recipient-types.schema-DjmM_yJu.d.cts} +37 -37
- package/dist/{recipient-types.schema-BdCeDExl.d.ts → recipient-types.schema-DjmM_yJu.d.ts} +37 -37
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -64,6 +64,7 @@ __export(index_exports, {
|
|
|
64
64
|
CREDENTIAL_CONTRACT_VERSION: () => CREDENTIAL_CONTRACT_VERSION,
|
|
65
65
|
CREDENTIAL_ERROR_CODES: () => CREDENTIAL_ERROR_CODES,
|
|
66
66
|
CREDENTIAL_FORMAT: () => CREDENTIAL_FORMAT,
|
|
67
|
+
CREDENTIAL_INVITATION_REQUEST_DOMAIN: () => CREDENTIAL_INVITATION_REQUEST_DOMAIN,
|
|
67
68
|
CREDENTIAL_PROTOCOL: () => CREDENTIAL_ACQUISITION_PROTOCOL,
|
|
68
69
|
CREDENTIAL_STEP_REGISTRY_VERSION: () => CREDENTIAL_STEP_REGISTRY_VERSION,
|
|
69
70
|
CapabilityKeyRegistry: () => CapabilityKeyRegistry,
|
|
@@ -87,6 +88,7 @@ __export(index_exports, {
|
|
|
87
88
|
DEFAULT_SIGNED_READ_URL_EXPIRY_MS: () => DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
|
|
88
89
|
DEFAULT_TINYCLOUD_FALLBACK_HOST: () => DEFAULT_TINYCLOUD_FALLBACK_HOST,
|
|
89
90
|
DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL: () => DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL,
|
|
91
|
+
DELIVERY_ADMISSION_DOMAIN: () => DELIVERY_ADMISSION_DOMAIN,
|
|
90
92
|
DUCKDB: () => import_bootstrap4.DUCKDB,
|
|
91
93
|
DataVaultService: () => import_sdk_services8.DataVaultService,
|
|
92
94
|
DatabaseHandle: () => import_sdk_services8.DatabaseHandle,
|
|
@@ -177,7 +179,6 @@ __export(index_exports, {
|
|
|
177
179
|
SERVICE_LONG_TO_SHORT: () => SERVICE_LONG_TO_SHORT,
|
|
178
180
|
SERVICE_SHORT_TO_LONG: () => SERVICE_SHORT_TO_LONG,
|
|
179
181
|
SHARE_DELIVERY_AUTHORIZATION_DOMAIN: () => SHARE_DELIVERY_AUTHORIZATION_DOMAIN,
|
|
180
|
-
SHARE_DELIVERY_AUTHORIZATION_V3_DOMAIN: () => SHARE_DELIVERY_AUTHORIZATION_V3_DOMAIN,
|
|
181
182
|
SPACE: () => import_bootstrap4.SPACE,
|
|
182
183
|
SQL: () => import_bootstrap4.SQL,
|
|
183
184
|
SQLAction: () => import_sdk_services8.SQLAction,
|
|
@@ -380,6 +381,7 @@ __export(index_exports, {
|
|
|
380
381
|
parsePolicySessionUcan: () => parsePolicySessionUcan,
|
|
381
382
|
parsePortableDelegation: () => parsePortableDelegation,
|
|
382
383
|
parseRecapCapabilities: () => parseRecapCapabilities,
|
|
384
|
+
parseSecretCatalogKey: () => import_sdk_services8.parseSecretCatalogKey,
|
|
383
385
|
parseShareArtifact: () => parseShareArtifact,
|
|
384
386
|
parseShareUrl: () => parseShareUrl,
|
|
385
387
|
parseSpaceUri: () => parseSpaceUri,
|
|
@@ -393,6 +395,7 @@ __export(index_exports, {
|
|
|
393
395
|
projectUnifiedPolicyCapabilities: () => projectUnifiedPolicyCapabilities,
|
|
394
396
|
projectUnifiedPolicyCapability: () => projectUnifiedPolicyCapability,
|
|
395
397
|
recapCaveatsEqual: () => recapCaveatsEqual,
|
|
398
|
+
registerPolicyV3: () => registerPolicyV3,
|
|
396
399
|
renewPolicyRootStatusV3: () => renewPolicyRootStatusV3,
|
|
397
400
|
requestTinyCloudManageKeyScope: () => requestTinyCloudManageKeyScope,
|
|
398
401
|
resolveCloudLocation: () => resolveCloudLocation,
|
|
@@ -3891,7 +3894,8 @@ var MAX_LEGACY_ENVELOPE_EXPIRES_AT = "2026-12-29T00:00:00Z";
|
|
|
3891
3894
|
var LAST_V2_READ_AT = "2027-01-05T00:00:00Z";
|
|
3892
3895
|
async function requestPolicyChallengeV3(input) {
|
|
3893
3896
|
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3894
|
-
const
|
|
3897
|
+
const policyRuntimePath = policyRuntimeBasePath(input.policyRuntimePath);
|
|
3898
|
+
const response = await fetchFn(new URL(`${policyRuntimePath}/challenges`, input.nodeOrigin), {
|
|
3895
3899
|
method: "POST",
|
|
3896
3900
|
redirect: "error",
|
|
3897
3901
|
signal: input.signal,
|
|
@@ -3904,6 +3908,13 @@ async function requestPolicyChallengeV3(input) {
|
|
|
3904
3908
|
throw new Error("policy challenge binding is invalid");
|
|
3905
3909
|
return value;
|
|
3906
3910
|
}
|
|
3911
|
+
function policyRuntimeBasePath(value) {
|
|
3912
|
+
const path = value ?? "/policy/v3";
|
|
3913
|
+
if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
|
|
3914
|
+
throw new Error("policy runtime path is invalid");
|
|
3915
|
+
}
|
|
3916
|
+
return path;
|
|
3917
|
+
}
|
|
3907
3918
|
function compactAttenuationForPolicyCapabilities(input) {
|
|
3908
3919
|
const attenuation = {};
|
|
3909
3920
|
for (const raw of input) {
|
|
@@ -3949,7 +3960,7 @@ function verifyPolicyRootStatusCheckpointV3(input) {
|
|
|
3949
3960
|
}
|
|
3950
3961
|
async function getPolicyRootStatusV3(input) {
|
|
3951
3962
|
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3952
|
-
const response = await fetchFn(new URL(`/
|
|
3963
|
+
const response = await fetchFn(new URL(`/policy/v3/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
|
|
3953
3964
|
method: "GET",
|
|
3954
3965
|
redirect: "error",
|
|
3955
3966
|
headers: { accept: "application/json" }
|
|
@@ -4008,7 +4019,7 @@ async function renewPolicyRootStatusV3(input) {
|
|
|
4008
4019
|
};
|
|
4009
4020
|
const signature = await input.sign((0, import_sha256.sha256)(new TextEncoder().encode(ROOT_STATUS_RENEWAL_V1_DOMAIN + jcsCanonicalize(unsigned))));
|
|
4010
4021
|
if (signature.length !== 64) throw new Error("policy root renewal signature must be Ed25519");
|
|
4011
|
-
const response = await fetchFn(new URL("/
|
|
4022
|
+
const response = await fetchFn(new URL("/policy/v3/status", input.nodeOrigin), {
|
|
4012
4023
|
method: "POST",
|
|
4013
4024
|
redirect: "error",
|
|
4014
4025
|
headers: { accept: "application/json", "content-type": "application/json" },
|
|
@@ -4263,6 +4274,133 @@ function contentSourceDigestHex(input) {
|
|
|
4263
4274
|
)
|
|
4264
4275
|
);
|
|
4265
4276
|
}
|
|
4277
|
+
function exactObject(value, keys, label) {
|
|
4278
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4279
|
+
throw new Error(`${label} is invalid`);
|
|
4280
|
+
}
|
|
4281
|
+
const record2 = value;
|
|
4282
|
+
if (Object.keys(record2).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record2, key))) {
|
|
4283
|
+
throw new Error(`${label} is invalid`);
|
|
4284
|
+
}
|
|
4285
|
+
return record2;
|
|
4286
|
+
}
|
|
4287
|
+
function didKeyEd25519PublicKey(value) {
|
|
4288
|
+
const principal = value.split("#", 1)[0];
|
|
4289
|
+
if (!principal.startsWith("did:key:")) {
|
|
4290
|
+
throw new Error("policy enforcer binding signer is invalid");
|
|
4291
|
+
}
|
|
4292
|
+
const material = base58btc.decode(principal.slice("did:key:".length));
|
|
4293
|
+
if (material.length !== 34 || material[0] !== 237 || material[1] !== 1) {
|
|
4294
|
+
throw new Error("policy enforcer binding signer is invalid");
|
|
4295
|
+
}
|
|
4296
|
+
return material.slice(2);
|
|
4297
|
+
}
|
|
4298
|
+
async function registerPolicyV3(input) {
|
|
4299
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
4300
|
+
const rootExpiresAt = new Date(input.rootExpiresAt);
|
|
4301
|
+
const canonicalRootExpiresAt = new Date(
|
|
4302
|
+
Math.floor(rootExpiresAt.getTime() / 1e3) * 1e3
|
|
4303
|
+
).toISOString().replace(/\.000Z$/, "Z");
|
|
4304
|
+
if (!Number.isFinite(rootExpiresAt.getTime()) || canonicalRootExpiresAt !== input.rootExpiresAt || rootExpiresAt.getTime() <= Date.now()) {
|
|
4305
|
+
throw new Error("policy root expiry is invalid");
|
|
4306
|
+
}
|
|
4307
|
+
const bindingResponse = await fetchFn(
|
|
4308
|
+
new URL("/policy/v3/enforcer-bindings", input.nodeOrigin),
|
|
4309
|
+
{
|
|
4310
|
+
method: "POST",
|
|
4311
|
+
redirect: "error",
|
|
4312
|
+
signal: input.signal,
|
|
4313
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
4314
|
+
body: JSON.stringify({
|
|
4315
|
+
rootExpiresAt: input.rootExpiresAt,
|
|
4316
|
+
enforcerDid: input.enforcerDid
|
|
4317
|
+
})
|
|
4318
|
+
}
|
|
4319
|
+
);
|
|
4320
|
+
if (!bindingResponse.ok) {
|
|
4321
|
+
throw new Error(`policy enforcer binding rejected (${bindingResponse.status})`);
|
|
4322
|
+
}
|
|
4323
|
+
const binding = exactObject(
|
|
4324
|
+
await bindingResponse.json(),
|
|
4325
|
+
[
|
|
4326
|
+
"schema",
|
|
4327
|
+
"enforcerDid",
|
|
4328
|
+
"nodeAudience",
|
|
4329
|
+
"attestationBindingDigestHex",
|
|
4330
|
+
"issuedAt",
|
|
4331
|
+
"expiresAt",
|
|
4332
|
+
"signature"
|
|
4333
|
+
],
|
|
4334
|
+
"policy enforcer binding"
|
|
4335
|
+
);
|
|
4336
|
+
const signature = exactObject(
|
|
4337
|
+
binding.signature,
|
|
4338
|
+
["suite", "signerDid", "value"],
|
|
4339
|
+
"policy enforcer binding signature"
|
|
4340
|
+
);
|
|
4341
|
+
const expectedBindingDigestHex = hex(
|
|
4342
|
+
(0, import_sha256.sha256)(
|
|
4343
|
+
new TextEncoder().encode(
|
|
4344
|
+
jcsCanonicalize({
|
|
4345
|
+
enforcerDid: input.enforcerDid,
|
|
4346
|
+
nodeAudience: input.expectedNodeAudience
|
|
4347
|
+
})
|
|
4348
|
+
)
|
|
4349
|
+
)
|
|
4350
|
+
);
|
|
4351
|
+
if (binding.schema !== ATTESTED_ENFORCER_BINDING_V2_SCHEMA || binding.enforcerDid !== input.enforcerDid || binding.nodeAudience !== input.expectedNodeAudience || binding.attestationBindingDigestHex !== expectedBindingDigestHex || binding.expiresAt !== input.rootExpiresAt || typeof binding.issuedAt !== "string" || Date.parse(binding.issuedAt) > Date.now() || signature.suite !== "Ed25519" || signature.signerDid !== input.expectedNodeAudience || typeof signature.value !== "string") {
|
|
4352
|
+
throw new Error("policy enforcer binding is invalid");
|
|
4353
|
+
}
|
|
4354
|
+
const { signature: _signature, ...unsignedBinding } = binding;
|
|
4355
|
+
const signedBinding = (0, import_sha256.sha256)(
|
|
4356
|
+
new TextEncoder().encode(
|
|
4357
|
+
`xyz.tinycloud.policy/AttestedEnforcerBinding/v2\0${jcsCanonicalize(unsignedBinding)}`
|
|
4358
|
+
)
|
|
4359
|
+
);
|
|
4360
|
+
if (!import_ed255193.ed25519.verify(
|
|
4361
|
+
decodeBase64Url2(signature.value),
|
|
4362
|
+
signedBinding,
|
|
4363
|
+
didKeyEd25519PublicKey(input.expectedNodeAudience),
|
|
4364
|
+
{ zip215: false }
|
|
4365
|
+
)) {
|
|
4366
|
+
throw new Error("policy enforcer binding signature is invalid");
|
|
4367
|
+
}
|
|
4368
|
+
const response = await fetchFn(
|
|
4369
|
+
new URL("/policy/v3/policies", input.nodeOrigin),
|
|
4370
|
+
{
|
|
4371
|
+
method: "POST",
|
|
4372
|
+
redirect: "error",
|
|
4373
|
+
signal: input.signal,
|
|
4374
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
4375
|
+
body: JSON.stringify({
|
|
4376
|
+
policyCid: input.policyCid,
|
|
4377
|
+
policy: input.policy,
|
|
4378
|
+
policyRoot: input.policyRoot.authorization.replace(/^Bearer\s+/i, ""),
|
|
4379
|
+
enforcementRoot: input.enforcementRoot.authorization.replace(/^Bearer\s+/i, ""),
|
|
4380
|
+
contentSourceDigestHex: input.contentSourceDigestHex,
|
|
4381
|
+
nativeProjectionHashHex: input.nativeProjectionHashHex,
|
|
4382
|
+
attestedEnforcerBinding: binding
|
|
4383
|
+
})
|
|
4384
|
+
}
|
|
4385
|
+
);
|
|
4386
|
+
if (!response.ok) {
|
|
4387
|
+
throw new Error(`policy registration rejected (${response.status})`);
|
|
4388
|
+
}
|
|
4389
|
+
const receipt = exactObject(
|
|
4390
|
+
await response.json(),
|
|
4391
|
+
["policyCid", "policyRootCid", "enforcementRootCid"],
|
|
4392
|
+
"policy registration response"
|
|
4393
|
+
);
|
|
4394
|
+
if (receipt.policyCid !== input.policyCid || receipt.policyRootCid !== input.policyRoot.cid || receipt.enforcementRootCid !== input.enforcementRoot.cid) {
|
|
4395
|
+
throw new Error("policy registration response binding is invalid");
|
|
4396
|
+
}
|
|
4397
|
+
return {
|
|
4398
|
+
policyCid: input.policyCid,
|
|
4399
|
+
policyRootCid: input.policyRoot.cid,
|
|
4400
|
+
enforcementRootCid: input.enforcementRoot.cid,
|
|
4401
|
+
attestedEnforcerBinding: binding
|
|
4402
|
+
};
|
|
4403
|
+
}
|
|
4266
4404
|
function policyDigestHex(policy) {
|
|
4267
4405
|
const canonicalPolicy = {
|
|
4268
4406
|
...policy,
|
|
@@ -4879,6 +5017,7 @@ async function admitPolicyCredentialV3(input) {
|
|
|
4879
5017
|
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
4880
5018
|
const challenge = await requestPolicyChallengeV3({
|
|
4881
5019
|
nodeOrigin,
|
|
5020
|
+
policyRuntimePath: input.policyRuntimePath,
|
|
4882
5021
|
policyCid: input.policyCid,
|
|
4883
5022
|
recipientDid: input.credential.holderDid,
|
|
4884
5023
|
requestedCapabilities: input.requestedCapabilities,
|
|
@@ -4891,7 +5030,7 @@ async function admitPolicyCredentialV3(input) {
|
|
|
4891
5030
|
challenge
|
|
4892
5031
|
});
|
|
4893
5032
|
const response = await fetchFn(
|
|
4894
|
-
new URL(
|
|
5033
|
+
new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin),
|
|
4895
5034
|
{
|
|
4896
5035
|
method: "POST",
|
|
4897
5036
|
redirect: "error",
|
|
@@ -4936,6 +5075,7 @@ async function admitPolicyCredentialV4(input) {
|
|
|
4936
5075
|
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
4937
5076
|
const challenge = await requestPolicyChallengeV3({
|
|
4938
5077
|
nodeOrigin,
|
|
5078
|
+
policyRuntimePath: input.policyRuntimePath,
|
|
4939
5079
|
policyCid: input.policyCid,
|
|
4940
5080
|
recipientDid: input.credential.holderDid,
|
|
4941
5081
|
requestedCapabilities: input.requestedCapabilities,
|
|
@@ -4947,7 +5087,7 @@ async function admitPolicyCredentialV4(input) {
|
|
|
4947
5087
|
policy,
|
|
4948
5088
|
challenge
|
|
4949
5089
|
});
|
|
4950
|
-
const response = await fetchFn(new URL(
|
|
5090
|
+
const response = await fetchFn(new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin), {
|
|
4951
5091
|
method: "POST",
|
|
4952
5092
|
redirect: "error",
|
|
4953
5093
|
signal: input.signal,
|
|
@@ -4974,8 +5114,22 @@ async function admitPolicyCredentialV4(input) {
|
|
|
4974
5114
|
enforcerDid: input.expectedEnforcerDid
|
|
4975
5115
|
});
|
|
4976
5116
|
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)) throw new Error("policy delegation signed binding is invalid");
|
|
5117
|
+
const importResponse = await fetchFn(new URL("/delegate", nodeOrigin), {
|
|
5118
|
+
method: "POST",
|
|
5119
|
+
redirect: "error",
|
|
5120
|
+
signal: input.signal,
|
|
5121
|
+
headers: { Authorization: session.authorization }
|
|
5122
|
+
});
|
|
5123
|
+
if (!importResponse.ok) throw new Error(`delegation import rejected (${importResponse.status})`);
|
|
4977
5124
|
input.signal?.throwIfAborted();
|
|
4978
|
-
return Object.freeze({ challenge, presentation, session });
|
|
5125
|
+
return Object.freeze({ challenge, presentation, session, delegationImported: true });
|
|
5126
|
+
}
|
|
5127
|
+
function policyRuntimeBasePath2(value) {
|
|
5128
|
+
const path = value ?? "/policy/v3";
|
|
5129
|
+
if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
|
|
5130
|
+
throw new Error("policy runtime path is invalid");
|
|
5131
|
+
}
|
|
5132
|
+
return path;
|
|
4979
5133
|
}
|
|
4980
5134
|
|
|
4981
5135
|
// src/requester/index.ts
|
|
@@ -12161,41 +12315,12 @@ function shareDeliveryTrustedKid(publicKey) {
|
|
|
12161
12315
|
|
|
12162
12316
|
// src/delegations/share-delivery-v3.ts
|
|
12163
12317
|
var import_ed2551910 = require("@noble/curves/ed25519");
|
|
12164
|
-
var
|
|
12165
|
-
var
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
"shareId",
|
|
12171
|
-
"policyCid",
|
|
12172
|
-
"policyRootCid",
|
|
12173
|
-
"enforcementRootCid",
|
|
12174
|
-
"nodeAudience",
|
|
12175
|
-
"enforcerDid",
|
|
12176
|
-
"targetOrigin",
|
|
12177
|
-
"openCredentialsAudience",
|
|
12178
|
-
"holder",
|
|
12179
|
-
"recipientMatcher",
|
|
12180
|
-
"deliveryEmail",
|
|
12181
|
-
"shareUrl",
|
|
12182
|
-
"returnOrigin",
|
|
12183
|
-
"documentName",
|
|
12184
|
-
"senderDid",
|
|
12185
|
-
"senderTrust",
|
|
12186
|
-
"contentSource",
|
|
12187
|
-
"contentSourceDigestHex",
|
|
12188
|
-
"shareExpiresAt",
|
|
12189
|
-
"issuedAt",
|
|
12190
|
-
"reportAbuseToken",
|
|
12191
|
-
"actions",
|
|
12192
|
-
"resource",
|
|
12193
|
-
"requestBodyDigest",
|
|
12194
|
-
"idempotencyKey",
|
|
12195
|
-
"expiresAt",
|
|
12196
|
-
"dataAuthority"
|
|
12197
|
-
];
|
|
12198
|
-
function exactObject(value, keys, label) {
|
|
12318
|
+
var import_sha2567 = require("@noble/hashes/sha256");
|
|
12319
|
+
var CREDENTIAL_INVITATION_REQUEST_DOMAIN = "xyz.tinycloud.credentials/invitation-request/v1\0";
|
|
12320
|
+
var DELIVERY_ADMISSION_DOMAIN = "xyz.tinycloud.policy/delivery-admission/v0\0";
|
|
12321
|
+
var REQUEST_KEYS = ["schema", "policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "audience", "issuedAt", "expiresAt", "nonce"];
|
|
12322
|
+
var ADMISSION_KEYS = ["schema", "policyId", "ownerDid", "recipient", "resource", "actions", "credentialType", "returnLink", "envelopeRef", "senderKeyDid", "audience", "issuedAt", "expiresAt", "nonce", "signature"];
|
|
12323
|
+
function exactObject2(value, keys, label) {
|
|
12199
12324
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
|
|
12200
12325
|
const record2 = value;
|
|
12201
12326
|
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`);
|
|
@@ -12214,6 +12339,12 @@ function object3(value, label) {
|
|
|
12214
12339
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
|
|
12215
12340
|
return value;
|
|
12216
12341
|
}
|
|
12342
|
+
function didKeyBytes2(did) {
|
|
12343
|
+
if (!did.startsWith("did:key:z") || /[#/?]/.test(did.slice("did:key:".length))) throw new Error("v3 delivery admission signer is invalid");
|
|
12344
|
+
const decoded = base58btc.decode(did.slice("did:key:".length));
|
|
12345
|
+
if (decoded.length !== 34 || decoded[0] !== 237 || decoded[1] !== 1) throw new Error("v3 delivery admission signer is invalid");
|
|
12346
|
+
return decoded.slice(2);
|
|
12347
|
+
}
|
|
12217
12348
|
function validateShareDeliveryAuthorizationV3Bytes(bytes2, expected) {
|
|
12218
12349
|
let parsed;
|
|
12219
12350
|
try {
|
|
@@ -12221,33 +12352,27 @@ function validateShareDeliveryAuthorizationV3Bytes(bytes2, expected) {
|
|
|
12221
12352
|
} catch {
|
|
12222
12353
|
throw new Error("v3 share delivery response is not valid UTF-8 JSON");
|
|
12223
12354
|
}
|
|
12224
|
-
const root =
|
|
12225
|
-
const
|
|
12226
|
-
const
|
|
12355
|
+
const root = exactObject2(parsed, ["request", "admission"], "v3 share delivery response");
|
|
12356
|
+
const request = exactObject2(root.request, REQUEST_KEYS, "credential invitation request");
|
|
12357
|
+
const admission = exactObject2(root.admission, ADMISSION_KEYS, "delivery admission");
|
|
12358
|
+
const signature = exactObject2(admission.signature, ["suite", "signerDid", "value"], "delivery admission signature");
|
|
12227
12359
|
const envelope = object3(expected.request.envelope, "v3 share envelope");
|
|
12228
|
-
const
|
|
12229
|
-
const
|
|
12230
|
-
const
|
|
12231
|
-
const
|
|
12232
|
-
const resource = object3(envelope.resource, "v3 resource");
|
|
12360
|
+
const policy = object3(envelope.policy, "v3 share policy");
|
|
12361
|
+
const requirement = object3(policy.credentialRequirement, "v3 credential requirement");
|
|
12362
|
+
const credentialType = object3(requirement.credentialType, "v3 credential type");
|
|
12363
|
+
const contentSource = object3(envelope.contentSource, "v3 content source");
|
|
12233
12364
|
const envelopeSignature = object3(envelope.signature, "v3 envelope signature");
|
|
12234
|
-
const
|
|
12235
|
-
const
|
|
12236
|
-
|
|
12237
|
-
const
|
|
12238
|
-
const
|
|
12239
|
-
if (
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
const
|
|
12243
|
-
|
|
12244
|
-
|
|
12245
|
-
if (!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || !Number.isFinite(shareExpiresAt) || expiresAt <= issuedAt || expiresAt - issuedAt > 5 * 6e4 || shareExpiresAt <= issuedAt || typeof authorization.holder !== "string" || !authorization.holder.startsWith("did:")) throw new Error("v3 share delivery authorization time or holder is invalid");
|
|
12246
|
-
const publicKey = expected.nodeProof.publicKey.length === 34 ? expected.nodeProof.publicKey.slice(2) : expected.nodeProof.publicKey;
|
|
12247
|
-
const signature = decodeBase64Url3(proof.signature);
|
|
12248
|
-
const signed = new TextEncoder().encode(`${SHARE_DELIVERY_AUTHORIZATION_V3_DOMAIN}${canonicalizeSignedObjectUnsigned(authorization)}`);
|
|
12249
|
-
if (publicKey.length !== 32 || signature.length !== 64 || !import_ed2551910.ed25519.verify(signature, signed, publicKey)) throw new Error("v3 share delivery proof signature is invalid");
|
|
12250
|
-
return { authorization, proof };
|
|
12365
|
+
const target = object3(envelope.target, "v3 target");
|
|
12366
|
+
const fields = ["policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "audience", "issuedAt", "expiresAt", "nonce"];
|
|
12367
|
+
if (request.schema !== "xyz.tinycloud.credentials/invitation-request/v1" || admission.schema !== "xyz.tinycloud.policy/delivery-admission/v0" || fields.some((field) => request[field] !== admission[field]) || request.policyId !== envelope.policyCid || request.recipient !== expected.request.recipientEmail || request.resource !== contentSource.kvResource || request.credentialType !== credentialType.id || request.credentialType !== "opencredentials.email/v1" || request.returnLink !== expected.request.shareUrl || request.envelopeRef !== expected.request.shareCid || request.audience !== expected.credentialsAudience || request.expiresAt !== expected.request.expiresAt || request.nonce !== expected.request.jti || admission.ownerDid !== envelopeSignature.signerDid || admission.senderKeyDid !== expected.senderKeyDid || canonicalizeSignedObjectUnsigned(admission.actions) !== canonicalizeSignedObjectUnsigned(["tinycloud.kv/get"]) || signature.suite !== "eddsa-ed25519-sha256-jcs-v1" || signature.signerDid !== target.nodeAudience) throw new Error("v3 share delivery authorization is not bound to the submitted request");
|
|
12368
|
+
const issuedAt = Date.parse(String(request.issuedAt));
|
|
12369
|
+
const expiresAt = Date.parse(String(request.expiresAt));
|
|
12370
|
+
if (!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || expiresAt <= issuedAt || expiresAt - issuedAt > 15 * 6e4) throw new Error("v3 share delivery authorization time is invalid");
|
|
12371
|
+
const admissionSignature = decodeBase64Url3(signature.value);
|
|
12372
|
+
const { signature: _signature, ...unsignedAdmission } = admission;
|
|
12373
|
+
const digest4 = (0, import_sha2567.sha256)(new TextEncoder().encode(`${DELIVERY_ADMISSION_DOMAIN}${canonicalizeSignedObjectUnsigned(unsignedAdmission)}`));
|
|
12374
|
+
if (admissionSignature.length !== 64 || !import_ed2551910.ed25519.verify(admissionSignature, digest4, didKeyBytes2(String(signature.signerDid)))) throw new Error("v3 share delivery admission signature is invalid");
|
|
12375
|
+
return { request, admission };
|
|
12251
12376
|
}
|
|
12252
12377
|
|
|
12253
12378
|
// src/delegations/sender-share-store.ts
|