Merge branch 'main' into ICU-1335-close-all-sessions-on-exit
This commit is contained in:
11 files changed
+86
-63
No files matched your search
@@ -1,7 +1,7 @@
|
||||
const path = require('path');
|
||||
const { spawnSync } = require('../helpers/spawn-promise.js');
|
||||
|
||||
const cliPath = async () => path.resolve(__dirname, '..', 'cli', 'boundary');
|
||||
const cliPath = async () => path.resolve(__dirname, '..', '..', 'cli', 'boundary');
|
||||
|
||||
module.exports = {
|
||||
// Check boundary cli existence
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const origin = require('../origin/index.js');
|
||||
const runtimeSettings = require('../services/runtime-settings.js');
|
||||
const isDev = require('electron-is-dev');
|
||||
|
||||
const csp = {
|
||||
@@ -28,9 +28,9 @@ const generateCSPHeader = () => {
|
||||
const policy = Object.assign({}, csp);
|
||||
|
||||
// If an origin is specified, add it to the connect-src directive
|
||||
if (origin.origin) {
|
||||
if (runtimeSettings.origin) {
|
||||
policy['connect-src'] = policy['connect-src'].slice();
|
||||
policy['connect-src'].push(origin.origin);
|
||||
policy['connect-src'].push(runtimeSettings.origin);
|
||||
}
|
||||
|
||||
return Object.keys(policy)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
const { net } = require('electron');
|
||||
|
||||
const requestTimeoutSeconds = 10;
|
||||
// Simple promise wrapper around Electron's net.request feature.
|
||||
// https://www.electronjs.org/docs/api/client-request
|
||||
const netRequestPromise = (url) =>
|
||||
new Promise((resolve, reject) => {
|
||||
try {
|
||||
const request = net.request(url);
|
||||
// We don't worry about canceling the request timeout timer once a
|
||||
// request ends because: request.abort() has no effect after a request
|
||||
// ends and the promise will already have been completed, so a rejection
|
||||
// has no effect either.
|
||||
const requestTimeout = setTimeout(() => {
|
||||
request.abort();
|
||||
reject(new Error('Request timeout'));
|
||||
}, requestTimeoutSeconds * 1000);
|
||||
request.on('error', reject);
|
||||
request.on('response', resolve);
|
||||
request.end();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = netRequestPromise;
|
||||
@@ -15,7 +15,7 @@ const {
|
||||
} = require('electron');
|
||||
require('./ipc/handlers.js');
|
||||
|
||||
const origin = require('./origin/index.js');
|
||||
const runtimeSettings = require('./services/runtime-settings.js');
|
||||
const { generateCSPHeader } = require('./config/content-security-policy.js');
|
||||
const sessionManager = require('./session/manager.js');
|
||||
|
||||
@@ -132,7 +132,7 @@ app.on('ready', async () => {
|
||||
|
||||
// If the user-specified origin changes, reload the page so that
|
||||
// the CSP can be refreshed with the this source allowed
|
||||
origin.onOriginChange(() => mainWindow.loadURL(emberAppURL));
|
||||
runtimeSettings.onOriginChange(() => mainWindow.loadURL(emberAppURL));
|
||||
|
||||
// If you want to open up dev tools programmatically, call
|
||||
// mainWindow.openDevTools();
|
||||
|
||||
@@ -2,28 +2,30 @@ const { shell } = require('electron');
|
||||
const isDev = require('electron-is-dev');
|
||||
const handle = require('./ipc-handler.js');
|
||||
const boundaryCli = require('../cli/index.js');
|
||||
const origin = require('../origin/index.js');
|
||||
const sessionManager = require('../session/manager.js');
|
||||
const sessionManager = require('../services/session-manager.js');
|
||||
const runtimeSettings = require('../services/runtime-settings.js');
|
||||
const sanitizer = require('../utils/sanitizer.js');
|
||||
|
||||
/**
|
||||
* Returns the current runtime origin, which is used by the main thread to
|
||||
* rewrite the CSP to allow requests.
|
||||
*/
|
||||
handle('getOrigin', () => origin.origin);
|
||||
handle('getOrigin', () => runtimeSettings.origin);
|
||||
|
||||
/**
|
||||
* Sets the origin to be used in the content security policy and triggers
|
||||
* a main window reload.
|
||||
*/
|
||||
handle('setOrigin', async (requestOrigin) => {
|
||||
await origin.validateOrigin(requestOrigin);
|
||||
origin.origin = requestOrigin;
|
||||
const origin = sanitizer.urlValidate(requestOrigin);
|
||||
await runtimeSettings.validateOrigin(origin);
|
||||
runtimeSettings.origin = origin;
|
||||
});
|
||||
|
||||
/**
|
||||
* Resets the origin.
|
||||
*/
|
||||
handle('resetOrigin', async () => origin.resetOrigin());
|
||||
handle('resetOrigin', async () => runtimeSettings.resetOrigin());
|
||||
|
||||
/**
|
||||
* Opens the specified URL in an external browser. Only secure HTTPs URLs are
|
||||
@@ -55,7 +57,7 @@ handle('cliExists', () => boundaryCli.exists());
|
||||
* Establishes a boundary session and returns session details.
|
||||
*/
|
||||
handle('connect', ({ target_id, token, host_id }) =>
|
||||
sessionManager.start(origin.origin, target_id, token, host_id)
|
||||
sessionManager.start(runtimeSettings.origin, target_id, token, host_id)
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
+2
-31
@@ -1,34 +1,7 @@
|
||||
const { net } = require('electron');
|
||||
|
||||
const requestTimeoutSeconds = 10;
|
||||
// Simple promise wrapper around Electron's net.request feature.
|
||||
// https://www.electronjs.org/docs/api/client-request
|
||||
const netRequestPromise = (url) =>
|
||||
new Promise((resolve, reject) => {
|
||||
try {
|
||||
const request = net.request(url);
|
||||
// We don't worry about canceling the request timeout timer once a
|
||||
// request ends because: request.abort() has no effect after a request
|
||||
// ends and the promise will already have been completed, so a rejection
|
||||
// has no effect either.
|
||||
const requestTimeout = setTimeout(() => {
|
||||
request.abort();
|
||||
reject(new Error('Request timeout'));
|
||||
}, requestTimeoutSeconds * 1000);
|
||||
request.on('error', reject);
|
||||
request.on('response', resolve);
|
||||
request.end();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
|
||||
// Provides a singleton class instance to enable a consistent view of
|
||||
// runtime settings across the application.
|
||||
const netRequestPromise = require('../helpers/net-request-promise.js');
|
||||
|
||||
// Runtime settings are any configuration, especially user-specified,
|
||||
// set up at runtime. For example, the Boundary origin is a runtime setting.
|
||||
|
||||
class RuntimeSettings {
|
||||
// Internal private origin is exposed via getter/setter below.
|
||||
#origin = undefined;
|
||||
@@ -84,6 +57,4 @@ class RuntimeSettings {
|
||||
}
|
||||
}
|
||||
|
||||
const runtimeSettings = new RuntimeSettings();
|
||||
|
||||
module.exports = runtimeSettings;
|
||||
module.exports = RuntimeSettings;
|
||||
@@ -1,5 +1,5 @@
|
||||
const { spawnAsyncJSONPromise } = require('../helpers/spawn-promise.js');
|
||||
const base62 = require('../utils/base62.js');
|
||||
const sanitizer = require('../utils/sanitizer.js');
|
||||
|
||||
class Session {
|
||||
#id;
|
||||
@@ -77,9 +77,9 @@ class Session {
|
||||
*/
|
||||
cliCommand() {
|
||||
const sanitized = {
|
||||
target_id: base62.escapeAndValidate(this.#targetId),
|
||||
token: base62.escapeAndValidate(this.#token),
|
||||
addr: encodeURI(this.#addr),
|
||||
target_id: sanitizer.base62EscapeAndValidate(this.#targetId),
|
||||
token: sanitizer.base62EscapeAndValidate(this.#token),
|
||||
addr: sanitizer.urlValidate(this.#addr),
|
||||
};
|
||||
|
||||
const command = [
|
||||
@@ -91,7 +91,7 @@ class Session {
|
||||
];
|
||||
|
||||
if (this.#hostId) {
|
||||
sanitized.host_id = base62.escapeAndValidate(this.#hostId);
|
||||
sanitized.host_id = sanitizer.base62EscapeAndValidate(this.#hostId);
|
||||
command.push(`-host-id=${sanitized.host_id}`);
|
||||
}
|
||||
return command;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
const RuntimeSettings = require('../models/runtime-settings.js');
|
||||
|
||||
// Provides a singleton class instance to enable a consistent view of
|
||||
// runtime settings across the application.
|
||||
|
||||
const runtimeSettings = new RuntimeSettings();
|
||||
|
||||
module.exports = runtimeSettings;
|
||||
File renamed without changes.
@@ -1,14 +0,0 @@
|
||||
module.exports = {
|
||||
/**
|
||||
* Super paranoid shell quote/escape and validation. Input must be base62.
|
||||
* @param {string} str
|
||||
*/
|
||||
escapeAndValidate: (str) => {
|
||||
const candidate = str.toString();
|
||||
if (candidate.match(/^[A-Za-z0-9_]*$/)) return candidate;
|
||||
throw new Error(`
|
||||
Could not invoke command:
|
||||
input contained unsafe characters.
|
||||
`);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
const { URL } = require('url');
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Super paranoid shell quote/escape and validation. Input must be base62.
|
||||
* @param {string} str
|
||||
*/
|
||||
base62EscapeAndValidate: (str) => {
|
||||
const candidate = str.toString();
|
||||
if (candidate.match(/^[A-Za-z0-9_]*$/)) return candidate;
|
||||
throw new Error(`
|
||||
Could not invoke command:
|
||||
input contained unsafe characters.
|
||||
`);
|
||||
},
|
||||
/**
|
||||
* Return a quoted string suitable for using in shell commands.
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
urlValidate: (str) => {
|
||||
try {
|
||||
const url = new URL(str);
|
||||
return `${url.protocol}://${url.host}`;
|
||||
} catch (e) {
|
||||
// Parse error
|
||||
throw new Error(`URL ${str} could not be validated.`);
|
||||
}
|
||||
},
|
||||
};
|
||||
Reference in new issue
Block a user