All files / src/services AffinidiVaultEncryptionService.ts

97.56% Statements 40/41
100% Branches 4/4
100% Functions 8/8
97.36% Lines 37/38

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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102  1x   1x                               1x       152x           6x   6x 20x 20x   20x   20x 20x 18x 36x 36x       20x   20x               6x       5x 5x 5x 5x 10x 10x     5x     5x       16x   16x 26x 26x 26x         16x 26x 16x       27x   27x       7x   7x      
import { KeyManager } from '@affinidi/common'
import { profile } from '@affinidi/tools-common'
 
import { isW3cCredential } from '../_helpers'
import { CredentialLike } from '../dto/internal'
import { VaultCredential } from '../dto/vault.dto'
 
type OriginalCredential = {
  credential: CredentialLike
}
 
type EncryptedCredential<TOriginal> = {
  idHash: string
  typeHashes: string[]
  cyphertext: string
  originalCredential: TOriginal
}
 
@profile()
export default class AffinidiVaultEncryptionService {
  private _keyManager: KeyManager
 
  constructor(keyManager: KeyManager) {
    this._keyManager = keyManager
  }
 
  async encryptCredentials<TOriginal extends OriginalCredential>(
    credentials: TOriginal[],
  ): Promise<EncryptedCredential<TOriginal>[]> {
    const encryptedCredentials: EncryptedCredential<TOriginal>[] = []
 
    for (const originalCredential of credentials) {
      const { credential } = originalCredential
      const credentialId = isW3cCredential(credential) ? credential.id : credential.data.id
 
      const idHash = await this._keyManager.computePersonalHash(credentialId)
 
      const typeHashes: string[] = []
      if (isW3cCredential(credential)) {
        for (const credentialType of credential.type) {
          const typeHash = await this._keyManager.computePersonalHash(credentialType)
          typeHashes.push(typeHash)
        }
      }
 
      const cyphertext = await this._keyManager.encryptByPublicKey(credential)
 
      encryptedCredentials.push({
        idHash,
        typeHashes,
        cyphertext,
        originalCredential,
      })
    }
 
    return encryptedCredentials
  }
 
  async computeTypesHashes(types: string[][]): Promise<string[][]> {
    const hashedTypes: string[][] = []
    for (const subset of types) {
      const hashedSubset: string[] = []
      for (const type of subset) {
        const hashedType = await this._keyManager.computePersonalHash(type)
        hashedSubset.push(hashedType)
      }
 
      hashedTypes.push(hashedSubset)
    }
 
    return hashedTypes
  }
 
  async decryptCredentials(encryptedCredentials: VaultCredential[]): Promise<CredentialLike[]> {
    let credentials: CredentialLike[] = []
 
    const decryptCredentialsPromises = encryptedCredentials.map(async (encryptedCredential) => {
      try {
        const result = await this.decryptCredential(encryptedCredential)
        return result
      } catch (error) {
        console.log('error decryptCredential', error)
      }
    })
    const data = await Promise.all(decryptCredentialsPromises)
    credentials = data.filter((credential) => !!credential)
    return credentials
  }
 
  async decryptCredential(encryptedCredential: VaultCredential): Promise<CredentialLike> {
    const credential = await this._keyManager.decryptByPrivateKey(encryptedCredential.payload)
 
    return credential
  }
 
  async computeHashedId(credentialId: string) {
    const hashedId = await this._keyManager.computePersonalHash(credentialId)
 
    return hashedId
  }
}