From 1ffd75c0a6b4fc7d0463ab5036e7ee9798660027 Mon Sep 17 00:00:00 2001 From: Hristo Terezov Date: Fri, 1 May 2020 14:48:08 -0500 Subject: [PATCH 1/2] fix(localStorage): exception when disabled. --- connection.js | 3 +- modules/UI/util/MessageHandler.js | 2 +- modules/util/JitsiLocalStorage.js | 77 ------------------- package-lock.json | 20 ++++- package.json | 2 +- react/features/base/app/components/BaseApp.js | 4 +- react/features/base/config/actions.js | 8 +- react/features/base/config/functions.any.js | 19 ++--- react/features/base/config/middleware.js | 33 ++++---- react/features/base/settings/reducer.js | 21 +++-- .../base/storage/PersistenceRegistry.js | 20 ++--- .../components/ChromeExtensionBanner.web.js | 29 ++++--- .../local-recording/session/SessionManager.js | 2 +- react/features/recent-list/reducer.js | 14 ++-- 14 files changed, 93 insertions(+), 161 deletions(-) delete mode 100644 modules/util/JitsiLocalStorage.js diff --git a/connection.js b/connection.js index 761ddd2a9..c0af3bda0 100644 --- a/connection.js +++ b/connection.js @@ -1,7 +1,8 @@ /* global APP, JitsiMeetJS, config */ +import { jitsiLocalStorage } from 'js-utils'; + import AuthHandler from './modules/UI/authentication/AuthHandler'; -import jitsiLocalStorage from './modules/util/JitsiLocalStorage'; import { connectionEstablished, diff --git a/modules/UI/util/MessageHandler.js b/modules/UI/util/MessageHandler.js index 4516fa130..94dc9883f 100644 --- a/modules/UI/util/MessageHandler.js +++ b/modules/UI/util/MessageHandler.js @@ -1,7 +1,7 @@ /* global $, APP */ const logger = require('jitsi-meet-logger').getLogger(__filename); -import jitsiLocalStorage from '../../util/JitsiLocalStorage'; +import { jitsiLocalStorage } from 'js-utils'; import { NOTIFICATION_TIMEOUT, diff --git a/modules/util/JitsiLocalStorage.js b/modules/util/JitsiLocalStorage.js deleted file mode 100644 index d09782d37..000000000 --- a/modules/util/JitsiLocalStorage.js +++ /dev/null @@ -1,77 +0,0 @@ -import Logger from 'jitsi-meet-logger'; - -const logger = Logger.getLogger(__filename); - -/** - * Dummy implementation of Storage interface with empty methods. - */ -class DummyLocalStorage { - /* eslint-disable no-empty-function */ - /** - * Empty function - */ - getItem() { } - - /** - * Empty function - */ - setItem() { } - - /** - * Empty function - */ - removeItem() { } - /* eslint-enable no-empty-function */ -} - -/** - * Wrapper class for browser's local storage object. - */ -class JitsiLocalStorage extends DummyLocalStorage { - /** - * @constructor - * @param {Storage} storage browser's local storage object. - */ - constructor() { - super(); - let storage; - - try { - storage = window.localStorage; - } catch (error) { - logger.error(error); - } - this.storage = storage || new DummyLocalStorage(); - } - - /** - * Returns that passed key's value. - * @param {string} keyName the name of the key you want to retrieve - * the value of. - * @returns {String|null} the value of the key. If the key does not exist, - * null is returned. - */ - getItem(keyName) { - return this.storage.getItem(keyName); - } - - /** - * Adds a key to the storage, or update key's value if it already exists. - * @param {string} keyName the name of the key you want to create/update. - * @param {string} keyValue the value you want to give the key you are - * creating/updating. - */ - setItem(keyName, keyValue) { - return this.storage.setItem(keyName, keyValue); - } - - /** - * Remove a key from the storage. - * @param {string} keyName the name of the key you want to remove. - */ - removeItem(keyName) { - return this.storage.removeItem(keyName); - } -} - -export default new JitsiLocalStorage(); diff --git a/package-lock.json b/package-lock.json index 7fec8f25d..5906d07d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10594,8 +10594,8 @@ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" }, "js-utils": { - "version": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1", - "from": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1", + "version": "github:jitsi/js-utils#efb02828785b2b532097d96f4b32a101847ba58b", + "from": "github:jitsi/js-utils#efb02828785b2b532097d96f4b32a101847ba58b", "requires": { "bowser": "2.7.0", "js-md5": "0.7.3", @@ -10809,6 +10809,22 @@ "strophejs-plugin-disco": "0.0.2", "strophejs-plugin-stream-management": "github:jitsi/strophejs-plugin-stream-management#e719a02b4f83856c1530882084a4b048ee622d45", "webrtc-adapter": "7.5.0" + }, + "dependencies": { + "js-md5": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz", + "integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==" + }, + "js-utils": { + "version": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1", + "from": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1", + "requires": { + "bowser": "2.7.0", + "js-md5": "0.7.3", + "postis": "2.2.0" + } + } } }, "libflacjs": { diff --git a/package.json b/package.json index 8d3e60307..8a7352a13 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "jquery-contextmenu": "2.4.5", "jquery-i18next": "1.2.1", "js-md5": "0.6.1", - "js-utils": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1", + "js-utils": "github:jitsi/js-utils#efb02828785b2b532097d96f4b32a101847ba58b", "jsrsasign": "8.0.12", "jwt-decode": "2.2.0", "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#dffe94f270f692c7421412bbbc597279e4a2d805", diff --git a/react/features/base/app/components/BaseApp.js b/react/features/base/app/components/BaseApp.js index ac7ca71e4..5ee6f35a2 100644 --- a/react/features/base/app/components/BaseApp.js +++ b/react/features/base/app/components/BaseApp.js @@ -1,5 +1,6 @@ // @flow +import { jitsiLocalStorage } from 'js-utils'; import _ from 'lodash'; import React, { Component, Fragment } from 'react'; import { I18nextProvider } from 'react-i18next'; @@ -15,7 +16,6 @@ import { } from '../../redux'; import { SoundCollection } from '../../sounds'; import { PersistenceRegistry } from '../../storage'; - import { appWillMount, appWillUnmount } from '../actions'; import logger from '../logger'; @@ -110,7 +110,7 @@ export default class BaseApp extends Component<*, State> { * @returns {Promise} */ _initStorage(): Promise<*> { - const { _initializing } = window.localStorage; + const _initializing = jitsiLocalStorage.getItem('_initializing'); return _initializing || Promise.resolve(); } diff --git a/react/features/base/config/actions.js b/react/features/base/config/actions.js index 613bdd769..0c5f930ab 100644 --- a/react/features/base/config/actions.js +++ b/react/features/base/config/actions.js @@ -1,5 +1,6 @@ // @flow +import { jitsiLocalStorage } from 'js-utils'; import type { Dispatch } from 'redux'; import { addKnownDomains } from '../known-domains'; @@ -109,11 +110,8 @@ export function storeConfig(baseURL: string, config: Object) { let b = false; try { - if (typeof window.config === 'undefined' - || window.config !== config) { - window.localStorage.setItem( - `${_CONFIG_STORE_PREFIX}/${baseURL}`, - JSON.stringify(config)); + if (typeof window.config === 'undefined' || window.config !== config) { + jitsiLocalStorage.setItem(`${_CONFIG_STORE_PREFIX}/${baseURL}`, JSON.stringify(config)); b = true; } } catch (e) { diff --git a/react/features/base/config/functions.any.js b/react/features/base/config/functions.any.js index 8f8894d4b..167c721fe 100644 --- a/react/features/base/config/functions.any.js +++ b/react/features/base/config/functions.any.js @@ -1,5 +1,6 @@ // @flow +import { jitsiLocalStorage } from 'js-utils'; import _ from 'lodash'; import CONFIG_WHITELIST from './configWhitelist'; @@ -136,22 +137,16 @@ function _getWhitelistedJSON(configName, configJSON) { * otherwise, {@code undefined}. */ export function restoreConfig(baseURL: string): ?Object { - let storage; const key = `${_CONFIG_STORE_PREFIX}/${baseURL}`; + const config = jitsiLocalStorage.getItem(key); - try { - // XXX Even reading the property localStorage of window may throw an - // error (which is user agent-specific behavior). - storage = window.localStorage; - - const config = storage.getItem(key); - - if (config) { + if (config) { + try { return JSON.parse(config) || undefined; + } catch (e) { + // Somehow incorrect data ended up in the storage. Clean it up. + jitsiLocalStorage.removeItem(key); } - } catch (e) { - // Somehow incorrect data ended up in the storage. Clean it up. - storage && storage.removeItem(key); } return undefined; diff --git a/react/features/base/config/middleware.js b/react/features/base/config/middleware.js index 4bfc222a5..96c2954a6 100644 --- a/react/features/base/config/middleware.js +++ b/react/features/base/config/middleware.js @@ -1,5 +1,7 @@ // @flow +import { jitsiLocalStorage } from 'js-utils'; + import { APP_WILL_MOUNT } from '../app'; import { addKnownDomains } from '../known-domains'; import { MiddlewareRegistry } from '../redux'; @@ -51,31 +53,28 @@ function _appWillMount(store, next, action) { // consequently, the feature known-domains, it's possible for the feature // base/config to know of domains which the feature known-domains is yet to // discover. - const { localStorage } = window; - if (localStorage) { - const prefix = `${_CONFIG_STORE_PREFIX}/`; - const knownDomains = []; + const prefix = `${_CONFIG_STORE_PREFIX}/`; + const knownDomains = []; - for (let i = 0; /* localStorage.key(i) */; ++i) { - const key = localStorage.key(i); + for (let i = 0; /* localStorage.key(i) */; ++i) { + const key = jitsiLocalStorage.key(i); - if (key) { - let baseURL; + if (key) { + let baseURL; - if (key.startsWith(prefix) - && (baseURL = key.substring(prefix.length))) { - const uri = parseURIString(baseURL); - let host; + if (key.startsWith(prefix) + && (baseURL = key.substring(prefix.length))) { + const uri = parseURIString(baseURL); + let host; - uri && (host = uri.host) && knownDomains.push(host); - } - } else { - break; + uri && (host = uri.host) && knownDomains.push(host); } + } else { + break; } - knownDomains.length && store.dispatch(addKnownDomains(knownDomains)); } + knownDomains.length && store.dispatch(addKnownDomains(knownDomains)); return result; } diff --git a/react/features/base/settings/reducer.js b/react/features/base/settings/reducer.js index 3d96831e4..ce5cfdf9e 100644 --- a/react/features/base/settings/reducer.js +++ b/react/features/base/settings/reducer.js @@ -1,5 +1,6 @@ // @flow +import { jitsiLocalStorage } from 'js-utils'; import { randomHexString } from 'js-utils/random'; import _ from 'lodash'; @@ -86,8 +87,7 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => { * @returns {Object} */ function _getLegacyProfile() { - let persistedProfile - = window.localStorage.getItem('features/base/profile'); + let persistedProfile = jitsiLocalStorage.getItem('features/base/profile'); if (persistedProfile) { try { @@ -123,9 +123,9 @@ function _initSettings(featureState) { // FIXME: jibri uses old settings.js local storage values to set its display // name and email. Provide another way for jibri to set these values, update // jibri, and remove the old settings.js values. - const savedDisplayName = window.localStorage.getItem('displayname'); - const savedEmail = window.localStorage.getItem('email'); - let avatarID = _.escape(window.localStorage.getItem('avatarId')); + const savedDisplayName = jitsiLocalStorage.getItem('displayname'); + const savedEmail = jitsiLocalStorage.getItem('email'); + let avatarID = _.escape(jitsiLocalStorage.getItem('avatarId')); // The helper _.escape will convert null to an empty strings. The empty // string will be saved in settings. On app re-load, because an empty string @@ -149,16 +149,13 @@ function _initSettings(featureState) { if (!browser.isReactNative()) { // Browser only - const localFlipX - = JSON.parse(window.localStorage.getItem('localFlipX') || 'true'); - const cameraDeviceId - = window.localStorage.getItem('cameraDeviceId') || ''; - const micDeviceId = window.localStorage.getItem('micDeviceId') || ''; + const localFlipX = JSON.parse(jitsiLocalStorage.getItem('localFlipX') || 'true'); + const cameraDeviceId = jitsiLocalStorage.getItem('cameraDeviceId') || ''; + const micDeviceId = jitsiLocalStorage.getItem('micDeviceId') || ''; // Currently audio output device change is supported only in Chrome and // default output always has 'default' device ID - const audioOutputDeviceId - = window.localStorage.getItem('audioOutputDeviceId') || 'default'; + const audioOutputDeviceId = jitsiLocalStorage.getItem('audioOutputDeviceId') || 'default'; settings = assignIfDefined({ audioOutputDeviceId, diff --git a/react/features/base/storage/PersistenceRegistry.js b/react/features/base/storage/PersistenceRegistry.js index 7a65ce1dc..441a688dd 100644 --- a/react/features/base/storage/PersistenceRegistry.js +++ b/react/features/base/storage/PersistenceRegistry.js @@ -1,6 +1,7 @@ // @flow import md5 from 'js-md5'; +import { jitsiLocalStorage } from 'js-utils'; import logger from './logger'; @@ -63,8 +64,7 @@ class PersistenceRegistry { // legacy if (Object.keys(filteredPersistedState).length === 0) { - const { localStorage } = window; - let persistedState = localStorage.getItem(PERSISTED_STATE_NAME); + let persistedState = jitsiLocalStorage.getItem(PERSISTED_STATE_NAME); if (persistedState) { try { @@ -82,7 +82,7 @@ class PersistenceRegistry { // Store into the new format and delete the old format so that // it's not used again. this.persistState(filteredPersistedState); - localStorage.removeItem(PERSISTED_STATE_NAME); + jitsiLocalStorage.removeItem(PERSISTED_STATE_NAME); } } @@ -110,18 +110,12 @@ class PersistenceRegistry { if (checksum !== this._checksum) { for (const subtreeName of Object.keys(filteredState)) { try { - window.localStorage.setItem( - subtreeName, - JSON.stringify(filteredState[subtreeName])); + jitsiLocalStorage.setItem(subtreeName, JSON.stringify(filteredState[subtreeName])); } catch (error) { - logger.error( - 'Error persisting redux subtree', - subtreeName, - error); + logger.error('Error persisting redux subtree', subtreeName, error); } } - logger.info( - `redux state persisted. ${this._checksum} -> ${checksum}`); + logger.info(`redux state persisted. ${this._checksum} -> ${checksum}`); this._checksum = checksum; } } @@ -225,7 +219,7 @@ class PersistenceRegistry { * @returns {Object} */ _getPersistedSubtree(subtreeName, subtreeConfig, subtreeDefaults) { - let persistedSubtree = window.localStorage.getItem(subtreeName); + let persistedSubtree = jitsiLocalStorage.getItem(subtreeName); if (persistedSubtree) { try { diff --git a/react/features/chrome-extension-banner/components/ChromeExtensionBanner.web.js b/react/features/chrome-extension-banner/components/ChromeExtensionBanner.web.js index d258b378b..c26629ae7 100644 --- a/react/features/chrome-extension-banner/components/ChromeExtensionBanner.web.js +++ b/react/features/chrome-extension-banner/components/ChromeExtensionBanner.web.js @@ -1,19 +1,24 @@ // @flow + +import { jitsiLocalStorage } from 'js-utils'; import React, { PureComponent } from 'react'; -import { connect } from '../../base/redux'; -import { Icon, IconClose } from '../../base/icons'; -import { translate } from '../../base/i18n'; -import { getCurrentConference } from '../../base/conference/functions'; -import { browser } from '../../base/lib-jitsi-meet'; -import { - checkChromeExtensionsInstalled, - isMobileBrowser -} from '../../base/environment/utils'; -import logger from '../logger'; + import { createChromeExtensionBannerEvent, sendAnalytics } from '../../analytics'; +import { getCurrentConference } from '../../base/conference/functions'; +import { Icon, IconClose } from '../../base/icons'; +import { translate } from '../../base/i18n'; +import { browser } from '../../base/lib-jitsi-meet'; +import { connect } from '../../base/redux'; +import { + checkChromeExtensionsInstalled, + isMobileBrowser +} from '../../base/environment/utils'; + +import logger from '../logger'; + declare var interfaceConfig: Object; @@ -182,7 +187,7 @@ class ChromeExtensionBanner extends PureComponent { return true; } - const dontShowAgain = localStorage.getItem(DONT_SHOW_AGAIN_CHECKED) === 'true'; + const dontShowAgain = jitsiLocalStorage.getItem(DONT_SHOW_AGAIN_CHECKED) === 'true'; return !this.props.bannerCfg.url || dontShowAgain @@ -212,7 +217,7 @@ class ChromeExtensionBanner extends PureComponent { render() { if (this._shouldNotRender()) { if (this.state.dontShowAgainChecked) { - localStorage.setItem(DONT_SHOW_AGAIN_CHECKED, 'true'); + jitsiLocalStorage.setItem(DONT_SHOW_AGAIN_CHECKED, 'true'); } return null; diff --git a/react/features/local-recording/session/SessionManager.js b/react/features/local-recording/session/SessionManager.js index d7c1753f9..f8c13402a 100644 --- a/react/features/local-recording/session/SessionManager.js +++ b/react/features/local-recording/session/SessionManager.js @@ -1,6 +1,6 @@ /* @flow */ -import jitsiLocalStorage from '../../../../modules/util/JitsiLocalStorage'; +import { jitsiLocalStorage } from 'js-utils'; import logger from '../logger'; diff --git a/react/features/recent-list/reducer.js b/react/features/recent-list/reducer.js index 6bbec3aef..ea4974f08 100644 --- a/react/features/recent-list/reducer.js +++ b/react/features/recent-list/reducer.js @@ -1,4 +1,7 @@ // @flow + +import { jitsiLocalStorage } from 'js-utils'; + import { APP_WILL_MOUNT } from '../base/app'; import { getURLWithoutParamsNormalized } from '../base/connection'; import { ReducerRegistry } from '../base/redux'; @@ -119,16 +122,17 @@ function _appWillMount(state) { * @returns {Array} */ function _getLegacyRecentRoomList(): Array { - try { - const str = window.localStorage.getItem(LEGACY_STORAGE_KEY); + const str = jitsiLocalStorage.getItem(LEGACY_STORAGE_KEY); - if (str) { + if (str) { + try { return JSON.parse(str); + } catch (error) { + logger.warn('Failed to parse legacy recent-room list!'); } - } catch (error) { - logger.warn('Failed to parse legacy recent-room list!'); } + return []; } From 360383440ed91e140fdfd4b2ff2d4329ca696cb9 Mon Sep 17 00:00:00 2001 From: Hristo Terezov Date: Sat, 2 May 2020 19:36:28 -0500 Subject: [PATCH 2/2] chore(package): Update dependencies. --- package-lock.json | 26 +++++--------------------- package.json | 4 ++-- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5906d07d7..73d5f9917 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10594,8 +10594,8 @@ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" }, "js-utils": { - "version": "github:jitsi/js-utils#efb02828785b2b532097d96f4b32a101847ba58b", - "from": "github:jitsi/js-utils#efb02828785b2b532097d96f4b32a101847ba58b", + "version": "github:jitsi/js-utils#0c0c4142bd559fffffaebaded80bdaba8414d6b8", + "from": "github:jitsi/js-utils#0c0c4142bd559fffffaebaded80bdaba8414d6b8", "requires": { "bowser": "2.7.0", "js-md5": "0.7.3", @@ -10794,37 +10794,21 @@ } }, "lib-jitsi-meet": { - "version": "github:jitsi/lib-jitsi-meet#dffe94f270f692c7421412bbbc597279e4a2d805", - "from": "github:jitsi/lib-jitsi-meet#dffe94f270f692c7421412bbbc597279e4a2d805", + "version": "github:jitsi/lib-jitsi-meet#c6e8d596b0817a6584915457b2cb9ef726e94181", + "from": "github:jitsi/lib-jitsi-meet#c6e8d596b0817a6584915457b2cb9ef726e94181", "requires": { "@jitsi/sdp-interop": "1.0.2", "@jitsi/sdp-simulcast": "0.3.0", "async": "0.9.0", "current-executing-script": "0.1.3", "jitsi-meet-logger": "github:jitsi/jitsi-meet-logger#5ec92357570dc8f0b7ffc1528820721c84c6af8b", - "js-utils": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1", + "js-utils": "github:jitsi/js-utils#0c0c4142bd559fffffaebaded80bdaba8414d6b8", "lodash.isequal": "4.5.0", "sdp-transform": "2.3.0", "strophe.js": "1.3.4", "strophejs-plugin-disco": "0.0.2", "strophejs-plugin-stream-management": "github:jitsi/strophejs-plugin-stream-management#e719a02b4f83856c1530882084a4b048ee622d45", "webrtc-adapter": "7.5.0" - }, - "dependencies": { - "js-md5": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz", - "integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==" - }, - "js-utils": { - "version": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1", - "from": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1", - "requires": { - "bowser": "2.7.0", - "js-md5": "0.7.3", - "postis": "2.2.0" - } - } } }, "libflacjs": { diff --git a/package.json b/package.json index 8a7352a13..367a56b8f 100644 --- a/package.json +++ b/package.json @@ -53,10 +53,10 @@ "jquery-contextmenu": "2.4.5", "jquery-i18next": "1.2.1", "js-md5": "0.6.1", - "js-utils": "github:jitsi/js-utils#efb02828785b2b532097d96f4b32a101847ba58b", + "js-utils": "github:jitsi/js-utils#0c0c4142bd559fffffaebaded80bdaba8414d6b8", "jsrsasign": "8.0.12", "jwt-decode": "2.2.0", - "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#dffe94f270f692c7421412bbbc597279e4a2d805", + "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#c6e8d596b0817a6584915457b2cb9ef726e94181", "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d", "lodash": "4.17.13", "moment": "2.19.4",