Browse Source

namespace fucntions for easier maintenance

pull/270/head
butlerx 4 years ago
parent
commit
11cb3d011a
No known key found for this signature in database GPG Key ID: B37CA765BAA89170
  1. 45
      src/client/wetty.ts
  2. 4
      src/client/wetty/disconnect.ts
  3. 5
      src/client/wetty/shared/type.ts
  4. 24
      src/client/wetty/term.ts
  5. 31
      src/client/wetty/term/confiruragtion.ts
  6. 7
      src/client/wetty/term/confiruragtion/clipboard.ts
  7. 12
      src/client/wetty/term/confiruragtion/load.ts
  8. 8
      src/main.ts
  9. 18
      src/server.ts
  10. 8
      src/server/command.ts
  11. 2
      src/server/command/ssh.ts
  12. 2
      src/server/login.ts
  13. 66
      src/server/socketServer.ts
  14. 6
      src/server/socketServer/assets.ts
  15. 2
      src/server/socketServer/html.ts
  16. 15
      src/server/socketServer/middleware.ts
  17. 36
      src/server/socketServer/socket.ts
  18. 0
      src/server/socketServer/ssl.ts
  19. 4
      src/server/spawn.ts
  20. 0
      src/shared/defaults.ts
  21. 2
      src/shared/logger.ts

45
src/client/wetty.ts

