diff --git a/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js b/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js index f2bbc7d9a..e3470fa85 100644 --- a/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js +++ b/ui/desktop/app/controllers/scopes/scope/projects/targets/index.js @@ -190,6 +190,7 @@ export default class ScopesScopeProjectsTargetsIndexController extends Controlle const options = { target_id: target.id, token: this.session.data.authenticated.token, + session_max_seconds: target.session_max_seconds, }; if (host) options.host_id = host.id; diff --git a/ui/desktop/electron-app/src/helpers/spawn-promise.js b/ui/desktop/electron-app/src/helpers/spawn-promise.js index 19ef4c5a3..0fe95afeb 100644 --- a/ui/desktop/electron-app/src/helpers/spawn-promise.js +++ b/ui/desktop/electron-app/src/helpers/spawn-promise.js @@ -27,16 +27,19 @@ module.exports = { * data on either stdout or stderr. The process is allowed to continue * running after the promise resolves. This function is intended to launch * the local proxy. - * @param {string} command + * @param {string[]} command + * @param {string} token + * @param {number} timeout Duration in seconds * @return {Promise} */ - spawnAsyncJSONPromise(command, token) { + spawnAsyncJSONPromise(command, token, timeout) { return new Promise((resolve, reject) => { const childProcess = spawn(path, command, { env: { ...process.env, BOUNDARY_TOKEN: token, }, + timeout: timeout ? timeout * 1000 : undefined, }); let outputStream = ''; let errorStream = ''; diff --git a/ui/desktop/electron-app/src/ipc/handlers.js b/ui/desktop/electron-app/src/ipc/handlers.js index c8f203a23..aa44c08d2 100644 --- a/ui/desktop/electron-app/src/ipc/handlers.js +++ b/ui/desktop/electron-app/src/ipc/handlers.js @@ -71,8 +71,14 @@ handle('cliExists', () => boundaryCli.exists()); /** * Establishes a boundary session and returns session details. */ -handle('connect', ({ target_id, token, host_id }) => - sessionManager.start(runtimeSettings.clusterUrl, target_id, token, host_id), +handle('connect', ({ target_id, token, host_id, session_max_seconds }) => + sessionManager.start( + runtimeSettings.clusterUrl, + target_id, + token, + host_id, + session_max_seconds, + ), ); /** diff --git a/ui/desktop/electron-app/src/models/session-manager.js b/ui/desktop/electron-app/src/models/session-manager.js index 20399470d..10cd6d41d 100644 --- a/ui/desktop/electron-app/src/models/session-manager.js +++ b/ui/desktop/electron-app/src/models/session-manager.js @@ -23,9 +23,16 @@ class SessionManager { * @param {string} target_id * @param {string} token * @param {string} host_id + * @param {number} session_max_seconds */ - start(addr, target_id, token, host_id) { - const session = new Session(addr, target_id, token, host_id); + start(addr, target_id, token, host_id, session_max_seconds) { + const session = new Session( + addr, + target_id, + token, + host_id, + session_max_seconds, + ); this.#sessions.push(session); return session.start(); } diff --git a/ui/desktop/electron-app/src/models/session.js b/ui/desktop/electron-app/src/models/session.js index 13624d91a..d3be7fd00 100644 --- a/ui/desktop/electron-app/src/models/session.js +++ b/ui/desktop/electron-app/src/models/session.js @@ -17,6 +17,7 @@ class Session { #process; #targetId; #proxyDetails; + #sessionMaxSeconds; /** * Initialize a session to a controller address @@ -25,12 +26,14 @@ class Session { * @param {string} targetId * @param {string} token * @param {string} hostId + * @param {number} sessionMaxSeconds */ - constructor(addr, targetId, token, hostId) { + constructor(addr, targetId, token, hostId, sessionMaxSeconds) { this.#addr = addr; this.#targetId = targetId; this.#token = token; this.#hostId = hostId; + this.#sessionMaxSeconds = sessionMaxSeconds; } /** @@ -48,22 +51,48 @@ class Session { return this.#process && !this.#process.killed; } + /** + * Generate cli command for session. + * @returns {string[]} + */ + get connectCommand() { + const sanitized = { + target_id: sanitizer.base62EscapeAndValidate(this.#targetId), + addr: sanitizer.urlValidate(this.#addr), + }; + + const command = [ + 'connect', + `-target-id=${sanitized.target_id}`, + `-token=env://BOUNDARY_TOKEN`, + `-addr=${sanitized.addr}`, + '-format=json', + ]; + + if (this.#hostId) { + sanitized.host_id = sanitizer.base62EscapeAndValidate(this.#hostId); + command.push(`-host-id=${sanitized.host_id}`); + } + return command; + } + /** * Using cli, initialize a session to a target. * Tracks local proxy details if successful. */ start() { - const command = this.cliCommand(); const sanitizedToken = sanitizer.base62EscapeAndValidate(this.#token); - return spawnAsyncJSONPromise(command, sanitizedToken).then( - (spawnedSession) => { - this.#process = spawnedSession.childProcess; - this.#proxyDetails = spawnedSession.response; - this.#process = spawnedSession.childProcess; - this.#id = this.#proxyDetails.session_id; - return this.#proxyDetails; - }, - ); + return spawnAsyncJSONPromise( + this.connectCommand, + sanitizedToken, + this.#sessionMaxSeconds, + ).then((spawnedSession) => { + this.#process = spawnedSession.childProcess; + this.#proxyDetails = spawnedSession.response; + this.#process = spawnedSession.childProcess; + this.#id = this.#proxyDetails.session_id; + return this.#proxyDetails; + }); } /** @@ -96,31 +125,6 @@ class Session { } }); } - - /** - * Generate cli command for session. - * @returns {[]} - */ - cliCommand() { - const sanitized = { - target_id: sanitizer.base62EscapeAndValidate(this.#targetId), - addr: sanitizer.urlValidate(this.#addr), - }; - - const command = [ - 'connect', - `-target-id=${sanitized.target_id}`, - `-token=env://BOUNDARY_TOKEN`, - `-addr=${sanitized.addr}`, - '-format=json', - ]; - - if (this.#hostId) { - sanitized.host_id = sanitizer.base62EscapeAndValidate(this.#hostId); - command.push(`-host-id=${sanitized.host_id}`); - } - return command; - } } module.exports = Session;