Skip to content

Commit e54955f

Browse files
committed
Merge tag 'v0.3.2'
2 parents dd09138 + 1b1c17a commit e54955f

48 files changed

Lines changed: 10086 additions & 5388 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ npm-debug.log
44
build
55
dist
66
docs
7+
test/tmp
78
.build
89
.coverage
910
.dist

Cargo.precompiled.toml

Lines changed: 0 additions & 19 deletions
This file was deleted.

Cargo.toml

Lines changed: 0 additions & 18 deletions
This file was deleted.

build.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

electron/index.js

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,20 @@ const fetchParity = require('./operations/fetchParity');
2525
const handleError = require('./operations/handleError');
2626
const messages = require('./messages');
2727
const { killParity } = require('./operations/runParity');
28+
const { getLocalDappsPath } = require('./utils/paths');
29+
const { name: appName } = require('../package.json');
2830

2931
const { app, BrowserWindow, ipcMain, session } = electron;
32+
const { URL } = url;
33+
3034
let mainWindow;
3135

36+
// Disable gpu acceleration on linux
37+
// https://github.com/parity-js/shell/issues/157
38+
if (!['darwin', 'win32'].includes(process.platform)) {
39+
app.disableHardwareAcceleration();
40+
}
41+
3242
function createWindow () {
3343
// Will send these variables to renderers via IPC
3444
global.dirName = __dirname;
@@ -37,13 +47,10 @@ function createWindow () {
3747

3848
mainWindow = new BrowserWindow({
3949
height: 800,
40-
width: 1200
50+
width: 1200,
51+
webPreferences: { nodeIntegrationInWorker: true }
4152
});
4253

43-
doesParityExist()
44-
.catch(() => fetchParity(mainWindow)) // Install parity if not present
45-
.catch(handleError); // Errors should be handled before, this is really just in case
46-
4754
if (cli.uiDev === true) {
4855
// Opens http://127.0.0.1:3000 in --ui-dev mode
4956
mainWindow.loadURL('http://127.0.0.1:3000');
@@ -59,6 +66,10 @@ function createWindow () {
5966
);
6067
}
6168

69+
doesParityExist()
70+
.catch(() => fetchParity(mainWindow)) // Install parity if not present
71+
.catch(handleError); // Errors should be handled before, this is really just in case
72+
6273
// Listen to messages from renderer process
6374
ipcMain.on('asynchronous-message', messages);
6475

@@ -74,6 +85,90 @@ function createWindow () {
7485
callback({ requestHeaders: details.requestHeaders });
7586
});
7687

88+
// Verify WebView Options Before Creation
89+
// https://electronjs.org/docs/tutorial/security#12-verify-webview-options-before-creation
90+
mainWindow.webContents.on('will-attach-webview', (event, webPreferences, params) => {
91+
// Strip away inline preload scripts, ours is at preloadURL
92+
delete webPreferences.preload;
93+
94+
// TODO Verify that the location of webPreferences.preloadURL is:
95+
// `file://path/to/app.asar/.build/preload.js`
96+
97+
// Disable Node.js integration
98+
webPreferences.nodeIntegration = false;
99+
webPreferences.contextIsolation = true;
100+
});
101+
102+
// Listen to the creation of (dapp) webviews to attach event listeners to them
103+
mainWindow.webContents.on('did-attach-webview', (event, webContents) => {
104+
// Do not accept all kinds of web permissions (camera, location...)
105+
// https://electronjs.org/docs/tutorial/security#4-handle-session-permission-requests-from-remote-content
106+
webContents.session
107+
.setPermissionRequestHandler((webContents, permission, callback) => {
108+
// Deny all permissions for dapps
109+
return callback(false);
110+
});
111+
112+
let baseUrl;
113+
let appId;
114+
115+
// Derive the dapp baseUrl (.../my-dapp/) from the first URL of the webview
116+
// (.../my-dapp/index.html). The baseUrl defines what files the webview is
117+
// allowed to navigate to within the same frame.
118+
// For example, my-dapp/index.html can navigate to my-dapp/some/dir/hi.html
119+
// and then back to my-dapp/index.html
120+
webContents.once('did-navigate', (e, initialUrl) => {
121+
const initialURL = new URL(initialUrl);
122+
123+
appId = initialURL.searchParams.get('appId');
124+
125+
initialURL.hash = '';
126+
initialURL.search = '';
127+
baseUrl = initialURL.href.substr(0, initialURL.href.lastIndexOf('/') + 1);
128+
});
129+
130+
// The event handler for will-navigate needs to be set in the main process
131+
// in order to be able to prevent the navigation: https://git.io/f4SNW
132+
webContents.on('will-navigate', (e, targetUrl) => {
133+
e.preventDefault();
134+
135+
if (targetUrl.startsWith(baseUrl)) {
136+
// The target resource is located inside the dapp folder: allow in-frame
137+
// navigation but enforce appId query parameter for inject.js
138+
139+
const newURL = new URL(targetUrl);
140+
141+
newURL.searchParams.set('appId', appId);
142+
143+
webContents.loadURL(newURL.href);
144+
} else {
145+
// Open all links to resources outside the dapp root in the browser
146+
// (or with the default desktop app for protocols other than http)
147+
148+
electron.shell.openExternal(targetUrl);
149+
}
150+
});
151+
152+
// Block in-page requests to resources outside the dapp folder
153+
webContents.session.webRequest.onBeforeRequest({ urls: ['file://*'] }, (details, callback) => {
154+
if (baseUrl &&
155+
!details.url.startsWith(baseUrl) &&
156+
// dapp-dapp-visible needs to be able to display the icons of other
157+
// dapps, so as a temporary fix we allow access to all images requests
158+
details.resourceType !== 'image') {
159+
const sanitizedUrl = details.url.replace(/'/, '');
160+
161+
if (!webContents.isDestroyed()) {
162+
webContents.executeJavaScript(`console.warn('Parity UI blocked a request to access ${sanitizedUrl}')`);
163+
}
164+
165+
callback({ cancel: true });
166+
} else {
167+
callback({ cancel: false });
168+
}
169+
});
170+
});
171+
77172
mainWindow.on('closed', () => {
78173
mainWindow = null;
79174
});
@@ -98,3 +193,10 @@ app.on('activate', () => {
98193
createWindow();
99194
}
100195
});
196+
197+
// userData value is derived from the Electron app name by default. However,
198+
// Electron doesn't know the app name defined in package.json because we
199+
// execute Electron directly on a file. Running Electron on a folder (either
200+
// .build/ or electron/) doesn't solve the issue because the package.json
201+
// is located in the parent directory.
202+
app.setPath('userData', path.join(app.getPath('appData'), appName));

electron/operations/runParity.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ module.exports = {
5454
.then(() => fsChmod(parityPath(), '755')) // Should already be 755 after download, just to be sure
5555
.then(() => {
5656
const logStream = fs.createWriteStream(logFile, { flags: 'a' });
57-
let logLastLine; // Always contains last line of the logFile
57+
let logLastLine = ''; // Always contains last line of the logFile
5858

5959
// Run an instance of parity with the correct args
6060
parity = spawn(parityPath(), parityArgv);

electron/operations/signerNewToken.js

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,28 @@ const { spawn } = require('child_process');
1919
const parityPath = require('../utils/parityPath');
2020

2121
module.exports = event => {
22-
// Generate a new token
23-
const paritySigner = spawn(parityPath(), ['signer', 'new-token']);
24-
25-
// Listen to the output of the previous command
26-
paritySigner.stdout.on('data', data => {
27-
// If the output line is xxxx-xxxx-xxxx-xxxx, then it's our token
28-
const match = data
29-
.toString()
30-
.match(
31-
/[a-zA-Z0-9]{4}(-)?[a-zA-Z0-9]{4}(-)?[a-zA-Z0-9]{4}(-)?[a-zA-Z0-9]{4}/
32-
);
33-
34-
if (match) {
35-
const token = match[0];
36-
37-
// Send back the token to the renderer process
38-
event.sender.send('asynchronous-reply', token);
39-
paritySigner.kill(); // We don't need the signer anymore
40-
}
41-
});
22+
try {
23+
// Generate a new token
24+
const paritySigner = spawn(parityPath(), ['signer', 'new-token']);
25+
26+
// Listen to the output of the previous command
27+
paritySigner.stdout.on('data', data => {
28+
// If the output line is xxxx-xxxx-xxxx-xxxx, then it's our token
29+
const match = data
30+
.toString()
31+
.match(
32+
/[a-zA-Z0-9]{4}(-)?[a-zA-Z0-9]{4}(-)?[a-zA-Z0-9]{4}(-)?[a-zA-Z0-9]{4}/
33+
);
34+
35+
if (match) {
36+
const token = match[0];
37+
38+
// Send back the token to the renderer process
39+
event.sender.send('asynchronous-reply', token);
40+
paritySigner.kill(); // We don't need the signer anymore
41+
}
42+
});
43+
} catch (err) {
44+
console.log("Can't run `parity signer new-token` command.");
45+
}
4246
};

electron/utils/parityPath.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616

1717
const { app } = require('electron');
1818

19-
const parityPath = `${app.getPath('userData')}/parity${process.platform === 'win32' ? '.exe' : ''}`;
20-
2119
// TODO parityPath is now in the Application Data folder by default, it would
2220
// be nice to first look if /usr/bin/parity exists (and return that as
2321
// parityPath). For now we keep Application Data as parityPath.
2422
// See https://github.com/parity-js/shell/issues/66
25-
module.exports = () => parityPath;
23+
24+
// We cannot use app.getPath('userData') outside of the exports because
25+
// it would then be executed before app.setPath('userData') in index.js
26+
module.exports = () => `${app.getPath('userData')}/parity${process.platform === 'win32' ? '.exe' : ''}`;

src/lib.rs renamed to electron/utils/paths.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@
1414
// You should have received a copy of the GNU General Public License
1515
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
1616

17-
#[cfg(feature = "with-syntex")]
18-
include!(concat!(env!("OUT_DIR"), "/lib.rs"));
17+
const path = require('path');
18+
const electron = require('electron');
1919

20-
#[cfg(not(feature = "with-syntex"))]
21-
include!("lib.rs.in");
20+
module.exports = {
21+
getLocalDappsPath: () => {
22+
const userData = electron.app.getPath('userData');
2223

24+
return path.join(userData, 'dapps');
25+
}
26+
};

0 commit comments

Comments
 (0)