@ -1,50 +1,27 @@
import _ from 'lodash';
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import { dom, library } from '@fortawesome/fontawesome-svg-core';
import { faCogs } from '@fortawesome/free-solid-svg-icons';
import { FileDownloader } from './wetty/download.js';
import { copySelected, copyShortcut } from './wetty/clipboard.js';
import { disconnect } from './wetty/disconnect.js';
import { configureTerm } from './wetty/options.js';
import { mobileKeyboard } from './wetty/mobile.js';
import { overlay, terminal } from './shared/elements.js';
import { socket } from './wetty/socket.js';
import { verifyPrompt } from './shared/verify.js';
import { FileDownloader } from './wetty/download';
import { disconnect } from './wetty/disconnect';
import { mobileKeyboard } from './wetty/mobile';
import { overlay } from './shared/elements';
import { socket } from './wetty/socket';
import { verifyPrompt } from './shared/verify';
import { terminal } from './wetty/term';
// Setup for fontawesome
library.add(faCogs);
dom.watch();
socket.on('connect', () => {
const term = new Terminal();
if (_.isNull(terminal)) return;
const fitAddon = new FitAddon();
term.loadAddon(fitAddon);
term.open(terminal);
const resize = (): void => {
fitAddon.fit();
socket.emit('resize', { cols: term.cols, rows: term.rows });
};
configureTerm(term, resize);
const term = terminal(socket);
if (_.isUndefined(term)) return;
if (!_.isNull(overlay)) overlay.style.display = 'none';
window.addEventListener('beforeunload', verifyPrompt, false);
term.attachCustomKeyEventHandler(copyShortcut);
document.addEventListener(
'mouseup',
event => {
if (term.hasSelection()) copySelected(event, term.getSelection());
},
false,
);
window.onresize = resize;
resize();
term.resizeTerm();
term.focus();
mobileKeyboard();
const fileDownloader = new FileDownloader();
@ -64,7 +41,7 @@ socket.on('connect', () => {
})
.on('login', () => {
term.writeln('');
resize();
term.resizeTerm();
})
.on('logout', disconnect)
.on('disconnect', disconnect)

4
src/client/wetty/disconnect.ts

@ -1,6 +1,6 @@
import _ from 'lodash';
import { verifyPrompt } from '../shared/verify.js';
import { overlay } from '../shared/elements.js';
import { verifyPrompt } from '../shared/verify';
import { overlay } from '../shared/elements';
export function disconnect(reason: string): void {
if (_.isNull(overlay)) return;

5
src/client/wetty/shared/type.ts

@ -0,0 +1,5 @@
import { Terminal } from 'xterm';
export class Term extends Terminal {
resizeTerm(): void {}
}

24
src/client/wetty/term.ts

@ -0,0 +1,24 @@
import _ from 'lodash';
import type { Socket } from 'socket.io-client';
import { FitAddon } from 'xterm-addon-fit';
import { Terminal } from 'xterm';
import type { Term } from './shared/type';
import { configureTerm } from './term/confiruragtion';
import { terminal as termElement } from '../shared/elements';
export function terminal(socket: typeof Socket): Term | undefined {
const term = new Terminal() as Term;
if (_.isNull(termElement)) return;
const fitAddon = new FitAddon();
term.loadAddon(fitAddon);
term.open(termElement);
term.resizeTerm = () => {
fitAddon.fit();
socket.emit('resize', { cols: term.cols, rows: term.rows });
};
configureTerm(term);
window.onresize = term.resizeTerm;
return term;
}

31
src/client/wetty/options.ts → src/client/wetty/term/confiruragtion.ts

@ -1,20 +1,11 @@
import _ from 'lodash';
import type { Terminal } from 'xterm';
import { editor } from '../shared/elements.js';
import type { Term } from '../shared/type';
import { copySelected, copyShortcut } from './confiruragtion/clipboard';
import { editor } from '../../shared/elements';
import { loadOptions } from './confiruragtion/load';
function loadOptions(): object {
const defaultOptions = { fontSize: 14 };
try {
return _.isUndefined(localStorage.options)
? defaultOptions
: JSON.parse(localStorage.options);
} catch {
return defaultOptions;
}
}
export function configureTerm(term: Terminal, resize: Function): void {
export function configureTerm(term: Term): void {
const options = loadOptions();
Object.entries(options).forEach(([key, value]) => {
term.setOption(key, value);
@ -33,7 +24,7 @@ export function configureTerm(term: Terminal, resize: Function): void {
const value = updated[key];
term.setOption(key, value);
});
resize();
term.resizeTerm();
} catch {
// skip
editor.classList.add('error');
@ -48,4 +39,14 @@ export function configureTerm(term: Terminal, resize: Function): void {
});
}
}
term.attachCustomKeyEventHandler(copyShortcut);
document.addEventListener(
'mouseup',
() => {
if (term.hasSelection()) copySelected(term.getSelection());
},
false,
);
}

7
src/client/wetty/clipboard.ts → src/client/wetty/term/confiruragtion/clipboard.ts

@ -1,12 +1,11 @@
/**
Copy text selection to clipboard on double click or select
@param event - the event this function is bound to eg mouseup
@param text - the selected text to copy
@returns boolean to indicate success or failure
*/
export function copySelected(event: Event, text: string): boolean {
if (event.clipboardData?.setData) {
event.clipboardData.setData('Text', text);
export function copySelected(text: string): boolean {
if (window.clipboardData?.setData) {
window.clipboardData.setData('Text', text);
return true;
}
if (

12
src/client/wetty/term/confiruragtion/load.ts

@ -0,0 +1,12 @@
import _ from 'lodash';
export function loadOptions(): object {
const defaultOptions = { fontSize: 14 };
try {
return _.isUndefined(localStorage.options)
? defaultOptions
: JSON.parse(localStorage.options);
} catch {
return defaultOptions;
}
}

8
src/main.ts

@ -3,15 +3,15 @@
* @module WeTTy
*/
import yargs from 'yargs';
import isUndefined from 'lodash/isUndefined.js';
import { logger } from './shared/logger.js';
import isUndefined from 'lodash/isUndefined';
import { logger } from './shared/logger';
import {
sshDefault,
serverDefault,
forceSSHDefault,
defaultCommand,
} from './server/default.js';
import { startServer } from './server.js';
} from './shared/defaults';
import { startServer } from './server';
const opts = yargs
.option('ssl-key', {

18
src/server.ts

@ -2,19 +2,18 @@
* Create WeTTY server
* @module WeTTy
*/
import type { SSH, SSL, SSLBuffer, Server } from './shared/interfaces';
import { getCommand } from './server/command.js';
import { loadSSL } from './server/ssl.js';
import { logger } from './shared/logger.js';
import { login } from './server/login.js';
import { server } from './server/socketServer.js';
import { spawn } from './server/spawn.js';
import type { SSH, SSL, Server } from './shared/interfaces';
import { getCommand } from './server/command';
import { logger } from './shared/logger';
import { login } from './server/login';
import { server } from './server/socketServer';
import { spawn } from './server/spawn';
import {
sshDefault,
serverDefault,
forceSSHDefault,
defaultCommand,
} from './server/default.js';
} from './shared/defaults';
/**
* Starts WeTTy Server
@ -36,8 +35,7 @@ export async function startServer(
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`);
}
const sslBuffer: SSLBuffer = await loadSSL(ssl);
const io = server(serverConf, sslBuffer);
const io = await server(serverConf, ssl);
/**
* Wetty server connected too
* @fires WeTTy#connnection

8
src/server/command.ts

@ -1,9 +1,9 @@
import url from 'url';
import { Socket } from 'socket.io';
import { SSH } from '../shared/interfaces.js';
import { address } from './command/address.js';
import { loginOptions } from './command/login.js';
import { sshOptions } from './command/ssh.js';
import { SSH } from '../shared/interfaces';
import { address } from './command/address';
import { loginOptions } from './command/login';
import { sshOptions } from './command/ssh';
const localhost = (host: string): boolean =>
process.getuid() === 0 &&

2
src/server/command/ssh.ts

@ -1,5 +1,5 @@
import isUndefined from 'lodash/isUndefined.js';
import { logger } from '../../shared/logger.js';
import { logger } from '../../shared/logger';
export function sshOptions(
{

2
src/server/login.ts

@ -1,5 +1,5 @@
import pty from 'node-pty';
import { xterm } from './shared/xterm.js';
import { xterm } from './shared/xterm';
export function login(socket: SocketIO.Socket): Promise<string> {
// Check request-header for username

66
src/server/socketServer.ts

@ -1,31 +1,23 @@
import compression from 'compression';
import express from 'express';
import favicon from 'serve-favicon';
import compression from 'compression';
import helmet from 'helmet';
import http from 'http';
import https from 'https';
import isUndefined from 'lodash/isUndefined.js';
import socket from 'socket.io';
import winston from 'express-winston';
import { join, resolve } from 'path';
import type { SSLBuffer, Server } from '../shared/interfaces';
import { html } from './socketServer/html.js';
import { logger } from '../shared/logger.js';
const trim = (str: string): string => str.replace(/\/*$/, '');
const serveStatic = (path: string) =>
express.static(resolve(process.cwd(), 'build', path));
import type { SSL, SSLBuffer, Server } from '../shared/interfaces';
import { favicon, redirect } from './socketServer/middleware';
import { html } from './socketServer/html';
import { listen } from './socketServer/socket';
import { logger } from '../shared/logger';
import { serveStatic, trim } from './socketServer/assets';
import { loadSSL } from './socketServer/ssl';
export function server(
export async function server(
{ base, port, host, title, bypassHelmet }: Server,
{ key, cert }: SSLBuffer,
): SocketIO.Server {
ssl?: SSL,
): Promise<SocketIO.Server> {
const basePath = trim(base);
logger.info('Starting server', {
key,
cert,
ssl,
port,
base,
title,
@ -38,15 +30,8 @@ export function server(
.use(`${basePath}/client`, serveStatic('client'))
.use(winston.logger(logger))
.use(compression())
.use(favicon(join('build', 'assets', 'favicon.ico')));
/* .use((req, res, next) => {
if (req.path.substr(-1) === '/' && req.path.length > 1)
res.redirect(
301,
req.path.slice(0, -1) + req.url.slice(req.path.length),
);
else next();
}); */
.use(favicon)
.use(redirect);
// Allow helmet to be bypassed.
// Unfortunately, order matters with middleware
@ -58,24 +43,7 @@ export function server(
const client = html(basePath, title);
app.get(basePath, client).get(`${basePath}/ssh/:user`, client);
return socket(
!isUndefined(key) && !isUndefined(cert)
? https.createServer({ key, cert }, app).listen(port, host, () => {
logger.info('Server started', {
port,
connection: 'https',
});
})
: http.createServer(app).listen(port, host, () => {
logger.info('Server started', {
port,
connection: 'http',
});
}),
{
path: `${basePath}/socket.io`,
pingInterval: 3000,
pingTimeout: 7000,
},
);
const sslBuffer: SSLBuffer = await loadSSL(ssl);
return listen(app, host, port, basePath, sslBuffer);
}

6
src/server/socketServer/assets.ts

@ -0,0 +1,6 @@
import { resolve } from 'path';
import express from 'express';
export const trim = (str: string): string => str.replace(/\/*$/, '');
export const serveStatic = (path: string) =>
express.static(resolve(process.cwd(), 'build', path));

2
src/server/socketServer/html.ts

@ -1,5 +1,5 @@
import type express from 'express';
import { isDev } from '../../shared/env.js';
import { isDev } from '../../shared/env';
const jsFiles = isDev ? ['dev', 'wetty'] : ['wetty'];
const cssFiles = ['styles', 'options', 'overlay', 'terminal'];

15
src/server/socketServer/middleware.ts

@ -0,0 +1,15 @@
import type express from 'express';
import { join } from 'path';
import { default as _favicon } from 'serve-favicon';
export const favicon = _favicon(join('build', 'assets', 'favicon.ico'));
export function redirect(
req: express.Request,
res: express.Response,
next: Function,
) {
if (req.path.substr(-1) === '/' && req.path.length > 1)
res.redirect(301, req.path.slice(0, -1) + req.url.slice(req.path.length));
else next();
}

36
src/server/socketServer/socket.ts

@ -0,0 +1,36 @@
import type express from 'express';
import socket from 'socket.io';
import http from 'http';
import https from 'https';
import isUndefined from 'lodash/isUndefined.js';
import { logger } from '../../shared/logger';
import type { SSLBuffer } from '../../shared/interfaces';
export const listen = (
app: express.Express,
host: string,
port: number,
path: string,
{ key, cert }: SSLBuffer,
): SocketIO.Server =>
socket(
!isUndefined(key) && !isUndefined(cert)
? https.createServer({ key, cert }, app).listen(port, host, () => {
logger.info('Server started', {
port,
connection: 'https',
});
})
: http.createServer(app).listen(port, host, () => {
logger.info('Server started', {
port,
connection: 'http',
});
}),
{
path: `${path}/socket.io`,
pingInterval: 3000,
pingTimeout: 7000,
},
);

0
src/server/ssl.ts → src/server/socketServer/ssl.ts

4
src/server/spawn.ts

@ -1,7 +1,7 @@
import isUndefined from 'lodash/isUndefined.js';
import pty from 'node-pty';
import { logger } from '../shared/logger.js';
import { xterm } from './shared/xterm.js';
import { logger } from '../shared/logger';
import { xterm } from './shared/xterm';
export function spawn(socket: SocketIO.Socket, args: string[]): void {
const term = pty.spawn('/usr/bin/env', args, xterm);

0
src/server/default.ts → src/shared/defaults.ts

2
src/shared/logger.ts

@ -1,6 +1,6 @@
import winston from 'winston';
import { isDev } from './env.js';
import { isDev } from './env';
const { combine, timestamp, label, simple, json, colorize } = winston.format;

Loading…
Cancel
Save