Pārlūkot izejas kodu

Fix the initialization of the (external) API

The counterpart of the external API in the Jitsi Meet Web app uses the
search URL param jwt to heuristically detect that the Web app is very
likely embedded (as an iframe) and, consequently, needs to forcefully
enable itself. It was looking at whether there was a JSON Web Token
(JWT) but that logic got broken when the JWT support was rewritten
because the check started happening before the search URL param jwt was
parsed.
master
Lyubo Marinov 8 gadus atpakaļ
vecāks
revīzija
320e67baa1

+ 24
- 18
app.js Parādīt failu

15
 
15
 
16
 window.toastr = require("toastr");
16
 window.toastr = require("toastr");
17
 
17
 
18
-import UI from "./modules/UI/UI";
19
-import settings from "./modules/settings/Settings";
20
 import conference from './conference';
18
 import conference from './conference';
21
 import API from './modules/API';
19
 import API from './modules/API';
22
-
23
-import translation from "./modules/translation/translation";
20
+import keyboardshortcut from './modules/keyboardshortcut/keyboardshortcut';
24
 import remoteControl from "./modules/remotecontrol/RemoteControl";
21
 import remoteControl from "./modules/remotecontrol/RemoteControl";
22
+import settings from "./modules/settings/Settings";
23
+import translation from "./modules/translation/translation";
24
+import UI from "./modules/UI/UI";
25
 
25
 
26
 const APP = {
26
 const APP = {
27
+    API,
28
+    conference,
29
+
30
+    /**
31
+     * After the APP has been initialized provides utility methods for dealing
32
+     * with the conference room URL(address).
33
+     * @type ConferenceUrl
34
+     */
35
+    ConferenceUrl: null,
36
+
27
     // Used by do_external_connect.js if we receive the attach data after
37
     // Used by do_external_connect.js if we receive the attach data after
28
     // connect was already executed. status property can be "initialized",
38
     // connect was already executed. status property can be "initialized",
29
     // "ready" or "connecting". We are interested in "ready" status only which
39
     // "ready" or "connecting". We are interested in "ready" status only which
34
         status: "initialized",
44
         status: "initialized",
35
         handler: null
45
         handler: null
36
     },
46
     },
47
+    connection: null,
48
+
37
     // Used for automated performance tests
49
     // Used for automated performance tests
38
     connectionTimes: {
50
     connectionTimes: {
39
         "index.loaded": window.indexLoadedTime
51
         "index.loaded": window.indexLoadedTime
40
     },
52
     },
41
-    UI,
42
-    settings,
43
-    conference,
44
-    translation,
53
+    keyboardshortcut,
54
+
45
     /**
55
     /**
46
      * The log collector which captures JS console logs for this app.
56
      * The log collector which captures JS console logs for this app.
47
      * @type {LogCollector}
57
      * @type {LogCollector}
48
      */
58
      */
49
     logCollector: null,
59
     logCollector: null,
60
+
50
     /**
61
     /**
51
      * Indicates if the log collector has been started (it will not be started
62
      * Indicates if the log collector has been started (it will not be started
52
      * if the welcome page is displayed).
63
      * if the welcome page is displayed).
53
      */
64
      */
54
     logCollectorStarted : false,
65
     logCollectorStarted : false,
55
-    /**
56
-     * After the APP has been initialized provides utility methods for dealing
57
-     * with the conference room URL(address).
58
-     * @type ConferenceUrl
59
-     */
60
-    ConferenceUrl : null,
61
-    connection: null,
62
-    API,
63
-    remoteControl
66
+    remoteControl,
67
+    settings,
68
+    translation,
69
+    UI
64
 };
70
 };
65
 
71
 
66
 // TODO The execution of the mobile app starts from react/index.native.js.
72
 // TODO The execution of the mobile app starts from react/index.native.js.
69
 // because we are at the beginning of introducing React into the Web app, allow
75
 // because we are at the beginning of introducing React into the Web app, allow
70
 // the execution of the Web app to start from app.js in order to reduce the
76
 // the execution of the Web app to start from app.js in order to reduce the
71
 // complexity of the beginning step.
77
 // complexity of the beginning step.
72
-require('./react');
78
+import './react';
73
 
