Skip to content

Commit

Permalink
feat: Add support for filtering encrypted field in list of values
Browse files Browse the repository at this point in the history
  • Loading branch information
m-przybylski committed Nov 29, 2024
1 parent 78e0f2f commit b231755
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 6 deletions.
27 changes: 24 additions & 3 deletions src/encryption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,12 @@ export function encryptOnWrite<Models extends string, Actions extends string>(
if (!fieldConfig.hash) {
console.warn(warnings.whereConnectClauseNoHash(operation, path))
} else {
const hash = hashString(clearText, fieldConfig.hash)
const fieldConfigHash = fieldConfig.hash
// If clearText is a list, hash each value
const hash: string | string[] = Array.isArray(clearText)
? clearText.map(value => hashString(value, fieldConfigHash))
: hashString(clearText, fieldConfigHash)

debug.encryption(
`Swapping encrypted search of ${model}.${field} with hash search under ${fieldConfig.hash.targetField} (hash: ${hash})`
)
Expand All @@ -90,6 +95,14 @@ export function encryptOnWrite<Models extends string, Actions extends string>(
return
}
}
// Encrypting list values is not yet supported
if (typeof clearText !== 'string') {
debug.encryption(
`Encrypting type ${typeof clearText} is not supported.`
)
return
}

if (isOrderBy(path, field, clearText)) {
// Remove unsupported orderBy clause on encrypted text
// (makes no sense to sort ciphertext nor to encrypt 'asc' | 'desc')
Expand Down Expand Up @@ -176,6 +189,14 @@ export function decryptOnRead<Models extends string, Actions extends string>(
field
}) {
try {
// Decrypting list values is not yet supported
if (typeof cipherText !== 'string') {
debug.decryption(
`Decrypting type ${cipherText} is not supported.`
)
return
}

if (!parseCloakedString(cipherText)) {
return
}
Expand Down Expand Up @@ -212,8 +233,8 @@ function rewriteHashedFieldPath(
hashField: string
) {
const items = path.split('.').reverse()
// Special case for `where field equals or not` clause
if (items.includes('where') && items[1] === field && ['equals', 'not'].includes(items[0])) {
// Special case for `where field equals, not or in` clause
if (items.includes('where') && items[1] === field && ['equals', 'not', 'in'].includes(items[0])) {
items[1] = hashField
return items.reverse().join('.')
}
Expand Down
21 changes: 21 additions & 0 deletions src/tests/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -486,4 +486,25 @@ describe.each(clients)('integration ($type)', ({ client }) => {
createHash('sha256').update(longNameUser.name).digest('hex')
)
}, 15_000) // storing 4 MiB into the DB is a bit slow

test('query entries in list', async () => {
await client.user.create({
data: {
name: 'Test User 1',
email: '[email protected]'
}
})
await client.user.create({
data: {
name: 'Test User 2',
email: '[email protected]'
}
})

const foundUserCount = await client.user.count({
where: { name: { in: ['Test User 1', 'Test User 2'] } }
})

expect(foundUserCount).toBe(2)
})
})
8 changes: 5 additions & 3 deletions src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface VisitorState {

export interface TargetField {
path: string
value: string
value: string | string[]
model: string
field: string
fieldConfig: FieldConfiguration
Expand Down Expand Up @@ -46,7 +46,9 @@ const makeVisitor = (
if (
type === 'object' &&
key in model.fields &&
typeof (node as any)?.[specialSubField] === 'string'
// Used for where: { field: in: []} queries
(typeof (node as any)?.[specialSubField] === 'string' ||
Array.isArray((node as any)?.[specialSubField]))
) {
const value: string = (node as any)[specialSubField]
const targetField: TargetField = {
Expand Down Expand Up @@ -84,7 +86,7 @@ export function visitInputTargetFields<
) {
traverseTree(
params.args,
makeVisitor(models, visitor, ['equals', 'set', 'not'], debug.encryption),
makeVisitor(models, visitor, ['equals', 'set', 'not', 'in'], debug.encryption),
{
currentModel: params.model!
}
Expand Down

0 comments on commit b231755

Please sign in to comment.