{"version":3,"file":"VaultStorageService.mjs","names":["VaultStorageService","logger: Logger","clientConfig: Record<string, unknown>"],"sources":["../../src/storage/VaultStorageService.ts"],"sourcesContent":["/**\n * Vault Storage Service\n *\n * Handles external storage operations for large vault files.\n * Supports S3 and S3-compatible storage (MinIO, Cloudflare R2, etc.)\n */\n\nimport type { AgentContext, Logger } from '@credo-ts/core'\nimport type {\n  S3StorageConfig,\n  VaultStorageReference,\n  PresignedUploadUrl,\n  PresignedDownloadUrl,\n} from './VaultStorageConfig'\n\nimport { injectable, inject, InjectionSymbols } from '@credo-ts/core'\n\nimport { sha256 } from '../crypto'\nimport { VaultError, VaultErrorCode } from '../errors'\nimport { DEFAULT_STORAGE_CONFIG } from './VaultStorageConfig'\n\n// S3 client types (dynamic import to avoid hard dependency)\ninterface S3Client {\n  send(command: unknown): Promise<unknown>\n}\n\ninterface S3Commands {\n  PutObjectCommand: new (input: unknown) => unknown\n  GetObjectCommand: new (input: unknown) => unknown\n  DeleteObjectCommand: new (input: unknown) => unknown\n  HeadObjectCommand: new (input: unknown) => unknown\n}\n\ninterface S3Presigner {\n  getSignedUrl(client: S3Client, command: unknown, options: { expiresIn: number }): Promise<string>\n}\n\n/**\n * Vault Storage Service\n *\n * Provides operations for storing and retrieving vault ciphertext\n * from external storage providers like S3.\n */\n@injectable()\nexport class VaultStorageService {\n  private logger: Logger\n  private s3Client?: S3Client\n  private s3Commands?: S3Commands\n  private s3Presigner?: S3Presigner\n  private config?: S3StorageConfig\n\n  public constructor(@inject(InjectionSymbols.Logger) logger: Logger) {\n    this.logger = logger\n  }\n\n  /**\n   * Configure the storage service with S3 settings\n   */\n  public async configure(config: S3StorageConfig): Promise<void> {\n    this.config = config\n    await this.initializeS3Client()\n  }\n\n  /**\n   * Check if storage is configured and ready\n   */\n  public isConfigured(): boolean {\n    return !!this.config && !!this.s3Client\n  }\n\n  /**\n   * Initialize S3 client (lazy loading)\n   */\n  private async initializeS3Client(): Promise<void> {\n    if (!this.config) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, 'Storage not configured')\n    }\n\n    try {\n      // Dynamic import to avoid hard dependency on @aws-sdk/client-s3\n      const { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, HeadObjectCommand } = await import(\n        '@aws-sdk/client-s3'\n      )\n      const { getSignedUrl } = await import('@aws-sdk/s3-request-presigner')\n\n      const clientConfig: Record<string, unknown> = {\n        region: this.config.region,\n      }\n\n      if (this.config.endpoint) {\n        clientConfig.endpoint = this.config.endpoint\n      }\n\n      if (this.config.forcePathStyle) {\n        clientConfig.forcePathStyle = true\n      }\n\n      if (this.config.accessKeyId && this.config.secretAccessKey) {\n        clientConfig.credentials = {\n          accessKeyId: this.config.accessKeyId,\n          secretAccessKey: this.config.secretAccessKey,\n        }\n      }\n\n      this.s3Client = new S3Client(clientConfig) as S3Client\n      this.s3Commands = {\n        PutObjectCommand,\n        GetObjectCommand,\n        DeleteObjectCommand,\n        HeadObjectCommand,\n      } as S3Commands\n      this.s3Presigner = { getSignedUrl } as S3Presigner\n\n      this.logger.info(`S3 storage initialized: bucket=${this.config.bucket}, region=${this.config.region}`)\n    } catch (error) {\n      this.logger.error('Failed to initialize S3 client', { error })\n      throw new VaultError(\n        VaultErrorCode.STORAGE_ERROR,\n        'Failed to initialize S3 client. Make sure @aws-sdk/client-s3 is installed.'\n      )\n    }\n  }\n\n  /**\n   * Upload vault ciphertext to S3\n   *\n   * @param ciphertext - Encrypted vault data\n   * @param vaultId - Vault identifier\n   * @param options - Upload options\n   * @returns Storage reference\n   */\n  public async upload(\n    ciphertext: Uint8Array,\n    vaultId: string,\n    options?: {\n      docId?: string\n      contentType?: string\n      metadata?: Record<string, string>\n    }\n  ): Promise<VaultStorageReference> {\n    if (!this.isConfigured()) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, 'Storage not configured')\n    }\n\n    const config = this.config!\n    const maxSize = config.maxFileSize ?? DEFAULT_STORAGE_CONFIG.MAX_FILE_SIZE\n\n    if (ciphertext.length > maxSize) {\n      throw new VaultError(\n        VaultErrorCode.STORAGE_ERROR,\n        `File size ${ciphertext.length} exceeds maximum ${maxSize} bytes`\n      )\n    }\n\n    // Generate storage key\n    const prefix = config.keyPrefix ?? DEFAULT_STORAGE_CONFIG.KEY_PREFIX\n    const storageKey = `${prefix}${vaultId}`\n\n    // Compute checksum\n    const checksum = this.computeChecksum(ciphertext)\n\n    // Upload to S3\n    const command = new this.s3Commands!.PutObjectCommand({\n      Bucket: config.bucket,\n      Key: storageKey,\n      Body: ciphertext,\n      ContentType: options?.contentType ?? 'application/octet-stream',\n      ContentLength: ciphertext.length,\n      ChecksumSHA256: checksum,\n      Metadata: {\n        'vault-id': vaultId,\n        ...(options?.docId && { 'doc-id': options.docId }),\n        ...options?.metadata,\n      },\n    })\n\n    await this.s3Client!.send(command)\n\n    const uri = this.buildStorageUri(config.bucket, storageKey)\n\n    this.logger.info(`Uploaded vault ${vaultId} to ${uri} (${ciphertext.length} bytes)`)\n\n    return {\n      type: 's3',\n      uri,\n      checksum: `sha-256:${checksum}`,\n      size: ciphertext.length,\n      contentType: options?.contentType ?? 'application/octet-stream',\n      metadata: options?.metadata,\n    }\n  }\n\n  /**\n   * Download vault ciphertext from S3\n   *\n   * @param reference - Storage reference\n   * @returns Ciphertext bytes\n   */\n  public async download(reference: VaultStorageReference): Promise<Uint8Array> {\n    if (!this.isConfigured()) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, 'Storage not configured')\n    }\n\n    const { bucket, key } = this.parseStorageUri(reference.uri)\n\n    const command = new this.s3Commands!.GetObjectCommand({\n      Bucket: bucket,\n      Key: key,\n    })\n\n    const response = (await this.s3Client!.send(command)) as { Body?: { transformToByteArray(): Promise<Uint8Array> } }\n\n    if (!response.Body) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, `Empty response for ${reference.uri}`)\n    }\n\n    const ciphertext = await response.Body.transformToByteArray()\n\n    // Verify checksum if provided\n    if (reference.checksum) {\n      const expectedChecksum = reference.checksum.replace('sha-256:', '')\n      const actualChecksum = this.computeChecksum(ciphertext)\n\n      if (actualChecksum !== expectedChecksum) {\n        throw new VaultError(\n          VaultErrorCode.INTEGRITY_CHECK_FAILED,\n          `Checksum mismatch: expected ${expectedChecksum}, got ${actualChecksum}`\n        )\n      }\n    }\n\n    this.logger.info(`Downloaded vault from ${reference.uri} (${ciphertext.length} bytes)`)\n\n    return ciphertext\n  }\n\n  /**\n   * Delete vault ciphertext from S3\n   *\n   * @param reference - Storage reference\n   */\n  public async delete(reference: VaultStorageReference): Promise<void> {\n    if (!this.isConfigured()) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, 'Storage not configured')\n    }\n\n    const { bucket, key } = this.parseStorageUri(reference.uri)\n\n    const command = new this.s3Commands!.DeleteObjectCommand({\n      Bucket: bucket,\n      Key: key,\n    })\n\n    await this.s3Client!.send(command)\n\n    this.logger.info(`Deleted vault from ${reference.uri}`)\n  }\n\n  /**\n   * Check if a vault exists in storage\n   *\n   * @param reference - Storage reference\n   * @returns True if exists\n   */\n  public async exists(reference: VaultStorageReference): Promise<boolean> {\n    if (!this.isConfigured()) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, 'Storage not configured')\n    }\n\n    const { bucket, key } = this.parseStorageUri(reference.uri)\n\n    try {\n      const command = new this.s3Commands!.HeadObjectCommand({\n        Bucket: bucket,\n        Key: key,\n      })\n\n      await this.s3Client!.send(command)\n      return true\n    } catch {\n      return false\n    }\n  }\n\n  /**\n   * Generate pre-signed URL for upload\n   *\n   * Used by vault operators to provide upload URLs to clients\n   *\n   * @param vaultId - Vault identifier\n   * @param options - Upload options\n   * @returns Pre-signed upload URL\n   */\n  public async generateUploadUrl(\n    vaultId: string,\n    options?: {\n      contentType?: string\n      maxSize?: number\n      expiresIn?: number\n    }\n  ): Promise<PresignedUploadUrl> {\n    if (!this.isConfigured()) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, 'Storage not configured')\n    }\n\n    const config = this.config!\n    const prefix = config.keyPrefix ?? DEFAULT_STORAGE_CONFIG.KEY_PREFIX\n    const storageKey = `${prefix}${vaultId}`\n    const expiresIn = options?.expiresIn ?? config.presignedUrlExpiry ?? DEFAULT_STORAGE_CONFIG.PRESIGNED_URL_EXPIRY\n\n    const command = new this.s3Commands!.PutObjectCommand({\n      Bucket: config.bucket,\n      Key: storageKey,\n      ContentType: options?.contentType ?? 'application/octet-stream',\n    })\n\n    const uploadUrl = await this.s3Presigner!.getSignedUrl(this.s3Client!, command, { expiresIn })\n\n    const expiresAt = new Date(Date.now() + expiresIn * 1000).toISOString()\n\n    return {\n      uploadUrl,\n      method: 'PUT',\n      headers: {\n        'Content-Type': options?.contentType ?? 'application/octet-stream',\n      },\n      expiresAt,\n      storageKey,\n      finalUri: this.buildStorageUri(config.bucket, storageKey),\n    }\n  }\n\n  /**\n   * Generate pre-signed URL for download\n   *\n   * @param reference - Storage reference\n   * @param expiresIn - Expiration in seconds\n   * @returns Pre-signed download URL\n   */\n  public async generateDownloadUrl(\n    reference: VaultStorageReference,\n    expiresIn?: number\n  ): Promise<PresignedDownloadUrl> {\n    if (!this.isConfigured()) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, 'Storage not configured')\n    }\n\n    const config = this.config!\n    const { bucket, key } = this.parseStorageUri(reference.uri)\n    const expiry = expiresIn ?? config.presignedUrlExpiry ?? DEFAULT_STORAGE_CONFIG.PRESIGNED_URL_EXPIRY\n\n    const command = new this.s3Commands!.GetObjectCommand({\n      Bucket: bucket,\n      Key: key,\n    })\n\n    const downloadUrl = await this.s3Presigner!.getSignedUrl(this.s3Client!, command, { expiresIn: expiry })\n\n    return {\n      downloadUrl,\n      expiresAt: new Date(Date.now() + expiry * 1000).toISOString(),\n      size: reference.size,\n      checksum: reference.checksum,\n    }\n  }\n\n  /**\n   * Download from a pre-signed URL (for clients without S3 credentials)\n   *\n   * @param downloadUrl - Pre-signed download URL\n   * @param expectedChecksum - Expected checksum for verification\n   * @returns Downloaded data\n   */\n  public async downloadFromUrl(downloadUrl: string, expectedChecksum?: string): Promise<Uint8Array> {\n    const response = await fetch(downloadUrl)\n\n    if (!response.ok) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, `Download failed: ${response.status} ${response.statusText}`)\n    }\n\n    const arrayBuffer = await response.arrayBuffer()\n    const data = new Uint8Array(arrayBuffer)\n\n    // Verify checksum if provided\n    if (expectedChecksum) {\n      const checksumValue = expectedChecksum.replace('sha-256:', '')\n      const actualChecksum = this.computeChecksum(data)\n\n      if (actualChecksum !== checksumValue) {\n        throw new VaultError(\n          VaultErrorCode.INTEGRITY_CHECK_FAILED,\n          `Checksum mismatch: expected ${checksumValue}, got ${actualChecksum}`\n        )\n      }\n    }\n\n    this.logger.debug(`Downloaded ${data.length} bytes from pre-signed URL`)\n\n    return data\n  }\n\n  /**\n   * Upload to a pre-signed URL (for clients without S3 credentials)\n   *\n   * @param uploadUrl - Pre-signed upload URL\n   * @param data - Data to upload\n   * @param contentType - Content type\n   * @returns Checksum of uploaded data\n   */\n  public async uploadToUrl(uploadUrl: string, data: Uint8Array, contentType?: string): Promise<string> {\n    const response = await fetch(uploadUrl, {\n      method: 'PUT',\n      body: data,\n      headers: {\n        'Content-Type': contentType ?? 'application/octet-stream',\n        'Content-Length': data.length.toString(),\n      },\n    })\n\n    if (!response.ok) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, `Upload failed: ${response.status} ${response.statusText}`)\n    }\n\n    const checksum = this.computeChecksum(data)\n    this.logger.debug(`Uploaded ${data.length} bytes to pre-signed URL`)\n\n    return `sha-256:${checksum}`\n  }\n\n  // ═══════════════════════════════════════════════════════════════════════════\n  // Private Helpers\n  // ═══════════════════════════════════════════════════════════════════════════\n\n  /**\n   * Compute SHA-256 checksum, encoded as standard base64 (with padding).\n   * AWS S3 ChecksumSHA256 expects standard base64, not base64url.\n   */\n  private computeChecksum(data: Uint8Array): string {\n    return base64EncodeStandard(sha256(data))\n  }\n\n  /**\n   * Build S3 URI from bucket and key\n   */\n  private buildStorageUri(bucket: string, key: string): string {\n    return `s3://${bucket}/${key}`\n  }\n\n  /**\n   * Parse S3 URI into bucket and key\n   */\n  private parseStorageUri(uri: string): { bucket: string; key: string } {\n    if (!uri.startsWith('s3://')) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, `Invalid S3 URI: ${uri}`)\n    }\n\n    const path = uri.slice(5) // Remove 's3://'\n    const slashIndex = path.indexOf('/')\n\n    if (slashIndex === -1) {\n      throw new VaultError(VaultErrorCode.STORAGE_ERROR, `Invalid S3 URI (no key): ${uri}`)\n    }\n\n    return {\n      bucket: path.slice(0, slashIndex),\n      key: path.slice(slashIndex + 1),\n    }\n  }\n}\n\n// Standard base64 (with padding) — used for AWS S3 ChecksumSHA256.\n// AWS does not accept base64url; we keep this local to avoid pulling Node\n// `Buffer` into the RN bundle.\nconst B64_STD = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\nfunction base64EncodeStandard(data: Uint8Array): string {\n  let out = ''\n  let i = 0\n  for (; i + 2 < data.length; i += 3) {\n    const v = (data[i] << 16) | (data[i + 1] << 8) | data[i + 2]\n    out += B64_STD[(v >> 18) & 0x3f] + B64_STD[(v >> 12) & 0x3f] + B64_STD[(v >> 6) & 0x3f] + B64_STD[v & 0x3f]\n  }\n  if (i < data.length) {\n    const a = data[i]\n    const b = i + 1 < data.length ? data[i + 1] : 0\n    out += B64_STD[(a >> 2) & 0x3f]\n    if (i + 1 < data.length) {\n      out += B64_STD[((a << 4) & 0x30) | ((b >> 4) & 0x0f)] + B64_STD[(b << 2) & 0x3c] + '='\n    } else {\n      out += B64_STD[(a << 4) & 0x30] + '=='\n    }\n  }\n  return out\n}\n"],"mappings":"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"}