{"version":3,"file":"credentialSelection.mjs","names":[],"sources":["../../../../src/modules/dif-presentation-exchange/utils/credentialSelection.ts"],"sourcesContent":["import {\n  type IPresentationDefinition,\n  type PEX,\n  type SelectResults,\n  Status,\n  type SubmissionRequirementMatch,\n} from '@animo-id/pex'\nimport type {\n  SubmissionRequirementMatchFrom,\n  SubmissionRequirementMatchInputDescriptor,\n} from '@animo-id/pex/dist/main/lib/evaluation/core'\nimport { SubmissionRequirementMatchType } from '@animo-id/pex/dist/main/lib/evaluation/core/index.js'\nimport { JSONPath } from '@astronautlabs/jsonpath'\nimport { decodeSdJwtSync, getClaimsSync } from '@sd-jwt/core'\nimport type { InputDescriptorV1, InputDescriptorV2, SubmissionRequirement } from '@sphereon/pex-models'\nimport { Rules } from '@sphereon/pex-models'\nimport type { AgentContext } from '../../../agent'\nimport { Hasher } from '../../../crypto'\nimport { CredoError } from '../../../error'\nimport type { JsonObject } from '../../../types'\nimport { MdocRecord } from '../../mdoc'\nimport { MdocDeviceResponse } from '../../mdoc/MdocDeviceResponse'\nimport { SdJwtVcRecord } from '../../sd-jwt-vc'\nimport { ClaimFormat, W3cCredentialRecord } from '../../vc'\nimport { DifPresentationExchangeError } from '../DifPresentationExchangeError'\nimport type {\n  DifPexCredentialsForRequest,\n  DifPexCredentialsForRequestRequirement,\n  DifPexCredentialsForRequestSubmissionEntry,\n  SubmissionEntryCredential,\n} from '../models'\nimport { getSphereonOriginalVerifiableCredential } from './transform'\n\nexport async function getCredentialsForRequest(\n  agentContext: AgentContext,\n  // PEX instance with hasher defined\n  pex: PEX,\n  presentationDefinition: IPresentationDefinition,\n  credentialRecords: Array<W3cCredentialRecord | SdJwtVcRecord | MdocRecord>\n): Promise<DifPexCredentialsForRequest> {\n  const encodedCredentials = credentialRecords.map(getSphereonOriginalVerifiableCredential)\n  const selectResultsRaw = pex.selectFrom(presentationDefinition, encodedCredentials)\n\n  const selectResults: CredentialRecordSelectResults = {\n    ...selectResultsRaw,\n    matches: selectResultsRaw.matches ?? [],\n    // Map the encoded credential to their respective credential record\n    verifiableCredential:\n      selectResultsRaw.verifiableCredential?.map((selectedEncoded, index): SubmissionEntryCredential => {\n        const credentialRecordIndex = selectResultsRaw.vcIndexes?.[index]\n        if (credentialRecordIndex === undefined || credentialRecordIndex === -1) {\n          throw new DifPresentationExchangeError('Unable to find credential in credential records.')\n        }\n        const credentialRecord = credentialRecords[credentialRecordIndex]\n        if (credentialRecord instanceof SdJwtVcRecord) {\n          // selectedEncoded always string when SdJwtVcRecord\n          // Get the decoded payload from the the selected credential, this already has SD applied\n          const { jwt, disclosures } = decodeSdJwtSync(selectedEncoded as string, Hasher.hash)\n          const prettyClaims = getClaimsSync(jwt.payload, disclosures, Hasher.hash)\n\n          return {\n            claimFormat: ClaimFormat.SdJwtDc,\n            credentialRecord,\n            disclosedPayload: prettyClaims as JsonObject,\n          }\n        }\n        if (credentialRecord instanceof MdocRecord) {\n          return {\n            claimFormat: ClaimFormat.MsoMdoc,\n            credentialRecord,\n            disclosedPayload: {},\n          }\n        }\n        if (credentialRecord instanceof W3cCredentialRecord) {\n          return {\n            claimFormat: credentialRecord.firstCredential.claimFormat,\n            credentialRecord,\n          }\n        }\n        throw new CredoError('Unrecognized credential record type')\n      }) ?? [],\n  }\n\n  const presentationSubmission: DifPexCredentialsForRequest = {\n    requirements: [],\n    areRequirementsSatisfied: false,\n    name: presentationDefinition.name,\n    purpose: presentationDefinition.purpose,\n  }\n\n  // If there's no submission requirements, ALL input descriptors MUST be satisfied\n  if (!presentationDefinition.submission_requirements || presentationDefinition.submission_requirements.length === 0) {\n    presentationSubmission.requirements = getSubmissionRequirementsForAllInputDescriptors(\n      presentationDefinition.input_descriptors,\n      selectResults\n    )\n  } else {\n    presentationSubmission.requirements = getSubmissionRequirements(presentationDefinition, selectResults)\n  }\n\n  const allEntries = presentationSubmission.requirements.flatMap((requirement) => requirement.submissionEntry)\n\n  const inputDescriptorsForMdocCredential = new Map<SubmissionEntryCredential, Set<string>>()\n  for (const entry of allEntries)\n    for (const verifiableCredential of entry.verifiableCredentials) {\n      if (verifiableCredential.claimFormat !== ClaimFormat.MsoMdoc) continue\n\n      const set = inputDescriptorsForMdocCredential.get(verifiableCredential) ?? new Set()\n      set.add(entry.inputDescriptorId)\n      inputDescriptorsForMdocCredential.set(verifiableCredential, set)\n    }\n\n  // NOTE: it might be better to apply disclosure per credential/match (as that's also how mdoc does this)\n  // however this doesn't work very well in wallets, as you usually won't show the same credential twice with\n  // different disclosed attributes\n  // Apply limit disclosure for all mdocs\n  for (const [verifiableCredential, inputDescriptorIds] of inputDescriptorsForMdocCredential.entries()) {\n    if (verifiableCredential.claimFormat !== ClaimFormat.MsoMdoc) continue\n\n    const inputDescriptorsForCredential = presentationDefinition.input_descriptors.filter(({ id }) =>\n      inputDescriptorIds.has(id)\n    )\n\n    const mdoc = verifiableCredential.credentialRecord.firstCredential\n    verifiableCredential.disclosedPayload = await MdocDeviceResponse.limitDisclosureToInputDescriptor(agentContext, {\n      inputDescriptor: {\n        id: mdoc.docType,\n        format: {\n          mso_mdoc: {\n            alg: [],\n          },\n        },\n        constraints: {\n          limit_disclosure: 'required',\n          fields: inputDescriptorsForCredential.flatMap((i) => i.constraints?.fields ?? []),\n        },\n      },\n      mdoc,\n    })\n  }\n\n  // There may be no requirements if we filter out all optional ones. To not makes things too complicated, we see it as an error\n  // for now if a request is made that has no required requirements (but only e.g. min: 0, which means we don't need to disclose anything)\n  // I see this more as the fault of the presentation definition, as it should have at least some requirements.\n  if (presentationSubmission.requirements.length === 0) {\n    throw new DifPresentationExchangeError(\n      'Presentation Definition does not require any credentials. Optional credentials are not included in the presentation submission.'\n    )\n  }\n\n  if (selectResults.areRequiredCredentialsPresent === Status.ERROR) {\n    return presentationSubmission\n  }\n\n  return {\n    ...presentationSubmission,\n\n    // If all requirements are satisfied, the presentation submission is satisfied\n    areRequirementsSatisfied: presentationSubmission.requirements.every(\n      (requirement) => requirement.isRequirementSatisfied\n    ),\n  }\n}\n\nfunction getSubmissionRequirements(\n  presentationDefinition: IPresentationDefinition,\n  selectResults: CredentialRecordSelectResults\n): Array<DifPexCredentialsForRequestRequirement> {\n  const submissionRequirements: Array<DifPexCredentialsForRequestRequirement> = []\n\n  const matches = selectResults.matches as SubmissionRequirementMatchFrom[]\n  if (!matches.every((match) => match.type === SubmissionRequirementMatchType.SubmissionRequirement && match.from)) {\n    throw new DifPresentationExchangeError(\n      `Expected all matches to be of type '${SubmissionRequirementMatchType.SubmissionRequirement}' with 'from' key.`\n    )\n  }\n\n  // There are submission requirements, so we need to select the input_descriptors\n  // based on the submission requirements\n  presentationDefinition.submission_requirements?.forEach((submissionRequirement, submissionRequirementIndex) => {\n    // Check: if the submissionRequirement uses `from_nested`, as we don't support this yet\n    if (submissionRequirement.from_nested) {\n      throw new DifPresentationExchangeError(\n        \"Presentation definition contains requirement using 'from_nested', which is not supported yet.\"\n      )\n    }\n\n    // Check if there's a 'from'. If not the structure is not as we expect it\n    if (!submissionRequirement.from) {\n      throw new DifPresentationExchangeError(\"Missing 'from' in submission requirement match\")\n    }\n\n    const match = matches.find((match) => match.id === submissionRequirementIndex)\n    if (!match) {\n      throw new Error(`Unable to find a match for submission requirement with index '${submissionRequirementIndex}'`)\n    }\n\n    if (submissionRequirement.rule === Rules.All) {\n      const selectedSubmission = getSubmissionRequirementRuleAll(\n        submissionRequirement,\n        presentationDefinition,\n        selectResults.verifiableCredential,\n        match\n      )\n      submissionRequirements.push(selectedSubmission)\n    } else {\n      const selectedSubmission = getSubmissionRequirementRulePick(\n        submissionRequirement,\n        presentationDefinition,\n        selectResults.verifiableCredential,\n        match\n      )\n\n      submissionRequirements.push(selectedSubmission)\n    }\n  })\n\n  // Submission may have requirement that doesn't require a credential to be submitted (e.g. min: 0)\n  // We use minimization strategy, and thus only disclose the minimum amount of information\n  const requirementsWithCredentials = submissionRequirements.filter((requirement) => requirement.needsCount > 0)\n\n  return requirementsWithCredentials\n}\n\nfunction getSubmissionRequirementsForAllInputDescriptors(\n  inputDescriptors: Array<InputDescriptorV1> | Array<InputDescriptorV2>,\n  selectResults: CredentialRecordSelectResults\n): Array<DifPexCredentialsForRequestRequirement> {\n  const submissionRequirements: Array<DifPexCredentialsForRequestRequirement> = []\n\n  const matches = selectResults.matches as SubmissionRequirementMatchInputDescriptor[]\n  if (!matches.every((match) => match.type === SubmissionRequirementMatchType.InputDescriptor)) {\n    throw new DifPresentationExchangeError(\n      `Expected all matches to be of type '${SubmissionRequirementMatchType.InputDescriptor}' when.`\n    )\n  }\n\n  for (const inputDescriptor of inputDescriptors) {\n    const submission = getSubmissionForInputDescriptor(inputDescriptor, selectResults.verifiableCredential, matches)\n    submissionRequirements.push({\n      rule: Rules.Pick,\n      needsCount: 1, // Every input descriptor is a distinct requirement, so the count is always 1,\n      submissionEntry: [submission],\n      isRequirementSatisfied: submission.verifiableCredentials.length >= 1,\n    })\n  }\n\n  return submissionRequirements\n}\n\nfunction getSubmissionRequirementRuleAll(\n  submissionRequirement: SubmissionRequirement,\n  presentationDefinition: IPresentationDefinition,\n  verifiableCredentials: SubmissionEntryCredential[],\n  match: SubmissionRequirementMatchFrom\n) {\n  // Check if there's a 'from'. If not the structure is not as we expect it\n  if (!submissionRequirement.from)\n    throw new DifPresentationExchangeError(\"Missing 'from' in submission requirement match.\")\n\n  const selectedSubmission: DifPexCredentialsForRequestRequirement = {\n    rule: Rules.All,\n    needsCount: 0,\n    name: submissionRequirement.name,\n    purpose: submissionRequirement.purpose,\n    submissionEntry: [],\n    isRequirementSatisfied: false,\n  }\n\n  for (const inputDescriptor of presentationDefinition.input_descriptors) {\n    // We only want to get the submission if the input descriptor belongs to the group\n    if (!inputDescriptor.group?.includes(match.from)) continue\n\n    const submission = getSubmissionForInputDescriptor(inputDescriptor, verifiableCredentials, match.input_descriptors)\n\n    // Rule ALL, so for every input descriptor that matches in this group, we need to add it\n    selectedSubmission.needsCount += 1\n    selectedSubmission.submissionEntry.push(submission)\n  }\n\n  return {\n    ...selectedSubmission,\n\n    // If all submissions have a credential, the requirement is satisfied\n    isRequirementSatisfied: selectedSubmission.submissionEntry.every(\n      (submission) => submission.verifiableCredentials.length >= 1\n    ),\n  }\n}\n\nfunction getSubmissionRequirementRulePick(\n  submissionRequirement: SubmissionRequirement,\n  presentationDefinition: IPresentationDefinition,\n  verifiableCredentials: SubmissionEntryCredential[],\n  match: SubmissionRequirementMatchFrom\n) {\n  // Check if there's a 'from'. If not the structure is not as we expect it\n  if (!submissionRequirement.from) {\n    throw new DifPresentationExchangeError(\"Missing 'from' in submission requirement match.\")\n  }\n\n  const selectedSubmission: DifPexCredentialsForRequestRequirement = {\n    rule: Rules.Pick,\n    needsCount: submissionRequirement.count ?? submissionRequirement.min ?? 1,\n    name: submissionRequirement.name,\n    purpose: submissionRequirement.purpose,\n    // If there's no count, min, or max we assume one credential is required for submission\n    // however, the exact behavior is not specified in the spec\n    submissionEntry: [],\n    isRequirementSatisfied: false,\n  }\n\n  const satisfiedSubmissions: Array<DifPexCredentialsForRequestSubmissionEntry> = []\n  const unsatisfiedSubmissions: Array<DifPexCredentialsForRequestSubmissionEntry> = []\n\n  for (const inputDescriptor of presentationDefinition.input_descriptors) {\n    // We only want to get the submission if the input descriptor belongs to the group\n    if (!inputDescriptor.group?.includes(match.from)) continue\n\n    const submission = getSubmissionForInputDescriptor(inputDescriptor, verifiableCredentials, match.input_descriptors)\n\n    if (submission.verifiableCredentials.length >= 1) {\n      satisfiedSubmissions.push(submission)\n    } else {\n      unsatisfiedSubmissions.push(submission)\n    }\n\n    // If we have found enough credentials to satisfy the requirement, we could stop\n    // but the user may not want the first x that match, so we continue and return all matches\n    // if (satisfiedSubmissions.length === selectedSubmission.needsCount) break\n  }\n\n  return {\n    ...selectedSubmission,\n\n    // If there are enough satisfied submissions, the requirement is satisfied\n    isRequirementSatisfied: satisfiedSubmissions.length >= selectedSubmission.needsCount,\n\n    // if the requirement is satisfied, we only need to return the satisfied submissions\n    // however if the requirement is not satisfied, we include all entries so the wallet could\n    // render which credentials are missing.\n    submissionEntry:\n      satisfiedSubmissions.length >= selectedSubmission.needsCount\n        ? satisfiedSubmissions\n        : [...satisfiedSubmissions, ...unsatisfiedSubmissions],\n  }\n}\n\nfunction getSubmissionForInputDescriptor(\n  inputDescriptor: InputDescriptorV1 | InputDescriptorV2,\n  verifiableCredentials: SubmissionEntryCredential[],\n  matches: SubmissionRequirementMatchInputDescriptor[]\n): DifPexCredentialsForRequestSubmissionEntry {\n  const matchesForInputDescriptor = matches.filter((m) => m.id === inputDescriptor.id)\n\n  const submissionEntry: DifPexCredentialsForRequestSubmissionEntry = {\n    inputDescriptorId: inputDescriptor.id,\n    name: inputDescriptor.name,\n    purpose: inputDescriptor.purpose,\n    verifiableCredentials: matchesForInputDescriptor.flatMap((matchForInputDescriptor) =>\n      extractCredentialsFromInputDescriptorMatch(matchForInputDescriptor, verifiableCredentials)\n    ),\n  }\n\n  // return early if no matches.\n  if (!matchesForInputDescriptor?.length) return submissionEntry\n\n  return submissionEntry\n}\n\nfunction extractCredentialsFromInputDescriptorMatch(\n  match: SubmissionRequirementMatchInputDescriptor,\n  availableCredentials: SubmissionEntryCredential[]\n) {\n  const verifiableCredentials: SubmissionEntryCredential[] = []\n\n  for (const vcPath of match.vc_path) {\n    const [verifiableCredential] = JSONPath.query(\n      { verifiableCredential: availableCredentials },\n      vcPath\n    ) as SubmissionEntryCredential[]\n    verifiableCredentials.push(verifiableCredential)\n  }\n\n  return verifiableCredentials\n}\n\n/**\n * Custom SelectResults that includes the Credo records instead of the encoded verifiable credential\n */\ntype CredentialRecordSelectResults = Omit<SelectResults, 'verifiableCredential'> & {\n  verifiableCredential: SubmissionEntryCredential[]\n  matches: SubmissionRequirementMatch[]\n}\n"],"mappings":"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"}