function buildPrivateOnDecrypt()

in modules/material-management/src/multi_keyring.ts [114:160]


function buildPrivateOnDecrypt<S extends SupportedAlgorithmSuites>() {
  return async function _onDecrypt(
    this: MultiKeyring<S>,
    material: DecryptionMaterial<S>,
    encryptedDataKeys: EncryptedDataKey[]
  ): Promise<DecryptionMaterial<S>> {
    const children = this.children.slice()
    if (this.generator) children.unshift(this.generator)

    const childKeyringErrors: Catchable[] = []

    for (const keyring of children) {
      /* Check for early return (Postcondition): Do not attempt to decrypt once I have a valid key. */
      if (material.hasValidKey()) return material

      try {
        await keyring.onDecrypt(material, encryptedDataKeys)
      } catch (e) {
        /* Failures onDecrypt should not short-circuit the process
         * If the caller does not have access they may have access
         * through another Keyring.
         */
        childKeyringErrors.push({ errPlus: e })
      }
    }

    /* Postcondition: A child keyring must provide a valid data key or no child keyring must have raised an error.
     * If I have a data key,
     * decrypt errors can be ignored.
     * However, if I was unable to decrypt a data key AND I have errors,
     * these errors should bubble up.
     * Otherwise, the only error customers will see is that
     * the material does not have an unencrypted data key.
     * So I return a concatenated Error message
     */
    needs(
      material.hasValidKey() ||
        (!material.hasValidKey() && !childKeyringErrors.length),
      childKeyringErrors.reduce(
        (m, e, i) => `${m} Error #${i + 1} \n ${e.errPlus.stack} \n`,
        'Unable to decrypt data key and one or more child keyrings had an error. \n '
      )
    )

    return material
  }
}