Skip to content

Commit

Permalink
Rebased from main, removed lockfiles from .gitignore
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian7573 committed Aug 25, 2021
2 parents 33995eb + 2a3b724 commit 419fcfb
Show file tree
Hide file tree
Showing 13 changed files with 120 additions and 42 deletions.
16 changes: 14 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier", "mocha"],
"plugins": ["@typescript-eslint", "prettier"],
"env": {
"es6": true,
"node": true,
Expand Down Expand Up @@ -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"]
}
}
]
}
5 changes: 1 addition & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,11 @@ jobs:
env:
CI: true
- name: Publish if version has been updated
uses: pascalgn/npm-publish-action@1.3.6
uses: pascalgn/npm-publish-action@1.3.8
with:
tag_name: "v%s"
tag_message: "v%s"
create_tag: "true"
commit_pattern: "^Release (\\S+)"
workspace: "."
publish_command: "yarn"
publish_args: "--non-interactive"
env:
GITHUB_TOKEN: ${{ secrets.node_github_token }}
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: Create Release
on:
push:
tags:
- 'v*'
jobs:
build:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Create Release
- uses: fregante/release-with-changelog@v3
with:
token: ${{ secrets.NODE_GITHUB_TOKEN }}
title: "Release {tag}"
exclude: true
commit-template: '- {title} ← {hash}'
template: |
### Changelog
{commits}
{range}
22 changes: 22 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Mark stale issues and pull requests

on:
schedule:
- cron: '39 10 * * *'

jobs:
stale:

runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write

steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Stale issue message'
stale-pr-message: 'Stale pull request message'
stale-issue-label: 'no-issue-activity'
stale-pr-label: 'no-pr-activity'
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
/package-lock.json
/yarn.lock

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
Expand Down
4 changes: 2 additions & 2 deletions containers/wetty/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM node:current-alpine as builder
RUN apk add -U build-base python
RUN apk add -U build-base python3
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN yarn && \
Expand All @@ -14,7 +14,7 @@ EXPOSE 3000
COPY --from=builder /usr/src/app/build /usr/src/app/build
COPY --from=builder /usr/src/app/node_modules /usr/src/app/node_modules
COPY package.json /usr/src/app
RUN apk add -U openssh-client sshpass && \
RUN apk add -U coreutils openssh-client sshpass && \
mkdir ~/.ssh

ENTRYPOINT [ "yarn" , "docker-entrypoint"]
2 changes: 1 addition & 1 deletion docs/nginx.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The following confs assume you want to serve WeTTy on the url
`example.com/wetty` and are running WeTTy with the default base and serving it
on the same server

For a more detailed look see the [nginx.conf](../bin/nginx.template) used for
For a more detailed look see the [nginx.conf](../conf/nginx.template) used for
testing

Put the following configuration in your nginx conf:
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wetty",
"version": "2.0.4",
"version": "2.1.1",
"description": "WeTTY = Web + TTY. Terminal access in browser over http/https",
"homepage": "https://github.com/butlerx/wetty",
"license": "MIT",
Expand All @@ -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",
Expand Down Expand Up @@ -111,7 +111,7 @@
"helmet": "^4.1.0",
"json5": "^2.1.3",
"lodash": "^4.17.20",
"node-pty": "^0.9.0",
"node-pty": "^0.10.0",
"parseurl": "^1.3.3",
"sass": "^1.26.10",
"socket.io": "^2.3.0",
Expand Down
48 changes: 24 additions & 24 deletions src/client/wetty/download.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
/* eslint-disable */

import { expect } from 'chai';
import 'mocha';
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(() => {
Expand Down Expand Up @@ -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',
Expand All @@ -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',
Expand All @@ -104,39 +104,39 @@ 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;
expect(onCompleteFileCallbackStub.getCall(0).args[0]).to.equal('FILE');
});

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('');
Expand All @@ -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';

Expand All @@ -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('');
Expand All @@ -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',
Expand All @@ -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');

Expand All @@ -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('');
Expand Down
3 changes: 2 additions & 1 deletion src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
forceSSHDefault,
defaultCommand,
} from './shared/defaults.js';
import { escapeShell } from './server/shared/shell.js';

/**
* Starts WeTTy Server
Expand Down Expand Up @@ -58,7 +59,7 @@ export async function start(
} else {
try {
const username = await login(socket);
args[1] = `${username.trim()}@${args[1]}`;
args[1] = `${escapeShell(username.trim())}@${args[1]}`;
logger.debug('Spawning term', {
username: username.trim(),
cmd: args.join(' '),
Expand Down
11 changes: 8 additions & 3 deletions src/server/command/address.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { escapeShell } from '../shared/shell.js';

export function address(
headers: Record<string, string>,
user: string,
Expand All @@ -6,9 +8,12 @@ export function address(
// Check request-header for username
const remoteUser = headers['remote-user'];
if (remoteUser) {
return `${remoteUser}@${host}`;
return `${escapeShell(remoteUser)}@${host}`;
}
const match = headers.referer.match('.+/ssh/([^/]+)$');
const fallback = user ? `${user}@${host}` : host;
return match ? `${match[1].split('?')[0]}@${host}` : fallback;
if (match) {
const username = escapeShell(match[1].split('?')[0]);
return `${username}@${host}`;
}
return user ? `${escapeShell(user)}@${host}` : host;
}
15 changes: 15 additions & 0 deletions src/server/shared/shell.spec.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
2 changes: 2 additions & 0 deletions src/server/shared/shell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const escapeShell = (username: string): string =>
username.replace(/^-|[^a-zA-Z0-9_-]/g, '');

0 comments on commit 419fcfb

Please sign in to comment.