mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-21 09:38:01 +02:00
Cli: Ask for master password when encryption or decryption fails
This commit is contained in:
parent
0e11273c45
commit
c19e59f5da
@ -78,6 +78,9 @@ packages/app-cli/app/command-e2ee.js.map
|
||||
packages/app-cli/app/command-settingschema.d.ts
|
||||
packages/app-cli/app/command-settingschema.js
|
||||
packages/app-cli/app/command-settingschema.js.map
|
||||
packages/app-cli/app/command-sync.d.ts
|
||||
packages/app-cli/app/command-sync.js
|
||||
packages/app-cli/app/command-sync.js.map
|
||||
packages/app-cli/app/command-testing.d.ts
|
||||
packages/app-cli/app/command-testing.js
|
||||
packages/app-cli/app/command-testing.js.map
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -61,6 +61,9 @@ packages/app-cli/app/command-e2ee.js.map
|
||||
packages/app-cli/app/command-settingschema.d.ts
|
||||
packages/app-cli/app/command-settingschema.js
|
||||
packages/app-cli/app/command-settingschema.js.map
|
||||
packages/app-cli/app/command-sync.d.ts
|
||||
packages/app-cli/app/command-sync.js
|
||||
packages/app-cli/app/command-sync.js.map
|
||||
packages/app-cli/app/command-testing.d.ts
|
||||
packages/app-cli/app/command-testing.js
|
||||
packages/app-cli/app/command-testing.js.map
|
||||
|
@ -6,8 +6,8 @@ import BaseItem from '@joplin/lib/models/BaseItem';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import * as pathUtils from '@joplin/lib/path-utils';
|
||||
import { getEncryptionEnabled } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
||||
import { generateMasterKeyAndEnableEncryption, loadMasterKeysFromSettings, setupAndDisableEncryption } from '@joplin/lib/services/e2ee/utils';
|
||||
import { getEncryptionEnabled, localSyncInfo } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
||||
import { generateMasterKeyAndEnableEncryption, loadMasterKeysFromSettings, masterPasswordIsValid, setupAndDisableEncryption } from '@joplin/lib/services/e2ee/utils';
|
||||
const imageType = require('image-type');
|
||||
const readChunk = require('read-chunk');
|
||||
|
||||
@ -40,6 +40,13 @@ class Command extends BaseCommand {
|
||||
this.stdout(_('Operation cancelled'));
|
||||
return false;
|
||||
}
|
||||
|
||||
const masterKey = localSyncInfo().masterKeys.find(mk => mk.id === masterKeyId);
|
||||
if (!(await masterPasswordIsValid(password, masterKey))) {
|
||||
this.stdout(_('Invalid password'));
|
||||
return false;
|
||||
}
|
||||
|
||||
Setting.setObjectValue('encryption.passwordCache', masterKeyId, password);
|
||||
await loadMasterKeysFromSettings(EncryptionService.instance());
|
||||
return true;
|
||||
|
@ -1,25 +1,24 @@
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
|
||||
import MigrationHandler from '@joplin/lib/services/synchronizer/MigrationHandler';
|
||||
import ResourceFetcher from '@joplin/lib/services/ResourceFetcher';
|
||||
import Synchronizer from '@joplin/lib/Synchronizer';
|
||||
import { masterKeysWithoutPassword } from '@joplin/lib/services/e2ee/utils';
|
||||
const { BaseCommand } = require('./base-command.js');
|
||||
const { app } = require('./app.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const { OneDriveApiNodeUtils } = require('@joplin/lib/onedrive-api-node-utils.js');
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const ResourceFetcher = require('@joplin/lib/services/ResourceFetcher').default;
|
||||
const Synchronizer = require('@joplin/lib/Synchronizer').default;
|
||||
const { reg } = require('@joplin/lib/registry.js');
|
||||
const { cliUtils } = require('./cli-utils.js');
|
||||
const md5 = require('md5');
|
||||
const locker = require('proper-lockfile');
|
||||
const fs = require('fs-extra');
|
||||
const SyncTargetRegistry = require('@joplin/lib/SyncTargetRegistry').default;
|
||||
const MigrationHandler = require('@joplin/lib/services/synchronizer/MigrationHandler').default;
|
||||
|
||||
class Command extends BaseCommand {
|
||||
constructor() {
|
||||
super();
|
||||
this.syncTargetId_ = null;
|
||||
this.releaseLockFn_ = null;
|
||||
this.oneDriveApiUtils_ = null;
|
||||
}
|
||||
|
||||
private syncTargetId_: number = null;
|
||||
private releaseLockFn_: Function = null;
|
||||
private oneDriveApiUtils_: any = null;
|
||||
|
||||
usage() {
|
||||
return 'sync';
|
||||
@ -37,9 +36,9 @@ class Command extends BaseCommand {
|
||||
];
|
||||
}
|
||||
|
||||
static lockFile(filePath) {
|
||||
static lockFile(filePath: string): Promise<Function> {
|
||||
return new Promise((resolve, reject) => {
|
||||
locker.lock(filePath, { stale: 1000 * 60 * 5 }, (error, release) => {
|
||||
locker.lock(filePath, { stale: 1000 * 60 * 5 }, (error: any, release: any) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
@ -50,9 +49,9 @@ class Command extends BaseCommand {
|
||||
});
|
||||
}
|
||||
|
||||
static isLocked(filePath) {
|
||||
static isLocked(filePath: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
locker.check(filePath, (error, isLocked) => {
|
||||
locker.check(filePath, (error: any, isLocked: boolean) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
@ -71,7 +70,7 @@ class Command extends BaseCommand {
|
||||
// OneDrive
|
||||
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(syncTarget.api());
|
||||
const auth = await this.oneDriveApiUtils_.oauthDance({
|
||||
log: (...s) => {
|
||||
log: (...s: any[]) => {
|
||||
return this.stdout(...s);
|
||||
},
|
||||
});
|
||||
@ -118,7 +117,7 @@ class Command extends BaseCommand {
|
||||
return !!this.oneDriveApiUtils_;
|
||||
}
|
||||
|
||||
async action(args) {
|
||||
async action(args: any) {
|
||||
this.releaseLockFn_ = null;
|
||||
|
||||
// Lock is unique per profile/database
|
||||
@ -166,12 +165,12 @@ class Command extends BaseCommand {
|
||||
|
||||
const sync = await syncTarget.synchronizer();
|
||||
|
||||
const options = {
|
||||
onProgress: report => {
|
||||
const options: any = {
|
||||
onProgress: (report: any) => {
|
||||
const lines = Synchronizer.reportToLines(report);
|
||||
if (lines.length) cliUtils.redraw(lines.join(' '));
|
||||
},
|
||||
onMessage: msg => {
|
||||
onMessage: (msg: string) => {
|
||||
cliUtils.redrawDone();
|
||||
this.stdout(msg);
|
||||
},
|
||||
@ -238,6 +237,9 @@ class Command extends BaseCommand {
|
||||
await ResourceFetcher.instance().waitForAllFinished();
|
||||
}
|
||||
|
||||
const noPasswordMkIds = await masterKeysWithoutPassword();
|
||||
if (noPasswordMkIds.length) this.stdout(`/!\\ ${_('Your password is needed to decrypt some of your data. Type `:e2ee decrypt` to set it.')}`);
|
||||
|
||||
await app().refreshCurrentFolder();
|
||||
} catch (error) {
|
||||
cleanUp();
|
@ -340,3 +340,17 @@ export async function masterPasswordIsValid(masterPassword: string, activeMaster
|
||||
// compare to whatever they've entered earlier.
|
||||
return Setting.value('encryption.masterPassword') === masterPassword;
|
||||
}
|
||||
|
||||
export async function masterKeysWithoutPassword(): Promise<string[]> {
|
||||
const syncInfo = localSyncInfo();
|
||||
const passwordCache = Setting.value('encryption.passwordCache');
|
||||
|
||||
const output: string[] = [];
|
||||
for (const mk of syncInfo.masterKeys) {
|
||||
if (!masterKeyEnabled(mk)) continue;
|
||||
const password = await findMasterKeyPassword(EncryptionService.instance(), mk, passwordCache);
|
||||
if (!password) output.push(mk.id);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user