79
 
74
 module.exports = APP;
80
 module.exports = APP;

+ 12
- 5
modules/API/API.js Parādīt failu

1
 import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
1
 import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
2
+import { parseJWTFromURLParams } from '../../react/features/jwt';
2
 import { getJitsiMeetTransport } from '../transport';
3
 import { getJitsiMeetTransport } from '../transport';
3
 
4
 
4
 import { API_ID } from './constants';
5
 import { API_ID } from './constants';
74
  * @returns {boolean}
75
  * @returns {boolean}
75
  */
76
  */
76
 function shouldBeEnabled() {
77
 function shouldBeEnabled() {
77
-    return typeof API_ID === 'number';
78
+    return (
79
+        typeof API_ID === 'number'
80
+
81
+            // XXX Enable the API when a JSON Web Token (JWT) is specified in
82
+            // the location/URL because then it is very likely that the Jitsi
83
+            // Meet (Web) app is being used by an external/wrapping (Web) app
84
+            // and, consequently, the latter will need to communicate with the
85
+            // former. (The described logic is merely a heuristic though.)
86
+            || parseJWTFromURLParams());
78
 }
87
 }
79
 
88
 
80
 /**
89
 /**
102
      * sends a message to the external application that API is initialized.
111
      * sends a message to the external application that API is initialized.
103
      *
112
      *
104
      * @param {Object} options - Optional parameters.
113
      * @param {Object} options - Optional parameters.
105
-     * @param {boolean} options.forceEnable - True to forcefully enable the
106
-     * module.
107
      * @returns {void}
114
      * @returns {void}
108
      */
115
      */
