From 0770647af5173a76ea675af0c1c97cad1430b74a Mon Sep 17 00:00:00 2001 From: butlerx Date: Wed, 25 Aug 2021 10:25:21 +0100 Subject: [PATCH] Release 2.1.1 Bugfix: remove `-` from the start of usernames --- .eslintrc.json | 16 +++++++++-- package.json | 4 +-- src/client/wetty/download.spec.ts | 48 +++++++++++++++---------------- src/server/shared/shell.spec.ts | 15 ++++++++++ src/server/shared/shell.ts | 2 +- 5 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 src/server/shared/shell.spec.ts diff --git a/.eslintrc.json b/.eslintrc.json index 311bd94..ba68e6f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "prettier", "mocha"], + "plugins": ["@typescript-eslint", "prettier"], "env": { "es6": true, "node": true, @@ -67,5 +67,17 @@ "extensions": [".ts", ".js"] } } - } + }, + "overrides": [ + { + "files": ["*.spec.ts"], + "extends": ["plugin:mocha/recommended"], + "plugins": ["mocha"], + "rules": { + "import/no-extraneous-dependencies": ["off"], + "mocha/no-mocha-arrows": ["off"], + "no-unused-expressions": ["off"] + } + } + ] } diff --git a/package.json b/package.json index 17bd01a..4ce7542 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wetty", - "version": "2.1.0", + "version": "2.1.1", "description": "WeTTY = Web + TTY. Terminal access in browser over http/https", "homepage": "https://github.com/butlerx/wetty", "license": "MIT", @@ -17,7 +17,7 @@ "build": "snowpack build", "dev": "NODE_ENV=development concurrently --kill-others --success first \"snowpack dev\" \"nodemon .\"", "prepublishOnly": "snowpack build", - "lint": "eslint src/**/*.ts", + "lint": "eslint src", "start": "NODE_ENV=production node .", "contributor": "all-contributors", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha -r ts-node/register src/**/*.spec.ts", diff --git a/src/client/wetty/download.spec.ts b/src/client/wetty/download.spec.ts index a7383f2..ce5b028 100644 --- a/src/client/wetty/download.spec.ts +++ b/src/client/wetty/download.spec.ts @@ -1,5 +1,3 @@ -/* eslint-disable */ - import { expect } from 'chai'; import 'mocha'; import * as sinon from 'sinon'; @@ -7,15 +5,17 @@ import * as sinon from 'sinon'; import { JSDOM } from 'jsdom'; import { FileDownloader } from './download'; +const noop = (): void => {}; // eslint-disable-line @typescript-eslint/no-empty-function + describe('FileDownloader', () => { const FILE_BEGIN = 'BEGIN'; const FILE_END = 'END'; - let fileDownloader: any; + let fileDownloader: FileDownloader; beforeEach(() => { const { window } = new JSDOM(`...`); global.document = window.document; - fileDownloader = new FileDownloader(() => {}, FILE_BEGIN, FILE_END); + fileDownloader = new FileDownloader(noop, FILE_BEGIN, FILE_END); }); afterEach(() => { @@ -81,7 +81,7 @@ describe('FileDownloader', () => { }); it('should buffer across incomplete file begin marker sequence on two calls', () => { - fileDownloader = new FileDownloader(() => {}, 'BEGIN', 'END'); + fileDownloader = new FileDownloader(noop, 'BEGIN', 'END'); const onCompleteFileCallbackStub = sinon.stub( fileDownloader, 'onCompleteFileCallback', @@ -94,7 +94,7 @@ describe('FileDownloader', () => { }); it('should buffer across incomplete file begin marker sequence on n calls', () => { - fileDownloader = new FileDownloader(() => {}, 'BEGIN', 'END'); + fileDownloader = new FileDownloader(noop, 'BEGIN', 'END'); const onCompleteFileCallbackStub = sinon.stub( fileDownloader, 'onCompleteFileCallback', @@ -104,25 +104,25 @@ describe('FileDownloader', () => { expect(fileDownloader.buffer('E')).to.equal(''); expect(fileDownloader.buffer('G')).to.equal(''); expect(fileDownloader.buffer('I')).to.equal(''); - expect(fileDownloader.buffer('NFILE' + 'END')).to.equal(''); + expect(fileDownloader.buffer('NFILEEND')).to.equal(''); expect(onCompleteFileCallbackStub.calledOnce).to.be.true; expect(onCompleteFileCallbackStub.getCall(0).args[0]).to.equal('FILE'); }); it('should buffer across incomplete file begin marker sequence with data on the left and right on multiple calls', () => { - fileDownloader = new FileDownloader(() => {}, 'BEGIN', 'END'); + fileDownloader = new FileDownloader(noop, 'BEGIN', 'END'); const onCompleteFileCallbackStub = sinon.stub( fileDownloader, 'onCompleteFileCallback', ); - expect(fileDownloader.buffer('DATA AT THE LEFT' + 'B')).to.equal( + expect(fileDownloader.buffer('DATA AT THE LEFTB')).to.equal( 'DATA AT THE LEFT', ); expect(fileDownloader.buffer('E')).to.equal(''); expect(fileDownloader.buffer('G')).to.equal(''); expect(fileDownloader.buffer('I')).to.equal(''); - expect(fileDownloader.buffer('NFILE' + 'ENDDATA AT THE RIGHT')).to.equal( + expect(fileDownloader.buffer('NFILEENDDATA AT THE RIGHT')).to.equal( 'DATA AT THE RIGHT', ); expect(onCompleteFileCallbackStub.calledOnce).to.be.true; @@ -130,13 +130,13 @@ describe('FileDownloader', () => { }); it('should buffer across incomplete file begin marker sequence then handle false positive', () => { - fileDownloader = new FileDownloader(() => {}, 'BEGIN', 'END'); + fileDownloader = new FileDownloader(noop, 'BEGIN', 'END'); const onCompleteFileCallbackStub = sinon.stub( fileDownloader, 'onCompleteFileCallback', ); - expect(fileDownloader.buffer('DATA AT THE LEFT' + 'B')).to.equal( + expect(fileDownloader.buffer('DATA AT THE LEFTB')).to.equal( 'DATA AT THE LEFT', ); expect(fileDownloader.buffer('E')).to.equal(''); @@ -150,7 +150,7 @@ describe('FileDownloader', () => { }); it('should buffer across incomplete file end marker sequence on two calls', () => { - fileDownloader = new FileDownloader(() => {}, 'BEGIN', 'END'); + fileDownloader = new FileDownloader(noop, 'BEGIN', 'END'); const mockFilePart1 = 'DATA AT THE LEFTBEGINFILEE'; const mockFilePart2 = 'NDDATA AT THE RIGHT'; @@ -166,13 +166,13 @@ describe('FileDownloader', () => { }); it('should buffer across incomplete file end and file begin marker sequence with data on the left and right on multiple calls', () => { - fileDownloader = new FileDownloader(() => {}, 'BEGIN', 'END'); + fileDownloader = new FileDownloader(noop, 'BEGIN', 'END'); const onCompleteFileCallbackStub = sinon.stub( fileDownloader, 'onCompleteFileCallback', ); - expect(fileDownloader.buffer('DATA AT THE LEFT' + 'BE')).to.equal( + expect(fileDownloader.buffer('DATA AT THE LEFTBE')).to.equal( 'DATA AT THE LEFT', ); expect(fileDownloader.buffer('G')).to.equal(''); @@ -187,7 +187,7 @@ describe('FileDownloader', () => { }); it('should be able to handle multiple files', () => { - fileDownloader = new FileDownloader(() => {}, 'BEGIN', 'END'); + fileDownloader = new FileDownloader(noop, 'BEGIN', 'END'); const onCompleteFileCallbackStub = sinon.stub( fileDownloader, 'onCompleteFileCallback', @@ -202,7 +202,7 @@ describe('FileDownloader', () => { 'SECOND DATA' + 'BEGIN', ), - ).to.equal('DATA AT THE LEFT' + 'SECOND DATA'); + ).to.equal('DATA AT THE LEFTSECOND DATA'); expect(onCompleteFileCallbackStub.calledOnce).to.be.true; expect(onCompleteFileCallbackStub.getCall(0).args[0]).to.equal('FILE1'); @@ -214,19 +214,19 @@ describe('FileDownloader', () => { }); it('should be able to handle multiple files with an ending marker', () => { - fileDownloader = new FileDownloader(() => {}, 'BEGIN', 'END'); + fileDownloader = new FileDownloader(noop, 'BEGIN', 'END'); const onCompleteFileCallbackStub = sinon.stub( fileDownloader, 'onCompleteFileCallback', ); - expect( - fileDownloader.buffer('DATA AT THE LEFT' + 'BEGIN' + 'FILE1' + 'EN'), - ).to.equal('DATA AT THE LEFT'); + expect(fileDownloader.buffer('DATA AT THE LEFTBEGINFILE1EN')).to.equal( + 'DATA AT THE LEFT', + ); expect(onCompleteFileCallbackStub.calledOnce).to.be.false; - expect( - fileDownloader.buffer('D' + 'SECOND DATA' + 'BEGIN' + 'FILE2' + 'EN'), - ).to.equal('SECOND DATA'); + expect(fileDownloader.buffer('DSECOND DATABEGINFILE2EN')).to.equal( + 'SECOND DATA', + ); expect(onCompleteFileCallbackStub.calledOnce).to.be.true; expect(onCompleteFileCallbackStub.getCall(0).args[0]).to.equal('FILE1'); expect(fileDownloader.buffer('D')).to.equal(''); diff --git a/src/server/shared/shell.spec.ts b/src/server/shared/shell.spec.ts new file mode 100644 index 0000000..03ffe57 --- /dev/null +++ b/src/server/shared/shell.spec.ts @@ -0,0 +1,15 @@ +import 'mocha'; +import { expect } from 'chai'; +import { escapeShell } from './shell'; + +describe('Values passed to escapeShell should be safe to pass woth sub processes', () => { + it('should escape remove subcommands', () => { + const cmd = escapeShell('test`echo hello`'); + expect(cmd).to.equal('testechohello'); + }); + + it('should ensure args cant be flags', () => { + const cmd = escapeShell("-oProxyCommand='bash' -c `wget localhost:2222`"); + expect(cmd).to.equal('oProxyCommandbash-cwgetlocalhost2222'); + }); +}); diff --git a/src/server/shared/shell.ts b/src/server/shared/shell.ts index 31ef09b..71c8415 100644 --- a/src/server/shared/shell.ts +++ b/src/server/shared/shell.ts @@ -1,2 +1,2 @@ export const escapeShell = (username: string): string => - username.replace(/[^a-zA-Z0-9-_]/g, ''); + username.replace(/^-|[^a-zA-Z0-9_-]/g, '');