{"version":3,"file":"MdocDeviceResponse.mjs","names":[],"sources":["../../../src/modules/mdoc/MdocDeviceResponse.ts"],"sourcesContent":["import {\n  CoseKey,\n  DeviceNamespaces,\n  DeviceRequest,\n  DeviceResponse,\n  DeviceSignedItems,\n  DocRequest,\n  Document,\n  defaultVerificationCallback,\n  IssuerNamespaces,\n  ItemsRequest,\n  limitDisclosureToDeviceRequestNameSpaces,\n  type MdocContext,\n  SessionTranscript,\n} from '@owf/mdoc'\nimport type { InputDescriptorV2 } from '@sphereon/pex-models'\nimport {\n  convertDcqlQueryToDeviceRequest,\n  convertPresentationDefinitionToDeviceRequest,\n  type Field,\n  type PresentationDefinition,\n} from '@verifiables/request-converter'\nimport { AgentContext } from '../../agent'\nimport { TypedArrayEncoder } from './../../utils'\nimport { PublicJwk } from '../kms'\nimport { ClaimFormat } from '../vc'\nimport { X509Certificate } from '../x509'\nimport type { Mdoc } from './Mdoc'\nimport { getMdocContext } from './MdocContext'\nimport { MdocError } from './MdocError'\nimport type {\n  MdocDeviceResponseDcqlQueryOptions,\n  MdocDeviceResponseOptions,\n  MdocDeviceResponsePresentationDefinitionOptions,\n  MdocDeviceResponseVerifyOptions,\n  MdocSessionTranscriptOptions,\n} from './MdocOptions'\nimport { isMdocSupportedSignatureAlgorithm, mdocSupportedSignatureAlgorithms } from './mdocSupportedAlgs'\nimport { nameSpacesRecordToMap } from './mdocUtil'\nimport { convertDocumentRequest } from './utils/convertDocumentRequest'\n\nexport type DeviceAndIssuerClaims = {\n  [docType: string]: {\n    [namespace: string]: {\n      [claimIdentifier: string]: unknown\n    }\n  }\n}\n\nexport class MdocDeviceResponse {\n  private constructor(public readonly deviceResponse: DeviceResponse) {}\n\n  /**\n   * claim format is convenience method added to all credential instances\n   */\n  public get claimFormat() {\n    return ClaimFormat.MsoMdoc as const\n  }\n\n  /**\n   * Encoded is convenience method added to all credential instances\n   */\n  public get encoded() {\n    return TypedArrayEncoder.toBase64Url(this.deviceResponse.encode())\n  }\n\n  /**\n   * To support a single DeviceResponse with multiple documents in OpenID4VP\n   */\n  public splitIntoSingleDocumentResponses(): MdocDeviceResponse[] {\n    const deviceResponses: MdocDeviceResponse[] = []\n\n    if (!this.deviceResponse.documents || this.deviceResponse.documents.length === 0) {\n      throw new MdocError('mdoc device response does not contain any mdocs')\n    }\n\n    for (const document of this.deviceResponse.documents) {\n      deviceResponses.push(\n        new MdocDeviceResponse(\n          DeviceResponse.createSimple({\n            version: this.deviceResponse.version,\n            status: this.deviceResponse.status,\n            documentErrors: this.deviceResponse.documentErrors,\n            documents: [document],\n          })\n        )\n      )\n    }\n\n    return deviceResponses\n  }\n\n  public static fromBase64Url(base64Url: string) {\n    const parsed = DeviceResponse.decode(TypedArrayEncoder.fromBase64Url(base64Url))\n\n    return new MdocDeviceResponse(parsed)\n  }\n\n  public static async createDeviceResponseWithPresentationDefinition(\n    agentContext: AgentContext,\n    options: MdocDeviceResponsePresentationDefinitionOptions\n  ) {\n    // @ts-expect-error: we need to match the types credo uses and the converter expects\n    const { deviceRequest } = convertPresentationDefinitionToDeviceRequest(options.presentationDefinition)\n    const documentRequests = convertDocumentRequest(deviceRequest.docRequests)\n\n    return MdocDeviceResponse.createDeviceResponse(agentContext, { ...options, documentRequests })\n  }\n\n  public static async createDeviceResponseWithDcqlQuery(\n    agentContext: AgentContext,\n    options: MdocDeviceResponseDcqlQueryOptions\n  ) {\n    // @ts-expect-error: we need to match the types credo uses and the converter expects\n    const { deviceRequest } = convertDcqlQueryToDeviceRequest(options.dcqlQuery)\n    const documentRequests = convertDocumentRequest(deviceRequest.docRequests)\n\n    return MdocDeviceResponse.createDeviceResponse(agentContext, { ...options, documentRequests })\n  }\n\n  public static async limitDisclosureToInputDescriptor(\n    _agentContext: AgentContext,\n    { mdoc, ...options }: { inputDescriptor: InputDescriptorV2; mdoc: Mdoc }\n  ) {\n    const inputDescriptor = MdocDeviceResponse.assertMdocInputDescriptor(options.inputDescriptor)\n\n    let issuerNamespaces: IssuerNamespaces | undefined\n\n    // First we try with all optional fields enabled, if that results in an error during the `limitDisclosureToDeviceRequestNameSpaces` call, we try again, skipping all optional fields\n    try {\n      // We take the first document request as we also only input a single input descriptor\n      const {\n        deviceRequest: {\n          docRequests: [convertedDocumentRequest],\n        },\n      } = convertPresentationDefinitionToDeviceRequest({\n        id: '<UNUSED_CREDO_ID>',\n        input_descriptors: [inputDescriptor],\n      })\n\n      const documentRequest = DocRequest.create({\n        itemsRequest: ItemsRequest.create({\n          docType: convertedDocumentRequest.itemsRequest.docType,\n          namespaces: convertedDocumentRequest.itemsRequest.nameSpaces,\n        }),\n      })\n\n      issuerNamespaces = limitDisclosureToDeviceRequestNameSpaces(mdoc.issuerSigned, documentRequest)\n    } catch (_error) {\n      // We take the first document request as we also only input a single input descriptor\n      const {\n        deviceRequest: {\n          docRequests: [convertedDocumentRequest],\n        },\n      } = convertPresentationDefinitionToDeviceRequest(\n        {\n          id: '<UNUSED_CREDO_ID>',\n          input_descriptors: [inputDescriptor],\n        },\n        { skipOptionalFields: true }\n      )\n\n      const documentRequest = DocRequest.create({\n        itemsRequest: ItemsRequest.create({\n          docType: convertedDocumentRequest.itemsRequest.docType,\n          namespaces: convertedDocumentRequest.itemsRequest.nameSpaces,\n        }),\n      })\n\n      issuerNamespaces = limitDisclosureToDeviceRequestNameSpaces(mdoc.issuerSigned, documentRequest)\n    }\n\n    const disclosedPayloadAsRecord = Object.fromEntries(\n      Array.from(issuerNamespaces.issuerNamespaces.entries()).map(([namespace, issuerSignedItem]) => [\n        namespace,\n        Object.fromEntries(issuerSignedItem.map((isi) => [isi.elementIdentifier, isi.elementValue])),\n      ])\n    )\n\n    return disclosedPayloadAsRecord\n  }\n\n  private static assertMdocInputDescriptor(inputDescriptor: InputDescriptorV2) {\n    if (!inputDescriptor.format || !inputDescriptor.format.mso_mdoc) {\n      throw new MdocError(`Input descriptor must contain 'mso_mdoc' format property`)\n    }\n\n    if (!inputDescriptor.format.mso_mdoc.alg) {\n      throw new MdocError(`Input descriptor mso_mdoc must contain 'alg' property`)\n    }\n\n    if (!inputDescriptor.constraints?.limit_disclosure || inputDescriptor.constraints.limit_disclosure !== 'required') {\n      throw new MdocError(\n        `Input descriptor must contain 'limit_disclosure' constraints property which is set to required`\n      )\n    }\n\n    if (!inputDescriptor.constraints?.fields?.every((field) => field.intent_to_retain !== undefined)) {\n      throw new MdocError(`Input descriptor must contain 'intent_to_retain' constraints property`)\n    }\n\n    return {\n      ...inputDescriptor,\n      format: {\n        mso_mdoc: inputDescriptor.format.mso_mdoc,\n      },\n      constraints: {\n        ...inputDescriptor.constraints,\n        limit_disclosure: 'required',\n        fields: (inputDescriptor.constraints.fields ?? []).map((field) => {\n          return {\n            ...field,\n            intent_to_retain: field.intent_to_retain ?? false,\n          }\n        }) as Field[],\n      },\n    } satisfies PresentationDefinition['input_descriptors'][number]\n  }\n\n  public static async createDeviceResponse(agentContext: AgentContext, options: MdocDeviceResponseOptions) {\n    const documents: Document[] = []\n\n    for (const document of options.mdocs) {\n      const deviceKeyJwk = document.deviceKey\n      const deviceKeyJwkJson = deviceKeyJwk.toJson()\n\n      if (!deviceKeyJwkJson.alg) {\n        // FIXME: we cannot provide alg anymore?\n        deviceKeyJwkJson.alg = MdocDeviceResponse.getAlgForDeviceKeyJwk(deviceKeyJwk)\n      }\n\n      // Set keyId to legacy key id if it doesn't have a key id set\n      if (!deviceKeyJwk.hasKeyId) {\n        deviceKeyJwk.keyId = deviceKeyJwk.legacyKeyId\n      }\n\n      const deviceRequestForDocument = DeviceRequest.create({\n        version: '1.0',\n        docRequests: options.documentRequests\n          .filter((request) => request.docType === document.docType)\n          .map((request) =>\n            DocRequest.create({\n              itemsRequest: ItemsRequest.create({\n                docType: request.docType,\n                namespaces: nameSpacesRecordToMap(request.nameSpaces),\n              }),\n            })\n          ),\n      })\n\n      const mdocContext = getMdocContext(agentContext)\n      const deviceResponse = await DeviceResponse.createWithDeviceRequest(\n        {\n          deviceRequest: deviceRequestForDocument,\n          issuerSigned: [document.issuerSigned],\n          sessionTranscript: await MdocDeviceResponse.calculateSessionTranscriptBytes(\n            mdocContext,\n            options.sessionTranscriptOptions\n          ),\n          deviceNamespaces: options.deviceNameSpaces\n            ? DeviceNamespaces.create({\n                deviceNamespaces: new Map(\n                  Object.entries(options.deviceNameSpaces).map(([namespace, namespaceValue]) => [\n                    namespace,\n                    DeviceSignedItems.create({\n                      deviceSignedItems: new Map(Object.entries(namespaceValue)),\n                    }),\n                  ])\n                ),\n              })\n            : undefined,\n          signature: {\n            signingKey: CoseKey.fromJwk(deviceKeyJwk.toJson()),\n          },\n        },\n        mdocContext\n      )\n\n      if (!deviceResponse.documents) {\n        throw new MdocError('Device response does not contain any documents')\n      }\n      documents.push(deviceResponse.documents[0])\n    }\n\n    return new MdocDeviceResponse(\n      DeviceResponse.createSimple({\n        version: '1.0',\n        documents,\n      })\n    )\n  }\n\n  public async verify(agentContext: AgentContext, options: Omit<MdocDeviceResponseVerifyOptions, 'deviceResponse'>) {\n    const mdocContext = getMdocContext(agentContext)\n\n    defaultVerificationCallback({\n      status: this.deviceResponse.documents?.length ? 'PASSED' : 'FAILED',\n      check: 'Device Response must include at least one document.',\n      category: 'DOCUMENT_FORMAT',\n    })\n\n    await this.deviceResponse\n      .verify(\n        {\n          trustedCertificates:\n            options.trustedCertificates?.map(\n              (certificate) => X509Certificate.fromEncodedCertificate(certificate).rawCertificate\n            ) ?? [],\n          disableCertificateChainValidation: false,\n          now: options.now,\n          skewSeconds: agentContext.config.validitySkewSeconds,\n          sessionTranscript: await MdocDeviceResponse.calculateSessionTranscriptBytes(\n            mdocContext,\n            options.sessionTranscriptOptions\n          ),\n        },\n        mdocContext\n      )\n      .catch((error) => {\n        throw new MdocError(`Mdoc with doctype ${this.deviceResponse.documents?.[0].docType} is not valid`, {\n          cause: error,\n        })\n      })\n  }\n\n  private static async calculateSessionTranscriptBytes(\n    mdocContext: MdocContext,\n    options: MdocSessionTranscriptOptions\n  ) {\n    if (options.type === 'sesionTranscriptBytes') {\n      return options.sessionTranscriptBytes\n    }\n\n    if (options.type === 'openId4VpDraft18') {\n      return SessionTranscript.forOid4VpDraft18(options, mdocContext)\n    }\n\n    if (options.type === 'openId4Vp') {\n      const { encryptionJwk, verifierGeneratedNonce, ...rest } = options\n      return SessionTranscript.forOid4Vp(\n        {\n          ...rest,\n          jwkThumbprint: encryptionJwk ? encryptionJwk.getJwkThumbprint() : undefined,\n          nonce: verifierGeneratedNonce,\n        },\n        mdocContext\n      )\n    }\n\n    if (options.type === 'openId4VpDcApi') {\n      const { encryptionJwk, verifierGeneratedNonce, ...rest } = options\n      return SessionTranscript.forOid4VpDcApi(\n        {\n          ...rest,\n          nonce: verifierGeneratedNonce,\n          jwkThumbprint: encryptionJwk ? encryptionJwk.getJwkThumbprint() : undefined,\n        },\n        mdocContext\n      )\n    }\n\n    if (options.type === 'openId4VpDcApiDraft24') {\n      const { verifierGeneratedNonce, ...rest } = options\n\n      return SessionTranscript.forOid4VpDcApiDraft24(\n        {\n          ...rest,\n          nonce: verifierGeneratedNonce,\n        },\n        mdocContext\n      )\n    }\n\n    throw new MdocError('Unsupported session transcript option')\n  }\n\n  private static getAlgForDeviceKeyJwk(jwk: PublicJwk) {\n    const signatureAlgorithm = jwk.supportedSignatureAlgorithms.find(isMdocSupportedSignatureAlgorithm)\n    if (!signatureAlgorithm) {\n      throw new MdocError(\n        `Unable to create mdoc device response. No supported signature algorithm found to sign device response for jwk  ${\n          jwk.jwkTypeHumanDescription\n        }. Key supports algs ${jwk.supportedSignatureAlgorithms.join(\n          ', '\n        )}. mdoc supports algs ${mdocSupportedSignatureAlgorithms.join(', ')}`\n      )\n    }\n\n    return signatureAlgorithm\n  }\n\n  public get issuerClaims(): DeviceAndIssuerClaims {\n    if (!this.deviceResponse.documents) return {}\n\n    return this.deviceResponse.documents.reduce(\n      (prev, document) => ({\n        // biome-ignore lint/performance/noAccumulatingSpread: time complexity is not relevant here\n        ...prev,\n        [document.docType]: Object.fromEntries(\n          Array.from(document.issuerSigned.issuerNamespaces.issuerNamespaces.entries()).map(([namespace, claim]) => [\n            namespace,\n            Object.fromEntries(claim.map((c) => [c.elementIdentifier, c.elementValue])),\n          ])\n        ),\n      }),\n      {}\n    )\n  }\n\n  public get deviceClaims(): DeviceAndIssuerClaims {\n    if (!this.deviceResponse.documents) return {}\n\n    return this.deviceResponse.documents.reduce(\n      (prev, document) => ({\n        // biome-ignore lint/performance/noAccumulatingSpread: time complexity is not relevant here\n        ...prev,\n        [document.docType]: Object.fromEntries(\n          Array.from(document.deviceSigned.deviceNamespaces.deviceNamespaces.entries()).map(([namespace, claim]) => [\n            namespace,\n            Object.fromEntries(claim.deviceSignedItems),\n          ])\n        ),\n      }),\n      {}\n    )\n  }\n}\n"],"mappings":"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"}