{"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 keyId = options.key.keyId\n    const kms =\n      backend || !keyId\n        ? this.getKms(this.agentContext, backend, operation)\n        : (await this.getKmsForOperationAndKeyId(this.agentContext, keyId, 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 keyId = routingKeyId(options.key)\n    const kms =\n      backend || !keyId\n        ? this.getKms(this.agentContext, backend, operation)\n        : (await this.getKmsForOperationAndKeyId(this.agentContext, keyId, 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 keyId = routingKeyId(options.key)\n    const kms =\n      backend || !keyId\n        ? this.getKms(this.agentContext, backend, operation)\n        : (await this.getKmsForOperationAndKeyId(this.agentContext, keyId, 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      if (operation && !kms.isOperationSupported(agentContext, operation)) continue\n\n      const publicKey = await kms.getPublicKey(this.agentContext, keyId)\n      if (publicKey)\n        return {\n          publicKey,\n          kms,\n        }\n    }\n\n    throw new KeyManagementKeyNotFoundError(\n      keyId,\n      this.keyManagementConfig.backends.map((b) => b.backend),\n      operation\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        : undefined\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 default backend (the `defaultBackend` from\n   * the `KeyManagementModuleConfig`, or the first registered backend if no\n   * `defaultBackend` was configured) will be used if it supports the operation.\n   * If the default backend does not support the operation, the first other\n   * backend that supports the operation will be used and a warning will be logged.\n   */\n  private getKms(agentContext: AgentContext, backend?: string, operation?: KmsOperation) {\n    const backends = this.keyManagementConfig.backends\n\n    if (backend) {\n      const kms = backends.find((kms) => kms.backend === backend)\n      if (!kms) {\n        const availableBackends = 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      if (operation && !kms.isOperationSupported(agentContext, 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    if (backends.length > 0) {\n      const defaultKms = this.keyManagementConfig.defaultBackend\n      if (!operation || defaultKms.isOperationSupported(agentContext, operation)) return defaultKms\n\n      const fallbackKms = backends.find(\n        (kms) => kms !== defaultKms && kms.isOperationSupported(agentContext, operation)\n      )\n\n      if (fallbackKms) {\n        return fallbackKms\n      }\n    }\n\n    throw new KeyManagementError(\n      operation\n        ? `No key management service backend found that supports ${getKmsOperationHumanDescription(operation)}`\n        : 'No key management service backend found.'\n    )\n  }\n}\n\nfunction routingKeyId(key: KmsEncryptOptions['key'] | KmsDecryptOptions['key']): string | undefined {\n  if (key.keyId) return key.keyId\n  if (key.keyAgreement && 'keyId' in key.keyAgreement) return key.keyAgreement.keyId\n  return undefined\n}\n"],"mappings":"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"}