export function cloneMaterial()

in modules/material-management/src/clone_cryptographic_material.ts [22:91]


export function cloneMaterial<M extends Material>(source: M): M {
  const { suite, encryptionContext } = source

  const clone = (
    suite instanceof NodeAlgorithmSuite
      ? source instanceof NodeEncryptionMaterial
        ? new NodeEncryptionMaterial(suite, encryptionContext)
        : new NodeDecryptionMaterial(suite, encryptionContext)
      : source instanceof WebCryptoEncryptionMaterial
      ? new WebCryptoEncryptionMaterial(suite, encryptionContext)
      : new WebCryptoDecryptionMaterial(suite, encryptionContext)
  ) as M

  /* The setTrace _must_ be the first trace,
   * If the material is an EncryptionMaterial
   * then the data key *must* have been generated.
   * If the material is DecryptionMaterial
   * then the data key *must* have been decrypted.
   * i.e. the required flags are:
   * WRAPPING_KEY_GENERATED_DATA_KEY, WRAPPING_KEY_DECRYPTED_DATA_KEY
   * These are controlled by the material itself.
   * Furthermore, subsequent trace entries,
   * *must* be in the same order as the added encrypted data keys.
   * See cryptographic_materials.ts `decorateCryptographicMaterial`, `decorateWebCryptoMaterial`.
   */
  const [setTrace, ...traces] = source.keyringTrace.slice()

  if (source.hasUnencryptedDataKey) {
    const udk = cloneUnencryptedDataKey(source.getUnencryptedDataKey())
    clone.setUnencryptedDataKey(udk, setTrace)
  }

  if ((source as WebCryptoDecryptionMaterial).hasCryptoKey) {
    const cryptoKey = (source as WebCryptoDecryptionMaterial).getCryptoKey()
    ;(clone as WebCryptoDecryptionMaterial).setCryptoKey(cryptoKey, setTrace)
  }

  if (isEncryptionMaterial(source) && isEncryptionMaterial(clone)) {
    const encryptedDataKeys = source.encryptedDataKeys
    /* Precondition: For each encrypted data key, there must be a trace. */
    needs(
      encryptedDataKeys.length === traces.length,
      'KeyringTrace length does not match encrypted data keys.'
    )
    encryptedDataKeys.forEach((edk, i) => {
      const { providerInfo, providerId } = edk
      const { keyNamespace, keyName, flags } = traces[i]
      /* Precondition: The traces must be in the same order as the encrypted data keys. */
      needs(
        keyName === providerInfo && keyNamespace === providerId,
        'Keyring trace does not match encrypted data key.'
      )
      clone.addEncryptedDataKey(edk, flags)
    })

    if (source.suite.signatureCurve && source.signatureKey) {
      clone.setSignatureKey(source.signatureKey)
    }
  } else if (isDecryptionMaterial(source) && isDecryptionMaterial(clone)) {
    /* Precondition: On Decrypt there must not be any additional traces other than the setTrace. */
    needs(!traces.length, 'Only 1 trace is valid on DecryptionMaterials.')
    if (source.suite.signatureCurve && source.verificationKey) {
      clone.setVerificationKey(source.verificationKey)
    }
  } else {
    throw new Error('Material mismatch')
  }

  return clone
}