109
-    init({ forceEnable } = {}) {
110
-        if (!shouldBeEnabled() && !forceEnable) {
116
+    init() {
117
+        if (!shouldBeEnabled()) {
111
             return;
118
             return;
112
         }
119
         }
113
 
120
 

+ 6
- 12
modules/keyboardshortcut/keyboardshortcut.js Parādīt failu

1
 /* global APP, $, JitsiMeetJS, interfaceConfig */
1
 /* global APP, $, JitsiMeetJS, interfaceConfig */
2
 
2
 
3
-import {
4
-    toggleDialog
5
-} from '../../react/features/base/dialog';
3
+import { toggleDialog } from '../../react/features/base/dialog';
6
 import { SpeakerStats } from '../../react/features/speaker-stats';
4
 import { SpeakerStats } from '../../react/features/speaker-stats';
7
 
5
 
8
 /**
6
 /**
17
  * triggered _only_ with a shortcut.
15
  * triggered _only_ with a shortcut.
18
  */
16
  */
19
 function initGlobalShortcuts() {
17
 function initGlobalShortcuts() {
20
-
21
     KeyboardShortcut.registerShortcut("ESCAPE", null, function() {
18
     KeyboardShortcut.registerShortcut("ESCAPE", null, function() {
22
         showKeyboardShortcutsPanel(false);
19
         showKeyboardShortcutsPanel(false);
23
     });
20
     });
57
  */
54
  */
58
 function showKeyboardShortcutsPanel(show) {
55
 function showKeyboardShortcutsPanel(show) {
59
     if (show
56
     if (show
60
-        && !APP.UI.messageHandler.isDialogOpened()
61
-        && keyboardShortcutDialog === null) {
62
-
57
+            && !APP.UI.messageHandler.isDialogOpened()
58
+            && keyboardShortcutDialog === null) {
63
         let msg = $('#keyboard-shortcuts').html();
59
         let msg = $('#keyboard-shortcuts').html();
64
         let buttons = { Close: true };
60
         let buttons = { Close: true };
65
 
61
 
66
         keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
62
         keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
67
             'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
63
             'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
68
-    } else {
69
-        if (keyboardShortcutDialog !== null) {
70
-            keyboardShortcutDialog.close();
71
-            keyboardShortcutDialog = null;
72
-        }
64
+    } else if (keyboardShortcutDialog !== null) {
65
+        keyboardShortcutDialog.close();
66
+        keyboardShortcutDialog = null;
73
     }
67
     }
74
 }
68
 }
75
 
69
 

+ 20
- 23
react/features/app/actions.js Parādīt failu

4
 import { loadConfig } from '../base/lib-jitsi-meet';
4
 import { loadConfig } from '../base/lib-jitsi-meet';
5
 
5
 
6
 import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
6
 import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
7
-import {
8
-    _getRouteToRender,
9
-    _parseURIString,
10
-    init
11
-} from './functions';
7
+import { _getRouteToRender, _parseURIString } from './functions';
12
 
8
 
13
-/**
14
- * Temporary solution. Should dispatch actions related to initial settings of
15
- * the app like setting log levels, reading the config parameters from query
16
- * string etc.
17
- *
18
- * @returns {Function}
19
- */
20
-export function appInit() {
21
-    return (dispatch: Dispatch<*>, getState: Function) =>
22
-        init(getState());
23
-}
9
+declare var APP: Object;
24
 
10
 
25
 /**
11
 /**
26
  * Triggers an in-app navigation to a specific route. Allows navigation to be
12
  * Triggers an in-app navigation to a specific route. Allows navigation to be
28
  *
14
  *
29
  * @param {(string|undefined)} uri - The URI to which to navigate. It may be a
15
  * @param {(string|undefined)} uri - The URI to which to navigate. It may be a
30
  * full URL with an HTTP(S) scheme, a full or partial URI with the app-specific
16
  * full URL with an HTTP(S) scheme, a full or partial URI with the app-specific
31
- * sheme, or a mere room name.
17
+ * scheme, or a mere room name.
32
  * @returns {Function}
18
  * @returns {Function}
33
  */
19
  */
34
 export function appNavigate(uri: ?string) {
20
 export function appNavigate(uri: ?string) {
180
  * }}
166
  * }}
181
  */
167
  */
182
 export function appWillMount(app) {
168
 export function appWillMount(app) {
183
-    return {
184
-        type: APP_WILL_MOUNT,
185
-        app
169
+    return (dispatch: Dispatch<*>) => {
170
+        dispatch({
171
+            type: APP_WILL_MOUNT,
172
+            app
173
+        });
174
+
175
+        // TODO There was a redux action creator appInit which I did not like
176
+        // because we already had the redux action creator appWillMount and,
177
+        // respectively, the redux action APP_WILL_MOUNT. So I set out to remove
178
+        // appInit and managed to move everything it was doing but the
179
+        // following. Which is not extremely bad because we haven't moved the
180
+        // API module into its own feature yet so we're bound to work on that in
181
+        // the future.
182
+        typeof APP === 'object' && APP.API.init();
186
     };
183
     };
187
 }
184
 }
188
 
185
 
205
 /**
202
 /**
206
  * Loads config.js from a specific host.
203
  * Loads config.js from a specific host.
207
  *
204
  *
208
- * @param {Object} location - The loction URI which specifies the host to load
205
+ * @param {Object} location - The location URI which specifies the host to load
209
  * the config.js from.
206
  * the config.js from.
210
  * @returns {Promise<Object>}
207
  * @returns {Promise<Object>}
211
  */
208
  */
224
 }
221
 }
225
 
222
 
226
 /**
223
 /**
227
- * Navigates to a route in accord with a specific Redux state.
224
+ * Navigates to a route in accord with a specific redux state.
228
  *
225
  *
229
- * @param {Object} state - The Redux state which determines/identifies the route
226
+ * @param {Object} state - The redux state which determines/identifies the route
230
  * to navigate to.
227
  * to navigate to.
231
  * @private
228
  * @private
232
  * @returns {void}
229
  * @returns {void}

+ 1
- 1
react/features/app/components/AbstractApp.js Parādīt failu

84
         // business logic in the React Component (i.e. UI) AbstractApp now.
84
         // business logic in the React Component (i.e. UI) AbstractApp now.
85
         let localParticipant;
85
         let localParticipant;
86
 
86
 
87
-        if (typeof APP !== 'undefined') {
87
+        if (typeof APP === 'object') {
88
             localParticipant = {
88
             localParticipant = {
89
                 avatarID: APP.settings.getAvatarId(),
89
                 avatarID: APP.settings.getAvatarId(),
90
                 avatarURL: APP.settings.getAvatarUrl(),
90
                 avatarURL: APP.settings.getAvatarUrl(),

+ 0
- 12
react/features/app/components/App.web.js Parādīt failu

1
-import { appInit } from '../actions';
2
 import { AbstractApp } from './AbstractApp';
1
 import { AbstractApp } from './AbstractApp';
3
 import { getLocationContextRoot } from '../functions';
2
 import { getLocationContextRoot } from '../functions';
4
 
3
 
38
         };
37
         };
39
     }
38
     }
40
 
39
 
41
-    /**
42
-     * Inits the app before component will mount.
43
-     *
44
-     * @inheritdoc
45
-     */
46
-    componentWillMount(...args) {
47
-        super.componentWillMount(...args);
48
-
49
-        this._getStore().dispatch(appInit());
50
-    }
51
-
52
     /**
40
     /**
53
      * Gets a Location object from the window with information about the current
41
      * Gets a Location object from the window with information about the current
54
      * location of the document.
42
      * location of the document.

+ 0
- 47
react/features/app/functions.web.js Parādīt failu

1
 /* @flow */
