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

DFE-42: Enable context isolation #141

Merged
merged 13 commits into from
Dec 4, 2023
3 changes: 1 addition & 2 deletions api/app-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@
* height: 700,
* resizable: true,
* webPreferences: {
* plugins: true,
* nodeIntegration: true
* plugins: true
* }
* });
* win.loadURL('file://index.html');
Expand Down
36 changes: 18 additions & 18 deletions api/downstream-electron-be.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*eslint no-console: ["error", { allow: ["warn", "error", "info"] }] */
"use strict";
'use strict';

const _ = require('underscore');
const Snowflake = require("./util/snowflake-id");
const Snowflake = require('./util/snowflake-id');

const appSettings = require('./app-settings');
const beMethods = require('./be-methods-all');
Expand Down Expand Up @@ -49,8 +50,7 @@ function deserialize (serializedJavascript) {
* height: 700,
* resizable: true,
* webPreferences: {
* plugins: true,
* nodeIntegration: true
* plugins: true
* }
* });
* win.loadURL('file://index.html');
Expand All @@ -70,7 +70,7 @@ function deserialize (serializedJavascript) {
*/
DownstreamElectronBE = function () {
this._offlineContentPort = appSettings.getSettings().offlineContentPortStart;
_.bindAll(this, "_onApiRequest", "processSubscriber");
_.bindAll(this, '_onApiRequest', 'processSubscriber');
this._createControllers();
this._serveOfflineContent();
this._attachEvents();
Expand All @@ -97,7 +97,7 @@ DownstreamElectronBE.prototype._apiMethods = function (methodName, promiseId, ar
response.promiseId = promiseId;
const onSuccess = function (result, subscribersId) {
response.subscribersId = subscribersId;
response.status = "OK";
response.status = 'OK';
response.result = result;
response.manifestId = manifestId;
self._send(response, target);
Expand All @@ -112,7 +112,7 @@ DownstreamElectronBE.prototype._apiMethods = function (methodName, promiseId, ar
internalError: internalError
});
response.manifestId = manifestId;
response.status = "ERROR";
response.status = 'ERROR';
response.error = err || {};
response.error.errorId = errorId;
response.error.details = internalError;
Expand All @@ -121,7 +121,7 @@ DownstreamElectronBE.prototype._apiMethods = function (methodName, promiseId, ar

// @TODO log all errors that user have seen, the errorId will help to find stack
try {
console.error(new Date(), "Error occurred", JSON.stringify(errorInfo));
console.error(new Date(), 'Error occurred', JSON.stringify(errorInfo));
} catch (e) {
//do nothing
}
Expand All @@ -132,13 +132,13 @@ DownstreamElectronBE.prototype._apiMethods = function (methodName, promiseId, ar
args.unshift(onSuccess);
args.unshift(this);
const method = this._getMethod(methodName);
if (typeof method === "function") {
if (typeof method === 'function') {
method.apply(null, args);
} else {
response.status = "ERROR";
response.status = 'ERROR';
response.error = "Provided method '" + methodName + "' doesn't exists";
this._send(response, target);
console.error("ERROR", "Provided method '" + methodName + "' doesn't exists");
console.error('ERROR', "Provided method '" + methodName + "' doesn't exists");
}
};

Expand All @@ -149,7 +149,7 @@ DownstreamElectronBE.prototype._apiMethods = function (methodName, promiseId, ar
*/
DownstreamElectronBE.prototype._attachEvents = function () {
const ipcMain = require('electron').ipcMain;
ipcMain.on("downstreamElectronBE", this._onApiRequest);
ipcMain.on('downstreamElectronBE', this._onApiRequest);
};

/**
Expand All @@ -171,7 +171,7 @@ DownstreamElectronBE.prototype._createControllers = function () {
* @private
*/
DownstreamElectronBE.prototype._getMethod = function (methodName) {
const names = methodName.split(".");
const names = methodName.split('.');
let i, j, method;
method = beMethods[names[0]];
for (i = 1, j = names.length; i < j; i++) {
Expand All @@ -192,7 +192,7 @@ DownstreamElectronBE.prototype._onApiRequest = function (evt, data, target) {
const promiseId = data.promiseId;
const argsObj = deserialize(data.args) || {};
const method = data.method;
const windowId = data.windowId;
const windowId = evt.sender.getOwnerBrowserWindow().id;
target = windowId;
let args = [];
let i = 0;
Expand All @@ -219,7 +219,7 @@ DownstreamElectronBE.prototype._send = function (response, target) {
}
}
} catch (err) {
console.error("internal error ocurred", err);
console.error('internal error ocurred', err);
}
};

Expand Down Expand Up @@ -247,9 +247,9 @@ DownstreamElectronBE.prototype.getOfflinePath = function (manifestId) {
let offlinePath = appSettings.getSettings().offlineDomain;
let offlineContentPort = this._offlineContentPort;
if (offlineContentPort) {
offlinePath += ":" + offlineContentPort;
offlinePath += ':' + offlineContentPort;
}
offlinePath += "/" + encodeURIComponent(appSettings.getSettings().downloadsName) + "/" + encodeURIComponent(manifestId) + "/";
offlinePath += '/' + encodeURIComponent(appSettings.getSettings().downloadsName) + '/' + encodeURIComponent(manifestId) + '/';
return offlinePath;
};

Expand All @@ -265,7 +265,7 @@ DownstreamElectronBE.prototype.getOfflinePath = function (manifestId) {
DownstreamElectronBE.prototype.processSubscriber = function (subscriberId, err, result, target, subscriberFinished) {
let response = {};
response.subscriberId = subscriberId;
response.status = err ? "ERROR" : "OK";
response.status = err ? 'ERROR' : 'OK';
response.err = err;
response.result = result;
response.subscriberFinished = subscriberFinished;
Expand Down
25 changes: 11 additions & 14 deletions api/downstream-electron-fe.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
'use strict';
const WIDEVINE_SCHEME_ID_URI = 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed';

const ipcRenderer = require('electron').ipcRenderer;

const translation = require("./translation/index");

let downstreamElectronFE;

function serialize (obj) {
Expand Down Expand Up @@ -73,10 +69,6 @@ function clonePersistentConfig (config) {
* all methods described in ({@link DownstreamElectronFE.downloads})
*/
function DownstreamElectronFE (window, persistent) {
let currentWindow = require('@electron/remote').getCurrentWindow();
if (currentWindow) {
this._windowId = currentWindow.id;
}
this._promisesObj = {};
this._subscribersId = {};
this._promiseCounter = 0;
Expand Down Expand Up @@ -126,7 +118,7 @@ DownstreamElectronFE.prototype.downloads.createPersistent = function (args, reso
if (this._persistent) {
this.downloads.info(manifestId).then(function (info) {
if (!info) {
reject(translation.getError(translation.e.manifests.NOT_FOUND, manifestId));
reject("Manifest with id='" + manifestId + "' not found.");
return;
}
const existingPersistentSessionId = info.persistent;
Expand Down Expand Up @@ -249,7 +241,6 @@ DownstreamElectronFE.prototype._apiCall = function (method, args, originalMethod
let request = {};
request.promiseId = promiseId;
request.method = method;
request.windowId = this._windowId;
request.args = serialize(args);
this._send(request);
return promise;
Expand All @@ -261,9 +252,15 @@ DownstreamElectronFE.prototype._apiCall = function (method, args, originalMethod
* @returns {void}
*/
DownstreamElectronFE.prototype._attachEvents = function () {
const ipcRenderer = require('electron').ipcRenderer;
ipcRenderer.on('downstreamElectronFE', this._processApi);
this._window.addEventListener('beforeunload', this._beforeUnload);
this._window.downstreamElectronAPI.receive('downstreamElectronFE', this._processApi);
this._window.onbeforeunload = (e) => {
this._beforeUnload();
// Unlike usual browsers that a message box will be prompted to users, returning
// a non-void value will silently cancel the close.
// It is recommended to use the dialog API to let the user confirm closing the
// application.
e.returnValue = false
}
};

/**
Expand Down Expand Up @@ -500,7 +497,7 @@ DownstreamElectronFE.prototype._saveSubscribersId = function (promise, subscribe
*/
DownstreamElectronFE.prototype._send = function (request) {
try {
ipcRenderer.send('downstreamElectronBE', request);
this._window.downstreamElectronAPI.send('downstreamElectronBE', request);
} catch (e) {
console.error(e);
}
Expand Down
27 changes: 27 additions & 0 deletions api/downstream-electron-preload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const {
contextBridge,
ipcRenderer
} = require('electron');

const downstreamElectron = require('./downstream-electron-fe.js');

// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
'downstreamElectronAPI', {
init: (window, persitance) => downstreamElectron.init(window, persitance),
send: (channel, data) => {
// whitelist channels
let validChannels = ['downstreamElectronBE'];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = ['downstreamElectronFE'];
if (validChannels.includes(channel)) {
ipcRenderer.on(channel, (event, ...args) => func(event, args.find(() => true)));
}
}
}
);
59 changes: 52 additions & 7 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
const {BrowserWindow, app, components} = require('electron');
const {
BrowserWindow,
app,
components,
ipcMain
} = require('electron');
const fs = require('fs');

require('@electron/remote/main').initialize();

// TESTING PRODUCTION
let index = './index';
if (!fs.existsSync(index)) {
Expand Down Expand Up @@ -47,12 +50,12 @@ function createWindow () {
height: 700,
resizable: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
plugins: true,
nodeIntegration: true,
// NOTE: !WARNING! use with caution it allows app to download content
// from any URL
webSecurity: false,
contextIsolation: false
webSecurity: false
}
});

Expand All @@ -77,6 +80,48 @@ app.on('window-all-closed', () => {
app.quit();
});

app.on('browser-window-created', (_, window) => {
require("@electron/remote/main").enable(window.webContents);
function playVideo (link, offlineSessionId, config) {
let playerWindow = new BrowserWindow({
width: 860,
height: 600,
show: true,
resizable: true,
webPreferences: {
plugins: true,
preload: path.join(__dirname, 'player/preload.js'),
// NOTE: !WARNING! use with caution it allows app to download content
// from any URL
webSecurity: false
}
});

const playerUrl = `file://${__dirname}/player/index.html`;

playerWindow.loadURL(playerUrl);
playerWindow.webContents.openDevTools();
playerWindow.webContents.on('did-finish-load', function (evt, args) {
playerWindow.webContents.send('utilsAPI', 'startPlaybackStream', {
url: link,
configuration: config,
offlineSessionId: offlineSessionId
});
});
}

ipcMain.on('utilsAPI', (event, message, ...args) => {
if (message === 'playVideo') {
playVideo(...args);
}
});


ipcMain.handle('utilsAPI', (event, message, ...args) => {
if (message === 'prepareTestFiles') {
var videoPath = args[0];
var audioPath = args[1];

return [
fs.readFileSync(videoPath).buffer,
fs.readFileSync(audioPath).buffer];
}
});
2 changes: 1 addition & 1 deletion downstream-electron-be.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion downstream-electron-be.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* downstream-electron,0.6.0,2023-11-29 13:00:33.608,castlabs GmbH
* downstream-electron,0.6.0,2023-12-04 15:37:24.209,castlabs GmbH
*
* Copyright (C) 2017 Castlabs GmbH.
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 1 addition & 1 deletion downstream-electron-fe.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion downstream-electron-fe.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* downstream-electron,0.6.0,2023-11-29 13:00:33.608,castlabs GmbH
* downstream-electron,0.6.0,2023-12-04 15:37:24.209,castlabs GmbH
*
* Copyright (C) 2017 Castlabs GmbH.
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
2 changes: 2 additions & 0 deletions downstream-electron-preload.js

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions downstream-electron-preload.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*!
* downstream-electron,0.6.0,2023-12-04 15:37:24.209,castlabs GmbH
*
* Copyright (C) 2017 Castlabs GmbH.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
14 changes: 8 additions & 6 deletions examples/drm/index.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>Electron API</title>
<script src="index.js"></script>

<script type="text/javascript" src="../../node_modules/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="index.js"></script>

<style>
#status {
margin: 10px 0;
Expand Down Expand Up @@ -52,23 +56,21 @@
display: block;
}

.progressItem .key {

}
.progressItem .key {}

.progressItem .stats {
color: #0057e7;
font-weight: 700;
}

</style>
</head>

<body>

<h3 id="header">Simple DRM example</h3>
<div id="videoOfflineWrapper">
<video id="videoOffline" crossOrigin="anonymous" hidden controls style="padding: 10px; width: 430px; height: 300px;">
<video id="videoOffline" crossOrigin="anonymous" hidden controls
style="padding: 10px; width: 430px; height: 300px;">
Your browser does not support HTML5 video.
</video>
</div>
Expand Down
Loading