@ewqwe/digital-identity 1.1.1
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/LICENSE +12 -0
- package/README.md +193 -0
- package/dist/api-client.d.ts +22 -0
- package/dist/attestation.d.ts +80 -0
- package/dist/config.d.ts +72 -0
- package/dist/dcql.d.ts +266 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +1112 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib.d.ts +18 -0
- package/dist/types.d.ts +521 -0
- package/package.json +57 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e={haip:{id:`haip`,name:`HAIP Profile`,description:`High Assurance Interoperability Profile for EUDI Wallet`,clientIdScheme:`x509_hash`,requestFormat:`jar`,responseMode:`direct_post.jwt`,urlSchemes:[`eudi-openid4vp://`,`openid4vp://`],requiresJarSigning:!0},"annex-a":{id:`annex-a`,name:`Annex A Profile`,description:`EU Age Verification Profile for Proof of Age`,clientIdScheme:`redirect_uri`,requestFormat:`plain`,responseMode:`direct_post`,urlSchemes:[`av://`],requiresJarSigning:!1},"haip-x509-san-dns":{id:`haip-x509-san-dns`,name:`HAIP (x509_san_dns)`,description:`HAIP with x509_san_dns client_id scheme`,clientIdScheme:`x509_san_dns`,requestFormat:`jar`,responseMode:`direct_post.jwt`,urlSchemes:[`eudi-openid4vp://`,`openid4vp://`],requiresJarSigning:!0}},t={mdl:{id:`mdl`,name:`Mobile Driver's License`,format:`mso_mdoc`,docType:`org.iso.18013.5.1.mDL`,namespace:`org.iso.18013.5.1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`portrait`,name:`Portrait`},{id:`age_over_21`,name:`Age Over 21`},{id:`age_over_18`,name:`Age Over 18`},{id:`document_number`,name:`Document Number`},{id:`issue_date`,name:`Issue Date`},{id:`expiry_date`,name:`Expiry Date`},{id:`issuing_authority`,name:`Issuing Authority`},{id:`issuing_country`,name:`Issuing Country`},{id:`driving_privileges`,name:`Driving Privileges`}]},"national-id":{id:`national-id`,name:`National ID (PID)`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.pid.1`,namespace:`eu.europa.ec.eudi.pid.1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`portrait`,name:`Portrait`},{id:`nationality`,name:`Nationality`},{id:`place_of_birth`,name:`Place of Birth`},{id:`resident_address`,name:`Resident Address`},{id:`resident_country`,name:`Resident Country`},{id:`sex`,name:`Sex`}]},"national-id-sd-jwt":{id:`national-id-sd-jwt`,name:`National ID (PID) — SD-JWT VC`,format:`dc+sd-jwt`,docType:`urn:eudi:pid:1`,namespace:`urn:eudi:pid:1`,vct:`urn:eudi:pid:1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birthdate`,name:`Birth Date`},{id:`picture`,name:`Portrait`},{id:`nationalities`,name:`Nationalities`},{id:`place_of_birth`,name:`Place of Birth`},{id:`address`,name:`Address`},{id:`sex`,name:`Sex`}]},"proof-of-age":{id:`proof-of-age`,name:`Proof of Age (EU AV)`,format:`mso_mdoc`,docType:`eu.europa.ec.av.1`,namespace:`eu.europa.ec.av.1`,profile:`annex-a`,claims:[{id:`age_over_18`,name:`Age Over 18`}]},"france-identite-numerique":{id:`france-identite-numerique`,name:`France Identité Numérique`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.pid.1`,namespace:`eu.europa.ec.eudi.pid.1`,profile:`haip`,claims:[{id:`age_over_18`,name:`Age Over 18`},{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`portrait`,name:`Portrait`}]},tax:{id:`tax`,name:`Tax Identification`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.tax.1`,namespace:`eu.europa.ec.eudi.tax.1`,profile:`haip`,claims:[{id:`tax_number`,name:`Tax Number`},{id:`registered_family_name`,name:`Registered Family Name`},{id:`registered_given_name`,name:`Registered Given Names`},{id:`issuing_country`,name:`Issuing Country`}]},"tax-sd-jwt":{id:`tax-sd-jwt`,name:`Tax Identification — SD-JWT VC`,format:`dc+sd-jwt`,docType:`urn:eu.europa.ec.eudi:tax:1`,namespace:`urn:eu.europa.ec.eudi:tax:1`,vct:`urn:eu.europa.ec.eudi:tax:1`,profile:`haip`,claims:[{id:`tax_number`,name:`Tax Number`},{id:`registered_family_name`,name:`Registered Family Name`},{id:`registered_given_name`,name:`Registered Given Names`},{id:`issuing_country`,name:`Issuing Country`}]},"pseudonym-age":{id:`pseudonym-age`,name:`Pseudonym (Age Over 18)`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.pseudonym.age_over_18.1`,namespace:`eu.europa.ec.eudi.pseudonym.age_over_18.1`,profile:`haip`,claims:[{id:`age_over_18`,name:`Age Over 18`}]},"pseudonym-age-sd-jwt":{id:`pseudonym-age-sd-jwt`,name:`Pseudonym (Age Over 18) — SD-JWT VC`,format:`dc+sd-jwt`,docType:`urn:eu.europa.ec.eudi:pseudonym_age_over_18:1`,namespace:`urn:eu.europa.ec.eudi:pseudonym_age_over_18:1`,vct:`urn:eu.europa.ec.eudi:pseudonym_age_over_18:1`,profile:`haip`,claims:[{id:`age_over_18`,name:`Age Over 18`}]},cor:{id:`cor`,name:`Certificate of Residence`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.cor.1`,namespace:`eu.europa.ec.eudi.cor.1`,profile:`haip`,claims:[{id:`resident_address`,name:`Resident Address`},{id:`resident_country`,name:`Resident Country`},{id:`resident_city`,name:`Resident City`},{id:`resident_postal_code`,name:`Resident Postal Code`},{id:`issuing_country`,name:`Issuing Country`}]},"photo-id":{id:`photo-id`,name:`Photo ID`,format:`mso_mdoc`,docType:`org.iso.23220.2.photoid.1`,namespace:`org.iso.23220.photoid.1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`portrait`,name:`Portrait`},{id:`document_number`,name:`Document Number`},{id:`issuing_authority`,name:`Issuing Authority`},{id:`issuing_country`,name:`Issuing Country`},{id:`expiry_date`,name:`Expiry Date`}]},reservation:{id:`reservation`,name:`Travel Reservation`,format:`mso_mdoc`,docType:`org.iso.18013.5.1.reservation`,namespace:`org.iso.18013.5.1.reservation`,profile:`haip`,claims:[{id:`reservation_number`,name:`Reservation Number`},{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`}]},iban:{id:`iban`,name:`IBAN`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.iban.1`,namespace:`eu.europa.ec.eudi.iban.1`,profile:`haip`,claims:[{id:`iban`,name:`IBAN`},{id:`account_holder`,name:`Account Holder`},{id:`bic`,name:`BIC`}]},"iban-sd-jwt":{id:`iban-sd-jwt`,name:`IBAN — SD-JWT VC`,format:`dc+sd-jwt`,docType:`urn:eu.europa.ec.eudi:iban:1`,namespace:`urn:eu.europa.ec.eudi:iban:1`,vct:`urn:eu.europa.ec.eudi:iban:1`,profile:`haip`,claims:[{id:`iban`,name:`IBAN`},{id:`account_holder`,name:`Account Holder`},{id:`bic`,name:`BIC`}]},ehic:{id:`ehic`,name:`European Health Insurance Card`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.ehic.1`,namespace:`eu.europa.ec.eudi.ehic.1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`personal_id`,name:`Personal ID`},{id:`institution_id`,name:`Institution ID`},{id:`institution_country`,name:`Institution Country`},{id:`card_number`,name:`Card Number`},{id:`expiry_date`,name:`Expiry Date`}]},"ehic-sd-jwt":{id:`ehic-sd-jwt`,name:`European Health Insurance Card — SD-JWT VC`,format:`dc+sd-jwt`,docType:`urn:eu.europa.ec.eudi:ehic:1`,namespace:`urn:eu.europa.ec.eudi:ehic:1`,vct:`urn:eu.europa.ec.eudi:ehic:1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`personal_id`,name:`Personal ID`},{id:`institution_id`,name:`Institution ID`},{id:`institution_country`,name:`Institution Country`},{id:`card_number`,name:`Card Number`},{id:`expiry_date`,name:`Expiry Date`}]},"health-id":{id:`health-id`,name:`Health ID`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.hiid.1`,namespace:`eu.europa.ec.eudi.hiid.1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`health_insurance_id`,name:`Health Insurance ID`},{id:`issuing_country`,name:`Issuing Country`}]},"health-id-sd-jwt":{id:`health-id-sd-jwt`,name:`Health ID — SD-JWT VC`,format:`dc+sd-jwt`,docType:`urn:eu.europa.ec.eudi:hiid:1`,namespace:`urn:eu.europa.ec.eudi:hiid:1`,vct:`urn:eu.europa.ec.eudi:hiid:1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`health_insurance_id`,name:`Health Insurance ID`},{id:`issuing_country`,name:`Issuing Country`}]},pda1:{id:`pda1`,name:`Portable Document A1`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.pda1.1`,namespace:`eu.europa.ec.eudi.pda1.1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`nationality`,name:`Nationality`},{id:`social_security_number`,name:`Social Security Number`},{id:`issuing_country`,name:`Issuing Country`},{id:`expiry_date`,name:`Expiry Date`}]},"pda1-sd-jwt":{id:`pda1-sd-jwt`,name:`Portable Document A1 — SD-JWT VC`,format:`dc+sd-jwt`,docType:`urn:eu.europa.ec.eudi:pda1:1`,namespace:`urn:eu.europa.ec.eudi:pda1:1`,vct:`urn:eu.europa.ec.eudi:pda1:1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`birth_date`,name:`Birth Date`},{id:`nationality`,name:`Nationality`},{id:`social_security_number`,name:`Social Security Number`},{id:`issuing_country`,name:`Issuing Country`},{id:`expiry_date`,name:`Expiry Date`}]},loyalty:{id:`loyalty`,name:`Loyalty Card`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.loyalty.1`,namespace:`eu.europa.ec.eudi.loyalty.1`,profile:`haip`,claims:[{id:`family_name`,name:`Family Name`},{id:`given_name`,name:`Given Names`},{id:`loyalty_number`,name:`Loyalty Number`},{id:`program_name`,name:`Program Name`}]},msisdn:{id:`msisdn`,name:`Mobile Phone Number (MSISDN)`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.msisdn.1`,namespace:`eu.europa.ec.eudi.msisdn.1`,profile:`haip`,claims:[{id:`phone_number`,name:`Phone Number`},{id:`registered_family_name`,name:`Registered Family Name`}]},"msisdn-sd-jwt":{id:`msisdn-sd-jwt`,name:`Mobile Phone Number (MSISDN) — SD-JWT VC`,format:`dc+sd-jwt`,docType:`urn:eu.europa.ec.eudi:msisdn:1`,namespace:`urn:eu.europa.ec.eudi:msisdn:1`,vct:`urn:eu.europa.ec.eudi:msisdn:1`,profile:`haip`,claims:[{id:`phone_number`,name:`Phone Number`},{id:`registered_family_name`,name:`Registered Family Name`}]},por:{id:`por`,name:`Power of Representation`,format:`mso_mdoc`,docType:`eu.europa.ec.eudi.por.1`,namespace:`eu.europa.ec.eudi.por.1`,profile:`haip`,claims:[{id:`legal_person_id`,name:`Legal Person ID`},{id:`legal_person_name`,name:`Legal Person Name`},{id:`representative_family_name`,name:`Representative Family Name`},{id:`representative_given_name`,name:`Representative Given Names`}]},"por-sd-jwt":{id:`por-sd-jwt`,name:`Power of Representation — SD-JWT VC`,format:`dc+sd-jwt`,docType:`urn:eu.europa.ec.eudi:por:1`,namespace:`urn:eu.europa.ec.eudi:por:1`,vct:`urn:eu.europa.ec.eudi:por:1`,profile:`haip`,claims:[{id:`legal_person_id`,name:`Legal Person ID`},{id:`legal_person_name`,name:`Legal Person Name`},{id:`representative_family_name`,name:`Representative Family Name`},{id:`representative_given_name`,name:`Representative Given Names`}]}};function n(e){let n=t[e];return n?n.claims.slice(0,5).map(e=>e.id):[]}function r(e){return t[e]?.claims||[]}function i(n){let r=t[n];return r&&e[r.profile]||null}function a(e){return t[e]?.profile||`haip`}var o=`eu.europa.ec.av.1`,s=`eu.europa.ec.av.1.mdoc`,c=`org.iso.18013.5.1`,l=`org.iso.18013.5.1.mDL`,u=`eu.europa.ec.eudi.pid.1`,d=`eu.europa.ec.eudi.pid.1`;function f(e=18){let t=`age_over_${e}`;return{credentials:[{id:`eu_av_proof`,format:`mso_mdoc`,meta:{doctype_value:s},claims:[{path:[o,t],values:[!0],intent_to_retain:!1}]}]}}function p(e=18){let t=`age_over_${e}`;return{credentials:[{id:`eu_av_proof`,format:`mso_mdoc`,meta:{doctype_value:s},claims:[{path:[o,t],values:[!0],intent_to_retain:!1}]},{id:`mdl_fallback`,format:`mso_mdoc`,meta:{doctype_value:l},claims:[{path:[c,t],values:[!0],intent_to_retain:!1}]}],credential_sets:[{options:[[`eu_av_proof`],[`mdl_fallback`]],required:!0}]}}function m(){return{credentials:[{id:`eu-pid-age-verification`,format:`mso_mdoc`,meta:{doctype_value:d},claims:[{path:[u,`age_over_18`]}]}]}}function h(e,n,r,i){let a=t[n];if(!a)throw Error(`Unknown credential type: ${n}`);let o=a.format===`dc+sd-jwt`,s=r.map(e=>{let t={id:e,path:o?[e]:[a.namespace,e]};return o||(t.intent_to_retain=!1),t}),c={credentials:[o?{id:`${n}_credential`,format:`dc+sd-jwt`,meta:{vct_values:[a.vct]},claims:s}:{id:`${n}_credential`,format:`mso_mdoc`,meta:{doctype_value:a.docType},claims:s}]},l=o?{"dc+sd-jwt":{"sd-jwt_alg_values":[`ES256`,`ES384`,`ES512`],"kb-jwt_alg_values":[`ES256`,`ES384`,`ES512`]}}:{mso_mdoc:{issuerauth_alg_values:[-7,-35,-36],deviceauth_alg_values:[-7,-35,-36]}};return{public_url:e,dcql_query:c,nonce:_(),credential_type:n,profile:i,client_metadata:{client_name:`ewQwe Digital Credentials Demo`,vp_formats:l}}}function g(e,t){return t||(e===`proof-of-age`?`annex-a`:`haip`)}function _(){let e=new Uint8Array(32);if(globalThis.crypto.getRandomValues(e),typeof btoa==`function`){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=/g,``)}if(typeof Buffer<`u`)return Buffer.from(e).toString(`base64`).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=/g,``);throw Error(`No base64 encoder available in this runtime`)}function v(e){try{return JSON.parse(e)}catch{return null}}function y(e){for(let t of e.credentials)for(let e of t.claims??[]){let t=e.path[e.path.length-1];if(typeof t!=`string`)continue;let n=t.match(/^age_over_(\d+)$/);if(n)return parseInt(n[1],10)}return null}function b(e){let t=e.nonce??_(),n=e.state??_(),r=f(e.ageThreshold??18);return{client_id:`redirect_uri:${e.redirectUri}`,response_type:`vp_token`,response_mode:`fragment`,nonce:t,state:n,redirect_uri:e.redirectUri,dcql_query:JSON.stringify(r)}}function x(e){let t=e.nonce??_(),n=e.state??_(),r=p(e.ageThreshold??18);return{client_id:`x509_san_dns:${e.rpDomain}`,response_type:`vp_token`,response_mode:`direct_post`,nonce:t,state:n,response_uri:e.responseUri,dcql_query:JSON.stringify(r)}}function S(e){let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=t.padEnd(t.length+(4-t.length%4)%4,`=`);if(typeof atob==`function`){let e=atob(n),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}if(typeof Buffer<`u`)return new Uint8Array(Buffer.from(n,`base64`));throw Error(`No base64 decoder available in this runtime`)}function C(){let e=globalThis.crypto?.subtle;if(!e)throw Error(`Web Crypto API is not available in this runtime`);return e}function w(e){let t=e.split(`.`);if(t.length!==3)throw Error(`Invalid JWT: expected 3 dot-separated parts`);let[n,r,i]=t;return[n,r,S(i)]}function T(e){let t=new TextDecoder().decode(S(e));return JSON.parse(t)}function E(e){let t=e.trim(),n;if(t.startsWith(`-----BEGIN CERTIFICATE-----`)){let e=S(t.replace(/-----BEGIN CERTIFICATE-----/,``).replace(/-----END CERTIFICATE-----/,``).replace(/\s+/g,``).replace(/\+/g,`-`).replace(/\//g,`_`)).buffer;n=D(e)}else n=t.startsWith(`-----BEGIN PUBLIC KEY-----`)?S(t.replace(/-----BEGIN PUBLIC KEY-----/,``).replace(/-----END PUBLIC KEY-----/,``).replace(/\s+/g,``).replace(/\+/g,`-`).replace(/\//g,`_`)).buffer:S(t.replace(/\s+/g,``).replace(/\+/g,`-`).replace(/\//g,`_`)).buffer;return C().importKey(`spki`,n,{name:`ECDSA`,namedCurve:`P-256`},!1,[`verify`])}function D(e){let t=new Uint8Array(e),n=new Uint8Array([42,134,72,206,61,2,1]);outer:for(let e=0;e<t.length-n.length;e++){for(let r=0;r<n.length;r++)if(t[e+r]!==n[r])continue outer;let r=e-2-2;if(r<2)continue;let i=O(t,r);if(i<0)continue;let[,a]=k(t,i);return t.slice(i,a).buffer}throw Error(`Could not extract SubjectPublicKeyInfo from certificate — EC public key OID not found`)}function O(e,t){for(let n=t-2;n>=0;n--)if(e[n]===48)try{let[r,i]=k(e,n);if(r<=t&&t<i)return n}catch{}return-1}function k(e,t){let n=t+1,r;if(e[n]&128){let t=e[n]&127;r=0;for(let i=0;i<t;i++)r=r<<8|e[++n];n++}else r=e[n++];return[n,n+r]}function A(e){let t=e.split(`.`);if(t.length!==3)throw Error(`Invalid JWT: expected 3 dot-separated parts`);return T(t[1])}function j(e){let t=Math.floor(Date.now()/1e3);return e.exp!==void 0&&e.exp<t?`expired`:e.nbf!==void 0&&e.nbf>t?`not_yet_valid`:`valid`}async function M(e,t){let n=e.split(`.`);if(n.length!==3)throw Error(`Invalid JWT: expected 3 dot-separated parts`);let r=JSON.parse(new TextDecoder().decode(S(n[0]))),i=typeof r.kid==`string`?r.kid:void 0,a=await fetch(t);if(!a.ok)throw Error(`Failed to fetch JWKS from ${t}: HTTP ${a.status}`);let o=await a.json(),s=Array.isArray(o.keys)?o.keys:[],c;if(i!==void 0&&(c=s.find(e=>e.kid===i)),c||=s.find(e=>{let t=e;return Array.isArray(t.x5c)&&t.x5c.length>0}),!c)throw Error(`No suitable attestation verification key found in JWKS${i===void 0?``:` for kid="${i}"`}`);let l=c;if(!Array.isArray(l.x5c)||l.x5c.length===0)throw Error(`JWKS attestation key does not include an x5c certificate`);return N(e,await E(`-----BEGIN CERTIFICATE-----\n${l.x5c[0]}\n-----END CERTIFICATE-----`))}async function N(e,t){let[n,r,i]=w(e),a=new TextEncoder().encode(`${n}.${r}`);if(!await C().verify({name:`ECDSA`,hash:{name:`SHA-256`}},t,i.buffer,a))throw Error(`Attestation JWT signature verification failed`);let o=T(r),s=j(o);if(s===`expired`)throw Error(`Attestation JWT is expired (exp=${o.exp}, now=${Math.floor(Date.now()/1e3)})`);if(s===`not_yet_valid`)throw Error(`Attestation JWT is not yet valid (nbf=${o.nbf}, now=${Math.floor(Date.now()/1e3)})`);return o}var P=class{constructor(e){if(e?.fetch)this.fetchFn=e.fetch;else if(typeof globalThis.fetch==`function`)this.fetchFn=globalThis.fetch.bind(globalThis);else throw Error(`No fetch implementation available`);this.baseUrl=e?.baseUrl?.replace(/\/$/u,``)??``}buildUrl(e){if(/^https?:\/\//i.test(e))return e;let t=e.startsWith(`/`)?e:`/${e}`;return`${this.baseUrl}${t}`}async requestJson(e,t,n){let r=this.buildUrl(t),i=await this.fetchFn(r,{method:e,headers:{"Content-Type":`application/json`},body:n===void 0?void 0:JSON.stringify(n)});if(!i.ok){let t=await i.text().catch(()=>``),n=t?`${i.status} ${i.statusText}: ${t}`:`${i.status} ${i.statusText}`;throw Error(`API request failed ${e} ${r}: ${n}`)}return await i.json()}async initOpenID4VPTransaction(e){return await this.requestJson(`POST`,`/ewqwe_api/openid4vp/init`,e)}async getOpenID4VPTransactionStatus(e){return await this.requestJson(`GET`,`/ewqwe_api/openid4vp/status/${encodeURIComponent(e)}`)}async getOpenID4VPAuthorizationRequest(e){return await this.requestJson(`GET`,`/ewqwe_api/openid4vp/request/${encodeURIComponent(e)}`)}async postOpenID4VPAuthorizationRequest(e,t){await this.requestJson(`POST`,`/ewqwe_api/openid4vp/request/${encodeURIComponent(e)}`,t)}async postOpenID4VPDirectPost(e){await this.requestJson(`POST`,`/ewqwe_api/openid4vp/direct_post`,e)}async getOpenID4VPJwks(){return await this.requestJson(`GET`,`/ewqwe_api/openid4vp/.well-known/jwks.json`)}async verifyPresentation(e){return await this.requestJson(`POST`,`/ewqwe_api/verify`,e)}};exports.CREDENTIAL_TYPES=t,exports.EU_AV_DOCTYPE=s,exports.EU_AV_NAMESPACE=o,exports.EU_PID_DOCTYPE=d,exports.EU_PID_NAMESPACE=u,exports.EwqweApiClient=P,exports.ISO_MDL_DOCTYPE=l,exports.ISO_MDL_NAMESPACE=c,exports.PROTOCOL_PROFILES=e,exports.base64urlDecode=S,exports.buildAgeVerificationQuery=f,exports.buildAgeVerificationQueryWithFallback=p,exports.buildAuthorizationRequest=b,exports.buildCrossDeviceAuthorizationRequest=x,exports.buildInitTransactionRequest=h,exports.decodeAttestation=A,exports.determineProfile=g,exports.extractAgeThreshold=y,exports.generateNonce=_,exports.getAttestationExpiryStatus=j,exports.getClaimsForType=r,exports.getDefaultAgeVerificationDCQL=m,exports.getDefaultClaims=n,exports.getProfileForType=i,exports.getProfileIdForType=a,exports.importVerifierPublicKey=E,exports.parseAttestation=M,exports.parseDCQLQuery=v,exports.verifyAttestation=N;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/config.ts","../src/dcql.ts","../src/attestation.ts","../src/api-client.ts"],"sourcesContent":["/**\n * @ewqwe/digital-identity — Protocol & Credential Configuration\n *\n * Defines protocol profiles (HAIP, Annex A), credential type specifications\n * (mDL, PID, Proof of Age), and helper functions for querying them.\n *\n * Node.js compatible — no platform-specific APIs.\n *\n * @see https://openid.net/specs/openid-4-verifiable-presentations-1_0.html\n * @see https://ageverification.dev/Technical%20Specification/annexes/annex-A/annex-A-av-profile\n * @see ISO/IEC 18013-5:2021 for mDL claims\n */\n\nimport type {\n ClaimDefinition,\n CredentialType,\n CredentialTypeConfig,\n ProfileId,\n ProtocolProfile,\n} from \"./types.js\";\n\n// =============================================================================\n// Protocol Profiles\n// =============================================================================\n\n/**\n * Protocol Profile Configurations\n *\n * **HAIP (High Assurance Interoperability Profile):**\n * - Used for: mDL, PID (National ID)\n * - Client ID Scheme: x509_hash (X.509 certificate SHA-256 hash)\n * - Request Format: JAR (JWT Authorization Request with x5c header)\n * - Response Mode: direct_post.jwt (encrypted/signed response)\n * - URL Schemes: eudi-openid4vp://, openid4vp://\n * - Reference: OpenID4VP HAIP Draft\n *\n * **Annex A (EU Age Verification Profile):**\n * - Used for: Proof of Age attestations\n * - Client ID Scheme: redirect_uri (redirect URI as client identifier)\n * - Request Format: Plain JSON (redirect_uri scheme forbids signed requests)\n * - Response Mode: direct_post (plain VP token)\n * - URL Schemes: av://\n * - Reference: https://ageverification.dev/Technical%20Specification/annexes/annex-A/annex-A-av-profile\n *\n * Note: The key difference is client_id_scheme. HAIP uses x509_hash with signed JARs,\n * while Annex A uses redirect_uri with plain JSON (signed requests are explicitly forbidden).\n * The `x509_hash` scheme is preferred over `x509_san_dns` because it provides a direct\n * cryptographic binding to the verifier's certificate, independent of DNS resolution.\n */\nexport const PROTOCOL_PROFILES: Record<ProfileId, ProtocolProfile> = {\n haip: {\n id: \"haip\",\n name: \"HAIP Profile\",\n description: \"High Assurance Interoperability Profile for EUDI Wallet\",\n clientIdScheme: \"x509_hash\",\n requestFormat: \"jar\",\n responseMode: \"direct_post.jwt\",\n urlSchemes: [\"eudi-openid4vp://\", \"openid4vp://\"],\n requiresJarSigning: true,\n },\n \"annex-a\": {\n id: \"annex-a\",\n name: \"Annex A Profile\",\n description: \"EU Age Verification Profile for Proof of Age\",\n clientIdScheme: \"redirect_uri\",\n requestFormat: \"plain\",\n responseMode: \"direct_post\",\n urlSchemes: [\"av://\"],\n requiresJarSigning: false,\n },\n \"haip-x509-san-dns\": {\n id: \"haip-x509-san-dns\",\n name: \"HAIP (x509_san_dns)\",\n description: \"HAIP with x509_san_dns client_id scheme\",\n clientIdScheme: \"x509_san_dns\",\n requestFormat: \"jar\",\n responseMode: \"direct_post.jwt\",\n urlSchemes: [\"eudi-openid4vp://\", \"openid4vp://\"],\n requiresJarSigning: true,\n },\n};\n\n// =============================================================================\n// Credential Types\n// =============================================================================\n\n/**\n * Credential type configurations based on ISO 18013-5, EU ARF, and EU Age Verification Profile.\n *\n * References:\n * - mDL: ISO/IEC 18013-5:2021\n * - PID: EU ARF Annex 2.02 Topic 3 (PID_04, PID_05)\n * - Proof of Age: EU Age Verification Profile (https://ageverification.dev)\n * - EUDI Wallet document categories: WalletCoreConfig.kt `documentCategories`\n *\n * Credential format identifiers:\n * - `\"mso_mdoc\"` — ISO/IEC 18013-5 Mobile Documents (CBOR-encoded, namespace-based claims)\n * - `\"dc+sd-jwt\"` — IETF SD-JWT VC (JSON-encoded, flat or nested claim paths)\n *\n * SD-JWT VC credential types use `vct` (Verifiable Credential Type) as the type\n * identifier instead of `docType`/`namespace`. Claims use JSON paths instead of\n * namespace-based paths. See OpenID4VP 1.0 §B.3 and draft-ietf-oauth-sd-jwt-vc-08.\n */\nexport const CREDENTIAL_TYPES: Record<CredentialType, CredentialTypeConfig> = {\n // ===========================================================================\n // Government\n // ===========================================================================\n\n mdl: {\n id: \"mdl\",\n name: \"Mobile Driver's License\",\n format: \"mso_mdoc\",\n docType: \"org.iso.18013.5.1.mDL\",\n namespace: \"org.iso.18013.5.1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"portrait\", name: \"Portrait\" },\n { id: \"age_over_21\", name: \"Age Over 21\" },\n { id: \"age_over_18\", name: \"Age Over 18\" },\n { id: \"document_number\", name: \"Document Number\" },\n { id: \"issue_date\", name: \"Issue Date\" },\n { id: \"expiry_date\", name: \"Expiry Date\" },\n { id: \"issuing_authority\", name: \"Issuing Authority\" },\n { id: \"issuing_country\", name: \"Issuing Country\" },\n { id: \"driving_privileges\", name: \"Driving Privileges\" },\n ],\n },\n\n \"national-id\": {\n id: \"national-id\",\n name: \"National ID (PID)\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.pid.1\",\n namespace: \"eu.europa.ec.eudi.pid.1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"portrait\", name: \"Portrait\" },\n { id: \"nationality\", name: \"Nationality\" },\n { id: \"place_of_birth\", name: \"Place of Birth\" },\n { id: \"resident_address\", name: \"Resident Address\" },\n { id: \"resident_country\", name: \"Resident Country\" },\n { id: \"sex\", name: \"Sex\" },\n ],\n },\n\n \"national-id-sd-jwt\": {\n id: \"national-id-sd-jwt\",\n name: \"National ID (PID) — SD-JWT VC\",\n format: \"dc+sd-jwt\",\n docType: \"urn:eudi:pid:1\",\n namespace: \"urn:eudi:pid:1\",\n vct: \"urn:eudi:pid:1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birthdate\", name: \"Birth Date\" },\n { id: \"picture\", name: \"Portrait\" },\n { id: \"nationalities\", name: \"Nationalities\" },\n { id: \"place_of_birth\", name: \"Place of Birth\" },\n { id: \"address\", name: \"Address\" },\n { id: \"sex\", name: \"Sex\" },\n ],\n },\n\n \"proof-of-age\": {\n id: \"proof-of-age\",\n name: \"Proof of Age (EU AV)\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.av.1\",\n namespace: \"eu.europa.ec.av.1\",\n profile: \"annex-a\",\n claims: [{ id: \"age_over_18\", name: \"Age Over 18\" }],\n },\n\n \"france-identite-numerique\": {\n id: \"france-identite-numerique\",\n name: \"France Identité Numérique\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.pid.1\",\n namespace: \"eu.europa.ec.eudi.pid.1\",\n profile: \"haip\",\n claims: [\n { id: \"age_over_18\", name: \"Age Over 18\" },\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"portrait\", name: \"Portrait\" },\n ],\n },\n\n tax: {\n id: \"tax\",\n name: \"Tax Identification\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.tax.1\",\n namespace: \"eu.europa.ec.eudi.tax.1\",\n profile: \"haip\",\n claims: [\n { id: \"tax_number\", name: \"Tax Number\" },\n { id: \"registered_family_name\", name: \"Registered Family Name\" },\n { id: \"registered_given_name\", name: \"Registered Given Names\" },\n { id: \"issuing_country\", name: \"Issuing Country\" },\n ],\n },\n\n \"tax-sd-jwt\": {\n id: \"tax-sd-jwt\",\n name: \"Tax Identification — SD-JWT VC\",\n format: \"dc+sd-jwt\",\n docType: \"urn:eu.europa.ec.eudi:tax:1\",\n namespace: \"urn:eu.europa.ec.eudi:tax:1\",\n vct: \"urn:eu.europa.ec.eudi:tax:1\",\n profile: \"haip\",\n claims: [\n { id: \"tax_number\", name: \"Tax Number\" },\n { id: \"registered_family_name\", name: \"Registered Family Name\" },\n { id: \"registered_given_name\", name: \"Registered Given Names\" },\n { id: \"issuing_country\", name: \"Issuing Country\" },\n ],\n },\n\n \"pseudonym-age\": {\n id: \"pseudonym-age\",\n name: \"Pseudonym (Age Over 18)\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.pseudonym.age_over_18.1\",\n namespace: \"eu.europa.ec.eudi.pseudonym.age_over_18.1\",\n profile: \"haip\",\n claims: [{ id: \"age_over_18\", name: \"Age Over 18\" }],\n },\n\n \"pseudonym-age-sd-jwt\": {\n id: \"pseudonym-age-sd-jwt\",\n name: \"Pseudonym (Age Over 18) — SD-JWT VC\",\n format: \"dc+sd-jwt\",\n docType: \"urn:eu.europa.ec.eudi:pseudonym_age_over_18:1\",\n namespace: \"urn:eu.europa.ec.eudi:pseudonym_age_over_18:1\",\n vct: \"urn:eu.europa.ec.eudi:pseudonym_age_over_18:1\",\n profile: \"haip\",\n claims: [{ id: \"age_over_18\", name: \"Age Over 18\" }],\n },\n\n cor: {\n id: \"cor\",\n name: \"Certificate of Residence\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.cor.1\",\n namespace: \"eu.europa.ec.eudi.cor.1\",\n profile: \"haip\",\n claims: [\n { id: \"resident_address\", name: \"Resident Address\" },\n { id: \"resident_country\", name: \"Resident Country\" },\n { id: \"resident_city\", name: \"Resident City\" },\n { id: \"resident_postal_code\", name: \"Resident Postal Code\" },\n { id: \"issuing_country\", name: \"Issuing Country\" },\n ],\n },\n\n // ===========================================================================\n // Travel\n // ===========================================================================\n\n \"photo-id\": {\n id: \"photo-id\",\n name: \"Photo ID\",\n format: \"mso_mdoc\",\n docType: \"org.iso.23220.2.photoid.1\",\n namespace: \"org.iso.23220.photoid.1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"portrait\", name: \"Portrait\" },\n { id: \"document_number\", name: \"Document Number\" },\n { id: \"issuing_authority\", name: \"Issuing Authority\" },\n { id: \"issuing_country\", name: \"Issuing Country\" },\n { id: \"expiry_date\", name: \"Expiry Date\" },\n ],\n },\n\n reservation: {\n id: \"reservation\",\n name: \"Travel Reservation\",\n format: \"mso_mdoc\",\n docType: \"org.iso.18013.5.1.reservation\",\n namespace: \"org.iso.18013.5.1.reservation\",\n profile: \"haip\",\n claims: [\n { id: \"reservation_number\", name: \"Reservation Number\" },\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n ],\n },\n\n // ===========================================================================\n // Finance\n // ===========================================================================\n\n iban: {\n id: \"iban\",\n name: \"IBAN\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.iban.1\",\n namespace: \"eu.europa.ec.eudi.iban.1\",\n profile: \"haip\",\n claims: [\n { id: \"iban\", name: \"IBAN\" },\n { id: \"account_holder\", name: \"Account Holder\" },\n { id: \"bic\", name: \"BIC\" },\n ],\n },\n\n \"iban-sd-jwt\": {\n id: \"iban-sd-jwt\",\n name: \"IBAN — SD-JWT VC\",\n format: \"dc+sd-jwt\",\n docType: \"urn:eu.europa.ec.eudi:iban:1\",\n namespace: \"urn:eu.europa.ec.eudi:iban:1\",\n vct: \"urn:eu.europa.ec.eudi:iban:1\",\n profile: \"haip\",\n claims: [\n { id: \"iban\", name: \"IBAN\" },\n { id: \"account_holder\", name: \"Account Holder\" },\n { id: \"bic\", name: \"BIC\" },\n ],\n },\n\n // ===========================================================================\n // Health\n // ===========================================================================\n\n ehic: {\n id: \"ehic\",\n name: \"European Health Insurance Card\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.ehic.1\",\n namespace: \"eu.europa.ec.eudi.ehic.1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"personal_id\", name: \"Personal ID\" },\n { id: \"institution_id\", name: \"Institution ID\" },\n { id: \"institution_country\", name: \"Institution Country\" },\n { id: \"card_number\", name: \"Card Number\" },\n { id: \"expiry_date\", name: \"Expiry Date\" },\n ],\n },\n\n \"ehic-sd-jwt\": {\n id: \"ehic-sd-jwt\",\n name: \"European Health Insurance Card — SD-JWT VC\",\n format: \"dc+sd-jwt\",\n docType: \"urn:eu.europa.ec.eudi:ehic:1\",\n namespace: \"urn:eu.europa.ec.eudi:ehic:1\",\n vct: \"urn:eu.europa.ec.eudi:ehic:1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"personal_id\", name: \"Personal ID\" },\n { id: \"institution_id\", name: \"Institution ID\" },\n { id: \"institution_country\", name: \"Institution Country\" },\n { id: \"card_number\", name: \"Card Number\" },\n { id: \"expiry_date\", name: \"Expiry Date\" },\n ],\n },\n\n \"health-id\": {\n id: \"health-id\",\n name: \"Health ID\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.hiid.1\",\n namespace: \"eu.europa.ec.eudi.hiid.1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"health_insurance_id\", name: \"Health Insurance ID\" },\n { id: \"issuing_country\", name: \"Issuing Country\" },\n ],\n },\n\n \"health-id-sd-jwt\": {\n id: \"health-id-sd-jwt\",\n name: \"Health ID — SD-JWT VC\",\n format: \"dc+sd-jwt\",\n docType: \"urn:eu.europa.ec.eudi:hiid:1\",\n namespace: \"urn:eu.europa.ec.eudi:hiid:1\",\n vct: \"urn:eu.europa.ec.eudi:hiid:1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"health_insurance_id\", name: \"Health Insurance ID\" },\n { id: \"issuing_country\", name: \"Issuing Country\" },\n ],\n },\n\n // ===========================================================================\n // Social Security\n // ===========================================================================\n\n pda1: {\n id: \"pda1\",\n name: \"Portable Document A1\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.pda1.1\",\n namespace: \"eu.europa.ec.eudi.pda1.1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"nationality\", name: \"Nationality\" },\n { id: \"social_security_number\", name: \"Social Security Number\" },\n { id: \"issuing_country\", name: \"Issuing Country\" },\n { id: \"expiry_date\", name: \"Expiry Date\" },\n ],\n },\n\n \"pda1-sd-jwt\": {\n id: \"pda1-sd-jwt\",\n name: \"Portable Document A1 — SD-JWT VC\",\n format: \"dc+sd-jwt\",\n docType: \"urn:eu.europa.ec.eudi:pda1:1\",\n namespace: \"urn:eu.europa.ec.eudi:pda1:1\",\n vct: \"urn:eu.europa.ec.eudi:pda1:1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"birth_date\", name: \"Birth Date\" },\n { id: \"nationality\", name: \"Nationality\" },\n { id: \"social_security_number\", name: \"Social Security Number\" },\n { id: \"issuing_country\", name: \"Issuing Country\" },\n { id: \"expiry_date\", name: \"Expiry Date\" },\n ],\n },\n\n // ===========================================================================\n // Retail\n // ===========================================================================\n\n loyalty: {\n id: \"loyalty\",\n name: \"Loyalty Card\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.loyalty.1\",\n namespace: \"eu.europa.ec.eudi.loyalty.1\",\n profile: \"haip\",\n claims: [\n { id: \"family_name\", name: \"Family Name\" },\n { id: \"given_name\", name: \"Given Names\" },\n { id: \"loyalty_number\", name: \"Loyalty Number\" },\n { id: \"program_name\", name: \"Program Name\" },\n ],\n },\n\n msisdn: {\n id: \"msisdn\",\n name: \"Mobile Phone Number (MSISDN)\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.msisdn.1\",\n namespace: \"eu.europa.ec.eudi.msisdn.1\",\n profile: \"haip\",\n claims: [\n { id: \"phone_number\", name: \"Phone Number\" },\n { id: \"registered_family_name\", name: \"Registered Family Name\" },\n ],\n },\n\n \"msisdn-sd-jwt\": {\n id: \"msisdn-sd-jwt\",\n name: \"Mobile Phone Number (MSISDN) — SD-JWT VC\",\n format: \"dc+sd-jwt\",\n docType: \"urn:eu.europa.ec.eudi:msisdn:1\",\n namespace: \"urn:eu.europa.ec.eudi:msisdn:1\",\n vct: \"urn:eu.europa.ec.eudi:msisdn:1\",\n profile: \"haip\",\n claims: [\n { id: \"phone_number\", name: \"Phone Number\" },\n { id: \"registered_family_name\", name: \"Registered Family Name\" },\n ],\n },\n\n // ===========================================================================\n // Other\n // ===========================================================================\n\n por: {\n id: \"por\",\n name: \"Power of Representation\",\n format: \"mso_mdoc\",\n docType: \"eu.europa.ec.eudi.por.1\",\n namespace: \"eu.europa.ec.eudi.por.1\",\n profile: \"haip\",\n claims: [\n { id: \"legal_person_id\", name: \"Legal Person ID\" },\n { id: \"legal_person_name\", name: \"Legal Person Name\" },\n { id: \"representative_family_name\", name: \"Representative Family Name\" },\n { id: \"representative_given_name\", name: \"Representative Given Names\" },\n ],\n },\n\n \"por-sd-jwt\": {\n id: \"por-sd-jwt\",\n name: \"Power of Representation — SD-JWT VC\",\n format: \"dc+sd-jwt\",\n docType: \"urn:eu.europa.ec.eudi:por:1\",\n namespace: \"urn:eu.europa.ec.eudi:por:1\",\n vct: \"urn:eu.europa.ec.eudi:por:1\",\n profile: \"haip\",\n claims: [\n { id: \"legal_person_id\", name: \"Legal Person ID\" },\n { id: \"legal_person_name\", name: \"Legal Person Name\" },\n { id: \"representative_family_name\", name: \"Representative Family Name\" },\n { id: \"representative_given_name\", name: \"Representative Given Names\" },\n ],\n },\n};\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Get default selected claims for a credential type (first 5 claims).\n */\nexport function getDefaultClaims(credentialType: CredentialType): string[] {\n const config = CREDENTIAL_TYPES[credentialType];\n if (!config) return [];\n return config.claims.slice(0, 5).map((c) => c.id);\n}\n\n/**\n * Get claim definitions for a credential type.\n */\nexport function getClaimsForType(\n credentialType: CredentialType,\n): ClaimDefinition[] {\n return CREDENTIAL_TYPES[credentialType]?.claims || [];\n}\n\n/**\n * Get the protocol profile for a credential type.\n */\nexport function getProfileForType(\n credentialType: CredentialType,\n): ProtocolProfile | null {\n const config = CREDENTIAL_TYPES[credentialType];\n if (!config) return null;\n return PROTOCOL_PROFILES[config.profile] || null;\n}\n\n/**\n * Get the profile ID for a credential type.\n */\nexport function getProfileIdForType(credentialType: CredentialType): ProfileId {\n const config = CREDENTIAL_TYPES[credentialType];\n return config?.profile || \"haip\";\n}\n","/**\n * @ewqwe/digital-identity — DCQL Query Utilities\n *\n * Functions to build, parse, and convert DCQL (Digital Credentials Query Language)\n * queries for EU Age Verification and OpenID4VP presentations.\n *\n * Node.js compatible — uses Node.js crypto API.\n *\n * @see https://openid.net/specs/openid-4-verifiable-presentations-1_0.html §6–7\n * @see https://ageverification.dev/Technical%20Specification/annexes/annex-A/annex-A-av-profile\n */\n\nimport type {\n CredentialType,\n InitTransactionRequest,\n ProfileId,\n VpFormats,\n} from \"./types.js\";\nimport { CREDENTIAL_TYPES } from \"./config.js\";\n\n// =============================================================================\n// Constants — Namespaces and Document Types\n// =============================================================================\n\n/** EU Age Verification namespace. */\nexport const EU_AV_NAMESPACE = \"eu.europa.ec.av.1\";\n\n/** EU Age Verification mDoc document type. */\nexport const EU_AV_DOCTYPE = \"eu.europa.ec.av.1.mdoc\";\n\n/** ISO 18013-5 mDL namespace. */\nexport const ISO_MDL_NAMESPACE = \"org.iso.18013.5.1\";\n\n/** ISO 18013-5 mDL document type. */\nexport const ISO_MDL_DOCTYPE = \"org.iso.18013.5.1.mDL\";\n\n/** EU PID namespace. */\nexport const EU_PID_NAMESPACE = \"eu.europa.ec.eudi.pid.1\";\n\n/** EU PID document type. */\nexport const EU_PID_DOCTYPE = \"eu.europa.ec.eudi.pid.1\";\n\n// ============================================================================\n// DCQL (Digital Credentials Query Language) — OpenID4VP 1.0 §6\n// ============================================================================\n\n/**\n * A single entry in `trusted_authorities` — identifies an authority or trust framework\n * that certifies credential issuers the Verifier will accept.\n *\n * A Credential matches if it satisfies **at least one** entry in the array.\n *\n * Type identifiers defined by OpenID4VP 1.0 §6.1.1:\n * - `\"aki\"` — X.509 Authority Key Identifier, base64url-encoded (§6.1.1.1)\n * - `\"etsi_tl\"` — ETSI Trusted List identifier (§6.1.1.2)\n * - `\"openid_federation\"` — OpenID Federation Entity Identifier (§6.1.1.3)\n *\n * @see https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-6.1.1\n */\nexport interface TrustedAuthoritiesQuery {\n /** Type identifier for the trust framework. */\n type: \"aki\" | \"etsi_tl\" | \"openid_federation\" | string;\n /** Non-empty array of values interpreted according to `type`. */\n values: string[];\n}\n\n/** A single claim constraint in a DCQL credential query. */\nexport interface DCQLClaimsQuery {\n /** Claim identifier (for referencing in claim_sets). */\n id?: string;\n /**\n * Claims Path Pointer (OpenID4VP 1.0 §7).\n *\n * A **non-empty** array whose elements must be:\n * - `string` — navigate into the named key of an object (§7.1)\n * - `number` (non-negative integer) — select the element at this index in an array (§7.1)\n * - `null` — select **all** elements of the currently selected array(s) (§7.1)\n *\n * For `mso_mdoc` credentials (§7.2) exactly two strings are required:\n * `[namespace, dataElementIdentifier]`.\n *\n * Examples from §7.3:\n * - `[\"address\", \"street_address\"]` — nested object key\n * - `[\"degrees\", null, \"type\"]` — all `type` values across the `degrees` array\n * - `[\"nationalities\", 1]` — second element of the `nationalities` array\n */\n path: (string | number | null)[];\n /** Expected values — if provided, claim must match one of these (§6.3). */\n values?: (string | number | boolean)[];\n /** Whether to retain this claim after verification (mso_mdoc only, §B.2.4). */\n intent_to_retain?: boolean;\n}\n\n/**\n * A single credential query in DCQL.\n *\n * Format identifiers per the OpenID4VP 1.0 spec (Appendix B):\n * - `\"mso_mdoc\"` — ISO/IEC 18013-5 Mobile Documents (§B.2)\n * - `\"dc+sd-jwt\"` — IETF SD-JWT VC (§B.3), canonical since Nov 2024\n * (was `\"vc+sd-jwt\"` before Nov 2024; both SHOULD be accepted per\n * draft-ietf-oauth-sd-jwt-vc-08 §3.2.1)\n * - `\"jwt_vc_json\"` — W3C VC signed as JWT (§B.1.3.1)\n * - `\"ldp_vc\"` — W3C VC with Linked Data Proofs (§B.1.3.2)\n *\n * @see https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#appendix-B\n * @see https://www.ietf.org/archive/id/draft-ietf-oauth-sd-jwt-vc-08.html#section-3.2.1\n */\nexport interface DCQLCredentialQuery {\n /** Unique identifier for this credential query. */\n id: string;\n /**\n * Credential format identifier.\n *\n * `\"mso_mdoc\"` is for ISO/IEC 18013-5 Mobile Documents (mDL/mDoc).\n *\n * `\"sd-jwt\"` formats are for IETF SD-JWT Verifiable Credentials. The current\n * IANA-registered identifier for SD-JWT VC is `\"dc+sd-jwt\"` (application/dc+sd-jwt),\n * which is the canonical name to use going forward. The older `\"vc+sd-jwt\"`\n * SHOULD also be accepted during the transitional period per draft-ietf-oauth-sd-jwt-vc-08 §3.2.1.\n *\n * `\"jwt_vc_json\"` is for W3C Verifiable Credentials signed as JWT without JSON-LD.\n *\n * `\"ldp_vc\"` is for W3C Verifiable Credentials with Linked Data Proofs.\n */\n format: \"mso_mdoc\" | \"dc+sd-jwt\" | \"vc+sd-jwt\" | \"jwt_vc_json\" | \"ldp_vc\";\n /** Format-specific metadata. */\n meta?: {\n /** Document type for mso_mdoc (e.g. \"org.iso.18013.5.1.mDL\"). */\n doctype_value?: string;\n /** Verifiable Credential Type values for dc+sd-jwt / vc+sd-jwt. */\n vct_values?: string[];\n /** Type values for jwt_vc_json / ldp_vc. */\n type_values?: string[][];\n };\n /** Claims to request from the credential. */\n claims?: DCQLClaimsQuery[];\n /** Named subsets of claims; the wallet picks one set. */\n claim_sets?: string[][];\n /** Allow the wallet to return multiple matching credentials. */\n multiple?: boolean;\n /**\n * Expected authorities or trust frameworks that certify issuers the Verifier will accept.\n *\n * OPTIONAL non-empty array. Every Credential returned by the Wallet SHOULD match at least\n * one of the conditions. The Verifier still bears its own responsibility to verify issuer\n * trust; this field is a hint to the Wallet to avoid sending credentials likely to be\n * rejected. See §6.1.1 for matching semantics per type.\n *\n * @see https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#section-6.1.1\n */\n trusted_authorities?: TrustedAuthoritiesQuery[];\n /**\n * Require cryptographic holder binding in the presentation.\n *\n * OPTIONAL. Default is `true` per §6.1 — a Verifiable Presentation with Cryptographic\n * Holder Binding is required unless explicitly set to `false`.\n */\n require_cryptographic_holder_binding?: boolean;\n}\n\n/** A credential set defining alternatives (OR logic). */\nexport interface DCQLCredentialSetQuery {\n /** Which credential query options satisfy this set. */\n options: string[][];\n /** Whether this credential set is required (default: true). */\n required?: boolean;\n /** Human-readable purpose for this credential set. */\n purpose?: string;\n}\n\n/** The complete DCQL query structure — OpenID4VP 1.0 §6. */\nexport interface DCQLQuery {\n /** Array of credential queries. */\n credentials: DCQLCredentialQuery[];\n /** Optional credential sets for defining alternatives. */\n credential_sets?: DCQLCredentialSetQuery[];\n}\n\n// =============================================================================\n// Query Builder Functions\n// =============================================================================\n\n/**\n * Build a minimal age verification query using the EU AV profile.\n *\n * @param ageThreshold - The age threshold to verify (e.g. 18, 21)\n * @returns DCQL query requesting age_over_N = true\n */\nexport function buildAgeVerificationQuery(\n ageThreshold: number = 18,\n): DCQLQuery {\n const claimName = `age_over_${ageThreshold}`;\n return {\n credentials: [\n {\n id: \"eu_av_proof\",\n format: \"mso_mdoc\",\n meta: { doctype_value: EU_AV_DOCTYPE },\n claims: [\n {\n path: [EU_AV_NAMESPACE, claimName],\n values: [true],\n intent_to_retain: false,\n },\n ],\n },\n ],\n };\n}\n\n/**\n * Build an age verification query with mDL fallback.\n *\n * Uses credential_sets to allow either EU AV proof OR mDL.\n *\n * @param ageThreshold - The age threshold to verify (e.g., 18, 21)\n * @returns DCQL query with EU AV primary and mDL fallback\n */\nexport function buildAgeVerificationQueryWithFallback(\n ageThreshold: number = 18,\n): DCQLQuery {\n const claimName = `age_over_${ageThreshold}`;\n return {\n credentials: [\n {\n id: \"eu_av_proof\",\n format: \"mso_mdoc\",\n meta: { doctype_value: EU_AV_DOCTYPE },\n claims: [\n {\n path: [EU_AV_NAMESPACE, claimName],\n values: [true],\n intent_to_retain: false,\n },\n ],\n },\n {\n id: \"mdl_fallback\",\n format: \"mso_mdoc\",\n meta: { doctype_value: ISO_MDL_DOCTYPE },\n claims: [\n {\n path: [ISO_MDL_NAMESPACE, claimName],\n values: [true],\n intent_to_retain: false,\n },\n ],\n },\n ],\n credential_sets: [\n {\n options: [[\"eu_av_proof\"], [\"mdl_fallback\"]],\n required: true,\n },\n ],\n };\n}\n\n/**\n * Default DCQL query requesting age_over_18 from EU PID.\n */\nexport function getDefaultAgeVerificationDCQL(): DCQLQuery {\n return {\n credentials: [\n {\n id: \"eu-pid-age-verification\",\n format: \"mso_mdoc\",\n meta: { doctype_value: EU_PID_DOCTYPE },\n claims: [{ path: [EU_PID_NAMESPACE, \"age_over_18\"] }],\n },\n ],\n };\n}\n\n/**\n * Build an `InitTransactionRequest` directly from a credential type and\n * selected claims — the canonical way to initialize an OpenID4VP transaction.\n *\n * Builds a **DCQL query** directly (never a legacy `PresentationDefinition`),\n * so no server-side conversion is required.\n *\n * @param publicUrl - The public URL the wallet is going to call back to\n * @param credentialType - The type of credential to request\n * @param selectedClaims - Array of claim IDs to include (e.g. `[\"age_over_18\"]`)\n * @returns `InitTransactionRequest` ready to POST to `/ewqwe_api/openid4vp/init`\n */\nexport function buildInitTransactionRequest(\n publicUrl: string,\n credentialType: CredentialType,\n selectedClaims: string[],\n profile?: ProfileId,\n): InitTransactionRequest {\n const config = CREDENTIAL_TYPES[credentialType];\n if (!config) {\n throw new Error(`Unknown credential type: ${credentialType}`);\n }\n\n const isSdJwt = config.format === \"dc+sd-jwt\";\n\n // Build DCQL Claims Path Pointers:\n // - mso_mdoc: [namespace, element] per OpenID4VP §7.2\n // - dc+sd-jwt: [claimName] per OpenID4VP §B.3 (flat JSON path)\n // Note: `intent_to_retain` is an mso_mdoc-only field (OpenID4VP §7.2.5).\n // It MUST NOT appear in dc+sd-jwt credential queries.\n const claims: DCQLClaimsQuery[] = selectedClaims.map((claimId) => {\n const query: DCQLClaimsQuery = {\n id: claimId,\n path: isSdJwt ? [claimId] : [config.namespace, claimId],\n };\n if (!isSdJwt) {\n query.intent_to_retain = false;\n }\n return query;\n });\n\n const credentialQuery: DCQLCredentialQuery = isSdJwt\n ? {\n id: `${credentialType}_credential`,\n format: \"dc+sd-jwt\",\n meta: { vct_values: [config.vct!] },\n claims,\n }\n : {\n id: `${credentialType}_credential`,\n format: \"mso_mdoc\",\n meta: { doctype_value: config.docType },\n claims,\n };\n\n const dcqlQuery: DCQLQuery = {\n credentials: [credentialQuery],\n };\n\n // Build vp_formats based on the credential format\n const vp_formats: VpFormats = isSdJwt\n ? {\n \"dc+sd-jwt\": {\n \"sd-jwt_alg_values\": [\"ES256\", \"ES384\", \"ES512\"],\n \"kb-jwt_alg_values\": [\"ES256\", \"ES384\", \"ES512\"],\n },\n }\n : {\n mso_mdoc: {\n issuerauth_alg_values: [-7, -35, -36],\n deviceauth_alg_values: [-7, -35, -36],\n },\n };\n\n return {\n public_url: publicUrl,\n dcql_query: dcqlQuery,\n nonce: generateNonce(),\n credential_type: credentialType,\n profile,\n client_metadata: {\n client_name: \"ewQwe Digital Credentials Demo\",\n vp_formats,\n },\n };\n}\n\n/**\n * Determine the protocol profile based on credential type or explicit selection.\n *\n * - mDL and PID → HAIP (x509_san_dns, JAR signing, eudi-openid4vp://)\n * - Proof of Age → Annex A (redirect_uri, plain request, av://)\n */\nexport function determineProfile(\n credentialType?: string,\n explicitProfile?: \"haip\" | \"annex-a\",\n): \"haip\" | \"annex-a\" {\n if (explicitProfile) return explicitProfile;\n if (credentialType === \"proof-of-age\") return \"annex-a\";\n return \"haip\";\n}\n\n// =============================================================================\n// Query Utility Functions\n// =============================================================================\n\n/**\n * Generate a cryptographically secure nonce for OpenID4VP requests.\n *\n * @returns Base64URL-encoded random nonce\n */\nexport function generateNonce(): string {\n const bytes = new Uint8Array(32);\n globalThis.crypto.getRandomValues(bytes);\n\n if (typeof btoa === \"function\") {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n }\n\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes)\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=/g, \"\");\n }\n\n throw new Error(\"No base64 encoder available in this runtime\");\n}\n\n/**\n * Validate the structural rules of a DCQL query per OpenID4VP 1.0 §6 and §6.4.1.\n *\n * Rules enforced:\n *\n * **§6 — Top level**\n * - `credentials` MUST be non-empty.\n * - Credential query `id` values MUST be unique across `credentials`.\n * - `credential_sets`, if present, MUST be non-empty.\n * - Each `credential_sets` option element MUST reference a valid credential query `id`.\n *\n * **§6.1 — Credential Query**\n * - Each credential `id` MUST be a non-empty string of alphanumeric, `-`, or `_`.\n * - `trusted_authorities`, if present, MUST be non-empty.\n *\n * **§6.3 & §6.4.1 — Claims / claim_sets**\n * - `claim_sets` MUST NOT be present when `claims` is absent.\n * - Claim `id` values MUST be unique within a single `claims` array.\n * - When `claim_sets` is present, every claim MUST have a non-empty `id`.\n * - Every identifier referenced in `claim_sets` MUST appear in `claims`.\n *\n * @param query - The DCQL query to validate.\n * @returns An object `{ valid: true }` or `{ valid: false, error: string }`.\n */\nexport function isValidDCQLQuery(\n query: DCQLQuery,\n): { valid: true } | { valid: false; error: string } {\n const err = (msg: string) => ({ valid: false as const, error: msg });\n const idPattern = /^[A-Za-z0-9_-]+$/;\n\n // §6: credentials MUST be non-empty.\n if (!query.credentials || query.credentials.length === 0) {\n return err(\"DCQL query 'credentials' must be non-empty\");\n }\n\n const seenCredIds = new Set<string>();\n for (const cred of query.credentials) {\n // §6.1: id must be non-empty alphanumeric/underscore/hyphen.\n if (!cred.id || !idPattern.test(cred.id)) {\n return err(\n `Credential query id ${JSON.stringify(cred.id)} must be a non-empty alphanumeric/underscore/hyphen string`,\n );\n }\n if (seenCredIds.has(cred.id)) {\n return err(`Duplicate credential query id ${JSON.stringify(cred.id)}`);\n }\n seenCredIds.add(cred.id);\n\n // §6.1.1: trusted_authorities, if present, must be non-empty.\n if (cred.trusted_authorities !== undefined) {\n if (cred.trusted_authorities.length === 0) {\n return err(\n `Credential query ${JSON.stringify(cred.id)}: 'trusted_authorities' must be non-empty when present`,\n );\n }\n }\n\n // §6.4.1: claim_sets MUST NOT be present if claims is absent.\n if (cred.claim_sets !== undefined && cred.claims === undefined) {\n return err(\n `Credential query ${JSON.stringify(cred.id)}: 'claim_sets' must not be present when 'claims' is absent`,\n );\n }\n\n if (cred.claims !== undefined) {\n // Claim IDs must be unique within the claims array.\n const seenClaimIds = new Set<string>();\n for (const claim of cred.claims) {\n if (claim.id !== undefined) {\n if (!claim.id || !idPattern.test(claim.id)) {\n return err(\n `Credential query ${JSON.stringify(cred.id)}: claim id ${JSON.stringify(claim.id)} must be a non-empty alphanumeric/underscore/hyphen string`,\n );\n }\n if (seenClaimIds.has(claim.id)) {\n return err(\n `Credential query ${JSON.stringify(cred.id)}: duplicate claim id ${JSON.stringify(claim.id)}`,\n );\n }\n seenClaimIds.add(claim.id);\n }\n }\n\n if (cred.claim_sets !== undefined) {\n // When claim_sets is present, every claim MUST have an id.\n for (const claim of cred.claims) {\n if (claim.id === undefined) {\n return err(\n `Credential query ${JSON.stringify(cred.id)}: all claims must have an 'id' when 'claim_sets' is present`,\n );\n }\n }\n // Every id in claim_sets must reference a known claim id.\n for (const set of cred.claim_sets) {\n for (const refId of set) {\n if (!seenClaimIds.has(refId)) {\n return err(\n `Credential query ${JSON.stringify(cred.id)}: 'claim_sets' references unknown claim id ${JSON.stringify(refId)}`,\n );\n }\n }\n }\n }\n }\n }\n\n // §6: credential_sets, if present, must be non-empty and reference valid credential IDs.\n if (query.credential_sets !== undefined) {\n if (query.credential_sets.length === 0) {\n return err(\"'credential_sets' must be non-empty when present\");\n }\n for (const cs of query.credential_sets) {\n for (const optionSet of cs.options) {\n for (const refId of optionSet) {\n if (!seenCredIds.has(refId)) {\n return err(\n `'credential_sets' option references unknown credential query id ${JSON.stringify(refId)}`,\n );\n }\n }\n }\n }\n }\n\n return { valid: true };\n}\n\n/**\n * Parse a DCQL query from a string (typically from URL parameters).\n *\n * @param queryString - JSON string containing DCQL query\n * @returns Parsed DCQL query or null if invalid\n */\nexport function parseDCQLQuery(queryString: string): DCQLQuery | null {\n try {\n return JSON.parse(queryString) as DCQLQuery;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract the age threshold from a DCQL query.\n *\n * @param query - DCQL query to analyze\n * @returns Age threshold (e.g. 18, 21) or null if not an age verification query\n */\nexport function extractAgeThreshold(query: DCQLQuery): number | null {\n for (const credential of query.credentials) {\n for (const claim of credential.claims ?? []) {\n const pathComp = claim.path[claim.path.length - 1];\n if (typeof pathComp !== \"string\") continue;\n const match = pathComp.match(/^age_over_(\\d+)$/);\n if (match) {\n return parseInt(match[1], 10);\n }\n }\n }\n return null;\n}\n\n/**\n * Build an OpenID4VP authorization request URL for same-device flow.\n */\nexport function buildAuthorizationRequest(params: {\n rpDomain: string;\n redirectUri: string;\n ageThreshold?: number;\n nonce?: string;\n state?: string;\n}): Record<string, string> {\n const nonce = params.nonce ?? generateNonce();\n const state = params.state ?? generateNonce();\n const query = buildAgeVerificationQuery(params.ageThreshold ?? 18);\n\n return {\n client_id: `redirect_uri:${params.redirectUri}`,\n response_type: \"vp_token\",\n response_mode: \"fragment\",\n nonce,\n state,\n redirect_uri: params.redirectUri,\n dcql_query: JSON.stringify(query),\n };\n}\n\n/**\n * Build an OpenID4VP authorization request for cross-device flow.\n *\n * Note: When using the HAIP profile with the EUDI Wallet, the client_id should be\n * `x509_hash:<cert_hash>` instead of `x509_san_dns:<domain>` for a direct cryptographic\n * binding to the verifier's certificate. The `x509_san_dns` form is maintained here for\n * legacy compatibility and for deployments that still rely on DNS-based identification.\n */\nexport function buildCrossDeviceAuthorizationRequest(params: {\n rpDomain: string;\n responseUri: string;\n ageThreshold?: number;\n nonce?: string;\n state?: string;\n}): Record<string, string> {\n const nonce = params.nonce ?? generateNonce();\n const state = params.state ?? generateNonce();\n const query = buildAgeVerificationQueryWithFallback(\n params.ageThreshold ?? 18,\n );\n\n return {\n client_id: `x509_san_dns:${params.rpDomain}`,\n response_type: \"vp_token\",\n response_mode: \"direct_post\",\n nonce,\n state,\n response_uri: params.responseUri,\n dcql_query: JSON.stringify(query),\n };\n}\n","/**\n * Attestation JWT parsing and verification utilities.\n *\n * Browser- and Node-compatible — uses the Web Crypto API only (SubtleCrypto).\n *\n * @module\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Decoded payload of a credential verification attestation JWT.\n *\n * Standard JWT claims are typed; all credential-specific claims (e.g.\n * `age_over_18`, `given_name`) are accessible via index signature because they\n * are format-agnostic and defined by the credential schema, not this library.\n */\nexport interface Attestation {\n /** Issuer — credential verifier identifier. */\n iss: string;\n /** Subject — transaction / attestation event ID. */\n sub: string;\n /** Audience — relying party identifier (client_id). */\n aud: string;\n /** Expiration time (Unix timestamp seconds). */\n exp: number;\n /** Issued at (Unix timestamp seconds). */\n iat: number;\n /** Not before (Unix timestamp seconds). */\n nbf: number;\n /** Unique attestation ID (UUID). */\n jti: string;\n /** Nonce from the OpenID4VP request (replay prevention). */\n nonce?: string;\n /** Credential doc_type (e.g. `\"org.iso.18013.5.1.mDL\"`). */\n doc_type?: string;\n /** Credential namespace (e.g. `\"org.iso.18013.5.1\"`). */\n namespace?: string;\n /** All credential-specific claims, keyed by claim name. */\n [key: string]: unknown;\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\n/**\n * Base64url-decode a string to a Uint8Array.\n * Handles the standard base64url alphabet (no padding required).\n */\nexport function base64urlDecode(input: string): Uint8Array {\n // Restore padding and convert base64url → base64\n const base64 = input.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = base64.padEnd(\n base64.length + ((4 - (base64.length % 4)) % 4),\n \"=\",\n );\n\n if (typeof atob === \"function\") {\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n\n if (typeof Buffer !== \"undefined\") {\n return new Uint8Array(Buffer.from(padded, \"base64\"));\n }\n\n throw new Error(\"No base64 decoder available in this runtime\");\n}\n\nfunction getSubtleCrypto(): SubtleCrypto {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) {\n throw new Error(\"Web Crypto API is not available in this runtime\");\n }\n return subtle;\n}\n\nfunction splitJwt(jwt: string): [string, string, Uint8Array] {\n const parts = jwt.split(\".\");\n if (parts.length !== 3) {\n throw new Error(\"Invalid JWT: expected 3 dot-separated parts\");\n }\n const [headerB64, payloadB64, sigB64] = parts;\n const signature = base64urlDecode(sigB64);\n return [headerB64, payloadB64, signature];\n}\n\nfunction decodePayload(payloadB64: string): Attestation {\n const json = new TextDecoder().decode(base64urlDecode(payloadB64));\n return JSON.parse(json) as Attestation;\n}\n\n// ============================================================================\n// PEM / SPKI import\n// ============================================================================\n\n/**\n * Import an ES256 (ECDSA P-256) public key for attestation signature verification.\n *\n * Accepts either:\n * - A raw SPKI DER encoded as a base64 string (no headers), or\n * - A PEM-encoded SubjectPublicKeyInfo certificate (`-----BEGIN PUBLIC KEY-----`), or\n * - A PEM-encoded X.509 certificate (`-----BEGIN CERTIFICATE-----`): the Subject\n * Public Key Info is automatically extracted from the TBSCertificate.\n */\nexport function importVerifierPublicKey(pemOrSpki: string): Promise<CryptoKey> {\n const trimmed = pemOrSpki.trim();\n\n let spkiDer: ArrayBuffer;\n\n if (trimmed.startsWith(\"-----BEGIN CERTIFICATE-----\")) {\n // X.509 certificate: extract SPKI from TBSCertificate\n const b64 = trimmed\n .replace(/-----BEGIN CERTIFICATE-----/, \"\")\n .replace(/-----END CERTIFICATE-----/, \"\")\n .replace(/\\s+/g, \"\");\n const certDer = base64urlDecode(b64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\"))\n .buffer as ArrayBuffer;\n spkiDer = extractSpkiFromCert(certDer);\n } else if (trimmed.startsWith(\"-----BEGIN PUBLIC KEY-----\")) {\n const b64 = trimmed\n .replace(/-----BEGIN PUBLIC KEY-----/, \"\")\n .replace(/-----END PUBLIC KEY-----/, \"\")\n .replace(/\\s+/g, \"\");\n spkiDer = base64urlDecode(b64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\"))\n .buffer as ArrayBuffer;\n } else {\n // Assume raw base64 (not base64url) SPKI DER\n const b64 = trimmed.replace(/\\s+/g, \"\");\n spkiDer = base64urlDecode(b64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\"))\n .buffer as ArrayBuffer;\n }\n\n return getSubtleCrypto().importKey(\n \"spki\",\n spkiDer,\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n false,\n [\"verify\"],\n );\n}\n\n/**\n * Minimal DER parser: walk the certificate DER to extract the SubjectPublicKeyInfo.\n *\n * The ASN.1 structure is:\n * Certificate SEQUENCE {\n * TBSCertificate SEQUENCE {\n * ... fields ...\n * subjectPublicKeyInfo SEQUENCE { algorithm, subjectPublicKey }\n * ...\n * }\n * ...\n * }\n *\n * We locate the SPKI by finding the AlgorithmIdentifier OID for id-ecPublicKey\n * (1.2.840.10045.2.1) inside the TBSCertificate and backing up to its containing\n * SEQUENCE, which is the SPKI.\n */\nfunction extractSpkiFromCert(der: ArrayBuffer): ArrayBuffer {\n const bytes = new Uint8Array(der);\n\n // OID for id-ecPublicKey: 1.2.840.10045.2.1 → hex 2a 86 48 ce 3d 02 01\n const EC_OID = new Uint8Array([0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01]);\n\n // Search for the OID bytes\n outer: for (let i = 0; i < bytes.length - EC_OID.length; i++) {\n for (let j = 0; j < EC_OID.length; j++) {\n if (bytes[i + j] !== EC_OID[j]) continue outer;\n }\n // Found OID at offset i. It is wrapped as: 06 <len> <oid bytes>\n // The containing SEQUENCE (AlgorithmIdentifier) starts just before with 30 <len>.\n // The SPKI SEQUENCE wraps that AlgorithmIdentifier.\n // Back up past: OID tag (1) + OID length byte (1) = we're already at OID content,\n // so the OID TLV starts at i-2.\n const oidTlvStart = i - 2;\n // AlgorithmIdentifier SEQUENCE starts before that\n const algIdStart = oidTlvStart - 2; // tag(1) + len(1) — works for short lengths\n if (algIdStart < 2) continue;\n // SPKI SEQUENCE is the parent; its tag is at algIdStart - 2 (for short-form len)\n // But DER lengths can be multi-byte. Scan backwards for the enclosing SEQUENCE tag.\n const spkiStart = findEnclosingSequence(bytes, algIdStart);\n if (spkiStart < 0) continue;\n const [, spkiEnd] = readTlvBounds(bytes, spkiStart);\n return bytes.slice(spkiStart, spkiEnd).buffer;\n }\n\n throw new Error(\n \"Could not extract SubjectPublicKeyInfo from certificate — EC public key OID not found\",\n );\n}\n\n/** Return the offset of the SEQUENCE tag that begins at or just before `contentStart`. */\nfunction findEnclosingSequence(\n bytes: Uint8Array,\n contentStart: number,\n): number {\n // Walk backwards looking for a 0x30 SEQUENCE tag whose declared length covers contentStart\n for (let i = contentStart - 2; i >= 0; i--) {\n if (bytes[i] !== 0x30) continue;\n try {\n const [bodyStart, end] = readTlvBounds(bytes, i);\n if (bodyStart <= contentStart && contentStart < end) return i;\n } catch {\n // ignore parse errors while scanning\n }\n }\n return -1;\n}\n\n/**\n * Parse a DER TLV at `offset`.\n * Returns `[bodyStart, end]` where `end` is the first byte after the TLV.\n */\nfunction readTlvBounds(bytes: Uint8Array, offset: number): [number, number] {\n let pos = offset + 1; // skip tag\n let len: number;\n if (bytes[pos] & 0x80) {\n const numBytes = bytes[pos] & 0x7f;\n len = 0;\n for (let k = 0; k < numBytes; k++) {\n len = (len << 8) | bytes[++pos];\n }\n pos++;\n } else {\n len = bytes[pos++];\n }\n return [pos, pos + len];\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Decode and verify an attestation JWT signed by the credential verifier.\n *\n * Steps:\n * 1. Fetches the JWKS from `jwksUrl`.\n * 2. Locates the verification key using the `kid` from the JWT header (falls back\n * to the first key carrying an `x5c` certificate chain).\n * 3. Imports the public key from the DER certificate in `x5c[0]`.\n * 4. Verifies the ES256 signature and checks `exp` / `nbf`.\n * 5. Returns the verified {@link Attestation}.\n *\n * @param jwt - Compact-serialized JWT from `VerifyResponse.attestation`.\n * @param jwksUrl - URL of the JWK Set that contains the attestation signing key,\n * e.g. `\"/ewqwe_api/openid4vp/.well-known/jwks.json\"`.\n * @throws If the JWKS cannot be fetched, no matching key is found, or verification fails.\n */\nexport function decodeAttestation(jwt: string): Attestation {\n const parts = jwt.split(\".\");\n if (parts.length !== 3) {\n throw new Error(\"Invalid JWT: expected 3 dot-separated parts\");\n }\n return decodePayload(parts[1]);\n}\n\nexport function getAttestationExpiryStatus(\n attestation: Attestation,\n): \"valid\" | \"expired\" | \"not_yet_valid\" {\n const nowSeconds = Math.floor(Date.now() / 1000);\n if (attestation.exp !== undefined && attestation.exp < nowSeconds) {\n return \"expired\";\n }\n if (attestation.nbf !== undefined && attestation.nbf > nowSeconds) {\n return \"not_yet_valid\";\n }\n return \"valid\";\n}\n\nexport async function parseAttestation(\n jwt: string,\n jwksUrl: string,\n): Promise<Attestation> {\n // Decode the JWT header to obtain the key ID\n const parts = jwt.split(\".\");\n if (parts.length !== 3) {\n throw new Error(\"Invalid JWT: expected 3 dot-separated parts\");\n }\n const header = JSON.parse(\n new TextDecoder().decode(base64urlDecode(parts[0])),\n ) as Record<string, unknown>;\n const kid = typeof header.kid === \"string\" ? header.kid : undefined;\n\n // Fetch the JWK Set\n const resp = await fetch(jwksUrl);\n if (!resp.ok) {\n throw new Error(\n `Failed to fetch JWKS from ${jwksUrl}: HTTP ${resp.status}`,\n );\n }\n const jwks = (await resp.json()) as { keys?: unknown[] };\n const keys = Array.isArray(jwks.keys) ? jwks.keys : [];\n\n // Find the matching key: prefer kid match, fall back to first key with x5c\n let jwk: unknown = undefined;\n if (kid !== undefined) {\n jwk = keys.find((k: unknown) => {\n const keyObj = k as Record<string, unknown>;\n return keyObj.kid === kid;\n });\n }\n if (!jwk) {\n jwk = keys.find((k: unknown) => {\n const keyObj = k as Record<string, unknown>;\n return Array.isArray(keyObj.x5c) && keyObj.x5c.length > 0;\n });\n }\n if (!jwk) {\n throw new Error(\n `No suitable attestation verification key found in JWKS${kid !== undefined ? ` for kid=\"${kid}\"` : \"\"}`,\n );\n }\n\n const jwkObj = jwk as Record<string, unknown>;\n if (!Array.isArray(jwkObj.x5c) || jwkObj.x5c.length === 0) {\n throw new Error(\"JWKS attestation key does not include an x5c certificate\");\n }\n\n // x5c values are standard base64-encoded DER (RFC 7517 §4.7).\n // Reconstruct a PEM so importVerifierPublicKey takes the certificate branch\n // and extracts the SubjectPublicKeyInfo via the DER parser.\n const certPem = `-----BEGIN CERTIFICATE-----\\n${jwkObj.x5c[0]}\\n-----END CERTIFICATE-----`;\n const publicKey = await importVerifierPublicKey(certPem);\n\n return verifyAttestation(jwt, publicKey);\n}\n\n/**\n * Verify an ES256 attestation JWT signature and return the decoded claims.\n *\n * @param jwt - The compact-serialized JWT string.\n * @param publicKey - The verifier's public key, obtained from `importVerifierPublicKey`.\n * @throws If the signature is invalid, the JWT is malformed, or the claims are expired.\n */\nexport async function verifyAttestation(\n jwt: string,\n publicKey: CryptoKey,\n): Promise<Attestation> {\n const [headerB64, payloadB64, signature] = splitJwt(jwt);\n\n const message = new TextEncoder().encode(`${headerB64}.${payloadB64}`);\n\n const valid = await getSubtleCrypto().verify(\n { name: \"ECDSA\", hash: { name: \"SHA-256\" } },\n publicKey,\n signature.buffer as ArrayBuffer,\n message,\n );\n\n if (!valid) {\n throw new Error(\"Attestation JWT signature verification failed\");\n }\n\n const claims = decodePayload(payloadB64);\n\n const status = getAttestationExpiryStatus(claims);\n if (status === \"expired\") {\n throw new Error(\n `Attestation JWT is expired (exp=${claims.exp}, now=${Math.floor(\n Date.now() / 1000,\n )})`,\n );\n }\n if (status === \"not_yet_valid\") {\n throw new Error(\n `Attestation JWT is not yet valid (nbf=${claims.nbf}, now=${Math.floor(\n Date.now() / 1000,\n )})`,\n );\n }\n\n return claims;\n}\n","import type {\n InitTransactionRequest,\n InitTransactionResponse,\n OpenID4VPRequest,\n OpenID4VPResponse,\n PresentationSubmission,\n TransactionStatusResult,\n VerifyRequest,\n VerifyResponse,\n} from \"./types.js\";\n\nexport type FetchFn = (\n input: RequestInfo,\n init?: RequestInit,\n) => Promise<Response>;\n\nexport interface ApiClientOptions {\n fetch?: FetchFn;\n baseUrl?: string;\n}\n\nexport class EwqweApiClient {\n private fetchFn: FetchFn;\n private baseUrl: string;\n\n constructor(options?: ApiClientOptions) {\n if (options?.fetch) {\n this.fetchFn = options.fetch;\n } else if (typeof globalThis.fetch === \"function\") {\n this.fetchFn = globalThis.fetch.bind(globalThis);\n } else {\n throw new Error(\"No fetch implementation available\");\n }\n\n this.baseUrl = options?.baseUrl?.replace(/\\/$/u, \"\") ?? \"\";\n }\n\n private buildUrl(path: string): string {\n if (/^https?:\\/\\//i.test(path)) {\n return path;\n }\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${this.baseUrl}${normalizedPath}`;\n }\n\n private async requestJson<T>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const url = this.buildUrl(path);\n const response = await this.fetchFn(url, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => \"\");\n const errMsg = text\n ? `${response.status} ${response.statusText}: ${text}`\n : `${response.status} ${response.statusText}`;\n throw new Error(`API request failed ${method} ${url}: ${errMsg}`);\n }\n\n const result = (await response.json()) as T;\n return result;\n }\n\n async initOpenID4VPTransaction(\n request: InitTransactionRequest,\n ): Promise<InitTransactionResponse> {\n return await this.requestJson<InitTransactionResponse>(\n \"POST\",\n \"/ewqwe_api/openid4vp/init\",\n request,\n );\n }\n\n async getOpenID4VPTransactionStatus(\n transactionId: string,\n ): Promise<TransactionStatusResult> {\n return await this.requestJson<TransactionStatusResult>(\n \"GET\",\n `/ewqwe_api/openid4vp/status/${encodeURIComponent(transactionId)}`,\n );\n }\n\n async getOpenID4VPAuthorizationRequest(\n transactionId: string,\n ): Promise<OpenID4VPRequest> {\n return await this.requestJson<OpenID4VPRequest>(\n \"GET\",\n `/ewqwe_api/openid4vp/request/${encodeURIComponent(transactionId)}`,\n );\n }\n\n async postOpenID4VPAuthorizationRequest(\n transactionId: string,\n authResponse: OpenID4VPResponse,\n ): Promise<void> {\n await this.requestJson<void>(\n \"POST\",\n `/ewqwe_api/openid4vp/request/${encodeURIComponent(transactionId)}`,\n authResponse,\n );\n }\n\n async postOpenID4VPDirectPost(response: OpenID4VPResponse): Promise<void> {\n await this.requestJson<void>(\n \"POST\",\n \"/ewqwe_api/openid4vp/direct_post\",\n response,\n );\n }\n\n async getOpenID4VPJwks(): Promise<{ keys: unknown[] }> {\n return await this.requestJson<{ keys: unknown[] }>(\n \"GET\",\n \"/ewqwe_api/openid4vp/.well-known/jwks.json\",\n );\n }\n\n async verifyPresentation(request: VerifyRequest): Promise<VerifyResponse> {\n return await this.requestJson<VerifyResponse>(\n \"POST\",\n \"/ewqwe_api/verify\",\n request,\n );\n }\n}\n"],"mappings":"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"}
|