一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
94 行
3.7 KiB
TypeScript
94 行
3.7 KiB
TypeScript
import Setting from '../../models/Setting';
|
|
import shim from '../../shim';
|
|
import { encryptionService, setupDatabaseAndSynchronizer, switchClient } from '../../testing/test-utils';
|
|
import EncryptionService from '../e2ee/EncryptionService';
|
|
import NoteLockKey from './NoteLockKey';
|
|
import NoteLockService from './NoteLockService';
|
|
import NoteLockSession from './NoteLockSession';
|
|
import { promptForImportedNoteLockKey } from './noteLockPrompts';
|
|
import { ErrorCode } from '../../errors';
|
|
|
|
const makePrompts = (passwords: (string|null)[]) => ({
|
|
promptPassword: jest.fn(async () => passwords.shift() ?? null),
|
|
goToNoteLockSetup: jest.fn(),
|
|
});
|
|
|
|
describe('noteLockPrompts', () => {
|
|
|
|
beforeEach(async () => {
|
|
await setupDatabaseAndSynchronizer(1);
|
|
await switchClient(1);
|
|
NoteLockService.destroyInstance();
|
|
NoteLockSession.destroyInstance();
|
|
NoteLockKey.destroyInstance();
|
|
EncryptionService.instance_ = encryptionService();
|
|
Setting.setValue('featureFlag.noteLock', true);
|
|
shim.showErrorDialog = jest.fn(async () => {});
|
|
});
|
|
|
|
const otherBackupKey = async () => ({ ...await encryptionService().generateMasterKey('backup'), id: 'backup' });
|
|
|
|
// Answers the dialogs in order: the "update them?" question (0 Yes, 1 No, 2 Cancel), then the setup question (0 Yes, 1 No).
|
|
const answer = (...responses: number[]) => {
|
|
shim.showMessageBox = jest.fn(async () => responses.shift());
|
|
};
|
|
|
|
it('should import a backup of this profile as it is, without any prompt', async () => {
|
|
const key = await NoteLockKey.instance().create('local');
|
|
answer(0);
|
|
const prompts = makePrompts([]);
|
|
|
|
expect(await promptForImportedNoteLockKey(key, prompts)).toBeNull();
|
|
expect(shim.showMessageBox).not.toHaveBeenCalled();
|
|
expect(prompts.promptPassword).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should unlock the session, then decrypt the key of a backup from another profile', async () => {
|
|
const backupKey = await otherBackupKey();
|
|
await NoteLockKey.instance().create('local');
|
|
answer(0);
|
|
const prompts = makePrompts(['local', 'wrong', 'backup']);
|
|
|
|
expect((await promptForImportedNoteLockKey(backupKey, prompts)).id).toBe(backupKey.id);
|
|
expect(NoteLockSession.instance().isUnlocked()).toBe(true);
|
|
expect(prompts.promptPassword).toHaveBeenNthCalledWith(1, 'Enter your current note lock password');
|
|
expect(shim.showErrorDialog).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should import unchanged when the user does not want to update the notes', async () => {
|
|
const backupKey = await otherBackupKey();
|
|
await NoteLockKey.instance().create('local');
|
|
answer(1);
|
|
const prompts = makePrompts([]);
|
|
|
|
expect(await promptForImportedNoteLockKey(backupKey, prompts)).toBeNull();
|
|
expect(prompts.promptPassword).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it.each([
|
|
['the question', []],
|
|
['the current password', [null]],
|
|
['the backup password', ['local', null]],
|
|
])('should cancel the import when %s is cancelled', async (_step, passwords: (string|null)[]) => {
|
|
const backupKey = await otherBackupKey();
|
|
await NoteLockKey.instance().create('local');
|
|
answer(passwords.length ? 0 : 2);
|
|
|
|
await expect(promptForImportedNoteLockKey(backupKey, makePrompts(passwords))).rejects.toMatchObject({ code: ErrorCode.Cancelled });
|
|
});
|
|
|
|
it.each([
|
|
['opens the note lock setup', true],
|
|
['does not', false],
|
|
])('should cancel the import when no note lock key is set up and the user %s', async (_label, opensSetup) => {
|
|
const backupKey = await otherBackupKey();
|
|
answer(0, opensSetup ? 0 : 1);
|
|
const prompts = makePrompts([]);
|
|
|
|
await expect(promptForImportedNoteLockKey(backupKey, prompts)).rejects.toMatchObject({ code: ErrorCode.Cancelled });
|
|
expect(prompts.goToNoteLockSetup).toHaveBeenCalledTimes(opensSetup ? 1 : 0);
|
|
expect(prompts.promptPassword).not.toHaveBeenCalled();
|
|
});
|
|
|
|
});
|