All files / src/services AffinidiVaultStorageService.ts

100% Statements 28/28
100% Branches 2/2
100% Functions 7/7
100% Lines 26/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 841x 1x   1x                         1x         152x 152x                 6x   6x 20x     6x 16x         15x     5x       16x   16x 16x   16x       2x 2x   1x   1x       5x   5x       3x       3x 10x        
import { AffinidiVaultApiService } from '@affinidi/internal-api-clients'
import { profile } from '@affinidi/tools-common'
 
import { extractSDKVersion } from '../_helpers'
import { CredentialLike } from '../dto/internal'
import { VaultCredential } from '../dto/vault.dto'
import { DidAuthAdapter } from '../shared/DidAuthAdapter'
import AffinidiVaultEncryptionService from './AffinidiVaultEncryptionService'
 
type AffinidiVaultStorageOptions = {
  didAuthAdapter: DidAuthAdapter
  accessApiKey: string
  vaultUrl: string
}
 
@profile()
export default class AffinidiVaultStorageService {
  private _encryptionService
  private _vaultApiService
 
  constructor(encryptionService: AffinidiVaultEncryptionService, options: AffinidiVaultStorageOptions) {
    this._encryptionService = encryptionService
    this._vaultApiService = new AffinidiVaultApiService({
      vaultUrl: options.vaultUrl,
      accessApiKey: options.accessApiKey,
      sdkVersion: extractSDKVersion(),
      didAuthAdapter: options.didAuthAdapter,
    })
  }
 
  public async saveCredentials(credentials: CredentialLike[], storageRegion: string): Promise<VaultCredential[]> {
    const responses: VaultCredential[] = []
 
    const encryptedCredentials = await this._encryptionService.encryptCredentials(
      credentials.map((credential) => ({ credential })),
    )
 
    for (const credential of encryptedCredentials) {
      const { body } = await this._vaultApiService.storeCredential(storageRegion, credential.idHash, {
        credentialTypes: credential.typeHashes,
        payload: credential.cyphertext,
      })
 
      responses.push(body)
    }
 
    return responses
  }
 
  public async searchCredentials(storageRegion: string, types?: string[][]): Promise<CredentialLike[]> {
    const hashedTypes = types ? await this._encryptionService.computeTypesHashes(types) : undefined
 
    const { body } = await this._vaultApiService.searchCredentials(storageRegion, hashedTypes)
    const credentials = await this._encryptionService.decryptCredentials(body.credentials)
 
    return credentials
  }
 
  public async getCredentialById(credentialId: string, storageRegion: string): Promise<CredentialLike> {
    const hashedId = await this._encryptionService.computeHashedId(credentialId)
    const { body } = await this._vaultApiService.getCredential(storageRegion, hashedId)
 
    const credential = await this._encryptionService.decryptCredential(body)
 
    return credential
  }
 
  public async deleteCredentialById(credentialId: string, storageRegion: string): Promise<void> {
    const hashedId = await this._encryptionService.computeHashedId(credentialId)
 
    await this._vaultApiService.deleteCredential(storageRegion, hashedId)
  }
 
  public async deleteAllCredentials(storageRegion: string): Promise<void> {
    const { body } = await this._vaultApiService.searchCredentials(storageRegion)
 
    // this could have perfomance problems when need delete big amount of credentials
    // probably can use some kind of concurrency, but it is unknown what behavior will be at each platform
    for (const credential of body.credentials) {
      await this._vaultApiService.deleteCredential(storageRegion, credential.credentialId)
    }
  }
}