@tinycloud/sdk-core 3.0.0-beta.6 → 3.0.0-beta.7
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 +191 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +191 -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 +3 -3
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,
|
|
@@ -393,6 +394,7 @@ __export(index_exports, {
|
|
|
393
394
|
projectUnifiedPolicyCapabilities: () => projectUnifiedPolicyCapabilities,
|
|
394
395
|
projectUnifiedPolicyCapability: () => projectUnifiedPolicyCapability,
|
|
395
396
|
recapCaveatsEqual: () => recapCaveatsEqual,
|
|
397
|
+
registerPolicyV3: () => registerPolicyV3,
|
|
396
398
|
renewPolicyRootStatusV3: () => renewPolicyRootStatusV3,
|
|
397
399
|
requestTinyCloudManageKeyScope: () => requestTinyCloudManageKeyScope,
|
|
398
400
|
resolveCloudLocation: () => resolveCloudLocation,
|
|
@@ -3891,7 +3893,8 @@ var MAX_LEGACY_ENVELOPE_EXPIRES_AT = "2026-12-29T00:00:00Z";
|
|
|
3891
3893
|
var LAST_V2_READ_AT = "2027-01-05T00:00:00Z";
|
|
3892
3894
|
async function requestPolicyChallengeV3(input) {
|
|
3893
3895
|
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3894
|
-
const
|
|
3896
|
+
const policyRuntimePath = policyRuntimeBasePath(input.policyRuntimePath);
|
|
3897
|
+
const response = await fetchFn(new URL(`${policyRuntimePath}/challenges`, input.nodeOrigin), {
|
|
3895
3898
|
method: "POST",
|
|
3896
3899
|
redirect: "error",
|
|
3897
3900
|
signal: input.signal,
|
|
@@ -3904,6 +3907,13 @@ async function requestPolicyChallengeV3(input) {
|
|
|
3904
3907
|
throw new Error("policy challenge binding is invalid");
|
|
3905
3908
|
return value;
|
|
3906
3909
|
}
|
|
3910
|
+
function policyRuntimeBasePath(value) {
|
|
3911
|
+
const path = value ?? "/policy/v3";
|
|
3912
|
+
if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
|
|
3913
|
+
throw new Error("policy runtime path is invalid");
|
|
3914
|
+
}
|
|
3915
|
+
return path;
|
|
3916
|
+
}
|
|
3907
3917
|
function compactAttenuationForPolicyCapabilities(input) {
|
|
3908
3918
|
const attenuation = {};
|
|
3909
3919
|
for (const raw of input) {
|
|
@@ -3949,7 +3959,7 @@ function verifyPolicyRootStatusCheckpointV3(input) {
|
|
|
3949
3959
|
}
|
|
3950
3960
|
async function getPolicyRootStatusV3(input) {
|
|
3951
3961
|
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3952
|
-
const response = await fetchFn(new URL(`/
|
|
3962
|
+
const response = await fetchFn(new URL(`/policy/v3/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
|
|
3953
3963
|
method: "GET",
|
|
3954
3964
|
redirect: "error",
|
|
3955
3965
|
headers: { accept: "application/json" }
|
|
@@ -4008,7 +4018,7 @@ async function renewPolicyRootStatusV3(input) {
|
|
|
4008
4018
|
};
|
|
4009
4019
|
const signature = await input.sign((0, import_sha256.sha256)(new TextEncoder().encode(ROOT_STATUS_RENEWAL_V1_DOMAIN + jcsCanonicalize(unsigned))));
|
|
4010
4020
|
if (signature.length !== 64) throw new Error("policy root renewal signature must be Ed25519");
|
|
4011
|
-
const response = await fetchFn(new URL("/
|
|
4021
|
+
const response = await fetchFn(new URL("/policy/v3/status", input.nodeOrigin), {
|
|
4012
4022
|
method: "POST",
|
|
4013
4023
|
redirect: "error",
|
|
4014
4024
|
headers: { accept: "application/json", "content-type": "application/json" },
|
|
@@ -4263,6 +4273,133 @@ function contentSourceDigestHex(input) {
|
|
|
4263
4273
|
)
|
|
4264
4274
|
);
|
|
4265
4275
|
}
|
|
4276
|
+
function exactObject(value, keys, label) {
|
|
4277
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4278
|
+
throw new Error(`${label} is invalid`);
|
|
4279
|
+
}
|
|
4280
|
+
const record2 = value;
|
|
4281
|
+
if (Object.keys(record2).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record2, key))) {
|
|
4282
|
+
throw new Error(`${label} is invalid`);
|
|
4283
|
+
}
|
|
4284
|
+
return record2;
|
|
4285
|
+
}
|
|
4286
|
+
function didKeyEd25519PublicKey(value) {
|
|
4287
|
+
const principal = value.split("#", 1)[0];
|
|
4288
|
+
if (!principal.startsWith("did:key:")) {
|
|
4289
|
+
throw new Error("policy enforcer binding signer is invalid");
|
|
4290
|
+
}
|
|
4291
|
+
const material = base58btc.decode(principal.slice("did:key:".length));
|
|
4292
|
+
if (material.length !== 34 || material[0] !== 237 || material[1] !== 1) {
|
|
4293
|
+
throw new Error("policy enforcer binding signer is invalid");
|
|
4294
|
+
}
|
|
4295
|
+
return material.slice(2);
|
|
4296
|
+
}
|
|
4297
|
+
async function registerPolicyV3(input) {
|
|
4298
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
4299
|
+
const rootExpiresAt = new Date(input.rootExpiresAt);
|
|
4300
|
+
const canonicalRootExpiresAt = new Date(
|
|
4301
|
+
Math.floor(rootExpiresAt.getTime() / 1e3) * 1e3
|
|
4302
|
+
).toISOString().replace(/\.000Z$/, "Z");
|
|
4303
|
+
if (!Number.isFinite(rootExpiresAt.getTime()) || canonicalRootExpiresAt !== input.rootExpiresAt || rootExpiresAt.getTime() <= Date.now()) {
|
|
4304
|
+
throw new Error("policy root expiry is invalid");
|
|
4305
|
+
}
|
|
4306
|
+
const bindingResponse = await fetchFn(
|
|
4307
|
+
new URL("/policy/v3/enforcer-bindings", input.nodeOrigin),
|
|
4308
|
+
{
|
|
4309
|
+
method: "POST",
|
|
4310
|
+
redirect: "error",
|
|
4311
|
+
signal: input.signal,
|
|
4312
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
4313
|
+
body: JSON.stringify({
|
|
4314
|
+
rootExpiresAt: input.rootExpiresAt,
|
|
4315
|
+
enforcerDid: input.enforcerDid
|
|
4316
|
+
})
|
|
4317
|
+
}
|
|
4318
|
+
);
|
|
4319
|
+
if (!bindingResponse.ok) {
|
|
4320
|
+
throw new Error(`policy enforcer binding rejected (${bindingResponse.status})`);
|
|
4321
|
+
}
|
|
4322
|
+
const binding = exactObject(
|
|
4323
|
+
await bindingResponse.json(),
|
|
4324
|
+
[
|
|
4325
|
+
"schema",
|
|
4326
|
+
"enforcerDid",
|
|
4327
|
+
"nodeAudience",
|
|
4328
|
+
"attestationBindingDigestHex",
|
|
4329
|
+
"issuedAt",
|
|
4330
|
+
"expiresAt",
|
|
4331
|
+
"signature"
|
|
4332
|
+
],
|
|
4333
|
+
"policy enforcer binding"
|
|
4334
|
+
);
|
|
4335
|
+
const signature = exactObject(
|
|
4336
|
+
binding.signature,
|
|
4337
|
+
["suite", "signerDid", "value"],
|
|
4338
|
+
"policy enforcer binding signature"
|
|
4339
|
+
);
|
|
4340
|
+
const expectedBindingDigestHex = hex(
|
|
4341
|
+
(0, import_sha256.sha256)(
|
|
4342
|
+
new TextEncoder().encode(
|
|
4343
|
+
jcsCanonicalize({
|
|
4344
|
+
enforcerDid: input.enforcerDid,
|
|
4345
|
+
nodeAudience: input.expectedNodeAudience
|
|
4346
|
+
})
|
|
4347
|
+
)
|
|
4348
|
+
)
|
|
4349
|
+
);
|
|
4350
|
+
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") {
|
|
4351
|
+
throw new Error("policy enforcer binding is invalid");
|
|
4352
|
+
}
|
|
4353
|
+
const { signature: _signature, ...unsignedBinding } = binding;
|
|
4354
|
+
const signedBinding = (0, import_sha256.sha256)(
|
|
4355
|
+
new TextEncoder().encode(
|
|
4356
|
+
`xyz.tinycloud.policy/AttestedEnforcerBinding/v2\0${jcsCanonicalize(unsignedBinding)}`
|
|
4357
|
+
)
|
|
4358
|
+
);
|
|
4359
|
+
if (!import_ed255193.ed25519.verify(
|
|
4360
|
+
decodeBase64Url2(signature.value),
|
|
4361
|
+
signedBinding,
|
|
4362
|
+
didKeyEd25519PublicKey(input.expectedNodeAudience),
|
|
4363
|
+
{ zip215: false }
|
|
4364
|
+
)) {
|
|
4365
|
+
throw new Error("policy enforcer binding signature is invalid");
|
|
4366
|
+
}
|
|
4367
|
+
const response = await fetchFn(
|
|
4368
|
+
new URL("/policy/v3/policies", input.nodeOrigin),
|
|
4369
|
+
{
|
|
4370
|
+
method: "POST",
|
|
4371
|
+
redirect: "error",
|
|
4372
|
+
signal: input.signal,
|
|
4373
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
4374
|
+
body: JSON.stringify({
|
|
4375
|
+
policyCid: input.policyCid,
|
|
4376
|
+
policy: input.policy,
|
|
4377
|
+
policyRoot: input.policyRoot.authorization.replace(/^Bearer\s+/i, ""),
|
|
4378
|
+
enforcementRoot: input.enforcementRoot.authorization.replace(/^Bearer\s+/i, ""),
|
|
4379
|
+
contentSourceDigestHex: input.contentSourceDigestHex,
|
|
4380
|
+
nativeProjectionHashHex: input.nativeProjectionHashHex,
|
|
4381
|
+
attestedEnforcerBinding: binding
|
|
4382
|
+
})
|
|
4383
|
+
}
|
|
4384
|
+
);
|
|
4385
|
+
if (!response.ok) {
|
|
4386
|
+
throw new Error(`policy registration rejected (${response.status})`);
|
|
4387
|
+
}
|
|
4388
|
+
const receipt = exactObject(
|
|
4389
|
+
await response.json(),
|
|
4390
|
+
["policyCid", "policyRootCid", "enforcementRootCid"],
|
|
4391
|
+
"policy registration response"
|
|
4392
|
+
);
|
|
4393
|
+
if (receipt.policyCid !== input.policyCid || receipt.policyRootCid !== input.policyRoot.cid || receipt.enforcementRootCid !== input.enforcementRoot.cid) {
|
|
4394
|
+
throw new Error("policy registration response binding is invalid");
|
|
4395
|
+
}
|
|
4396
|
+
return {
|
|
4397
|
+
policyCid: input.policyCid,
|
|
4398
|
+
policyRootCid: input.policyRoot.cid,
|
|
4399
|
+
enforcementRootCid: input.enforcementRoot.cid,
|
|
4400
|
+
attestedEnforcerBinding: binding
|
|
4401
|
+
};
|
|
4402
|
+
}
|
|
4266
4403
|
function policyDigestHex(policy) {
|
|
4267
4404
|
const canonicalPolicy = {
|
|
4268
4405
|
...policy,
|
|
@@ -4879,6 +5016,7 @@ async function admitPolicyCredentialV3(input) {
|
|
|
4879
5016
|
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
4880
5017
|
const challenge = await requestPolicyChallengeV3({
|
|
4881
5018
|
nodeOrigin,
|
|
5019
|
+
policyRuntimePath: input.policyRuntimePath,
|
|
4882
5020
|
policyCid: input.policyCid,
|
|
4883
5021
|
recipientDid: input.credential.holderDid,
|
|
4884
5022
|
requestedCapabilities: input.requestedCapabilities,
|
|
@@ -4891,7 +5029,7 @@ async function admitPolicyCredentialV3(input) {
|
|
|
4891
5029
|
challenge
|
|
4892
5030
|
});
|
|
4893
5031
|
const response = await fetchFn(
|
|
4894
|
-
new URL(
|
|
5032
|
+
new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin),
|
|
4895
5033
|
{
|
|
4896
5034
|
method: "POST",
|
|
4897
5035
|
redirect: "error",
|
|
@@ -4936,6 +5074,7 @@ async function admitPolicyCredentialV4(input) {
|
|
|
4936
5074
|
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
4937
5075
|
const challenge = await requestPolicyChallengeV3({
|
|
4938
5076
|
nodeOrigin,
|
|
5077
|
+
policyRuntimePath: input.policyRuntimePath,
|
|
4939
5078
|
policyCid: input.policyCid,
|
|
4940
5079
|
recipientDid: input.credential.holderDid,
|
|
4941
5080
|
requestedCapabilities: input.requestedCapabilities,
|
|
@@ -4947,7 +5086,7 @@ async function admitPolicyCredentialV4(input) {
|
|
|
4947
5086
|
policy,
|
|
4948
5087
|
challenge
|
|
4949
5088
|
});
|
|
4950
|
-
const response = await fetchFn(new URL(
|
|
5089
|
+
const response = await fetchFn(new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin), {
|
|
4951
5090
|
method: "POST",
|
|
4952
5091
|
redirect: "error",
|
|
4953
5092
|
signal: input.signal,
|
|
@@ -4974,8 +5113,22 @@ async function admitPolicyCredentialV4(input) {
|
|
|
4974
5113
|
enforcerDid: input.expectedEnforcerDid
|
|
4975
5114
|
});
|
|
4976
5115
|
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");
|
|
5116
|
+
const importResponse = await fetchFn(new URL("/delegate", nodeOrigin), {
|
|
5117
|
+
method: "POST",
|
|
5118
|
+
redirect: "error",
|
|
5119
|
+
signal: input.signal,
|
|
5120
|
+
headers: { Authorization: session.authorization }
|
|
5121
|
+
});
|
|
5122
|
+
if (!importResponse.ok) throw new Error(`delegation import rejected (${importResponse.status})`);
|
|
4977
5123
|
input.signal?.throwIfAborted();
|
|
4978
|
-
return Object.freeze({ challenge, presentation, session });
|
|
5124
|
+
return Object.freeze({ challenge, presentation, session, delegationImported: true });
|
|
5125
|
+
}
|
|
5126
|
+
function policyRuntimeBasePath2(value) {
|
|
5127
|
+
const path = value ?? "/policy/v3";
|
|
5128
|
+
if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
|
|
5129
|
+
throw new Error("policy runtime path is invalid");
|
|
5130
|
+
}
|
|
5131
|
+
return path;
|
|
4979
5132
|
}
|
|
4980
5133
|
|
|
4981
5134
|
// src/requester/index.ts
|
|
@@ -12161,41 +12314,12 @@ function shareDeliveryTrustedKid(publicKey) {
|
|
|
12161
12314
|
|
|
12162
12315
|
// src/delegations/share-delivery-v3.ts
|
|
12163
12316
|
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) {
|
|
12317
|
+
var import_sha2567 = require("@noble/hashes/sha256");
|
|
12318
|
+
var CREDENTIAL_INVITATION_REQUEST_DOMAIN = "xyz.tinycloud.credentials/invitation-request/v1\0";
|
|
12319
|
+
var DELIVERY_ADMISSION_DOMAIN = "xyz.tinycloud.policy/delivery-admission/v0\0";
|
|
12320
|
+
var REQUEST_KEYS = ["schema", "policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "audience", "issuedAt", "expiresAt", "nonce"];
|
|
12321
|
+
var ADMISSION_KEYS = ["schema", "policyId", "ownerDid", "recipient", "resource", "actions", "credentialType", "returnLink", "envelopeRef", "senderKeyDid", "audience", "issuedAt", "expiresAt", "nonce", "signature"];
|
|
12322
|
+
function exactObject2(value, keys, label) {
|
|
12199
12323
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
|
|
12200
12324
|
const record2 = value;
|
|
12201
12325
|
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 +12338,12 @@ function object3(value, label) {
|
|
|
12214
12338
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
|
|
12215
12339
|
return value;
|
|
12216
12340
|
}
|
|
12341
|
+
function didKeyBytes2(did) {
|
|
12342
|
+
if (!did.startsWith("did:key:z") || /[#/?]/.test(did.slice("did:key:".length))) throw new Error("v3 delivery admission signer is invalid");
|
|
12343
|
+
const decoded = base58btc.decode(did.slice("did:key:".length));
|
|
12344
|
+
if (decoded.length !== 34 || decoded[0] !== 237 || decoded[1] !== 1) throw new Error("v3 delivery admission signer is invalid");
|
|
12345
|
+
return decoded.slice(2);
|
|
12346
|
+
}
|
|
12217
12347
|
function validateShareDeliveryAuthorizationV3Bytes(bytes2, expected) {
|
|
12218
12348
|
let parsed;
|
|
12219
12349
|
try {
|
|
@@ -12221,33 +12351,27 @@ function validateShareDeliveryAuthorizationV3Bytes(bytes2, expected) {
|
|
|
12221
12351
|
} catch {
|
|
12222
12352
|
throw new Error("v3 share delivery response is not valid UTF-8 JSON");
|
|
12223
12353
|
}
|
|
12224
|
-
const root =
|
|
12225
|
-
const
|
|
12226
|
-
const
|
|
12354
|
+
const root = exactObject2(parsed, ["request", "admission"], "v3 share delivery response");
|
|
12355
|
+
const request = exactObject2(root.request, REQUEST_KEYS, "credential invitation request");
|
|
12356
|
+
const admission = exactObject2(root.admission, ADMISSION_KEYS, "delivery admission");
|
|
12357
|
+
const signature = exactObject2(admission.signature, ["suite", "signerDid", "value"], "delivery admission signature");
|
|
12227
12358
|
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");
|
|
12359
|
+
const policy = object3(envelope.policy, "v3 share policy");
|
|
12360
|
+
const requirement = object3(policy.credentialRequirement, "v3 credential requirement");
|
|
12361
|
+
const credentialType = object3(requirement.credentialType, "v3 credential type");
|
|
12362
|
+
const contentSource = object3(envelope.contentSource, "v3 content source");
|
|
12233
12363
|
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 };
|
|
12364
|
+
const target = object3(envelope.target, "v3 target");
|
|
12365
|
+
const fields = ["policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "audience", "issuedAt", "expiresAt", "nonce"];
|
|
12366
|
+
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");
|
|
12367
|
+
const issuedAt = Date.parse(String(request.issuedAt));
|
|
12368
|
+
const expiresAt = Date.parse(String(request.expiresAt));
|
|
12369
|
+
if (!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || expiresAt <= issuedAt || expiresAt - issuedAt > 15 * 6e4) throw new Error("v3 share delivery authorization time is invalid");
|
|
12370
|
+
const admissionSignature = decodeBase64Url3(signature.value);
|
|
12371
|
+
const { signature: _signature, ...unsignedAdmission } = admission;
|
|
12372
|
+
const digest4 = (0, import_sha2567.sha256)(new TextEncoder().encode(`${DELIVERY_ADMISSION_DOMAIN}${canonicalizeSignedObjectUnsigned(unsignedAdmission)}`));
|
|
12373
|
+
if (admissionSignature.length !== 64 || !import_ed2551910.ed25519.verify(admissionSignature, digest4, didKeyBytes2(String(signature.signerDid)))) throw new Error("v3 share delivery admission signature is invalid");
|
|
12374
|
+
return { request, admission };
|
|
12251
12375
|
}
|
|
12252
12376
|
|
|
12253
12377
|
// src/delegations/sender-share-store.ts
|