From 8380200d88f97218e977e3b180f28dd48f3a2d19 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Wed, 25 Sep 2024 03:37:40 +0900 Subject: [PATCH] fix: support decrypting strings larger than 4 MiB (#123) The `cloakedStringRegex` regex fails on ciphertexts larger than 4 MiB. The new `parseCloakedString` in [`@47ng/cloak@1.2.0`][1] doesn't have this limitation. [1]: https://github.com/47ng/cloak/releases/tag/v1.2.0 Fixes: https://github.com/47ng/prisma-field-encryption/issues/122 --- package.json | 2 +- src/encryption.ts | 4 ++-- src/tests/integration.test.ts | 33 +++++++++++++++++++++++++++++++++ yarn.lock | 8 ++++---- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 1d25e97..c6ee11c 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "migrate": "ts-node ./src/tests/migrate.ts" }, "dependencies": { - "@47ng/cloak": "^1.1.0", + "@47ng/cloak": "^1.2.0", "@prisma/generator-helper": "^5.9.1", "debug": "^4.3.4", "immer": "^10.0.3", diff --git a/src/encryption.ts b/src/encryption.ts index 8ba0fea..7472382 100644 --- a/src/encryption.ts +++ b/src/encryption.ts @@ -1,11 +1,11 @@ import { - cloakedStringRegex, CloakKeychain, decryptStringSync, encryptStringSync, findKeyForMessage, makeKeychainSync, ParsedCloakKey, + parseCloakedString, parseKeySync } from '@47ng/cloak' import { Draft, produce } from 'immer' @@ -176,7 +176,7 @@ export function decryptOnRead( field }) { try { - if (!cloakedStringRegex.test(cipherText)) { + if (!parseCloakedString(cipherText)) { return } const decryptionKey = findKeyForMessage(cipherText, keys.keychain) diff --git a/src/tests/integration.test.ts b/src/tests/integration.test.ts index 92e89f2..a5ea969 100644 --- a/src/tests/integration.test.ts +++ b/src/tests/integration.test.ts @@ -1,4 +1,5 @@ import { cloakedStringRegex } from '@47ng/cloak' +import { createHash } from 'node:crypto' import fs from 'node:fs/promises' import path from 'node:path' import { errors } from '../errors' @@ -453,4 +454,36 @@ describe.each(clients)('integration ($type)', ({ client }) => { expect(received!.name).toEqual(' François') // clear text in returned value expect(received!.email).toEqual(normalizeTestEmail) }) + + test('query field with 4 MiB+ data', async () => { + const longNameUser = { + name: 'a'.repeat(4_194_304), + email: 'mr-4MiB-name@example.test' + } as const + await client.user.upsert({ + where: { + email: longNameUser.email + }, + create: longNameUser, + update: longNameUser + }) + const savedUser = await client.user.findUniqueOrThrow({ + where: { + email: longNameUser.email + } + }) + expect(savedUser.email).toStrictEqual(longNameUser.email) + // The encrypted field is larger than the unencrypted field, so just comparing + // the lengths is fine. + expect(savedUser.name?.length).toStrictEqual(longNameUser.name.length) + // Don't test for equality, otherwise we'd fill up the jest log with + // a massive error message if something goes wrong. + expect( + createHash('sha256') + .update(savedUser.name ?? '') + .digest('hex') + ).toStrictEqual( + createHash('sha256').update(longNameUser.name).digest('hex') + ) + }, 15_000) // storing 4 MiB into the DB is a bit slow }) diff --git a/yarn.lock b/yarn.lock index f5b10fa..20c78f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@47ng/cloak@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@47ng/cloak/-/cloak-1.1.0.tgz#4172ea63287d3c28aef3ac361fbe313d55647204" - integrity sha512-47dVSPgjTiH3Fgt2CATudxJAU7Fv1WjFIo2e4tXG2UcQitqmIGf9GCgv1MnGv8ctNGPAy9gsjHnNujzuZ1bOow== +"@47ng/cloak@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@47ng/cloak/-/cloak-1.2.0.tgz#7d811527b1530ac55196c7e41fc3bb3eb0c0ac82" + integrity sha512-kKufIDIfW7+YdW+m/0PIFR9zsoIan04tCiAoWsvd2e/MsIh4HtU//n/xDk8eNTTl9cN/rI78qd1r2zCP0QB7hw== dependencies: "@47ng/codec" "^1.0.1" "@stablelib/base64" "^1.0.1"