mirror of
https://github.com/sorenisanerd/gotty.git
synced 2024-11-22 12:24:25 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
48c794023a
36
.github/workflows/pre-release.yaml
vendored
Normal file
36
.github/workflows/pre-release.yaml
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
name: "pre-release"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "master"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pre-release-docker:
|
||||||
|
name: "Pre Release Docker"
|
||||||
|
runs-on: "ubuntu-latest"
|
||||||
|
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
|
- uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
|
- uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: "${{ secrets.DOCKER_HUB_USER }}"
|
||||||
|
password: "${{ secrets.DOCKER_HUB_TOKEN }}"
|
||||||
|
|
||||||
|
- name: "Build and push docker image"
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: "${{ secrets.DOCKER_REPO }}:latest"
|
15
Dockerfile
15
Dockerfile
@ -1,15 +1,20 @@
|
|||||||
FROM golang:1.16
|
FROM node:16 as js-build
|
||||||
|
WORKDIR /gotty
|
||||||
|
COPY js /gotty/js
|
||||||
|
COPY Makefile /gotty/
|
||||||
|
RUN make bindata/static/js/gotty.js.map
|
||||||
|
|
||||||
|
FROM golang:1.16 as go-build
|
||||||
WORKDIR /gotty
|
WORKDIR /gotty
|
||||||
COPY . /gotty
|
COPY . /gotty
|
||||||
|
COPY --from=js-build /gotty/js/node_modules /gotty/js/node_modules
|
||||||
|
COPY --from=js-build /gotty/bindata/static/js /gotty/bindata/static/js
|
||||||
RUN CGO_ENABLED=0 make
|
RUN CGO_ENABLED=0 make
|
||||||
|
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
RUN apk update && \
|
RUN apk update && \
|
||||||
apk upgrade && \
|
apk upgrade && \
|
||||||
apk --no-cache add ca-certificates && \
|
apk --no-cache add ca-certificates bash
|
||||||
apk add bash
|
|
||||||
WORKDIR /root
|
WORKDIR /root
|
||||||
COPY --from=0 /gotty/gotty /usr/bin/
|
COPY --from=go-build /gotty/gotty /usr/bin/
|
||||||
CMD ["gotty", "-w", "bash"]
|
CMD ["gotty", "-w", "bash"]
|
||||||
|
@ -37,12 +37,12 @@ func (factory *Factory) Name() string {
|
|||||||
return "local command"
|
return "local command"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *Factory) New(params map[string][]string) (server.Slave, error) {
|
func (factory *Factory) New(params map[string][]string, headers map[string][]string) (server.Slave, error) {
|
||||||
argv := make([]string, len(factory.argv))
|
argv := make([]string, len(factory.argv))
|
||||||
copy(argv, factory.argv)
|
copy(argv, factory.argv)
|
||||||
if params["arg"] != nil && len(params["arg"]) > 0 {
|
if params["arg"] != nil && len(params["arg"]) > 0 {
|
||||||
argv = append(argv, params["arg"]...)
|
argv = append(argv, params["arg"]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return New(factory.command, argv, factory.opts...)
|
return New(factory.command, argv, headers, factory.opts...)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package localcommand
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -27,11 +28,22 @@ type LocalCommand struct {
|
|||||||
ptyClosed chan struct{}
|
ptyClosed chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(command string, argv []string, options ...Option) (*LocalCommand, error) {
|
func New(command string, argv []string, headers map[string][]string, options ...Option) (*LocalCommand, error) {
|
||||||
cmd := exec.Command(command, argv...)
|
cmd := exec.Command(command, argv...)
|
||||||
|
|
||||||
cmd.Env = append(os.Environ(), "TERM=xterm-256color")
|
cmd.Env = append(os.Environ(), "TERM=xterm-256color")
|
||||||
|
|
||||||
|
// Combine headers into key=value pairs to set as env vars
|
||||||
|
// Prefix the headers with "http_" so we don't overwrite any other env vars
|
||||||
|
// which potentially has the same name and to bring these closer to what
|
||||||
|
// a (F)CGI server would proxy to a backend service
|
||||||
|
// Replace hyphen with underscore and make them all upper case
|
||||||
|
for key, values := range headers {
|
||||||
|
h := "HTTP_" + strings.Replace(strings.ToUpper(key), "-", "_", -1) + "=" + strings.Join(values, ",")
|
||||||
|
// log.Printf("Adding header: %s", h)
|
||||||
|
cmd.Env = append(cmd.Env, h)
|
||||||
|
}
|
||||||
|
|
||||||
pty, err := pty.Start(cmd)
|
pty, err := pty.Start(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// todo close cmd?
|
// todo close cmd?
|
||||||
|
@ -23,7 +23,7 @@ func TestNewFactory(t *testing.T) {
|
|||||||
t.Errorf("factory.options = %v, expected %v", factory.options, &Options{})
|
t.Errorf("factory.options = %v, expected %v", factory.options, &Options{})
|
||||||
}
|
}
|
||||||
|
|
||||||
slave, _ := factory.New(nil)
|
slave, _ := factory.New(nil, nil)
|
||||||
lcmd := slave.(*LocalCommand)
|
lcmd := slave.(*LocalCommand)
|
||||||
if lcmd.closeSignal != 123 {
|
if lcmd.closeSignal != 123 {
|
||||||
t.Errorf("lcmd.closeSignal = %v, expected %v", lcmd.closeSignal, 123)
|
t.Errorf("lcmd.closeSignal = %v, expected %v", lcmd.closeSignal, 123)
|
||||||
@ -40,7 +40,7 @@ func TestFactoryNew(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
slave, err := factory.New(nil)
|
slave, err := factory.New(nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("factory.New() returned error")
|
t.Errorf("factory.New() returned error")
|
||||||
return
|
return
|
||||||
|
12
js/package-lock.json
generated
12
js/package-lock.json
generated
@ -1384,9 +1384,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/loader-utils": {
|
"node_modules/loader-utils": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||||
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
|
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"big.js": "^5.2.2",
|
"big.js": "^5.2.2",
|
||||||
"emojis-list": "^3.0.0",
|
"emojis-list": "^3.0.0",
|
||||||
@ -3770,9 +3770,9 @@
|
|||||||
"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg=="
|
"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg=="
|
||||||
},
|
},
|
||||||
"loader-utils": {
|
"loader-utils": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||||
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
|
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"big.js": "^5.2.2",
|
"big.js": "^5.2.2",
|
||||||
"emojis-list": "^3.0.0",
|
"emojis-list": "^3.0.0",
|
||||||
|
@ -72,7 +72,11 @@ func (server *Server) generateHandleWS(ctx context.Context, cancel context.Cance
|
|||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
err = server.processWSConn(ctx, conn)
|
if server.options.PassHeaders {
|
||||||
|
err = server.processWSConn(ctx, conn, r.Header)
|
||||||
|
} else {
|
||||||
|
err = server.processWSConn(ctx, conn, nil)
|
||||||
|
}
|
||||||
|
|
||||||
switch err {
|
switch err {
|
||||||
case ctx.Err():
|
case ctx.Err():
|
||||||
@ -87,7 +91,7 @@ func (server *Server) generateHandleWS(ctx context.Context, cancel context.Cance
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) processWSConn(ctx context.Context, conn *websocket.Conn) error {
|
func (server *Server) processWSConn(ctx context.Context, conn *websocket.Conn, headers map[string][]string) error {
|
||||||
typ, initLine, err := conn.ReadMessage()
|
typ, initLine, err := conn.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to authenticate websocket connection")
|
return errors.Wrapf(err, "failed to authenticate websocket connection")
|
||||||
@ -116,7 +120,7 @@ func (server *Server) processWSConn(ctx context.Context, conn *websocket.Conn) e
|
|||||||
}
|
}
|
||||||
params := query.Query()
|
params := query.Query()
|
||||||
var slave Slave
|
var slave Slave
|
||||||
slave, err = server.factory.New(params)
|
slave, err = server.factory.New(params, headers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to create backend")
|
return errors.Wrapf(err, "failed to create backend")
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ type Options struct {
|
|||||||
Once bool `hcl:"once" flagName:"once" flagDescribe:"Accept only one client and exit on disconnection" default:"false"`
|
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"`
|
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"`
|
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"`
|
||||||
|
PassHeaders bool `hcl:"pass_headers" flagName:"pass-headers" flagDescribe:"Pass HTTP request headers as environment variables (e.g. Cookie becomes HTTP_COOKIE)" default:"false"`
|
||||||
Width int `hcl:"width" flagName:"width" flagDescribe:"Static width of the screen, 0(default) means dynamically resize" default:"0"`
|
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"`
|
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:""`
|
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:""`
|
||||||
|
@ -13,5 +13,5 @@ type Slave interface {
|
|||||||
|
|
||||||
type Factory interface {
|
type Factory interface {
|
||||||
Name() string
|
Name() string
|
||||||
New(params map[string][]string) (Slave, error)
|
New(params map[string][]string, headers map[string][]string) (Slave, error)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user