Skip to content

Commit

Permalink
style: fix
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <timo@animo.id>
  • Loading branch information
TimoGlastra committed Sep 18, 2024
1 parent 7a32234 commit 9717960
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 53 deletions.
6 changes: 5 additions & 1 deletion lib/evaluation/evaluationClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ import {
UriEvaluationHandler,
} from './handlers';

const DEFAULT_LIMIT_DISCLOSURE_TYPES = [IProofType.BbsBlsSignatureProof2020, 'DataIntegrityProof.anoncredsvc-2023', 'DataIntegrityProof.anoncreds-2023'];
const DEFAULT_LIMIT_DISCLOSURE_TYPES = [
IProofType.BbsBlsSignatureProof2020,
'DataIntegrityProof.anoncredsvc-2023',
'DataIntegrityProof.anoncreds-2023',
];

export class EvaluationClient {
constructor() {
Expand Down
79 changes: 52 additions & 27 deletions lib/evaluation/handlers/limitDisclosureEvaluationHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,46 @@ export class LimitDisclosureEvaluationHandler extends AbstractEvaluationHandler
}

public handle(pd: IInternalPresentationDefinition, wrappedVcs: WrappedVerifiableCredential[]): void {
this.evaluateLimitDisclosure(pd.input_descriptors as InputDescriptorV2[], wrappedVcs)
this.evaluateLimitDisclosure(pd.input_descriptors as InputDescriptorV2[], wrappedVcs);
}

private isLimitDisclosureSupported(elligibleInputDescriptors: InputDescriptorWithIndex[], wvc: WrappedVerifiableCredential, vcIndex: number): boolean {
private isLimitDisclosureSupported(
elligibleInputDescriptors: InputDescriptorWithIndex[],
wvc: WrappedVerifiableCredential,
vcIndex: number,
): boolean {
if (wvc.format === 'vc+sd-jwt') return true;

const limitDisclosureSignatures = this.client.limitDisclosureSignatureSuites;
const decoded = wvc.decoded as IVerifiableCredential
const proofs = Array.isArray(decoded.proof) ? decoded.proof : decoded.proof ? [decoded.proof] : undefined
const requiredLimitDisclosureInputDescriptorIds = elligibleInputDescriptors.map(({ inputDescriptor: { constraints }, inputDescriptorIndex }) => constraints?.limit_disclosure === Optionality.Required ? inputDescriptorIndex : undefined).filter((id): id is number => id !== undefined)
const decoded = wvc.decoded as IVerifiableCredential;
const proofs = Array.isArray(decoded.proof) ? decoded.proof : decoded.proof ? [decoded.proof] : undefined;
const requiredLimitDisclosureInputDescriptorIds = elligibleInputDescriptors
.map(({ inputDescriptor: { constraints }, inputDescriptorIndex }) =>
constraints?.limit_disclosure === Optionality.Required ? inputDescriptorIndex : undefined,
)
.filter((id): id is number => 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(elligibleInputDescriptors.map(i => i.inputDescriptorIndex), vcIndex, 'Multiple proofs on verifiable credential not supported for limit disclosure');
this.createLimitDisclosureNotSupportedResult(
elligibleInputDescriptors.map((i) => i.inputDescriptorIndex),
vcIndex,
'Multiple proofs on verifiable credential not supported for limit disclosure',
);
}
return false;
}

const proof = proofs[0]
const proof = proofs[0];
const signatureSuite = proof.cryptosuite ? `${proof.type}.${proof.cryptosuite}` : proof.type;
if (!limitDisclosureSignatures?.includes(signatureSuite)) {
if (requiredLimitDisclosureInputDescriptorIds.length > 0) {
this.createLimitDisclosureNotSupportedResult(requiredLimitDisclosureInputDescriptorIds, vcIndex, `Signature suite '${signatureSuite}' is not present in limitDisclosureSignatureSuites [${limitDisclosureSignatures.join(',')}]`);
this.createLimitDisclosureNotSupportedResult(
requiredLimitDisclosureInputDescriptorIds,
vcIndex,
`Signature suite '${signatureSuite}' is not present in limitDisclosureSignatureSuites [${limitDisclosureSignatures.join(',')}]`,
);
}
return false;
}
Expand All @@ -62,21 +78,24 @@ export class LimitDisclosureEvaluationHandler extends AbstractEvaluationHandler

private evaluateLimitDisclosure(inputDescriptors: Array<InputDescriptorV2 | InputDescriptorV1>, wrappedVcs: WrappedVerifiableCredential[]): void {
wrappedVcs.forEach((wvc, vcIndex) => {
const elligibleInputDescriptors = elligibleInputDescriptorsForWrappedVc(inputDescriptors, vcIndex, this.getResults())
const includeLimitDisclosure = elligibleInputDescriptors.some(({ inputDescriptor: { constraints } }) => constraints?.limit_disclosure === Optionality.Preferred || constraints?.limit_disclosure === Optionality.Required)

if (elligibleInputDescriptors.length > 0 && includeLimitDisclosure && this.isLimitDisclosureSupported(elligibleInputDescriptors, wvc, vcIndex)) {
const elligibleInputDescriptors = elligibleInputDescriptorsForWrappedVc(inputDescriptors, vcIndex, this.getResults());
const includeLimitDisclosure = elligibleInputDescriptors.some(
({ inputDescriptor: { constraints } }) =>
constraints?.limit_disclosure === Optionality.Preferred || constraints?.limit_disclosure === Optionality.Required,
);

if (
elligibleInputDescriptors.length > 0 &&
includeLimitDisclosure &&
this.isLimitDisclosureSupported(elligibleInputDescriptors, wvc, vcIndex)
) {
this.enforceLimitDisclosure(wrappedVcs, elligibleInputDescriptors, vcIndex);
}
});
}

private enforceLimitDisclosure(
wrappedVcs: WrappedVerifiableCredential[],
elligibleInputDescriptors: InputDescriptorWithIndex[],
vcIndex: number,
) {
const wvc = wrappedVcs[vcIndex]
private enforceLimitDisclosure(wrappedVcs: WrappedVerifiableCredential[], elligibleInputDescriptors: InputDescriptorWithIndex[], vcIndex: number) {
const wvc = wrappedVcs[vcIndex];

if (CredentialMapper.isWrappedSdJwtVerifiableCredential(wvc)) {
const presentationFrame = this.createSdJwtPresentationFrame(elligibleInputDescriptors, wvc.credential, vcIndex);
Expand All @@ -100,7 +119,7 @@ export class LimitDisclosureEvaluationHandler extends AbstractEvaluationHandler
* remain untouched and the verifiable credential won't be submitted.
*/
if (internalCredentialToSend) {
wvc.credential = internalCredentialToSend
wvc.credential = internalCredentialToSend;
for (const { inputDescriptorIndex, inputDescriptor } of elligibleInputDescriptors) {
this.createSuccessResult(inputDescriptorIndex, `$[${vcIndex}]`, inputDescriptor.constraints?.limit_disclosure);
}
Expand Down Expand Up @@ -139,7 +158,11 @@ export class LimitDisclosureEvaluationHandler extends AbstractEvaluationHandler
return presentationFrame;
}

private createVcWithRequiredFields(inputDescriptors: InputDescriptorWithIndex[], vc: IVerifiableCredential, vcIndex: number): IVerifiableCredential | undefined {
private createVcWithRequiredFields(
inputDescriptors: InputDescriptorWithIndex[],
vc: IVerifiableCredential,
vcIndex: number,
): IVerifiableCredential | undefined {
let credentialToSend: IVerifiableCredential = {} as IVerifiableCredential;
credentialToSend = Object.assign(credentialToSend, vc);
credentialToSend.credentialSubject = {};
Expand Down Expand Up @@ -202,12 +225,14 @@ export class LimitDisclosureEvaluationHandler extends AbstractEvaluationHandler
}

private createLimitDisclosureNotSupportedResult(idIdxs: number[], vcIdx: number, reason?: string) {
return this.getResults().push(...idIdxs.map((idIdx) => ({
input_descriptor_path: `$.input_descriptors[${idIdx}]`,
verifiable_credential_path: `$[${vcIdx}]`,
evaluator: this.getName(),
status: Status.ERROR,
message: reason ? `${PexMessages.LIMIT_DISCLOSURE_NOT_SUPPORTED}. ${reason}` : PexMessages.LIMIT_DISCLOSURE_NOT_SUPPORTED,
})));
return this.getResults().push(
...idIdxs.map((idIdx) => ({
input_descriptor_path: `$.input_descriptors[${idIdx}]`,
verifiable_credential_path: `$[${vcIdx}]`,
evaluator: this.getName(),
status: Status.ERROR,
message: reason ? `${PexMessages.LIMIT_DISCLOSURE_NOT_SUPPORTED}. ${reason}` : PexMessages.LIMIT_DISCLOSURE_NOT_SUPPORTED,
})),
);
}
}
34 changes: 21 additions & 13 deletions lib/evaluation/handlers/markForSubmissionEvaluationHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,31 @@ import { EvaluationClient } from '../evaluationClient';

import { AbstractEvaluationHandler } from './abstractEvaluationHandler';

export function elligibleInputDescriptorsForWrappedVc(inputDescriptors: Array<InputDescriptorV2 | InputDescriptorV1>, vcIndex: number, results: HandlerCheckResult[]) {
return inputDescriptors.map((inputDescriptor, inputDescriptorIndex) => {
export function elligibleInputDescriptorsForWrappedVc(
inputDescriptors: Array<InputDescriptorV2 | InputDescriptorV1>,
vcIndex: number,
results: HandlerCheckResult[],
) {
return inputDescriptors
.map((inputDescriptor, inputDescriptorIndex) => {
const matchingResults = results.filter(
({ verifiable_credential_path, input_descriptor_path }) =>
verifiable_credential_path === `$[${vcIndex}]` && input_descriptor_path === `$.input_descriptors[${inputDescriptorIndex}]`,
);

const matchingResults = results.filter(({ verifiable_credential_path, input_descriptor_path }) => verifiable_credential_path === `$[${vcIndex}]` && input_descriptor_path === `$.input_descriptors[${inputDescriptorIndex}]`)
const hasError = matchingResults.some((result) => result.status === Status.ERROR);
const hasInfo = matchingResults.some((result) => result.status === Status.INFO);

const hasError = matchingResults.some(result => result.status === Status.ERROR)
const hasInfo = matchingResults.some(result => result.status === Status.INFO)

if (hasInfo && !hasError) {
return {
inputDescriptor,
inputDescriptorIndex
if (hasInfo && !hasError) {
return {
inputDescriptor,
inputDescriptorIndex,
};
}
}

return undefined
}).filter((value): value is Exclude<typeof value, undefined> => value !== undefined)
return undefined;
})
.filter((value): value is Exclude<typeof value, undefined> => value !== undefined);
}

export class MarkForSubmissionEvaluationHandler extends AbstractEvaluationHandler {
Expand Down
4 changes: 2 additions & 2 deletions lib/types/Internal.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
import { IVerifiableCredential, IVerifiablePresentation } from '@sphereon/ssi-types';

export interface InputDescriptorWithIndex {
inputDescriptorIndex: number
inputDescriptor: InputDescriptorV1 | InputDescriptorV2
inputDescriptorIndex: number;
inputDescriptor: InputDescriptorV1 | InputDescriptorV2;
}

export type PathComponent = string | number;
Expand Down
17 changes: 7 additions & 10 deletions test/evaluation/evaluationClientWrapper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { Status } from '../../lib';
import { EvaluationClient, EvaluationClientWrapper } from '../../lib/evaluation';
import { InternalPresentationDefinitionV1, InternalPresentationDefinitionV2 } from '../../lib/types';
import { SSITypesBuilder } from '../../lib/types';
import { hasher } from '../SdJwt.spec';

import { EvaluationClientWrapperData } from './EvaluationClientWrapperData';
import { hasher } from '../SdJwt.spec';

function getFile(path: string) {
return fs.readFileSync(path, 'utf-8');
Expand Down Expand Up @@ -727,29 +727,26 @@ describe('evaluate', () => {
expect(ps.descriptor_map.map((d) => d.path)).toEqual(['$.verifiableCredential[0]', '$.verifiableCredential[0]', '$.verifiableCredential[0]']);
});

it("only applies selective disclosure to a wrapped vc based on the constraints from matching input descriptors", function () {
it('only applies selective disclosure to a wrapped vc based on the constraints from matching input descriptors', function () {
const pdSchema: InternalPresentationDefinitionV2 = getFileAsJson(
'./test/dif_pe_examples/pdV2/pd-multi-sd-jwt-selective-disclosure.json',
).presentation_definition;
const vcs: string[] = getFileAsJson('test/dif_pe_examples/vc/vc-2-sd-jwt.json').vcs;
const pd = SSITypesBuilder.modelEntityInternalPresentationDefinitionV2(pdSchema);
const evaluationClientWrapper: EvaluationClientWrapper = new EvaluationClientWrapper();
const evaluationResults = evaluationClientWrapper.evaluate(
pd,
SSITypesBuilder.mapExternalVerifiableCredentialsToWrappedVcs(vcs, hasher),
);
const evaluationResults = evaluationClientWrapper.evaluate(pd, SSITypesBuilder.mapExternalVerifiableCredentialsToWrappedVcs(vcs, hasher));
expect(evaluationResults).toMatchObject({
verifiableCredential: [
// It should keep two disclsures, but remove one. based on PD requirements.
// First disclosure comes from first input descriptor. Second form the second input descriptor
// the limit discloure logic recognizes that one credential can be used for both input decriptors, and
// the limit discloure logic recognizes that one credential can be used for both input decriptors, and
// applies both input descriptors disclosure fields.
// If you only disclose it for one input descriptor, it does mean you reveal maybe some attributes that
// are not required, but this is the best way i think for now, without overly complicating the API (otherwise
// we need to have a separate disclosure credential per vc<->pd match).
"eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSIsImtpZCI6IiN6Nk1rZmhyQ2QxZmJoSmRlTEh2aTFYblpWUTlaNnBVSmFXbXdmVVNtQUxvMnc0OHcifQ.eyJ0ZXN0RmllbGQiOiJ0ZXN0VmFsdWUiLCJ2Y3QiOiJ0ZXN0LXZjdCIsImNuZiI6eyJraWQiOiJkaWQ6a2V5Ono2TWtlcHY0VXNQalBCNHFxS2Jpc3ZEUTlYdFkzVEIzQ1JiTm9QOXc3bTlSR0o2ZCN6Nk1rZXB2NFVzUGpQQjRxcUtiaXN2RFE5WHRZM1RCM0NSYk5vUDl3N205UkdKNmQifSwiaXNzIjoiZGlkOndlYjoxMjcuMC4wLjE6OTAwMDpwYXJhZHltLXB1YmxpYy1tZXRhZGF0YToyNzMxZWRjMC0yN2JiLTQ1MmYtYWIxZS1kM2I3M2I3YWFkYWMiLCJpYXQiOjE3MjY2NDk1OTEsIl9zZCI6WyI4bmhDRXVHVVNfSlpZY1hPMGY1Yzg4Q0lQdFluWm5vWVlYWVRkQjZGd05JIiwiRURqM1JoU3B0TlNIbEp5ZHJWRDZJeEt0ZG9iMHdUVzRiMnd6UjBjVUlkWSIsImpHSDJFYXl1cmw0bTFTOXNUSFdpWkVRYXpLT01jU1hlN2RtRlBqSnlibFUiXSwiX3NkX2FsZyI6InNoYS0yNTYifQ.F51KfZ6knRgxltGTNyISwyb2vXjV3x90Fp_UV4cJNfg9sDVrASs07f_hv1kbBjQhEEyJIw5rFwyXa958AjnTDA~WyI5MDIzNDA0MDI3NzI4OTU2OTg2NzQ5MDMiLCJjb21wbGlhbnQiLGZhbHNlXQ~WyI1MzYzNjM5MzQ2MDc1MzcyODgzNzU0OSIsIm5vbkNvbXBsaWFudCIsdHJ1ZV0~",
"eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSIsImtpZCI6IiN6Nk1rZmhyQ2QxZmJoSmRlTEh2aTFYblpWUTlaNnBVSmFXbXdmVVNtQUxvMnc0OHcifQ.eyJ2Y3QiOiJ0ZXN0LXZjdC0yIiwiY25mIjp7ImtpZCI6ImRpZDprZXk6ejZNa3ZONkhkNzlxS1dqdDhhcUxQanRHV0JYUlJSeHd5YjM3UDRvWEhUclhrdm5mI3o2TWt2TjZIZDc5cUtXanQ4YXFMUGp0R1dCWFJSUnh3eWIzN1A0b1hIVHJYa3ZuZiJ9LCJpc3MiOiJkaWQ6d2ViOjEyNy4wLjAuMTo5MDAwOnBhcmFkeW0tcHVibGljLW1ldGFkYXRhOjI3MzFlZGMwLTI3YmItNDUyZi1hYjFlLWQzYjczYjdhYWRhYyIsImlhdCI6MTcyNjY0OTU5MSwiX3NkX2FsZyI6InNoYS0yNTYifQ.-zEUcxH73-IcA9QZ71DcryjJ5WAhUarGIg3NjQ097ng0NIdd9V1Z-q_yZr-VVjThMWdu841UKakBuZQVCMTbDw~"
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSIsImtpZCI6IiN6Nk1rZmhyQ2QxZmJoSmRlTEh2aTFYblpWUTlaNnBVSmFXbXdmVVNtQUxvMnc0OHcifQ.eyJ0ZXN0RmllbGQiOiJ0ZXN0VmFsdWUiLCJ2Y3QiOiJ0ZXN0LXZjdCIsImNuZiI6eyJraWQiOiJkaWQ6a2V5Ono2TWtlcHY0VXNQalBCNHFxS2Jpc3ZEUTlYdFkzVEIzQ1JiTm9QOXc3bTlSR0o2ZCN6Nk1rZXB2NFVzUGpQQjRxcUtiaXN2RFE5WHRZM1RCM0NSYk5vUDl3N205UkdKNmQifSwiaXNzIjoiZGlkOndlYjoxMjcuMC4wLjE6OTAwMDpwYXJhZHltLXB1YmxpYy1tZXRhZGF0YToyNzMxZWRjMC0yN2JiLTQ1MmYtYWIxZS1kM2I3M2I3YWFkYWMiLCJpYXQiOjE3MjY2NDk1OTEsIl9zZCI6WyI4bmhDRXVHVVNfSlpZY1hPMGY1Yzg4Q0lQdFluWm5vWVlYWVRkQjZGd05JIiwiRURqM1JoU3B0TlNIbEp5ZHJWRDZJeEt0ZG9iMHdUVzRiMnd6UjBjVUlkWSIsImpHSDJFYXl1cmw0bTFTOXNUSFdpWkVRYXpLT01jU1hlN2RtRlBqSnlibFUiXSwiX3NkX2FsZyI6InNoYS0yNTYifQ.F51KfZ6knRgxltGTNyISwyb2vXjV3x90Fp_UV4cJNfg9sDVrASs07f_hv1kbBjQhEEyJIw5rFwyXa958AjnTDA~WyI5MDIzNDA0MDI3NzI4OTU2OTg2NzQ5MDMiLCJjb21wbGlhbnQiLGZhbHNlXQ~WyI1MzYzNjM5MzQ2MDc1MzcyODgzNzU0OSIsIm5vbkNvbXBsaWFudCIsdHJ1ZV0~',
'eyJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFZERTQSIsImtpZCI6IiN6Nk1rZmhyQ2QxZmJoSmRlTEh2aTFYblpWUTlaNnBVSmFXbXdmVVNtQUxvMnc0OHcifQ.eyJ2Y3QiOiJ0ZXN0LXZjdC0yIiwiY25mIjp7ImtpZCI6ImRpZDprZXk6ejZNa3ZONkhkNzlxS1dqdDhhcUxQanRHV0JYUlJSeHd5YjM3UDRvWEhUclhrdm5mI3o2TWt2TjZIZDc5cUtXanQ4YXFMUGp0R1dCWFJSUnh3eWIzN1A0b1hIVHJYa3ZuZiJ9LCJpc3MiOiJkaWQ6d2ViOjEyNy4wLjAuMTo5MDAwOnBhcmFkeW0tcHVibGljLW1ldGFkYXRhOjI3MzFlZGMwLTI3YmItNDUyZi1hYjFlLWQzYjczYjdhYWRhYyIsImlhdCI6MTcyNjY0OTU5MSwiX3NkX2FsZyI6InNoYS0yNTYifQ.-zEUcxH73-IcA9QZ71DcryjJ5WAhUarGIg3NjQ097ng0NIdd9V1Z-q_yZr-VVjThMWdu841UKakBuZQVCMTbDw~',
],
})
});
});
});

0 comments on commit 9717960

Please sign in to comment.