refactor: Add SessionManager and Session classes to electron

This commit is contained in:
Susmitha Girumala committed 2021-05-11 16:42:30 -04:00
1 parent 053e16dca8
commit dfbb54a1ee
5 files changed
+157 -49

No files matched your search

+1 -35
View File
@@ -1,46 +1,12 @@
const path = require('path');
const { spawnAsyncJSONPromise, spawnSync } = require('./spawn-promise');
const origin = require('./origin.js');
const { spawnSync } = require('./spawn-promise');
const cliPath = async () => path.resolve(__dirname, '..', 'cli', 'boundary');
/**
* Super paranoid shell quote/escape and validation. Input must be base62.
* @param {string} str
*/
const escapeAndValidateBase62 = (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.
`);
};
module.exports = {
// Check boundary cli existence
exists: () => Boolean(cliPath()),
// Initiate connection and return output
connect: (target_id, token, host_id) => {
const addr = origin.origin;
const sanitized = {
target_id: escapeAndValidateBase62(target_id),
token: escapeAndValidateBase62(token),
};
if (host_id) sanitized.host_id = escapeAndValidateBase62(host_id);
const command = [
'connect',
`-target-id=${sanitized.target_id}`,
`-token=${sanitized.token}`,
`-addr=${addr}`,
'-format=json',
];
if (host_id) command.push(`-host-id=${sanitized.host_id}`);
return spawnAsyncJSONPromise(command);
},
// Returns JSON-formatted version information from the CLI
version: () => {
const command = ['-v'];
+6 -5
View File
@@ -3,7 +3,7 @@ const isDev = require('electron-is-dev');
const handle = require('./ipc-handler');
const boundaryCli = require('./boundary-cli');
const origin = require('./origin');
const spawnSession = require('./spawn-session');
const sessionManager = require('./session/manager');
/**
* Returns the current runtime origin, which is used by the main thread to
@@ -57,12 +57,13 @@ handle('cliExists', () => boundaryCli.exists());
* Establishes a boundary session and returns session details.
*/
handle('connect', ({ target_id, token, host_id }) =>
boundaryCli.connect(target_id, token, host_id)
sessionManager.start(origin.origin, target_id, token, host_id)
);
/**
* Cancel an established boundary session spawned process.
*/
handle('cancel', ({ session_id }) => {
spawnSession.cancelSession(session_id);
});
handle('cancel', ({ session_id }) =>
// spawnSession.cancelSession(session_id);
sessionManager.stop(session_id)
);
@@ -0,0 +1,99 @@
const { spawnAsyncJSONPromise } = require('../spawn-promise');
// FIXME create structure 'util' folder for spawn-promise
/**
* Super paranoid shell quote/escape and validation. Input must be base62.
* @param {string} str
*/
const escapeAndValidateBase62 = (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.
`);
};
class Session {
#id;
#pid;
#addr;
#token;
#hostId;
#targetId;
#proxyDetails;
/**
* Initialize a session to a controller address
* using target details.
* @param {string} addr
* @param {string} targetId
* @param {string} token
* @param {string} hostId
*/
constructor(addr, targetId, token, hostId) {
this.#addr = addr;
this.#targetId = targetId;
this.#token = token;
this.#hostId = hostId;
}
/**
* @return {boolean}
*/
get isActive() {
return Boolean(this.#pid);
}
/**
* Returns session proxy details.
* Only available after successful start of a session.
* @return {object}
*/
get proxyDetails() {
return this.#proxyDetails;
}
// Spawn process
// Track spawned process this.pid = pid;
/**
* Using cli, initialize a session to a target.
* Tracks local proxy details if successful.
*/
start() {
const command = this.cliCommand();
return spawnAsyncJSONPromise(command).then((spawnedSession) => {
this.#id = this.#proxyDetails.session_id;
this.#pid = spawnedSession.childProcess.pid;
this.#proxyDetails = spawnedSession.response;
});
}
/**
* Generate cli command for session.
* @returns {[]}
*/
cliCommand() {
const sanitized = {
target_id: escapeAndValidateBase62(this.#targetId),
token: escapeAndValidateBase62(this.#token),
};
const command = [
'connect',
`-target-id=${sanitized.target_id}`,
`-token=${sanitized.token}`,
`-addr=${this.#addr}`,
'-format=json',
];
if (this.#hostId) {
sanitized.host_id = escapeAndValidateBase62(this.#hostId);
command.push(`-host-id=${sanitized.host_id}`);
}
return command;
}
}
module.exports = Session;
@@ -0,0 +1,39 @@
const Session = require('./index.js');
class SessionManager {
#sessions;
constructor() {
this.#sessions = [];
}
/**
* Start a session and track it.
* Returns session proxy details if successfully started.
* Only successfully started sessions will be tracked.
* @param {string} addr
* @param {string} target_id
* @param {string} token
* @param {string} host_id
*/
start(addr, target_id, token, host_id) {
const session = new Session(addr, target_id, token, host_id);
return session.start().then(() => {
this.#sessions.push(session);
return session.proxyDetails;
});
}
stopById() {
}
stopAll() {
}
get sessions() {
return this.#sessions;
}
}
const sessionManager = new SessionManager();
module.exports = sessionManager;
+12 -9
View File
@@ -47,25 +47,28 @@ module.exports = {
outputStream += data.toString();
const jsonData = jsonify(outputStream);
if (jsonData) {
if (jsonData.termination_reason) {
spawnSession.cancelProcess(childProcess.pid);
} else {
// Track only successfully launched child processes
spawnSession.add({ childProcess, data: jsonData });
}
outputStream = '';
resolve(jsonData);
// if (jsonData.termination_reason) {
// spawnSession.cancelProcess(childProcess.pid);
// } else {
// // Track only successfully launched child processes
// spawnSession.add({ childProcess, data: jsonData });
// }
// FIXME
// outputStream = '';
resolve({ childProcess, response: jsonData });
}
});
// @todo Cancel spawned session childprocess on error? Does it get automatically cancelled?
// @todo on error - should childprocess be closed?
// Test on connection limit errors especially
childProcess.stderr.on('data', (data) => {
errorStream += data.toString();
const jsonData = jsonify(errorStream);
if (jsonData) {
const error = jsonData.api_error || jsonData.error;
errorStream = '';
// FIXME
// errorStream = '';
reject(new Error(error.message));
}
});