UNPKG

webssh2-server

Version:

A Websocket to SSH2 gateway using xterm.js, socket.io, ssh2

240 lines (239 loc) 6.85 kB
// app/utils/config-builder.ts // Configuration builder utility for creating and validating configs import { ok, err } from '../utils/result.js'; import { validateConfigPure } from './config-validator.js'; import { DEFAULT_SSO_HEADERS } from '../constants/security.js'; import { validateSshHost, validateSshPort, validateCssColor } from '../validation/config.js'; /** * Transform config to enhanced config with full validation */ export function enhanceConfig(config) { // Use the existing validation pipeline const validationResult = validateConfigPure(config); if (validationResult.ok) { // Validation passed, continue with additional checks } else { // Convert validation error to our error format return err([{ path: '', message: validationResult.error.message, value: config }]); } // Additional branded type validations const errors = []; if (config.ssh.host != null) { try { validateSshHost(config.ssh.host); } catch (e) { errors.push({ path: 'ssh.host', message: e.message, value: config.ssh.host, }); } } try { validateSshPort(config.ssh.port); } catch (e) { errors.push({ path: 'ssh.port', message: e.message, value: config.ssh.port, }); } if (config.header.background !== '') { try { validateCssColor(config.header.background); } catch (e) { errors.push({ path: 'header.background', message: e.message, value: config.header.background, }); } } if (errors.length > 0) { return err(errors); } return ok(config); } /** * Configuration builder for creating validated configs */ export class ConfigBuilder { config = {}; withSshHost(host) { this.config.ssh = { ...this.config.ssh, host, }; return this; } withSshPort(port) { this.config.ssh = { ...this.config.ssh, port, }; return this; } withSshLocalAddress(localAddress) { this.config.ssh = { ...this.config.ssh, localAddress, }; return this; } withSshLocalPort(localPort) { this.config.ssh = { ...this.config.ssh, localPort, }; return this; } withSshAlgorithms(algorithms) { const currentAlgorithms = this.config.ssh?.algorithms; this.config.ssh = { ...this.config.ssh, algorithms: { cipher: algorithms.cipher ?? currentAlgorithms?.cipher ?? [], compress: algorithms.compress ?? currentAlgorithms?.compress ?? [], hmac: algorithms.hmac ?? currentAlgorithms?.hmac ?? [], kex: algorithms.kex ?? currentAlgorithms?.kex ?? [], serverHostKey: algorithms.serverHostKey ?? currentAlgorithms?.serverHostKey ?? [], }, }; return this; } withSshAllowedSubnets(subnets) { this.config.ssh = { ...this.config.ssh, allowedSubnets: subnets, }; return this; } withHeader(text, background) { this.config.header = { text, background }; return this; } withOptions(options) { const defaultOptions = { challengeButton: false, autoLog: false, allowReauth: false, allowReconnect: false, allowReplay: false, replayCRLF: false, }; this.config.options = { ...defaultOptions, ...this.config.options, ...options, }; return this; } withSessionSecret(secret) { this.config.session = { name: this.config.session?.name ?? 'webssh2', ...this.config.session, secret, }; return this; } withSessionName(name) { this.config.session = { secret: this.config.session?.secret ?? '', ...this.config.session, name, }; return this; } withSsoConfig(sso) { this.config.sso = { ...this.config.sso, ...sso, }; return this; } withHttpOrigins(origins) { this.config.http = { origins }; return this; } withListenConfig(ip, port) { this.config.listen = { ip, port }; return this; } withUserCredentials(user) { this.config.user = { ...this.config.user, ...user, }; return this; } validate() { // Set defaults for required fields const fullConfig = { listen: this.config.listen ?? { ip: '0.0.0.0', port: 2222 }, http: this.config.http ?? { origins: [] }, user: this.config.user ?? { name: null, password: null, privateKey: null, passphrase: null, }, ssh: { host: null, port: 22, term: 'xterm-256color', readyTimeout: 20000, keepaliveInterval: 60000, keepaliveCountMax: 10, allowedSubnets: [], alwaysSendKeyboardInteractivePrompts: false, disableInteractiveAuth: false, algorithms: { cipher: [], compress: [], hmac: [], kex: [], serverHostKey: [], }, ...this.config.ssh, }, header: this.config.header ?? { text: null, background: 'green', }, options: this.config.options ?? { challengeButton: false, autoLog: false, allowReauth: false, allowReconnect: false, allowReplay: false, replayCRLF: false, }, session: this.config.session ?? { secret: '', name: 'webssh2', }, sso: this.config.sso ?? { enabled: false, csrfProtection: false, trustedProxies: [], headerMapping: DEFAULT_SSO_HEADERS, }, }; return enhanceConfig(fullConfig); } build() { const result = this.validate(); if (result.ok) { return result.value; } return null; } }