UNPKG

@sphereon/ssi-types

Version:

SSI Common Types

142 lines • 7.37 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sdJwtDecodedCredentialToUniformCredential = void 0; exports.isWrappedSdJwtVerifiableCredential = isWrappedSdJwtVerifiableCredential; exports.isWrappedSdJwtVerifiablePresentation = isWrappedSdJwtVerifiablePresentation; exports.decodeSdJwtVc = decodeSdJwtVc; exports.decodeSdJwtVcAsync = decodeSdJwtVcAsync; const decode_1 = require("@sd-jwt/decode"); const did_1 = require("./did"); function isWrappedSdJwtVerifiableCredential(vc) { return vc.format === 'vc+sd-jwt'; } function isWrappedSdJwtVerifiablePresentation(vp) { return vp.format === 'vc+sd-jwt'; } /** * Decode an SD-JWT vc from its compact format (string) to an object containing the disclosures, * signed payload, decoded payload and the compact SD-JWT vc. * * Both the input and output interfaces of this method are defined in `@sphereon/ssi-types`, so * this method hides the actual implementation of SD-JWT (which is currently based on @sd-jwt/core) */ function decodeSdJwtVc(compactSdJwtVc, hasher) { const { jwt, disclosures, kbJwt } = (0, decode_1.decodeSdJwtSync)(compactSdJwtVc, hasher); const signedPayload = jwt.payload; const decodedPayload = (0, decode_1.getClaimsSync)(signedPayload, disclosures, hasher); const compactKeyBindingJwt = kbJwt ? compactSdJwtVc.split('~').pop() : undefined; return Object.assign({ compactSdJwtVc, decodedPayload: decodedPayload, disclosures: disclosures.map((d) => { const decoded = d.key ? [d.salt, d.key, d.value] : [d.salt, d.value]; if (!d._digest) throw new Error('Implementation error: digest not present in disclosure'); return { decoded: decoded, digest: d._digest, encoded: d.encode(), }; }), signedPayload: signedPayload }, (compactKeyBindingJwt && kbJwt && { kbJwt: { header: kbJwt.header, compact: compactKeyBindingJwt, payload: kbJwt.payload, }, })); } /** * Decode an SD-JWT vc from its compact format (string) to an object containing the disclosures, * signed payload, decoded payload and the compact SD-JWT vc. * * Both the input and output interfaces of this method are defined in `@sphereon/ssi-types`, so * this method hides the actual implementation of SD-JWT (which is currently based on @sd-jwt/core) */ function decodeSdJwtVcAsync(compactSdJwtVc, hasher) { return __awaiter(this, void 0, void 0, function* () { const { jwt, disclosures, kbJwt } = yield (0, decode_1.decodeSdJwt)(compactSdJwtVc, hasher); const signedPayload = jwt.payload; const decodedPayload = yield (0, decode_1.getClaims)(signedPayload, disclosures, hasher); const compactKeyBindingJwt = kbJwt ? compactSdJwtVc.split('~').pop() : undefined; return Object.assign({ compactSdJwtVc, decodedPayload: decodedPayload, disclosures: disclosures.map((d) => { const decoded = d.key ? [d.salt, d.key, d.value] : [d.salt, d.value]; if (!d._digest) throw new Error('Implementation error: digest not present in disclosure'); return { decoded: decoded, digest: d._digest, encoded: d.encode(), }; }), signedPayload: signedPayload }, (compactKeyBindingJwt && kbJwt && { kbJwt: { header: kbJwt.header, payload: kbJwt.payload, compact: compactKeyBindingJwt, }, })); }); } const sdJwtDecodedCredentialToUniformCredential = (decoded, opts) => { var _a, _b, _c; const { decodedPayload } = decoded; const { exp, nbf, iss, iat, vct, cnf, status, sub, jti } = decodedPayload; const maxSkewInMS = (_a = opts === null || opts === void 0 ? void 0 : opts.maxTimeSkewInMS) !== null && _a !== void 0 ? _a : 1500; const expirationDate = jwtDateToISOString({ jwtClaim: exp, claimName: 'exp' }); let issuanceDateStr = jwtDateToISOString({ jwtClaim: iat, claimName: 'iat' }); let nbfDateAsStr; if (nbf) { nbfDateAsStr = jwtDateToISOString({ jwtClaim: nbf, claimName: 'nbf' }); if (issuanceDateStr && nbfDateAsStr && issuanceDateStr !== nbfDateAsStr) { const diff = Math.abs(new Date(nbfDateAsStr).getTime() - new Date(iss).getTime()); if (!maxSkewInMS || diff > maxSkewInMS) { throw Error(`Inconsistent issuance dates between JWT claim (${nbfDateAsStr}) and VC value (${iss})`); } } issuanceDateStr = nbfDateAsStr; } const issuanceDate = issuanceDateStr; if (!issuanceDate) { throw Error(`JWT issuance date is required but was not present`); } // Filter out the fields we don't want in credentialSubject const excludedFields = new Set(['vct', 'cnf', 'iss', 'iat', 'exp', 'nbf', 'jti', 'sub']); const credentialSubject = Object.entries(decodedPayload).reduce((acc, [key, value]) => { if (!excludedFields.has(key) && value !== undefined && value !== '' && !(typeof value === 'object' && value !== null && Object.keys(value).length === 0)) { acc[key] = value; } return acc; }, {}); const credential = Object.assign(Object.assign(Object.assign({ type: [vct], '@context': [], credentialSubject: Object.assign(Object.assign({}, credentialSubject), { id: (_c = (_b = credentialSubject.id) !== null && _b !== void 0 ? _b : sub) !== null && _c !== void 0 ? _c : jti }), issuanceDate, expirationDate, issuer: iss }, (cnf && { cnf })), (status && { status })), { proof: { type: did_1.IProofType.SdJwtProof2024, created: nbfDateAsStr !== null && nbfDateAsStr !== void 0 ? nbfDateAsStr : issuanceDate, proofPurpose: did_1.IProofPurpose.authentication, verificationMethod: iss, jwt: decoded.compactSdJwtVc, } }); return credential; }; exports.sdJwtDecodedCredentialToUniformCredential = sdJwtDecodedCredentialToUniformCredential; const jwtDateToISOString = ({ jwtClaim, claimName, isRequired = false, }) => { if (jwtClaim) { const claim = parseInt(jwtClaim.toString()); // change JWT seconds to millisecond for the date return new Date(claim * (claim < 9999999999 ? 1000 : 1)).toISOString().replace(/\.000Z/, 'Z'); } else if (isRequired) { throw Error(`JWT claim ${claimName} is required but was not present`); } return undefined; }; //# sourceMappingURL=sd-jwt-vc.js.map