diff --git a/lang/main.json b/lang/main.json index 015c10c76..3caa544ea 100644 --- a/lang/main.json +++ b/lang/main.json @@ -460,7 +460,11 @@ "unmute": "Unmute", "newDeviceCameraTitle": "New camera detected", "newDeviceAudioTitle": "New audio device detected", - "newDeviceAction": "Use" + "newDeviceAction": "Use", + "OldElectronAPPTitle": "Security vulnerability!", + "oldElectronClientDescription1": "You appear to be using an old verion of the Jitsi Meet client which has known security vulnerabilities. Please make sure you update to our ", + "oldElectronClientDescription2": "latest build", + "oldElectronClientDescription3": " now!" }, "passwordSetRemotely": "set by another participant", "passwordDigitsOnly": "Up to {{number}} digits", diff --git a/react/features/app/components/App.web.js b/react/features/app/components/App.web.js index 672442b18..dad24fb10 100644 --- a/react/features/app/components/App.web.js +++ b/react/features/app/components/App.web.js @@ -14,6 +14,7 @@ import '../../power-monitor'; import '../../room-lock'; import '../../talk-while-muted'; import '../../video-layout'; +import '../../old-client-notification'; import { AbstractApp } from './AbstractApp'; diff --git a/react/features/old-client-notification/components/OldElectronAPPNotificationDescription.js b/react/features/old-client-notification/components/OldElectronAPPNotificationDescription.js new file mode 100644 index 000000000..6a06715c2 --- /dev/null +++ b/react/features/old-client-notification/components/OldElectronAPPNotificationDescription.js @@ -0,0 +1,47 @@ +// @flow + +import React, { Component } from 'react'; +import { translate } from '../../base/i18n'; + +/** + * The type of the React {@code Component} props of {@link OldElectronAPPNotificationDescription}. + */ +type Props = { + + /** + * Invoked to obtain translated strings. + */ + t: Function +}; + +/** + * A component that renders the description of the notification for old Jitsi Meet Electron clients. + * + * @extends AbstractApp + */ +export class OldElectronAPPNotificationDescription extends Component { + /** + * Implements React's {@link Component#render()}. + * + * @inheritdoc + * @returns {ReactElement} + */ + render() { + const { t } = this.props; + + return ( +
+ { t('notify.oldElectronClientDescription1') } + + { t('notify.oldElectronClientDescription2') } + + { t('notify.oldElectronClientDescription3') } +
); + } + +} + +export default translate(OldElectronAPPNotificationDescription); diff --git a/react/features/old-client-notification/components/index.js b/react/features/old-client-notification/components/index.js new file mode 100644 index 000000000..cbc72ce6a --- /dev/null +++ b/react/features/old-client-notification/components/index.js @@ -0,0 +1,3 @@ +// @flow + +export { default as OldElectronAPPNotificationDescription } from './OldElectronAPPNotificationDescription'; diff --git a/react/features/old-client-notification/functions.js b/react/features/old-client-notification/functions.js new file mode 100644 index 000000000..9c4be0beb --- /dev/null +++ b/react/features/old-client-notification/functions.js @@ -0,0 +1,28 @@ +// @flow + +import { browser } from '../../../react/features/base/lib-jitsi-meet'; + +/** + * Returns true if Jitsi Meet is running in too old jitsi-meet-electron app and false otherwise. + * + * @returns {boolean} - True if Jitsi Meet is running in too old jitsi-meet-electron app and false otherwise. + */ +export function isOldJitsiMeetElectronApp() { + if (!browser.isElectron()) { + return false; + } + + const match = navigator.userAgent.match(/(JitsiMeet)\s*\/\s*((\d+)\.[^\s]*)/); + + if (!Array.isArray(match) || match.length < 3) { + return false; + } + + const majorVersion = Number(match[3]); + + if (isNaN(majorVersion) || majorVersion >= 2) { + return false; + } + + return true; +} diff --git a/react/features/old-client-notification/index.js b/react/features/old-client-notification/index.js new file mode 100644 index 000000000..d43689289 --- /dev/null +++ b/react/features/old-client-notification/index.js @@ -0,0 +1 @@ +import './middleware'; diff --git a/react/features/old-client-notification/middleware.js b/react/features/old-client-notification/middleware.js new file mode 100644 index 000000000..5339eafbc --- /dev/null +++ b/react/features/old-client-notification/middleware.js @@ -0,0 +1,43 @@ +// @flow + +import React from 'react'; + +import { APP_WILL_MOUNT } from '../base/app'; +import { MiddlewareRegistry } from '../base/redux'; +import { showErrorNotification } from '../notifications'; + +import { isOldJitsiMeetElectronApp } from './functions'; +import { OldElectronAPPNotificationDescription } from './components'; + +declare var interfaceConfig: Object; + +MiddlewareRegistry.register(store => next => action => { + switch (action.type) { + case APP_WILL_MOUNT: + return _appWillMount(store, next, action); + } + + return next(action); +}); + +/** + * Notifies the feature that the action {@link APP_WILL_MOUNT} has being dispatched. + * + * @param {Store} store - The redux store in which the specified {@code action} is being dispatched. + * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the specified {@code action}. + * @param {Action} action - The redux action {@code APP_WILL_MOUNT} which is being dispatched. + * @private + * @returns {Object} The new state that is the result of the reduction of the specified {@code action}. + */ +function _appWillMount(store, next, action) { + if (isOldJitsiMeetElectronApp()) { + const { dispatch } = store; + + dispatch(showErrorNotification({ + titleKey: 'notify.OldElectronAPPTitle', + description: + })); + } + + return next(action); +}