1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-06-27 23:28:38 +02:00

All: Improved E2EE usability by making its state a property of the sync target (#5276)

This commit is contained in:
Laurent
2021-08-12 16:54:10 +01:00
committed by GitHub
parent ba3cbfa051
commit dcd5a8d975
102 changed files with 1775 additions and 551 deletions

View File

@ -10,6 +10,8 @@ import MasterKey from '../../models/MasterKey';
import BaseItem from '../../models/BaseItem';
import { ResourceEntity } from '../database/types';
import Synchronizer from '../../Synchronizer';
import { getEncryptionEnabled, setEncryptionEnabled } from '../synchronizer/syncInfoUtils';
import { loadMasterKeysFromSettings, setupAndDisableEncryption, setupAndEnableEncryption } from '../e2ee/utils';
let insideBeforeEach = false;
@ -31,7 +33,7 @@ describe('Synchronizer.e2ee', function() {
});
it('notes and folders should get encrypted when encryption is enabled', (async () => {
Setting.setValue('encryption.enabled', true);
setEncryptionEnabled(true);
const masterKey = await loadEncryptionMasterKey();
const folder1 = await Folder.save({ title: 'folder1' });
let note1 = await Note.save({ title: 'un', body: 'to be encrypted', parent_id: folder1.id });
@ -55,7 +57,7 @@ describe('Synchronizer.e2ee', function() {
expect(masterKey_2.content).toBe(masterKey.content);
expect(masterKey_2.checksum).toBe(masterKey.checksum);
// Now load the master key we got from client 1 and try to decrypt
await encryptionService().loadMasterKey_(masterKey_2, '123456', true);
await encryptionService().loadMasterKey(masterKey_2, '123456', true);
// Get the decrypted items back
await Folder.decrypt(folder1_2);
await Note.decrypt(note1_2);
@ -74,7 +76,7 @@ describe('Synchronizer.e2ee', function() {
it('should enable encryption automatically when downloading new master key (and none was previously available)',(async () => {
// Enable encryption on client 1 and sync an item
Setting.setValue('encryption.enabled', true);
setEncryptionEnabled(true);
await loadEncryptionMasterKey();
let folder1 = await Folder.save({ title: 'folder1' });
await synchronizerStart();
@ -82,9 +84,9 @@ describe('Synchronizer.e2ee', function() {
await switchClient(2);
// Synchronising should enable encryption since we're going to get a master key
expect(Setting.value('encryption.enabled')).toBe(false);
expect(getEncryptionEnabled()).toBe(false);
await synchronizerStart();
expect(Setting.value('encryption.enabled')).toBe(true);
expect(getEncryptionEnabled()).toBe(true);
// Check that we got the master key from client 1
const masterKey = (await MasterKey.all())[0];
@ -109,7 +111,7 @@ describe('Synchronizer.e2ee', function() {
// Now client 2 set the master key password
Setting.setObjectValue('encryption.passwordCache', masterKey.id, '123456');
await encryptionService().loadMasterKeysFromSettings();
await loadMasterKeysFromSettings(encryptionService());
// Now that master key should be loaded
expect(encryptionService().loadedMasterKeyIds()[0]).toBe(masterKey.id);
@ -141,24 +143,22 @@ describe('Synchronizer.e2ee', function() {
// Then enable encryption and sync again
let masterKey = await encryptionService().generateMasterKey('123456');
masterKey = await MasterKey.save(masterKey);
await encryptionService().enableEncryption(masterKey, '123456');
await encryptionService().loadMasterKeysFromSettings();
await setupAndEnableEncryption(encryptionService(), masterKey, '123456');
await loadMasterKeysFromSettings(encryptionService());
await synchronizerStart();
// Even though the folder has not been changed it should have been synced again so that
// an encrypted version of it replaces the decrypted version.
files = await fileApi().list('', { includeDirs: false, syncItemsOnly: true });
expect(files.items.length).toBe(2);
expect(files.items.length).toBe(1);
// By checking that the folder title is not present, we can confirm that the item has indeed been encrypted
// One of the two items is the master key
content = await fileApi().get(files.items[0].path);
expect(content.indexOf('folder1') < 0).toBe(true);
content = await fileApi().get(files.items[1].path);
expect(content.indexOf('folder1') < 0).toBe(true);
}));
it('should upload decrypted items to sync target after encryption disabled', (async () => {
Setting.setValue('encryption.enabled', true);
setEncryptionEnabled(true);
await loadEncryptionMasterKey();
await Folder.save({ title: 'folder1' });
@ -167,7 +167,7 @@ describe('Synchronizer.e2ee', function() {
let allEncrypted = await allSyncTargetItemsEncrypted();
expect(allEncrypted).toBe(true);
await encryptionService().disableEncryption();
await setupAndDisableEncryption(encryptionService());
await synchronizerStart();
allEncrypted = await allSyncTargetItemsEncrypted();
@ -179,7 +179,7 @@ describe('Synchronizer.e2ee', function() {
// which means it's going to fail in unexpected way. So the loop below wait for beforeEach to be done.
while (insideBeforeEach) await time.msleep(100);
Setting.setValue('encryption.enabled', true);
setEncryptionEnabled(true);
const masterKey = await loadEncryptionMasterKey();
await Folder.save({ title: 'folder1' });
@ -188,21 +188,21 @@ describe('Synchronizer.e2ee', function() {
await switchClient(2);
await synchronizerStart();
expect(Setting.value('encryption.enabled')).toBe(true);
expect(getEncryptionEnabled()).toBe(true);
// If we try to disable encryption now, it should throw an error because some items are
// currently encrypted. They must be decrypted first so that they can be sent as
// plain text to the sync target.
// let hasThrown = await checkThrowAsync(async () => await encryptionService().disableEncryption());
// let hasThrown = await checkThrowAsync(async () => await setupAndDisableEncryption(encryptionService()));
// expect(hasThrown).toBe(true);
// Now supply the password, and decrypt the items
Setting.setObjectValue('encryption.passwordCache', masterKey.id, '123456');
await encryptionService().loadMasterKeysFromSettings();
await loadMasterKeysFromSettings(encryptionService());
await decryptionWorker().start();
// Try to disable encryption again
const hasThrown = await checkThrowAsync(async () => await encryptionService().disableEncryption());
const hasThrown = await checkThrowAsync(async () => await setupAndDisableEncryption(encryptionService()));
expect(hasThrown).toBe(false);
// If we sync now the target should receive the decrypted items
@ -212,7 +212,7 @@ describe('Synchronizer.e2ee', function() {
}));
it('should set the resource file size after decryption', (async () => {
Setting.setValue('encryption.enabled', true);
setEncryptionEnabled(true);
const masterKey = await loadEncryptionMasterKey();
const folder1 = await Folder.save({ title: 'folder1' });
@ -227,7 +227,7 @@ describe('Synchronizer.e2ee', function() {
await synchronizerStart();
Setting.setObjectValue('encryption.passwordCache', masterKey.id, '123456');
await encryptionService().loadMasterKeysFromSettings();
await loadMasterKeysFromSettings(encryptionService());
const fetcher = newResourceFetcher(synchronizer());
fetcher.queueDownload_(resource1.id);
@ -249,8 +249,8 @@ describe('Synchronizer.e2ee', function() {
expect(await allSyncTargetItemsEncrypted()).toBe(false);
const masterKey = await loadEncryptionMasterKey();
await encryptionService().enableEncryption(masterKey, '123456');
await encryptionService().loadMasterKeysFromSettings();
await setupAndEnableEncryption(encryptionService(), masterKey, '123456');
await loadMasterKeysFromSettings(encryptionService());
await synchronizerStart();
@ -264,20 +264,20 @@ describe('Synchronizer.e2ee', function() {
const note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
await shim.attachFileToNote(note1, `${supportDir}/photo.jpg`);
const masterKey = await loadEncryptionMasterKey();
await encryptionService().enableEncryption(masterKey, '123456');
await encryptionService().loadMasterKeysFromSettings();
await synchronizerStart();
await setupAndEnableEncryption(encryptionService(), masterKey, '123456');
await loadMasterKeysFromSettings(encryptionService());
// await synchronizerStart();
const resource1 = (await Resource.all())[0];
expect(resource1.encryption_blob_encrypted).toBe(0);
// const resource1 = (await Resource.all())[0];
// expect(resource1.encryption_blob_encrypted).toBe(0);
}));
it('should decrypt the resource metadata, but not try to decrypt the file, if it is not present', (async () => {
const note1 = await Note.save({ title: 'note' });
await shim.attachFileToNote(note1, `${supportDir}/photo.jpg`);
const masterKey = await loadEncryptionMasterKey();
await encryptionService().enableEncryption(masterKey, '123456');
await encryptionService().loadMasterKeysFromSettings();
await setupAndEnableEncryption(encryptionService(), masterKey, '123456');
await loadMasterKeysFromSettings(encryptionService());
await synchronizerStart();
expect(await allSyncTargetItemsEncrypted()).toBe(true);
@ -285,7 +285,7 @@ describe('Synchronizer.e2ee', function() {
await synchronizerStart();
Setting.setObjectValue('encryption.passwordCache', masterKey.id, '123456');
await encryptionService().loadMasterKeysFromSettings();
await loadMasterKeysFromSettings(encryptionService());
await decryptionWorker().start();
let resource = (await Resource.all())[0];
@ -311,8 +311,8 @@ describe('Synchronizer.e2ee', function() {
const note = await Note.save({ title: 'ma note' });
const masterKey = await loadEncryptionMasterKey();
await encryptionService().enableEncryption(masterKey, '123456');
await encryptionService().loadMasterKeysFromSettings();
await setupAndEnableEncryption(encryptionService(), masterKey, '123456');
await loadMasterKeysFromSettings(encryptionService());
await synchronizerStart();
await switchClient(2);
@ -329,7 +329,7 @@ describe('Synchronizer.e2ee', function() {
await Note.save({ id: note.id, encryption_cipher_text: 'doesntlookright' });
Setting.setObjectValue('encryption.passwordCache', masterKey.id, '123456');
await encryptionService().loadMasterKeysFromSettings();
await loadMasterKeysFromSettings(encryptionService());
hasThrown = await checkThrowAsync(async () => await decryptionWorker().start({ errorHandler: 'throw' }));
expect(hasThrown).toBe(true);
@ -367,7 +367,7 @@ describe('Synchronizer.e2ee', function() {
}));
it('should not encrypt notes that are shared by link', (async () => {
Setting.setValue('encryption.enabled', true);
setEncryptionEnabled(true);
await loadEncryptionMasterKey();
await createFolderTree('', [
@ -459,7 +459,7 @@ describe('Synchronizer.e2ee', function() {
return;
}
Setting.setValue('encryption.enabled', true);
setEncryptionEnabled(true);
await loadEncryptionMasterKey();
const folder1 = await createFolderTree('', [