mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-08 13:06:15 +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.d.ts
|
||||||
packages/app-cli/app/command-settingschema.js
|
packages/app-cli/app/command-settingschema.js
|
||||||
packages/app-cli/app/command-settingschema.js.map
|
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.d.ts
|
||||||
packages/app-cli/app/command-testing.js
|
packages/app-cli/app/command-testing.js
|
||||||
packages/app-cli/app/command-testing.js.map
|
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.d.ts
|
||||||
packages/app-cli/app/command-settingschema.js
|
packages/app-cli/app/command-settingschema.js
|
||||||
packages/app-cli/app/command-settingschema.js.map
|
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.d.ts
|
||||||
packages/app-cli/app/command-testing.js
|
packages/app-cli/app/command-testing.js
|
||||||
packages/app-cli/app/command-testing.js.map
|
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 Setting from '@joplin/lib/models/Setting';
|
||||||
import shim from '@joplin/lib/shim';
|
import shim from '@joplin/lib/shim';
|
||||||
import * as pathUtils from '@joplin/lib/path-utils';
|
import * as pathUtils from '@joplin/lib/path-utils';
|
||||||
import { getEncryptionEnabled } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
import { getEncryptionEnabled, localSyncInfo } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
||||||
import { generateMasterKeyAndEnableEncryption, loadMasterKeysFromSettings, setupAndDisableEncryption } from '@joplin/lib/services/e2ee/utils';
|
import { generateMasterKeyAndEnableEncryption, loadMasterKeysFromSettings, masterPasswordIsValid, setupAndDisableEncryption } from '@joplin/lib/services/e2ee/utils';
|
||||||
const imageType = require('image-type');
|
const imageType = require('image-type');
|
||||||
const readChunk = require('read-chunk');
|
const readChunk = require('read-chunk');
|
||||||
|
|
||||||
@ -40,6 +40,13 @@ class Command extends BaseCommand {
|
|||||||
this.stdout(_('Operation cancelled'));
|
this.stdout(_('Operation cancelled'));
|
||||||
return false;
|
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);
|
Setting.setObjectValue('encryption.passwordCache', masterKeyId, password);
|
||||||
await loadMasterKeysFromSettings(EncryptionService.instance());
|
await loadMasterKeysFromSettings(EncryptionService.instance());
|
||||||
return true;
|
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 { BaseCommand } = require('./base-command.js');
|
||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('@joplin/lib/locale');
|
|
||||||
const { OneDriveApiNodeUtils } = require('@joplin/lib/onedrive-api-node-utils.js');
|
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 { reg } = require('@joplin/lib/registry.js');
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
const { cliUtils } = require('./cli-utils.js');
|
||||||
const md5 = require('md5');
|
const md5 = require('md5');
|
||||||
const locker = require('proper-lockfile');
|
const locker = require('proper-lockfile');
|
||||||
const fs = require('fs-extra');
|
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 {
|
class Command extends BaseCommand {
|
||||||
constructor() {
|
|
||||||
super();
|
private syncTargetId_: number = null;
|
||||||
this.syncTargetId_ = null;
|
private releaseLockFn_: Function = null;
|
||||||
this.releaseLockFn_ = null;
|
private oneDriveApiUtils_: any = null;
|
||||||
this.oneDriveApiUtils_ = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'sync';
|
return 'sync';
|
||||||
@ -37,9 +36,9 @@ class Command extends BaseCommand {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
static lockFile(filePath) {
|
static lockFile(filePath: string): Promise<Function> {
|
||||||
return new Promise((resolve, reject) => {
|
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) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
return;
|
return;
|
||||||
@ -50,9 +49,9 @@ class Command extends BaseCommand {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static isLocked(filePath) {
|
static isLocked(filePath: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
locker.check(filePath, (error, isLocked) => {
|
locker.check(filePath, (error: any, isLocked: boolean) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
return;
|
return;
|
||||||
@ -71,7 +70,7 @@ class Command extends BaseCommand {
|
|||||||
// OneDrive
|
// OneDrive
|
||||||
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(syncTarget.api());
|
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(syncTarget.api());
|
||||||
const auth = await this.oneDriveApiUtils_.oauthDance({
|
const auth = await this.oneDriveApiUtils_.oauthDance({
|
||||||
log: (...s) => {
|
log: (...s: any[]) => {
|
||||||
return this.stdout(...s);
|
return this.stdout(...s);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -118,7 +117,7 @@ class Command extends BaseCommand {
|
|||||||
return !!this.oneDriveApiUtils_;
|
return !!this.oneDriveApiUtils_;
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args: any) {
|
||||||
this.releaseLockFn_ = null;
|
this.releaseLockFn_ = null;
|
||||||
|
|
||||||
// Lock is unique per profile/database
|
// Lock is unique per profile/database
|
||||||
@ -166,12 +165,12 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
const sync = await syncTarget.synchronizer();
|
const sync = await syncTarget.synchronizer();
|
||||||
|
|
||||||
const options = {
|
const options: any = {
|
||||||
onProgress: report => {
|
onProgress: (report: any) => {
|
||||||
const lines = Synchronizer.reportToLines(report);
|
const lines = Synchronizer.reportToLines(report);
|
||||||
if (lines.length) cliUtils.redraw(lines.join(' '));
|
if (lines.length) cliUtils.redraw(lines.join(' '));
|
||||||
},
|
},
|
||||||
onMessage: msg => {
|
onMessage: (msg: string) => {
|
||||||
cliUtils.redrawDone();
|
cliUtils.redrawDone();
|
||||||
this.stdout(msg);
|
this.stdout(msg);
|
||||||
},
|
},
|
||||||
@ -238,6 +237,9 @@ class Command extends BaseCommand {
|
|||||||
await ResourceFetcher.instance().waitForAllFinished();
|
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();
|
await app().refreshCurrentFolder();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
cleanUp();
|
cleanUp();
|
@ -340,3 +340,17 @@ export async function masterPasswordIsValid(masterPassword: string, activeMaster
|
|||||||
// compare to whatever they've entered earlier.
|
// compare to whatever they've entered earlier.
|
||||||
return Setting.value('encryption.masterPassword') === masterPassword;
|
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