diff --git a/packages/lib/components/shared/note-screen-shared.ts b/packages/lib/components/shared/note-screen-shared.ts index 68eb39e98db..d2b4311289f 100644 --- a/packages/lib/components/shared/note-screen-shared.ts +++ b/packages/lib/components/shared/note-screen-shared.ts @@ -298,7 +298,15 @@ shared.isModified = function(comp: BaseNoteScreenComponent) { shared.reloadNote = async (comp: BaseNoteScreenComponent, useDefaultEditorState = false) => { const isProvisionalNote = comp.props.provisionalNoteIds.includes(comp.props.noteId); - const note = await Note.load(comp.props.noteId); + let note = await Note.load(comp.props.noteId); + if (note?.encryption_cipher_text) { + try { + note = await Note.decrypt(note); + } catch (error) { + reg.logger().info(`Could not decrypt note ${note.id}, note could not be refreshed:`, error.message); + note = null; // fall into the non existent note handling + } + } let mode = comp.state.mode; if (useDefaultEditorState) { diff --git a/packages/lib/services/DecryptionWorker.ts b/packages/lib/services/DecryptionWorker.ts index 76606d02d08..2b886f5c151 100644 --- a/packages/lib/services/DecryptionWorker.ts +++ b/packages/lib/services/DecryptionWorker.ts @@ -1,5 +1,5 @@ import BaseItem, { ItemsThatNeedDecryptionResult } from '../models/BaseItem'; -import BaseModel from '../BaseModel'; +import BaseModel, { ModelType } from '../BaseModel'; import MasterKey from '../models/MasterKey'; import Resource from '../models/Resource'; import ResourceService from './ResourceService'; @@ -219,6 +219,12 @@ export default class DecryptionWorker { await this.kvStore().deleteValue(errorKey); }; + const markSuccessfulDecryption = async (decryptedItemType: number) => { + await clearDecryptionCounter(); + if (!decryptedItemCounts[decryptedItemType]) decryptedItemCounts[decryptedItemType] = 0; + decryptedItemCounts[decryptedItemType]++; + }; + // Don't log in production as it results in many messages when importing many items // this.logger().debug('DecryptionWorker: decrypting: ' + item.id + ' (' + ItemClass.tableName() + ')'); try { @@ -231,13 +237,19 @@ export default class DecryptionWorker { continue; } - const decryptedItem = await ItemClass.decrypt(item); - - await clearDecryptionCounter(); - - if (!decryptedItemCounts[decryptedItem.type_]) decryptedItemCounts[decryptedItem.type_] = 0; + if (item.type_ === ModelType.Note) { + // Validate if still eligible to decrypt using the latest encryption_applied value, as notes may be decrypted on demand while the decryption worker is running. + // If it has been decrypted already, avoid decrypting it again to avoid potentially overwriting it with an outdated version + const encryptionApplied = (await ItemClass.load(item.id, { fields: ['encryption_applied'] }))?.encryption_applied; + if (!encryptionApplied) { + this.logger().info(`DecryptionWorker: Skipping decryption for note ${item.id} as it was already decrypted on demand`); + await markSuccessfulDecryption(item.type_); + continue; + } + } - decryptedItemCounts[decryptedItem.type_]++; + const decryptedItem = await ItemClass.decrypt(item); + await markSuccessfulDecryption(decryptedItem.type_); if (decryptedItem.type_ === Resource.modelType() && !!decryptedItem.encryption_blob_encrypted) { // itemsThatNeedDecryption() will return the resource again if the blob has not been decrypted,