// server // app/routes.js import express from 'express' import { getValidatedHost, getValidatedPort, maskSensitiveData, validateSshTerm, parseEnvVars, } from './utils.js' import handleConnection from './connectionHandler.js' import { createNamespacedDebug } from './logger.js' import { createAuthMiddleware } from './middleware.js' import { ConfigError, handleError } from './errors.js' import { HTTP } from './constants.js' const debug = createNamespacedDebug('routes') export function createRoutes(config) { const router = express.Router() const auth = createAuthMiddleware(config) // Scenario 1: No auth required, uses websocket authentication instead router.get('/', (req, res) => { debug('router.get./: Accessed / route') handleConnection(req, res) }) /** * Handles the "/host/" route, which requires authentication and uses the * `auth` middleware function to handle HTTP Basic Authentication. * * This route validates the host and port parameters, sets the `sshCredentials` * object in the session, and calls the `handleConnection` function to handle * the connection. * * If the `config.ssh.host` is not set, it throws a `ConfigError` with the * appropriate error message. * * @param {Object} req - The Express request object * @param {Object} res - The Express response object */ router.get('/host/', auth, (req, res) => { debug(`router.get.host: /ssh/host/ route`) const envVars = parseEnvVars(req.query.env) if (envVars) { req.session.envVars = envVars debug('routes: Parsed environment variables: %O', envVars) } try { if (!config.ssh.host) { throw new ConfigError('Host parameter required when default host not configured') } const { host } = config.ssh const port = getValidatedPort(req.query.port) const sshterm = validateSshTerm(req.query.sshterm) req.session.sshCredentials = req.session.sshCredentials || {} req.session.sshCredentials.host = host req.session.sshCredentials.port = port if (req.query.sshterm) { req.session.sshCredentials.term = sshterm } req.session.usedBasicAuth = true const sanitizedCredentials = maskSensitiveData( JSON.parse(JSON.stringify(req.session.sshCredentials)) ) debug('/ssh/host/ Credentials: ', sanitizedCredentials) handleConnection(req, res, { host: host }) } catch (err) { const error = new ConfigError(`Invalid configuration: ${err.message}`) handleError(error, res) } }) // Scenario 2: Auth required, uses HTTP Basic Auth router.get('/host/:host?', auth, (req, res) => { debug(`router.get.host: /ssh/host/${req.params.host} route`) const envVars = parseEnvVars(req.query.env) if (envVars) { req.session.envVars = envVars debug('routes: Parsed environment variables: %O', envVars) } try { const host = getValidatedHost(req.params.host) const port = getValidatedPort(req.query.port) // Validate and sanitize sshterm parameter if it exists const sshterm = validateSshTerm(req.query.sshterm) req.session.sshCredentials = req.session.sshCredentials || {} req.session.sshCredentials.host = host req.session.sshCredentials.port = port if (req.query.sshterm) { req.session.sshCredentials.term = sshterm } req.session.usedBasicAuth = true // Sanitize and log the sshCredentials object const sanitizedCredentials = maskSensitiveData( JSON.parse(JSON.stringify(req.session.sshCredentials)) ) debug('/ssh/host/ Credentials: ', sanitizedCredentials) handleConnection(req, res, { host: host }) } catch (err) { const error = new ConfigError(`Invalid configuration: ${err.message}`) handleError(error, res) } }) // Clear credentials route router.get('/clear-credentials', (req, res) => { req.session.sshCredentials = null res.status(HTTP.OK).send(HTTP.CREDENTIALS_CLEARED) }) router.get('/force-reconnect', (req, res) => { req.session.sshCredentials = null res.status(HTTP.UNAUTHORIZED).send(HTTP.AUTH_REQUIRED) }) return router }