1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-04-04 21:35:03 +02:00

Cli: Fixes #2981: Add support for retrying decryption after it has failed multiple times

This commit is contained in:
Laurent Cozic 2020-04-08 18:02:31 +01:00
parent a6459d3641
commit 7ccd19e21d
7 changed files with 54 additions and 29 deletions

View File

@ -24,12 +24,11 @@ class Command extends BaseCommand {
['-p, --password <password>', 'Use this password as master password (For security reasons, it is not recommended to use this option).'], ['-p, --password <password>', 'Use this password as master password (For security reasons, it is not recommended to use this option).'],
['-v, --verbose', 'More verbose output for the `target-status` command'], ['-v, --verbose', 'More verbose output for the `target-status` command'],
['-o, --output <directory>', 'Output directory'], ['-o, --output <directory>', 'Output directory'],
['--retry-failed-items', 'Applies to `decrypt` command - retries decrypting items that previously could not be decrypted.'],
]; ];
} }
async action(args) { async action(args) {
// change-password
const options = args.options; const options = args.options;
const askForMasterKey = async error => { const askForMasterKey = async error => {
@ -44,6 +43,27 @@ class Command extends BaseCommand {
return true; return true;
}; };
const startDecryption = async () => {
this.stdout(_('Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.'));
while (true) {
try {
await DecryptionWorker.instance().start();
break;
} catch (error) {
if (error.code === 'masterKeyNotLoaded') {
const ok = await askForMasterKey(error);
if (!ok) return;
continue;
}
throw error;
}
}
this.stdout(_('Completed decryption.'));
};
if (args.command === 'enable') { if (args.command === 'enable') {
const password = options.password ? options.password.toString() : await this.prompt(_('Enter master password:'), { type: 'string', secure: true }); const password = options.password ? options.password.toString() : await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
if (!password) { if (!password) {
@ -73,24 +93,8 @@ class Command extends BaseCommand {
const plainText = await EncryptionService.instance().decryptString(args.path); const plainText = await EncryptionService.instance().decryptString(args.path);
this.stdout(plainText); this.stdout(plainText);
} else { } else {
this.stdout(_('Starting decryption... Please wait as it may take several minutes depending on how much there is to decrypt.')); if (args.options['retry-failed-items']) await DecryptionWorker.instance().clearDisabledItems();
await startDecryption();
while (true) {
try {
await DecryptionWorker.instance().start();
break;
} catch (error) {
if (error.code === 'masterKeyNotLoaded') {
const ok = await askForMasterKey(error);
if (!ok) return;
continue;
}
throw error;
}
}
this.stdout(_('Completed decryption.'));
} }
return; return;

View File

@ -25,19 +25,28 @@ class Command extends BaseCommand {
this.stdout(`# ${section.title}`); this.stdout(`# ${section.title}`);
this.stdout(''); this.stdout('');
let canRetryType = '';
for (const n in section.body) { for (const n in section.body) {
if (!section.body.hasOwnProperty(n)) continue; if (!section.body.hasOwnProperty(n)) continue;
const line = section.body[n]; const item = section.body[n];
this.stdout(line);
if (typeof item === 'object') {
canRetryType = item.canRetryType;
this.stdout(item.text);
} else {
this.stdout(item);
} }
} }
app() if (canRetryType === 'e2ee') {
.gui() this.stdout('');
.showConsole(); this.stdout(_('To retry decryption of these items. Run `e2ee decrypt --retry-failed-items`'));
app() }
.gui() }
.maximizeConsole();
app().gui().showConsole();
app().gui().maximizeConsole();
} }
} }

View File

@ -46,6 +46,8 @@ class NoteWidget extends TextWidget {
if (this.note_ && this.note_.encryption_applied) { if (this.note_ && this.note_.encryption_applied) {
this.text = _('One or more items are currently encrypted and you may need to supply a master password. To do so please type `e2ee decrypt`. If you have already supplied the password, the encrypted items are being decrypted in the background and will be available soon.'); this.text = _('One or more items are currently encrypted and you may need to supply a master password. To do so please type `e2ee decrypt`. If you have already supplied the password, the encrypted items are being decrypted in the background and will be available soon.');
this.text += '\n\n';
this.text += _('You may also type `status` for more information.');
} else { } else {
this.text = this.note_ ? `${this.note_.title}\n\n${this.note_.body}` : ''; this.text = this.note_ ? `${this.note_.title}\n\n${this.note_.body}` : '';
} }

View File

@ -7,7 +7,7 @@
"test": "gulp buildTests -L && jasmine --config=tests/support/jasmine.json", "test": "gulp buildTests -L && jasmine --config=tests/support/jasmine.json",
"postinstall": "npm run build && patch-package --patch-dir ../patches", "postinstall": "npm run build && patch-package --patch-dir ../patches",
"build": "gulp build", "build": "gulp build",
"start": "gulp build -L && node 'build/main.js' --profile ~/Temp/TestNotes2 --stack-trace-enabled --log-level debug --env dev" "start": "gulp build -L && node 'build/main.js' --stack-trace-enabled --log-level debug --env dev"
}, },
"bugs": { "bugs": {
"url": "https://github.com/laurent22/joplin/issues" "url": "https://github.com/laurent22/joplin/issues"

View File

@ -89,6 +89,10 @@ class DecryptionWorker {
await this.kvStore().deleteValue(`decrypt:${typeId}:${itemId}`); await this.kvStore().deleteValue(`decrypt:${typeId}:${itemId}`);
} }
async clearDisabledItems() {
await this.kvStore().deleteByPrefix('decrypt:');
}
dispatchReport(report) { dispatchReport(report) {
const action = Object.assign({}, report); const action = Object.assign({}, report);
action.type = 'DECRYPTION_WORKER_SET'; action.type = 'DECRYPTION_WORKER_SET';

View File

@ -58,6 +58,10 @@ class KvStore extends BaseService {
await this.db().exec('DELETE FROM key_values WHERE `key` = ?', [key]); await this.db().exec('DELETE FROM key_values WHERE `key` = ?', [key]);
} }
async deleteByPrefix(prefix) {
await this.db().exec('DELETE FROM key_values WHERE `key` LIKE ?', [`${prefix}%`]);
}
async clear() { async clear() {
await this.db().exec('DELETE FROM key_values'); await this.db().exec('DELETE FROM key_values');
} }

View File

@ -150,6 +150,7 @@ class ReportService {
section.body.push({ section.body.push({
text: _('%s: %s', toTitleCase(BaseModel.modelTypeToName(row.type_)), row.id), text: _('%s: %s', toTitleCase(BaseModel.modelTypeToName(row.type_)), row.id),
canRetry: true, canRetry: true,
canRetryType: 'e2ee',
retryHandler: async () => { retryHandler: async () => {
await DecryptionWorker.instance().clearDisabledItem(row.type_, row.id); await DecryptionWorker.instance().clearDisabledItem(row.type_, row.id);
DecryptionWorker.instance().scheduleStart(); DecryptionWorker.instance().scheduleStart();
@ -207,6 +208,7 @@ class ReportService {
section.body.push({ section.body.push({
text: _('%s (%s): %s', row.resource_title, row.resource_id, row.fetch_error), text: _('%s (%s): %s', row.resource_title, row.resource_id, row.fetch_error),
canRetry: true, canRetry: true,
canRetryType: 'resourceDownload',
retryHandler: async () => { retryHandler: async () => {
await Resource.resetErrorStatus(row.resource_id); await Resource.resetErrorStatus(row.resource_id);
ResourceFetcher.instance().autoAddResources(); ResourceFetcher.instance().autoAddResources();