From 610717ecc0de0108150e08fc0ff907ef4fe06174 Mon Sep 17 00:00:00 2001 From: steunix Date: Sat, 9 Aug 2025 16:47:36 +0200 Subject: [PATCH] Item decryption: avoid to read item from db unnecessarily Fixes #339 --- api/v1/controllers/items.mjs | 21 ++++++++++++--------- api/v1/controllers/onetimetokens.mjs | 15 ++++++++++----- model/item.mjs | 22 ++++------------------ 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/api/v1/controllers/items.mjs b/api/v1/controllers/items.mjs index 976c3d6..f837b15 100644 --- a/api/v1/controllers/items.mjs +++ b/api/v1/controllers/items.mjs @@ -106,7 +106,7 @@ export async function get (req, res, next) { // Decrypt content try { - item.data = await Item.decrypt(itemid, req) + item.data = await Item.decrypt(item, req) } catch (e) { res.status(R.UNPROCESSABLE_ENTITY).send(R.ko('This item is corrupted and cannot be decrypted')) return @@ -482,20 +482,23 @@ export async function update (req, res, next) { } } - // Recalculate the data - let encData - const updateStruct = {} + // Check if the new folder is personal let newIsPersonal = item.personal if (folderFromURL) { // If the folder is changing, check if the new folder is personal newIsPersonal = await Folder.isPersonal(folderFromURL) } + + // Reencrypt the data + const updateStruct = {} let newData + let encData + + // If data is given, use it, otherwise decrypt the current data if (req.body?.data) { newData = req.body.data } else { - // If no data is given, decrypt the current data - newData = await Item.decrypt(itemid, req) + newData = await Item.decrypt(item, req) } // Encrypt according to the new folder @@ -527,7 +530,7 @@ export async function update (req, res, next) { updateStruct.type = req.body.type || null } - // Check if something has changed + // Check if something has changed in non encrypted fields const changedFields = [] if (updateStruct?.title && updateStruct.title !== item.title) { changedFields.push('title') @@ -544,7 +547,7 @@ export async function update (req, res, next) { // Check what has changed in data if (req.body?.data) { - const decData = await Item.decrypt(itemid, req) + const decData = await Item.decrypt(item, req) if (decData !== req.body.data) { // If JSON, check all properties for changes const olddata = JSON.parse(decData) @@ -721,7 +724,7 @@ export async function clone (req, res, next) { } // Reencrypt data - const oldData = await Item.decrypt(itemid, req) + const oldData = await Item.decrypt(item, req) let newData if (item.personal) { newData = await Item.encrypt(oldData, req.user, req.personaltoken) diff --git a/api/v1/controllers/onetimetokens.mjs b/api/v1/controllers/onetimetokens.mjs index a08fee0..b462b70 100644 --- a/api/v1/controllers/onetimetokens.mjs +++ b/api/v1/controllers/onetimetokens.mjs @@ -13,7 +13,7 @@ import * as Config from '../../../lib/config.mjs' import * as Events from '../../../lib/event.mjs' import * as Const from '../../../lib/const.mjs' import * as JV from '../../../lib/jsonvalidator.mjs' -import * as Items from '../../../model/item.mjs' +import * as Item from '../../../model/item.mjs' import * as KMS from '../../../lib/kms/kms.mjs' import * as Metrics from '../../../lib/metrics.mjs' @@ -98,16 +98,21 @@ export async function get (req, res, next) { if (ottoken.type === 1) { // Get item relevant fields const item = await DB.items.findUnique({ - where: { id: ottoken.itemid }, - select: { id: true, type: true, title: true } + where: { id: ottoken.itemid } }) if (item === null) { res.status(R.NOT_FOUND).send(R.ko('Item not found')) return } - item.data = await Items.decrypt(ottoken.itemid, req) + item.data = await Item.decrypt(item, req) - resp.item = Crypt.encryptedPayload(key, JSON.stringify(item)) + const retpayload = { + id: item.id, + title: item.title, + type: item.type, + data: item.data + } + resp.item = Crypt.encryptedPayload(key, JSON.stringify(retpayload)) } // Delete token diff --git a/model/item.mjs b/model/item.mjs index a75ff79..60d4bf7 100644 --- a/model/item.mjs +++ b/model/item.mjs @@ -43,25 +43,11 @@ export async function updateFTS (id) { /** * Decrypt user data - * @param {string} itemid Item ID - * @param {object} req Express request - * @returns {string} Decrypted data + * @param {Object} item Item db record + * @param {Object} req Express request + * @returns {string} Decrypted data, base64 encoded */ -export async function decrypt (itemid, req) { - // Search item - const item = await DB.items.findUniqueOrThrow({ - where: { id: itemid }, - select: { - data: true, - dataiv: true, - dataauthtag: true, - algo: true, - personal: true, - kmsid: true, - dek: true - } - }) - +export async function decrypt (item, req) { let data data = await KMS.decrypt(item.kmsid, item.dek, item.data, item.dataiv, item.dataauthtag, item.algo)