diff --git a/ElectronClient/app/gui/MainScreen.jsx b/ElectronClient/app/gui/MainScreen.jsx
index d9fb93e629..3e2a0a9885 100644
--- a/ElectronClient/app/gui/MainScreen.jsx
+++ b/ElectronClient/app/gui/MainScreen.jsx
@@ -448,7 +448,7 @@ class MainScreenComponent extends React.Component {
if (this.props.hasDisabledSyncItems) {
msg = {_('Some items cannot be synchronised.')} { onViewDisabledItemsClick() }}>{_('View them now')}
} else if (this.props.showMissingMasterKeyMessage) {
- msg = {_('Some items cannot be decrypted.')} { onViewMasterKeysClick() }}>{_('Set the password')}
+ msg = {_('One or more master keys need a password.')} { onViewMasterKeysClick() }}>{_('Set the password')}
}
messageComp = (
diff --git a/ReactNativeClient/lib/BaseApplication.js b/ReactNativeClient/lib/BaseApplication.js
index 3f63b232f0..f321d9e5d6 100644
--- a/ReactNativeClient/lib/BaseApplication.js
+++ b/ReactNativeClient/lib/BaseApplication.js
@@ -59,6 +59,8 @@ class BaseApplication {
// be derived from the state and not set directly since that would make the
// state and UI out of sync.
this.currentFolder_ = null;
+
+ this.decryptionWorker_resourceMetadataButNotBlobDecrypted = this.decryptionWorker_resourceMetadataButNotBlobDecrypted.bind(this);
}
logger() {
@@ -285,6 +287,19 @@ class BaseApplication {
}
}
+ async decryptionWorker_resourceMetadataButNotBlobDecrypted(event) {
+ this.scheduleAutoAddResources();
+ }
+
+ scheduleAutoAddResources() {
+ if (this.scheduleAutoAddResourcesIID_) return;
+
+ this.scheduleAutoAddResourcesIID_ = setTimeout(() => {
+ this.scheduleAutoAddResourcesIID_ = null;
+ ResourceFetcher.instance().autoAddResources();
+ }, 1000);
+ }
+
reducerActionToString(action) {
let o = [action.type];
if ('id' in action) o.push(action.id);
@@ -314,7 +329,7 @@ class BaseApplication {
}
async generalMiddleware(store, next, action) {
- this.logger().debug('Reducer action', this.reducerActionToString(action));
+ // this.logger().debug('Reducer action', this.reducerActionToString(action));
const result = next(action);
const newState = store.getState();
@@ -608,6 +623,7 @@ class BaseApplication {
DecryptionWorker.instance().setLogger(this.logger_);
DecryptionWorker.instance().setEncryptionService(EncryptionService.instance());
await EncryptionService.instance().loadMasterKeysFromSettings();
+ DecryptionWorker.instance().on('resourceMetadataButNotBlobDecrypted', this.decryptionWorker_resourceMetadataButNotBlobDecrypted);
ResourceFetcher.instance().setFileApi(() => { return reg.syncTarget().fileApi() });
ResourceFetcher.instance().setLogger(this.logger_);
diff --git a/ReactNativeClient/lib/reducer.js b/ReactNativeClient/lib/reducer.js
index 9292dd8924..6963574466 100644
--- a/ReactNativeClient/lib/reducer.js
+++ b/ReactNativeClient/lib/reducer.js
@@ -535,6 +535,12 @@ const reducer = (state = defaultState, action) => {
newState.masterKeys = action.items;
break;
+ case 'MASTERKEY_SET_NOT_LOADED':
+
+ newState = Object.assign({}, state);
+ newState.notLoadedMasterKeys = action.ids;
+ break;
+
case 'MASTERKEY_ADD_NOT_LOADED':
if (state.notLoadedMasterKeys.indexOf(action.id) < 0) {
diff --git a/ReactNativeClient/lib/services/DecryptionWorker.js b/ReactNativeClient/lib/services/DecryptionWorker.js
index d8758db383..b4bb1cc5ed 100644
--- a/ReactNativeClient/lib/services/DecryptionWorker.js
+++ b/ReactNativeClient/lib/services/DecryptionWorker.js
@@ -1,4 +1,5 @@
const BaseItem = require('lib/models/BaseItem');
+const MasterKey = require('lib/models/MasterKey');
const Resource = require('lib/models/Resource');
const ResourceService = require('lib/services/ResourceService');
const { Logger } = require('lib/logger.js');
@@ -75,6 +76,20 @@ class DecryptionWorker {
return;
}
+ const loadedMasterKeyCount = await this.encryptionService().loadedMasterKeysCount();
+ if (!loadedMasterKeyCount) {
+ this.logger().info('DecryptionWorker: cannot start because no master key is currently loaded.');
+ const ids = await MasterKey.allIds();
+
+ if (ids.length) {
+ this.dispatch({
+ type: 'MASTERKEY_SET_NOT_LOADED',
+ ids: ids,
+ });
+ }
+ return;
+ }
+
this.logger().info('DecryptionWorker: starting decryption...');
this.state_ = 'started';
@@ -101,7 +116,7 @@ class DecryptionWorker {
});
// Don't log in production as it results in many messages when importing many items
- // this.logger().info('DecryptionWorker: decrypting: ' + item.id + ' (' + ItemClass.tableName() + ')');
+ // this.logger().debug('DecryptionWorker: decrypting: ' + item.id + ' (' + ItemClass.tableName() + ')');
try {
const decryptedItem = await ItemClass.decrypt(item);
@@ -115,6 +130,10 @@ class DecryptionWorker {
if (decryptedItem.type_ === Resource.modelType() && !decryptedItem.encryption_blob_encrypted) {
this.eventEmitter_.emit('resourceDecrypted', { id: decryptedItem.id });
}
+
+ if (decryptedItem.type_ === Resource.modelType() && !decryptedItem.encryption_applied && !!decryptedItem.encryption_blob_encrypted) {
+ this.eventEmitter_.emit('resourceMetadataButNotBlobDecrypted', { id: decryptedItem.id });
+ }
} catch (error) {
excludedIds.push(item.id);
@@ -154,10 +173,10 @@ class DecryptionWorker {
const downloadedButEncryptedBlobCount = await Resource.downloadedButEncryptedBlobCount();
- this.dispatchReport({ state: 'idle' });
-
this.state_ = 'idle';
+ this.dispatchReport({ state: 'idle' });
+
if (downloadedButEncryptedBlobCount) {
this.logger().info('DecryptionWorker: Some resources have been downloaded but are not decrypted yet. Scheduling another decryption. Resource count: ' + downloadedButEncryptedBlobCount);
this.scheduleStart();
diff --git a/ReactNativeClient/lib/services/ResourceFetcher.js b/ReactNativeClient/lib/services/ResourceFetcher.js
index bdea59c745..040108b5ec 100644
--- a/ReactNativeClient/lib/services/ResourceFetcher.js
+++ b/ReactNativeClient/lib/services/ResourceFetcher.js
@@ -120,6 +120,7 @@ class ResourceFetcher extends BaseService {
// sync. The other ones have been done using migrations/20.js. This code can be removed
// after a few months.
if (resource && resource.size < 0 && localResourceContentPath && !resource.encryption_blob_encrypted) {
+ await shim.fsDriver().waitTillExists(localResourceContentPath);
await ResourceService.autoSetFileSizes();
}
@@ -194,7 +195,9 @@ class ResourceFetcher extends BaseService {
});
}
- async autoAddResources(limit) {
+ async autoAddResources(limit = null) {
+ if (limit === null) limit = 10;
+
if (this.addingResources_) return;
this.addingResources_ = true;
diff --git a/ReactNativeClient/lib/services/ResourceService.js b/ReactNativeClient/lib/services/ResourceService.js
index 8e52823ad7..43dadc118b 100644
--- a/ReactNativeClient/lib/services/ResourceService.js
+++ b/ReactNativeClient/lib/services/ResourceService.js
@@ -111,8 +111,8 @@ class ResourceService extends BaseService {
}
}
- static async autoSetFileSize(resourceId, filePath) {
- const itDoes = await shim.fsDriver().waitTillExists(filePath);
+ static async autoSetFileSize(resourceId, filePath, waitTillExists = true) {
+ const itDoes = await shim.fsDriver().waitTillExists(filePath, waitTillExists ? 10000 : 0);
if (!itDoes) {
// this.logger().warn('Trying to set file size on non-existent resource:', resourceId, filePath);
return;
@@ -125,7 +125,7 @@ class ResourceService extends BaseService {
const resources = await Resource.needFileSizeSet();
for (const r of resources) {
- await this.autoSetFileSize(r.id, Resource.fullPath(r));
+ await this.autoSetFileSize(r.id, Resource.fullPath(r), false);
}
}
diff --git a/ReactNativeClient/root.js b/ReactNativeClient/root.js
index 8fb111ddec..865184b07f 100644
--- a/ReactNativeClient/root.js
+++ b/ReactNativeClient/root.js
@@ -86,7 +86,7 @@ const logReducerAction = function(action) {
let msg = [action.type];
if (action.routeName) msg.push(action.routeName);
- reg.logger().info('Reducer action', msg.join(', '));
+ // reg.logger().debug('Reducer action', msg.join(', '));
}
const generalMiddleware = store => next => async (action) => {