Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge upstream release v2022.9.1 #56

Merged
merged 8 commits into from
Oct 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions app/features/conference/components/Conference.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { push } from 'react-router-redux';
import i18n from '../../../i18n';
import config from '../../config';
import { getSetting } from '../../settings';
import { parseURLParams } from '../../utils/parseURLParams';

import { conferenceEnded, conferenceJoined } from '../actions';
import JitsiMeetExternalAPI from '../external_api';
Expand Down Expand Up @@ -178,14 +179,7 @@ class Conference extends Component<Props, State> {
const roomName = url.pathname.split('/').pop();
const host = this._conference.serverURL.replace(/https?:\/\//, '');
const searchParameters = Object.fromEntries(url.searchParams);
const hashParameters = url.hash.substring(1).split('&')
.reduce((res, item) => {
const parts = item.split('=');

res[parts[0]] = parts[1];

return res;
}, {});
const hashParameters = parseURLParams(url);

const locale = { lng: i18n.language };
const urlParameters = {
Expand Down
2 changes: 1 addition & 1 deletion app/features/conference/external_api.js

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions app/features/utils/parseURLParams.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import Bourne from '@hapi/bourne';

/**
* Prints the error and reports it to the global error handler.
*
* @param {Error} e - The error object.
* @param {string} msg - A custom message to print in addition to the error.
* @returns {void}
*/
export function reportError(e, msg = '') {
console.error(msg, e);
window.onerror && window.onerror(msg, undefined, undefined, undefined, e);
}


/**
* A list if keys to ignore when parsing.
*
* @type {string[]}
*/
const blacklist = [ '__proto__', 'constructor', 'prototype' ];

/**
* Parses the query/search or fragment/hash parameters out of a specific URL and
* returns them as a JS object.
*
* @param {URL} url - The URL to parse.
* @param {boolean} dontParse - If falsy, some transformations (for parsing the
* value as JSON) will be executed.
* @param {string} source - If {@code 'search'}, the parameters will parsed out
* of {@code url.search}; otherwise, out of {@code url.hash}.
* @returns {Object}
*/
export function parseURLParams(
url,
dontParse = false,
source = 'hash') {
if (typeof url === 'string') {
// eslint-disable-next-line no-param-reassign
url = new URL(url);
}
const paramStr = source === 'search' ? url.search : url.hash;
const params = {};
const paramParts = (paramStr && paramStr.substring(1).split('&')) || [];

// Detect and ignore hash params for hash routers.
if (source === 'hash' && paramParts.length === 1) {
const firstParam = paramParts[0];

if (firstParam.startsWith('/') && firstParam.split('&').length === 1) {
return params;
}
}

paramParts.forEach(part => {
const param = part.split('=');
const key = param[0];

if (!key || key.split('.').some(k => blacklist.includes(k))) {
return;
}

let value;

try {
value = param[1];

if (!dontParse) {
const decoded = decodeURIComponent(value).replace(/\\&/, '&');

value = decoded === 'undefined' ? undefined : Bourne.parse(decoded);
}
} catch (e) {
reportError(
e, `Failed to parse URL parameter value: ${String(value)}`);

return;
}
params[key] = value;
});

return params;
}
4 changes: 3 additions & 1 deletion app/i18n/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ const languages = {
nl: { translation: require('./lang/nl.json') },
pt: { translation: require('./lang/pt-br.json') },
ru: { translation: require('./lang/ru.json') },
sq: { translation: require('./lang/sq.json') }
sq: { translation: require('./lang/sq.json') },
'zh-CN': { translation: require('./lang/zh-CN.json') },
'zh-TW': { translation: require('./lang/zh-TW.json') }
};

const detectedLocale = navigator.language;
Expand Down
33 changes: 33 additions & 0 deletions app/i18n/lang/zh-CN.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"enterConferenceNameOrUrl": "输入你的会议室名称或Jitsi网址",
"go": "开始",
"help": "帮助",
"termsLink": "条款",
"privacyLink": "隐私",
"recentListLabel": "或重新加入最近的会议",
"sendFeedbackLink": "发送反馈",
"aboutLink": "关于",
"sourceLink": "源代码",
"versionLabel": "版本:{{version}}",
"onboarding": {
"startTour": "开始参观",
"skip": "跳过",
"welcome": "欢迎使用{{appName}}",
"letUsShowYouAround": "让我们带你参观一下!",
"next": "下一个",
"conferenceUrl": "输入你想加入的会议室的名称(或完整的网址),你也可以使用不同的名称创建会议室,其他人只需输入相同的名称即可加入。",
"settingsDrawerButton": "点击此处打开设置。",
"serverSetting": "这将是你开始会议的服务器,你可以使用自己的服务器,但你无需这样做!",
"serverTimeout": "加入会议超时,如果在超时之前未加入会议,则会议将被取消。",
"alwaysOnTop": "你可以选择是否要启用“始终置顶”,该窗口在主窗口失去焦点时显示,这将适用于所有会议。"
},
"settings": {
"back": "返回",
"alwaysOnTopWindow": "始终置顶",
"invalidServer": "服务器网址无效",
"invalidServerTimeout": "服务器超时值无效",
"serverUrl": "服务器网址",
"serverTimeout": "服务器超时(秒)",
"disableAGC": "禁用自动增益控制"
}
}
33 changes: 33 additions & 0 deletions app/i18n/lang/zh-TW.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"enterConferenceNameOrUrl": "輸入會議室名稱或Jitsi網址",
"go": "開始",
"help": "協助",
"termsLink": "條款",
"privacyLink": "隱私權",
"recentListLabel": "或重新加入最近的會議",
"sendFeedbackLink": "傳送意見反應",
"aboutLink": "關於",
"sourceLink": "原始碼",
"versionLabel": "版本:{{version}}",
"onboarding": {
"startTour": "開始遊覽",
"skip": "跳過",
"welcome": "歡迎使用{{appName}}",
"letUsShowYouAround": "讓我們帶你四處逛逛!",
"next": "Next",
"conferenceUrl": "請輸入您想加入的會議室名稱(或完整網址),您可以想一個名稱來建立會議室,只要其他人輸入相同的名稱就能加入會議室喔。",
"settingsDrawerButton": "按一下這裡開啟設定。",
"serverSetting": "這將是您開始會議的伺服器,您可以使用自己的伺服器,但您無需這樣做!",
"serverTimeout": "加入會議超時,如果在超時之前沒有加入會議,則會議將被取消。",
"alwaysOnTop": "您可以選擇是否啟用「保持在最上層」,該視窗將在主視窗失去焦點時顯示,這將適用於所有會議。"
},
"settings": {
"back": "返回",
"alwaysOnTopWindow": "保持在最上層",
"invalidServer": "伺服器網址無效",
"invalidServerTimeout": "伺服器超時值無效",
"serverUrl": "伺服器網址",
"serverTimeout": "伺服器超時(秒)",
"disableAGC": "停用自動取得控制"
}
}
2 changes: 1 addition & 1 deletion app/preload/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function setupRenderer(api, options = {}) {

// Allow window to be on top if enabled in settings
if (options.enableAlwaysOnTopWindow) {
setupAlwaysOnTopRender(api);
setupAlwaysOnTopRender(api, null, { showOnPrejoin: true });
}

// Disable WiFiStats on mac due to jitsi-meet-electron#585
Expand Down
25 changes: 15 additions & 10 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,30 +207,35 @@ function createJitsiMeetWindow() {
enableBlinkFeatures: 'WebAssemblyCSP',
contextIsolation: false,
nodeIntegration: false,
preload: path.resolve(basePath, './build/preload.js')
preload: path.resolve(basePath, './build/preload.js'),
sandbox: false
}
};

const windowOpenHandler = ({ url, frameName }) => {
const target = getPopupTarget(url, frameName);

if (!target || target === 'browser') {
openExternalLink(url);
}

return { action: 'deny' };
};

mainWindow = new BrowserWindow(options);
windowState.manage(mainWindow);
mainWindow.loadURL(indexURL);

mainWindow.webContents.setWindowOpenHandler(windowOpenHandler);

initPopupsConfigurationMain(mainWindow);
setupAlwaysOnTopMain(mainWindow);
setupAlwaysOnTopMain(mainWindow, null, windowOpenHandler);
setupPowerMonitorMain(mainWindow);
setupScreenSharingMain(mainWindow, config.default.appName, pkgJson.build.appId);
if (ENABLE_REMOTE_CONTROL) {
new RemoteControlMain(mainWindow); // eslint-disable-line no-new
}

mainWindow.webContents.on('new-window', (event, url, frameName) => {
const target = getPopupTarget(url, frameName);

if (!target || target === 'browser') {
event.preventDefault();
openExternalLink(url);
}
});
mainWindow.on('closed', () => {
mainWindow = null;
});
Expand Down
Loading