diff --git a/app/scripts/const/default-app-settings.js b/app/scripts/const/default-app-settings.js index 7010b542..d992b522 100644 --- a/app/scripts/const/default-app-settings.js +++ b/app/scripts/const/default-app-settings.js @@ -45,6 +45,7 @@ const DefaultAppSettings = { useLegacyAutoType: false, // use legacy auto-type engine (will be removed in future versions) deviceOwnerAuth: null, // Touch ID: null / 'memory' / 'file' deviceOwnerAuthTimeoutMinutes: 0, // how often master password is required with Touch ID + disableOfflineStorage: false, // don't cache loaded files in offline storage yubiKeyShowIcon: true, // show an icon to open OTP codes from YubiKey yubiKeyAutoOpen: false, // auto-load one-time codes when there are open files diff --git a/app/scripts/locales/base.json b/app/scripts/locales/base.json index 6d97d1fb..4f7cd464 100644 --- a/app/scripts/locales/base.json +++ b/app/scripts/locales/base.json @@ -449,6 +449,7 @@ "setGenLockAutoType": "On auto-type", "setGenLockOrSleep": "When the computer is locked or put to sleep", "setGenStorage": "Storage", + "setGenDisableOfflineStorage": "Don't cache loaded files in offline storage", "setGenStorageLogout": "Log out", "setGenShowAdvanced": "Show advanced settings", "setGenDevTools": "Show dev tools", diff --git a/app/scripts/models/app-model.js b/app/scripts/models/app-model.js index 5810d486..7203326b 100644 --- a/app/scripts/models/app-model.js +++ b/app/scripts/models/app-model.js @@ -526,7 +526,8 @@ class AppModel { fileInfo && fileInfo.openDate && fileInfo.rev === params.rev && - fileInfo.storage !== 'file' + fileInfo.storage !== 'file' && + !this.settings.disableOfflineStorage ) { logger.info('Open file from cache because it is latest'); this.openFileFromCache( @@ -547,7 +548,12 @@ class AppModel { }, fileInfo ); - } else if (!fileInfo || !fileInfo.openDate || params.storage === 'file') { + } else if ( + !fileInfo || + !fileInfo.openDate || + params.storage === 'file' || + this.settings.disableOfflineStorage + ) { this.openFileFromStorage(params, callback, fileInfo, logger); } else { logger.info('Open file from cache, will sync after load', params.storage); @@ -595,7 +601,7 @@ class AppModel { logger.info('Load from storage'); storage.load(params.path, params.opts, (err, data, stat) => { if (err) { - if (fileInfo && fileInfo.openDate) { + if (fileInfo && fileInfo.openDate && !this.settings.disableOfflineStorage) { logger.info('Open file from cache because of storage load error', err); this.openFileFromCache(params, callback, fileInfo); } else { @@ -619,7 +625,8 @@ class AppModel { !noCache && fileInfo && storage.name !== 'file' && - (err || (stat && stat.rev === cacheRev)) + (err || (stat && stat.rev === cacheRev)) && + !this.settings.disableOfflineStorage ) { logger.info( 'Open file from cache because ' + (err ? 'stat error' : 'it is latest'), @@ -689,7 +696,7 @@ class AppModel { if (fileInfo) { file.syncDate = fileInfo.syncDate; } - if (updateCacheOnSuccess) { + if (updateCacheOnSuccess && !this.settings.disableOfflineStorage) { logger.info('Save loaded file to cache'); Storage.cache.save(file.id, null, params.fileData); } @@ -976,6 +983,10 @@ class AppModel { logger.info('Updated sync date, saving modified file'); saveToCacheAndStorage(); } else if (file.dirty) { + if (this.settings.disableOfflineStorage) { + logger.info('File is dirty and cache is disabled'); + return complete(err); + } logger.info('Saving not modified dirty file to cache'); Storage.cache.save(fileInfo.id, null, data, (err) => { if (err) { @@ -1038,6 +1049,9 @@ class AppModel { } else if (!file.dirty) { logger.info('Saving to storage, skip cache because not dirty'); saveToStorage(data); + } else if (this.settings.disableOfflineStorage) { + logger.info('Saving to storage because cache is disabled'); + saveToStorage(data); } else { logger.info('Saving to cache'); Storage.cache.save(fileInfo.id, null, data, (err) => { @@ -1061,6 +1075,10 @@ class AppModel { logger.info('File does not exist in storage, creating'); saveToCacheAndStorage(); } else if (file.dirty) { + if (this.settings.disableOfflineStorage) { + logger.info('Stat error, dirty, cache is disabled', err || 'no error'); + return complete(err); + } logger.info('Stat error, dirty, save to cache', err || 'no error'); file.getData((data, e) => { if (e) { @@ -1098,6 +1116,14 @@ class AppModel { } } + deleteAllCachedFiles() { + for (const fileInfo of this.fileInfos) { + if (fileInfo.storage && !fileInfo.modified) { + Storage.cache.remove(fileInfo.id); + } + } + } + clearStoredKeyFiles() { for (const fileInfo of this.fileInfos) { fileInfo.set({ diff --git a/app/scripts/views/app-view.js b/app/scripts/views/app-view.js index b537eefa..bd4f7fd6 100644 --- a/app/scripts/views/app-view.js +++ b/app/scripts/views/app-view.js @@ -578,9 +578,13 @@ class AppView extends View { complete: (res) => { if (res === 'ignore') { this.model.closeAllFiles(); - complete(true); + if (complete) { + complete(true); + } } else { - complete(false); + if (complete) { + complete(false); + } } } }); diff --git a/app/scripts/views/settings/settings-general-view.js b/app/scripts/views/settings/settings-general-view.js index 93aa3c10..f1a1eeac 100644 --- a/app/scripts/views/settings/settings-general-view.js +++ b/app/scripts/views/settings/settings-general-view.js @@ -61,6 +61,7 @@ class SettingsGeneralView extends View { 'click .settings__general-restart-btn': 'installUpdateAndRestart', 'click .settings__general-download-update-btn': 'downloadUpdate', 'click .settings__general-update-found-btn': 'installFoundUpdate', + 'change .settings__general-disable-offline-storage': 'changeDisableOfflineStorage', 'change .settings__general-prv-check': 'changeStorageEnabled', 'click .settings__general-prv-logout': 'logoutFromStorage', 'click .settings__general-show-advanced': 'showAdvancedSettings', @@ -139,7 +140,8 @@ class SettingsGeneralView extends View { showReloadApp: Features.isStandalone, hasDeviceOwnerAuth: Launcher && Launcher.hasTouchId(), deviceOwnerAuth: AppSettingsModel.deviceOwnerAuth, - deviceOwnerAuthTimeout: AppSettingsModel.deviceOwnerAuthTimeoutMinutes + deviceOwnerAuthTimeout: AppSettingsModel.deviceOwnerAuthTimeoutMinutes, + disableOfflineStorage: AppSettingsModel.disableOfflineStorage }); this.renderProviderViews(storageProviders); } @@ -476,6 +478,14 @@ class SettingsGeneralView extends View { Events.emit('refresh'); } + changeDisableOfflineStorage(e) { + const disableOfflineStorage = e.target.checked; + AppSettingsModel.disableOfflineStorage = disableOfflineStorage; + if (disableOfflineStorage) { + this.appModel.deleteAllCachedFiles(); + } + } + changeStorageEnabled(e) { const storage = Storage[$(e.target).data('storage')]; if (storage) { diff --git a/app/templates/settings/settings-general.hbs b/app/templates/settings/settings-general.hbs index 5bbbffee..b8445318 100644 --- a/app/templates/settings/settings-general.hbs +++ b/app/templates/settings/settings-general.hbs @@ -300,6 +300,12 @@ {{/if}}

{{res 'setGenStorage'}}

+
+ + +
+ {{#each storageProviders as |prv|}}