From bcf054fd0868e26a23b64fc47bebfe96e0ec3210 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 24 Sep 2023 16:26:01 +0100 Subject: [PATCH] All: Resolves #6978: Improved handling of invalid sync info --- .../synchronizer/syncInfoUtils.test.ts | 25 +++++++++++++++++-- .../services/synchronizer/syncInfoUtils.ts | 17 +++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/packages/lib/services/synchronizer/syncInfoUtils.test.ts b/packages/lib/services/synchronizer/syncInfoUtils.test.ts index 559684d48..53984df99 100644 --- a/packages/lib/services/synchronizer/syncInfoUtils.test.ts +++ b/packages/lib/services/synchronizer/syncInfoUtils.test.ts @@ -1,6 +1,6 @@ -import { afterAllCleanUp, setupDatabaseAndSynchronizer, switchClient, encryptionService, msleep } from '../../testing/test-utils'; +import { afterAllCleanUp, setupDatabaseAndSynchronizer, logger, switchClient, encryptionService, msleep } from '../../testing/test-utils'; import MasterKey from '../../models/MasterKey'; -import { masterKeyEnabled, mergeSyncInfos, setMasterKeyEnabled, SyncInfo, syncInfoEquals } from './syncInfoUtils'; +import { localSyncInfo, masterKeyEnabled, mergeSyncInfos, saveLocalSyncInfo, setMasterKeyEnabled, SyncInfo, syncInfoEquals } from './syncInfoUtils'; describe('syncInfoUtils', () => { @@ -154,4 +154,25 @@ describe('syncInfoUtils', () => { expect(mergeSyncInfos(syncInfo1, syncInfo2).activeMasterKeyId).toBe('1'); }); + it('should fix the sync info if it contains invalid data', async () => { + logger.enabled = false; + + const syncInfo = new SyncInfo(); + syncInfo.masterKeys = [{ + id: '1', + content: 'content1', + hasBeenUsed: true, + enabled: 0, + }]; + syncInfo.activeMasterKeyId = '2'; + + saveLocalSyncInfo(syncInfo); + + const loaded = localSyncInfo(); + expect(loaded.activeMasterKeyId).toBe(''); + expect(loaded.masterKeys.length).toBe(1); + + logger.enabled = true; + }); + }); diff --git a/packages/lib/services/synchronizer/syncInfoUtils.ts b/packages/lib/services/synchronizer/syncInfoUtils.ts index 863c18e68..f42a39e37 100644 --- a/packages/lib/services/synchronizer/syncInfoUtils.ts +++ b/packages/lib/services/synchronizer/syncInfoUtils.ts @@ -1,3 +1,4 @@ +import Logger from '@joplin/utils/Logger'; import { FileApi } from '../../file-api'; import JoplinDatabase from '../../JoplinDatabase'; import Setting from '../../models/Setting'; @@ -6,6 +7,8 @@ import { PublicPrivateKeyPair } from '../e2ee/ppk'; import { MasterKeyEntity } from '../e2ee/types'; const fastDeepEqual = require('fast-deep-equal'); +const logger = Logger.create('syncInfoUtils'); + export interface SyncInfoValueBoolean { value: boolean; updatedTime: number; @@ -75,15 +78,25 @@ export async function fetchSyncInfo(api: FileApi): Promise { if (oldVersion) output = { version: 1 }; } - return new SyncInfo(JSON.stringify(output)); + return fixSyncInfo(new SyncInfo(JSON.stringify(output))); } export function saveLocalSyncInfo(syncInfo: SyncInfo) { Setting.setValue('syncInfoCache', syncInfo.serialize()); } +const fixSyncInfo = (syncInfo: SyncInfo) => { + if (syncInfo.activeMasterKeyId) { + if (!syncInfo.masterKeys || !syncInfo.masterKeys.find(mk => mk.id === syncInfo.activeMasterKeyId)) { + logger.warn(`Sync info is using a non-existent key as the active key - clearing it: ${syncInfo.activeMasterKeyId}`); + syncInfo.activeMasterKeyId = ''; + } + } + return syncInfo; +}; + export function localSyncInfo(): SyncInfo { - return new SyncInfo(Setting.value('syncInfoCache')); + return fixSyncInfo(new SyncInfo(Setting.value('syncInfoCache'))); } export function localSyncInfoFromState(state: State): SyncInfo {