mirror of
https://github.com/sorenisanerd/gotty.git
synced 2024-12-22 23:17:29 +00:00
Merge branch 'master' of https://github.com/sorenisanerd/gotty into process-http-headers
This commit is contained in:
commit
936288058d
@ -25,7 +25,7 @@
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/160090?v=4",
|
||||
"profile": "http://linux2go.dk/",
|
||||
"contributions": [
|
||||
"code"
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -322,7 +322,7 @@
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/42201?v=4",
|
||||
"profile": "https://rusnak.io/",
|
||||
"contributions": [
|
||||
"code"
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -333,6 +333,195 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jkandasa",
|
||||
"name": "Jeeva Kandasamy",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1004403?v=4",
|
||||
"profile": "https://github.com/jkandasa",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hardliner66",
|
||||
"name": "Steve Biedermann",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/2937272?v=4",
|
||||
"profile": "https://twitch.tv/iamhardliner",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "xgdgsc",
|
||||
"name": "xgdgsc",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1189869?v=4",
|
||||
"profile": "https://github.com/xgdgsc",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "flechaig",
|
||||
"name": "flechaig",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10887132?v=4",
|
||||
"profile": "https://github.com/flechaig",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Fan-SJ",
|
||||
"name": "Fan-SJ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/49977708?v=4",
|
||||
"profile": "https://github.com/Fan-SJ",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dmartin",
|
||||
"name": "Dustin Martin",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1657652?v=4",
|
||||
"profile": "https://github.com/dmartin",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ahmetb",
|
||||
"name": "Ahmet Alp Balkan",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/159209?v=4",
|
||||
"profile": "https://ahmet.dev/",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "CoconutMacaroon",
|
||||
"name": "CoconutMacaroon",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/45187468?v=4",
|
||||
"profile": "https://github.com/CoconutMacaroon",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "DannyBen",
|
||||
"name": "Danny Ben Shitrit",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/2405099?v=4",
|
||||
"profile": "https://github.dannyben.com/",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "George-NG",
|
||||
"name": "George-NG",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/28577165?v=4",
|
||||
"profile": "https://github.com/George-NG",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ghthor",
|
||||
"name": "Will Owens",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/160298?v=4",
|
||||
"profile": "https://github.com/ghthor",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jpillora",
|
||||
"name": "Jaime Pillora",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/633843?v=4",
|
||||
"profile": "https://jpillora.com/",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kaisawind",
|
||||
"name": "kaisawind",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/4010613?v=4",
|
||||
"profile": "https://github.com/kaisawind",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "linyinli",
|
||||
"name": "linyinli",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/42955482?v=4",
|
||||
"profile": "https://github.com/linyinli",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "LucaMarconato",
|
||||
"name": "LucaMarconato",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/2664412?v=4",
|
||||
"profile": "https://github.com/LucaMarconato",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "masterkain",
|
||||
"name": "Kain",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/12844?v=4",
|
||||
"profile": "https://audiobox.fm/",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Nexuist",
|
||||
"name": "Andi Andreas",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1498061?v=4",
|
||||
"profile": "http://duro.me/",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "qigj",
|
||||
"name": "qigj",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/56585735?v=4",
|
||||
"profile": "https://github.com/qigj",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "shuaiyy",
|
||||
"name": "shuaiyy",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19821321?v=4",
|
||||
"profile": "https://github.com/shuaiyy",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "v20z",
|
||||
"name": "v20z",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/2884824?v=4",
|
||||
"profile": "https://github.com/v20z",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Yann-Qiu",
|
||||
"name": "Yanfeng Qiu",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/56961747?v=4",
|
||||
"profile": "https://github.com/Yann-Qiu",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7
|
||||
|
47
.github/workflows/main.yaml
vendored
47
.github/workflows/main.yaml
vendored
@ -1,24 +1,49 @@
|
||||
name: Go
|
||||
name: "Unit and Build Tests"
|
||||
|
||||
on:
|
||||
- push
|
||||
push:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
|
||||
jobs:
|
||||
bundle-up-to-date:
|
||||
runs-on: "ubuntu-latest"
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- run: "make clean"
|
||||
- run: "make assets"
|
||||
- name: "Make sure gotty.js bundle is up-to-date"
|
||||
run: "diffsize=$(git diff bindata/static/js/gotty.js | wc -l); test $diffsize == 0"
|
||||
|
||||
|
||||
cross-compile-test:
|
||||
runs-on: "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.16
|
||||
go-version: 1.19
|
||||
|
||||
- name: Test
|
||||
run: make test
|
||||
- name: "Build & test"
|
||||
run: "make tools test cross_compile"
|
||||
|
||||
- name: Build
|
||||
run: make tools cross_compile
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binaries
|
||||
path: builds/pkg/*/gotty
|
37
.github/workflows/pre-release.yaml
vendored
37
.github/workflows/pre-release.yaml
vendored
@ -1,37 +0,0 @@
|
||||
---
|
||||
name: "pre-release"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
|
||||
jobs:
|
||||
pre-release:
|
||||
name: "Pre Release"
|
||||
runs-on: "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
|
||||
|
||||
- name: "Build & test"
|
||||
run: "make tools release-artifacts"
|
||||
|
||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
automatic_release_tag: "latest"
|
||||
prerelease: true
|
||||
title: "Development Build"
|
||||
files: |
|
||||
LICENSE
|
||||
builds/dist/*
|
30
.github/workflows/quick-build.yaml
vendored
Normal file
30
.github/workflows/quick-build.yaml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: "Quick build test"
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
|
||||
jobs:
|
||||
quick-build-test:
|
||||
runs-on: "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: "Build"
|
||||
run: "touch bindata/* bindata/*/* ; make"
|
||||
|
||||
- name: Upload linux/amd64 artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: gotty-linux-amd64
|
||||
path: gotty
|
40
.github/workflows/release.yml
vendored
Normal file
40
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
name: "tagged-release"
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
tagged-release:
|
||||
name: "Tagged Release"
|
||||
runs-on: "ubuntu-latest"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: "Build & test"
|
||||
run: "make tools test release-artifacts"
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binaries
|
||||
path: builds/pkg/*/gotty
|
||||
|
||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
prerelease: false
|
||||
draft: true
|
||||
files: |
|
||||
LICENSE
|
||||
builds/dist/*
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
gotty
|
||||
bindata/static
|
||||
builds
|
||||
js/dist
|
||||
js/node_modules/*
|
||||
|
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch GoTTY",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"program": "${workspaceFolder}",
|
||||
"args": ["-a", "127.0.0.1", "-w", "bash"]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
FROM golang:1.13.1
|
||||
FROM golang:1.16
|
||||
|
||||
WORKDIR /gotty
|
||||
COPY . /gotty
|
||||
|
2
LICENSE
2
LICENSE
@ -1,7 +1,7 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2017 Iwasaki Yudai
|
||||
Copyright (c) 2021 Søren L. Hansen
|
||||
Copyright (c) 2021-2022 Søren L. Hansen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
69
Makefile
69
Makefile
@ -2,6 +2,8 @@ OUTPUT_DIR = ./builds
|
||||
GIT_COMMIT = `git rev-parse HEAD | cut -c1-7`
|
||||
VERSION = $(shell git describe --tags)
|
||||
BUILD_OPTIONS = -ldflags "-X main.Version=$(VERSION)"
|
||||
WEBPACK_MODE = production
|
||||
export CGO_ENABLED=0
|
||||
|
||||
gotty: main.go assets server/*.go webtty/*.go backend/*.go Makefile
|
||||
go build ${BUILD_OPTIONS}
|
||||
@ -9,52 +11,39 @@ gotty: main.go assets server/*.go webtty/*.go backend/*.go Makefile
|
||||
docker:
|
||||
docker build . -t gotty-bash:$(VERSION)
|
||||
|
||||
.PHONY: assets
|
||||
assets: bindata/static/js/gotty.js bindata/static/index.html bindata/static/icon.svg bindata/static/favicon.ico bindata/static/css/index.css bindata/static/css/xterm.css bindata/static/css/xterm_customize.css bindata/static/manifest.json bindata/static/icon_192.png
|
||||
.PHONY: all docker assets
|
||||
assets: bindata/static/js/gotty.js.map \
|
||||
bindata/static/js/gotty.js \
|
||||
bindata/static/index.html \
|
||||
bindata/static/icon.svg \
|
||||
bindata/static/favicon.ico \
|
||||
bindata/static/css/index.css \
|
||||
bindata/static/css/xterm.css \
|
||||
bindata/static/css/xterm_customize.css \
|
||||
bindata/static/manifest.json \
|
||||
bindata/static/icon_192.png
|
||||
|
||||
.PHONY: all
|
||||
all: gotty docker
|
||||
all: gotty
|
||||
|
||||
bindata/static:
|
||||
mkdir -p bindata/static
|
||||
bindata/static bindata/static/css bindata/static/js:
|
||||
mkdir -p $@
|
||||
|
||||
bindata/static/icon.svg: bindata/static resources/icon.svg
|
||||
cp resources/icon.svg bindata/static/icon.svg
|
||||
bindata/static/%: resources/% | bindata/static/css
|
||||
cp "$<" "$@"
|
||||
|
||||
bindata/static/index.html: bindata/static resources/index.html
|
||||
cp resources/index.html bindata/static/index.html
|
||||
bindata/static/css/%.css: resources/%.css | bindata/static
|
||||
cp "$<" "$@"
|
||||
|
||||
bindata/static/manifest.json: bindata/static resources/manifest.json
|
||||
cp resources/manifest.json bindata/static/manifest.json
|
||||
|
||||
bindata/static/favicon.ico: bindata/static resources/favicon.ico
|
||||
cp resources/favicon.ico bindata/static/favicon.ico
|
||||
|
||||
bindata/static/icon_192.png: bindata/static resources/icon_192.png
|
||||
cp resources/icon_192.png bindata/static/icon_192.png
|
||||
|
||||
bindata/static/js: bindata/static
|
||||
mkdir -p bindata/static/js
|
||||
|
||||
bindata/static/css: bindata/static
|
||||
mkdir -p bindata/static/css
|
||||
|
||||
bindata/static/css/index.css: bindata/static/css resources/index.css
|
||||
cp resources/index.css bindata/static/css/index.css
|
||||
|
||||
bindata/static/css/xterm_customize.css: bindata/static/css resources/xterm_customize.css
|
||||
cp resources/xterm_customize.css bindata/static/css/xterm_customize.css
|
||||
|
||||
bindata/static/css/xterm.css: bindata/static/css js/node_modules/xterm/css/xterm.css
|
||||
cp js/node_modules/xterm/css/xterm.css bindata/static/css/xterm.css
|
||||
bindata/static/css/xterm.css: js/node_modules/xterm/css/xterm.css | bindata/static
|
||||
cp "$<" "$@"
|
||||
|
||||
js/node_modules/xterm/dist/xterm.css:
|
||||
cd js && \
|
||||
npm install
|
||||
|
||||
bindata/static/js/gotty.js: js/src/* js/node_modules/webpack
|
||||
bindata/static/js/gotty.js.map bindata/static/js/gotty.js: js/src/* | js/node_modules/webpack
|
||||
cd js && \
|
||||
npx webpack
|
||||
npx webpack --mode=$(WEBPACK_MODE)
|
||||
|
||||
js/node_modules/webpack:
|
||||
cd js && \
|
||||
@ -66,8 +55,8 @@ README-options:
|
||||
rm options.txt.tmp
|
||||
|
||||
tools:
|
||||
go get github.com/mitchellh/gox
|
||||
go get github.com/tcnksm/ghr
|
||||
go install github.com/mitchellh/gox@latest
|
||||
go install github.com/tcnksm/ghr@latest
|
||||
|
||||
test:
|
||||
if [ `go fmt $(go list ./... | grep -v /vendor/) | wc -l` -gt 0 ]; then echo "go fmt error"; exit 1; fi
|
||||
@ -89,4 +78,8 @@ release:
|
||||
ghr -draft ${VERSION} ${OUTPUT_DIR}/dist # -c ${GIT_COMMIT} --delete --prerelease -u sorenisanerd -r gotty ${VERSION}
|
||||
|
||||
clean:
|
||||
rm -fr gotty builds js/dist bindata/static
|
||||
rm -fr gotty builds js/dist bindata/static js/node_modules
|
||||
|
||||
addcontributors:
|
||||
gh issue list -s all -L 1000 --json author -t "$$(echo '{{ range . }}{{ .author.login }}\n{{ end }}')" | sort | uniq | xargs -Ifoo all-contributors add foo bug --commitTemplate '<%= (newContributor ? "Add" : "Update") %> @<%= username %> as a contributor'
|
||||
gh pr list -s all -L 1000 --json author -t "$$(echo '{{ range . }}{{ .author.login }}\n{{ end }}')" | sort | uniq | xargs -Ifoo all-contributors add foo code --commitTemplate '<%= (newContributor ? "Add" : "Update") %> @<%= username %> as a contributor'
|
74
NEWS.md
74
NEWS.md
@ -1,4 +1,76 @@
|
||||
# GoTTY releases
|
||||
## 1.5.0 (2022-09-01)
|
||||
|
||||
* Add @ahmetb as a contributor ([276767a](https://github.com/sorenisanerd/gotty/commit/276767a))
|
||||
* Add @CoconutMacaroon as a contributor ([74c1318](https://github.com/sorenisanerd/gotty/commit/74c1318))
|
||||
* Add @DannyBen as a contributor ([fcfa161](https://github.com/sorenisanerd/gotty/commit/fcfa161))
|
||||
* Add @dmartin as a contributor ([6b2ae89](https://github.com/sorenisanerd/gotty/commit/6b2ae89))
|
||||
* Add @Fan-SJ as a contributor ([c2428c8](https://github.com/sorenisanerd/gotty/commit/c2428c8))
|
||||
* Add @flechaig as a contributor ([2c4004d](https://github.com/sorenisanerd/gotty/commit/2c4004d))
|
||||
* Add @George-NG as a contributor ([270ae45](https://github.com/sorenisanerd/gotty/commit/270ae45))
|
||||
* Add @ghthor as a contributor ([1a6bccd](https://github.com/sorenisanerd/gotty/commit/1a6bccd))
|
||||
* Add @jpillora as a contributor ([f52fbd7](https://github.com/sorenisanerd/gotty/commit/f52fbd7))
|
||||
* Add @kaisawind as a contributor ([accff3a](https://github.com/sorenisanerd/gotty/commit/accff3a))
|
||||
* Add @linyinli as a contributor ([8014af3](https://github.com/sorenisanerd/gotty/commit/8014af3))
|
||||
* Add @LucaMarconato as a contributor ([3bd9836](https://github.com/sorenisanerd/gotty/commit/3bd9836))
|
||||
* Add @masterkain as a contributor ([369e2f7](https://github.com/sorenisanerd/gotty/commit/369e2f7))
|
||||
* Add @Nexuist as a contributor ([ca691bc](https://github.com/sorenisanerd/gotty/commit/ca691bc))
|
||||
* Add @qigj as a contributor ([5a052e7](https://github.com/sorenisanerd/gotty/commit/5a052e7))
|
||||
* Add @shuaiyy as a contributor ([95e1bbd](https://github.com/sorenisanerd/gotty/commit/95e1bbd))
|
||||
* Add @v20z as a contributor ([d594bef](https://github.com/sorenisanerd/gotty/commit/d594bef))
|
||||
* Add @xgdgsc as a contributor ([c197990](https://github.com/sorenisanerd/gotty/commit/c197990))
|
||||
* Add @Yann-Qiu as a contributor ([7b994ec](https://github.com/sorenisanerd/gotty/commit/7b994ec))
|
||||
* Update @flechaig as a contributor ([9877e9c](https://github.com/sorenisanerd/gotty/commit/9877e9c))
|
||||
* Update @flechaig as a contributor ([e03ea9c](https://github.com/sorenisanerd/gotty/commit/e03ea9c))
|
||||
* Update @prusnak as a contributor ([3c45888](https://github.com/sorenisanerd/gotty/commit/3c45888))
|
||||
* Update @prusnak as a contributor ([8d7f5fc](https://github.com/sorenisanerd/gotty/commit/8d7f5fc))
|
||||
* Update @sorenisanerd as a contributor ([34f516b](https://github.com/sorenisanerd/gotty/commit/34f516b))
|
||||
* Update @sorenisanerd as a contributor ([89a04d1](https://github.com/sorenisanerd/gotty/commit/89a04d1))
|
||||
* Update @xgdgsc as a contributor ([b3c5d03](https://github.com/sorenisanerd/gotty/commit/b3c5d03))
|
||||
* Update @xgdgsc as a contributor ([09f7e95](https://github.com/sorenisanerd/gotty/commit/09f7e95))
|
||||
* Add make target to add contributors ([1bbfd5e](https://github.com/sorenisanerd/gotty/commit/1bbfd5e))
|
||||
* Add missing import "strings" ([d0e3ffb](https://github.com/sorenisanerd/gotty/commit/d0e3ffb))
|
||||
* add slash ([7706bf2](https://github.com/sorenisanerd/gotty/commit/7706bf2))
|
||||
* Always disable CGO ([7a96f37](https://github.com/sorenisanerd/gotty/commit/7a96f37)), closes [#39](https://github.com/sorenisanerd/gotty/issues/39)
|
||||
* Bump terser from 5.12.1 to 5.14.2 in /js ([3ae13e0](https://github.com/sorenisanerd/gotty/commit/3ae13e0))
|
||||
* Create a release when a new tag is pushed ([d8fe975](https://github.com/sorenisanerd/gotty/commit/d8fe975))
|
||||
* Ensure --quiet flag is honored ([7d431a7](https://github.com/sorenisanerd/gotty/commit/7d431a7)), closes [#45](https://github.com/sorenisanerd/gotty/issues/45)
|
||||
* Refresh dependencies, drop node-sass ([94e5873](https://github.com/sorenisanerd/gotty/commit/94e5873))
|
||||
* Run tests on pull requests ([316d5ff](https://github.com/sorenisanerd/gotty/commit/316d5ff))
|
||||
|
||||
|
||||
## 1.4.0 (2022-05-30)
|
||||
|
||||
* Add @hardliner66 as a contributor ([1ca998e](https://github.com/sorenisanerd/gotty/commit/1ca998e))
|
||||
* Add @jkandasa as a contributor ([cd23910](https://github.com/sorenisanerd/gotty/commit/cd23910))
|
||||
* Add backend tests ([603c650](https://github.com/sorenisanerd/gotty/commit/603c650))
|
||||
* Add generated data to git ([a9fbc07](https://github.com/sorenisanerd/gotty/commit/a9fbc07))
|
||||
* add quiet flag to disable logging ([4109b11](https://github.com/sorenisanerd/gotty/commit/4109b11))
|
||||
* Add references to @yudai ([bffd821](https://github.com/sorenisanerd/gotty/commit/bffd821)), closes [#8](https://github.com/sorenisanerd/gotty/issues/8)
|
||||
* Add rule to build gotty.js.map ([82c3acf](https://github.com/sorenisanerd/gotty/commit/82c3acf))
|
||||
* Apply font size and family in xterm ([f157dbe](https://github.com/sorenisanerd/gotty/commit/f157dbe)), closes [#21](https://github.com/sorenisanerd/gotty/issues/21)
|
||||
* Avoid HTTP 401 error on manifest.json due to CORS ([817b5c8](https://github.com/sorenisanerd/gotty/commit/817b5c8))
|
||||
* Bump browserslist from 4.16.4 to 4.16.6 in /js ([8deba62](https://github.com/sorenisanerd/gotty/commit/8deba62))
|
||||
* Disable arg passing by default ([5c8eb10](https://github.com/sorenisanerd/gotty/commit/5c8eb10)), closes [#17](https://github.com/sorenisanerd/gotty/issues/17)
|
||||
* Do not include ALL of bootstrap ([b63ea16](https://github.com/sorenisanerd/gotty/commit/b63ea16))
|
||||
* Ensure defaults for booleans is set correctly ([28f8e61](https://github.com/sorenisanerd/gotty/commit/28f8e61)), closes [#16](https://github.com/sorenisanerd/gotty/issues/16)
|
||||
* Fix existing tests ([d674aa1](https://github.com/sorenisanerd/gotty/commit/d674aa1)), closes [#13](https://github.com/sorenisanerd/gotty/issues/13)
|
||||
* Fix warnings from Markdown linter ([aa86a34](https://github.com/sorenisanerd/gotty/commit/aa86a34))
|
||||
* go fmt ([dcb153c](https://github.com/sorenisanerd/gotty/commit/dcb153c))
|
||||
* Improve webtty test coverage ([f61763f](https://github.com/sorenisanerd/gotty/commit/f61763f))
|
||||
* Make client request base64 encoding ([dd3603c](https://github.com/sorenisanerd/gotty/commit/dd3603c))
|
||||
* Make sure we read the full message ([1eed97f](https://github.com/sorenisanerd/gotty/commit/1eed97f))
|
||||
* Publish artifacts on push to master ([6c62ab7](https://github.com/sorenisanerd/gotty/commit/6c62ab7))
|
||||
* Remove hterm ([163fd05](https://github.com/sorenisanerd/gotty/commit/163fd05))
|
||||
* Run tests on push ([55674f1](https://github.com/sorenisanerd/gotty/commit/55674f1))
|
||||
* Run tests on push to all branches ([679a324](https://github.com/sorenisanerd/gotty/commit/679a324))
|
||||
* update go version in Dockerfile ([fd2fb99](https://github.com/sorenisanerd/gotty/commit/fd2fb99))
|
||||
* Update js dependencies ([26fc412](https://github.com/sorenisanerd/gotty/commit/26fc412))
|
||||
* Update xterm.js and other js libs ([81afdc7](https://github.com/sorenisanerd/gotty/commit/81afdc7)), closes [#18](https://github.com/sorenisanerd/gotty/issues/18)
|
||||
* Use bootstrap components for up- and downloads ([7f05f2f](https://github.com/sorenisanerd/gotty/commit/7f05f2f))
|
||||
* Use Go's built-in embed mechanism ([f66f0d0](https://github.com/sorenisanerd/gotty/commit/f66f0d0)), closes [#7](https://github.com/sorenisanerd/gotty/issues/7)
|
||||
* feat(zmodem): Allow file uploads/downloads ([782991c](https://github.com/sorenisanerd/gotty/commit/782991c))
|
||||
|
||||
|
||||
|
||||
## v1.3.0
|
||||
|
||||
|
44
README.md
44
README.md
@ -1,6 +1,6 @@
|
||||
# ![](https://raw.githubusercontent.com/sorenisanerd/gotty/master/resources/favicon.ico) GoTTY - Share your terminal as a web application
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[![All Contributors](https://img.shields.io/badge/all_contributors-36-orange.svg?style=flat-square)](#contributors-)
|
||||
[![All Contributors](https://img.shields.io/badge/all_contributors-57-orange.svg?style=flat-square)](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
[![GitHub release](http://img.shields.io/github/release/sorenisanerd/gotty.svg?style=flat-square)][release]
|
||||
@ -73,7 +73,6 @@ By default, GoTTY starts a web server at port 8080. Open the URL on your web bro
|
||||
--width value Static width of the screen, 0(default) means dynamically resize (default: 0) [$GOTTY_WIDTH]
|
||||
--height value Static height of the screen, 0(default) means dynamically resize (default: 0) [$GOTTY_HEIGHT]
|
||||
--ws-origin value A regular expression that matches origin URLs to be accepted by WebSocket. No cross origin requests are acceptable by default [$GOTTY_WS_ORIGIN]
|
||||
--term value Terminal name to use on the browser, one of xterm or hterm. (default: "xterm") [$GOTTY_TERM]
|
||||
--enable-webgl Enable WebGL renderer (default: true) [$GOTTY_ENABLE_WEBGL]
|
||||
--close-signal value Signal sent to the command process when gotty close it (default: SIGHUP) (default: 1) [$GOTTY_CLOSE_SIGNAL]
|
||||
--close-timeout value Time in seconds to force kill process after client is disconnected (default: -1) (default: -1) [$GOTTY_CLOSE_TIMEOUT]
|
||||
@ -82,7 +81,7 @@ By default, GoTTY starts a web server at port 8080. Open the URL on your web bro
|
||||
--version, -v print the version (default: false)
|
||||
```
|
||||
### Config File
|
||||
You can customize default options and your terminal (hterm) by providing a config file to the `gotty` command. GoTTY loads a profile file at `~/.gotty` by default when it exists.
|
||||
You can customize default options and your terminal by providing a config file to the `gotty` command. GoTTY loads a profile file at `~/.gotty` by default when it exists.
|
||||
|
||||
```
|
||||
// Listen at port 9000 by default
|
||||
@ -91,12 +90,6 @@ port = "9000"
|
||||
// Enable TSL/SSL by default
|
||||
enable_tls = true
|
||||
|
||||
// hterm preferences
|
||||
// Smaller font and a little bit bluer background color
|
||||
preferences {
|
||||
font_size = 5
|
||||
background_color = "rgb(16, 16, 32)"
|
||||
}
|
||||
```
|
||||
|
||||
See the [`.gotty`](https://github.com/sorenisanerd/gotty/blob/master/.gotty) file in this repository for the list of configuration options.
|
||||
@ -164,7 +157,7 @@ To build the frontend part (JS files and other static files), you need `npm`.
|
||||
|
||||
## Architecture
|
||||
|
||||
GoTTY uses [xterm.js](https://xtermjs.org/) and [hterm](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-hterm) to run a JavaScript based terminal on web browsers. GoTTY itself provides a websocket server that simply relays output from the TTY to clients and receives input from clients and forwards it to the TTY. This hterm + websocket idea is inspired by [Wetty](https://github.com/krishnasrinivas/wetty).
|
||||
GoTTY uses [xterm.js](https://xtermjs.org/) to run a JavaScript based terminal on web browsers. GoTTY itself provides a websocket server that simply relays output from the TTY to clients and receives input from clients and forwards it to the TTY. This xterm + websocket idea is inspired by [Wetty](https://github.com/krishnasrinivas/wetty).
|
||||
|
||||
## Alternatives
|
||||
|
||||
@ -198,7 +191,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center"><a href="https://yudai.arielworks.com/"><img src="https://avatars.githubusercontent.com/u/33192?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Iwasaki Yudai</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=yudai" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://linux2go.dk/"><img src="https://avatars.githubusercontent.com/u/160090?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Soren L. Hansen</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=sorenisanerd" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://linux2go.dk/"><img src="https://avatars.githubusercontent.com/u/160090?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Soren L. Hansen</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Asorenisanerd" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/uovobw"><img src="https://avatars.githubusercontent.com/u/1194751?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrea Lusuardi</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=uovobw" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/moul"><img src="https://avatars.githubusercontent.com/u/94029?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Manfred Touron</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=moul" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/svanellewee"><img src="https://avatars.githubusercontent.com/u/1567439?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stephan</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=svanellewee" title="Code">💻</a></td>
|
||||
@ -239,10 +232,37 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center"><a href="https://www.shingt.com/"><img src="https://avatars.githubusercontent.com/u/1391330?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shinichi Goto</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=shingt" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://twitter.com/_yogeshsingh"><img src="https://avatars.githubusercontent.com/u/8512357?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ygit</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=ygit" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://forum.cachem.fr/viewforum.php?f=21"><img src="https://avatars.githubusercontent.com/u/3392684?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stéphane</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Anephaste" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://rusnak.io/"><img src="https://avatars.githubusercontent.com/u/42201?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pavol Rusnak</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=prusnak" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://rusnak.io/"><img src="https://avatars.githubusercontent.com/u/42201?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pavol Rusnak</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Aprusnak" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/devanlai"><img src="https://avatars.githubusercontent.com/u/1348448?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Devan Lai</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=devanlai" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jkandasa"><img src="https://avatars.githubusercontent.com/u/1004403?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jeeva Kandasamy</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=jkandasa" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://twitch.tv/iamhardliner"><img src="https://avatars.githubusercontent.com/u/2937272?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Steve Biedermann</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/commits?author=hardliner66" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/xgdgsc"><img src="https://avatars.githubusercontent.com/u/1189869?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xgdgsc</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Axgdgsc" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/flechaig"><img src="https://avatars.githubusercontent.com/u/10887132?v=4?s=100" width="100px;" alt=""/><br /><sub><b>flechaig</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Aflechaig" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/Fan-SJ"><img src="https://avatars.githubusercontent.com/u/49977708?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fan-SJ</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3AFan-SJ" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/dmartin"><img src="https://avatars.githubusercontent.com/u/1657652?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dustin Martin</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Admartin" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://ahmet.dev/"><img src="https://avatars.githubusercontent.com/u/159209?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ahmet Alp Balkan</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Aahmetb" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/CoconutMacaroon"><img src="https://avatars.githubusercontent.com/u/45187468?v=4?s=100" width="100px;" alt=""/><br /><sub><b>CoconutMacaroon</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3ACoconutMacaroon" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.dannyben.com/"><img src="https://avatars.githubusercontent.com/u/2405099?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Danny Ben Shitrit</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3ADannyBen" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/George-NG"><img src="https://avatars.githubusercontent.com/u/28577165?v=4?s=100" width="100px;" alt=""/><br /><sub><b>George-NG</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3AGeorge-NG" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/ghthor"><img src="https://avatars.githubusercontent.com/u/160298?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Will Owens</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Aghthor" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://jpillora.com/"><img src="https://avatars.githubusercontent.com/u/633843?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jaime Pillora</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Ajpillora" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/kaisawind"><img src="https://avatars.githubusercontent.com/u/4010613?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kaisawind</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Akaisawind" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/linyinli"><img src="https://avatars.githubusercontent.com/u/42955482?v=4?s=100" width="100px;" alt=""/><br /><sub><b>linyinli</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Alinyinli" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/LucaMarconato"><img src="https://avatars.githubusercontent.com/u/2664412?v=4?s=100" width="100px;" alt=""/><br /><sub><b>LucaMarconato</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3ALucaMarconato" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://audiobox.fm/"><img src="https://avatars.githubusercontent.com/u/12844?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kain</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Amasterkain" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="http://duro.me/"><img src="https://avatars.githubusercontent.com/u/1498061?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andi Andreas</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3ANexuist" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/qigj"><img src="https://avatars.githubusercontent.com/u/56585735?v=4?s=100" width="100px;" alt=""/><br /><sub><b>qigj</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Aqigj" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/shuaiyy"><img src="https://avatars.githubusercontent.com/u/19821321?v=4?s=100" width="100px;" alt=""/><br /><sub><b>shuaiyy</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Ashuaiyy" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/v20z"><img src="https://avatars.githubusercontent.com/u/2884824?v=4?s=100" width="100px;" alt=""/><br /><sub><b>v20z</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3Av20z" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Yann-Qiu"><img src="https://avatars.githubusercontent.com/u/56961747?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yanfeng Qiu</b></sub></a><br /><a href="https://github.com/sorenisanerd/gotty/issues?q=author%3AYann-Qiu" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
13
bindata/static/css/index.css
Normal file
13
bindata/static/css/index.css
Normal file
@ -0,0 +1,13 @@
|
||||
html, body, #terminal {
|
||||
background: black;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0%;
|
||||
margin: 0%;
|
||||
}
|
||||
|
||||
.progress .progress-bar {
|
||||
transition: unset;
|
||||
transition-duration: 0.1s;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
190
bindata/static/css/xterm.css
Normal file
190
bindata/static/css/xterm.css
Normal file
@ -0,0 +1,190 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
cursor: text;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -5;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer,
|
||||
.xterm .xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.xterm.column-select.focus {
|
||||
/* Column selection mode */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility,
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.xterm-dim {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.xterm-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.xterm-strikethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.xterm-screen .xterm-decoration-container .xterm-decoration {
|
||||
z-index: 6;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.xterm-decoration-overview-ruler {
|
||||
z-index: 7;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.xterm-decoration-top {
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
}
|
19
bindata/static/css/xterm_customize.css
Normal file
19
bindata/static/css/xterm_customize.css
Normal file
@ -0,0 +1,19 @@
|
||||
.terminal {
|
||||
font-family: "DejaVu Sans Mono", "Everson Mono", FreeMono, Menlo, Terminal, monospace, "Apple Symbols";
|
||||
}
|
||||
|
||||
.xterm-overlay {
|
||||
font-family: "DejaVu Sans Mono", "Everson Mono", FreeMono, Menlo, Terminal, monospace, "Apple Symbols";
|
||||
border-radius: 15px;
|
||||
font-size: xx-large;
|
||||
color: black;
|
||||
background: white;
|
||||
opacity: 0.75;
|
||||
padding: 0.2em 0.5em 0.2em 0.5em;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
user-select: none;
|
||||
transition: opacity 180ms ease-in;
|
||||
}
|
BIN
bindata/static/favicon.ico
Normal file
BIN
bindata/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
66
bindata/static/icon.svg
Normal file
66
bindata/static/icon.svg
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 708.4149 708.41411"
|
||||
height="708.41412"
|
||||
width="708.41492"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
version="1.1"><metadata
|
||||
id="metadata8"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs6"><clipPath
|
||||
id="clipPath18"
|
||||
clipPathUnits="userSpaceOnUse"><path
|
||||
id="path16"
|
||||
d="M 0,2000 H 2000 V 0 H 0 Z" /></clipPath></defs><g
|
||||
transform="matrix(1.3333333,0,0,-1.3333333,-979.12558,1687.5405)"
|
||||
id="g10"><g
|
||||
id="g12"><g
|
||||
clip-path="url(#clipPath18)"
|
||||
id="g14"><g
|
||||
transform="translate(772.1414,1265.6554)"
|
||||
id="g20"><path
|
||||
id="path22"
|
||||
style="fill:#de3c28;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -20.875,0 -37.797,-16.922 -37.797,-37.797 v -126.348 -25.917 -212.342 L 345.882,0 Z" /></g><g
|
||||
transform="translate(956.8504,734.3448)"
|
||||
id="g24"><path
|
||||
id="path26"
|
||||
style="fill:#af1419;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 h 260.209 c 26.839,0 48.596,21.757 48.596,48.596 v 275.281 z" /></g><g
|
||||
transform="translate(1265.6552,1075.5929)"
|
||||
id="g28"><path
|
||||
id="path30"
|
||||
style="fill:#db0918;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v 25.918 126.348 c 0,20.875 -16.922,37.796 -37.796,37.796 h -109.836 l -383.679,-402.404 v -80.31 c 0,-26.839 21.757,-48.596 48.596,-48.596 h 173.91 L 0,-17.371 Z" /></g><g
|
||||
transform="translate(1169.2147,909.6954)"
|
||||
id="g32"><path
|
||||
id="path34"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 h -138.227 c -9.129,0 -16.528,7.4 -16.528,16.529 0,9.128 7.399,16.529 16.528,16.529 H 0 c 9.129,0 16.528,-7.401 16.528,-16.529 C 16.528,7.4 9.129,0 0,0" /></g><g
|
||||
transform="translate(898.8318,1033.5314)"
|
||||
id="g36"><path
|
||||
id="path38"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c 2.86,-0.72 5.65,-1.45 8.37,-2.2 -0.63,-8.56 -7.76,-15.3 -16.479,-15.3 -9.13,0 -16.531,7.4 -16.531,16.53 v 8.54 c 1.861,-0.83 3.72,-1.549 5.601,-2.15 C -15.199,4.18 -8.85,2.37 0,0" /></g><g
|
||||
transform="translate(907.2527,1150.7814)"
|
||||
id="g40"><path
|
||||
id="path42"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v -65.81 c -4.45,1.59 -9.98,2.38 -16.601,2.38 -6.21,0 -11.7,-0.88 -16.46,-2.64 V 0 c 0,9.13 7.401,16.53 16.531,16.53 C -7.4,16.53 0,9.13 0,0" /></g><g
|
||||
transform="translate(874.1922,868.8272)"
|
||||
id="g44"><path
|
||||
id="path46"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 v 65.811 c 4.45,-1.59 9.98,-2.38 16.601,-2.38 6.21,0 11.699,0.88 16.46,2.639 V 0 C 33.061,-9.13 25.66,-16.529 16.53,-16.529 7.4,-16.529 0,-9.13 0,0" /></g><g
|
||||
transform="translate(966.6326,994.1915)"
|
||||
id="g48"><path
|
||||
id="path50"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 0,0 c -3.53,7.28 -8.45,13.3 -14.75,18.06 -6.301,4.76 -13.95,8.8 -22.94,12.14 -6.661,2.47 -13.911,4.78 -21.741,6.94 -2.719,0.75 -5.509,1.48 -8.37,2.2 -8.849,2.37 -15.199,4.18 -19.039,5.42 -1.881,0.6 -3.74,1.32 -5.6,2.15 -1.951,0.87 -3.88,1.87 -5.8,2.99 -3.76,2.19 -6.71,4.81 -8.861,7.85 -2.139,3.05 -3.219,6.67 -3.219,10.86 0,6.75 3.16,12.54 9.46,17.34 2.49,1.9 5.299,3.43 8.42,4.57 4.759,1.76 10.25,2.64 16.46,2.64 6.62,0 12.15,-0.79 16.6,-2.38 3.01,-1.05 5.52,-2.48 7.54,-4.26 5.01,-4.42 9.3,-10.59 12.88,-18.49 2.77,-5.52 5.34,-9.49 7.71,-11.92 2.37,-2.43 5.84,-3.64 10.399,-3.64 5.011,0 9.191,2.02 12.54,6.07 3.351,4.04 5.031,8.59 5.031,13.63 0,5.52 -1.34,11.19 -4.021,17 -2.689,5.8 -6.939,11.35 -12.75,16.63 -5.809,5.28 -13.119,9.52 -21.929,12.71 -5.23,1.89 -11.031,3.22 -17.4,3.99 -4.37,0.53 -9.011,0.79 -13.921,0.79 -6.779,0 -13.159,-0.48 -19.139,-1.45 -7.361,-1.19 -14.121,-3.11 -20.29,-5.76 -11.18,-4.81 -19.72,-11.69 -25.621,-20.63 -5.899,-8.95 -8.849,-19.18 -8.849,-30.7 0,-12.09 2.79,-22.2 8.38,-30.34 5.59,-8.14 13.15,-14.56 22.67,-19.28 9.52,-4.71 21.349,-8.83 35.48,-12.35 10.55,-2.57 18.98,-4.99 25.279,-7.28 6.301,-2.28 11.441,-5.59 15.42,-9.92 3.981,-4.33 5.971,-9.97 5.971,-16.92 0,-8.76 -3.69,-16.06 -11.061,-21.92 -7.379,-5.85 -16.969,-8.78 -28.769,-8.78 -8.59,0 -15.521,1.45 -20.79,4.36 -5.28,2.9 -9.37,6.59 -12.28,11.06 -2.901,4.47 -5.611,10.04 -8.111,16.71 -2.059,5.61 -4.54,9.85 -7.449,12.7 -2.9,2.86 -6.46,4.29 -10.66,4.29 -5.181,0 -9.45,-1.84 -12.811,-5.5 -3.349,-3.66 -5.029,-8.07 -5.029,-13.21 0,-8.85 2.8,-17.96 8.39,-27.34 5.58,-9.38 12.849,-16.87 21.79,-22.49 12.61,-7.8 28.61,-11.7 48.019,-11.7 16.181,0 30.181,2.85 41.981,8.56 11.809,5.71 20.769,13.61 26.9,23.7 6.119,10.09 9.18,21.47 9.18,34.129 C 5.3,-16.21 3.54,-7.28 0,0" /></g></g></g></g></svg>
|
After Width: | Height: | Size: 5.3 KiB |
BIN
bindata/static/icon_192.png
Normal file
BIN
bindata/static/icon_192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
22
bindata/static/index.html
Normal file
22
bindata/static/index.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>{{ .title }}</title>
|
||||
<link rel="manifest" href="manifest.json" crossorigin="use-credentials">
|
||||
<link rel="icon" href="favicon.ico">
|
||||
<link rel="icon" href="icon.svg" type="image/svg+xml">
|
||||
<link rel="stylesheet" href="./css/index.css" />
|
||||
<link rel="stylesheet" href="./css/xterm.css" />
|
||||
<link rel="stylesheet" href="./css/xterm_customize.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="terminal"></div>
|
||||
<script src="./auth_token.js"></script>
|
||||
<script src="./config.js"></script>
|
||||
<script src="./js/gotty.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
3
bindata/static/js/gotty.js
Normal file
3
bindata/static/js/gotty.js
Normal file
File diff suppressed because one or more lines are too long
7
bindata/static/js/gotty.js.LICENSE.txt
Normal file
7
bindata/static/js/gotty.js.LICENSE.txt
Normal file
@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Bootstrap v5.2.0 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*! crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
1
bindata/static/js/gotty.js.map
Normal file
1
bindata/static/js/gotty.js.map
Normal file
File diff suppressed because one or more lines are too long
650
bindata/static/js/gotty.licenses.txt
Normal file
650
bindata/static/js/gotty.licenses.txt
Normal file
@ -0,0 +1,650 @@
|
||||
@popperjs/core
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Federico Zivolo
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
bootstrap
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2022 Twitter, Inc.
|
||||
Copyright (c) 2011-2022 The Bootstrap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
crc-32
|
||||
Apache-2.0
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (C) 2014-present SheetJS LLC
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
css-loader
|
||||
MIT
|
||||
Copyright JS Foundation and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
jsx-runtime
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-present Jason Miller
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
preact
|
||||
MIT
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-present Jason Miller
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
style-loader
|
||||
MIT
|
||||
Copyright JS Foundation and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
xterm
|
||||
MIT
|
||||
Copyright (c) 2017-2019, The xterm.js authors (https://github.com/xtermjs/xterm.js)
|
||||
Copyright (c) 2014-2016, SourceLair Private Company (https://www.sourcelair.com)
|
||||
Copyright (c) 2012-2013, Christopher Jeffrey (https://github.com/chjj/)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
xterm-addon-fit
|
||||
MIT
|
||||
Copyright (c) 2019, The xterm.js authors (https://github.com/xtermjs/xterm.js)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
xterm-addon-web-links
|
||||
MIT
|
||||
Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
xterm-addon-webgl
|
||||
MIT
|
||||
Copyright (c) 2018, The xterm.js authors (https://github.com/xtermjs/xterm.js)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
zmodem.js
|
||||
Apache-2.0
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
15
bindata/static/manifest.json
Normal file
15
bindata/static/manifest.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"short_name": "{{ .title }}",
|
||||
"name": "{{ .title }}",
|
||||
"start_url": "./",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./icon_192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
}
|
||||
],
|
||||
"display": "minimal-ui",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#000000"
|
||||
}
|
4431
js/package-lock.json
generated
4431
js/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,33 @@
|
||||
{
|
||||
"name": "gotty",
|
||||
"version": "2.0.0",
|
||||
"version": "1.4.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/bootstrap": "^5.1.9",
|
||||
"compression-webpack-plugin": "^9.2.0",
|
||||
"license-loader": "^0.5.0",
|
||||
"license-webpack-plugin": "^4.0.2",
|
||||
"purgecss": "^4.1.3",
|
||||
"sass": "^1.54.5",
|
||||
"sass-loader": "^12.6.0",
|
||||
"terser-webpack-plugin": "^5.3.1",
|
||||
"ts-loader": "^8.3.0",
|
||||
"typescript": "^4.3.2",
|
||||
"webpack": "^5.38.1",
|
||||
"webpack": "^5.72.0",
|
||||
"webpack-cli": "^4.7.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.11.5",
|
||||
"bootstrap": "^5.1.3",
|
||||
"css-loader": "^5.2.6",
|
||||
"libapps": "github:yudai/libapps#release-hterm-1.70",
|
||||
"debounce": "^1.2.1",
|
||||
"preact": "^10.7.1",
|
||||
"react-bootstrap": "^2.2.3",
|
||||
"style-loader": "^2.0.0",
|
||||
"xterm": "^4.12.0",
|
||||
"xterm-addon-fit": "^0.5.0",
|
||||
"xterm-addon-web-links": "^0.4.0",
|
||||
"xterm-addon-webgl": "^0.10.0"
|
||||
"xterm-addon-webgl": "^0.10.0",
|
||||
"zmodem.js": "^0.1.10"
|
||||
}
|
||||
}
|
||||
|
63
js/src/MyModal.tsx
Normal file
63
js/src/MyModal.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import { createRef, Component, ComponentChildren } from "preact";
|
||||
import { Modal } from "bootstrap";
|
||||
import './bootstrap.scss';
|
||||
|
||||
interface ModalProps {
|
||||
children: ComponentChildren;
|
||||
buttons?: ComponentChildren;
|
||||
title: string;
|
||||
dismissHandler?: (hideModal?: () => void) => void;
|
||||
}
|
||||
|
||||
export class MyModal extends Component<ModalProps, {}> {
|
||||
ref = createRef<HTMLDivElement>();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
Modal.getOrCreateInstance(this.ref.current!).show();
|
||||
this.ref.current?.addEventListener('hide.bs.modal', () => { this.props.dismissHandler && this.props.dismissHandler(); });
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.hide()
|
||||
}
|
||||
|
||||
hide(): void {
|
||||
Modal.getOrCreateInstance(this.ref.current!).hide();
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div class="modal fade" ref={this.ref} tabIndex={-1} aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{this.props.title}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{this.props.children}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{this.props.buttons}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
interface ButtonProps {
|
||||
priority: "primary" | "secondary" | "danger"
|
||||
clickHandler?: () => void
|
||||
children: ComponentChildren
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function Button(props:ButtonProps) {
|
||||
let classes: string = "btn btn-" + props.priority
|
||||
|
||||
return <button type="button" disabled={props.disabled} class={classes} onClick={ () => { props.clickHandler ? props.clickHandler() : null; }}>{ props.children}</button>
|
||||
}
|
25
js/src/bootstrap.scss
vendored
Normal file
25
js/src/bootstrap.scss
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
@import "mixins/banner";
|
||||
@include bsBanner("");
|
||||
|
||||
|
||||
// scss-docs-start import-stack
|
||||
// Configuration
|
||||
@import "functions";
|
||||
@import "variables";
|
||||
@import "maps";
|
||||
@import "mixins";
|
||||
@import "utilities";
|
||||
|
||||
// Layout & components
|
||||
@import "root";
|
||||
@import "reboot";
|
||||
@import "type";
|
||||
@import "images";
|
||||
@import "containers";
|
||||
@import "grid";
|
||||
@import "buttons";
|
||||
@import "transitions";
|
||||
@import "progress";
|
||||
@import "close";
|
||||
@import "modal";
|
||||
@import "spinners";
|
@ -1,94 +0,0 @@
|
||||
import * as bare from "libapps";
|
||||
|
||||
export class Hterm {
|
||||
elem: HTMLElement;
|
||||
|
||||
term: bare.hterm.Terminal;
|
||||
io: bare.hterm.IO;
|
||||
|
||||
columns: number;
|
||||
rows: number;
|
||||
|
||||
// to "show" the current message when removeMessage() is called
|
||||
message: string;
|
||||
|
||||
constructor(elem: HTMLElement) {
|
||||
this.elem = elem;
|
||||
bare.hterm.defaultStorage = new bare.lib.Storage.Memory();
|
||||
this.term = new bare.hterm.Terminal();
|
||||
this.term.getPrefs().set("send-encoding", "raw");
|
||||
this.term.decorate(this.elem);
|
||||
|
||||
this.io = this.term.io.push();
|
||||
this.term.installKeyboard();
|
||||
};
|
||||
|
||||
info(): { columns: number, rows: number } {
|
||||
return { columns: this.columns, rows: this.rows };
|
||||
};
|
||||
|
||||
output(data: string) {
|
||||
if (this.term.io != null) {
|
||||
this.term.io.writeUTF8(data);
|
||||
}
|
||||
};
|
||||
|
||||
showMessage(message: string, timeout: number) {
|
||||
this.message = message;
|
||||
if (timeout > 0) {
|
||||
this.term.io.showOverlay(message, timeout);
|
||||
} else {
|
||||
this.term.io.showOverlay(message, null);
|
||||
}
|
||||
};
|
||||
|
||||
removeMessage(): void {
|
||||
// there is no hideOverlay(), so show the same message with 0 sec
|
||||
this.term.io.showOverlay(this.message, 0);
|
||||
}
|
||||
|
||||
setWindowTitle(title: string) {
|
||||
this.term.setWindowTitle(title);
|
||||
};
|
||||
|
||||
setPreferences(value: object) {
|
||||
Object.keys(value).forEach((key) => {
|
||||
if (key != "EnableWebGL") {
|
||||
this.term.getPrefs().set(key, value[key]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onInput(callback: (input: string) => void) {
|
||||
this.io.onVTKeystroke = (data) => {
|
||||
callback(data);
|
||||
};
|
||||
this.io.sendString = (data) => {
|
||||
callback(data);
|
||||
};
|
||||
};
|
||||
|
||||
onResize(callback: (colmuns: number, rows: number) => void) {
|
||||
this.io.onTerminalResize = (columns: number, rows: number) => {
|
||||
this.columns = columns;
|
||||
this.rows = rows;
|
||||
callback(columns, rows);
|
||||
};
|
||||
};
|
||||
|
||||
deactivate(): void {
|
||||
this.io.onVTKeystroke = function () { };
|
||||
this.io.sendString = function () { };
|
||||
this.io.onTerminalResize = function () { };
|
||||
this.term.uninstallKeyboard();
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.removeMessage();
|
||||
this.term.installKeyboard();
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this.term.uninstallKeyboard();
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { Hterm } from "./hterm";
|
||||
import { Xterm } from "./xterm";
|
||||
import { OurXterm } from "./xterm";
|
||||
import { Terminal, WebTTY, protocols } from "./webtty";
|
||||
import { ConnectionFactory } from "./websocket";
|
||||
|
||||
@ -11,11 +10,8 @@ const elem = document.getElementById("terminal")
|
||||
|
||||
if (elem !== null) {
|
||||
var term: Terminal;
|
||||
if (gotty_term == "hterm") {
|
||||
term = new Hterm(elem);
|
||||
} else {
|
||||
term = new Xterm(elem);
|
||||
}
|
||||
term = new OurXterm(elem);
|
||||
|
||||
const httpsEnabled = window.location.protocol == "https:";
|
||||
const url = (httpsEnabled ? 'wss://' : 'ws://') + window.location.host + window.location.pathname + 'ws';
|
||||
const args = window.location.search;
|
||||
@ -23,6 +19,9 @@ if (elem !== null) {
|
||||
const wt = new WebTTY(term, factory, args, gotty_auth_token);
|
||||
const closer = wt.open();
|
||||
|
||||
// According to https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event
|
||||
// this event is unreliable and in some cases (Firefox is mentioned), having an
|
||||
// "unload" event handler can have unwanted side effects. Consider commenting it out.
|
||||
window.addEventListener("unload", () => {
|
||||
closer();
|
||||
term.close();
|
||||
|
@ -15,7 +15,6 @@ export class ConnectionFactory {
|
||||
export class Connection {
|
||||
bare: WebSocket;
|
||||
|
||||
|
||||
constructor(url: string, protocols: string[]) {
|
||||
this.bare = new WebSocket(url, protocols);
|
||||
}
|
||||
|
162
js/src/webtty.ts
162
js/src/webtty.ts
@ -1,162 +0,0 @@
|
||||
export const protocols = ["webtty"];
|
||||
|
||||
export const msgInputUnknown = '0';
|
||||
export const msgInput = '1';
|
||||
export const msgPing = '2';
|
||||
export const msgResizeTerminal = '3';
|
||||
|
||||
export const msgUnknownOutput = '0';
|
||||
export const msgOutput = '1';
|
||||
export const msgPong = '2';
|
||||
export const msgSetWindowTitle = '3';
|
||||
export const msgSetPreferences = '4';
|
||||
export const msgSetReconnect = '5';
|
||||
export const msgSetBufferSize = '6';
|
||||
|
||||
|
||||
export interface Terminal {
|
||||
info(): { columns: number, rows: number };
|
||||
output(data: string): void;
|
||||
showMessage(message: string, timeout: number): void;
|
||||
removeMessage(): void;
|
||||
setWindowTitle(title: string): void;
|
||||
setPreferences(value: object): void;
|
||||
onInput(callback: (input: string) => void): void;
|
||||
onResize(callback: (colmuns: number, rows: number) => void): void;
|
||||
reset(): void;
|
||||
deactivate(): void;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
export interface Connection {
|
||||
open(): void;
|
||||
close(): void;
|
||||
send(data: string): void;
|
||||
isOpen(): boolean;
|
||||
onOpen(callback: () => void): void;
|
||||
onReceive(callback: (data: string) => void): void;
|
||||
onClose(callback: () => void): void;
|
||||
}
|
||||
|
||||
export interface ConnectionFactory {
|
||||
create(): Connection;
|
||||
}
|
||||
|
||||
|
||||
export class WebTTY {
|
||||
term: Terminal;
|
||||
connectionFactory: ConnectionFactory;
|
||||
args: string;
|
||||
authToken: string;
|
||||
reconnect: number;
|
||||
bufSize: number;
|
||||
|
||||
constructor(term: Terminal, connectionFactory: ConnectionFactory, args: string, authToken: string) {
|
||||
this.term = term;
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.args = args;
|
||||
this.authToken = authToken;
|
||||
this.reconnect = -1;
|
||||
this.bufSize = 1024;
|
||||
};
|
||||
|
||||
open() {
|
||||
let connection = this.connectionFactory.create();
|
||||
let pingTimer: NodeJS.Timeout;
|
||||
let reconnectTimeout: NodeJS.Timeout;
|
||||
|
||||
const setup = () => {
|
||||
connection.onOpen(() => {
|
||||
const termInfo = this.term.info();
|
||||
|
||||
connection.send(JSON.stringify(
|
||||
{
|
||||
Arguments: this.args,
|
||||
AuthToken: this.authToken,
|
||||
}
|
||||
));
|
||||
|
||||
|
||||
const resizeHandler = (colmuns: number, rows: number) => {
|
||||
connection.send(
|
||||
msgResizeTerminal + JSON.stringify(
|
||||
{
|
||||
columns: colmuns,
|
||||
rows: rows
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
this.term.onResize(resizeHandler);
|
||||
resizeHandler(termInfo.columns, termInfo.rows);
|
||||
|
||||
this.term.onInput(
|
||||
(input: string) => {
|
||||
// Leave room for message type id
|
||||
let effectiveBufferSize = this.bufSize - 1;
|
||||
|
||||
// Split input into buffer sized chunks
|
||||
for (let i = 0; i < Math.ceil(input.length/effectiveBufferSize); i++) {
|
||||
let inputChunk = input.substring(i*effectiveBufferSize, Math.min((i+1)*effectiveBufferSize, input.length))
|
||||
connection.send(msgInput + inputChunk);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
pingTimer = setInterval(() => {
|
||||
connection.send(msgPing)
|
||||
}, 30 * 1000);
|
||||
|
||||
});
|
||||
|
||||
connection.onReceive((data) => {
|
||||
const payload = data.slice(1);
|
||||
switch (data[0]) {
|
||||
case msgOutput:
|
||||
this.term.output(atob(payload));
|
||||
break;
|
||||
case msgPong:
|
||||
break;
|
||||
case msgSetWindowTitle:
|
||||
this.term.setWindowTitle(payload);
|
||||
break;
|
||||
case msgSetPreferences:
|
||||
const preferences = JSON.parse(payload);
|
||||
this.term.setPreferences(preferences);
|
||||
break;
|
||||
case msgSetReconnect:
|
||||
const autoReconnect = JSON.parse(payload);
|
||||
console.log("Enabling reconnect: " + autoReconnect + " seconds")
|
||||
this.reconnect = autoReconnect;
|
||||
break;
|
||||
case msgSetBufferSize:
|
||||
const bufSize = JSON.parse(payload);
|
||||
this.bufSize = bufSize;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
connection.onClose(() => {
|
||||
clearInterval(pingTimer);
|
||||
this.term.deactivate();
|
||||
this.term.showMessage("Connection Closed", 0);
|
||||
if (this.reconnect > 0) {
|
||||
reconnectTimeout = setTimeout(() => {
|
||||
connection = this.connectionFactory.create();
|
||||
this.term.reset();
|
||||
setup();
|
||||
}, this.reconnect * 1000);
|
||||
}
|
||||
});
|
||||
|
||||
connection.open();
|
||||
}
|
||||
|
||||
setup();
|
||||
return () => {
|
||||
clearTimeout(reconnectTimeout);
|
||||
connection.close();
|
||||
}
|
||||
};
|
||||
};
|
270
js/src/webtty.tsx
Normal file
270
js/src/webtty.tsx
Normal file
@ -0,0 +1,270 @@
|
||||
export const protocols = ["webtty"];
|
||||
|
||||
export const msgInputUnknown = '0';
|
||||
export const msgInput = '1';
|
||||
export const msgPing = '2';
|
||||
export const msgResizeTerminal = '3';
|
||||
export const msgSetEncoding = '4';
|
||||
|
||||
export const msgUnknownOutput = '0';
|
||||
export const msgOutput = '1';
|
||||
export const msgPong = '2';
|
||||
export const msgSetWindowTitle = '3';
|
||||
export const msgSetPreferences = '4';
|
||||
export const msgSetReconnect = '5';
|
||||
export const msgSetBufferSize = '6';
|
||||
|
||||
|
||||
export interface Terminal {
|
||||
/*
|
||||
* Get dimensions of the terminal
|
||||
*/
|
||||
info(): { columns: number, rows: number };
|
||||
|
||||
/*
|
||||
* Process output from the server side
|
||||
*/
|
||||
output(data: Uint8Array): void;
|
||||
|
||||
/*
|
||||
* Display a message overlay on the terminal
|
||||
*/
|
||||
showMessage(message: string, timeout: number): void;
|
||||
|
||||
// Don't think we need this anymore
|
||||
// getMessage(): HTMLElement;
|
||||
|
||||
/*
|
||||
* Remove message shown by shoMessage. You only need to call
|
||||
* this if you want to dismiss it sooner than the timeout.
|
||||
*/
|
||||
removeMessage(): void;
|
||||
|
||||
|
||||
/*
|
||||
* Set window title
|
||||
*/
|
||||
setWindowTitle(title: string): void;
|
||||
|
||||
/*
|
||||
* Set preferences. TODO: Add typings
|
||||
*/
|
||||
setPreferences(value: object): void;
|
||||
|
||||
|
||||
/*
|
||||
* Sets an input (e.g. user types something) handler
|
||||
*/
|
||||
onInput(callback: (input: string) => void): void;
|
||||
|
||||
/*
|
||||
* Sets a resize handler
|
||||
*/
|
||||
onResize(callback: (colmuns: number, rows: number) => void): void;
|
||||
|
||||
reset(): void;
|
||||
deactivate(): void;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
export interface Connection {
|
||||
open(): void;
|
||||
close(): void;
|
||||
|
||||
/*
|
||||
* This takes fucking strings??
|
||||
*/
|
||||
send(s: string): void;
|
||||
|
||||
isOpen(): boolean;
|
||||
onOpen(callback: () => void): void;
|
||||
onReceive(callback: (data: string) => void): void;
|
||||
onClose(callback: () => void): void;
|
||||
}
|
||||
|
||||
export interface ConnectionFactory {
|
||||
create(): Connection;
|
||||
}
|
||||
|
||||
export class WebTTY {
|
||||
/*
|
||||
* A terminal instance that implements the Terminal interface.
|
||||
* This made a lot of sense when we had both HTerm and xterm, but
|
||||
* now I wonder if the abstraction makes sense. Keeping it for now,
|
||||
* though.
|
||||
*/
|
||||
term: Terminal;
|
||||
|
||||
/*
|
||||
* ConnectionFactory and connection instance. We pass the factory
|
||||
* in instead of just a connection so that we can reconnect.
|
||||
*/
|
||||
connectionFactory: ConnectionFactory;
|
||||
connection: Connection;
|
||||
|
||||
/*
|
||||
* Arguments passed in by the user. We forward them to the backend
|
||||
* where they are appended to the command line.
|
||||
*/
|
||||
args: string;
|
||||
|
||||
/*
|
||||
* An authentication token. The client gets this from `/auth_token.js`.
|
||||
*/
|
||||
authToken: string;
|
||||
|
||||
/*
|
||||
* If connection is dropped, reconnect after `reconnect` seconds.
|
||||
* -1 means do not reconnect.
|
||||
*/
|
||||
reconnect: number;
|
||||
|
||||
/*
|
||||
* The server's buffer size. If a single message exceeds this size, it will
|
||||
* be truncated on the server, so we track it here so that we can split messages
|
||||
* into chunks small enough that we don't hurt the server's feelings.
|
||||
*/
|
||||
bufSize: number;
|
||||
|
||||
constructor(term: Terminal, connectionFactory: ConnectionFactory, args: string, authToken: string) {
|
||||
this.term = term;
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.args = args;
|
||||
this.authToken = authToken;
|
||||
this.reconnect = -1;
|
||||
this.bufSize = 1024;
|
||||
};
|
||||
|
||||
open() {
|
||||
let connection = this.connectionFactory.create();
|
||||
let pingTimer: NodeJS.Timeout;
|
||||
let reconnectTimeout: NodeJS.Timeout;
|
||||
this.connection = connection;
|
||||
|
||||
const setup = () => {
|
||||
connection.onOpen(() => {
|
||||
const termInfo = this.term.info();
|
||||
|
||||
this.initializeConnection(this.args, this.authToken);
|
||||
|
||||
this.term.onResize((columns: number, rows: number) => {
|
||||
this.sendResizeTerminal(columns, rows);
|
||||
});
|
||||
|
||||
this.sendResizeTerminal(termInfo.columns, termInfo.rows);
|
||||
|
||||
this.sendSetEncoding("base64");
|
||||
|
||||
this.term.onInput(
|
||||
(input: string | Uint8Array) => {
|
||||
this.sendInput(input);
|
||||
}
|
||||
);
|
||||
|
||||
pingTimer = setInterval(() => {
|
||||
this.sendPing()
|
||||
}, 30 * 1000);
|
||||
});
|
||||
|
||||
connection.onReceive((data) => {
|
||||
const payload = data.slice(1);
|
||||
switch (data[0]) {
|
||||
case msgOutput:
|
||||
this.term.output(Uint8Array.from(atob(payload), c => c.charCodeAt(0)));
|
||||
break;
|
||||
case msgPong:
|
||||
break;
|
||||
case msgSetWindowTitle:
|
||||
this.term.setWindowTitle(payload);
|
||||
break;
|
||||
case msgSetPreferences:
|
||||
const preferences = JSON.parse(payload);
|
||||
this.term.setPreferences(preferences);
|
||||
break;
|
||||
case msgSetReconnect:
|
||||
const autoReconnect = JSON.parse(payload);
|
||||
console.log("Enabling reconnect: " + autoReconnect + " seconds")
|
||||
this.reconnect = autoReconnect;
|
||||
break;
|
||||
case msgSetBufferSize:
|
||||
const bufSize = JSON.parse(payload);
|
||||
this.bufSize = bufSize;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
connection.onClose(() => {
|
||||
clearInterval(pingTimer);
|
||||
this.term.deactivate();
|
||||
this.term.showMessage("Connection Closed", 0);
|
||||
if (this.reconnect > 0) {
|
||||
reconnectTimeout = setTimeout(() => {
|
||||
connection = this.connectionFactory.create();
|
||||
this.term.reset();
|
||||
setup();
|
||||
}, this.reconnect * 1000);
|
||||
}
|
||||
});
|
||||
|
||||
connection.open();
|
||||
}
|
||||
|
||||
setup();
|
||||
return () => {
|
||||
clearTimeout(reconnectTimeout);
|
||||
connection.close();
|
||||
}
|
||||
};
|
||||
|
||||
private initializeConnection(args, authToken) {
|
||||
this.connection.send(JSON.stringify(
|
||||
{
|
||||
Arguments: args,
|
||||
AuthToken: authToken,
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
/*
|
||||
* sendInput sends data to the server. It accepts strings or Uint8Arrays.
|
||||
* strings will be encoded as UTF-8. Uint8Arrays are passed along as-is.
|
||||
*/
|
||||
private sendInput(input: string | Uint8Array) {
|
||||
let effectiveBufferSize = this.bufSize - 1;
|
||||
let dataString: string;
|
||||
|
||||
if (typeof input === "string") {
|
||||
dataString = input;
|
||||
} else {
|
||||
dataString = String.fromCharCode(...input)
|
||||
}
|
||||
|
||||
// Account for base64 encoding
|
||||
let maxChunkSize = Math.floor(effectiveBufferSize / 4) * 3;
|
||||
|
||||
for (let i = 0; i < Math.ceil(dataString.length / maxChunkSize); i++) {
|
||||
let inputChunk = dataString.substring(i * maxChunkSize, Math.min((i + 1) * maxChunkSize, dataString.length))
|
||||
this.connection.send(msgInput + btoa(inputChunk));
|
||||
}
|
||||
}
|
||||
|
||||
private sendPing(): void {
|
||||
this.connection.send(msgPing);
|
||||
}
|
||||
|
||||
private sendResizeTerminal(colmuns: number, rows: number) {
|
||||
this.connection.send(
|
||||
msgResizeTerminal + JSON.stringify(
|
||||
{
|
||||
columns: colmuns,
|
||||
rows: rows
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private sendSetEncoding(encoding: "base64" | "null") {
|
||||
this.connection.send(msgSetEncoding + encoding)
|
||||
}
|
||||
|
||||
};
|
@ -2,27 +2,40 @@ import { Terminal, IDisposable } from "xterm";
|
||||
import { FitAddon } from 'xterm-addon-fit';
|
||||
import { WebLinksAddon } from 'xterm-addon-web-links';
|
||||
import { WebglAddon } from 'xterm-addon-webgl';
|
||||
import { lib } from "libapps"
|
||||
import { ZModemAddon } from "./zmodem";
|
||||
|
||||
export class Xterm {
|
||||
export class OurXterm {
|
||||
// The HTMLElement that contains our terminal
|
||||
elem: HTMLElement;
|
||||
|
||||
// The xtermjs.XTerm
|
||||
term: Terminal;
|
||||
|
||||
resizeListener: () => void;
|
||||
decoder: lib.UTF8Decoder;
|
||||
|
||||
message: HTMLElement;
|
||||
messageTimeout: number;
|
||||
messageTimer: NodeJS.Timeout;
|
||||
|
||||
onResizeHandler: IDisposable;
|
||||
onDataHandler: IDisposable;
|
||||
|
||||
fitAddOn: FitAddon;
|
||||
zmodemAddon: ZModemAddon;
|
||||
toServer: (data: string | Uint8Array) => void;
|
||||
encoder: TextEncoder
|
||||
|
||||
constructor(elem: HTMLElement) {
|
||||
this.elem = elem;
|
||||
this.term = new Terminal();
|
||||
this.fitAddOn = new FitAddon();
|
||||
this.zmodemAddon = new ZModemAddon({
|
||||
toTerminal: (x: Uint8Array) => this.term.write(x),
|
||||
toServer: (x: Uint8Array) => this.sendInput(x)
|
||||
});
|
||||
this.term.loadAddon(new WebLinksAddon());
|
||||
this.term.loadAddon(this.fitAddOn);
|
||||
this.term.loadAddon(this.zmodemAddon);
|
||||
|
||||
this.message = elem.ownerDocument.createElement("div");
|
||||
this.message.className = "xterm-overlay";
|
||||
@ -37,21 +50,29 @@ export class Xterm {
|
||||
this.term.open(elem);
|
||||
this.term.focus();
|
||||
this.resizeListener();
|
||||
window.addEventListener("resize", () => { this.resizeListener(); });
|
||||
|
||||
this.decoder = new lib.UTF8Decoder()
|
||||
window.addEventListener("resize", () => { this.resizeListener(); });
|
||||
};
|
||||
|
||||
info(): { columns: number, rows: number } {
|
||||
return { columns: this.term.cols, rows: this.term.rows };
|
||||
};
|
||||
|
||||
output(data: string) {
|
||||
this.term.write(this.decoder.decode(data));
|
||||
// This gets called from the Websocket's onReceive handler
|
||||
output(data: Uint8Array) {
|
||||
this.zmodemAddon.consume(data);
|
||||
};
|
||||
|
||||
getMessage(): HTMLElement {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
showMessage(message: string, timeout: number) {
|
||||
this.message.textContent = message;
|
||||
this.message.innerHTML = message;
|
||||
this.showMessageElem(timeout);
|
||||
}
|
||||
|
||||
showMessageElem(timeout: number) {
|
||||
this.elem.appendChild(this.message);
|
||||
|
||||
if (this.messageTimer) {
|
||||
@ -59,7 +80,11 @@ export class Xterm {
|
||||
}
|
||||
if (timeout > 0) {
|
||||
this.messageTimer = setTimeout(() => {
|
||||
this.elem.removeChild(this.message);
|
||||
try {
|
||||
this.elem.removeChild(this.message);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}, timeout);
|
||||
}
|
||||
};
|
||||
@ -86,11 +111,23 @@ export class Xterm {
|
||||
});
|
||||
};
|
||||
|
||||
onInput(callback: (input: string) => void) {
|
||||
this.onDataHandler = this.term.onData((data) => {
|
||||
callback(data);
|
||||
});
|
||||
sendInput(data: Uint8Array) {
|
||||
return this.toServer(data)
|
||||
}
|
||||
|
||||
onInput(callback: (input: string) => void) {
|
||||
this.encoder = new TextEncoder()
|
||||
this.toServer = callback;
|
||||
|
||||
// I *think* we're ok like this, but if not, we can dispose
|
||||
// of the previous handler and put the new one in place.
|
||||
if (this.onDataHandler !== undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
this.onDataHandler = this.term.onData((input) => {
|
||||
this.toServer(this.encoder.encode(input));
|
||||
});
|
||||
};
|
||||
|
||||
onResize(callback: (colmuns: number, rows: number) => void) {
|
||||
@ -114,4 +151,16 @@ export class Xterm {
|
||||
window.removeEventListener("resize", this.resizeListener);
|
||||
this.term.dispose();
|
||||
}
|
||||
|
||||
disableStdin(): void {
|
||||
this.term.options.disableStdin = true;
|
||||
}
|
||||
|
||||
enableStdin(): void {
|
||||
this.term.options.disableStdin = false;
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this.term.focus();
|
||||
}
|
||||
}
|
245
js/src/zmodem.tsx
Normal file
245
js/src/zmodem.tsx
Normal file
@ -0,0 +1,245 @@
|
||||
import { ITerminalAddon, Terminal } from "xterm";
|
||||
import { Browser, Detection, Offer, Sentry, Session } from 'zmodem.js/src/zmodem_browser';
|
||||
import { MyModal, Button } from "./MyModal";
|
||||
import { Component, ComponentChildren, createRef, render } from "preact";
|
||||
|
||||
export class ZModemAddon implements ITerminalAddon {
|
||||
term: Terminal;
|
||||
elem: HTMLDivElement;
|
||||
sentry: Sentry;
|
||||
toTerminal: (data: Uint8Array) => void;
|
||||
toServer: (data: Uint8Array) => void;
|
||||
|
||||
constructor(props: {
|
||||
toTerminal: (data: Uint8Array) => void,
|
||||
toServer: (data: Uint8Array) => void
|
||||
}) {
|
||||
this.createElement();
|
||||
this.toTerminal = props.toTerminal;
|
||||
this.toServer = props.toServer;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
private createElement() {
|
||||
this.elem = document.createElement("div");
|
||||
document.body.prepend(this.elem);
|
||||
}
|
||||
|
||||
consume(data: Uint8Array) {
|
||||
this.sentry.consume(data)
|
||||
}
|
||||
|
||||
activate(terminal: Terminal): void {
|
||||
this.term = terminal
|
||||
}
|
||||
|
||||
dispose() {
|
||||
}
|
||||
|
||||
private init() {
|
||||
render(<></>, this.elem);
|
||||
|
||||
this.sentry = new Sentry({
|
||||
'to_terminal': (d: Uint8Array) => this.toTerminal(d),
|
||||
'on_detect': (detection: Detection) => this.onDetect(detection),
|
||||
'sender': (x: Uint8Array) => { this.toServer(x) },
|
||||
'on_retract': () => this.reset(),
|
||||
});
|
||||
}
|
||||
|
||||
private reset() {
|
||||
this.init();
|
||||
this.term.options.disableStdin = false;
|
||||
this.term.focus();
|
||||
}
|
||||
|
||||
private onDetect(detection: Detection) {
|
||||
var zsession = detection.confirm();
|
||||
|
||||
this.term.options.disableStdin = true;
|
||||
|
||||
zsession.on('session_end', () => { this.reset() });
|
||||
|
||||
if (zsession.type === "send") {
|
||||
this.send(zsession);
|
||||
}
|
||||
else {
|
||||
zsession.on("offer", (xfer: any) => this.onOffer(xfer));
|
||||
zsession.start();
|
||||
}
|
||||
}
|
||||
|
||||
private send(zsession: Session) {
|
||||
render(<SendFileModal session={zsession} />, this.elem)
|
||||
}
|
||||
|
||||
private onOffer(xfer: Offer) {
|
||||
render(<ReceiveFileModal xfer={xfer} onFinish={() => this.reset()} />, this.elem)
|
||||
}
|
||||
}
|
||||
|
||||
// Renders a bootstrap progress bar
|
||||
function Progress(props: { min: number, max: number, now: number, children?: ComponentChildren }) {
|
||||
let { min, max, now } = props;
|
||||
let percentage = "0";
|
||||
|
||||
if ((typeof min === "number") &&
|
||||
(typeof max === "number") &&
|
||||
(typeof now === "number") &&
|
||||
(min != max)) {
|
||||
percentage = (100 * (now - min) / (max - min)).toFixed(0);
|
||||
}
|
||||
|
||||
return <div class="progress">
|
||||
<div class="progress-bar" role="progressbar" style={"width: " + percentage + "%"} aria-valuenow={now} aria-valuemin={min} aria-valuemax={max}>{props.children}</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
interface ReceiveFileModalProps {
|
||||
xfer: Offer;
|
||||
onFinish?: () => void;
|
||||
}
|
||||
|
||||
interface ReceiveFileModalState {
|
||||
state: "notstarted" | "started" | "skipped" | "done"
|
||||
}
|
||||
|
||||
export class ReceiveFileModal extends Component<ReceiveFileModalProps, ReceiveFileModalState> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.setState({ state: "notstarted" })
|
||||
}
|
||||
|
||||
accept() {
|
||||
this.setState({ state: "started" });
|
||||
|
||||
let timerID = setInterval(
|
||||
() => this.forceUpdate(),
|
||||
100
|
||||
);
|
||||
|
||||
this.props.xfer.accept().then((payloads: any) => {
|
||||
// All done, so stop updating the progress bar
|
||||
// and perform a final render.
|
||||
clearInterval(timerID);
|
||||
this.forceUpdate();
|
||||
|
||||
if (this.state.state != "skipped") {
|
||||
Browser.save_to_disk(
|
||||
payloads,
|
||||
this.props.xfer.get_details().name
|
||||
);
|
||||
}
|
||||
this.setState({ state: "done" })
|
||||
})
|
||||
}
|
||||
|
||||
finish() {
|
||||
console.log('finished');
|
||||
if (this.props.onFinish) this.props.onFinish();
|
||||
}
|
||||
|
||||
progress() {
|
||||
if (this.state.state !== "notstarted") {
|
||||
return <Progress min={0} max={this.props.xfer.get_details().size} now={this.props.xfer.get_offset()} />
|
||||
}
|
||||
}
|
||||
|
||||
skip() {
|
||||
this.props.xfer.skip()
|
||||
this.setState({ state: "skipped" })
|
||||
}
|
||||
|
||||
buttons() {
|
||||
switch (this.state.state) {
|
||||
case "notstarted":
|
||||
return <>
|
||||
<Button priority="primary" clickHandler={() => { this.accept(); }}>Accept</Button>
|
||||
<Button priority="secondary" clickHandler={() => { this.skip(); }}>Decline</Button>
|
||||
</>
|
||||
case "started":
|
||||
return <>
|
||||
<Button priority="danger" clickHandler={() => { this.skip(); }}>Cancel</Button>
|
||||
</>
|
||||
case "skipped":
|
||||
return <>
|
||||
<Button priority="danger" disabled={true}>Skipping...</Button>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.state != "done")
|
||||
return <MyModal title="Incoming file"
|
||||
buttons={this.buttons()}>
|
||||
Accept <code>{this.props.xfer.get_details().name}</code> ({this.props.xfer.get_details().size.toLocaleString(undefined, { maximumFractionDigits: 0 })} bytes)?
|
||||
{this.progress()}
|
||||
</MyModal>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class SendFileModal extends Component<SendFileModalProps, SendFileModalState> {
|
||||
filePickerRef = createRef<HTMLInputElement>();
|
||||
|
||||
constructor(props: SendFileModalProps) {
|
||||
super(props)
|
||||
this.setState({ state: "notstarted" })
|
||||
}
|
||||
|
||||
buttons() {
|
||||
switch (this.state.state) {
|
||||
case "started":
|
||||
return <>
|
||||
<Button priority="primary" clickHandler={() => { this.send(); }} disabled={true}>
|
||||
Sending...
|
||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
</Button>
|
||||
</>
|
||||
case "notstarted":
|
||||
return <>
|
||||
<Button priority="primary" clickHandler={() => { this.send(); }}>Send</Button>
|
||||
</>
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
send() {
|
||||
Browser.send_files(this.props.session,
|
||||
this.filePickerRef.current!.files, {
|
||||
on_offer_response: (f, xfer) => { this.setState({ state: "started" }) },
|
||||
}).then(() => {
|
||||
this.setState({ state: "done" })
|
||||
this.props.session.close()
|
||||
if (this.props.onFinish !== undefined) {
|
||||
this.props.onFinish();
|
||||
}
|
||||
})
|
||||
.catch(e => console.log(e));
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.state != "done")
|
||||
return <MyModal title="Send file(s)"
|
||||
buttons={this.buttons()}>
|
||||
<div class="mb-3">
|
||||
<label for="formFileMultiple" class="form-label">
|
||||
Remote requested file transfer
|
||||
</label>
|
||||
<input ref={this.filePickerRef} class="form-control form-control-sm" type="file" id="formFileMultiple" multiple />
|
||||
</div>
|
||||
</MyModal>
|
||||
}
|
||||
}
|
||||
|
||||
interface SendFileModalProps {
|
||||
onFinish?: () => void;
|
||||
session: Session;
|
||||
}
|
||||
|
||||
interface SendFileModalState {
|
||||
state: "notstarted" | "started" | "done"
|
||||
currentFile: any
|
||||
}
|
@ -1,16 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "preact",
|
||||
"strictNullChecks": true,
|
||||
"noUnusedLocals" : true,
|
||||
"noImplicitThis": true,
|
||||
"alwaysStrict": true,
|
||||
"outDir": "./dist/",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"target": "es5",
|
||||
"target": "esnext",
|
||||
"module": "commonJS",
|
||||
"baseUrl": ".",
|
||||
"types": ["preact", "node"],
|
||||
"paths": {
|
||||
"*": ["./typings/*"]
|
||||
}
|
||||
|
51
js/typings/libapps/index.d.ts
vendored
51
js/typings/libapps/index.d.ts
vendored
@ -1,51 +0,0 @@
|
||||
export declare namespace hterm {
|
||||
export class Terminal {
|
||||
io: IO;
|
||||
onTerminalReady: () => void;
|
||||
|
||||
constructor();
|
||||
getPrefs(): Prefs;
|
||||
decorate(HTMLElement);
|
||||
installKeyboard(): void;
|
||||
uninstallKeyboard(): void;
|
||||
setWindowTitle(title: string): void;
|
||||
reset(): void;
|
||||
softReset(): void;
|
||||
}
|
||||
|
||||
export class IO {
|
||||
writeUTF8: ((data: string) => void);
|
||||
writeUTF16: ((data: string) => void);
|
||||
onVTKeystroke: ((data: string) => void) | null;
|
||||
sendString: ((data: string) => void) | null;
|
||||
onTerminalResize: ((columns: number, rows: number) => void) | null;
|
||||
|
||||
push(): IO;
|
||||
writeUTF(data: string);
|
||||
showOverlay(message: string, timeout: number | null);
|
||||
}
|
||||
|
||||
export class Prefs {
|
||||
set(key: string, value: string): void;
|
||||
}
|
||||
|
||||
export var defaultStorage: lib.Storage;
|
||||
}
|
||||
|
||||
export declare namespace lib {
|
||||
export interface Storage {
|
||||
}
|
||||
|
||||
export interface Memory {
|
||||
new (): Storage;
|
||||
Memory(): Storage
|
||||
}
|
||||
|
||||
export var Storage: {
|
||||
Memory: Memory
|
||||
}
|
||||
|
||||
export class UTF8Decoder {
|
||||
decode(str: string)
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
const path = require('path');
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
const LicenseWebpackPlugin = require('license-webpack-plugin').LicenseWebpackPlugin;
|
||||
|
||||
module.exports = {
|
||||
entry: "./src/main.ts",
|
||||
@ -12,6 +14,9 @@ module.exports = {
|
||||
resolve: {
|
||||
extensions: [".ts", ".tsx", ".js"],
|
||||
},
|
||||
plugins: [
|
||||
new LicenseWebpackPlugin()
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
@ -24,10 +29,21 @@ module.exports = {
|
||||
use: ["style-loader", "css-loader"],
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
include: /node_modules/,
|
||||
loader: 'license-loader'
|
||||
test: /\.scss$/i,
|
||||
use: ["style-loader", "css-loader", {
|
||||
loader: "sass-loader",
|
||||
options: {
|
||||
sassOptions: {
|
||||
includePaths: ["node_modules/bootstrap/scss"]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [new TerserPlugin()],
|
||||
},
|
||||
};
|
||||
|
6
main.go
6
main.go
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
@ -65,6 +66,11 @@ func main() {
|
||||
|
||||
utils.ApplyFlags(cliFlags, flagMappings, c, appOptions, backendOptions)
|
||||
|
||||
if appOptions.Quiet {
|
||||
log.SetFlags(0)
|
||||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
if c.IsSet("credential") {
|
||||
appOptions.EnableBasicAuth = true
|
||||
}
|
||||
|
@ -4,4 +4,10 @@ html, body, #terminal {
|
||||
width: 100%;
|
||||
padding: 0%;
|
||||
margin: 0%;
|
||||
}
|
||||
|
||||
.progress .progress-bar {
|
||||
transition: unset;
|
||||
transition-duration: 0.1s;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
@ -1,18 +1,22 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ .title }}</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="icon" href="favicon.ico">
|
||||
<link rel="icon" href="icon.svg" type="image/svg+xml">
|
||||
<link rel="stylesheet" href="./css/index.css" />
|
||||
<link rel="stylesheet" href="./css/xterm.css" />
|
||||
<link rel="stylesheet" href="./css/xterm_customize.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="terminal"></div>
|
||||
<script src="./auth_token.js"></script>
|
||||
<script src="./config.js"></script>
|
||||
<script src="./js/gotty.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<head>
|
||||
<title>{{ .title }}</title>
|
||||
<link rel="manifest" href="manifest.json" crossorigin="use-credentials">
|
||||
<link rel="icon" href="favicon.ico">
|
||||
<link rel="icon" href="icon.svg" type="image/svg+xml">
|
||||
<link rel="stylesheet" href="./css/index.css" />
|
||||
<link rel="stylesheet" href="./css/xterm.css" />
|
||||
<link rel="stylesheet" href="./css/xterm_customize.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="terminal"></div>
|
||||
<script src="./auth_token.js"></script>
|
||||
<script src="./config.js"></script>
|
||||
<script src="./js/gotty.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -154,13 +154,6 @@ func (server *Server) processWSConn(ctx context.Context, conn *websocket.Conn, h
|
||||
if server.options.Height > 0 {
|
||||
opts = append(opts, webtty.WithFixedRows(server.options.Height))
|
||||
}
|
||||
if server.options.Preferences == nil {
|
||||
server.options.Preferences = &HtermPrefernces{}
|
||||
}
|
||||
// Awkward hack until HtermPreferences can be phased out
|
||||
server.options.Preferences.EnableWebGL = server.options.EnableWebGL
|
||||
opts = append(opts, webtty.WithMasterPreferences(server.options.Preferences))
|
||||
|
||||
tty, err := webtty.New(&wsWrapper{conn}, slave, opts...)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to create webtty")
|
||||
@ -236,7 +229,7 @@ func (server *Server) handleAuthToken(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (server *Server) handleConfig(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/javascript")
|
||||
w.Write([]byte("var gotty_term = '" + server.options.Term + "';"))
|
||||
w.Write([]byte("var gotty_term = 'xterm';"))
|
||||
}
|
||||
|
||||
// titleVariables merges maps in a specified order.
|
||||
|
@ -5,33 +5,32 @@ import (
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Address string `hcl:"address" flagName:"address" flagSName:"a" flagDescribe:"IP address to listen" default:"0.0.0.0"`
|
||||
Port string `hcl:"port" flagName:"port" flagSName:"p" flagDescribe:"Port number to liten" default:"8080"`
|
||||
Path string `hcl:"path" flagName:"path" flagSName:"m" flagDescribe:"Base path" default:"/"`
|
||||
PermitWrite bool `hcl:"permit_write" flagName:"permit-write" flagSName:"w" flagDescribe:"Permit clients to write to the TTY (BE CAREFUL)" default:"false"`
|
||||
EnableBasicAuth bool `hcl:"enable_basic_auth" default:"false"`
|
||||
Credential string `hcl:"credential" flagName:"credential" flagSName:"c" flagDescribe:"Credential for Basic Authentication (ex: user:pass, default disabled)" default:""`
|
||||
EnableRandomUrl bool `hcl:"enable_random_url" flagName:"random-url" flagSName:"r" flagDescribe:"Add a random string to the URL" default:"false"`
|
||||
RandomUrlLength int `hcl:"random_url_length" flagName:"random-url-length" flagDescribe:"Random URL length" default:"8"`
|
||||
EnableTLS bool `hcl:"enable_tls" flagName:"tls" flagSName:"t" flagDescribe:"Enable TLS/SSL" default:"false"`
|
||||
TLSCrtFile string `hcl:"tls_crt_file" flagName:"tls-crt" flagDescribe:"TLS/SSL certificate file path" default:"~/.gotty.crt"`
|
||||
TLSKeyFile string `hcl:"tls_key_file" flagName:"tls-key" flagDescribe:"TLS/SSL key file path" default:"~/.gotty.key"`
|
||||
EnableTLSClientAuth bool `hcl:"enable_tls_client_auth" default:"false"`
|
||||
TLSCACrtFile string `hcl:"tls_ca_crt_file" flagName:"tls-ca-crt" flagDescribe:"TLS/SSL CA certificate file for client certifications" default:"~/.gotty.ca.crt"`
|
||||
IndexFile string `hcl:"index_file" flagName:"index" flagDescribe:"Custom index.html file" default:""`
|
||||
TitleFormat string `hcl:"title_format" flagName:"title-format" flagSName:"" flagDescribe:"Title format of browser window" default:"{{ .command }}@{{ .hostname }}"`
|
||||
EnableReconnect bool `hcl:"enable_reconnect" flagName:"reconnect" flagDescribe:"Enable reconnection" default:"false"`
|
||||
ReconnectTime int `hcl:"reconnect_time" flagName:"reconnect-time" flagDescribe:"Time to reconnect" default:"10"`
|
||||
MaxConnection int `hcl:"max_connection" flagName:"max-connection" flagDescribe:"Maximum connection to gotty" default:"0"`
|
||||
Once bool `hcl:"once" flagName:"once" flagDescribe:"Accept only one client and exit on disconnection" default:"false"`
|
||||
Timeout int `hcl:"timeout" flagName:"timeout" flagDescribe:"Timeout seconds for waiting a client(0 to disable)" default:"0"`
|
||||
PermitArguments bool `hcl:"permit_arguments" flagName:"permit-arguments" flagDescribe:"Permit clients to send command line arguments in URL (e.g. http://example.com:8080/?arg=AAA&arg=BBB)" default:"false"`
|
||||
Preferences *HtermPrefernces `hcl:"preferences"`
|
||||
Width int `hcl:"width" flagName:"width" flagDescribe:"Static width of the screen, 0(default) means dynamically resize" default:"0"`
|
||||
Height int `hcl:"height" flagName:"height" flagDescribe:"Static height of the screen, 0(default) means dynamically resize" default:"0"`
|
||||
WSOrigin string `hcl:"ws_origin" flagName:"ws-origin" flagDescribe:"A regular expression that matches origin URLs to be accepted by WebSocket. No cross origin requests are acceptable by default" default:""`
|
||||
Term string `hcl:"term" flagName:"term" flagDescribe:"Terminal name to use on the browser, one of xterm or hterm." default:"xterm"`
|
||||
EnableWebGL bool `hcl:"enable_webgl" flagName:"enable-webgl" flagDescribe:"Enable WebGL renderer" default:"true"`
|
||||
Address string `hcl:"address" flagName:"address" flagSName:"a" flagDescribe:"IP address to listen" default:"0.0.0.0"`
|
||||
Port string `hcl:"port" flagName:"port" flagSName:"p" flagDescribe:"Port number to liten" default:"8080"`
|
||||
Path string `hcl:"path" flagName:"path" flagSName:"m" flagDescribe:"Base path" default:"/"`
|
||||
PermitWrite bool `hcl:"permit_write" flagName:"permit-write" flagSName:"w" flagDescribe:"Permit clients to write to the TTY (BE CAREFUL)" default:"false"`
|
||||
EnableBasicAuth bool `hcl:"enable_basic_auth" default:"false"`
|
||||
Credential string `hcl:"credential" flagName:"credential" flagSName:"c" flagDescribe:"Credential for Basic Authentication (ex: user:pass, default disabled)" default:""`
|
||||
EnableRandomUrl bool `hcl:"enable_random_url" flagName:"random-url" flagSName:"r" flagDescribe:"Add a random string to the URL" default:"false"`
|
||||
RandomUrlLength int `hcl:"random_url_length" flagName:"random-url-length" flagDescribe:"Random URL length" default:"8"`
|
||||
EnableTLS bool `hcl:"enable_tls" flagName:"tls" flagSName:"t" flagDescribe:"Enable TLS/SSL" default:"false"`
|
||||
TLSCrtFile string `hcl:"tls_crt_file" flagName:"tls-crt" flagDescribe:"TLS/SSL certificate file path" default:"~/.gotty.crt"`
|
||||
TLSKeyFile string `hcl:"tls_key_file" flagName:"tls-key" flagDescribe:"TLS/SSL key file path" default:"~/.gotty.key"`
|
||||
EnableTLSClientAuth bool `hcl:"enable_tls_client_auth" default:"false"`
|
||||
TLSCACrtFile string `hcl:"tls_ca_crt_file" flagName:"tls-ca-crt" flagDescribe:"TLS/SSL CA certificate file for client certifications" default:"~/.gotty.ca.crt"`
|
||||
IndexFile string `hcl:"index_file" flagName:"index" flagDescribe:"Custom index.html file" default:""`
|
||||
TitleFormat string `hcl:"title_format" flagName:"title-format" flagSName:"" flagDescribe:"Title format of browser window" default:"{{ .command }}@{{ .hostname }}"`
|
||||
EnableReconnect bool `hcl:"enable_reconnect" flagName:"reconnect" flagDescribe:"Enable reconnection" default:"false"`
|
||||
ReconnectTime int `hcl:"reconnect_time" flagName:"reconnect-time" flagDescribe:"Time to reconnect" default:"10"`
|
||||
MaxConnection int `hcl:"max_connection" flagName:"max-connection" flagDescribe:"Maximum connection to gotty" default:"0"`
|
||||
Once bool `hcl:"once" flagName:"once" flagDescribe:"Accept only one client and exit on disconnection" default:"false"`
|
||||
Timeout int `hcl:"timeout" flagName:"timeout" flagDescribe:"Timeout seconds for waiting a client(0 to disable)" default:"0"`
|
||||
PermitArguments bool `hcl:"permit_arguments" flagName:"permit-arguments" flagDescribe:"Permit clients to send command line arguments in URL (e.g. http://example.com:8080/?arg=AAA&arg=BBB)" default:"false"`
|
||||
Width int `hcl:"width" flagName:"width" flagDescribe:"Static width of the screen, 0(default) means dynamically resize" default:"0"`
|
||||
Height int `hcl:"height" flagName:"height" flagDescribe:"Static height of the screen, 0(default) means dynamically resize" default:"0"`
|
||||
WSOrigin string `hcl:"ws_origin" flagName:"ws-origin" flagDescribe:"A regular expression that matches origin URLs to be accepted by WebSocket. No cross origin requests are acceptable by default" default:""`
|
||||
EnableWebGL bool `hcl:"enable_webgl" flagName:"enable-webgl" flagDescribe:"Enable WebGL renderer" default:"true"`
|
||||
Quiet bool `hcl:"quiet" flagName:"quiet" flagDescribe:"Don't log" default:"false"`
|
||||
|
||||
TitleVariables map[string]interface{}
|
||||
}
|
||||
@ -42,61 +41,3 @@ func (options *Options) Validate() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type HtermPrefernces struct {
|
||||
AltGrMode *string `hcl:"alt_gr_mode" json:"alt-gr-mode,omitempty"`
|
||||
AltBackspaceIsMetaBackspace bool `hcl:"alt_backspace_is_meta_backspace" json:"alt-backspace-is-meta-backspace,omitempty"`
|
||||
AltIsMeta bool `hcl:"alt_is_meta" json:"alt-is-meta,omitempty"`
|
||||
AltSendsWhat string `hcl:"alt_sends_what" json:"alt-sends-what,omitempty"`
|
||||
AudibleBellSound string `hcl:"audible_bell_sound" json:"audible-bell-sound,omitempty"`
|
||||
DesktopNotificationBell bool `hcl:"desktop_notification_bell" json:"desktop-notification-bell,omitempty"`
|
||||
BackgroundColor string `hcl:"background_color" json:"background-color,omitempty"`
|
||||
BackgroundImage string `hcl:"background_image" json:"background-image,omitempty"`
|
||||
BackgroundSize string `hcl:"background_size" json:"background-size,omitempty"`
|
||||
BackgroundPosition string `hcl:"background_position" json:"background-position,omitempty"`
|
||||
BackspaceSendsBackspace bool `hcl:"backspace_sends_backspace" json:"backspace-sends-backspace,omitempty"`
|
||||
CharacterMapOverrides map[string]map[string]string `hcl:"character_map_overrides" json:"character-map-overrides,omitempty"`
|
||||
CloseOnExit bool `hcl:"close_on_exit" json:"close-on-exit,omitempty"`
|
||||
CursorBlink bool `hcl:"cursor_blink" json:"cursor-blink,omitempty"`
|
||||
CursorBlinkCycle [2]int `hcl:"cursor_blink_cycle" json:"cursor-blink-cycle,omitempty"`
|
||||
CursorColor string `hcl:"cursor_color" json:"cursor-color,omitempty"`
|
||||
ColorPaletteOverrides []*string `hcl:"color_palette_overrides" json:"color-palette-overrides,omitempty"`
|
||||
CopyOnSelect bool `hcl:"copy_on_select" json:"copy-on-select,omitempty"`
|
||||
UseDefaultWindowCopy bool `hcl:"use_default_window_copy" json:"use-default-window-copy,omitempty"`
|
||||
ClearSelectionAfterCopy bool `hcl:"clear_selection_after_copy" json:"clear-selection-after-copy,omitempty"`
|
||||
CtrlPlusMinusZeroZoom bool `hcl:"ctrl_plus_minus_zero_zoom" json:"ctrl-plus-minus-zero-zoom,omitempty"`
|
||||
CtrlCCopy bool `hcl:"ctrl_c_copy" json:"ctrl-c-copy,omitempty"`
|
||||
CtrlVPaste bool `hcl:"ctrl_v_paste" json:"ctrl-v-paste,omitempty"`
|
||||
EastAsianAmbiguousAsTwoColumn bool `hcl:"east_asian_ambiguous_as_two_column" json:"east-asian-ambiguous-as-two-column,omitempty"`
|
||||
Enable8BitControl *bool `hcl:"enable_8_bit_control" json:"enable-8-bit-control,omitempty"`
|
||||
EnableBold *bool `hcl:"enable_bold" json:"enable-bold,omitempty"`
|
||||
EnableBoldAsBright bool `hcl:"enable_bold_as_bright" json:"enable-bold-as-bright,omitempty"`
|
||||
EnableClipboardNotice bool `hcl:"enable_clipboard_notice" json:"enable-clipboard-notice,omitempty"`
|
||||
EnableClipboardWrite bool `hcl:"enable_clipboard_write" json:"enable-clipboard-write,omitempty"`
|
||||
EnableDec12 bool `hcl:"enable_dec12" json:"enable-dec12,omitempty"`
|
||||
EnableWebGL bool `json:"EnableWebGL,omitempty"`
|
||||
Environment map[string]string `hcl:"environment" json:"environment,omitempty"`
|
||||
FontFamily string `hcl:"font_family" json:"font-family,omitempty"`
|
||||
FontSize int `hcl:"font_size" json:"font-size,omitempty"`
|
||||
FontSmoothing string `hcl:"font_smoothing" json:"font-smoothing,omitempty"`
|
||||
ForegroundColor string `hcl:"foreground_color" json:"foreground-color,omitempty"`
|
||||
HomeKeysScroll bool `hcl:"home_keys_scroll" json:"home-keys-scroll,omitempty"`
|
||||
Keybindings map[string]string `hcl:"keybindings" json:"keybindings,omitempty"`
|
||||
MaxStringSequence int `hcl:"max_string_sequence" json:"max-string-sequence,omitempty"`
|
||||
MediaKeysAreFkeys bool `hcl:"media_keys_are_fkeys" json:"media-keys-are-fkeys,omitempty"`
|
||||
MetaSendsEscape bool `hcl:"meta_sends_escape" json:"meta-sends-escape,omitempty"`
|
||||
MousePasteButton *int `hcl:"mouse_paste_button" json:"mouse-paste-button,omitempty"`
|
||||
PageKeysScroll bool `hcl:"page_keys_scroll" json:"page-keys-scroll,omitempty"`
|
||||
PassAltNumber *bool `hcl:"pass_alt_number" json:"pass-alt-number,omitempty"`
|
||||
PassCtrlNumber *bool `hcl:"pass_ctrl_number" json:"pass-ctrl-number,omitempty"`
|
||||
PassMetaNumber *bool `hcl:"pass_meta_number" json:"pass-meta-number,omitempty"`
|
||||
PassMetaV bool `hcl:"pass_meta_v" json:"pass-meta-v,omitempty"`
|
||||
ReceiveEncoding string `hcl:"receive_encoding" json:"receive-encoding,omitempty"`
|
||||
ScrollOnKeystroke bool `hcl:"scroll_on_keystroke" json:"scroll-on-keystroke,omitempty"`
|
||||
ScrollOnOutput bool `hcl:"scroll_on_output" json:"scroll-on-output,omitempty"`
|
||||
ScrollbarVisible bool `hcl:"scrollbar_visible" json:"scrollbar-visible,omitempty"`
|
||||
ScrollWheelMoveMultiplier int `hcl:"scroll_wheel_move_multiplier" json:"scroll-wheel-move-multiplier,omitempty"`
|
||||
SendEncoding string `hcl:"send_encoding" json:"send-encoding,omitempty"`
|
||||
ShiftInsertPaste bool `hcl:"shift_insert_paste" json:"shift-insert-paste,omitempty"`
|
||||
UserCss string `hcl:"user_css" json:"user-css,omitempty"`
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
noesctmpl "text/template"
|
||||
"time"
|
||||
|
||||
@ -111,7 +112,12 @@ func (server *Server) Run(ctx context.Context, options ...RunOption) error {
|
||||
if server.options.EnableRandomUrl {
|
||||
path = "/" + randomstring.Generate(server.options.RandomUrlLength) + "/"
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
if !strings.HasSuffix(path, "/") {
|
||||
path = path + "/"
|
||||
}
|
||||
handlers := server.setupHandlers(cctx, cancel, path, counter)
|
||||
srv, err := server.setupHTTPServer(handlers)
|
||||
if err != nil {
|
||||
|
@ -1,7 +1,10 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type wsWrapper struct {
|
||||
@ -28,6 +31,11 @@ func (wsw *wsWrapper) Read(p []byte) (n int, err error) {
|
||||
continue
|
||||
}
|
||||
|
||||
return reader.Read(p)
|
||||
b, err := ioutil.ReadAll(reader)
|
||||
if len(b) > len(p) {
|
||||
return 0, errors.Wrapf(err, "Client message exceeded buffer size")
|
||||
}
|
||||
n = copy(p, b)
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
|
19
webtty/codecs.go
Normal file
19
webtty/codecs.go
Normal file
@ -0,0 +1,19 @@
|
||||
package webtty
|
||||
|
||||
type Decoder interface {
|
||||
Decode(dst, src []byte) (int, error)
|
||||
}
|
||||
|
||||
type Encoder interface {
|
||||
Encode(dst, src []byte) (int, error)
|
||||
}
|
||||
|
||||
type NullCodec struct{}
|
||||
|
||||
func (NullCodec) Encode(dst, src []byte) (int, error) {
|
||||
return copy(dst, src), nil
|
||||
}
|
||||
|
||||
func (NullCodec) Decode(dst, src []byte) (int, error) {
|
||||
return copy(dst, src), nil
|
||||
}
|
@ -13,6 +13,8 @@ const (
|
||||
Ping = '2'
|
||||
// Notify that the browser size has been changed
|
||||
ResizeTerminal = '3'
|
||||
// Change encoding
|
||||
SetEncoding = '4'
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -24,6 +24,7 @@ type WebTTY struct {
|
||||
rows int
|
||||
reconnect int // in seconds
|
||||
masterPrefs []byte
|
||||
decoder Decoder
|
||||
|
||||
bufferSize int
|
||||
writeMutex sync.Mutex
|
||||
@ -43,6 +44,7 @@ func New(masterConn Master, slave Slave, options ...Option) (*WebTTY, error) {
|
||||
rows: 0,
|
||||
|
||||
bufferSize: 1024,
|
||||
decoder: &NullCodec{},
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
@ -176,7 +178,13 @@ func (wt *WebTTY) handleMasterReadEvent(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := wt.slave.Write(data[1:])
|
||||
var decodedBuffer = make([]byte, len(data))
|
||||
n, err := wt.decoder.Decode(decodedBuffer, data[1:])
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to decode received data")
|
||||
}
|
||||
|
||||
_, err = wt.slave.Write(decodedBuffer[:n])
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to write received data to slave")
|
||||
}
|
||||
@ -187,6 +195,14 @@ func (wt *WebTTY) handleMasterReadEvent(data []byte) error {
|
||||
return errors.Wrapf(err, "failed to return Pong message to master")
|
||||
}
|
||||
|
||||
case SetEncoding:
|
||||
switch string(data[1:]) {
|
||||
case "base64":
|
||||
wt.decoder = base64.StdEncoding
|
||||
case "null":
|
||||
wt.decoder = NullCodec{}
|
||||
}
|
||||
|
||||
case ResizeTerminal:
|
||||
if wt.columns != 0 && wt.rows != 0 {
|
||||
break
|
||||
|
Loading…
Reference in New Issue
Block a user