1
 /* @flow */
2
 
2
 
3
-import Logger from 'jitsi-meet-logger';
4
-
5
 import { isRoomValid } from '../base/conference';
3
 import { isRoomValid } from '../base/conference';
6
-import JitsiMeetJS from '../base/lib-jitsi-meet';
7
 import { Platform, RouteRegistry } from '../base/react';
4
 import { Platform, RouteRegistry } from '../base/react';
8
 import { Conference } from '../conference';
5
 import { Conference } from '../conference';
9
 import {
6
 import {
14
 } from '../unsupported-browser';
11
 } from '../unsupported-browser';
15
 import { WelcomePage } from '../welcome';
12
 import { WelcomePage } from '../welcome';
16
 
13
 
17
-import KeyboardShortcut
18
-    from '../../../modules/keyboardshortcut/keyboardshortcut';
19
-import JitsiMeetLogStorage from '../../../modules/util/JitsiMeetLogStorage';
20
-
21
 declare var APP: Object;
14
 declare var APP: Object;
22
 declare var interfaceConfig: Object;
15
 declare var interfaceConfig: Object;
23
 declare var loggingConfig: Object;
16
 declare var loggingConfig: Object;
106
     return route;
99
     return route;
107
 }
100
 }
108
 
101
 
109
-/**
110
- * Temporary solution. Later we'll get rid of global APP and set its properties
111
- * in redux store.
112
- *
113
- * @param {Object} state - Snapshot of current state of redux store.
114
- * @returns {void}
115
- */
116
-export function init(state: Object) {
117
-    _initLogging();
118
-
119
-    APP.keyboardshortcut = KeyboardShortcut;
120
-
121
-    const { jwt } = state['features/jwt'];
122
-
123
-    // Force enable the API if jwt token is passed because most probably
124
-    // jitsi meet is displayed inside of wrapper that will need to communicate
125
-    // with jitsi meet.
126
-    APP.API.init(jwt ? { forceEnable: true } : undefined);
127
-
128
-    APP.translation.init();
129
-}
130
-
131
-/**
132
- * Initializes logging in the app.
133
- *
134
- * @private
135
- * @returns {void}
136
- */
137
-function _initLogging() {
138
-    // Create the LogCollector and register it as the global log transport. It
139
-    // is done early to capture as much logs as possible. Captured logs will be
140
-    // cached, before the JitsiMeetLogStorage gets ready (statistics module is
141
-    // initialized).
142
-    if (!APP.logCollector && !loggingConfig.disableLogCollector) {
143
-        APP.logCollector = new Logger.LogCollector(new JitsiMeetLogStorage());
144
-        Logger.addGlobalTransport(APP.logCollector);
145
-        JitsiMeetJS.addGlobalLogTransport(APP.logCollector);
146
-    }
147
-}
148
-
149
 /**
102
 /**
150
  * Intercepts route components based on a {@link _INTERCEPT_COMPONENT_RULES}.
103
  * Intercepts route components based on a {@link _INTERCEPT_COMPONENT_RULES}.
151
  *
104
  *

+ 0
- 5
react/features/app/index.js Parādīt failu

3
 export * from './components';
3
 export * from './components';
4
 export * from './functions';
4
 export * from './functions';
5
 
5
 
6
-// We need to import the jwt module in order to register the reducer and
7
-// middleware, because the module is not used outside of this feature.
8
-import '../jwt';
9
-
10
 import './reducer';
6
 import './reducer';
11
-

+ 1
- 1
react/features/base/config/parseURLParams.js Parādīt failu

3
 /**
3
 /**
4
  * Parses the parameters from the URL and returns them as a JS object.
4
  * Parses the parameters from the URL and returns them as a JS object.
5
  *
5
  *
6
- * @param {string} url - URL to parse.
6
+ * @param {string} url - The URL to parse.
7
  * @param {boolean} dontParse - If false or undefined some transformations
7
  * @param {boolean} dontParse - If false or undefined some transformations
8
  * (for parsing the value as JSON) are going to be executed.
8
  * (for parsing the value as JSON) are going to be executed.
9
  * @param {string} source - Values - "hash"/"search" if "search" the parameters
9
  * @param {string} source - Values - "hash"/"search" if "search" the parameters

+ 2
- 0
react/features/base/i18n/index.js Parādīt failu

4
 // TODO Eventually (e.g. when the non-React Web app is rewritten into React), it
4
 // TODO Eventually (e.g. when the non-React Web app is rewritten into React), it
5
 // should not be necessary to export i18next.
5
 // should not be necessary to export i18next.
6
 export { default as i18next } from './i18next';
6
 export { default as i18next } from './i18next';
7
+
8
+import './middleware';

+ 48
- 0
react/features/base/i18n/middleware.js Parādīt failu

1
+/* @flow */
2
+
3
+import { SET_CONFIG } from '../config';
4
+import { MiddlewareRegistry } from '../redux';
5
+
6
+declare var APP: Object;
7
+
8
+/**
9
+ * The redux middleware of the feature base/i18n.
10
+ *
11
+ * @param {Store} store - The redux store.
12
+ * @returns {Function}
13
+ * @private
14
+ */
15
+MiddlewareRegistry.register(store => next => action => {
16
+    switch (action.type) {
17
+    case SET_CONFIG:
18
+        return _setConfig(store, next, action);
19
+    }
20
+
21
+    return next(action);
22
+});
23
+
24
+/**
25
+ * Notifies the feature base/i18n that the action SET_CONFIG is being dispatched
26
+ * within a specific redux store.
27
+ *
28
+ * @param {Store} store - The redux store in which the specified action is being
29
+ * dispatched.
30
+ * @param {Dispatch} next - The redux dispatch function to dispatch the
31
+ * specified action to the specified store.
32
+ * @param {Action} action - The redux action SET_CONFIG which is being
33
+ * dispatched in the specified store.
34
+ * @private
35
+ * @returns {Object} The new state that is the result of the reduction of the
36
+ * specified action.
37
+ */
38
+function _setConfig({ dispatch, getState }, next, action) {
39
+    const oldValue = getState()['features/base/config'];
40
+    const result = next(action);
41
+    const newValue = getState()['features/base/config'];
42
+
43
+    if (oldValue !== newValue && typeof APP === 'object') {
44
+        APP.translation.init();
45
+    }
46
+
47
+    return result;
48
+}

