export function getEncryptionMaterials()

in modules/cache-material/src/caching_cryptographic_materials_decorators.ts [80:150]


export function getEncryptionMaterials<S extends SupportedAlgorithmSuites>({
  buildEncryptionMaterialCacheKey,
}: CryptographicMaterialsCacheKeyHelpersInterface<S>): GetEncryptionMaterials<S> {
  return async function getEncryptionMaterials(
    this: CachingMaterialsManager<S>,
    request: EncryptionRequest<S>
  ): Promise<EncryptionMaterial<S>> {
    const { suite, encryptionContext, plaintextLength, commitmentPolicy } =
      request

    /* Check for early return (Postcondition): If I can not cache the EncryptionMaterial, do not even look. */
    if (
      (suite && !suite.cacheSafe) ||
      typeof plaintextLength !== 'number' ||
      plaintextLength < 0
    ) {
      const material =
        await this._backingMaterialsManager.getEncryptionMaterials(request)
      return material
    }

    const cacheKey = await buildEncryptionMaterialCacheKey(this._partition, {
      suite,
      encryptionContext,
    })
    const entry = this._cache.getEncryptionMaterial(cacheKey, plaintextLength)
    /* Check for early return (Postcondition): If I have a valid EncryptionMaterial, return it. */
    if (entry && !this._cacheEntryHasExceededLimits(entry)) {
      return cloneResponse(entry.response)
    } else {
      this._cache.del(cacheKey)
    }

    const material = await this._backingMaterialsManager
      /* Strip any information about the plaintext from the backing request,
       * because the resulting response may be used to encrypt multiple plaintexts.
       */
      .getEncryptionMaterials({ suite, encryptionContext, commitmentPolicy })

    /* Check for early return (Postcondition): If I can not cache the EncryptionMaterial, just return it. */
    if (!material.suite.cacheSafe) return material

    /* It is possible for an entry to exceed limits immediately.
     * The simplest case is to need to encrypt more than then maxBytesEncrypted.
     * In this case, I return the response to encrypt the data,
     * but do not put a know invalid item into the cache.
     */
    const testEntry = {
      response: material,
      now: Date.now(),
      messagesEncrypted: 1,
      bytesEncrypted: plaintextLength,
    }
    if (!this._cacheEntryHasExceededLimits(testEntry)) {
      this._cache.putEncryptionMaterial(
        cacheKey,
        material,
        plaintextLength,
        this._maxAge
      )
      return cloneResponse(material)
    } else {
      /* Postcondition: If the material has exceeded limits it MUST NOT be cloned.
       * If it is cloned, and the clone is returned,
       * then there exist a copy of the unencrypted data key.
       * It is true that this data would be caught by GC, it is better to just not rely on that.
       */
      return material
    }
  }
}