{"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  public findVerificationMethodsByPurpose(allowedPurposes: readonly DidVerificationMethods[]): VerificationMethod[] {\n    const methods: VerificationMethod[] = []\n\n    for (const purpose of allowedPurposes) {\n      for (const entry of this[purpose] ?? []) {\n        methods.push(typeof entry === 'string' ? this.dereferenceVerificationMethod(entry) : entry)\n      }\n    }\n\n    return methods\n  }\n\n  public findVerificationMethodsByTypeAndPurpose(\n    verificationMethodTypes: string | readonly string[],\n    allowedPurposes: readonly DidVerificationMethods[]\n  ): VerificationMethod[] {\n    const acceptedTypes = new Set(\n      typeof verificationMethodTypes === 'string' ? [verificationMethodTypes] : verificationMethodTypes\n    )\n\n    return this.findVerificationMethodsByPurpose(allowedPurposes).filter((method) => acceptedTypes.has(method.type))\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"],"mappings":"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"}