@tinycloud/sdk-core 3.0.0-beta.8 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{credential-admission-CFjUChF8.d.cts → credential-admission-BxpkckU0.d.cts} +23 -3
- package/dist/{credential-admission-DIEPgQ0o.d.ts → credential-admission-CO9WMtGs.d.ts} +23 -3
- package/dist/delegations/index.cjs +101 -188
- package/dist/delegations/index.cjs.map +1 -1
- package/dist/delegations/index.d.cts +3 -3
- package/dist/delegations/index.d.ts +3 -3
- package/dist/delegations/index.js +102 -193
- package/dist/delegations/index.js.map +1 -1
- package/dist/index.cjs +381 -218
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +74 -7
- package/dist/index.d.ts +74 -7
- package/dist/index.js +382 -223
- package/dist/index.js.map +1 -1
- package/dist/policy/index.cjs +82 -36
- 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 +82 -36
- package/dist/policy/index.js.map +1 -1
- package/dist/{recipient-types.schema-DjmM_yJu.d.cts → recipient-types.schema-D9AI8tjN.d.cts} +42 -105
- package/dist/{recipient-types.schema-DjmM_yJu.d.ts → recipient-types.schema-D9AI8tjN.d.ts} +42 -105
- package/package.json +4 -4
package/dist/policy/index.cjs
CHANGED
|
@@ -108,6 +108,7 @@ __export(policy_exports, {
|
|
|
108
108
|
requestPolicyChallengeV3: () => requestPolicyChallengeV3,
|
|
109
109
|
revokePolicyRootV3: () => revokePolicyRootV3,
|
|
110
110
|
serializeJcsJson: () => serialize,
|
|
111
|
+
signCompactPolicyDescendant: () => signCompactPolicyDescendant,
|
|
111
112
|
signCompactUcanAuthorization: () => signCompactUcanAuthorization,
|
|
112
113
|
signCompactUcanRootAuthorization: () => signCompactUcanRootAuthorization,
|
|
113
114
|
signPolicyCredentialPresentationV4: () => signPolicyCredentialPresentationV4,
|
|
@@ -3939,8 +3940,9 @@ async function signCompactUcanAuthorization(input) {
|
|
|
3939
3940
|
throw new Error("compact invocation lifetime must be between one and 60 seconds");
|
|
3940
3941
|
return signCompactUcan(input);
|
|
3941
3942
|
}
|
|
3943
|
+
var MAX_POLICY_ROOT_SECONDS = 31 * 24 * 60 * 60;
|
|
3942
3944
|
async function signCompactUcanRootAuthorization(input) {
|
|
3943
|
-
if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore >
|
|
3945
|
+
if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore > MAX_POLICY_ROOT_SECONDS)
|
|
3944
3946
|
throw new Error("compact policy root lifetime must be between one second and 31 days");
|
|
3945
3947
|
return signCompactUcan({ ...input, proofs: [] });
|
|
3946
3948
|
}
|
|
@@ -3975,7 +3977,7 @@ function createCompactPolicyInvocation(input) {
|
|
|
3975
3977
|
const signature = import_ed255192.ed25519.sign(signingInput, input.privateKey);
|
|
3976
3978
|
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
3977
3979
|
}
|
|
3978
|
-
function
|
|
3980
|
+
function compactPolicyDescendantClaims(input) {
|
|
3979
3981
|
const parent = parseCompactUcanAuthorization(input.parentAuthorization, input.parentCid);
|
|
3980
3982
|
if (parent.payload.aud !== input.issuerDid) throw new Error("policy descendant issuer is not the parent audience");
|
|
3981
3983
|
const parentFact = parent.payload.fct[0];
|
|
@@ -3983,29 +3985,53 @@ function createCompactPolicyDescendant(input) {
|
|
|
3983
3985
|
if (!Number.isInteger(depth) || depth <= 0) throw new Error("policy descendant depth is exhausted");
|
|
3984
3986
|
if (!compactAttenuationContains(parent.payload.att, input.attenuation))
|
|
3985
3987
|
throw new Error("policy descendant exceeds the parent attenuation");
|
|
3988
|
+
const now = Math.max(input.now ?? parent.payload.nbf + 1, parent.payload.nbf + 1);
|
|
3989
|
+
const exp = Math.min(input.expiresAt ?? parent.payload.exp - 1, parent.payload.exp - 1);
|
|
3990
|
+
if (exp <= now) throw new Error("policy parent has no strictly narrower validity window");
|
|
3991
|
+
return {
|
|
3992
|
+
parentCid: parent.cid,
|
|
3993
|
+
fact: { ...parentFact, remainingRedelegationDepth: depth - 1 },
|
|
3994
|
+
notBefore: now,
|
|
3995
|
+
expiresAt: exp,
|
|
3996
|
+
nonce: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16)))
|
|
3997
|
+
};
|
|
3998
|
+
}
|
|
3999
|
+
function createCompactPolicyDescendant(input) {
|
|
4000
|
+
const claims = compactPolicyDescendantClaims(input);
|
|
3986
4001
|
const principal = input.issuerDid.split("#", 1)[0];
|
|
3987
4002
|
const didMaterial = base58btc.decode(principal.slice("did:key:".length));
|
|
3988
4003
|
const publicKey = import_ed255192.ed25519.getPublicKey(input.privateKey);
|
|
3989
4004
|
if (didMaterial.length !== 34 || !equalBytes(publicKey, didMaterial.slice(2))) throw new Error("policy descendant signer does not bind issuer DID");
|
|
3990
|
-
const now = Math.max(input.now ?? Math.floor(Date.now() / 1e3), parent.payload.nbf + 1);
|
|
3991
|
-
const exp = Math.min(input.expiresAt ?? now + 60, now + 60, parent.payload.exp - 1);
|
|
3992
|
-
if (exp <= now) throw new Error("policy parent has no strictly narrower validity window");
|
|
3993
4005
|
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) }, typ: "JWT", ucv: "0.10.0" };
|
|
3994
4006
|
const payload = {
|
|
3995
4007
|
att: input.attenuation,
|
|
3996
4008
|
aud: input.audienceDid,
|
|
3997
|
-
exp,
|
|
3998
|
-
fct: [
|
|
4009
|
+
exp: claims.expiresAt,
|
|
4010
|
+
fct: [claims.fact],
|
|
3999
4011
|
iss: input.issuerDid.includes("#") ? input.issuerDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
4000
|
-
nbf:
|
|
4001
|
-
nnc:
|
|
4002
|
-
prf: [
|
|
4012
|
+
nbf: claims.notBefore,
|
|
4013
|
+
nnc: claims.nonce,
|
|
4014
|
+
prf: [claims.parentCid]
|
|
4003
4015
|
};
|
|
4004
4016
|
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
4005
4017
|
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
4006
4018
|
const signature = import_ed255192.ed25519.sign(new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`), input.privateKey);
|
|
4007
4019
|
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
4008
4020
|
}
|
|
4021
|
+
async function signCompactPolicyDescendant(input) {
|
|
4022
|
+
const claims = compactPolicyDescendantClaims(input);
|
|
4023
|
+
return signCompactUcan({
|
|
4024
|
+
issuerDid: input.issuerDid,
|
|
4025
|
+
audienceDid: input.audienceDid,
|
|
4026
|
+
attenuation: input.attenuation,
|
|
4027
|
+
facts: [claims.fact],
|
|
4028
|
+
proofs: [claims.parentCid],
|
|
4029
|
+
notBefore: claims.notBefore,
|
|
4030
|
+
expiresAt: claims.expiresAt,
|
|
4031
|
+
nonce: claims.nonce,
|
|
4032
|
+
sign: input.sign
|
|
4033
|
+
});
|
|
4034
|
+
}
|
|
4009
4035
|
function compactAttenuationContains(parent, child) {
|
|
4010
4036
|
const selector = (value) => {
|
|
4011
4037
|
if (value.length !== 1 || !isRecordValue(value[0])) return void 0;
|
|
@@ -4075,7 +4101,7 @@ function parsePolicySessionUcan(authorization, expectedProofs) {
|
|
|
4075
4101
|
throw new Error("policy session UCAN fact is incomplete");
|
|
4076
4102
|
if (hasV4AuditFactShape && (!LOWER_SHA256_HEX.test(fact.credentialIdAuditDigestHex) || !LOWER_SHA256_HEX.test(fact.presentationJtiAuditDigestHex)))
|
|
4077
4103
|
throw new Error("policy session UCAN v4 audit facts are invalid");
|
|
4078
|
-
if (fact.profile !== POLICY_SESSION_UCAN_V1_PROFILE || typeof fact.remainingRedelegationDepth !== "number" || !Number.isInteger(fact.remainingRedelegationDepth) || fact.remainingRedelegationDepth < 0 || fact.remainingRedelegationDepth > 8 || parsed.payload.exp - parsed.payload.nbf >
|
|
4104
|
+
if (fact.profile !== POLICY_SESSION_UCAN_V1_PROFILE || typeof fact.remainingRedelegationDepth !== "number" || !Number.isInteger(fact.remainingRedelegationDepth) || fact.remainingRedelegationDepth < 0 || fact.remainingRedelegationDepth > 8 || parsed.payload.exp - parsed.payload.nbf > MAX_POLICY_ROOT_SECONDS || parsed.payload.iss.split("#", 1)[0] !== fact.nodeAudience || parsed.payload.aud !== fact.recipientDid)
|
|
4079
4105
|
throw new Error("policy session UCAN fact is invalid");
|
|
4080
4106
|
return {
|
|
4081
4107
|
authorization,
|
|
@@ -4156,6 +4182,7 @@ var RECOVERABLE = /* @__PURE__ */ new Set([
|
|
|
4156
4182
|
"ISSUER_UNREADY",
|
|
4157
4183
|
"OFFLINE",
|
|
4158
4184
|
"POPUP_BLOCKED",
|
|
4185
|
+
"PROOF_REJECTED",
|
|
4159
4186
|
"REQUEST_EXPIRED",
|
|
4160
4187
|
"SIGNATURE_REJECTED",
|
|
4161
4188
|
"UNSUPPORTED_PROFILE",
|
|
@@ -4174,6 +4201,7 @@ var CredentialError = class extends Error {
|
|
|
4174
4201
|
|
|
4175
4202
|
// src/credentials/requirement.ts
|
|
4176
4203
|
var ID = /^[a-z0-9][a-z0-9._-]{0,127}(?:\/v1)?$/;
|
|
4204
|
+
var CLAIM_NAME = /^[a-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
4177
4205
|
function validateCredentialRequirement(value) {
|
|
4178
4206
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new CredentialError("UNSUPPORTED_PROFILE", "Credential requirement is invalid");
|
|
4179
4207
|
const raw = value;
|
|
@@ -4187,7 +4215,7 @@ function validateCredentialRequirement(value) {
|
|
|
4187
4215
|
if (typeof raw.claims !== "object" || raw.claims === null || Array.isArray(raw.claims)) throw new CredentialError("UNSUPPORTED_PROFILE", "Credential claims are invalid");
|
|
4188
4216
|
const claims = {};
|
|
4189
4217
|
for (const [key, value2] of Object.entries(raw.claims).sort(([a], [b]) => a.localeCompare(b))) {
|
|
4190
|
-
if (!
|
|
4218
|
+
if (!CLAIM_NAME.test(key) || typeof value2 !== "string" || value2.length === 0 || value2.length > 4096) throw new CredentialError("UNSUPPORTED_PROFILE", "Credential claim is invalid");
|
|
4191
4219
|
claims[key] = value2;
|
|
4192
4220
|
}
|
|
4193
4221
|
if (raw.maxAgeSeconds !== void 0 && (!Number.isSafeInteger(raw.maxAgeSeconds) || raw.maxAgeSeconds < 1)) throw new CredentialError("UNSUPPORTED_PROFILE", "Credential freshness is invalid");
|
|
@@ -4568,24 +4596,21 @@ async function admitPolicyCredentialV3(input) {
|
|
|
4568
4596
|
policy,
|
|
4569
4597
|
challenge
|
|
4570
4598
|
});
|
|
4571
|
-
const response = await
|
|
4599
|
+
const response = await postPolicyDelegation(
|
|
4600
|
+
fetchFn,
|
|
4572
4601
|
new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin),
|
|
4573
4602
|
{
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
credentialSpaceId,
|
|
4586
|
-
presentation
|
|
4587
|
-
})
|
|
4588
|
-
}
|
|
4603
|
+
policyCid: input.policyCid,
|
|
4604
|
+
challengeId: challenge.challengeId,
|
|
4605
|
+
nonce: challenge.nonce,
|
|
4606
|
+
requirement: validateCredentialRequirement(input.requirement),
|
|
4607
|
+
credential: envelopeFromVerified(input.credential),
|
|
4608
|
+
accountAuthorizationCid,
|
|
4609
|
+
credentialSpaceId,
|
|
4610
|
+
presentation
|
|
4611
|
+
},
|
|
4612
|
+
requestedSessionExpiry(input.requestedExpiresAt, policy),
|
|
4613
|
+
input.signal
|
|
4589
4614
|
);
|
|
4590
4615
|
if (!response.ok) throw new Error(`policy delegation rejected (${response.status})`);
|
|
4591
4616
|
const value = record(await response.json(), "policy delegation");
|
|
@@ -4626,20 +4651,20 @@ async function admitPolicyCredentialV4(input) {
|
|
|
4626
4651
|
policy,
|
|
4627
4652
|
challenge
|
|
4628
4653
|
});
|
|
4629
|
-
const response = await
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
headers: { accept: "application/json", "content-type": "application/json" },
|
|
4634
|
-
body: JSON.stringify({
|
|
4654
|
+
const response = await postPolicyDelegation(
|
|
4655
|
+
fetchFn,
|
|
4656
|
+
new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin),
|
|
4657
|
+
{
|
|
4635
4658
|
policyCid: input.policyCid,
|
|
4636
4659
|
challengeId: challenge.challengeId,
|
|
4637
4660
|
nonce: challenge.nonce,
|
|
4638
4661
|
requirement: validateCredentialRequirement(input.requirement),
|
|
4639
4662
|
credential: envelopeFromVerified(input.credential),
|
|
4640
4663
|
presentation
|
|
4641
|
-
}
|
|
4642
|
-
|
|
4664
|
+
},
|
|
4665
|
+
requestedSessionExpiry(input.requestedExpiresAt, policy),
|
|
4666
|
+
input.signal
|
|
4667
|
+
);
|
|
4643
4668
|
if (!response.ok) throw new Error(`policy delegation rejected (${response.status})`);
|
|
4644
4669
|
const value = record(await response.json(), "policy delegation");
|
|
4645
4670
|
if (value.admitted !== true || typeof value.sessionCid !== "string" || typeof value.authorization !== "string") throw new Error("policy delegation response is invalid");
|
|
@@ -4663,6 +4688,27 @@ async function admitPolicyCredentialV4(input) {
|
|
|
4663
4688
|
input.signal?.throwIfAborted();
|
|
4664
4689
|
return Object.freeze({ challenge, presentation, session, delegationImported: true });
|
|
4665
4690
|
}
|
|
4691
|
+
function requestedSessionExpiry(requested, policy) {
|
|
4692
|
+
const value = requested === void 0 ? policy.expiresAt : requested;
|
|
4693
|
+
if (value === null || value === void 0) return void 0;
|
|
4694
|
+
const seconds = Math.floor(Date.parse(value) / 1e3);
|
|
4695
|
+
if (!Number.isFinite(seconds) || seconds <= Math.floor(Date.now() / 1e3) + 60) return void 0;
|
|
4696
|
+
return new Date(seconds * 1e3).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
4697
|
+
}
|
|
4698
|
+
async function postPolicyDelegation(fetchFn, url, body, requestedExpiresAt, signal) {
|
|
4699
|
+
const send = (payload) => fetchFn(url, {
|
|
4700
|
+
method: "POST",
|
|
4701
|
+
redirect: "error",
|
|
4702
|
+
signal,
|
|
4703
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
4704
|
+
body: JSON.stringify(payload)
|
|
4705
|
+
});
|
|
4706
|
+
if (requestedExpiresAt === void 0) return send(body);
|
|
4707
|
+
const response = await send({ ...body, requestedExpiresAt });
|
|
4708
|
+
if (response.status !== 422) return response;
|
|
4709
|
+
await response.body?.cancel().catch(() => void 0);
|
|
4710
|
+
return send(body);
|
|
4711
|
+
}
|
|
4666
4712
|
function policyRuntimeBasePath2(value) {
|
|
4667
4713
|
const path = value ?? "/policy/v3";
|
|
4668
4714
|
if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
|