diff --git a/react/features/app/actions.native.ts b/react/features/app/actions.native.ts index 23ef235c14..1af9a36f9d 100644 --- a/react/features/app/actions.native.ts +++ b/react/features/app/actions.native.ts @@ -151,7 +151,7 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) { } dispatch(setLocationURL(locationURL)); - dispatch(setConfig(config)); + dispatch(setConfig(config, locationURL)); dispatch(setRoom(room)); if (!room) { diff --git a/react/features/app/actions.web.ts b/react/features/app/actions.web.ts index 476b4148f0..9c482a33ba 100644 --- a/react/features/app/actions.web.ts +++ b/react/features/app/actions.web.ts @@ -74,7 +74,7 @@ export function appNavigate(uri?: string) { const config = await loadConfig(); dispatch(setLocationURL(locationURL)); - dispatch(setConfig(config)); + dispatch(setConfig(config, locationURL)); dispatch(setRoom(room)); }; } diff --git a/react/features/base/conference/actions.ts b/react/features/base/conference/actions.ts index ad54cf60b1..6769effdf5 100644 --- a/react/features/base/conference/actions.ts +++ b/react/features/base/conference/actions.ts @@ -984,7 +984,7 @@ export function setStartMutedPolicy( * @param {string} subject - The new subject. * @returns {void} */ -export function setSubject(subject: string) { +export function setSubject(subject: string | undefined) { return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const { conference } = getState()['features/base/conference']; @@ -1008,7 +1008,7 @@ export function setSubject(subject: string) { * localSubject: string * }} */ -export function setLocalSubject(localSubject: string) { +export function setLocalSubject(localSubject: string | undefined) { return { type: CONFERENCE_LOCAL_SUBJECT_CHANGED, localSubject diff --git a/react/features/base/conference/functions.ts b/react/features/base/conference/functions.ts index 49802797e7..37801e2faf 100644 --- a/react/features/base/conference/functions.ts +++ b/react/features/base/conference/functions.ts @@ -185,12 +185,18 @@ export function forEachConference( export function getConferenceName(stateful: IStateful): string { const state = toState(stateful); const { callee } = state['features/base/jwt']; - const { callDisplayName } = state['features/base/config']; + const { + callDisplayName, + localSubject: configLocalSubject, + subject: configSubject + } = state['features/base/config']; const { localSubject, pendingSubjectChange, room, subject } = getConferenceState(state); return (pendingSubjectChange - || localSubject + || configSubject || subject + || configLocalSubject + || localSubject || callDisplayName || callee?.name || (room && safeStartCase(safeDecodeURIComponent(room)))) ?? ''; diff --git a/react/features/base/conference/middleware.any.ts b/react/features/base/conference/middleware.any.ts index 224cb50588..9665a39e33 100644 --- a/react/features/base/conference/middleware.any.ts +++ b/react/features/base/conference/middleware.any.ts @@ -592,8 +592,8 @@ function _setRoom({ dispatch, getState }: IStore, next: Function, action: AnyAct if (room) { // Set the stored subject. - dispatch(setLocalSubject(localSubject ?? '')); - dispatch(setSubject(subject ?? '')); + localSubject && dispatch(setLocalSubject(localSubject)); + subject && dispatch(setSubject(subject)); } return next(action); diff --git a/react/features/base/config/actions.ts b/react/features/base/config/actions.ts index 59020bb0ec..643fe96b3e 100644 --- a/react/features/base/config/actions.ts +++ b/react/features/base/config/actions.ts @@ -96,53 +96,51 @@ export function overwriteConfig(config: Object) { * * @param {Object} config - The configuration to be represented by the feature * base/config. + * @param {URL} locationURL - The URL of the location which necessitated the + * loading of a configuration. * @returns {Function} */ -export function setConfig(config: IConfig = {}) { - return (dispatch: IStore['dispatch'], getState: IStore['getState']) => { - const { locationURL } = getState()['features/base/connection']; +export function setConfig(config: IConfig = {}, locationURL: URL | undefined) { + // Now that the loading of the config was successful override the values + // with the parameters passed in the hash part of the location URI. + // TODO We're still in the middle ground between old Web with config, + // and interfaceConfig used via global variables and new + // Web and mobile reading the respective values from the redux store. + // Only the config will be overridden on React Native, as the other + // globals will be undefined here. It's intentional - we do not care to + // override those configs yet. + locationURL + && setConfigFromURLParams( - // Now that the loading of the config was successful override the values - // with the parameters passed in the hash part of the location URI. - // TODO We're still in the middle ground between old Web with config, - // and interfaceConfig used via global variables and new - // Web and mobile reading the respective values from the redux store. - // Only the config will be overridden on React Native, as the other - // globals will be undefined here. It's intentional - we do not care to - // override those configs yet. - locationURL - && setConfigFromURLParams( + // On Web the config also comes from the window.config global, + // but it is resolved in the loadConfig procedure. + config, + window.interfaceConfig, + locationURL); - // On Web the config also comes from the window.config global, - // but it is resolved in the loadConfig procedure. - config, - window.interfaceConfig, - locationURL); + let { bosh } = config; - let { bosh } = config; + if (bosh) { + // Normalize the BOSH URL. + if (bosh.startsWith('//')) { + // By default our config.js doesn't include the protocol. + bosh = `${locationURL?.protocol}${bosh}`; + } else if (bosh.startsWith('/')) { + // Handle relative URLs, which won't work on mobile. + const { + protocol, + host, + contextRoot + } = parseURIString(locationURL?.href); - if (bosh) { - // Normalize the BOSH URL. - if (bosh.startsWith('//')) { - // By default our config.js doesn't include the protocol. - bosh = `${locationURL?.protocol}${bosh}`; - } else if (bosh.startsWith('/')) { - // Handle relative URLs, which won't work on mobile. - const { - protocol, - host, - contextRoot - } = parseURIString(locationURL?.href); - - bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`; - } - config.bosh = bosh; + bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`; } + config.bosh = bosh; + } - dispatch({ - type: SET_CONFIG, - config - }); + return { + type: SET_CONFIG, + config }; } diff --git a/react/features/base/util/parseURLParams.ts b/react/features/base/util/parseURLParams.ts index 78c2790104..c8a152fab5 100644 --- a/react/features/base/util/parseURLParams.ts +++ b/react/features/base/util/parseURLParams.ts @@ -60,9 +60,12 @@ export function parseURLParams( value = param[1]; if (!dontParse) { - const decoded = decodeURIComponent(value).replace(/\\&/, '&'); + const decoded = decodeURIComponent(value).replace(/\\&/, '&') + .replace(/[\u2018\u2019]/g, '\'') + .replace(/[\u201C\u201D]/g, '"'); value = decoded === 'undefined' ? undefined : safeJsonParse(decoded); + } } catch (e: any) { reportError( diff --git a/react/features/prejoin/components/web/PrejoinApp.tsx b/react/features/prejoin/components/web/PrejoinApp.tsx index 7aaa5d592d..899592ae2d 100644 --- a/react/features/prejoin/components/web/PrejoinApp.tsx +++ b/react/features/prejoin/components/web/PrejoinApp.tsx @@ -50,6 +50,9 @@ export default class PrejoinApp extends BaseApp { ? store.getState()['features/base/settings'] : { startWithAudioMuted: undefined, startWithVideoMuted: undefined }; + const { locationURL } = store + ? store.getState()['features/base/connection'] + : { locationURL: undefined }; dispatch?.(setConfig({ prejoinConfig: { @@ -57,7 +60,7 @@ export default class PrejoinApp extends BaseApp { }, startWithAudioMuted, startWithVideoMuted - })); + }, locationURL)); await dispatch?.(setupInitialDevices()); const { tryCreateLocalTracks, errors } = createPrejoinTracks();