Async SF API

This commit is contained in:
Mo Bitar
2018-05-21 21:26:36 -05:00
parent 367fbeed20
commit f43186d3e1
16 changed files with 180 additions and 176 deletions

View File

@@ -1,3 +1,9 @@
{
"presets": ["env"]
"presets": ["env"],
"plugins": [
["transform-runtime", {
"polyfill": false,
"regenerator": true
}]
]
}

View File

@@ -13,7 +13,7 @@ class AccountMenu {
$timeout, storageManager, $compile, archiveManager) {
'ngInject';
$scope.formData = {mergeLocal: true, url: syncManager.serverURL, ephemeral: false};
$scope.formData = {mergeLocal: true, url: syncManager.serverURL, ephemeral: false, email: "a@bitar.io", user_password: "password"};
$scope.user = authManager.user;
$scope.server = syncManager.serverURL;
@@ -262,26 +262,28 @@ class AccountMenu {
}.bind(this)
if(data.auth_params) {
SFJS.crypto.computeEncryptionKeysForUser(password, data.auth_params, (keys) => {
SFJS.crypto.computeEncryptionKeysForUser(password, data.auth_params).then((keys) => {
try {
SFItemTransformer.decryptMultipleItems(data.items, keys, false); /* throws = false as we don't want to interrupt all decryption if just one fails */
// delete items enc_item_key since the user's actually key will do the encrypting once its passed off
data.items.forEach(function(item){
item.enc_item_key = null;
item.auth_hash = null;
});
SFJS.itemTransformer.decryptMultipleItems(data.items, keys, false) /* throws = false as we don't want to interrupt all decryption if just one fails */
.then(() => {
// delete items enc_item_key since the user's actually key will do the encrypting once its passed off
data.items.forEach(function(item){
item.enc_item_key = null;
item.auth_hash = null;
});
var errorCount = 0;
// Don't import items that didn't decrypt properly
data.items = data.items.filter(function(item){
if(item.errorDecrypting) {
errorCount++;
return false;
}
return true;
var errorCount = 0;
// Don't import items that didn't decrypt properly
data.items = data.items.filter(function(item){
if(item.errorDecrypting) {
errorCount++;
return false;
}
return true;
})
onDataReady(errorCount);
})
onDataReady(errorCount);
}
catch (e) {
console.log("Error decrypting", e);

View File

@@ -174,7 +174,7 @@ class PasswordWizard {
// Ensure value for current password matches what's saved
let authParams = authManager.getAuthParams();
let password = $scope.formData.currentPassword;
SFJS.crypto.computeEncryptionKeysForUser(password, authParams, (keys) => {
SFJS.crypto.computeEncryptionKeysForUser(password, authParams).then((keys) => {
let success = keys.mk === authManager.keys().mk;
if(success) {
this.currentServerPw = keys.pw;
@@ -202,7 +202,10 @@ class PasswordWizard {
let currentServerPw = this.currentServerPw;
SFJS.crypto.generateInitialEncryptionKeysForUser(authManager.user.email, newUserPassword, (newKeys, newAuthParams) => {
SFJS.crypto.generateInitialEncryptionKeysForUser(authManager.user.email, newUserPassword).then((results) => {
let newKeys = results.newKeys;
let newAuthParams = results.newAuthParams;
// perform a sync beforehand to pull in any last minutes changes before we change the encryption key (and thus cant decrypt new changes)
syncManager.sync((response) => {
authManager.changePassword(currentServerPw, newKeys, newAuthParams, (response) => {

View File

@@ -9,7 +9,7 @@ class Item {
this.observers = [];
if(!this.uuid) {
this.uuid = SFJS.crypto.generateUUID();
this.uuid = SFJS.crypto.generateUUIDSync();
}
}

View File

@@ -3,34 +3,35 @@ class ItemParams {
constructor(item, keys, version) {
this.item = item;
this.keys = keys;
this.version = version || SFJS.crypto.version();
this.version = version || SFJS.version();
}
paramsForExportFile(includeDeleted) {
async paramsForExportFile(includeDeleted) {
this.additionalFields = ["updated_at"];
this.forExportFile = true;
if(includeDeleted) {
return this.__params();
} else {
return _.omit(this.__params(), ["deleted"]);
var result = await this.__params();
return _.omit(result, ["deleted"]);
}
}
paramsForExtension() {
async paramsForExtension() {
return this.paramsForExportFile();
}
paramsForLocalStorage() {
async paramsForLocalStorage() {
this.additionalFields = ["updated_at", "dirty", "errorDecrypting"];
this.forExportFile = true;
return this.__params();
}
paramsForSync() {
async paramsForSync() {
return this.__params();
}
__params() {
async __params() {
console.assert(!this.item.dummy, "Item is dummy, should not have gotten here.", this.item.dummy)
@@ -39,7 +40,7 @@ class ItemParams {
// Items should always be encrypted for export files. Only respect item.doNotEncrypt for remote sync params.
var doNotEncrypt = this.item.doNotEncrypt() && !this.forExportFile;
if(this.keys && !doNotEncrypt) {
var encryptedParams = SFItemTransformer.encryptItem(this.item, this.keys, this.version);
var encryptedParams = await SFJS.itemTransformer.encryptItem(this.item, this.keys, this.version);
_.merge(params, encryptedParams);
if(this.version !== "001") {
@@ -47,7 +48,7 @@ class ItemParams {
}
}
else {
params.content = this.forExportFile ? this.item.createContentJSONFromProperties() : "000" + SFJS.crypto.base64(JSON.stringify(this.item.createContentJSONFromProperties()));
params.content = this.forExportFile ? this.item.createContentJSONFromProperties() : "000" + await SFJS.crypto.base64(JSON.stringify(this.item.createContentJSONFromProperties()));
if(!this.forExportFile) {
params.enc_item_key = null;
params.auth_hash = null;

View File

@@ -60,17 +60,18 @@ class ActionsManager {
switch (action.verb) {
case "get": {
this.httpManager.getAbsolute(action.url, {}, function(response){
this.httpManager.getAbsolute(action.url, {}, (response) => {
action.error = false;
var items = response.items || [response.item];
SFItemTransformer.decryptMultipleItems(items, this.authManager.keys());
items = this.modelManager.mapResponseItemsToLocalModels(items, ModelManager.MappingSourceRemoteActionRetrieved);
for(var item of items) {
item.setDirty(true);
}
this.syncManager.sync(null);
customCallback({items: items});
}.bind(this), function(response){
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});
})
}, (response) => {
action.error = true;
customCallback(null);
})
@@ -80,13 +81,13 @@ class ActionsManager {
case "render": {
this.httpManager.getAbsolute(action.url, {}, function(response){
this.httpManager.getAbsolute(action.url, {}, (response) => {
action.error = false;
SFItemTransformer.decryptItem(response.item, this.authManager.keys());
var item = this.modelManager.createItem(response.item, true /* Dont notify observers */);
customCallback({item: item});
}.bind(this), function(response){
SFJS.itemTransformer.decryptItem(response.item, this.authManager.keys()).then(() => {
var item = this.modelManager.createItem(response.item, true /* Dont notify observers */);
customCallback({item: item});
})
}, (response) => {
action.error = true;
customCallback(null);
})
@@ -102,22 +103,15 @@ class ActionsManager {
}
case "post": {
var params = {};
this.outgoingParamsForItem(item, extension, decrypted).then((itemParams) => {
var params = {
items: [itemParams] // Wrap it in an array
}
if(action.all) {
var items = this.modelManager.allItemsMatchingTypes(action.content_types);
params.items = items.map(function(item){
var params = this.outgoingParamsForItem(item, extension, decrypted);
return params;
}.bind(this))
} else {
params.items = [this.outgoingParamsForItem(item, extension, decrypted)];
}
this.performPost(action, extension, params, function(response){
customCallback(response);
});
this.performPost(action, extension, params, function(response){
customCallback(response);
});
})
break;
}
@@ -130,7 +124,7 @@ class ActionsManager {
action.lastExecuted = new Date();
}
outgoingParamsForItem(item, extension, decrypted = false) {
async outgoingParamsForItem(item, extension, decrypted = false) {
var keys = this.authManager.keys();
if(decrypted) {
keys = null;

View File

@@ -24,22 +24,23 @@ class ArchiveManager {
protocolVersion = this.authManager.protocolVersion();
}
}
var data = this.__itemsData(keys, authParams, protocolVersion);
this.__downloadData(data, `SN Archive - ${new Date()}.txt`);
this.__itemsData(keys, authParams, protocolVersion).then((data) => {
this.__downloadData(data, `SN Archive - ${new Date()}.txt`);
// download as zipped plain text files
if(!keys) {
var notes = this.modelManager.allItemsMatchingTypes(["Note"]);
this.__downloadZippedNotes(notes);
}
// download as zipped plain text files
if(!keys) {
var notes = this.modelManager.allItemsMatchingTypes(["Note"]);
this.__downloadZippedNotes(notes);
}
})
}
/*
Private
*/
__itemsData(keys, authParams, protocolVersion) {
let data = this.modelManager.getAllItemsJSONData(keys, authParams, protocolVersion);
async __itemsData(keys, authParams, protocolVersion) {
let data = await this.modelManager.getAllItemsJSONData(keys, authParams, protocolVersion);
let blobData = new Blob([data], {type: 'text/json'});
return blobData;
}

View File

@@ -83,37 +83,8 @@ angular.module('app')
}
}
this.costMinimumForVersion = function(version) {
// all current versions have a min of 3000
// future versions will increase this
return SFJS.crypto.costMinimumForVersion(version);
}
this.isProtocolVersionSupported = function(version) {
return SFJS.crypto.supportedVersions().includes(version);
}
/* Upon sign in to an outdated version, the user will be presented with an alert requiring them to confirm
understanding they are signing in with an older version of the protocol, and must upgrade immediately after completing sign in.
*/
this.isProtocolVersionOutdated = function(version) {
// YYYY-MM-DD
let expirationDates = {
"001" : Date.parse("2018-01-01"),
"002" : Date.parse("2019-06-01"),
}
let date = expirationDates[version];
if(!date) {
// No expiration date, is active version
return false;
}
let expired = new Date() > date;
return expired;
}
this.supportsPasswordDerivationCost = function(cost) {
return SFJS.crypto.supportsPasswordDerivationCost(cost);
return SFJS.supportedVersions().includes(version);
}
this.getAuthParamsForEmail = function(url, email, extraParams, callback) {
@@ -130,7 +101,7 @@ angular.module('app')
}
this.login = function(url, email, password, ephemeral, strictSignin, extraParams, callback) {
this.getAuthParamsForEmail(url, email, extraParams, function(authParams){
this.getAuthParamsForEmail(url, email, extraParams, (authParams) => {
// SF3 requires a unique identifier in the auth params
authParams.identifier = email;
@@ -147,7 +118,7 @@ angular.module('app')
if(!this.isProtocolVersionSupported(authParams.version)) {
var message;
if(SFJS.crypto.isVersionNewerThanLibraryVersion(authParams.version)) {
if(SFJS.isVersionNewerThanLibraryVersion(authParams.version)) {
// The user has a new account type, but is signing in to an older client.
message = "This version of the application does not support your newer account type. Please upgrade to the latest version of Standard Notes to sign in.";
} else {
@@ -158,14 +129,14 @@ angular.module('app')
return;
}
if(this.isProtocolVersionOutdated(authParams.version)) {
if(SFJS.isProtocolVersionOutdated(authParams.version)) {
let message = `The encryption version for your account, ${authParams.version}, is outdated and requires upgrade. You may proceed with login, but are advised to follow prompts for Security Updates once inside. Please visit standardnotes.org/help/security for more information.\n\nClick 'OK' to proceed with login.`
if(!confirm(message)) {
return;
}
}
if(!this.supportsPasswordDerivationCost(authParams.pw_cost)) {
if(!SFJS.supportsPasswordDerivationCost(authParams.pw_cost)) {
let message = "Your account was created on a platform with higher security capabilities than this browser supports. " +
"If we attempted to generate your login keys here, it would take hours. " +
"Please use a browser with more up to date security capabilities, like Google Chrome or Firefox, to log in."
@@ -173,7 +144,7 @@ angular.module('app')
return;
}
var minimum = this.costMinimumForVersion(authParams.version);
var minimum = SFJS.costMinimumForVersion(authParams.version);
if(authParams.pw_cost < minimum) {
let message = "Unable to login due to insecure password parameters. Please visit standardnotes.org/help/security for more information.";
callback({error: {message: message}});
@@ -182,7 +153,7 @@ angular.module('app')
if(strictSignin) {
// Refuse sign in if authParams.version is anything but the latest version
var latestVersion = SFJS.crypto.version();
var latestVersion = SFJS.version();
if(authParams.version !== latestVersion) {
let message = `Strict sign in refused server sign in parameters. The latest security version is ${latestVersion}, but your account is reported to have version ${authParams.version}. If you'd like to proceed with sign in anyway, please disable strict sign in and try again.`;
callback({error: {message: message}});
@@ -190,24 +161,25 @@ angular.module('app')
}
}
SFJS.crypto.computeEncryptionKeysForUser(password, authParams, function(keys){
SFJS.crypto.computeEncryptionKeysForUser(password, authParams).then((keys) => {
var requestUrl = url + "/auth/sign_in";
var params = _.merge({password: keys.pw, email: email}, extraParams);
httpManager.postAbsolute(requestUrl, params, function(response){
httpManager.postAbsolute(requestUrl, params, (response) => {
this.setEphemeral(ephemeral);
this.handleAuthResponse(response, email, url, authParams, keys);
this.checkForSecurityUpdate();
$timeout(() => callback(response));
}.bind(this), function(response){
}, (response) => {
console.error("Error logging in", response);
if(typeof response !== 'object') {
response = {error: {message: "A server error occurred while trying to sign in. Please try again."}};
}
$timeout(() => callback(response));
})
});
}.bind(this));
}.bind(this))
});
})
}
this.handleAuthResponse = function(response, email, url, authParams, keys) {
@@ -238,7 +210,10 @@ angular.module('app')
}
this.register = function(url, email, password, ephemeral, callback) {
SFJS.crypto.generateInitialEncryptionKeysForUser(email, password, (keys, authParams) => {
SFJS.crypto.generateInitialEncryptionKeysForUser(email, password).then((results) => {
let keys = results.keys;
let authParams = results.authParams;
var requestUrl = url + "/auth";
var params = _.merge({password: keys.pw, email: email}, authParams);
@@ -277,12 +252,12 @@ angular.module('app')
this.updateAuthParams = function(authParams, callback) {
var requestUrl = storageManager.getItem("server") + "/auth/update";
var params = authParams;
httpManager.postAbsolute(requestUrl, params, function(response) {
httpManager.postAbsolute(requestUrl, params, (response) => {
storageManager.setItem("auth_params", JSON.stringify(authParams));
if(callback) {
callback(response);
}
}.bind(this), function(response){
}, function(response){
var error = response;
console.error("Update error:", response);
if(callback) {
@@ -297,7 +272,7 @@ angular.module('app')
return;
}
let latest = SFJS.crypto.version();
let latest = SFJS.version();
if(this.protocolVersion() !== latest) {
// Prompt user to perform security update

View File

@@ -716,7 +716,7 @@ class ComponentManager {
console.log("Web|componentManager|registerComponentWindow", component);
}
component.window = componentWindow;
component.sessionKey = SFJS.crypto.generateUUID();
component.sessionKey = SFJS.crypto.generateUUIDSync();
this.sendMessageToComponent(component, {
action: "component-registered",
sessionKey: component.sessionKey,

View File

@@ -36,7 +36,7 @@ class DesktopManager {
Sending a component in its raw state is really slow for the desktop app
Keys are not passed into ItemParams, so the result is not encrypted
*/
convertComponentForTransmission(component) {
async convertComponentForTransmission(component) {
return new ItemParams(component).paramsForExportFile(true);
}
@@ -44,14 +44,15 @@ class DesktopManager {
syncComponentsInstallation(components) {
if(!this.isDesktop) return;
var data = components.map((component) => {
Promise.all(components.map((component) => {
return this.convertComponentForTransmission(component);
})).then((data) => {
this.installationSyncHandler(data);
})
this.installationSyncHandler(data);
}
installComponent(component) {
this.installComponentHandler(this.convertComponentForTransmission(component));
async installComponent(component) {
this.installComponentHandler(await this.convertComponentForTransmission(component));
}
registerUpdateObserver(callback) {
@@ -128,7 +129,7 @@ class DesktopManager {
}
}
desktop_requestBackupFile() {
desktop_requestBackupFile(callback) {
var keys, authParams, protocolVersion;
if(this.authManager.offline() && this.passcodeManager.hasPasscode()) {
keys = this.passcodeManager.keys();
@@ -140,13 +141,14 @@ class DesktopManager {
protocolVersion = this.authManager.protocolVersion();
}
let data = this.modelManager.getAllItemsJSONData(
this.modelManager.getAllItemsJSONData(
keys,
authParams,
protocolVersion,
true /* return null on empty */
);
return data;
).then((data) => {
callback(data);
})
}
desktop_setMajorDataChangeHandler(handler) {

View File

@@ -59,7 +59,7 @@ class ModelManager {
var newItem = this.createItem(item);
newItem.uuid = SFJS.crypto.generateUUID();
newItem.uuid = SFJS.crypto.generateUUIDSync();
// Update uuids of relationships
newItem.informReferencesOfUUIDChange(item.uuid, newItem.uuid);
@@ -455,24 +455,25 @@ class ModelManager {
Archives
*/
getAllItemsJSONData(keys, authParams, protocolVersion, returnNullIfEmpty) {
var items = _.map(this.allItems, (item) => {
async getAllItemsJSONData(keys, authParams, protocolVersion, returnNullIfEmpty) {
return Promise.all(this.allItems.map((item) => {
var itemParams = new ItemParams(item, keys, protocolVersion);
return itemParams.paramsForExportFile();
});
})).then((items) => {
if(returnNullIfEmpty && items.length == 0) {
return null;
}
if(returnNullIfEmpty && items.length == 0) {
return null;
}
var data = {items: items}
var data = {items: items}
if(keys) {
// auth params are only needed when encrypted with a standard file key
data["auth_params"] = authParams;
}
if(keys) {
// auth params are only needed when encrypted with a standard file key
data["auth_params"] = authParams;
}
return JSON.stringify(data, null, 2 /* pretty print */);
})
return JSON.stringify(data, null, 2 /* pretty print */);
}

View File

@@ -32,7 +32,7 @@ angular.module('app')
this.unlock = function(passcode, callback) {
var params = this.passcodeAuthParams();
SFJS.crypto.computeEncryptionKeysForUser(passcode, params, (keys) => {
SFJS.crypto.computeEncryptionKeysForUser(passcode, params).then((keys) => {
if(keys.pw !== params.hash) {
callback(false);
return;
@@ -40,16 +40,20 @@ angular.module('app')
this._keys = keys;
this._authParams = params;
this.decryptLocalStorage(keys, params);
this._locked = false;
callback(true);
this.decryptLocalStorage(keys, params).then(() => {
this._locked = false;
callback(true);
})
});
}
this.setPasscode = (passcode, callback) => {
var uuid = SFJS.crypto.generateUUID();
var uuid = SFJS.crypto.generateUUIDSync();
SFJS.crypto.generateInitialEncryptionKeysForUser(uuid, passcode).then((results) => {
let keys = results.keys;
let authParams = results.authParams;
SFJS.crypto.generateInitialEncryptionKeysForUser(uuid, passcode, (keys, authParams) => {
authParams.hash = keys.pw;
this._keys = keys;
this._hasPasscode = true;
@@ -83,9 +87,9 @@ angular.module('app')
storageManager.setItemsMode(authManager.isEphemeralSession() ? StorageManager.Ephemeral : StorageManager.FixedEncrypted, true);
}
this.decryptLocalStorage = function(keys, authParams) {
this.decryptLocalStorage = async function(keys, authParams) {
storageManager.setKeys(keys, authParams);
storageManager.decryptStorage();
return storageManager.decryptStorage();
}
}
});

View File

@@ -154,12 +154,14 @@ class StorageManager {
// Save new encrypted storage in Fixed storage
var params = new ItemParams(encryptedStorage, this.encryptedStorageKeys, this.encryptedStorageAuthParams.version);
this.setItem("encryptedStorage", JSON.stringify(params.paramsForSync()), StorageManager.Fixed);
params.paramsForSync().then((syncParams) => {
this.setItem("encryptedStorage", JSON.stringify(syncParams), StorageManager.Fixed);
})
}
decryptStorage() {
async decryptStorage() {
var stored = JSON.parse(this.getItem("encryptedStorage", StorageManager.Fixed));
SFItemTransformer.decryptItem(stored, this.encryptedStorageKeys);
await SFJS.itemTransformer.decryptItem(stored, this.encryptedStorageKeys);
var encryptedStorage = new EncryptedStorage(stored);
for(var key of Object.keys(encryptedStorage.storage)) {

View File

@@ -29,24 +29,26 @@ class SyncManager {
var version = this.authManager.offline() ? this.passcodeManager.protocolVersion() : this.authManager.protocolVersion();
var keys = this.authManager.offline() ? this.passcodeManager.keys() : this.authManager.keys();
var params = items.map(function(item) {
Promise.all(items.map(async (item) => {
var itemParams = new ItemParams(item, keys, version);
itemParams = itemParams.paramsForLocalStorage();
itemParams = await itemParams.paramsForLocalStorage();
if(offlineOnly) {
delete itemParams.dirty;
}
return itemParams;
}.bind(this));
this.storageManager.saveModels(params, callback);
})).then((params) => {
this.storageManager.saveModels(params, callback);
})
}
loadLocalItems(callback) {
var params = this.storageManager.getAllModels(function(items){
var items = this.handleItemsResponse(items, null, ModelManager.MappingSourceLocalRetrieved);
Item.sortItemsByDate(items);
callback(items);
}.bind(this))
var params = this.storageManager.getAllModels((items) => {
this.handleItemsResponse(items, null, ModelManager.MappingSourceLocalRetrieved).then((items) => {
Item.sortItemsByDate(items);
callback(items);
})
})
}
syncOffline(items, callback) {
@@ -54,7 +56,7 @@ class SyncManager {
for(var item of items) {
item.updated_at = new Date();
}
this.writeItemsToLocalStorage(items, true, function(responseItems){
this.writeItemsToLocalStorage(items, true, (responseItems) => {
// delete anything needing to be deleted
for(var item of items) {
if(item.deleted) {
@@ -70,7 +72,7 @@ class SyncManager {
if(callback) {
callback({success: true});
}
}.bind(this))
})
}
@@ -201,7 +203,7 @@ class SyncManager {
this.syncLocked = false;
}
sync(callback, options = {}, source) {
async sync(callback, options = {}, source) {
if(this.syncLocked) {
console.log("Sync Locked, Returning;");
@@ -281,11 +283,14 @@ class SyncManager {
var params = {};
params.limit = 150;
params.items = _.map(subItems, function(item){
await Promise.all(subItems.map((item) => {
var itemParams = new ItemParams(item, keys, version);
itemParams.additionalFields = options.additionalFields;
return itemParams.paramsForSync();
}.bind(this));
})).then((itemsParams) => {
params.items = itemsParams;
})
for(var item of subItems) {
// Reset dirty counter to 0, since we're about to sync it.
@@ -300,7 +305,7 @@ class SyncManager {
this.stopCheckingIfSyncIsTakingTooLong();
}.bind(this);
var onSyncSuccess = function(response) {
var onSyncSuccess = async function(response) {
// Check to make sure any subItem hasn't been marked as dirty again while a sync was ongoing
var itemsToClearAsDirty = [];
for(var item of subItems) {
@@ -325,8 +330,7 @@ class SyncManager {
// Map retrieved items to local data
// Note that deleted items will not be returned
var retrieved
= this.handleItemsResponse(response.retrieved_items, null, ModelManager.MappingSourceRemoteRetrieved);
var retrieved = await this.handleItemsResponse(response.retrieved_items, null, ModelManager.MappingSourceRemoteRetrieved);
// Append items to master list of retrieved items for this ongoing sync operation
this.allRetreivedItems = this.allRetreivedItems.concat(retrieved);
@@ -337,8 +341,7 @@ class SyncManager {
var omitFields = ["content", "auth_hash"];
// Map saved items to local data
var saved =
this.handleItemsResponse(response.saved_items, omitFields, ModelManager.MappingSourceRemoteSaved);
var saved = await this.handleItemsResponse(response.saved_items, omitFields, ModelManager.MappingSourceRemoteSaved);
// Append items to master list of saved items for this ongoing sync operation
this.allSavedItems = this.allSavedItems.concat(saved);
@@ -418,9 +421,9 @@ class SyncManager {
}
}
handleItemsResponse(responseItems, omitFields, source) {
async handleItemsResponse(responseItems, omitFields, source) {
var keys = this.authManager.keys() || this.passcodeManager.keys();
SFItemTransformer.decryptMultipleItems(responseItems, keys);
await SFJS.itemTransformer.decryptMultipleItems(responseItems, keys);
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
@@ -446,7 +449,7 @@ class SyncManager {
}
}
handleUnsavedItemsResponse(unsaved) {
async handleUnsavedItemsResponse(unsaved) {
if(unsaved.length == 0) {
return;
}
@@ -454,7 +457,7 @@ class SyncManager {
console.log("Handle unsaved", unsaved);
var i = 0;
var handleNext = () => {
var handleNext = async () => {
if(i >= unsaved.length) {
// Handled all items
this.sync(null, {additionalFields: ["created_at", "updated_at"]});
@@ -463,7 +466,7 @@ class SyncManager {
var mapping = unsaved[i];
var itemResponse = mapping.item;
SFItemTransformer.decryptMultipleItems([itemResponse], this.authManager.keys());
await SFJS.itemTransformer.decryptMultipleItems([itemResponse], this.authManager.keys());
var item = this.modelManager.findItem(itemResponse.uuid);
if(!item) {

9
package-lock.json generated
View File

@@ -1001,6 +1001,15 @@
"regenerator-transform": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz"
}
},
"babel-plugin-transform-runtime": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz",
"integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
"dev": true,
"requires": {
"babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
}
},
"babel-plugin-transform-strict-mode": {
"version": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
"integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",

View File

@@ -12,6 +12,7 @@
"angular": "^1.6.1",
"angular-mocks": "^1.6.1",
"babel-cli": "^6.18.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.1.1",
"babel-preset-es2016": "^6.16.0",
"bower": "^1.8.0",