Actions handle error decrypting

This commit is contained in:
Mo Bitar
2018-05-27 11:04:14 -05:00
parent 0dbeff78a6
commit 2024233d69
7 changed files with 270 additions and 162 deletions

View File

@@ -1,10 +1,16 @@
class ActionsManager {
constructor(httpManager, modelManager, authManager, syncManager) {
this.httpManager = httpManager;
this.modelManager = modelManager;
this.authManager = authManager;
this.syncManager = syncManager;
constructor(httpManager, modelManager, authManager, syncManager, $rootScope, $compile, $timeout) {
this.httpManager = httpManager;
this.modelManager = modelManager;
this.authManager = authManager;
this.syncManager = syncManager;
this.$rootScope = $rootScope;
this.$compile = $compile;
this.$timeout = $timeout;
// Used when decrypting old items with new keys. This array is only kept in memory.
this.previousPasswords = [];
}
get extensions() {
@@ -46,36 +52,83 @@ class ActionsManager {
}
}
executeAction(action, extension, item, callback) {
async executeAction(action, extension, item, callback) {
var customCallback = function(response) {
var customCallback = (response) => {
action.running = false;
callback(response);
this.$timeout(() => {
callback(response);
})
}
action.running = true;
let decrypted = action.access_type == "decrypted";
var triedPasswords = [];
let handleResponseDecryption = async (response, keys, merge) => {
var item = response.item;
await SFJS.itemTransformer.decryptItem(item, keys);
if(!item.errorDecrypting) {
if(merge) {
var items = this.modelManager.mapResponseItemsToLocalModels([item], ModelManager.MappingSourceRemoteActionRetrieved);
for(var mappedItem of items) {
mappedItem.setDirty(true);
}
this.syncManager.sync(null);
customCallback({item: item});
} else {
item = this.modelManager.createItem(item, true /* Dont notify observers */);
customCallback({item: item});
}
return true;
} else {
// Error decrypting
if(!response.auth_params) {
// In some cases revisions were missing auth params. Instruct the user to email us to get this remedied.
alert("We were unable to decrypt this revision using your current keys, and this revision is missing metadata that would allow us to try different keys to decrypt it. This can likely be fixed with some manual intervention. Please email hello@standardnotes.org for assistance.");
return;
}
// Try previous passwords
for(let passwordCandidate of this.previousPasswords) {
if(triedPasswords.includes(passwordCandidate)) {
continue;
}
triedPasswords.push(passwordCandidate);
var keyResults = await SFJS.crypto.computeEncryptionKeysForUser(passwordCandidate, response.auth_params);
if(!keyResults) {
continue;
}
var success = await handleResponseDecryption(response, keyResults, merge);
if(success) {
return true;
}
}
this.presentPasswordModal((password) => {
this.previousPasswords.push(password);
handleResponseDecryption(response, keys, merge);
});
return false;
}
}
switch (action.verb) {
case "get": {
this.httpManager.getAbsolute(action.url, {}, (response) => {
action.error = false;
var items = response.items || [response.item];
SFJS.itemTransformer.decryptMultipleItems(items, this.authManager.keys()).then(() => {
items = this.modelManager.mapResponseItemsToLocalModels(items, ModelManager.MappingSourceRemoteActionRetrieved);
for(var item of items) {
item.setDirty(true);
}
this.syncManager.sync(null);
customCallback({items: items});
})
handleResponseDecryption(response, this.authManager.keys(), true);
}, (response) => {
action.error = true;
customCallback(null);
})
break;
}
@@ -83,10 +136,7 @@ class ActionsManager {
this.httpManager.getAbsolute(action.url, {}, (response) => {
action.error = false;
SFJS.itemTransformer.decryptItem(response.item, this.authManager.keys()).then(() => {
var item = this.modelManager.createItem(response.item, true /* Dont notify observers */);
customCallback({item: item});
})
handleResponseDecryption(response, this.authManager.keys(), false);
}, (response) => {
action.error = true;
customCallback(null);
@@ -148,6 +198,17 @@ class ActionsManager {
})
}
presentPasswordModal(callback) {
var scope = this.$rootScope.$new(true);
scope.type = "password";
scope.title = "Decryption Assistance";
scope.message = "Unable to decrypt this item with your current keys. Please enter your account password at the time of this revision.";
scope.callback = callback;
var el = this.$compile( "<input-modal type='type' message='message' title='title' callback='callback'></input-modal>" )(scope);
angular.element(document.body).append(el);
}
}
angular.module('app').service('actionsManager', ActionsManager);