+ 26
- 0
react/features/base/logging/middleware.js Parādīt failu

6
 import JitsiMeetJS, { LIB_WILL_INIT } from '../lib-jitsi-meet';
6
 import JitsiMeetJS, { LIB_WILL_INIT } from '../lib-jitsi-meet';
7
 import { MiddlewareRegistry } from '../redux';
7
 import { MiddlewareRegistry } from '../redux';
8
 
8
 
9
+import JitsiMeetLogStorage from '../../../../modules/util/JitsiMeetLogStorage';
10
+
9
 import { SET_LOGGING_CONFIG } from './actionTypes';
11
 import { SET_LOGGING_CONFIG } from './actionTypes';
10
 
12
 
11
 declare var APP: Object;
13
 declare var APP: Object;
60
     return next(action);
62
     return next(action);
61
 }
63
 }
62
 
64
 
65
+/**
66
+ * Initializes logging in the app.
67
+ *
68
+ * @param {Object} loggingConfig - The configuration with which logging is to be
69
+ * initialized.
70
+ * @private
71
+ * @returns {void}
72
+ */
73
+function _initLogging(loggingConfig) {
74
+    // Create the LogCollector and register it as the global log transport. It
75
+    // is done early to capture as much logs as possible. Captured logs will be
76
+    // cached, before the JitsiMeetLogStorage gets ready (statistics module is
77
+    // initialized).
78
+    if (typeof APP === 'object'
79
+            && !APP.logCollector
80
+            && !loggingConfig.disableLogCollector) {
81
+        APP.logCollector = new Logger.LogCollector(new JitsiMeetLogStorage());
82
+        Logger.addGlobalTransport(APP.logCollector);
83
+        JitsiMeetJS.addGlobalLogTransport(APP.logCollector);
84
+    }
85
+}
86
+
63
 /**
87
 /**
64
  * Notifies the feature base/logging that the action {@link LIB_WILL_INIT} is
88
  * Notifies the feature base/logging that the action {@link LIB_WILL_INIT} is
65
  * being dispatched within a specific Redux {@code store}.
89
  * being dispatched within a specific Redux {@code store}.
102
     if (oldValue !== newValue) {
126
     if (oldValue !== newValue) {
103
         _setLogLevels(Logger, newValue);
127
         _setLogLevels(Logger, newValue);
104
         _setLogLevels(JitsiMeetJS, newValue);
128
         _setLogLevels(JitsiMeetJS, newValue);
129
+
130
+        _initLogging(newValue);
105
     }
131
     }
106
 
132
 
107
     return result;
133
     return result;

+ 16
- 0
react/features/jwt/functions.js Parādīt failu

1
+/* @flow */
2
+
3
+import { parseURLParams } from '../base/config';
4
+
5
+/**
6
+ * Retrieves the JSON Web Token (JWT), if any, defined by a specific
7
+ * {@link URL}.
8
+ *
9
+ * @param {URL} url - The {@code URL} to parse and retrieve the JSON Web Token
10
+ * (JWT), if any, from.
11
+ * @returns {string} The JSON Web Token (JWT), if any, defined by the specified
12
+ * {@code url}; otherwise, {@code undefined}.
13
+ */
14
+export function parseJWTFromURLParams(url: URL = window.location) {
15
+    return parseURLParams(url, true, 'search').jwt;
16
+}

