{"version":3,"file":"KeyManagementApi.mjs","names":[],"sources":["../../../src/modules/kms/KeyManagementApi.ts"],"sourcesContent":["import { AgentContext } from '../../agent'\nimport { injectable } from '../../plugins'\nimport { zParseWithErrorHandling } from '../../utils/zod'\nimport { KeyManagementError } from './error/KeyManagementError'\nimport { KeyManagementKeyNotFoundError } from './error/KeyManagementKeyNotFoundError'\nimport { getJwkHumanDescription, type KmsJwkPrivate } from './jwk'\nimport { createKeyTypeForSigningAlgorithm } from './jwk/alg/signing'\nimport { KeyManagementModuleConfig } from './KeyManagementModuleConfig'\nimport {\n  getKmsOperationHumanDescription,\n  type KmsDecryptOptions,\n  type KmsDeleteKeyOptions,\n  type KmsGetPublicKeyOptions,\n  type KmsImportKeyOptions,\n  type KmsOperation,\n  type KmsRandomBytesOptions,\n} from './options'\nimport { type WithBackend, zWithBackend } from './options/backend'\nimport {\n  type KmsCreateKeyForSignatureAlgorithmOptions,\n  type KmsCreateKeyOptions,\n  type KmsCreateKeyReturn,\n  type KmsCreateKeyType,\n  type KmsCreateKeyTypeAsymmetric,\n  zKmsCreateKeyForSignatureAlgorithmOptions,\n  zKmsCreateKeyOptions,\n} from './options/KmsCreateKeyOptions'\nimport { zKmsDecryptOptions } from './options/KmsDecryptOptions'\nimport { zKmsDeleteKeyOptions } from './options/KmsDeleteKeyOptions'\nimport { type KmsEncryptOptions, zKmsEncryptOptions } from './options/KmsEncryptOptions'\nimport { zKmsGetPublicKeyOptions } from './options/KmsGetPublicKeyOptions'\nimport { type KmsImportKeyReturn, zKmsImportKeyOptions } from './options/KmsImportKeyOptions'\nimport { zKmsRandomBytesOptions } from './options/KmsRandomBytesOptions'\nimport { type KmsSignOptions, zKmsSignOptions } from './options/KmsSignOptions'\nimport { type KmsVerifyOptions, zKmsVerifyOptions } from './options/KmsVerifyOptions'\n\n@injectable()\nexport class KeyManagementApi {\n  public constructor(\n    private keyManagementConfig: KeyManagementModuleConfig,\n    private agentContext: AgentContext\n  ) {}\n\n  /**\n   * Whether an operation is supported.\n   *\n   * @returns a list of backends that support the operation. In case\n   * no backends are supported it returns an empty array\n   */\n  public supportedBackendsForOperation(operation: KmsOperation): string[] {\n    const supportedBackends: string[] = []\n\n    for (const kms of this.keyManagementConfig.backends) {\n      const isOperationSupported = kms.isOperationSupported(this.agentContext, operation)\n      if (isOperationSupported) {\n        supportedBackends.push(kms.backend)\n      }\n    }\n\n    return supportedBackends\n  }\n\n  /**\n   * Create a key.\n   */\n  public async createKey<Type extends KmsCreateKeyType>(\n    options: WithBackend<KmsCreateKeyOptions<Type>>\n  ): Promise<KmsCreateKeyReturn<Type>> {\n    const { backend, ...kmsOptions } = zParseWithErrorHandling(\n      zWithBackend(zKmsCreateKeyOptions),\n      options,\n      'Invalid options provided to createKey method'\n    )\n\n    const kms = this.getKms(this.agentContext, backend, {\n      operation: 'createKey',\n      type: options.type,\n    })\n\n    const key = await kms.createKey(this.agentContext, kmsOptions)\n    key.publicJwk.kid = key.keyId\n\n    this.agentContext.config.logger.debug(\n      `Created key ${getJwkHumanDescription(key.publicJwk)} with key id '${key.keyId}'`\n    )\n\n    return key\n  }\n\n  /**\n   * Create a key.\n   */\n  public async createKeyForSignatureAlgorithm(\n    options: WithBackend<KmsCreateKeyForSignatureAlgorithmOptions>\n  ): Promise<KmsCreateKeyReturn<KmsCreateKeyTypeAsymmetric>> {\n    const { backend, algorithm, ...kmsOptions } = zParseWithErrorHandling(\n      zWithBackend(zKmsCreateKeyForSignatureAlgorithmOptions),\n      options,\n      'Invalid options provided to createKeyForSignatureAlgorithm method'\n    )\n\n    const type = createKeyTypeForSigningAlgorithm(algorithm)\n    const kms = this.getKms(this.agentContext, backend, {\n      operation: 'createKey',\n      type,\n    })\n\n    // Ensure the kid is set to the keyId\n    const key = await kms.createKey(this.agentContext, {\n      ...kmsOptions,\n      type,\n    })\n    key.publicJwk.kid = key.keyId\n\n    return key\n  }\n\n  /**\n   * Sign using a key.\n   */\n  public async sign(options: WithBackend<KmsSignOptions>) {\n    const { backend, ...kmsOptions } = zParseWithErrorHandling(\n      zWithBackend(zKmsSignOptions),\n      options,\n      'Invalid options provided to sign method'\n    )\n\n    const operation = {\n      operation: 'sign',\n      algorithm: options.algorithm,\n    } as const\n\n    const kms = backend\n      ? this.getKms(this.agentContext, backend, operation)\n      : (await this.getKmsForOperationAndKeyId(this.agentContext, options.keyId, operation)).kms\n    return await kms.sign(this.agentContext, kmsOptions)\n  }\n\n  /**\n   * Verify using a key.\n   */\n  public async verify(options: WithBackend<KmsVerifyOptions>) {\n    const { backend, ...kmsOptions } = zParseWithErrorHandling(\n      zWithBackend(zKmsVerifyOptions),\n      options,\n      'Invalid options provided to verify method'\n    )\n\n    const operation = { operation: 'verify', algorithm: options.algorithm } as const\n    const kms =\n      backend || typeof options.key !== 'string'\n        ? this.getKms(this.agentContext, backend, operation)\n        : (await this.getKmsForOperationAndKeyId(this.agentContext, options.key, operation)).kms\n\n    return await kms.verify(this.agentContext, kmsOptions)\n  }\n\n  /**\n   * Encrypt.\n   */\n  public async encrypt(options: WithBackend<KmsEncryptOptions>) {\n    const { backend, ...kmsOptions } = zParseWithErrorHandling(\n      zWithBackend(zKmsEncryptOptions),\n      options,\n      'Invalid options provided to encrypt method'\n    )\n\n    const operation = {\n      operation: 'encrypt',\n      encryption: options.encryption,\n      keyAgreement: options.key.keyAgreement,\n    } as const\n    const kms =\n      backend || typeof options.key !== 'string'\n        ? this.getKms(this.agentContext, backend, operation)\n        : (await this.getKmsForOperationAndKeyId(this.agentContext, options.key, operation)).kms\n\n    return await kms.encrypt(this.agentContext, kmsOptions)\n  }\n\n  /**\n   * Decrypt.\n   */\n  public async decrypt(options: WithBackend<KmsDecryptOptions>) {\n    const { backend, ...kmsOptions } = zParseWithErrorHandling(\n      zWithBackend(zKmsDecryptOptions),\n      options,\n      'Invalid options provided to decrypt method'\n    )\n\n    const operation = {\n      operation: 'decrypt',\n      decryption: options.decryption,\n      keyAgreement: options.key.keyAgreement,\n    } as const\n    const kms =\n      backend || typeof options.key !== 'string'\n        ? this.getKms(\n            this.agentContext,\n\n            backend,\n            operation\n          )\n        : (await this.getKmsForOperationAndKeyId(this.agentContext, options.key, operation)).kms\n\n    return await kms.decrypt(this.agentContext, kmsOptions)\n  }\n\n  /**\n   * Import a key.\n   */\n  public async importKey<Jwk extends KmsJwkPrivate>(\n    options: WithBackend<KmsImportKeyOptions<Jwk>>\n  ): Promise<KmsImportKeyReturn<Jwk>> {\n    const { backend, ...kmsOptions } = zParseWithErrorHandling(\n      zWithBackend(zKmsImportKeyOptions),\n      options,\n      'Invalid options provided to importKey method'\n    )\n\n    const operation = {\n      operation: 'importKey',\n      privateJwk: options.privateJwk,\n    } as const\n    const kms = this.getKms(this.agentContext, backend, operation)\n\n    const key = await kms.importKey(this.agentContext, kmsOptions)\n\n    this.agentContext.config.logger.trace(\n      `Imported key ${getJwkHumanDescription(key.publicJwk)} with key id '${key.keyId}'`\n    )\n\n    return key\n  }\n\n  /**\n   * Get a public key.\n   */\n  public async getPublicKey(options: WithBackend<KmsGetPublicKeyOptions>) {\n    const { backend, keyId } = zParseWithErrorHandling(\n      zWithBackend(zKmsGetPublicKeyOptions),\n      options,\n      'Invalid options provided to getPublicKey method'\n    )\n\n    if (backend) {\n      const kms = this.getKms(this.agentContext, backend)\n      const publicKey = await kms.getPublicKey(this.agentContext, keyId)\n\n      if (!publicKey) {\n        throw new KeyManagementKeyNotFoundError(keyId, [backend])\n      }\n    }\n\n    const { publicKey } = await this.getKmsForOperationAndKeyId(this.agentContext, options.keyId)\n    return publicKey\n  }\n\n  /**\n   * Delete a key.\n   */\n  public async deleteKey(options: WithBackend<KmsDeleteKeyOptions>) {\n    const { backend, ...kmsOptions } = zParseWithErrorHandling(\n      zWithBackend(zKmsDeleteKeyOptions),\n      options,\n      'Invalid options provided to deleteKey method'\n    )\n\n    const operation = {\n      operation: 'deleteKey',\n    } as const\n    const kms = this.getKms(this.agentContext, backend, operation)\n    return await kms.deleteKey(this.agentContext, kmsOptions)\n  }\n\n  /**\n   * Generate random bytes\n   */\n  public randomBytes(options: WithBackend<KmsRandomBytesOptions>) {\n    const { backend, ...kmsOptions } = zParseWithErrorHandling(\n      zWithBackend(zKmsRandomBytesOptions),\n      options,\n      'Invalid options provided to randomBytes method'\n    )\n\n    const operation = {\n      operation: 'randomBytes',\n    } as const\n    const kms = this.getKms(this.agentContext, backend, operation)\n    return kms.randomBytes(this.agentContext, kmsOptions)\n  }\n\n  /**\n   * Get the kms associated with a specific `keyId`.\n   *\n   * This uses a naive approach of fetching the key for each configured kms\n   * until it finds the registered key.\n   *\n   * In the future this approach might be optimized based on:\n   * - caching\n   * - keeping a registry\n   * - backend specific key prefixes\n   */\n  private async getKmsForOperationAndKeyId(agentContext: AgentContext, keyId: string, operation?: KmsOperation) {\n    for (const kms of this.keyManagementConfig.backends) {\n      const isOperationSupported = operation ? kms.isOperationSupported(agentContext, operation) : true\n      if (!isOperationSupported) continue\n\n      const publicKey = await kms.getPublicKey(this.agentContext, keyId)\n      if (publicKey)\n        return {\n          publicKey,\n          kms,\n        }\n    }\n\n    if (operation) {\n      throw new KeyManagementKeyNotFoundError(\n        keyId,\n        this.keyManagementConfig.backends.map((b) => b.backend),\n        `The key may exist in one of the key management services in which case the key management service does not support the ${getKmsOperationHumanDescription(operation)}`\n      )\n    }\n\n    throw new KeyManagementKeyNotFoundError(\n      keyId,\n      this.keyManagementConfig.backends.map((b) => b.backend)\n    )\n  }\n\n  /**\n   * Get the kms backend for a specific operation.\n   *\n   * If a backend is provided, it will be checked if the backend supports\n   * the operation. Otherwise the first backend that supports the operation\n   * will be used.\n   */\n  private getKms(agentContext: AgentContext, backend?: string, operation?: KmsOperation) {\n    if (backend) {\n      const kms = this.keyManagementConfig.backends.find((kms) => kms.backend === backend)\n      if (!kms) {\n        const availableBackends = this.keyManagementConfig.backends.map((kms) => `'${kms.backend}'`)\n        throw new KeyManagementError(\n          `No key management service is configured for backend '${backend}'. Available backends are ${availableBackends.join(\n            ', '\n          )}`\n        )\n      }\n\n      const isOperationSupported = operation ? kms.isOperationSupported(agentContext, operation) : true\n      if (!isOperationSupported && operation) {\n        throw new KeyManagementError(\n          `Key management service backend '${backend}' does not support ${getKmsOperationHumanDescription(operation)}`\n        )\n      }\n\n      return kms\n    }\n\n    for (const kms of this.keyManagementConfig.backends) {\n      const isOperationSupported = operation ? kms.isOperationSupported(agentContext, operation) : true\n      if (isOperationSupported) return kms\n    }\n\n    if (operation) {\n      throw new KeyManagementError(\n        `No key management service backend found that supports ${getKmsOperationHumanDescription(operation)}`\n      )\n    }\n\n    throw new KeyManagementError('No key management service backend found.')\n  }\n}\n"],"mappings":"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"}