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:
parent
a6459d3641
commit
7ccd19e21d
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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}` : '';
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
@ -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';
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user