Browse Source

Merge branch 'master' into relative

pull/175/head
Cian Butler 6 years ago
committed by GitHub
parent
commit
77f48b37e5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      README.md
  2. 6
      index.js
  3. 2
      package.json
  4. 40
      src/client/index.ts
  5. 50
      src/client/wetty.scss
  6. 6
      src/server/index.ts
  7. 1
      src/server/interfaces.ts
  8. 23
      src/server/server.ts

6
README.md

@ -24,11 +24,11 @@ $ yarn build
To install it globally from npm use yarn or npm: To install it globally from npm use yarn or npm:
- yarn, `yarn -g add wetty.js` - yarn, `yarn global add wetty.js`
- npm, `npm i -g wetty.js` - npm, `npm i -g wetty.js`
For auto-login feature you'll need sshpass installed(NOT required for rest of For auto-login feature you'll need sshpass installed (NOT required for rest of
the program". the program).
- `apt-get install sshpass` (debian eg. Ubuntu) - `apt-get install sshpass` (debian eg. Ubuntu)
- `yum install sshpass` (red hat flavours eg. CentOs) - `yum install sshpass` (red hat flavours eg. CentOs)

6
index.js

@ -94,6 +94,12 @@ if (require.main === module) {
type: 'string', type: 'string',
default: process.env.COMMAND || 'login', default: process.env.COMMAND || 'login',
}, },
bypasshelmet: {
demand: false,
description: 'disable helmet from placing security restrictions',
type: 'boolean',
default: false,
},
help: { help: {
demand: false, demand: false,
alias: 'h', alias: 'h',

2
package.json

@ -94,7 +94,7 @@
"eslint-plugin-typescript": "^1.0.0-rc.1", "eslint-plugin-typescript": "^1.0.0-rc.1",
"file-loader": "^3.0.1", "file-loader": "^3.0.1",
"husky": "^1.3.1", "husky": "^1.3.1",
"lint-staged": "^6.1.1", "lint-staged": "~8.2.0",
"mini-css-extract-plugin": "^0.5.0", "mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.11.0", "node-sass": "^4.11.0",
"nodemon": "^1.14.10", "nodemon": "^1.14.10",

40
src/client/index.ts

@ -15,8 +15,46 @@ const socket = io(window.location.origin, {
socket.on('connect', () => { socket.on('connect', () => {
const term = new Terminal(); const term = new Terminal();
term.open(document.getElementById('terminal')); term.open(document.getElementById('terminal'));
term.setOption('fontSize', 14); const defaultOptions = { fontSize: 14 };
let options: any;
try {
if (localStorage.options === undefined) {
options = defaultOptions;
} else {
options = JSON.parse(localStorage.options);
}
} catch {
options = defaultOptions;
}
Object.keys(options).forEach(key => {
const value = options[key];
term.setOption(key, value);
});
const code = JSON.stringify(options, null, 2);
const editor = document.querySelector('#options .editor');
editor.value = code;
editor.addEventListener('keyup', e => {
try {
const updated = JSON.parse(editor.value);
const updatedCode = JSON.stringify(updated, null, 2);
editor.value = updatedCode;
editor.classList.remove('error');
localStorage.options = updatedCode;
Object.keys(updated).forEach(key => {
const value = updated[key];
term.setOption(key, value);
});
resize();
} catch {
// skip
editor.classList.add('error');
}
});
document.getElementById('overlay').style.display = 'none'; document.getElementById('overlay').style.display = 'none';
document.querySelector('#options .toggler').addEventListener('click', e => {
document.getElementById('options').classList.toggle('opened');
e.preventDefault();
});
window.addEventListener('beforeunload', handler, false); window.addEventListener('beforeunload', handler, false);
/* /*
term.scrollPort_.screen_.setAttribute('contenteditable', 'false'); term.scrollPort_.screen_.setAttribute('contenteditable', 'false');

50
src/client/wetty.scss

@ -3,6 +3,7 @@
$black: #000; $black: #000;
$grey: rgba(0, 0, 0, 0.75); $grey: rgba(0, 0, 0, 0.75);
$white: #fff; $white: #fff;
$lgrey: #ccc;
html, html,
body { body {
@ -44,4 +45,53 @@ body {
position: relative; position: relative;
width: 100%; width: 100%;
} }
#options {
position: absolute;
top: 1em;
right: 1em;
z-index: 20;
height: 16px;
width: 16px;
a.toggler {
display: inline-block;
position: absolute;
right: 1em;
top: 0em;
font-size: 16px;
color: $lgrey;
z-index: 20;
:hover {
color: $white;
}
}
.editor {
background-color: rgba(0, 0, 0, 0.85);
padding: 0.5em;
border-radius: 0.3em;
border-color: rgba(255, 255, 255, 0.25);
display: none;
position: relative;
height: 100%;
width: 100%;
top: 1em;
right: 2em;
color: #eee;
font-size: 24px;
}
.editor.error {
color: red;
}
}
#options.opened {
height: 50%;
width: 50%;
.editor {
display: flex;
}
}
} }

6
src/server/index.ts

@ -17,6 +17,7 @@ export interface Options {
port: number; port: number;
title: string; title: string;
command?: string; command?: string;
bypasshelmet?: boolean;
} }
interface CLI extends Options { interface CLI extends Options {
@ -38,6 +39,7 @@ export default class Server {
command, command,
sslkey, sslkey,
sslcert, sslcert,
bypasshelmet,
}: Options): Promise<void> { }: Options): Promise<void> {
wetty wetty
.on('exit', ({ code, msg }: { code: number; msg: string }) => { .on('exit', ({ code, msg }: { code: number; msg: string }) => {
@ -56,11 +58,11 @@ export default class Server {
host: sshhost, host: sshhost,
auth: sshauth, auth: sshauth,
port: sshport, port: sshport,
title: title, title,
pass: sshpass, pass: sshpass,
key: sshkey, key: sshkey,
}, },
{ base, host, port, title }, { base, host, port, title, bypasshelmet },
command, command,
{ key: sslkey, cert: sslcert } { key: sslkey, cert: sslcert }
); );

1
src/server/interfaces.ts

@ -21,4 +21,5 @@ export interface Server {
port: number; port: number;
host: string; host: string;
base: string; base: string;
bypasshelmet: boolean;
} }

23
src/server/server.ts

@ -17,7 +17,7 @@ const distDir = path.join(__dirname, 'client');
const trim = (str: string): string => str.replace(/\/*$/, ''); const trim = (str: string): string => str.replace(/\/*$/, '');
export default function createServer( export default function createServer(
{ base, port, host, title }: Server, { base, port, host, title, bypasshelmet }: Server,
{ key, cert }: SSLBuffer { key, cert }: SSLBuffer
): SocketIO.Server { ): SocketIO.Server {
const basePath = trim(base); const basePath = trim(base);
@ -39,6 +39,7 @@ export default function createServer(
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>${title}</title> <title>${title}</title>
<link rel="stylesheet" href="${resourcePath}public/index.css" /> <link rel="stylesheet" href="${resourcePath}public/index.css" />
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
</head> </head>
<body> <body>
<div id="overlay"> <div id="overlay">
@ -47,6 +48,12 @@ export default function createServer(
<input type="button" onclick="location.reload();" value="reconnect" /> <input type="button" onclick="location.reload();" value="reconnect" />
</div> </div>
</div> </div>
<div id="options">
<a class="toggler"
href="#"
alt="Toggle options"><i class="fas fa-cogs"></i></a>
<textarea class="editor"></textarea>
</div>
<div id="terminal"></div> <div id="terminal"></div>
<script src="${resourcePath}public/index.js"></script> <script src="${resourcePath}public/index.js"></script>
</body> </body>
@ -56,16 +63,22 @@ export default function createServer(
const app = express(); const app = express();
app app
.use(morgan('combined', { stream: logger.stream })) .use(morgan('combined', { stream: logger.stream }))
.use(helmet())
.use(compression()) .use(compression())
.use(favicon(path.join(distDir, 'favicon.ico'))) .use(favicon(path.join(distDir, 'favicon.ico')))
.use(`${basePath}/public`, express.static(distDir)) .use(`${basePath}/public`, express.static(distDir))
.use((req, res, next) => { .use((req, res, next) => {
if (req.url === basePath) res.redirect(301, req.url + '/'); if (req.url === basePath) res.redirect(301, req.url + '/');
else next(); else next();
}) });
.get(basePath, html)
.get(`${basePath}/ssh/:user`, html); // Allow helmet to be bypassed.
// Unfortunately, order matters with middleware
// which is why this is thrown in the middle
if (!bypasshelmet) {
app.use(helmet());
}
app.get(basePath, html).get(`${basePath}/ssh/:user`, html);
return socket( return socket(
!isUndefined(key) && !isUndefined(cert) !isUndefined(key) && !isUndefined(cert)

Loading…
Cancel
Save