{"version":3,"file":"DidDocument.mjs","names":[],"sources":["../../../../src/modules/dids/domain/DidDocument.ts"],"sourcesContent":["import { Expose, Type } from 'class-transformer'\nimport { IsArray, IsOptional, IsString, ValidateNested } from 'class-validator'\nimport { CredoError } from '../../../error'\nimport { TypedArrayEncoder } from '../../../utils'\nimport { JsonTransformer } from '../../../utils/JsonTransformer'\nimport { IsStringOrStringArray } from '../../../utils/transformers'\nimport { Ed25519PublicJwk, PublicJwk, X25519PublicJwk } from '../../kms'\nimport { findMatchingEd25519Key } from '../findMatchingEd25519Key'\nimport { getPublicJwkFromVerificationMethod } from './key-type'\nimport type { DidDocumentService } from './service'\nimport { DidCommV1Service, IndyAgentService } from './service'\nimport { ServiceTransformer } from './service/ServiceTransformer'\nimport { IsStringOrVerificationMethod, VerificationMethod, VerificationMethodTransformer } from './verificationMethod'\n\nexport type DidPurpose =\n  | 'authentication'\n  | 'keyAgreement'\n  | 'assertionMethod'\n  | 'capabilityInvocation'\n  | 'capabilityDelegation'\n\ntype DidVerificationMethods = DidPurpose | 'verificationMethod'\n\ninterface DidDocumentOptions {\n  context?: string | string[]\n  id: string\n  alsoKnownAs?: string[]\n  controller?: string | string[]\n  verificationMethod?: VerificationMethod[]\n  service?: DidDocumentService[]\n  authentication?: Array<string | VerificationMethod>\n  assertionMethod?: Array<string | VerificationMethod>\n  keyAgreement?: Array<string | VerificationMethod>\n  capabilityInvocation?: Array<string | VerificationMethod>\n  capabilityDelegation?: Array<string | VerificationMethod>\n}\n\nexport class DidDocument {\n  @Expose({ name: '@context' })\n  @IsStringOrStringArray()\n  public context: string | string[] = ['https://www.w3.org/ns/did/v1']\n\n  @IsString()\n  public id!: string\n\n  @IsArray()\n  @IsString({ each: true })\n  @IsOptional()\n  public alsoKnownAs?: string[]\n\n  @IsStringOrStringArray()\n  @IsOptional()\n  public controller?: string | string[]\n\n  @IsArray()\n  @ValidateNested({ each: true })\n  @Type(() => VerificationMethod)\n  @IsOptional()\n  public verificationMethod?: VerificationMethod[]\n\n  @IsArray()\n  @ServiceTransformer()\n  @IsOptional()\n  public service?: DidDocumentService[]\n\n  @IsArray()\n  @VerificationMethodTransformer()\n  @IsStringOrVerificationMethod({ each: true })\n  @IsOptional()\n  public authentication?: Array<string | VerificationMethod>\n\n  @IsArray()\n  @VerificationMethodTransformer()\n  @IsStringOrVerificationMethod({ each: true })\n  @IsOptional()\n  public assertionMethod?: Array<string | VerificationMethod>\n\n  @IsArray()\n  @VerificationMethodTransformer()\n  @IsStringOrVerificationMethod({ each: true })\n  @IsOptional()\n  public keyAgreement?: Array<string | VerificationMethod>\n\n  @IsArray()\n  @VerificationMethodTransformer()\n  @IsStringOrVerificationMethod({ each: true })\n  @IsOptional()\n  public capabilityInvocation?: Array<string | VerificationMethod>\n\n  @IsArray()\n  @VerificationMethodTransformer()\n  @IsStringOrVerificationMethod({ each: true })\n  @IsOptional()\n  public capabilityDelegation?: Array<string | VerificationMethod>\n\n  public constructor(options: DidDocumentOptions) {\n    if (options) {\n      this.context = options.context ?? this.context\n      this.id = options.id\n      this.alsoKnownAs = options.alsoKnownAs\n      this.controller = options.controller\n      this.verificationMethod = options.verificationMethod\n      this.service = options.service\n      this.authentication = options.authentication\n      this.assertionMethod = options.assertionMethod\n      this.keyAgreement = options.keyAgreement\n      this.capabilityInvocation = options.capabilityInvocation\n      this.capabilityDelegation = options.capabilityDelegation\n    }\n  }\n\n  public dereferenceVerificationMethod(keyId: string) {\n    // TODO: once we use JSON-LD we should use that to resolve references in did documents.\n    // for now we check whether the key id ends with the keyId.\n    // so if looking for #123 and key.id is did:key:123#123, it is valid. But #123 as key.id is also valid\n    const verificationMethod = this.verificationMethod?.find((key) => this.matchKeyId(keyId, key.id))\n\n    if (!verificationMethod) {\n      throw new CredoError(`Unable to locate verification method with id '${keyId}'`)\n    }\n\n    return verificationMethod\n  }\n\n  public dereferenceKey(keyId: string, allowedPurposes?: DidVerificationMethods[]) {\n    const allPurposes: DidVerificationMethods[] = [\n      'authentication',\n      'keyAgreement',\n      'assertionMethod',\n      'capabilityInvocation',\n      'capabilityDelegation',\n      'verificationMethod',\n    ]\n\n    const purposes = allowedPurposes ?? allPurposes\n\n    for (const purpose of purposes) {\n      for (const key of this[purpose] ?? []) {\n        if (typeof key === 'string' && this.matchKeyId(keyId, key)) {\n          return this.dereferenceVerificationMethod(key)\n        }\n        if (typeof key !== 'string' && this.matchKeyId(keyId, key.id)) {\n          return key\n        }\n      }\n    }\n\n    throw new CredoError(`Unable to locate verification method with id '${keyId}' in purposes ${purposes}`)\n  }\n\n  private matchKeyId(externalKeyId: string, didDocumentKeyId: string) {\n    // Compact is did removed from start but only if it matches the id of this document.\n    const compactExternalKeyId = externalKeyId.startsWith(this.id) ? externalKeyId.slice(this.id.length) : externalKeyId\n    const compactDidDocumentKeyId = didDocumentKeyId.startsWith(this.id)\n      ? didDocumentKeyId.slice(this.id.length)\n      : didDocumentKeyId\n\n    return compactExternalKeyId === compactDidDocumentKeyId\n  }\n\n  public findVerificationMethodByPublicKey(publicJwk: PublicJwk, allowedPurposes?: DidVerificationMethods[]) {\n    const allPurposes: DidVerificationMethods[] = [\n      'authentication',\n      'keyAgreement',\n      'assertionMethod',\n      'capabilityInvocation',\n      'capabilityDelegation',\n      'verificationMethod',\n    ]\n\n    const purposes = allowedPurposes ?? allPurposes\n\n    for (const purpose of purposes) {\n      for (const key of this[purpose] ?? []) {\n        const verificationMethod = typeof key === 'string' ? this.dereferenceVerificationMethod(key) : key\n        if (getPublicJwkFromVerificationMethod(verificationMethod).equals(publicJwk)) return verificationMethod\n      }\n    }\n\n    throw new CredoError(\n      `Unable to locate verification method with public key ${publicJwk.jwkTypeHumanDescription} in purposes ${purposes}`\n    )\n  }\n\n  /**\n   * Returns all of the service endpoints matching the given type.\n   *\n   * @param type The type of service(s) to query.\n   */\n  public getServicesByType<S extends DidDocumentService = DidDocumentService>(type: string): S[] {\n    return (this.service?.filter((service) => service.type === type) ?? []) as S[]\n  }\n\n  /**\n   * Returns all of the service endpoints matching the given class\n   *\n   * @param classType The class to query services.\n   */\n  public getServicesByClassType<S extends DidDocumentService = DidDocumentService>(\n    classType: new (...args: never[]) => S\n  ): S[] {\n    return (this.service?.filter((service) => service instanceof classType) ?? []) as S[]\n  }\n\n  /**\n   * Get all DIDComm services ordered by priority descending. This means the highest\n   * priority will be the first entry.\n   */\n  public get didCommServices(): Array<IndyAgentService | DidCommV1Service> {\n    const didCommServiceTypes = [IndyAgentService.type, DidCommV1Service.type]\n    const services = (this.service?.filter((service) => didCommServiceTypes.includes(service.type)) ?? []) as Array<\n      IndyAgentService | DidCommV1Service\n    >\n\n    // Sort services based on indicated priority\n    return services.sort((a, b) => a.priority - b.priority)\n  }\n\n  // TODO: it would probably be easier if we add a utility to each service so we don't have to handle logic for all service types here\n  public get recipientKeys(): PublicJwk<Ed25519PublicJwk | X25519PublicJwk>[] {\n    return this.getRecipientKeysWithVerificationMethod({\n      // False for now to avoid breaking changes\n      mapX25519ToEd25519: false,\n    }).map(({ publicJwk }) => publicJwk)\n  }\n\n  /**\n   * Returns the recipient keys with their verification method matches\n   *\n   * We should probably deprecate recipientKeys in favour of this one\n   */\n  public getRecipientKeysWithVerificationMethod<MapX25519ToEd25519 extends boolean>({\n    mapX25519ToEd25519,\n  }: {\n    mapX25519ToEd25519: MapX25519ToEd25519\n  }): Array<{\n    verificationMethod: VerificationMethod\n    publicJwk: PublicJwk<MapX25519ToEd25519 extends true ? Ed25519PublicJwk : Ed25519PublicJwk | X25519PublicJwk>\n  }> {\n    const recipientKeys: Array<{\n      verificationMethod: VerificationMethod\n      publicJwk: PublicJwk<Ed25519PublicJwk | X25519PublicJwk>\n    }> = []\n\n    const seenVerificationMethodIds: string[] = []\n    for (const service of this.didCommServices) {\n      if (service.type === IndyAgentService.type) {\n        for (const publicKeyBase58 of service.recipientKeys) {\n          const publicJwk = PublicJwk.fromPublicKey({\n            kty: 'OKP',\n            crv: 'Ed25519',\n            publicKey: TypedArrayEncoder.fromBase58(publicKeyBase58),\n          })\n          const verificationMethod = [...(this.verificationMethod ?? []), ...(this.authentication ?? [])]\n            .map((v) => (typeof v === 'string' ? this.dereferenceVerificationMethod(v) : v))\n            .find((v) => {\n              const vPublicJwk = getPublicJwkFromVerificationMethod(v)\n              return vPublicJwk.equals(publicJwk)\n            })\n\n          if (!verificationMethod) {\n            throw new CredoError('Could not find verification method for IndyAgentService recipient key')\n          }\n\n          // Skip adding if already present\n          if (seenVerificationMethodIds.includes(verificationMethod.id)) {\n            continue\n          }\n\n          recipientKeys.push({\n            publicJwk,\n            verificationMethod,\n          })\n        }\n      } else if (service.type === DidCommV1Service.type) {\n        for (const recipientKey of service.recipientKeys) {\n          const verificationMethod = this.dereferenceKey(recipientKey, ['authentication', 'keyAgreement'])\n          if (seenVerificationMethodIds.includes(verificationMethod.id)) {\n            // Skip adding if already present\n            continue\n          }\n\n          const publicJwk = getPublicJwkFromVerificationMethod(verificationMethod)\n\n          if (!publicJwk.is(Ed25519PublicJwk, X25519PublicJwk)) {\n            throw new CredoError(\n              'Expected either Ed25519PublicJwk or X25519PublicJwk for DidcommV1Service recipient key'\n            )\n          }\n\n          recipientKeys.push({\n            publicJwk,\n            verificationMethod,\n          })\n        }\n      }\n    }\n\n    if (!mapX25519ToEd25519) {\n      return recipientKeys as Array<{\n        verificationMethod: VerificationMethod\n        publicJwk: PublicJwk<MapX25519ToEd25519 extends true ? Ed25519PublicJwk : Ed25519PublicJwk | X25519PublicJwk>\n      }>\n    }\n\n    return recipientKeys.map(({ publicJwk, verificationMethod }) => {\n      if (publicJwk.is(Ed25519PublicJwk)) return { publicJwk, verificationMethod }\n\n      const matchingEd25519Key = findMatchingEd25519Key(publicJwk as PublicJwk<X25519PublicJwk>, this)\n\n      // For DIDcomm v1 if you use X25519 you MUST also include the Ed25519 key\n      if (!matchingEd25519Key) {\n        throw new CredoError(\n          `Unable to find matching Ed25519 key for X25519 verification method with id ${verificationMethod.id}`\n        )\n      }\n\n      return matchingEd25519Key\n    })\n  }\n\n  public toJSON() {\n    return JsonTransformer.toJSON(this)\n  }\n\n  public static fromJSON(didDocument: unknown) {\n    return JsonTransformer.fromJSON(didDocument, DidDocument)\n  }\n}\n\n/**\n * Extracting the verification method for signature type\n * @param type Signature type\n * @param didDocument DidDocument\n * @returns verification method\n */\nexport async function findVerificationMethodByKeyType(\n  keyType: string,\n  didDocument: DidDocument\n): Promise<VerificationMethod | null> {\n  const didVerificationMethods: DidVerificationMethods[] = [\n    'verificationMethod',\n    'authentication',\n    'keyAgreement',\n    'assertionMethod',\n    'capabilityInvocation',\n    'capabilityDelegation',\n  ]\n  for (const purpose of didVerificationMethods) {\n    const key: VerificationMethod[] | (string | VerificationMethod)[] | undefined = didDocument[purpose]\n    if (Array.isArray(key)) {\n      for (const method of key) {\n        if (typeof method !== 'string') {\n          if (method.type === keyType) {\n            return method\n          }\n        }\n      }\n    }\n  }\n\n  return null\n}\n"],"mappings":"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"}