+ 1
- 0
react/features/jwt/index.js Parādīt failu

1
 export * from './actions';
1
 export * from './actions';
2
+export * from './functions';
2
 
3
 
3
 import './middleware';
4
 import './middleware';
4
 import './reducer';
5
 import './reducer';

+ 3
- 2
react/features/jwt/middleware.js Parādīt failu

1
 import jwtDecode from 'jwt-decode';
1
 import jwtDecode from 'jwt-decode';
2
 
2
 
3
-import { parseURLParams, SET_CONFIG } from '../base/config';
3
+import { SET_CONFIG } from '../base/config';
4
 import { SET_LOCATION_URL } from '../base/connection';
4
 import { SET_LOCATION_URL } from '../base/connection';
5
 import { MiddlewareRegistry } from '../base/redux';
5
 import { MiddlewareRegistry } from '../base/redux';
6
 
6
 
7
 import { setJWT } from './actions';
7
 import { setJWT } from './actions';
8
 import { SET_JWT } from './actionTypes';
8
 import { SET_JWT } from './actionTypes';
9
+import { parseJWTFromURLParams } from './functions';
9
 
10
 
10
 /**
11
 /**
11
  * Middleware to parse token data upon setting a new room URL.
12
  * Middleware to parse token data upon setting a new room URL.
55
     let jwt;
56
     let jwt;
56
 
57
 
57
     if (locationURL) {
58
     if (locationURL) {
58
-        jwt = parseURLParams(locationURL, true, 'search').jwt;
59
+        jwt = parseJWTFromURLParams(locationURL);
59
     }
60
     }
60
     dispatch(setJWT(jwt));
61
     dispatch(setJWT(jwt));
61
 
62
 

Notiek ielāde…
Atcelt
Saglabāt