Skip to content

Commit

Permalink
Merge pull request #59 from csett86/ffmuc-release-2022-10-1
Browse files Browse the repository at this point in the history
Merge upstream release v2022.10.1
  • Loading branch information
GoliathLabs authored Oct 28, 2022
2 parents afda070 + 30f46c9 commit ea9ab9d
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 224 deletions.
14 changes: 0 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,6 @@ For *macOS* user, you can install the application using the following command:
brew install --cask freifunkMUC/freifunkmeet/freifunk-meet
```

### Using it with your own Jitsi Meet installation

:warning: The following additional HTTP headers are known to break the Electron App:

```
Content-Security-Policy "frame-ancestors [looks like any value is bad]";
X-Frame-Options "DENY";
X-Frame-Options "sameorigin";
```
A working Content Security Policy looks like that:
```
Content-Security-Policy "img-src 'self' 'unsafe-inline' data:; script-src 'self' 'unsafe-inline' 'wasm-eval'; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'none';";
```

## Development

If you want to hack on this project, here is how you do it.
Expand Down
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;
}
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
46 changes: 35 additions & 11 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ app.commandLine.appendSwitch('disable-site-isolation-trials');

// This allows BrowserWindow.setContentProtection(true) to work on macOS.
// https://github.com/electron/electron/issues/19880
app.commandLine.appendSwitch('disable-features', 'IOSurfaceCapturer');
app.commandLine.appendSwitch('disable-features', 'DesktopCaptureMacV2,IOSurfaceCapturer');

// Enable Opus RED field trial.
app.commandLine.appendSwitch('force-fieldtrials', 'WebRTC-Audio-Red-For-Opus/Enabled/');
Expand Down Expand Up @@ -207,30 +207,54 @@ 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);

// Filter out x-frame-options and frame-ancestors CSP to allow loading jitsi via the iframe API
// Resolves https://github.com/jitsi/jitsi-meet-electron/issues/285
mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
delete details.responseHeaders['x-frame-options'];

if (details.responseHeaders['content-security-policy']) {
const cspFiltered = details.responseHeaders['content-security-policy'][0]
.split(';')
.filter(x => x.indexOf('frame-ancestors') === -1)
.join(';');

details.responseHeaders['content-security-policy'] = [ cspFiltered ];
}

callback({
responseHeaders: details.responseHeaders
});
});

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

0 comments on commit ea9ab9d

Please sign in to comment.