Filter file scheme; disable http, https and ftp entirely
This commit is contained in:
parent
96bbc9d738
commit
e2d044e02b
4 changed files with 169 additions and 3 deletions
59
app/protocol_filter.js
Normal file
59
app/protocol_filter.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
const path = require('path');
|
||||
|
||||
const FILE_SCHEME = /^file:\/\//;
|
||||
const WINDOWS_PREFIX = /^\/[A-Z]:/;
|
||||
function _urlToPath(targetUrl) {
|
||||
let withoutScheme = targetUrl.replace(FILE_SCHEME, '');
|
||||
if (WINDOWS_PREFIX.test(withoutScheme)) {
|
||||
withoutScheme = withoutScheme.slice(1);
|
||||
}
|
||||
|
||||
const withoutQuerystring = withoutScheme.replace(/\?.*$/, '');
|
||||
const withoutHash = withoutQuerystring.replace(/#.*$/, '');
|
||||
|
||||
return decodeURIComponent(withoutHash);
|
||||
}
|
||||
|
||||
function _createFileHandler({ userDataPath, installPath }) {
|
||||
return (request, callback) => {
|
||||
// normalize() is primarily useful here for switching / to \ on windows
|
||||
const target = path.normalize(_urlToPath(request.url));
|
||||
|
||||
if (!path.isAbsolute(target)) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
if (!target.startsWith(userDataPath) && !target.startsWith(installPath)) {
|
||||
console.log(`Warning: denying request to ${target}`);
|
||||
return callback();
|
||||
}
|
||||
|
||||
return callback({
|
||||
path: target,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function installFileHandler({ protocol, userDataPath, installPath }) {
|
||||
protocol.interceptFileProtocol(
|
||||
'file',
|
||||
_createFileHandler({ userDataPath, installPath })
|
||||
);
|
||||
}
|
||||
|
||||
// Turn off all browser web requests since we do all web requests via Node.js
|
||||
function _webHandler(request, callback) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
function installWebHandler({ protocol }) {
|
||||
protocol.interceptFileProtocol('http', _webHandler);
|
||||
protocol.interceptFileProtocol('https', _webHandler);
|
||||
protocol.interceptFileProtocol('ftp', _webHandler);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
_urlToPath,
|
||||
installFileHandler,
|
||||
installWebHandler,
|
||||
};
|
|
@ -742,7 +742,6 @@ async function exportConversation(db, conversation, options) {
|
|||
const jsonString = JSON.stringify(stringify(message));
|
||||
stream.write(jsonString);
|
||||
|
||||
console.log({ backupMessage: message });
|
||||
if (attachments && attachments.length > 0) {
|
||||
const exportAttachments = () =>
|
||||
writeAttachments(attachments, {
|
||||
|
|
29
main.js
29
main.js
|
@ -5,7 +5,14 @@ const os = require('os');
|
|||
const _ = require('lodash');
|
||||
const electron = require('electron');
|
||||
|
||||
const { BrowserWindow, app, Menu, shell, ipcMain: ipc } = electron;
|
||||
const {
|
||||
BrowserWindow,
|
||||
app,
|
||||
Menu,
|
||||
shell,
|
||||
ipcMain: ipc,
|
||||
protocol: electronProtocol,
|
||||
} = electron;
|
||||
|
||||
const packageJson = require('./package.json');
|
||||
|
||||
|
@ -16,6 +23,10 @@ const GlobalErrors = require('./js/modules/global_errors');
|
|||
const logging = require('./app/logging');
|
||||
const windowState = require('./app/window_state');
|
||||
const { createTemplate } = require('./app/menu');
|
||||
const {
|
||||
installFileHandler,
|
||||
installWebHandler,
|
||||
} = require('./app/protocol_filter');
|
||||
|
||||
GlobalErrors.addHandler();
|
||||
|
||||
|
@ -429,6 +440,21 @@ function showAbout() {
|
|||
// Some APIs can only be used after this event occurs.
|
||||
let ready = false;
|
||||
app.on('ready', () => {
|
||||
const userDataPath = app.getPath('userData');
|
||||
const installPath = app.getAppPath();
|
||||
|
||||
if (process.env.NODE_ENV !== 'test' && process.env.NODE_ENV !== 'test-lib') {
|
||||
installFileHandler({
|
||||
protocol: electronProtocol,
|
||||
userDataPath,
|
||||
installPath,
|
||||
});
|
||||
}
|
||||
|
||||
installWebHandler({
|
||||
protocol: electronProtocol,
|
||||
});
|
||||
|
||||
// NOTE: Temporarily allow `then` until we convert the entire file to `async` / `await`:
|
||||
/* eslint-disable more/no-then */
|
||||
let loggingSetupError;
|
||||
|
@ -453,7 +479,6 @@ app.on('ready', () => {
|
|||
}
|
||||
|
||||
console.log('Ensure attachments directory exists');
|
||||
const userDataPath = app.getPath('userData');
|
||||
await Attachments.ensureDirectory(userDataPath);
|
||||
|
||||
ready = true;
|
||||
|
|
83
test/app/protocol_filter_test.js
Normal file
83
test/app/protocol_filter_test.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
const { expect } = require('chai');
|
||||
|
||||
const { _urlToPath } = require('../../app/protocol_filter');
|
||||
|
||||
describe('Protocol Filter', () => {
|
||||
describe('_urlToPath', () => {
|
||||
it('returns proper file path for unix style file URI with hash', () => {
|
||||
const path =
|
||||
'file:///Users/someone/Development/signal/electron/background.html#first-page';
|
||||
const expected =
|
||||
'/Users/someone/Development/signal/electron/background.html';
|
||||
|
||||
const actual = _urlToPath(path);
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
|
||||
it('returns proper file path for unix style file URI with querystring', () => {
|
||||
const path =
|
||||
'file:///Users/someone/Development/signal/electron/background.html?name=Signal&locale=en&version=2.4.0';
|
||||
const expected =
|
||||
'/Users/someone/Development/signal/electron/background.html';
|
||||
|
||||
const actual = _urlToPath(path);
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
|
||||
it('returns proper file path for unix style file URI with hash and querystring', () => {
|
||||
const path =
|
||||
'file:///Users/someone/Development/signal/electron/background.html#somewhere?name=Signal';
|
||||
const expected =
|
||||
'/Users/someone/Development/signal/electron/background.html';
|
||||
|
||||
const actual = _urlToPath(path);
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
|
||||
it('returns proper file path for windows style file URI', () => {
|
||||
const path =
|
||||
'file:///C:/Users/Someone/dev/desktop/background.html?name=Signal&locale=en&version=2.4.0';
|
||||
const expected = 'C:/Users/Someone/dev/desktop/background.html';
|
||||
|
||||
const actual = _urlToPath(path, { isWindows: true });
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
|
||||
it('translates from URL format to filesystem format', () => {
|
||||
const path =
|
||||
'file:///Users/someone/Development%20Files/signal/electron/background.html';
|
||||
const expected =
|
||||
'/Users/someone/Development Files/signal/electron/background.html';
|
||||
|
||||
const actual = _urlToPath(path);
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
|
||||
it('translates from URL format to filesystem format', () => {
|
||||
const path =
|
||||
'file:///Users/someone/Development%20Files/signal/electron/background.html';
|
||||
const expected =
|
||||
'/Users/someone/Development Files/signal/electron/background.html';
|
||||
|
||||
const actual = _urlToPath(path);
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
|
||||
// this seems to be the only way to get a relative path through Electron
|
||||
it('handles SMB share path', () => {
|
||||
const path = 'file://relative/path';
|
||||
const expected = 'relative/path';
|
||||
|
||||
const actual = _urlToPath(path);
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
|
||||
it('hands back a path with .. in it', () => {
|
||||
const path = 'file://../../..';
|
||||
const expected = '../../..';
|
||||
|
||||
const actual = _urlToPath(path);
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue