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
}
}