26 changed files with 272 additions and 103 deletions
			
			
		| @ -0,0 +1,27 @@ | |||||
|  | { | ||||
|  |   ssh: { | ||||
|  |     // user:  'username', // default user to use when ssh-ing | ||||
|  |     host: 'localhost', // Server to ssh to | ||||
|  |     auth: 'password', // shh authentication, method. Defaults to "password", you can use "publickey,password" instead' | ||||
|  |     // pass: "password", // Password to use when sshing | ||||
|  |     // key: "", // path to an optional client private key, connection will be password-less and insecure! | ||||
|  |     port: 22, // Port to ssh to | ||||
|  |     knownHosts: '/dev/null', // ssh knownHosts file to use | ||||
|  |   }, | ||||
|  |   server:  { | ||||
|  |     base: '/wetty/', // URL base to serve resources from | ||||
|  |     port: 3000, // Port to listen on | ||||
|  |     host: '0.0.0.0', // address to listen on | ||||
|  |     title: 'WeTTy - The Web Terminal Emulator', // Page title | ||||
|  |     bypassHelmet: false, // Disable Helmet security checks | ||||
|  |   }, | ||||
|  | 
 | ||||
|  |   forceSSH: false, // Force sshing to local machine over login if running as root | ||||
|  |   command: 'login', // Command to run on server. Login will use ssh if connecting to different server | ||||
|  |   /* | ||||
|  |   ssl:{ | ||||
|  |     key: 'ssl.key', | ||||
|  |     cert: 'ssl.cert', | ||||
|  |   } | ||||
|  |   */ | ||||
|  | } | ||||
| @ -0,0 +1,126 @@ | |||||
|  | import fs from 'fs-extra'; | ||||
|  | import path from 'path'; | ||||
|  | import JSON5 from 'json5'; | ||||
|  | import isUndefined from 'lodash/isUndefined.js'; | ||||
|  | 
 | ||||
|  | import type { Config, SSH, Server } from './interfaces'; | ||||
|  | import { | ||||
|  |   sshDefault, | ||||
|  |   serverDefault, | ||||
|  |   forceSSHDefault, | ||||
|  |   defaultCommand, | ||||
|  | } from './defaults.js'; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Cast given value to boolean | ||||
|  |  * | ||||
|  |  * @param value - variable to cast | ||||
|  |  * @returns variable cast to boolean | ||||
|  |  */ | ||||
|  | function ensureBoolean(value: any): boolean { | ||||
|  |   switch (value) { | ||||
|  |     case true: | ||||
|  |     case 'true': | ||||
|  |     case 1: | ||||
|  |     case '1': | ||||
|  |     case 'on': | ||||
|  |     case 'yes': | ||||
|  |       return true; | ||||
|  |     default: | ||||
|  |       return false; | ||||
|  |   } | ||||
|  | } | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Load JSON5 config from file and merge with default args | ||||
|  |  * If no path is provided the default config is returned | ||||
|  |  * | ||||
|  |  * @param filepath - path to config to load | ||||
|  |  * @returns variable cast to boolean | ||||
|  |  */ | ||||
|  | export async function loadConfigFile(filepath?: string): Promise<Config> { | ||||
|  |   if (isUndefined(filepath)) { | ||||
|  |     return { | ||||
|  |       ssh: sshDefault, | ||||
|  |       server: serverDefault, | ||||
|  |       command: defaultCommand, | ||||
|  |       forceSSH: forceSSHDefault, | ||||
|  |     }; | ||||
|  |   } | ||||
|  |   const content = await fs.readFile(path.resolve(filepath)); | ||||
|  |   const parsed = JSON5.parse(content.toString()) as Config; | ||||
|  |   return { | ||||
|  |     ssh: isUndefined(parsed.ssh) | ||||
|  |       ? sshDefault | ||||
|  |       : Object.assign(sshDefault, parsed.ssh), | ||||
|  |     server: isUndefined(parsed.server) | ||||
|  |       ? serverDefault | ||||
|  |       : Object.assign(serverDefault, parsed.server), | ||||
|  |     command: isUndefined(parsed.command) ? defaultCommand : `${parsed.command}`, | ||||
|  |     forceSSH: isUndefined(parsed.forceSSH) | ||||
|  |       ? forceSSHDefault | ||||
|  |       : ensureBoolean(parsed.forceSSH), | ||||
|  |     ssl: parsed.ssl, | ||||
|  |   }; | ||||
|  | } | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Merge 2 objects removing undefined fields | ||||
|  |  * | ||||
|  |  * @param target - base object | ||||
|  |  * @param source - object to get new values from | ||||
|  |  * @returns merged object | ||||
|  |  * | ||||
|  |  */ | ||||
|  | const objectAssign = ( | ||||
|  |   target: Record<string, any>, | ||||
|  |   source: Record<string, any>, | ||||
|  | ): Record<string, any> => | ||||
|  |   Object.fromEntries( | ||||
|  |     Object.entries(source).map(([key, value]) => [ | ||||
|  |       key, | ||||
|  |       isUndefined(source[key]) ? target[key] : value, | ||||
|  |     ]), | ||||
|  |   ); | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * Merge cli arguemens with config object | ||||
|  |  * | ||||
|  |  * @param opts - Object containing cli args | ||||
|  |  * @param config - Config object | ||||
|  |  * @returns merged configuration | ||||
|  |  * | ||||
|  |  */ | ||||
|  | export function mergeCliConf( | ||||
|  |   opts: Record<string, any>, | ||||
|  |   config: Config, | ||||
|  | ): Config { | ||||
|  |   const ssl = { | ||||
|  |     key: opts['ssl-key'], | ||||
|  |     cert: opts['ssl-cert'], | ||||
|  |     ...config.ssl, | ||||
|  |   }; | ||||
|  |   return { | ||||
|  |     ssh: objectAssign(config.ssh, { | ||||
|  |       user: opts['ssh-user'], | ||||
|  |       host: opts['ssh-host'], | ||||
|  |       auth: opts['ssh-auth'], | ||||
|  |       port: opts['ssh-port'], | ||||
|  |       pass: opts['ssh-pass'], | ||||
|  |       key: opts['ssh-key'], | ||||
|  |       knownHosts: opts['known-hosts'], | ||||
|  |     }) as SSH, | ||||
|  |     server: objectAssign(config.server, { | ||||
|  |       base: opts.base, | ||||
|  |       host: opts.host, | ||||
|  |       port: opts.port, | ||||
|  |       title: opts.title, | ||||
|  |       bypassHelmet: opts['bypass-helmet'], | ||||
|  |     }) as Server, | ||||
|  |     command: isUndefined(opts.command) ? config.command : opts.command, | ||||
|  |     forceSSH: isUndefined(opts['force-ssh']) | ||||
|  |       ? config.forceSSH | ||||
|  |       : opts['force-ssh'], | ||||
|  |     ssl: isUndefined(ssl.key) || isUndefined(ssl.cert) ? undefined : ssl, | ||||
|  |   }; | ||||
|  | } | ||||
					Loading…
					
					
				
		Reference in new issue