@tinycloud/sdk-core 3.8.1-beta.2 → 3.9.0-beta.4
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-DCJhDFFv.d.ts → credential-admission-5iS1yUHN.d.ts} +19 -3
- package/dist/{credential-admission-B7_F6Yb3.d.cts → credential-admission-CB37nOWk.d.cts} +19 -3
- package/dist/held-credentials/index.cjs +286 -116
- package/dist/held-credentials/index.cjs.map +1 -1
- package/dist/held-credentials/index.d.cts +117 -40
- package/dist/held-credentials/index.d.ts +117 -40
- package/dist/held-credentials/index.js +286 -116
- package/dist/held-credentials/index.js.map +1 -1
- package/dist/index.cjs +14 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.js +14 -6
- package/dist/index.js.map +1 -1
- package/dist/policy/index.d.cts +2 -2
- package/dist/policy/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -3,6 +3,8 @@ import { z } from 'zod';
|
|
|
3
3
|
|
|
4
4
|
declare const CREDENTIAL_ACQUISITION_PROTOCOL: "tinycloud.credentials/acquisition/v1";
|
|
5
5
|
declare const HOLDER_BINDING_DOMAIN: "tinycloud.credentials/holder-binding/v1";
|
|
6
|
+
/** Signing domain of the held (account, EIP-191) binding. Equal to `ACCOUNT_BINDING_DOMAIN` of held-credentials. */
|
|
7
|
+
declare const ACCOUNT_HOLDER_BINDING_DOMAIN: "tinycloud.credentials/account-binding/v1";
|
|
6
8
|
declare const CREDENTIAL_CONTRACT_VERSION: 1;
|
|
7
9
|
declare const CREDENTIAL_STEP_REGISTRY_VERSION: 1;
|
|
8
10
|
declare const CREDENTIAL_FORMAT: "vc+sd-jwt";
|
|
@@ -65,14 +67,20 @@ interface CredentialFlowDescriptor {
|
|
|
65
67
|
readonly vct: string;
|
|
66
68
|
};
|
|
67
69
|
readonly claims: readonly CredentialClaimDescriptor[];
|
|
68
|
-
readonly subjectRelationship: "holder_is_subject";
|
|
70
|
+
readonly subjectRelationship: "holder_is_subject" | "account_is_subject";
|
|
69
71
|
readonly inputs: readonly CredentialInputDescriptor[];
|
|
70
72
|
readonly steps: readonly CredentialStepDescriptor[];
|
|
73
|
+
/** Ticket: `{EdDSA, holder-binding/v1}` with `holder_is_subject`. Held: `{EIP191, account-binding/v1}` with `account_is_subject`. */
|
|
71
74
|
readonly holderBinding: {
|
|
72
75
|
readonly required: true;
|
|
73
76
|
readonly alg: "EdDSA";
|
|
74
77
|
readonly domain: typeof HOLDER_BINDING_DOMAIN;
|
|
75
78
|
readonly version: 1;
|
|
79
|
+
} | {
|
|
80
|
+
readonly required: true;
|
|
81
|
+
readonly alg: "EIP191";
|
|
82
|
+
readonly domain: typeof ACCOUNT_HOLDER_BINDING_DOMAIN;
|
|
83
|
+
readonly version: 1;
|
|
76
84
|
};
|
|
77
85
|
readonly endpoints: Readonly<Record<"request" | "state" | "challenge" | "proof" | "holderBinding" | "holderSignature" | "issue" | "result", CredentialEndpointId>>;
|
|
78
86
|
readonly lifecycle: {
|
|
@@ -108,7 +116,8 @@ interface CredentialRequirement {
|
|
|
108
116
|
readonly claims: Readonly<Record<string, string>>;
|
|
109
117
|
readonly maxAgeSeconds?: number;
|
|
110
118
|
}
|
|
111
|
-
|
|
119
|
+
/** The ticket (did:key, EdDSA) holder binding: 19 fields. */
|
|
120
|
+
interface TicketHolderBinding {
|
|
112
121
|
readonly type: typeof HOLDER_BINDING_DOMAIN;
|
|
113
122
|
readonly protocol: typeof CREDENTIAL_ACQUISITION_PROTOCOL;
|
|
114
123
|
readonly requestId: string;
|
|
@@ -129,6 +138,13 @@ interface CredentialHolderBinding {
|
|
|
129
138
|
readonly issuedAt: string;
|
|
130
139
|
readonly expiresAt: string;
|
|
131
140
|
}
|
|
141
|
+
/** The held (account, EIP-191) holder binding: the ticket fields plus `credentialLifetimeSeconds`, a `urn:uuid` v4 `jti`, the account `type`. 20 fields. */
|
|
142
|
+
interface AccountHolderBinding extends Omit<TicketHolderBinding, "type"> {
|
|
143
|
+
readonly type: typeof ACCOUNT_HOLDER_BINDING_DOMAIN;
|
|
144
|
+
readonly credentialLifetimeSeconds: 31_536_000;
|
|
145
|
+
}
|
|
146
|
+
/** A holder binding is exactly one of the two shapes, keyed on `type`. */
|
|
147
|
+
type CredentialHolderBinding = TicketHolderBinding | AccountHolderBinding;
|
|
132
148
|
interface IssuerVerificationKey {
|
|
133
149
|
readonly kid: string;
|
|
134
150
|
readonly alg: "EdDSA";
|
|
@@ -929,4 +945,4 @@ interface PolicyCredentialAdmissionV4 {
|
|
|
929
945
|
/** Accountless admission. The request deliberately has no account custody fields. */
|
|
930
946
|
declare function admitPolicyCredentialV4(input: AdmitPolicyCredentialV4Input): Promise<PolicyCredentialAdmissionV4>;
|
|
931
947
|
|
|
932
|
-
export { type RegisterPolicyV3Input as $, ATTESTED_ENFORCER_BINDING_V2_SCHEMA as A, type BuildPolicyCredentialPresentationV3Input as B, CONTENT_SOURCE_V1_DOMAIN as C, type PolicyChallengeV3 as D, ED25519_JCS_SIGNATURE_SUITE as E, type PolicyCredentialAdmissionV3 as F, type PolicyCredentialAdmissionV4 as G, type PolicyCredentialPresentationV3 as H, type PolicyCredentialPresentationV4 as I, type JsonObject as J, type PolicyCredentialRequirementV1 as K, LAST_V2_CREATE_AT as L, MAX_LEGACY_ENVELOPE_EXPIRES_AT as M, NATIVE_PROJECTION_V1_DOMAIN as N, type PolicyRootStatusV3 as O, type PolicyEngineRecord as P, type PolicyRootV3 as Q, type PolicySessionUcanFactV1 as R, type SignedObjectSigner as S, type PolicySessionUcanV1 as T, type UnsignedPolicyEngineRecord as U, type PolicyStatus as V, ROOT_REVOCATION_V1_DOMAIN as W, ROOT_REVOCATION_V1_SCHEMA as X, ROOT_STATUS_CHECKPOINT_V1_SCHEMA as Y, ROOT_STATUS_RENEWAL_V1_DOMAIN as Z, ROOT_STATUS_V1_DOMAIN as _, type Policy as a, revokePolicyRootV3 as a$, type RegisterPolicyV3Receipt as a0, type SignCompactUcanAuthorizationInput as a1, type SignCompactUcanRootAuthorizationInput as a2, SignatureMaterialError as a3, type SignatureSuite as a4, SignatureVerificationError as a5, SignedObjectCanonicalizationError as a6, SignedObjectDigestError as a7, type SignedObjectErrorCode as a8, SignedObjectIdError as a9, canonicalizeSignedObjectUnsigned as aA, canonicalizeUnifiedPolicyCapability as aB, compactAttenuationContains as aC, contentSourceDigestHex as aD, createAndSignPolicy as aE, createAndSignPolicyEngineRecord as aF, createAndSignPolicyStatus as aG, createAndSignSignedObject as aH, createCompactPolicyDescendant as aI, createCompactPolicyInvocation as aJ, deriveSignedObjectMaterial as aK, getPolicyRootStatusV3 as aL, issuedCredentialEnvelopeFromVerified as aM, mintPolicySessionV3 as aN, normalizeUnifiedPolicyCapability as aO, parseCompactUcanAuthorization as aP, parsePolicySessionUcan as aQ, parseSignedCompactUcanAttenuation as aR, policyCidFromCanonicalBytes as aS, policyDigestHex as aT, policyIdForDigestHex as aU, policyV2DigestHex as aV, projectUnifiedPolicyCapabilities as aW, projectUnifiedPolicyCapability as aX, registerPolicyV3 as aY, renewPolicyRootStatusV3 as aZ, requestPolicyChallengeV3 as a_, type SignedObjectKind as aa, type SignedObjectMaterial as ab, SignedObjectProfileError as ac, SignedObjectSchemaError as ad, type SignedObjectSignature as ae, type SignedObjectVerificationResult as af, type SignedPolicyObject as ag, SigningKeyBindingError as ah, type UnifiedContentSource as ai, type UnifiedEncryptionCapability as aj, type UnifiedKvCapability as ak, type UnifiedNativeCapability as al, type UnifiedPolicyCapability as am, type UnifiedPolicyV1 as an, type UnifiedPolicyV2 as ao, type UnifiedResourceSelector as ap, type UnsignedPolicy as aq, type UnsignedPolicyCredentialPresentationV4 as ar, type UnsignedPolicyObject as as, type UnsignedPolicyStatus as at, type UnsignedUnifiedPolicyV2 as au, UnsupportedSignatureSuiteError as av, admitPolicyCredentialV3 as aw, admitPolicyCredentialV4 as ax, buildPolicyCredentialPresentationV3 as ay, buildPolicyCredentialPresentationV4 as az, type AdmitPolicyCredentialV3Input as b, signCompactPolicyDescendant as b0, signCompactUcanAuthorization as b1, signCompactUcanRootAuthorization as b2, signPolicyCredentialPresentationV4 as b3, signedObjectIdFor as b4, toSignedObjectError as b5, unifiedNativeProjectionHashHex as b6, unifiedPolicyCapabilityContains as b7, unifiedPolicyCapabilityDigestHex as b8, unifiedPolicyCapabilityFromNative as b9,
|
|
948
|
+
export { type RegisterPolicyV3Input as $, ATTESTED_ENFORCER_BINDING_V2_SCHEMA as A, type BuildPolicyCredentialPresentationV3Input as B, CONTENT_SOURCE_V1_DOMAIN as C, type PolicyChallengeV3 as D, ED25519_JCS_SIGNATURE_SUITE as E, type PolicyCredentialAdmissionV3 as F, type PolicyCredentialAdmissionV4 as G, type PolicyCredentialPresentationV3 as H, type PolicyCredentialPresentationV4 as I, type JsonObject as J, type PolicyCredentialRequirementV1 as K, LAST_V2_CREATE_AT as L, MAX_LEGACY_ENVELOPE_EXPIRES_AT as M, NATIVE_PROJECTION_V1_DOMAIN as N, type PolicyRootStatusV3 as O, type PolicyEngineRecord as P, type PolicyRootV3 as Q, type PolicySessionUcanFactV1 as R, type SignedObjectSigner as S, type PolicySessionUcanV1 as T, type UnsignedPolicyEngineRecord as U, type PolicyStatus as V, ROOT_REVOCATION_V1_DOMAIN as W, ROOT_REVOCATION_V1_SCHEMA as X, ROOT_STATUS_CHECKPOINT_V1_SCHEMA as Y, ROOT_STATUS_RENEWAL_V1_DOMAIN as Z, ROOT_STATUS_V1_DOMAIN as _, type Policy as a, revokePolicyRootV3 as a$, type RegisterPolicyV3Receipt as a0, type SignCompactUcanAuthorizationInput as a1, type SignCompactUcanRootAuthorizationInput as a2, SignatureMaterialError as a3, type SignatureSuite as a4, SignatureVerificationError as a5, SignedObjectCanonicalizationError as a6, SignedObjectDigestError as a7, type SignedObjectErrorCode as a8, SignedObjectIdError as a9, canonicalizeSignedObjectUnsigned as aA, canonicalizeUnifiedPolicyCapability as aB, compactAttenuationContains as aC, contentSourceDigestHex as aD, createAndSignPolicy as aE, createAndSignPolicyEngineRecord as aF, createAndSignPolicyStatus as aG, createAndSignSignedObject as aH, createCompactPolicyDescendant as aI, createCompactPolicyInvocation as aJ, deriveSignedObjectMaterial as aK, getPolicyRootStatusV3 as aL, issuedCredentialEnvelopeFromVerified as aM, mintPolicySessionV3 as aN, normalizeUnifiedPolicyCapability as aO, parseCompactUcanAuthorization as aP, parsePolicySessionUcan as aQ, parseSignedCompactUcanAttenuation as aR, policyCidFromCanonicalBytes as aS, policyDigestHex as aT, policyIdForDigestHex as aU, policyV2DigestHex as aV, projectUnifiedPolicyCapabilities as aW, projectUnifiedPolicyCapability as aX, registerPolicyV3 as aY, renewPolicyRootStatusV3 as aZ, requestPolicyChallengeV3 as a_, type SignedObjectKind as aa, type SignedObjectMaterial as ab, SignedObjectProfileError as ac, SignedObjectSchemaError as ad, type SignedObjectSignature as ae, type SignedObjectVerificationResult as af, type SignedPolicyObject as ag, SigningKeyBindingError as ah, type UnifiedContentSource as ai, type UnifiedEncryptionCapability as aj, type UnifiedKvCapability as ak, type UnifiedNativeCapability as al, type UnifiedPolicyCapability as am, type UnifiedPolicyV1 as an, type UnifiedPolicyV2 as ao, type UnifiedResourceSelector as ap, type UnsignedPolicy as aq, type UnsignedPolicyCredentialPresentationV4 as ar, type UnsignedPolicyObject as as, type UnsignedPolicyStatus as at, type UnsignedUnifiedPolicyV2 as au, UnsupportedSignatureSuiteError as av, admitPolicyCredentialV3 as aw, admitPolicyCredentialV4 as ax, buildPolicyCredentialPresentationV3 as ay, buildPolicyCredentialPresentationV4 as az, type AdmitPolicyCredentialV3Input as b, signCompactPolicyDescendant as b0, signCompactUcanAuthorization as b1, signCompactUcanRootAuthorization as b2, signPolicyCredentialPresentationV4 as b3, signedObjectIdFor as b4, toSignedObjectError as b5, unifiedNativeProjectionHashHex as b6, unifiedPolicyCapabilityContains as b7, unifiedPolicyCapabilityDigestHex as b8, unifiedPolicyCapabilityFromNative as b9, ACCOUNT_HOLDER_BINDING_DOMAIN as bA, type AccountHolderBinding as bB, CREDENTIAL_ACQUISITION_PROTOCOL as bC, CREDENTIAL_CONTRACT_VERSION as bD, CREDENTIAL_FORMAT as bE, CREDENTIAL_STEP_REGISTRY_VERSION as bF, type CredentialClaimDescriptor as bG, type CredentialEndpointId as bH, type CredentialInputDescriptor as bI, type CredentialProgressEvent as bJ, type CredentialStepDescriptor as bK, type CredentialStepType as bL, type CredentialUxState as bM, HOLDER_BINDING_DOMAIN as bN, type IssuerVerificationKey as bO, validatePolicyCredentialRequirementV1 as ba, validatePolicyEngineRecordSigned as bb, validatePolicyEngineRecordSignedShape as bc, validatePolicyEngineRecordUnsigned as bd, validatePolicySigned as be, validatePolicySignedShape as bf, validatePolicyStatusSigned as bg, validatePolicyStatusSignedShape as bh, validatePolicyStatusUnsigned as bi, validatePolicyUnsigned as bj, validateUnifiedPolicyV2 as bk, verifyPolicy as bl, verifyPolicyEngineRecord as bm, verifyPolicyRootRevocationV3 as bn, verifyPolicyRootStatusCheckpointV3 as bo, verifyPolicyStatus as bp, verifySignedObject as bq, type TicketHolderBinding as br, type CredentialHolderBinding as bs, type CredentialFlowDescriptor as bt, type CredentialRequirement as bu, type StoredCredentialRecord as bv, type VerifiedCredential as bw, type CredentialStorageReceipt as bx, type IssuedCredentialEnvelope as by, type CredentialIssuerMetadata as bz, type AdmitPolicyCredentialV4Input as c, type AttestedEnforcerBindingV2 as d, type BuildPolicyCredentialPresentationV4Input as e, type CompactPolicyDescendantInput as f, type CompactPolicyInvocationInput as g, type CompactUcanAuthorizationV1 as h, EIP191_JCS_SIGNATURE_SUITE as i, LAST_V2_READ_AT as j, POLICY_CAPABILITY_V1_DOMAIN as k, POLICY_CAPABILITY_V1_SCHEMA as l, POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE as m, POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA as n, POLICY_ENGINE_RECORD_SCHEMA as o, POLICY_PRESENTATION_V3_DOMAIN as p, POLICY_PRESENTATION_V3_SCHEMA as q, POLICY_PRESENTATION_V4_DOMAIN as r, POLICY_PRESENTATION_V4_SCHEMA as s, POLICY_SCHEMA as t, POLICY_SESSION_UCAN_V1_PROFILE as u, POLICY_STATUS_SCHEMA as v, POLICY_V1_DOMAIN as w, POLICY_V1_SCHEMA as x, POLICY_V2_DOMAIN as y, POLICY_V2_SCHEMA as z };
|
|
@@ -3,6 +3,8 @@ import { z } from 'zod';
|
|
|
3
3
|
|
|
4
4
|
declare const CREDENTIAL_ACQUISITION_PROTOCOL: "tinycloud.credentials/acquisition/v1";
|
|
5
5
|
declare const HOLDER_BINDING_DOMAIN: "tinycloud.credentials/holder-binding/v1";
|
|
6
|
+
/** Signing domain of the held (account, EIP-191) binding. Equal to `ACCOUNT_BINDING_DOMAIN` of held-credentials. */
|
|
7
|
+
declare const ACCOUNT_HOLDER_BINDING_DOMAIN: "tinycloud.credentials/account-binding/v1";
|
|
6
8
|
declare const CREDENTIAL_CONTRACT_VERSION: 1;
|
|
7
9
|
declare const CREDENTIAL_STEP_REGISTRY_VERSION: 1;
|
|
8
10
|
declare const CREDENTIAL_FORMAT: "vc+sd-jwt";
|
|
@@ -65,14 +67,20 @@ interface CredentialFlowDescriptor {
|
|
|
65
67
|
readonly vct: string;
|
|
66
68
|
};
|
|
67
69
|
readonly claims: readonly CredentialClaimDescriptor[];
|
|
68
|
-
readonly subjectRelationship: "holder_is_subject";
|
|
70
|
+
readonly subjectRelationship: "holder_is_subject" | "account_is_subject";
|
|
69
71
|
readonly inputs: readonly CredentialInputDescriptor[];
|
|
70
72
|
readonly steps: readonly CredentialStepDescriptor[];
|
|
73
|
+
/** Ticket: `{EdDSA, holder-binding/v1}` with `holder_is_subject`. Held: `{EIP191, account-binding/v1}` with `account_is_subject`. */
|
|
71
74
|
readonly holderBinding: {
|
|
72
75
|
readonly required: true;
|
|
73
76
|
readonly alg: "EdDSA";
|
|
74
77
|
readonly domain: typeof HOLDER_BINDING_DOMAIN;
|
|
75
78
|
readonly version: 1;
|
|
79
|
+
} | {
|
|
80
|
+
readonly required: true;
|
|
81
|
+
readonly alg: "EIP191";
|
|
82
|
+
readonly domain: typeof ACCOUNT_HOLDER_BINDING_DOMAIN;
|
|
83
|
+
readonly version: 1;
|
|
76
84
|
};
|
|
77
85
|
readonly endpoints: Readonly<Record<"request" | "state" | "challenge" | "proof" | "holderBinding" | "holderSignature" | "issue" | "result", CredentialEndpointId>>;
|
|
78
86
|
readonly lifecycle: {
|
|
@@ -108,7 +116,8 @@ interface CredentialRequirement {
|
|
|
108
116
|
readonly claims: Readonly<Record<string, string>>;
|
|
109
117
|
readonly maxAgeSeconds?: number;
|
|
110
118
|
}
|
|
111
|
-
|
|
119
|
+
/** The ticket (did:key, EdDSA) holder binding: 19 fields. */
|
|
120
|
+
interface TicketHolderBinding {
|
|
112
121
|
readonly type: typeof HOLDER_BINDING_DOMAIN;
|
|
113
122
|
readonly protocol: typeof CREDENTIAL_ACQUISITION_PROTOCOL;
|
|
114
123
|
readonly requestId: string;
|
|
@@ -129,6 +138,13 @@ interface CredentialHolderBinding {
|
|
|
129
138
|
readonly issuedAt: string;
|
|
130
139
|
readonly expiresAt: string;
|
|
131
140
|
}
|
|
141
|
+
/** The held (account, EIP-191) holder binding: the ticket fields plus `credentialLifetimeSeconds`, a `urn:uuid` v4 `jti`, the account `type`. 20 fields. */
|
|
142
|
+
interface AccountHolderBinding extends Omit<TicketHolderBinding, "type"> {
|
|
143
|
+
readonly type: typeof ACCOUNT_HOLDER_BINDING_DOMAIN;
|
|
144
|
+
readonly credentialLifetimeSeconds: 31_536_000;
|
|
145
|
+
}
|
|
146
|
+
/** A holder binding is exactly one of the two shapes, keyed on `type`. */
|
|
147
|
+
type CredentialHolderBinding = TicketHolderBinding | AccountHolderBinding;
|
|
132
148
|
interface IssuerVerificationKey {
|
|
133
149
|
readonly kid: string;
|
|
134
150
|
readonly alg: "EdDSA";
|
|
@@ -929,4 +945,4 @@ interface PolicyCredentialAdmissionV4 {
|
|
|
929
945
|
/** Accountless admission. The request deliberately has no account custody fields. */
|
|
930
946
|
declare function admitPolicyCredentialV4(input: AdmitPolicyCredentialV4Input): Promise<PolicyCredentialAdmissionV4>;
|
|
931
947
|
|
|
932
|
-
export { type RegisterPolicyV3Input as $, ATTESTED_ENFORCER_BINDING_V2_SCHEMA as A, type BuildPolicyCredentialPresentationV3Input as B, CONTENT_SOURCE_V1_DOMAIN as C, type PolicyChallengeV3 as D, ED25519_JCS_SIGNATURE_SUITE as E, type PolicyCredentialAdmissionV3 as F, type PolicyCredentialAdmissionV4 as G, type PolicyCredentialPresentationV3 as H, type PolicyCredentialPresentationV4 as I, type JsonObject as J, type PolicyCredentialRequirementV1 as K, LAST_V2_CREATE_AT as L, MAX_LEGACY_ENVELOPE_EXPIRES_AT as M, NATIVE_PROJECTION_V1_DOMAIN as N, type PolicyRootStatusV3 as O, type PolicyEngineRecord as P, type PolicyRootV3 as Q, type PolicySessionUcanFactV1 as R, type SignedObjectSigner as S, type PolicySessionUcanV1 as T, type UnsignedPolicyEngineRecord as U, type PolicyStatus as V, ROOT_REVOCATION_V1_DOMAIN as W, ROOT_REVOCATION_V1_SCHEMA as X, ROOT_STATUS_CHECKPOINT_V1_SCHEMA as Y, ROOT_STATUS_RENEWAL_V1_DOMAIN as Z, ROOT_STATUS_V1_DOMAIN as _, type Policy as a, revokePolicyRootV3 as a$, type RegisterPolicyV3Receipt as a0, type SignCompactUcanAuthorizationInput as a1, type SignCompactUcanRootAuthorizationInput as a2, SignatureMaterialError as a3, type SignatureSuite as a4, SignatureVerificationError as a5, SignedObjectCanonicalizationError as a6, SignedObjectDigestError as a7, type SignedObjectErrorCode as a8, SignedObjectIdError as a9, canonicalizeSignedObjectUnsigned as aA, canonicalizeUnifiedPolicyCapability as aB, compactAttenuationContains as aC, contentSourceDigestHex as aD, createAndSignPolicy as aE, createAndSignPolicyEngineRecord as aF, createAndSignPolicyStatus as aG, createAndSignSignedObject as aH, createCompactPolicyDescendant as aI, createCompactPolicyInvocation as aJ, deriveSignedObjectMaterial as aK, getPolicyRootStatusV3 as aL, issuedCredentialEnvelopeFromVerified as aM, mintPolicySessionV3 as aN, normalizeUnifiedPolicyCapability as aO, parseCompactUcanAuthorization as aP, parsePolicySessionUcan as aQ, parseSignedCompactUcanAttenuation as aR, policyCidFromCanonicalBytes as aS, policyDigestHex as aT, policyIdForDigestHex as aU, policyV2DigestHex as aV, projectUnifiedPolicyCapabilities as aW, projectUnifiedPolicyCapability as aX, registerPolicyV3 as aY, renewPolicyRootStatusV3 as aZ, requestPolicyChallengeV3 as a_, type SignedObjectKind as aa, type SignedObjectMaterial as ab, SignedObjectProfileError as ac, SignedObjectSchemaError as ad, type SignedObjectSignature as ae, type SignedObjectVerificationResult as af, type SignedPolicyObject as ag, SigningKeyBindingError as ah, type UnifiedContentSource as ai, type UnifiedEncryptionCapability as aj, type UnifiedKvCapability as ak, type UnifiedNativeCapability as al, type UnifiedPolicyCapability as am, type UnifiedPolicyV1 as an, type UnifiedPolicyV2 as ao, type UnifiedResourceSelector as ap, type UnsignedPolicy as aq, type UnsignedPolicyCredentialPresentationV4 as ar, type UnsignedPolicyObject as as, type UnsignedPolicyStatus as at, type UnsignedUnifiedPolicyV2 as au, UnsupportedSignatureSuiteError as av, admitPolicyCredentialV3 as aw, admitPolicyCredentialV4 as ax, buildPolicyCredentialPresentationV3 as ay, buildPolicyCredentialPresentationV4 as az, type AdmitPolicyCredentialV3Input as b, signCompactPolicyDescendant as b0, signCompactUcanAuthorization as b1, signCompactUcanRootAuthorization as b2, signPolicyCredentialPresentationV4 as b3, signedObjectIdFor as b4, toSignedObjectError as b5, unifiedNativeProjectionHashHex as b6, unifiedPolicyCapabilityContains as b7, unifiedPolicyCapabilityDigestHex as b8, unifiedPolicyCapabilityFromNative as b9,
|
|
948
|
+
export { type RegisterPolicyV3Input as $, ATTESTED_ENFORCER_BINDING_V2_SCHEMA as A, type BuildPolicyCredentialPresentationV3Input as B, CONTENT_SOURCE_V1_DOMAIN as C, type PolicyChallengeV3 as D, ED25519_JCS_SIGNATURE_SUITE as E, type PolicyCredentialAdmissionV3 as F, type PolicyCredentialAdmissionV4 as G, type PolicyCredentialPresentationV3 as H, type PolicyCredentialPresentationV4 as I, type JsonObject as J, type PolicyCredentialRequirementV1 as K, LAST_V2_CREATE_AT as L, MAX_LEGACY_ENVELOPE_EXPIRES_AT as M, NATIVE_PROJECTION_V1_DOMAIN as N, type PolicyRootStatusV3 as O, type PolicyEngineRecord as P, type PolicyRootV3 as Q, type PolicySessionUcanFactV1 as R, type SignedObjectSigner as S, type PolicySessionUcanV1 as T, type UnsignedPolicyEngineRecord as U, type PolicyStatus as V, ROOT_REVOCATION_V1_DOMAIN as W, ROOT_REVOCATION_V1_SCHEMA as X, ROOT_STATUS_CHECKPOINT_V1_SCHEMA as Y, ROOT_STATUS_RENEWAL_V1_DOMAIN as Z, ROOT_STATUS_V1_DOMAIN as _, type Policy as a, revokePolicyRootV3 as a$, type RegisterPolicyV3Receipt as a0, type SignCompactUcanAuthorizationInput as a1, type SignCompactUcanRootAuthorizationInput as a2, SignatureMaterialError as a3, type SignatureSuite as a4, SignatureVerificationError as a5, SignedObjectCanonicalizationError as a6, SignedObjectDigestError as a7, type SignedObjectErrorCode as a8, SignedObjectIdError as a9, canonicalizeSignedObjectUnsigned as aA, canonicalizeUnifiedPolicyCapability as aB, compactAttenuationContains as aC, contentSourceDigestHex as aD, createAndSignPolicy as aE, createAndSignPolicyEngineRecord as aF, createAndSignPolicyStatus as aG, createAndSignSignedObject as aH, createCompactPolicyDescendant as aI, createCompactPolicyInvocation as aJ, deriveSignedObjectMaterial as aK, getPolicyRootStatusV3 as aL, issuedCredentialEnvelopeFromVerified as aM, mintPolicySessionV3 as aN, normalizeUnifiedPolicyCapability as aO, parseCompactUcanAuthorization as aP, parsePolicySessionUcan as aQ, parseSignedCompactUcanAttenuation as aR, policyCidFromCanonicalBytes as aS, policyDigestHex as aT, policyIdForDigestHex as aU, policyV2DigestHex as aV, projectUnifiedPolicyCapabilities as aW, projectUnifiedPolicyCapability as aX, registerPolicyV3 as aY, renewPolicyRootStatusV3 as aZ, requestPolicyChallengeV3 as a_, type SignedObjectKind as aa, type SignedObjectMaterial as ab, SignedObjectProfileError as ac, SignedObjectSchemaError as ad, type SignedObjectSignature as ae, type SignedObjectVerificationResult as af, type SignedPolicyObject as ag, SigningKeyBindingError as ah, type UnifiedContentSource as ai, type UnifiedEncryptionCapability as aj, type UnifiedKvCapability as ak, type UnifiedNativeCapability as al, type UnifiedPolicyCapability as am, type UnifiedPolicyV1 as an, type UnifiedPolicyV2 as ao, type UnifiedResourceSelector as ap, type UnsignedPolicy as aq, type UnsignedPolicyCredentialPresentationV4 as ar, type UnsignedPolicyObject as as, type UnsignedPolicyStatus as at, type UnsignedUnifiedPolicyV2 as au, UnsupportedSignatureSuiteError as av, admitPolicyCredentialV3 as aw, admitPolicyCredentialV4 as ax, buildPolicyCredentialPresentationV3 as ay, buildPolicyCredentialPresentationV4 as az, type AdmitPolicyCredentialV3Input as b, signCompactPolicyDescendant as b0, signCompactUcanAuthorization as b1, signCompactUcanRootAuthorization as b2, signPolicyCredentialPresentationV4 as b3, signedObjectIdFor as b4, toSignedObjectError as b5, unifiedNativeProjectionHashHex as b6, unifiedPolicyCapabilityContains as b7, unifiedPolicyCapabilityDigestHex as b8, unifiedPolicyCapabilityFromNative as b9, ACCOUNT_HOLDER_BINDING_DOMAIN as bA, type AccountHolderBinding as bB, CREDENTIAL_ACQUISITION_PROTOCOL as bC, CREDENTIAL_CONTRACT_VERSION as bD, CREDENTIAL_FORMAT as bE, CREDENTIAL_STEP_REGISTRY_VERSION as bF, type CredentialClaimDescriptor as bG, type CredentialEndpointId as bH, type CredentialInputDescriptor as bI, type CredentialProgressEvent as bJ, type CredentialStepDescriptor as bK, type CredentialStepType as bL, type CredentialUxState as bM, HOLDER_BINDING_DOMAIN as bN, type IssuerVerificationKey as bO, validatePolicyCredentialRequirementV1 as ba, validatePolicyEngineRecordSigned as bb, validatePolicyEngineRecordSignedShape as bc, validatePolicyEngineRecordUnsigned as bd, validatePolicySigned as be, validatePolicySignedShape as bf, validatePolicyStatusSigned as bg, validatePolicyStatusSignedShape as bh, validatePolicyStatusUnsigned as bi, validatePolicyUnsigned as bj, validateUnifiedPolicyV2 as bk, verifyPolicy as bl, verifyPolicyEngineRecord as bm, verifyPolicyRootRevocationV3 as bn, verifyPolicyRootStatusCheckpointV3 as bo, verifyPolicyStatus as bp, verifySignedObject as bq, type TicketHolderBinding as br, type CredentialHolderBinding as bs, type CredentialFlowDescriptor as bt, type CredentialRequirement as bu, type StoredCredentialRecord as bv, type VerifiedCredential as bw, type CredentialStorageReceipt as bx, type IssuedCredentialEnvelope as by, type CredentialIssuerMetadata as bz, type AdmitPolicyCredentialV4Input as c, type AttestedEnforcerBindingV2 as d, type BuildPolicyCredentialPresentationV4Input as e, type CompactPolicyDescendantInput as f, type CompactPolicyInvocationInput as g, type CompactUcanAuthorizationV1 as h, EIP191_JCS_SIGNATURE_SUITE as i, LAST_V2_READ_AT as j, POLICY_CAPABILITY_V1_DOMAIN as k, POLICY_CAPABILITY_V1_SCHEMA as l, POLICY_CREDENTIAL_REQUIREMENT_V1_TYPE as m, POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA as n, POLICY_ENGINE_RECORD_SCHEMA as o, POLICY_PRESENTATION_V3_DOMAIN as p, POLICY_PRESENTATION_V3_SCHEMA as q, POLICY_PRESENTATION_V4_DOMAIN as r, POLICY_PRESENTATION_V4_SCHEMA as s, POLICY_SCHEMA as t, POLICY_SESSION_UCAN_V1_PROFILE as u, POLICY_STATUS_SCHEMA as v, POLICY_V1_DOMAIN as w, POLICY_V1_SCHEMA as x, POLICY_V2_DOMAIN as y, POLICY_V2_SCHEMA as z };
|
|
@@ -42,13 +42,18 @@ __export(held_credentials_exports, {
|
|
|
42
42
|
PRESENTATION_STATEMENT: () => PRESENTATION_STATEMENT,
|
|
43
43
|
SD_HASH_RESOURCE_PREFIX: () => SD_HASH_RESOURCE_PREFIX,
|
|
44
44
|
assertValidAudience: () => assertValidAudience,
|
|
45
|
+
buildHeldPresentationSiwe: () => buildHeldPresentationSiwe,
|
|
46
|
+
checkReturnedPresentation: () => checkReturnedPresentation,
|
|
45
47
|
normaliseEmail: () => normaliseEmail,
|
|
46
48
|
parseIssuerSet: () => parseIssuerSet,
|
|
47
49
|
parsePkhDid: () => parsePkhDid,
|
|
48
50
|
pkhPrincipalsEqual: () => pkhPrincipalsEqual,
|
|
49
51
|
randomNonce: () => randomNonce,
|
|
50
52
|
registryKey: () => registryKey,
|
|
53
|
+
sdHash: () => sdHash,
|
|
54
|
+
selectDisclosures: () => selectDisclosures,
|
|
51
55
|
toChecksumAddress: () => toChecksumAddress,
|
|
56
|
+
verifyHeldEmailCredential: () => verifyHeldEmailCredential,
|
|
52
57
|
verifyHeldPresentation: () => verifyHeldPresentation
|
|
53
58
|
});
|
|
54
59
|
module.exports = __toCommonJS(held_credentials_exports);
|
|
@@ -502,86 +507,7 @@ function parseIssuerSet(raw, options) {
|
|
|
502
507
|
return new IssuerSet(CONSTRUCT, raw.version, entries);
|
|
503
508
|
}
|
|
504
509
|
|
|
505
|
-
// src/held-credentials/
|
|
506
|
-
var PRESENTATION_STATEMENT = "Present a TinyCloud held credential";
|
|
507
|
-
var SD_HASH_RESOURCE_PREFIX = "urn:tinycloud:sd-hash:";
|
|
508
|
-
var RFC3339 = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?(?:Z|([+-])(\d{2}):(\d{2}))$/;
|
|
509
|
-
function parseRfc3339(value) {
|
|
510
|
-
const m = RFC3339.exec(value);
|
|
511
|
-
if (!m) return null;
|
|
512
|
-
const [year, month, day, hour, minute, second] = [m[1], m[2], m[3], m[4], m[5], m[6]].map(Number);
|
|
513
|
-
if (month < 1 || month > 12 || hour > 23 || minute > 59 || second > 59) return null;
|
|
514
|
-
const date = /* @__PURE__ */ new Date(0);
|
|
515
|
-
date.setUTCFullYear(year, month - 1, day);
|
|
516
|
-
if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) return null;
|
|
517
|
-
let offsetMinutes = 0;
|
|
518
|
-
if (m[8] !== void 0) {
|
|
519
|
-
const oh = Number(m[9]), om = Number(m[10]);
|
|
520
|
-
if (oh > 23 || om > 59) return null;
|
|
521
|
-
offsetMinutes = (m[8] === "-" ? -1 : 1) * (oh * 60 + om);
|
|
522
|
-
}
|
|
523
|
-
const millis = m[7] === void 0 ? 0 : Number(m[7].padEnd(3, "0").slice(0, 3));
|
|
524
|
-
date.setUTCHours(hour, minute, second, millis);
|
|
525
|
-
return date.getTime() - offsetMinutes * 6e4;
|
|
526
|
-
}
|
|
527
|
-
var AUDIENCE = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?(?::([1-9][0-9]{0,4}))?$/;
|
|
528
|
-
function assertValidAudience(audience) {
|
|
529
|
-
const match = AUDIENCE.exec(audience);
|
|
530
|
-
if (!match || match[1] !== void 0 && (Number(match[1]) > 65535 || match[1] === "443")) {
|
|
531
|
-
refuse("bad-config", "audience must be a lowercase host[:port] authority without a default port");
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
function parseStrictSiwe(message) {
|
|
535
|
-
const bad = (why) => refuse("bad-siwe", why);
|
|
536
|
-
const lines = message.split("\n");
|
|
537
|
-
const head = /^(\S+) wants you to sign in with your Ethereum account:$/.exec(lines[0] ?? "");
|
|
538
|
-
if (!head) bad("header line");
|
|
539
|
-
const address = lines[1] ?? "";
|
|
540
|
-
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) bad("address");
|
|
541
|
-
if (toChecksumAddress(address) !== address) bad("address must be EIP-55 checksummed");
|
|
542
|
-
if (lines[2] !== "") bad("layout");
|
|
543
|
-
const statement = lines[3];
|
|
544
|
-
if (statement === void 0 || statement === "") bad("statement");
|
|
545
|
-
if (lines[4] !== "") bad("layout");
|
|
546
|
-
let index = 5;
|
|
547
|
-
const field = (name, optional = false) => {
|
|
548
|
-
const line = lines[index];
|
|
549
|
-
const prefix = `${name}: `;
|
|
550
|
-
if (line === void 0 || !line.startsWith(prefix)) {
|
|
551
|
-
if (optional) return void 0;
|
|
552
|
-
return bad(`missing ${name}`);
|
|
553
|
-
}
|
|
554
|
-
index += 1;
|
|
555
|
-
const value = line.slice(prefix.length);
|
|
556
|
-
if (value === "") bad(`empty ${name}`);
|
|
557
|
-
return value;
|
|
558
|
-
};
|
|
559
|
-
const uri = field("URI");
|
|
560
|
-
const version = field("Version");
|
|
561
|
-
const chainId = field("Chain ID");
|
|
562
|
-
const nonce = field("Nonce");
|
|
563
|
-
const issuedAt = field("Issued At");
|
|
564
|
-
const expirationTime = field("Expiration Time", true);
|
|
565
|
-
const notBefore = field("Not Before", true);
|
|
566
|
-
if (lines[index]?.startsWith("Request ID: ")) bad("Request ID is not accepted");
|
|
567
|
-
const resources = [];
|
|
568
|
-
if (lines[index] === "Resources:") {
|
|
569
|
-
index += 1;
|
|
570
|
-
while (lines[index] !== void 0 && lines[index].startsWith("- ")) {
|
|
571
|
-
resources.push(lines[index].slice(2));
|
|
572
|
-
index += 1;
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
if (index !== lines.length) bad("trailing content");
|
|
576
|
-
if (!/^[0-9]+$/.test(chainId)) bad("chain id");
|
|
577
|
-
if (!/^[A-Za-z0-9]{8,}$/.test(nonce)) bad("nonce must be alphanumeric");
|
|
578
|
-
for (const [name, value] of [["Issued At", issuedAt], ["Expiration Time", expirationTime], ["Not Before", notBefore]]) {
|
|
579
|
-
if (value !== void 0 && parseRfc3339(value) === null) bad(`${name} is not RFC 3339`);
|
|
580
|
-
}
|
|
581
|
-
return { domain: head[1], address, statement, uri, version, chainId, nonce, issuedAt, expirationTime, notBefore, resources };
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// src/held-credentials/verify.ts
|
|
510
|
+
// src/held-credentials/credential.ts
|
|
585
511
|
var SHARED_SIGNED = /* @__PURE__ */ new Set(["iss", "sub", "iat", "nbf", "exp", "jti", "vct", "profile", "profileVersion", "holderBinding", "status", "_sd_alg", "_sd"]);
|
|
586
512
|
var RESERVED_CLAIMS = /* @__PURE__ */ new Set([...SHARED_SIGNED, "...", "cnf"]);
|
|
587
513
|
var HELD_LIMITS = {
|
|
@@ -597,36 +523,14 @@ var HELD_LIMITS = {
|
|
|
597
523
|
var HEADER_MEMBERS = /* @__PURE__ */ new Set(["alg", "typ", "kid"]);
|
|
598
524
|
var JTI_UUID_V4 = /^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
599
525
|
function sdHash(sdJwt) {
|
|
526
|
+
if (typeof sdJwt !== "string" || !isAscii(sdJwt)) refuse("bad-presentation", "sdJwt must be an ASCII string");
|
|
600
527
|
return encodeBase64Url((0, import_sha256.sha256)(asciiBytes(sdJwt)));
|
|
601
528
|
}
|
|
602
529
|
function isSafeInt(value) {
|
|
603
530
|
return typeof value === "number" && Number.isSafeInteger(value);
|
|
604
531
|
}
|
|
605
|
-
|
|
606
|
-
const { now, issuerSet, acceptedIssuers, acceptedProfiles, didMethods,
|
|
607
|
-
const rows = options.rows ?? DEFAULT_ROWS;
|
|
608
|
-
if (!(now instanceof Date) || Number.isNaN(now.getTime())) refuse("bad-config", "now must be a valid Date");
|
|
609
|
-
if (!IssuerSet.is(issuerSet)) refuse("bad-config", "issuerSet must come from parseIssuerSet");
|
|
610
|
-
if (!nonceStore || !didMethods || !Array.isArray(didMethods.issuer)) refuse("bad-config", "issuerSet, nonceStore and didMethods are required");
|
|
611
|
-
if (!Array.isArray(acceptedIssuers) || acceptedIssuers.length === 0) refuse("bad-config", "acceptedIssuers must not be empty");
|
|
612
|
-
if (!Array.isArray(acceptedProfiles) || acceptedProfiles.length === 0) refuse("bad-config", "acceptedProfiles must not be empty");
|
|
613
|
-
assertValidAudience(audience);
|
|
614
|
-
if (parsePkhDid(callerAccount) === null) refuse("bad-config", "callerAccount must be a did:pkh:eip155 account");
|
|
615
|
-
if (!isObject(presentation) || Object.keys(presentation).sort().join() !== "sdJwt,siwe") refuse("bad-presentation", "unexpected shape");
|
|
616
|
-
const { sdJwt, siwe } = presentation;
|
|
617
|
-
if (typeof sdJwt !== "string" || !isAscii(sdJwt)) refuse("bad-presentation", "sdJwt must be an ASCII string");
|
|
618
|
-
if (!isObject(siwe) || Object.keys(siwe).sort().join() !== "message,signature" || typeof siwe.message !== "string" || typeof siwe.signature !== "string") refuse("bad-presentation", "siwe shape");
|
|
619
|
-
const sdJwtText = sdJwt;
|
|
620
|
-
const siweMessage = siwe.message;
|
|
621
|
-
const siweSignature = siwe.signature;
|
|
622
|
-
if (sdJwtText.length > HELD_LIMITS.sdJwtChars) refuse("bad-presentation", "sdJwt is too long");
|
|
623
|
-
if (siweMessage.length > HELD_LIMITS.siweMessageChars) refuse("bad-presentation", "siwe message is too long");
|
|
624
|
-
if (siweSignature.length > HELD_LIMITS.siweSignatureChars) refuse("bad-presentation", "siwe signature is too long");
|
|
625
|
-
const message = parseStrictSiwe(siweMessage);
|
|
626
|
-
if (message.domain !== audience) refuse("bad-siwe", "domain is not this verifier's audience");
|
|
627
|
-
if (!/^[0-9A-Za-z]{22,}$/.test(message.nonce)) refuse("bad-nonce", "nonce must be at least 22 base62 characters (or 32 hex)");
|
|
628
|
-
const consumed = await nonceStore.consume(audience, message.nonce, callerAccount);
|
|
629
|
-
if (!consumed.existed) refuse("nonce-replayed", "nonce is unknown, already used, or bound to another account");
|
|
532
|
+
function checkHeldCredential(sdJwtText, policy) {
|
|
533
|
+
const { now, issuerSet, acceptedIssuers, acceptedProfiles, didMethods, rows } = policy;
|
|
630
534
|
const parts = sdJwtText.split("~");
|
|
631
535
|
if (parts.length < 2 || parts[parts.length - 1] !== "") refuse("bad-presentation", "sdJwt must end with ~ and carry no key-binding JWT");
|
|
632
536
|
const [jwt, ...disclosureParts] = parts.slice(0, -1);
|
|
@@ -713,6 +617,183 @@ async function verifyHeldPresentation(presentation, options) {
|
|
|
713
617
|
claims[name] = value;
|
|
714
618
|
}
|
|
715
619
|
row.validateDisclosed(claims);
|
|
620
|
+
return {
|
|
621
|
+
issuer: issuerDid,
|
|
622
|
+
subject,
|
|
623
|
+
subjectPkh,
|
|
624
|
+
issuedAt: new Date(iat * 1e3),
|
|
625
|
+
expiresAt: new Date(exp * 1e3),
|
|
626
|
+
credentialId: payload.jti,
|
|
627
|
+
profile,
|
|
628
|
+
profileVersion,
|
|
629
|
+
vct,
|
|
630
|
+
claims
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
function toVerifiedCredential(checked) {
|
|
634
|
+
return {
|
|
635
|
+
issuer: checked.issuer,
|
|
636
|
+
subject: canonicalPkhDid(checked.subject),
|
|
637
|
+
subjectAddress: registryKey(checked.subject),
|
|
638
|
+
expiresAt: checked.expiresAt,
|
|
639
|
+
credentialId: checked.credentialId,
|
|
640
|
+
profile: checked.profile,
|
|
641
|
+
profileVersion: checked.profileVersion,
|
|
642
|
+
vct: checked.vct,
|
|
643
|
+
claims: checked.claims
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
function verifyHeldEmailCredential(sdJwt, options) {
|
|
647
|
+
const { now, issuerSet, acceptedIssuers, didMethods, owner } = options;
|
|
648
|
+
if (!(now instanceof Date) || Number.isNaN(now.getTime())) refuse("bad-config", "now must be a valid Date");
|
|
649
|
+
if (!IssuerSet.is(issuerSet)) refuse("bad-config", "issuerSet must come from parseIssuerSet");
|
|
650
|
+
if (!didMethods || !Array.isArray(didMethods.issuer)) refuse("bad-config", "didMethods is required");
|
|
651
|
+
if (!Array.isArray(acceptedIssuers) || acceptedIssuers.length === 0) refuse("bad-config", "acceptedIssuers must not be empty");
|
|
652
|
+
if (parsePkhDid(owner) === null) refuse("bad-config", "owner must be a did:pkh:eip155 account");
|
|
653
|
+
if (typeof sdJwt !== "string" || !isAscii(sdJwt)) refuse("bad-presentation", "sdJwt must be an ASCII string");
|
|
654
|
+
if (sdJwt.length > HELD_LIMITS.sdJwtChars) refuse("bad-presentation", "sdJwt is too long");
|
|
655
|
+
const checked = checkHeldCredential(sdJwt, {
|
|
656
|
+
now,
|
|
657
|
+
issuerSet,
|
|
658
|
+
acceptedIssuers,
|
|
659
|
+
didMethods,
|
|
660
|
+
acceptedProfiles: [{ profile: EMAIL_HELD_ROW.profile, profileVersion: EMAIL_HELD_ROW.profileVersion }],
|
|
661
|
+
rows: [EMAIL_HELD_ROW]
|
|
662
|
+
});
|
|
663
|
+
if (!pkhPrincipalsEqual(owner, checked.subject)) refuse("nonce-account-mismatch", "subject is not the authenticated owner");
|
|
664
|
+
return { ...toVerifiedCredential(checked), issuedAt: checked.issuedAt };
|
|
665
|
+
}
|
|
666
|
+
function selectDisclosures(sdJwt, names) {
|
|
667
|
+
if (typeof sdJwt !== "string") refuse("bad-presentation", "sdJwt must be a string");
|
|
668
|
+
if (names.length === 0 || new Set(names).size !== names.length) refuse("bad-config", "names must be non-empty and unique");
|
|
669
|
+
const parts = sdJwt.split("~");
|
|
670
|
+
if (parts.length < 2 || parts[parts.length - 1] !== "") refuse("bad-presentation", "sdJwt must end with ~ and carry no key-binding JWT");
|
|
671
|
+
const [jwt, ...disclosures] = parts.slice(0, -1);
|
|
672
|
+
const kept = [];
|
|
673
|
+
const found = /* @__PURE__ */ new Set();
|
|
674
|
+
for (const disclosure of disclosures) {
|
|
675
|
+
const decoded = parseStrictJson(decodeUtf8(decodeBase64Url(disclosure, "bad-disclosure"), "bad-disclosure"), "bad-disclosure");
|
|
676
|
+
if (!Array.isArray(decoded) || decoded.length !== 3 || typeof decoded[1] !== "string") refuse("bad-disclosure", "disclosure must be [salt, name, value]");
|
|
677
|
+
const name = decoded[1];
|
|
678
|
+
if (names.includes(name)) {
|
|
679
|
+
if (found.has(name)) refuse("bad-disclosure", `duplicate disclosure for ${name}`);
|
|
680
|
+
kept.push(disclosure);
|
|
681
|
+
found.add(name);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
for (const name of names) if (!found.has(name)) refuse("bad-disclosure", `no disclosure for ${name}`);
|
|
685
|
+
return [jwt, ...kept, ""].join("~");
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// src/held-credentials/siwe.ts
|
|
689
|
+
var PRESENTATION_STATEMENT = "Present a TinyCloud held credential";
|
|
690
|
+
var SD_HASH_RESOURCE_PREFIX = "urn:tinycloud:sd-hash:";
|
|
691
|
+
var RFC3339 = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?(?:Z|([+-])(\d{2}):(\d{2}))$/;
|
|
692
|
+
function parseRfc3339(value) {
|
|
693
|
+
const m = RFC3339.exec(value);
|
|
694
|
+
if (!m) return null;
|
|
695
|
+
const [year, month, day, hour, minute, second] = [m[1], m[2], m[3], m[4], m[5], m[6]].map(Number);
|
|
696
|
+
if (month < 1 || month > 12 || hour > 23 || minute > 59 || second > 59) return null;
|
|
697
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
698
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
699
|
+
if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) return null;
|
|
700
|
+
let offsetMinutes = 0;
|
|
701
|
+
if (m[8] !== void 0) {
|
|
702
|
+
const oh = Number(m[9]), om = Number(m[10]);
|
|
703
|
+
if (oh > 23 || om > 59) return null;
|
|
704
|
+
offsetMinutes = (m[8] === "-" ? -1 : 1) * (oh * 60 + om);
|
|
705
|
+
}
|
|
706
|
+
const millis = m[7] === void 0 ? 0 : Number(m[7].padEnd(3, "0").slice(0, 3));
|
|
707
|
+
date.setUTCHours(hour, minute, second, millis);
|
|
708
|
+
return date.getTime() - offsetMinutes * 6e4;
|
|
709
|
+
}
|
|
710
|
+
var AUDIENCE = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?(?::([1-9][0-9]{0,4}))?$/;
|
|
711
|
+
function assertValidAudience(audience) {
|
|
712
|
+
const match = AUDIENCE.exec(audience);
|
|
713
|
+
if (!match || match[1] !== void 0 && (Number(match[1]) > 65535 || match[1] === "443")) {
|
|
714
|
+
refuse("bad-config", "audience must be a lowercase host[:port] authority without a default port");
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
function parseStrictSiwe(message) {
|
|
718
|
+
const bad = (why) => refuse("bad-siwe", why);
|
|
719
|
+
const lines = message.split("\n");
|
|
720
|
+
const head = /^(\S+) wants you to sign in with your Ethereum account:$/.exec(lines[0] ?? "");
|
|
721
|
+
if (!head) bad("header line");
|
|
722
|
+
const address = lines[1] ?? "";
|
|
723
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) bad("address");
|
|
724
|
+
if (toChecksumAddress(address) !== address) bad("address must be EIP-55 checksummed");
|
|
725
|
+
if (lines[2] !== "") bad("layout");
|
|
726
|
+
const statement = lines[3];
|
|
727
|
+
if (statement === void 0 || statement === "") bad("statement");
|
|
728
|
+
if (lines[4] !== "") bad("layout");
|
|
729
|
+
let index = 5;
|
|
730
|
+
const field = (name, optional = false) => {
|
|
731
|
+
const line = lines[index];
|
|
732
|
+
const prefix = `${name}: `;
|
|
733
|
+
if (line === void 0 || !line.startsWith(prefix)) {
|
|
734
|
+
if (optional) return void 0;
|
|
735
|
+
return bad(`missing ${name}`);
|
|
736
|
+
}
|
|
737
|
+
index += 1;
|
|
738
|
+
const value = line.slice(prefix.length);
|
|
739
|
+
if (value === "") bad(`empty ${name}`);
|
|
740
|
+
return value;
|
|
741
|
+
};
|
|
742
|
+
const uri = field("URI");
|
|
743
|
+
const version = field("Version");
|
|
744
|
+
const chainId = field("Chain ID");
|
|
745
|
+
const nonce = field("Nonce");
|
|
746
|
+
const issuedAt = field("Issued At");
|
|
747
|
+
const expirationTime = field("Expiration Time", true);
|
|
748
|
+
const notBefore = field("Not Before", true);
|
|
749
|
+
if (lines[index]?.startsWith("Request ID: ")) bad("Request ID is not accepted");
|
|
750
|
+
const resources = [];
|
|
751
|
+
if (lines[index] === "Resources:") {
|
|
752
|
+
index += 1;
|
|
753
|
+
while (lines[index] !== void 0 && lines[index].startsWith("- ")) {
|
|
754
|
+
resources.push(lines[index].slice(2));
|
|
755
|
+
index += 1;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
if (index !== lines.length) bad("trailing content");
|
|
759
|
+
if (!/^[0-9]+$/.test(chainId)) bad("chain id");
|
|
760
|
+
if (!/^[A-Za-z0-9]{8,}$/.test(nonce)) bad("nonce must be alphanumeric");
|
|
761
|
+
for (const [name, value] of [["Issued At", issuedAt], ["Expiration Time", expirationTime], ["Not Before", notBefore]]) {
|
|
762
|
+
if (value !== void 0 && parseRfc3339(value) === null) bad(`${name} is not RFC 3339`);
|
|
763
|
+
}
|
|
764
|
+
return { domain: head[1], address, statement, uri, version, chainId, nonce, issuedAt, expirationTime, notBefore, resources };
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// src/held-credentials/verify.ts
|
|
768
|
+
async function verifyHeldPresentation(presentation, options) {
|
|
769
|
+
const { now, issuerSet, acceptedIssuers, acceptedProfiles, didMethods, audience, nonceStore, callerAccount } = options;
|
|
770
|
+
const rows = options.rows ?? DEFAULT_ROWS;
|
|
771
|
+
if (!(now instanceof Date) || Number.isNaN(now.getTime())) refuse("bad-config", "now must be a valid Date");
|
|
772
|
+
if (!IssuerSet.is(issuerSet)) refuse("bad-config", "issuerSet must come from parseIssuerSet");
|
|
773
|
+
if (!nonceStore || !didMethods || !Array.isArray(didMethods.issuer)) refuse("bad-config", "issuerSet, nonceStore and didMethods are required");
|
|
774
|
+
if (!Array.isArray(acceptedIssuers) || acceptedIssuers.length === 0) refuse("bad-config", "acceptedIssuers must not be empty");
|
|
775
|
+
if (!Array.isArray(acceptedProfiles) || acceptedProfiles.length === 0) refuse("bad-config", "acceptedProfiles must not be empty");
|
|
776
|
+
assertValidAudience(audience);
|
|
777
|
+
if (parsePkhDid(callerAccount) === null) refuse("bad-config", "callerAccount must be a did:pkh:eip155 account");
|
|
778
|
+
if (!isObject(presentation) || Object.keys(presentation).sort().join() !== "sdJwt,siwe") refuse("bad-presentation", "unexpected shape");
|
|
779
|
+
const { sdJwt, siwe } = presentation;
|
|
780
|
+
if (typeof sdJwt !== "string" || !isAscii(sdJwt)) refuse("bad-presentation", "sdJwt must be an ASCII string");
|
|
781
|
+
if (!isObject(siwe) || Object.keys(siwe).sort().join() !== "message,signature" || typeof siwe.message !== "string" || typeof siwe.signature !== "string") refuse("bad-presentation", "siwe shape");
|
|
782
|
+
const sdJwtText = sdJwt;
|
|
783
|
+
const siweMessage = siwe.message;
|
|
784
|
+
const siweSignature = siwe.signature;
|
|
785
|
+
if (sdJwtText.length > HELD_LIMITS.sdJwtChars) refuse("bad-presentation", "sdJwt is too long");
|
|
786
|
+
if (siweMessage.length > HELD_LIMITS.siweMessageChars) refuse("bad-presentation", "siwe message is too long");
|
|
787
|
+
if (siweSignature.length > HELD_LIMITS.siweSignatureChars) refuse("bad-presentation", "siwe signature is too long");
|
|
788
|
+
const message = parseStrictSiwe(siweMessage);
|
|
789
|
+
if (message.domain !== audience) refuse("bad-siwe", "domain is not this verifier's audience");
|
|
790
|
+
if (!/^[0-9A-Za-z]{22,}$/.test(message.nonce)) refuse("bad-nonce", "nonce must be at least 22 base62 characters (or 32 hex)");
|
|
791
|
+
const consumed = await nonceStore.consume(audience, message.nonce, callerAccount);
|
|
792
|
+
if (!consumed.existed) refuse("nonce-replayed", "nonce is unknown, already used, or bound to another account");
|
|
793
|
+
const checked = checkHeldCredential(sdJwtText, { now, issuerSet, acceptedIssuers, acceptedProfiles, didMethods, rows });
|
|
794
|
+
const subject = checked.subject;
|
|
795
|
+
const subjectPkh = checked.subjectPkh;
|
|
796
|
+
const nowMs = now.getTime();
|
|
716
797
|
let origin;
|
|
717
798
|
try {
|
|
718
799
|
const url = new URL(message.uri);
|
|
@@ -732,17 +813,7 @@ async function verifyHeldPresentation(presentation, options) {
|
|
|
732
813
|
const recovered = recoverEip191Address(siweMessage, signatureBytes);
|
|
733
814
|
if (recovered === null || recovered !== subjectPkh.address) refuse("bad-siwe-signature", "signature does not recover the credential subject");
|
|
734
815
|
if (!pkhPrincipalsEqual(callerAccount, subject)) refuse("nonce-account-mismatch", "subject is not the authenticated caller");
|
|
735
|
-
return
|
|
736
|
-
issuer: issuerDid,
|
|
737
|
-
subject: canonicalPkhDid(subject),
|
|
738
|
-
subjectAddress: registryKey(subject),
|
|
739
|
-
expiresAt: new Date(exp * 1e3),
|
|
740
|
-
credentialId: payload.jti,
|
|
741
|
-
profile,
|
|
742
|
-
profileVersion,
|
|
743
|
-
vct,
|
|
744
|
-
claims
|
|
745
|
-
};
|
|
816
|
+
return toVerifiedCredential(checked);
|
|
746
817
|
}
|
|
747
818
|
|
|
748
819
|
// src/held-credentials/nonce-store.ts
|
|
@@ -790,4 +861,103 @@ function normaliseEmail(email) {
|
|
|
790
861
|
if (local === "") return null;
|
|
791
862
|
return `${local}@${domain}`;
|
|
792
863
|
}
|
|
864
|
+
|
|
865
|
+
// src/held-credentials/presentation.ts
|
|
866
|
+
var import_secp256k12 = require("@noble/curves/secp256k1");
|
|
867
|
+
var NONCE_FORMAT = /^[0-9A-Za-z]{22,}$/;
|
|
868
|
+
var SD_HASH_FORMAT = /^[A-Za-z0-9_-]{43}$/;
|
|
869
|
+
var SIGNATURE_FORMAT = /^0x[0-9a-fA-F]{130}$/;
|
|
870
|
+
var SECP256K1_HALF_ORDER = import_secp256k12.secp256k1.CURVE.n / 2n;
|
|
871
|
+
function isValidDate(value) {
|
|
872
|
+
return value instanceof Date && !Number.isNaN(value.getTime());
|
|
873
|
+
}
|
|
874
|
+
function hasLowS(signature) {
|
|
875
|
+
return BigInt(`0x${signature.slice(66, 130)}`) <= SECP256K1_HALF_ORDER;
|
|
876
|
+
}
|
|
877
|
+
function wholeSecondRfc3339(value, field) {
|
|
878
|
+
if (value.getUTCMilliseconds() !== 0) refuse("bad-config", `${field} must be a whole second`);
|
|
879
|
+
return value.toISOString().replace(".000Z", "Z");
|
|
880
|
+
}
|
|
881
|
+
function rfc3339Millis(value) {
|
|
882
|
+
const millis = parseRfc3339(value);
|
|
883
|
+
if (millis === null) refuse("bad-siwe", "SIWE timestamp is not RFC 3339");
|
|
884
|
+
return millis;
|
|
885
|
+
}
|
|
886
|
+
async function buildHeldPresentationSiwe(input) {
|
|
887
|
+
const { audience, nonce, sdHash: hash, account, issuedAt, expirationTime, sign } = input;
|
|
888
|
+
if (typeof audience !== "string") refuse("bad-config", "audience must be a string");
|
|
889
|
+
assertValidAudience(audience);
|
|
890
|
+
const subject = parsePkhDid(account);
|
|
891
|
+
if (subject === null) refuse("bad-config", "account must be a did:pkh:eip155 account");
|
|
892
|
+
if (subject.chainId !== "1") refuse("bad-config", "held presentations are on chain 1");
|
|
893
|
+
if (typeof nonce !== "string" || !NONCE_FORMAT.test(nonce)) refuse("bad-config", "nonce must be at least 22 base62 characters");
|
|
894
|
+
if (typeof hash !== "string" || !SD_HASH_FORMAT.test(hash)) refuse("bad-config", "sdHash must be a base64url SHA-256");
|
|
895
|
+
if (!isValidDate(issuedAt)) refuse("bad-config", "issuedAt must be a valid Date");
|
|
896
|
+
if (expirationTime !== void 0 && !isValidDate(expirationTime)) refuse("bad-config", "expirationTime must be a valid Date");
|
|
897
|
+
if (expirationTime !== void 0 && expirationTime.getTime() <= issuedAt.getTime()) refuse("bad-config", "expirationTime must be after issuedAt");
|
|
898
|
+
if (typeof sign !== "function") refuse("bad-config", "sign is required");
|
|
899
|
+
const message = [
|
|
900
|
+
`${audience} wants you to sign in with your Ethereum account:`,
|
|
901
|
+
toChecksumAddress(subject.address),
|
|
902
|
+
"",
|
|
903
|
+
PRESENTATION_STATEMENT,
|
|
904
|
+
"",
|
|
905
|
+
`URI: https://${audience}`,
|
|
906
|
+
"Version: 1",
|
|
907
|
+
"Chain ID: 1",
|
|
908
|
+
`Nonce: ${nonce}`,
|
|
909
|
+
`Issued At: ${wholeSecondRfc3339(issuedAt, "issuedAt")}`,
|
|
910
|
+
...expirationTime === void 0 ? [] : [`Expiration Time: ${wholeSecondRfc3339(expirationTime, "expirationTime")}`],
|
|
911
|
+
"Resources:",
|
|
912
|
+
`- ${SD_HASH_RESOURCE_PREFIX}${hash}`
|
|
913
|
+
].join("\n");
|
|
914
|
+
parseStrictSiwe(message);
|
|
915
|
+
if (message.length > HELD_LIMITS.siweMessageChars) refuse("bad-config", "SIWE message exceeds the node limit");
|
|
916
|
+
const signature = await sign(message);
|
|
917
|
+
if (typeof signature !== "string" || !SIGNATURE_FORMAT.test(signature)) refuse("bad-config", "signer must return 0x-prefixed 65-byte hex");
|
|
918
|
+
if (!hasLowS(signature)) refuse("bad-siwe-signature", "signer must return a low-S signature");
|
|
919
|
+
const recovered = recoverEip191Address(message, hexToBytes(signature.slice(2), "bad-siwe-signature"));
|
|
920
|
+
if (recovered !== subject.address) refuse("bad-siwe-signature", "signer does not control the account");
|
|
921
|
+
return { message, signature };
|
|
922
|
+
}
|
|
923
|
+
function checkReturnedPresentation(presentation, options) {
|
|
924
|
+
const { now, audience, account } = options;
|
|
925
|
+
if (!isValidDate(now)) refuse("bad-config", "now must be a valid Date");
|
|
926
|
+
assertValidAudience(audience);
|
|
927
|
+
if (parsePkhDid(account) === null) refuse("bad-config", "account must be a did:pkh:eip155 account");
|
|
928
|
+
if (!isObject(presentation) || Object.keys(presentation).sort().join() !== "sdJwt,siwe") refuse("bad-presentation", "unexpected shape");
|
|
929
|
+
const { sdJwt, siwe } = presentation;
|
|
930
|
+
if (typeof sdJwt !== "string" || !isAscii(sdJwt) || sdJwt.length > HELD_LIMITS.sdJwtChars) refuse("bad-presentation", "sdJwt must be a bounded ASCII string");
|
|
931
|
+
if (!isObject(siwe) || Object.keys(siwe).sort().join() !== "message,signature" || typeof siwe.message !== "string" || typeof siwe.signature !== "string") {
|
|
932
|
+
refuse("bad-presentation", "siwe must carry message and signature");
|
|
933
|
+
}
|
|
934
|
+
const siweMessage = siwe.message;
|
|
935
|
+
const siweSignature = siwe.signature;
|
|
936
|
+
if (siweMessage.length > HELD_LIMITS.siweMessageChars) refuse("bad-presentation", "siwe message is too long");
|
|
937
|
+
if (!SIGNATURE_FORMAT.test(siweSignature) || !hasLowS(siweSignature)) refuse("bad-siwe-signature", "signature must be 0x-prefixed 65-byte low-S hex");
|
|
938
|
+
const parsed = parseStrictSiwe(siweMessage);
|
|
939
|
+
if (parsed.domain !== audience) refuse("bad-siwe", "domain is not the audience");
|
|
940
|
+
let origin;
|
|
941
|
+
try {
|
|
942
|
+
const url = new URL(parsed.uri);
|
|
943
|
+
origin = url.protocol === "https:" && !url.username && !url.password ? url.origin : void 0;
|
|
944
|
+
} catch {
|
|
945
|
+
origin = void 0;
|
|
946
|
+
}
|
|
947
|
+
if (origin !== `https://${audience}`) refuse("bad-siwe", "uri must be an https origin matching the audience");
|
|
948
|
+
if (parsed.version !== "1") refuse("bad-siwe", "version must be 1");
|
|
949
|
+
if (parsed.statement !== PRESENTATION_STATEMENT) refuse("bad-siwe", "unexpected statement");
|
|
950
|
+
if (parsed.chainId !== "1") refuse("bad-siwe", "chain id must be 1");
|
|
951
|
+
if (!NONCE_FORMAT.test(parsed.nonce)) refuse("bad-nonce", "nonce must be at least 22 base62 characters");
|
|
952
|
+
if (parsed.resources.length !== 1 || parsed.resources[0] !== `${SD_HASH_RESOURCE_PREFIX}${sdHash(sdJwt)}`) {
|
|
953
|
+
refuse("bad-siwe", "resources must be exactly the sd_hash of this presentation");
|
|
954
|
+
}
|
|
955
|
+
const nowMs = now.getTime();
|
|
956
|
+
if (parsed.expirationTime !== void 0 && nowMs >= rfc3339Millis(parsed.expirationTime)) refuse("bad-siwe", "SIWE has expired");
|
|
957
|
+
if (parsed.notBefore !== void 0 && nowMs < rfc3339Millis(parsed.notBefore)) refuse("bad-siwe", "SIWE is not yet valid");
|
|
958
|
+
if (!pkhPrincipalsEqual(`did:pkh:eip155:${parsed.chainId}:${parsed.address}`, account)) refuse("bad-siwe", "SIWE address is not the account");
|
|
959
|
+
const recovered = recoverEip191Address(siweMessage, hexToBytes(siweSignature.slice(2), "bad-siwe-signature"));
|
|
960
|
+
if (recovered === null || recovered !== parsed.address.toLowerCase()) refuse("bad-siwe-signature", "signature does not recover the SIWE address");
|
|
961
|
+
return { sdJwt, siwe: { message: siweMessage, signature: siweSignature } };
|
|
962
|
+
}
|
|
793
963
|
//# sourceMappingURL=index.cjs.map
|