'asc' and 'desc' are encrypted when using orderBy on String values
forbesgillikin opened this issue · 7 comments
prisma.user.findMany({
where: {
archived: false
},
take: 25,
skip: 0,
orderBy: {
lastName: 'asc'
}
})
lastName is not encrypted in the Prisma model.
'asc'
becomes encrypted when passed into Prisma
Argument lastName: Provided value '*encryptedvalue*' of type String on prisma.findManyUser is not a SortOrder.
Using SortOrders on other types works as expected.
May I see the relevant Prisma model in your schema please, with the @encrypted
annotations?
In my OP I referenced a different model but this is the one of concern in my project
model Card {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
cardID String @unique /// @encrypted
cardIDHash String? @unique /// @encrypted:hash(cardID)
cardNumber String @unique /// @encrypted
cardNumberHash String? @unique /// @encrypted:hash(cardNumber)
date DateTime @default(now())
firstName String
lastName String
email String?
lastPaid DateTime? @default(now())
lastPaidAmount Float?
archived Boolean @default(false)
cardHolderTypeId String
cardHolderType CardHolderType @relation(fields: [cardHolderTypeId], references: [id], onDelete: Cascade, onUpdate: Cascade)
transactions Transaction[]
}
const cards = await prisma.card.findMany({
where: {
archived: false,
cardHolderType: cardHolderType
? { name: cardHolderType }
: { isNot: undefined }
},
include: {
cardHolderType: true,
transactions: true
},
take: 25,
skip: page > 1 ? (page - 1) * 25 : 0,
orderBy: {
lastName: 'asc'
}
})
'asc'
gets converted into an encrypted string. When using orderBy
with non-supported types like ID, Float, DateTime, 'asc'
is not converted to an encrypted string and Prisma resolves as expected.
What do the debugging logs say? I'd be curious to see what the schema analysis looks like, to understand how this path ends up being encrypted, especially on a read-only query.
Hi @franky47
I got the same error.
Prisma schema:
model User {
id Int @id @default(autoincrement())
email String @unique /// @encrypted
emailHash String? @unique /// @encryption:hash(email)
name String?
password String
salt String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
expiredAt DateTime @updatedAt
products Product[]
}
The error is:
{
"statusCode": 500,
"error": "Internal Server Error",
"message": "\nInvalid `prisma.user.findMany()` invocation in\nC:\\projects\\fastify-test\\src\\modules\\user\\user.service.ts:30:22\n\n 27 }\n 28 \n 29 export async function findUsers() {\n→ 30 return prisma.user.findMany({\n select: {\n email: true,\n name: true,\n id: true,\n createdAt: true,\n expiredAt: true\n },\n orderBy: {\n email: 'v1.aesgcm256.d2a16aa0.uYZkVsBGJYUxarPL.MlYUnc9DVYnZN1FQ4mU3Js-wDd0=',\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n emailHash: 'c3f46fc280c4ac3e5724798b684c86b04d0bc217adcfcb1dade3c1ef56fd8e6b'\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n }\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n })\n\nArgument orderBy of type UserOrderByWithRelationInput needs exactly one argument, but you provided email and emailHash. Please choose one. Available args: \ntype UserOrderByWithRelationInput {\n id?: SortOrder\n email?: SortOrder\n emailHash?: SortOrder\n name?: SortOrder\n password?: SortOrder\n salt?: SortOrder\n createdAt?: SortOrder\n updatedAt?: SortOrder\n expiredAt?: SortOrder\n products?: ProductOrderByRelationAggregateInput\n}\nArgument email: Provided value 'v1.aesgcm256.d2a16aa0.uYZkVsBGJYUxarPL.MlYUnc9DVYnZN1FQ4mU3Js-wDd0=' of type String on prisma.findManyUser is not a SortOrder.\n→ Possible values: SortOrder.asc, SortOrder.desc\nArgument emailHash: Provided value 'c3f46fc280c4ac3e5724798b684c86b04d0bc217adcfcb1dade3c1ef56fd8e6b' of type String on prisma.findManyUser is not a SortOrder.\n→ Possible values: SortOrder.asc, SortOrder.desc\n\n"
}
Hi,
Same Error:
invalid `prisma.tbl_user.findMany()` invocation:
{
select: {
id: true,
email: true,
first_name: true,
last_name: true,
user_title: true,
user_roles: true
},
take: 25,
skip: 0,
orderBy: {
first_name: 'v1.aesgcm256.23ba68b8.pkemoldaauMZo5nQ.vt1RxX8FGGHG8IYIQ6J0vdjRAw=='
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
}
Argument first_name: Provided value 'v1.aesgcm256.23ba68b8.pkemoldaauMZo5nQ.vt1RxX8FGGHG8IYIQ6J0vdjRAw==' of type String on prisma.findManytbl_user is not a SortOrder.
→ Possible values: SortOrder.asc, SortOrder.desc
Here's the debug log:
prisma-field-encryption:decryption Raw result from database: {
prisma-field-encryption:decryption id: 1,
prisma-field-encryption:decryption email: 'v1.aesgcm256.23ba68b8.bbmyY0Q5BsE305dW.d9_gD7LhCfbK7kC1IQNqKg7AHCDZSa6uxL1uaeGm8V68X1I4TdHsPgekq59SdQ==',
prisma-field-encryption:decryption email_Hash: '6cb2b703ca2003f860d7de38ff0e9561aad24f028ef0367fec0f005b655f98f3',
prisma-field-encryption:decryption title_id: 1,
prisma-field-encryption:decryption first_name: 'v1.aesgcm256.23ba68b8.k9WII-p_LfhiMiAQ.yPzxr49mHck-Qx_-UgSWShgI3fjwoA==',
prisma-field-encryption:decryption last_name: 'v1.aesgcm256.23ba68b8.85oljSoT_aAH026W.gly8ICZWPZ2bIaj52Ro6P9WElMyPPbEJDTeg40s=',
prisma-field-encryption:decryption ininitals: 'v1.aesgcm256.23ba68b8.aL4yxVFK4Fizk2Bx.piZxYLjpneocspIEh1TQL_sN',
prisma-field-encryption:decryption password_hash: '$2b$10$zH7enIi7Vkpoayqzhl/J3uYR8IqjY.SBQNcMfqI.2Hvi9FYeEhT.i',
prisma-field-encryption:decryption user_auth_token: '45bbc49e-3855-4f81-a48e-18ec44a72e1a',
prisma-field-encryption:decryption theme_id: 1,
prisma-field-encryption:decryption country_flag: '🇩🇪',
prisma-field-encryption:decryption is_creator: true,
prisma-field-encryption:decryption is_light_theme: false,
prisma-field-encryption:decryption created: 2023-04-11T19:16:01.567Z,
prisma-field-encryption:decryption updated: null,
prisma-field-encryption:decryption deleted: null,
prisma-field-encryption:decryption user_theme: {
prisma-field-encryption:decryption id: 1,
prisma-field-encryption:decryption name: 'skeleton',
prisma-field-encryption:decryption symbol: '💀',
prisma-field-encryption:decryption created: 2023-04-11T19:16:01.510Z,
prisma-field-encryption:decryption updated: null,
prisma-field-encryption:decryption deleted: null
prisma-field-encryption:decryption },
prisma-field-encryption:decryption user_roles: [
prisma-field-encryption:decryption {
prisma-field-encryption:decryption id: 1,
prisma-field-encryption:decryption user_id: 1,
prisma-field-encryption:decryption role_name: 'Superadmin',
prisma-field-encryption:decryption created: 2023-04-11T19:16:01.567Z,
prisma-field-encryption:decryption updated: null,
prisma-field-encryption:decryption deleted: null
prisma-field-encryption:decryption }
prisma-field-encryption:decryption ],
prisma-field-encryption:decryption country: {
prisma-field-encryption:decryption id: 2,
prisma-field-encryption:decryption country_name: 'Germany',
prisma-field-encryption:decryption country_code: 'DE',
prisma-field-encryption:decryption flag: '🇩🇪',
prisma-field-encryption:decryption language: 'de',
prisma-field-encryption:decryption created: 2023-04-11T19:16:01.537Z,
prisma-field-encryption:decryption updated: null,
prisma-field-encryption:decryption deleted: null
prisma-field-encryption:decryption },
prisma-field-encryption:decryption user_title: { id: 1, country_id: 2, title: '' }
prisma-field-encryption:decryption } +25ms
prisma-field-encryption:decryption Visiting {
prisma-field-encryption:decryption field: 'email',
prisma-field-encryption:decryption model: 'tbl_user',
prisma-field-encryption:decryption fieldConfig: {
prisma-field-encryption:decryption encrypt: true,
prisma-field-encryption:decryption strictDecryption: false,
prisma-field-encryption:decryption hash: {
prisma-field-encryption:decryption targetField: 'email_Hash',
prisma-field-encryption:decryption algorithm: 'sha256',
prisma-field-encryption:decryption salt: '=L3eIcvVPL)!',
prisma-field-encryption:decryption inputEncoding: 'utf8',
prisma-field-encryption:decryption outputEncoding: 'hex'
prisma-field-encryption:decryption }
prisma-field-encryption:decryption },
prisma-field-encryption:decryption path: 'email',
prisma-field-encryption:decryption value: 'v1.aesgcm256.23ba68b8.bbmyY0Q5BsE305dW.d9_gD7LhCfbK7kC1IQNqKg7AHCDZSa6uxL1uaeGm8V68X1I4TdHsPgekq59SdQ=='
prisma-field-encryption:decryption } +1ms
prisma-field-encryption:decryption Decrypted tbl_user.email at path `email` using key fingerprint 23ba68b8 +1ms
prisma-field-encryption:decryption Visiting {
prisma-field-encryption:decryption field: 'first_name',
prisma-field-encryption:decryption model: 'tbl_user',
prisma-field-encryption:decryption fieldConfig: { encrypt: true, strictDecryption: false },
prisma-field-encryption:decryption path: 'first_name',
prisma-field-encryption:decryption value: 'v1.aesgcm256.23ba68b8.k9WII-p_LfhiMiAQ.yPzxr49mHck-Qx_-UgSWShgI3fjwoA=='
prisma-field-encryption:decryption } +0ms
prisma-field-encryption:decryption Decrypted tbl_user.first_name at path `first_name` using key fingerprint 23ba68b8 +0ms
prisma-field-encryption:decryption Visiting {
prisma-field-encryption:decryption field: 'last_name',
prisma-field-encryption:decryption model: 'tbl_user',
prisma-field-encryption:decryption fieldConfig: { encrypt: true, strictDecryption: false },
prisma-field-encryption:decryption path: 'last_name',
prisma-field-encryption:decryption value: 'v1.aesgcm256.23ba68b8.85oljSoT_aAH026W.gly8ICZWPZ2bIaj52Ro6P9WElMyPPbEJDTeg40s='
prisma-field-encryption:decryption } +0ms
prisma-field-encryption:decryption Decrypted tbl_user.last_name at path `last_name` using key fingerprint 23ba68b8 +1ms
prisma-field-encryption:decryption Visiting {
prisma-field-encryption:decryption field: 'ininitals',
prisma-field-encryption:decryption model: 'tbl_user',
prisma-field-encryption:decryption fieldConfig: { encrypt: true, strictDecryption: false },
prisma-field-encryption:decryption path: 'ininitals',
prisma-field-encryption:decryption value: 'v1.aesgcm256.23ba68b8.aL4yxVFK4Fizk2Bx.piZxYLjpneocspIEh1TQL_sN'
prisma-field-encryption:decryption } +0ms
prisma-field-encryption:decryption Decrypted tbl_user.ininitals at path `ininitals` using key fingerprint 23ba68b8 +0ms
prisma-field-encryption:decryption Changing model: following connection tbl_user.user_theme to model tbl_theme +0ms
prisma-field-encryption:decryption Changing model: following connection tbl_user.user_roles to model tbl_user_role +0ms
prisma-field-encryption:decryption Changing model: following connection tbl_user.country to model tbl_country +1ms
prisma-field-encryption:decryption Changing model: following connection tbl_user.user_title to model tbl_title +0ms
prisma-field-encryption:decryption Decrypted result: {
prisma-field-encryption:decryption id: 1,
prisma-field-encryption:decryption email: 'ichangedthis@change.com',
prisma-field-encryption:decryption email_Hash: '6cb2b703ca2003f860d7de38ff0e9561aad24f028ef0367fec0f005b655f98f3',
prisma-field-encryption:decryption title_id: 1,
prisma-field-encryption:decryption first_name: 'Changed',
prisma-field-encryption:decryption last_name: 'ChangedChanged',
prisma-field-encryption:decryption ininitals: 'MS',
prisma-field-encryption:decryption password_hash: '$2b$10$zH7enIi7Vkpoayqzhl/J3uYR8IqjY.SBQNcMfqI.2Hvi9FYeEhT.i',
prisma-field-encryption:decryption user_auth_token: '45bbc49e-3855-4f81-a48e-18ec44a72e1a',
prisma-field-encryption:decryption theme_id: 1,
prisma-field-encryption:decryption country_flag: '🇩🇪',
prisma-field-encryption:decryption is_creator: true,
prisma-field-encryption:decryption is_light_theme: false,
prisma-field-encryption:decryption created: 2023-04-11T19:16:01.567Z,
prisma-field-encryption:decryption updated: null,
prisma-field-encryption:decryption deleted: null,
prisma-field-encryption:decryption user_theme: {
prisma-field-encryption:decryption id: 1,
prisma-field-encryption:decryption name: 'skeleton',
prisma-field-encryption:decryption symbol: '💀',
prisma-field-encryption:decryption created: 2023-04-11T19:16:01.510Z,
prisma-field-encryption:decryption updated: null,
prisma-field-encryption:decryption deleted: null
prisma-field-encryption:decryption },
prisma-field-encryption:decryption user_roles: [
prisma-field-encryption:decryption {
prisma-field-encryption:decryption id: 1,
prisma-field-encryption:decryption user_id: 1,
prisma-field-encryption:decryption role_name: 'Superadmin',
prisma-field-encryption:decryption created: 2023-04-11T19:16:01.567Z,
prisma-field-encryption:decryption updated: null,
prisma-field-encryption:decryption deleted: null
prisma-field-encryption:decryption }
prisma-field-encryption:decryption ],
prisma-field-encryption:decryption country: {
prisma-field-encryption:decryption id: 2,
prisma-field-encryption:decryption country_name: 'Germany',
prisma-field-encryption:decryption country_code: 'DE',
prisma-field-encryption:decryption flag: '🇩🇪',
prisma-field-encryption:decryption language: 'de',
prisma-field-encryption:decryption created: 2023-04-11T19:16:01.537Z,
prisma-field-encryption:decryption updated: null,
prisma-field-encryption:decryption deleted: null
prisma-field-encryption:decryption },
prisma-field-encryption:decryption user_title: { id: 1, country_id: 2, title: '' }
prisma-field-encryption:decryption } +0ms
prisma-field-encryption:encryption Clear-text input: {
prisma-field-encryption:encryption args: {
prisma-field-encryption:encryption select: {
prisma-field-encryption:encryption id: true,
prisma-field-encryption:encryption email: true,
prisma-field-encryption:encryption first_name: true,
prisma-field-encryption:encryption last_name: true,
prisma-field-encryption:encryption user_title: true,
prisma-field-encryption:encryption user_roles: true
prisma-field-encryption:encryption },
prisma-field-encryption:encryption take: 25,
prisma-field-encryption:encryption skip: 0,
prisma-field-encryption:encryption orderBy: { first_name: 'asc' }
prisma-field-encryption:encryption },
prisma-field-encryption:encryption dataPath: [],
prisma-field-encryption:encryption runInTransaction: false,
prisma-field-encryption:encryption action: 'findMany',
prisma-field-encryption:encryption model: 'tbl_user'
prisma-field-encryption:encryption } +11ms
prisma-field-encryption:encryption Visiting {
prisma-field-encryption:encryption field: 'first_name',
prisma-field-encryption:encryption model: 'tbl_user',
prisma-field-encryption:encryption fieldConfig: { encrypt: true, strictDecryption: false },
prisma-field-encryption:encryption path: 'orderBy.first_name',
prisma-field-encryption:encryption value: 'asc'
prisma-field-encryption:encryption } +4ms
prisma-field-encryption:encryption Encrypted tbl_user.first_name at path `orderBy.first_name` +1ms
prisma-field-encryption:encryption Encrypted input: {
prisma-field-encryption:encryption args: {
prisma-field-encryption:encryption select: {
prisma-field-encryption:encryption id: true,
prisma-field-encryption:encryption email: true,
prisma-field-encryption:encryption first_name: true,
prisma-field-encryption:encryption last_name: true,
prisma-field-encryption:encryption user_title: true,
prisma-field-encryption:encryption user_roles: true
prisma-field-encryption:encryption },
prisma-field-encryption:encryption take: 25,
prisma-field-encryption:encryption skip: 0,
prisma-field-encryption:encryption orderBy: {
prisma-field-encryption:encryption first_name: 'v1.aesgcm256.23ba68b8.pkemoldaauMZo5nQ.vt1RxX8FGGHG8IYIQ6J0vdjRAw=='
prisma-field-encryption:encryption }
prisma-field-encryption:encryption },
prisma-field-encryption:encryption dataPath: [],
prisma-field-encryption:encryption runInTransaction: false,
prisma-field-encryption:encryption action: 'findMany',
prisma-field-encryption:encryption model: 'tbl_user'
prisma-field-encryption:encryption } +0ms
ERR query users.userTable - 11ms
Thanks for the debug logs, I can see where the problem is now. I'll have to add a special case for the presence of orderBy
in the query, but it will also need to apply this sorting logic not at the database level (which makes no sense as we'd be sorting the ciphertext), but at runtime after decryption.
I'm closing this as "won't fix", as sorting on encrypted values is not something I'd recommend: since the database cannot do the job itself (sorting random ciphertext won't do much good for sorting the underlying clear text data), sorting would have to be done at runtime after decryption, which is another whole can of worms of parsing the query to know what to work on, and play nicely with pagination.
If anyone wishes to tackle this problem, I'll happily review PRs.
In the mean time, attempting to orderBy
on an encrypted field will log an error, and fix the encrypted 'asc' | 'desc' issue so that Prisma doesn't complain (it will actually drop the orderBy
clause).
As for @forbesgillikin and @codewithmecoder, if you're indeed sorting on non-encrypted fields and see this error, please provide me with debug logs so I can have a better idea of what is going on.