@sphereon/pex
Version:
A Typescript implementation of the v1 and v2 DIF Presentation Exchange specification
211 lines • 23.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LimitDisclosureEvaluationHandler = void 0;
const pex_models_1 = require("@sphereon/pex-models");
const ssi_types_1 = require("@sphereon/ssi-types");
const ConstraintUtils_1 = require("../../ConstraintUtils");
const Messages_1 = __importDefault(require("../../types/Messages"));
const utils_1 = require("../../utils");
const abstractEvaluationHandler_1 = require("./abstractEvaluationHandler");
const markForSubmissionEvaluationHandler_1 = require("./markForSubmissionEvaluationHandler");
class LimitDisclosureEvaluationHandler extends abstractEvaluationHandler_1.AbstractEvaluationHandler {
constructor(client) {
super(client);
}
getName() {
return 'LimitDisclosureEvaluation';
}
handle(pd, wrappedVcs) {
this.evaluateLimitDisclosure(pd.input_descriptors, wrappedVcs);
}
isLimitDisclosureSupported(eligibleInputDescriptors, wvc, vcIndex) {
if (wvc.format === 'vc+sd-jwt' || wvc.format === 'mso_mdoc')
return true;
if (wvc.format === 'ldp' || wvc.format === 'jwt')
return false;
const limitDisclosureSignatures = this.client.limitDisclosureSignatureSuites;
const decoded = wvc.decoded;
const proofs = Array.isArray(decoded.proof) ? decoded.proof : decoded.proof ? [decoded.proof] : undefined;
const requiredLimitDisclosureInputDescriptorIds = eligibleInputDescriptors
.map(({ inputDescriptor: { constraints }, inputDescriptorIndex }) => (constraints === null || constraints === void 0 ? void 0 : constraints.limit_disclosure) === pex_models_1.Optionality.Required ? inputDescriptorIndex : undefined)
.filter((id) => id !== undefined);
if (!proofs || proofs.length === 0 || proofs.length > 1 || !proofs[0].type) {
// todo: Support/inspect array based proofs
if (requiredLimitDisclosureInputDescriptorIds.length > 0) {
this.createLimitDisclosureNotSupportedResult(eligibleInputDescriptors.map((i) => i.inputDescriptorIndex), vcIndex, 'Multiple proofs on verifiable credential not supported for limit disclosure');
}
return false;
}
const proof = proofs[0];
const signatureSuite = proof.cryptosuite ? `${proof.type}.${proof.cryptosuite}` : proof.type;
if (!(limitDisclosureSignatures === null || limitDisclosureSignatures === void 0 ? void 0 : limitDisclosureSignatures.includes(signatureSuite))) {
if (requiredLimitDisclosureInputDescriptorIds.length > 0) {
this.createLimitDisclosureNotSupportedResult(requiredLimitDisclosureInputDescriptorIds, vcIndex, `Signature suite '${signatureSuite}' is not present in limitDisclosureSignatureSuites [${limitDisclosureSignatures.join(',')}]`);
}
return false;
}
return true;
}
evaluateLimitDisclosure(inputDescriptors, wrappedVcs) {
wrappedVcs.forEach((wvc, vcIndex) => {
const eligibleInputDescriptors = (0, markForSubmissionEvaluationHandler_1.eligibleInputDescriptorsForWrappedVc)(inputDescriptors, vcIndex, this.getResults());
const includeLimitDisclosure = eligibleInputDescriptors.some(({ inputDescriptor: { constraints } }) => (constraints === null || constraints === void 0 ? void 0 : constraints.limit_disclosure) === pex_models_1.Optionality.Preferred || (constraints === null || constraints === void 0 ? void 0 : constraints.limit_disclosure) === pex_models_1.Optionality.Required);
if (eligibleInputDescriptors.length > 0 && includeLimitDisclosure && this.isLimitDisclosureSupported(eligibleInputDescriptors, wvc, vcIndex)) {
this.enforceLimitDisclosure(wrappedVcs, eligibleInputDescriptors, vcIndex);
}
});
}
enforceLimitDisclosure(wrappedVcs, eligibleInputDescriptors, vcIndex) {
var _a, _b, _c;
const wvc = wrappedVcs[vcIndex];
if (ssi_types_1.CredentialMapper.isWrappedSdJwtVerifiableCredential(wvc)) {
const presentationFrame = this.createSdJwtPresentationFrame(eligibleInputDescriptors, wvc.credential, vcIndex);
// We update the SD-JWT to it's presentation format (remove disclosures, update pretty payload, etc..), except
// we don't create or include the (optional) KB-JWT yet, this is done when we create the presentation
if (presentationFrame) {
(0, utils_1.applySdJwtLimitDisclosure)(wvc.credential, presentationFrame);
wvc.decoded = wvc.credential.decodedPayload;
// We need to overwrite the original, as that is returned in the selectFrom method
// But we also want to keep the format of the original credential.
wvc.original = ssi_types_1.CredentialMapper.isSdJwtDecodedCredential(wvc.original) ? wvc.credential : wvc.credential.compactSdJwtVc;
for (const { inputDescriptorIndex, inputDescriptor } of eligibleInputDescriptors) {
this.createSuccessResult(inputDescriptorIndex, `$[${vcIndex}]`, (_a = inputDescriptor.constraints) === null || _a === void 0 ? void 0 : _a.limit_disclosure);
}
}
}
else if (ssi_types_1.CredentialMapper.isWrappedMdocCredential(wvc)) {
for (const { inputDescriptorIndex, inputDescriptor } of eligibleInputDescriptors) {
this.createSuccessResult(inputDescriptorIndex, `$[${vcIndex}]`, (_b = inputDescriptor.constraints) === null || _b === void 0 ? void 0 : _b.limit_disclosure);
}
}
else if (ssi_types_1.CredentialMapper.isWrappedW3CVerifiableCredential(wvc)) {
const internalCredentialToSend = this.createVcWithRequiredFields(eligibleInputDescriptors, wvc.credential, vcIndex);
/* When verifiableCredentialToSend is null/undefined an error is raised, the credential will
* remain untouched and the verifiable credential won't be submitted.
*/
if (internalCredentialToSend) {
wvc.credential = internalCredentialToSend;
for (const { inputDescriptorIndex, inputDescriptor } of eligibleInputDescriptors) {
this.createSuccessResult(inputDescriptorIndex, `$[${vcIndex}]`, (_c = inputDescriptor.constraints) === null || _c === void 0 ? void 0 : _c.limit_disclosure);
}
}
}
else {
throw new Error('Unsupported format for selective disclosure');
}
}
createSdJwtPresentationFrame(inputDescriptors, vc, vcIndex) {
var _a, _b;
// Mapping of key -> true to indicate which values should be disclosed in an SD-JWT
// Can be nested array / object
const presentationFrame = {};
const processNestedObject = (obj, currentPath, basePath) => {
if (obj === null || typeof obj !== 'object') {
// For literal values, set the path to true in the presentation frame
utils_1.JsonPathUtils.setValue(presentationFrame, currentPath, true);
return;
}
// For arrays, process each element
if (Array.isArray(obj)) {
obj.forEach((item, index) => {
processNestedObject(item, [...currentPath, index], basePath);
});
return;
}
// For objects, process each child property
Object.entries(obj).forEach(([key, value]) => {
processNestedObject(value, [...currentPath, key], basePath);
});
};
for (const { inputDescriptor, inputDescriptorIndex } of inputDescriptors) {
for (const field of (_b = (_a = inputDescriptor.constraints) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : []) {
if (field.path) {
const inputField = utils_1.JsonPathUtils.extractInputField(vc.decodedPayload, field.path);
if (inputField.length > 0) {
const selectedField = inputField[0];
const fieldValue = utils_1.JsonPathUtils.getValue(vc.decodedPayload, selectedField.path);
if (fieldValue !== null && typeof fieldValue === 'object') {
// For objects, recursively process all nested fields
processNestedObject(fieldValue, selectedField.path, selectedField.path);
}
else {
// For literal values, just set the path to true
utils_1.JsonPathUtils.setValue(presentationFrame, selectedField.path, true);
}
}
else {
this.createMandatoryFieldNotFoundResult(inputDescriptorIndex, vcIndex, field.path);
return undefined;
}
}
}
}
return presentationFrame;
}
createVcWithRequiredFields(inputDescriptors, vc, vcIndex) {
var _a, _b;
let credentialToSend = {};
credentialToSend = Object.assign(credentialToSend, vc);
credentialToSend.credentialSubject = {};
for (const { inputDescriptor, inputDescriptorIndex } of inputDescriptors) {
for (const field of (_b = (_a = inputDescriptor.constraints) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : []) {
if (field.path) {
const inputField = utils_1.JsonPathUtils.extractInputField(vc, field.path);
if (inputField.length > 0) {
credentialToSend = this.copyResultPathToDestinationCredential(inputField[0], vc, credentialToSend);
}
else {
this.createMandatoryFieldNotFoundResult(inputDescriptorIndex, vcIndex, field.path);
return undefined;
}
}
}
}
return credentialToSend;
}
copyResultPathToDestinationCredential(requiredField, internalCredential, internalCredentialToSend) {
//TODO: ESSIFI-186
let credentialSubject = Object.assign({}, internalCredential.credentialSubject);
requiredField.path.forEach((e) => {
if (credentialSubject[e]) {
credentialSubject = { [e]: credentialSubject[e] };
}
});
internalCredentialToSend.credentialSubject = Object.assign(Object.assign({}, internalCredentialToSend.credentialSubject), credentialSubject);
return internalCredentialToSend;
}
createSuccessResult(idIdx, path, limitDisclosure) {
return this.getResults().push({
input_descriptor_path: `$.input_descriptors[${idIdx}]`,
verifiable_credential_path: `${path}`,
evaluator: this.getName(),
status: limitDisclosure === pex_models_1.Optionality.Required ? ConstraintUtils_1.Status.INFO : ConstraintUtils_1.Status.WARN,
message: Messages_1.default.LIMIT_DISCLOSURE_APPLIED,
payload: undefined,
});
}
createMandatoryFieldNotFoundResult(idIdx, vcIdx, path) {
return this.getResults().push({
input_descriptor_path: `$.input_descriptors[${idIdx}]`,
verifiable_credential_path: `$[${vcIdx}]`,
evaluator: this.getName(),
status: ConstraintUtils_1.Status.ERROR,
message: Messages_1.default.VERIFIABLE_CREDENTIAL_MANDATORY_FIELD_NOT_PRESENT,
payload: path,
});
}
createLimitDisclosureNotSupportedResult(idIdxs, vcIdx, reason) {
return this.getResults().push(...idIdxs.map((idIdx) => ({
input_descriptor_path: `$.input_descriptors[${idIdx}]`,
verifiable_credential_path: `$[${vcIdx}]`,
evaluator: this.getName(),
status: ConstraintUtils_1.Status.ERROR,
message: reason ? `${Messages_1.default.LIMIT_DISCLOSURE_NOT_SUPPORTED}. ${reason}` : Messages_1.default.LIMIT_DISCLOSURE_NOT_SUPPORTED,
})));
}
}
exports.LimitDisclosureEvaluationHandler = LimitDisclosureEvaluationHandler;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGltaXREaXNjbG9zdXJlRXZhbHVhdGlvbkhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWIvZXZhbHVhdGlvbi9oYW5kbGVycy9saW1pdERpc2Nsb3N1cmVFdmFsdWF0aW9uSGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxxREFBeUY7QUFDekYsbURBUzZCO0FBRzdCLDJEQUErQztBQUUvQyxvRUFBK0M7QUFDL0MsdUNBQXVFO0FBR3ZFLDJFQUF3RTtBQUN4RSw2RkFBNEY7QUFFNUYsTUFBYSxnQ0FBaUMsU0FBUSxxREFBeUI7SUFDN0UsWUFBWSxNQUF3QjtRQUNsQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDaEIsQ0FBQztJQUVNLE9BQU87UUFDWixPQUFPLDJCQUEyQixDQUFDO0lBQ3JDLENBQUM7SUFFTSxNQUFNLENBQUMsRUFBbUMsRUFBRSxVQUF5QztRQUMxRixJQUFJLENBQUMsdUJBQXVCLENBQUMsRUFBRSxDQUFDLGlCQUF3QyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ3hGLENBQUM7SUFFTywwQkFBMEIsQ0FDaEMsd0JBQW9ELEVBQ3BELEdBQWdDLEVBQ2hDLE9BQWU7UUFFZixJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssV0FBVyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssVUFBVTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3pFLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxLQUFLLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxLQUFLO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFFL0QsTUFBTSx5QkFBeUIsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLDhCQUE4QixDQUFDO1FBQzdFLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxPQUFnQyxDQUFDO1FBQ3JELE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxD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