一些检查失败了
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
70 行
2.8 KiB
TypeScript
70 行
2.8 KiB
TypeScript
import { _ } from '../../locale';
|
|
import JoplinError from '../../JoplinError';
|
|
import { ErrorCode } from '../../errors';
|
|
import shim from '../../shim';
|
|
import { MasterKeyEntity } from '../e2ee/types';
|
|
import NoteLockKey, { DecryptedNoteLockKey } from './NoteLockKey';
|
|
import NoteLockSession from './NoteLockSession';
|
|
|
|
// Shared by desktop and mobile, which each supply their own password prompt and settings navigation.
|
|
export interface NoteLockPrompts {
|
|
promptPassword: (label: string)=> Promise<string|null>;
|
|
goToNoteLockSetup: ()=> void;
|
|
}
|
|
|
|
const promptNoteLockSetup = async (prompts: NoteLockPrompts) => {
|
|
const answer = await shim.showMessageBox(_('A note lock key is required to update these notes, but hasn\'t been set up yet on your profile. Would you like to set one up now?'), {
|
|
buttons: [_('Yes'), _('No')],
|
|
cancelId: 1,
|
|
});
|
|
if (answer === 0) {
|
|
prompts.goToNoteLockSetup();
|
|
}
|
|
};
|
|
|
|
const cancelled = () => new JoplinError('Cancelled', ErrorCode.Cancelled);
|
|
|
|
// Returns false when the user cancels or has no note lock password to unlock with.
|
|
export const unlockNoteLockSession = async (prompts: NoteLockPrompts) => {
|
|
if (!NoteLockKey.instance().load()) {
|
|
await promptNoteLockSetup(prompts);
|
|
return false;
|
|
}
|
|
|
|
while (!NoteLockSession.instance().isUnlocked()) {
|
|
const password = await prompts.promptPassword(_('Enter your current note lock password'));
|
|
if (!password) return false;
|
|
try {
|
|
await NoteLockSession.instance().unlock(password);
|
|
} catch {
|
|
await shim.showErrorDialog(_('Invalid password'));
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
// Returns the backup's key decrypted, to re-encrypt its locked notes for this profile, or null to import them unchanged.
|
|
// Throws a cancelled error when the user cancels any step, so the whole import stops.
|
|
export const promptForImportedNoteLockKey = async (backupKey: MasterKeyEntity, prompts: NoteLockPrompts): Promise<DecryptedNoteLockKey|null> => {
|
|
// Already under the profile's key, so the notes need no update.
|
|
if (backupKey.id === NoteLockKey.instance().load()?.id) return null;
|
|
|
|
const answer = await shim.showMessageBox(_('This backup contains notes locked with a different key. They must be updated now to use your current key, or they\'ll remain inaccessible and cannot be updated later. Would you like to update them?'), {
|
|
buttons: [_('Yes'), _('No'), _('Cancel')],
|
|
cancelId: 2,
|
|
});
|
|
if (answer === 1) return null;
|
|
if (answer !== 0) throw cancelled();
|
|
if (!await unlockNoteLockSession(prompts)) throw cancelled();
|
|
|
|
while (true) {
|
|
const password = await prompts.promptPassword(_('Enter the note lock password the backup was created with'));
|
|
if (!password) throw cancelled();
|
|
try {
|
|
return await NoteLockKey.instance().decrypt(password, backupKey);
|
|
} catch {
|
|
await shim.showErrorDialog(_('Invalid password'));
|
|
}
|
|
}
|
|
};
|