Better handling for errorDecrypting
This commit is contained in:
@@ -31,20 +31,27 @@ class ItemParams {
|
|||||||
console.assert(!this.item.dummy, "Item is dummy, should not have gotten here.", this.item.dummy)
|
console.assert(!this.item.dummy, "Item is dummy, should not have gotten here.", this.item.dummy)
|
||||||
|
|
||||||
var params = {uuid: this.item.uuid, content_type: this.item.content_type, deleted: this.item.deleted, created_at: this.item.created_at};
|
var params = {uuid: this.item.uuid, content_type: this.item.content_type, deleted: this.item.deleted, created_at: this.item.created_at};
|
||||||
if(this.keys && !this.item.doNotEncrypt()) {
|
if(!this.item.errorDecrypting) {
|
||||||
var encryptedParams = EncryptionHelper.encryptItem(this.item, this.keys, this.version);
|
if(this.keys && !this.item.doNotEncrypt()) {
|
||||||
_.merge(params, encryptedParams);
|
var encryptedParams = EncryptionHelper.encryptItem(this.item, this.keys, this.version);
|
||||||
|
_.merge(params, encryptedParams);
|
||||||
|
|
||||||
if(this.version !== "001") {
|
if(this.version !== "001") {
|
||||||
params.auth_hash = null;
|
params.auth_hash = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
else {
|
params.content = this.forExportFile ? this.item.createContentJSONFromProperties() : "000" + Neeto.crypto.base64(JSON.stringify(this.item.createContentJSONFromProperties()));
|
||||||
params.content = this.forExportFile ? this.item.createContentJSONFromProperties() : "000" + Neeto.crypto.base64(JSON.stringify(this.item.createContentJSONFromProperties()));
|
if(!this.forExportFile) {
|
||||||
if(!this.forExportFile) {
|
params.enc_item_key = null;
|
||||||
params.enc_item_key = null;
|
params.auth_hash = null;
|
||||||
params.auth_hash = null;
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Error decrypting, keep "content" and related fields as is (and do not try to encrypt, otherwise that would be undefined behavior)
|
||||||
|
params.content = this.item.content;
|
||||||
|
params.enc_item_key = this.item.enc_item_key;
|
||||||
|
params.auth_hash = this.item.auth_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.additionalFields) {
|
if(this.additionalFields) {
|
||||||
|
|||||||
@@ -197,7 +197,8 @@ angular.module('app.frontend')
|
|||||||
|
|
||||||
this.saveKeys = function(keys) {
|
this.saveKeys = function(keys) {
|
||||||
this._keys = keys;
|
this._keys = keys;
|
||||||
storageManager.setItem("pw", keys.pw);
|
// Doesn't need to be saved.
|
||||||
|
// storageManager.setItem("pw", keys.pw);
|
||||||
storageManager.setItem("mk", keys.mk);
|
storageManager.setItem("mk", keys.mk);
|
||||||
storageManager.setItem("ak", keys.ak);
|
storageManager.setItem("ak", keys.ak);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ class AccountMenu {
|
|||||||
var block = function() {
|
var block = function() {
|
||||||
$timeout(function(){
|
$timeout(function(){
|
||||||
$scope.onSuccessfulAuth()();
|
$scope.onSuccessfulAuth()();
|
||||||
|
syncManager.refreshErroredItems();
|
||||||
syncManager.sync();
|
syncManager.sync();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ class EncryptionHelper {
|
|||||||
|
|
||||||
// return if uuid in auth hash does not match item uuid. Signs of tampering.
|
// return if uuid in auth hash does not match item uuid. Signs of tampering.
|
||||||
if(keyParams.uuid && keyParams.uuid !== item.uuid) {
|
if(keyParams.uuid && keyParams.uuid !== item.uuid) {
|
||||||
|
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||||
item.errorDecrypting = true;
|
item.errorDecrypting = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -99,6 +100,7 @@ class EncryptionHelper {
|
|||||||
var item_key = Neeto.crypto.decryptText(keyParams, requiresAuth);
|
var item_key = Neeto.crypto.decryptText(keyParams, requiresAuth);
|
||||||
|
|
||||||
if(!item_key) {
|
if(!item_key) {
|
||||||
|
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||||
item.errorDecrypting = true;
|
item.errorDecrypting = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -110,6 +112,7 @@ class EncryptionHelper {
|
|||||||
|
|
||||||
// return if uuid in auth hash does not match item uuid. Signs of tampering.
|
// return if uuid in auth hash does not match item uuid. Signs of tampering.
|
||||||
if(itemParams.uuid && itemParams.uuid !== item.uuid) {
|
if(itemParams.uuid && itemParams.uuid !== item.uuid) {
|
||||||
|
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||||
item.errorDecrypting = true;
|
item.errorDecrypting = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -121,11 +124,14 @@ class EncryptionHelper {
|
|||||||
|
|
||||||
var content = Neeto.crypto.decryptText(itemParams, true);
|
var content = Neeto.crypto.decryptText(itemParams, true);
|
||||||
if(!content) {
|
if(!content) {
|
||||||
|
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||||
item.errorDecrypting = true;
|
item.errorDecrypting = true;
|
||||||
} else {
|
} else {
|
||||||
|
if(item.errorDecrypting == true) { item.errorDecryptingValueChanged = true;}
|
||||||
|
// Content should only be set if it was successfully decrypted, and should otherwise remain unchanged.
|
||||||
item.errorDecrypting = false;
|
item.errorDecrypting = false;
|
||||||
|
item.content = content;
|
||||||
}
|
}
|
||||||
item.content = content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static decryptMultipleItems(items, keys, throws) {
|
static decryptMultipleItems(items, keys, throws) {
|
||||||
@@ -139,6 +145,7 @@ class EncryptionHelper {
|
|||||||
try {
|
try {
|
||||||
this.decryptItem(item, keys);
|
this.decryptItem(item, keys);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if(!item.errorDecrypting) { item.errorDecryptingValueChanged = true;}
|
||||||
item.errorDecrypting = true;
|
item.errorDecrypting = true;
|
||||||
if(throws) {
|
if(throws) {
|
||||||
throw e;
|
throw e;
|
||||||
|
|||||||
@@ -118,7 +118,14 @@ class ModelManager {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_obj = _.omit(json_obj, omitFields || [])
|
// Lodash's _.omit, which was previously used, seems to cause unexpected behavior
|
||||||
|
// when json_obj is an ES6 item class. So we instead manually omit each key.
|
||||||
|
if(Array.isArray(omitFields)) {
|
||||||
|
for(var key of omitFields) {
|
||||||
|
delete json_obj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var item = this.findItem(json_obj.uuid);
|
var item = this.findItem(json_obj.uuid);
|
||||||
|
|
||||||
if(item) {
|
if(item) {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class SyncManager {
|
|||||||
markAllItemsDirtyAndSaveOffline(callback, alternateUUIDs) {
|
markAllItemsDirtyAndSaveOffline(callback, alternateUUIDs) {
|
||||||
|
|
||||||
// use a copy, as alternating uuid will affect array
|
// use a copy, as alternating uuid will affect array
|
||||||
var originalItems = this.modelManager.allItems.slice();
|
var originalItems = this.modelManager.allItems.filter((item) => {return !item.errorDecrypting}).slice();
|
||||||
|
|
||||||
var block = () => {
|
var block = () => {
|
||||||
var allItems = this.modelManager.allItems;
|
var allItems = this.modelManager.allItems;
|
||||||
@@ -359,9 +359,30 @@ class SyncManager {
|
|||||||
var keys = this.authManager.keys() || this.passcodeManager.keys();
|
var keys = this.authManager.keys() || this.passcodeManager.keys();
|
||||||
EncryptionHelper.decryptMultipleItems(responseItems, keys);
|
EncryptionHelper.decryptMultipleItems(responseItems, keys);
|
||||||
var items = this.modelManager.mapResponseItemsToLocalModelsOmittingFields(responseItems, omitFields, source);
|
var items = this.modelManager.mapResponseItemsToLocalModelsOmittingFields(responseItems, omitFields, source);
|
||||||
|
|
||||||
|
// During the decryption process, items may be marked as "errorDecrypting". If so, we want to be sure
|
||||||
|
// to persist this new state by writing these items back to local storage. When an item's "errorDecrypting"
|
||||||
|
// flag is changed, its "errorDecryptingValueChanged" flag will be set, so we can find these items by filtering (then unsetting) below:
|
||||||
|
var itemsWithErrorStatusChange = items.filter((item) => {
|
||||||
|
var valueChanged = item.errorDecryptingValueChanged;
|
||||||
|
// unset after consuming value
|
||||||
|
item.errorDecryptingValueChanged = false;
|
||||||
|
return valueChanged;
|
||||||
|
});
|
||||||
|
if(itemsWithErrorStatusChange.length > 0) {
|
||||||
|
this.writeItemsToLocalStorage(itemsWithErrorStatusChange, false, null);
|
||||||
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refreshErroredItems() {
|
||||||
|
var erroredItems = this.modelManager.allItems.filter((item) => {return item.errorDecrypting == true});
|
||||||
|
if(erroredItems.length > 0) {
|
||||||
|
this.handleItemsResponse(erroredItems, null, ModelManager.MappingSourceLocalRetrieved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleUnsavedItemsResponse(unsaved) {
|
handleUnsavedItemsResponse(unsaved) {
|
||||||
if(unsaved.length == 0) {
|
if(unsaved.length == 0) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -89,9 +89,6 @@
|
|||||||
%label.block
|
%label.block
|
||||||
Encryption key:
|
Encryption key:
|
||||||
.wrap.normal.mt-1.selectable {{encryptionKey()}}
|
.wrap.normal.mt-1.selectable {{encryptionKey()}}
|
||||||
%label.block.mt-5.mb-0
|
|
||||||
Server password:
|
|
||||||
.wrap.normal.mt-1.selectable {{serverPassword() ? serverPassword() : 'Not available. Sign out then sign back in to compute.'}}
|
|
||||||
%label.block.mt-5.mb-0
|
%label.block.mt-5.mb-0
|
||||||
Authentication key:
|
Authentication key:
|
||||||
.wrap.normal.mt-1.selectable {{authKey() ? authKey() : 'Not available. Sign out then sign back in to compute.'}}
|
.wrap.normal.mt-1.selectable {{authKey() ? authKey() : 'Not available. Sign out then sign back in to compute.'}}
|
||||||
|
|||||||
Reference in New Issue
Block a user