Compare commits

...

10 Commits

Author SHA1 Message Date
Evan Chen ddf5e86cbc build: add s390x arch 2021-12-29 14:15:27 +08:00
Evan Chen faf8300d8f feat: #3 2021-11-24 23:02:50 +08:00
Evan Chen f309009a76 fix: #4 2021-11-19 17:19:50 +08:00
Evan Chen 7aec30d473 fix: #2 2021-11-19 15:47:47 +08:00
Evan Chen 9728bfab58 fix: TERM env not set 2021-11-18 15:32:50 +08:00
Evan Chen 6828e6397a docs: add log
continuous-integration/drone/tag Build is passing Details
2021-11-18 14:50:57 +08:00
Evan Chen b6b0774531 feat: start new cmd with custom args in ?cmd=
continuous-integration/drone/tag Build is passing Details
2021-11-18 13:54:29 +08:00
Evan Chen 6a75a1e27f chore: update profile
continuous-integration/drone/tag Build is passing Details
2021-11-18 11:24:49 +08:00
Evan Chen af0fc1b352 docs: update usage prompt 2021-11-18 11:10:35 +08:00
Evan Chen 2fecf640de build: make nocgo default 2021-11-18 10:51:41 +08:00
11 changed files with 216 additions and 99 deletions

View File

@ -9,14 +9,20 @@ Usage: gterm [options]
address to bind (default ":8000")
-allow string
restrict ip
-arg value
additional args to pass to cmd, multiple args can be passed, ex. -arg a -arg b
-dev
is development mode
set the system to development mode
-dir string
the working dir that the shell will start from
-log-level int
log level (default 9)
log level, error:1 debug:2 warn:4 info:8 (default 9)
-name string
the application title (default "gterm")
the application name (default "gterm")
-profile
print default profile, could be invoked with <(..)
-shell string
the shell behind (default "bash")
the shell to use (default "bash")
-v show version
```

13
build.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
VERSION=$(git describe --tags --abbrev=0)
BUILD=$(git rev-parse --short HEAD)
PROJ=gterm
DIST=dist
LDFLAGS="-ldflags \"-X main.Version=${VERSION} -X main.Build=${BUILD} -w -s\""
BIN_FILENAME="${PROJ}"
CMD="CGO_ENABLED=0 go build ${LDFLAGS} -o ${DIST}/${BIN_FILENAME} cmd/gterm/main.go"
echo "${CMD}"
eval $CMD

View File

@ -3,12 +3,14 @@ package main
import (
"flag"
"fmt"
"net"
"net/http"
"os"
"strings"
"kumoly.io/lib/klog"
"kumoly.io/lib/ksrv"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"kumoly.io/lib/guard"
"kumoly.io/tools/gterm"
)
@ -27,32 +29,40 @@ var Version = "0.0.0"
var Build = "alpha"
var (
flagAllowIP string
flagAppName string
flagAddr string
flagShell string
flagDir string
flagLogLevel int
flagDev bool
flagVer bool
flagArgs arrayFlags
flagProfile bool
flagAllowIPNet string
flagAppName string
flagAddr string
flagShell string
flagDir string
flagLogLevel int
flagLogPretty bool
flagDev bool
flagVer bool
flagArgs arrayFlags
flagProfile bool
flagSalt string
flagUsr string
flagPasswd string
)
func init() {
flag.StringVar(&flagAppName, "name", "gterm", "the application title")
flag.StringVar(&flagAppName, "name", "gterm", "the application name")
flag.StringVar(&flagAddr, "addr", ":8000", "address to bind")
flag.StringVar(&flagShell, "shell", "bash", "the shell behind")
flag.StringVar(&flagDir, "dir", ".", "the working dir")
flag.Var(&flagArgs, "arg", "additional args to pass to cmd")
flag.BoolVar(&flagDev, "dev", false, "is development mode")
flag.IntVar(&flagLogLevel, "log-level", 9, "log level")
flag.StringVar(&flagAllowIP, "allow", "", "restrict ip")
flag.BoolVar(&flagProfile, "profile", false, "print default profile, invoked with <(..)")
flag.StringVar(&flagShell, "shell", "bash", "the shell to use")
flag.StringVar(&flagDir, "dir", "", "the working dir that the shell will start from")
flag.Var(&flagArgs, "arg", "additional args to pass to cmd, multiple args can be passed, ex. -arg a -arg b")
flag.BoolVar(&flagDev, "dev", false, "set the system to development mode")
flag.IntVar(&flagLogLevel, "log-level", 1, "log level [-1(trace):5(panic)] 7 to disable")
flag.StringVar(&flagAllowIPNet, "allow", "", "restrict ip in a specific ip net")
flag.BoolVar(&flagProfile, "profile", false, "print default profile, could be invoked with <(..)")
flag.StringVar(&flagSalt, "salt", "", "add salt to encoded keyparam")
flag.BoolVar(&flagVer, "v", false, "show version")
flag.BoolVar(&flagLogPretty, "pretty", false, "log message in human readable format (the original log is json)")
flag.StringVar(&flagUsr, "usr", "", "username, use basic auth for authentication if user and password are set")
flag.StringVar(&flagPasswd, "passwd", "", "password, use basic auth for authentication if user and password are set")
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: gterm [options] [args...]\n")
fmt.Fprintf(os.Stderr, "Usage: gterm [options]\n")
flag.PrintDefaults()
}
}
@ -68,42 +78,45 @@ func main() {
return
}
klog.LEVEL = klog.Llevel(flagLogLevel)
klog.PROD = !flagDev
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.SetGlobalLevel(zerolog.Level(flagLogLevel))
if flagLogPretty {
log.Logger = log.Output(zerolog.ConsoleWriter{
Out: os.Stdout,
TimeFormat: "2006/01/02 15:04:05",
})
}
if flagDev {
log.Logger = log.With().Caller().Logger()
}
log.Logger = log.With().Str("mod", "gtrem").Logger()
g := gterm.New()
g.AppName = flagAppName
g.Cmd = flagShell
g.Args = flagArgs
g.Dir = flagDir
g.Salt = flagSalt
gd := guard.New()
if flagAllowIPNet != "" {
_, ipnet, err := net.ParseCIDR(flagAllowIPNet)
if err != nil {
log.Panic().Err(err).Msg("")
}
gd.AllowIPNet = ipnet
}
if flagUsr != "" && flagPasswd != "" {
gd.SetBasicAuth(flagUsr, flagPasswd)
}
server := &http.Server{
Addr: flagAddr,
Handler: Middleware(g),
Handler: gd.Guard(g),
}
klog.Info("gterm starting at ", flagAddr)
log.Info().Msgf("gterm starting at %s", flagAddr)
err := server.ListenAndServe()
if err != nil {
panic(err)
}
}
func Middleware(next http.Handler) http.Handler {
log := klog.Sub(flagAppName)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Error(err)
}
}()
ip := ksrv.GetIP(r)
if flagAllowIP != "" {
if !ksrv.MatchIPGlob(ip, flagAllowIP) {
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("permission denied"))
}
}
next.ServeHTTP(w, r)
log.Debug(ip, " ", r.URL.String())
})
}

5
go.mod
View File

@ -5,11 +5,14 @@ go 1.17
require (
github.com/creack/pty v1.1.17
github.com/gorilla/websocket v1.4.2
kumoly.io/lib/klog v0.0.8
github.com/rs/zerolog v1.26.0
kumoly.io/lib/guard v0.1.1
kumoly.io/lib/ksrv v0.0.2-0.20211112060911-0d61b343a298
kumoly.io/lib/xorencrypt v0.1.0
)
require (
github.com/mattn/go-isatty v0.0.14 // indirect
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
kumoly.io/lib/klog v0.0.8 // indirect
)

35
go.sum
View File

@ -1,13 +1,48 @@
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE=
github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
kumoly.io/lib/guard v0.1.0 h1:PvFM0bcWbgfZQv4QfRwDmrK9FAjv9QYwfJY3Ffg6JA0=
kumoly.io/lib/guard v0.1.0/go.mod h1:yWg9RDSI6YXkOPmP6Ad93aMqzlxhgW8LOe/ZRjjYX3U=
kumoly.io/lib/guard v0.1.1 h1:aUcn0qVtX6TqRhp7bWSjIRlbWRWtuK0cjCArILTbAcY=
kumoly.io/lib/guard v0.1.1/go.mod h1:yWg9RDSI6YXkOPmP6Ad93aMqzlxhgW8LOe/ZRjjYX3U=
kumoly.io/lib/klog v0.0.8 h1:6hTfDlZh7KGnPrd2tUrauCKRImSnyyN9DHXpey3Czn8=
kumoly.io/lib/klog v0.0.8/go.mod h1:Snm+c1xRrh/RbXsxQf7UGYbAJGPcIa6bEEN+CmzJh7M=
kumoly.io/lib/ksrv v0.0.2-0.20211112060911-0d61b343a298 h1:0raqoIXmNpD6s1SrJbieAyIIkDyhe+aqfaXvx8wenrI=
kumoly.io/lib/ksrv v0.0.2-0.20211112060911-0d61b343a298/go.mod h1:pwd+NspxnoxPJAETRY2V4i2qZc+orKLxvWzGUBiqBW8=
kumoly.io/lib/xorencrypt v0.1.0 h1:VssGocaBAPyLn+QURVY8FdFYRBmwFr26z7ame0zwV44=
kumoly.io/lib/xorencrypt v0.1.0/go.mod h1:+L3JtdD/CTlcXvE8X7AvOJBVbN16qvnxxv3zIWPZgQM=

121
gterm.go
View File

@ -13,9 +13,10 @@ import (
"github.com/creack/pty"
"github.com/gorilla/websocket"
"kumoly.io/lib/klog"
"github.com/rs/zerolog/log"
"kumoly.io/lib/ksrv"
"kumoly.io/lib/ksrv/engine"
"kumoly.io/lib/xorencrypt"
"kumoly.io/tools/gterm/public"
)
@ -29,10 +30,12 @@ var tmpl *engine.Engine
var servePublic = http.FileServer(http.FS(public.FS))
var pool map[string]chan struct{}
var locks map[string]chan struct{}
func init() {
tmpl = engine.Must(engine.New("").Parse(index))
pool = map[string]chan struct{}{}
locks = map[string]chan struct{}{}
}
type GTerm struct {
@ -53,6 +56,7 @@ type GTerm struct {
// cycle should be tolerated, beyond this the connection should be deemed dead
Timeout time.Duration
BufferSize int
Salt string
}
func New() *GTerm {
@ -73,13 +77,12 @@ func New() *GTerm {
// }
go func() {
//print pool
log := klog.Sub("gterm")
for {
cons := []string{}
for k := range pool {
cons = append(cons, k)
}
log.Info("current connections: ", cons)
log.Info().Interface("connections", cons).Msg("")
time.Sleep(5 * time.Minute)
}
}()
@ -125,6 +128,29 @@ func (g *GTerm) App(w http.ResponseWriter, r *http.Request) {
servePublic.ServeHTTP(w, r)
}
type NewCmdRequest struct {
Cmd string `json:"cmd"`
Envs []string `json:"envs"`
Args []string `json:"args"`
Dir string `json:"dir"`
Block bool `json:"block"`
}
func (g *GTerm) defaultCmd() *exec.Cmd {
cmd := exec.Command(g.Cmd, g.Args...)
cmd.Env = g.Envs
if g.Dir != "" && g.Dir != "." {
cmd.Dir = g.Dir
}
return cmd
}
func (g *GTerm) echo(msg string) *exec.Cmd {
cmd := exec.Command("echo", msg)
cmd.Env = g.Envs
return cmd
}
func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
id := fmt.Sprintf("[%02d] %s", ctr(), ksrv.GetIP(r))
pool[id] = make(chan struct{}, 1)
@ -132,8 +158,43 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
close(pool[id])
delete(pool, id)
}()
l := klog.Sub(id)
l.Info("connection established.")
l := log.With().Str("id", id).Logger()
var cmd *exec.Cmd
if newCmd := r.URL.Query().Get("cmd"); newCmd != "" {
param, _ := xorencrypt.Decrypt(newCmd, g.Salt)
req := &NewCmdRequest{}
err := json.Unmarshal([]byte(param), req)
if err != nil {
l.Error().Err(err).Str("base", newCmd).Str("decrypt", param).Msg("cmd decode failed")
cmd = g.echo("cmd decode failed")
} else {
cmd = exec.Command(req.Cmd, req.Args...)
cmd.Env = append(req.Envs, "TERM=xterm-256color")
cmd.Dir = req.Dir
if req.Block {
lock, ok := locks[newCmd]
if !ok {
locks[newCmd] = make(chan struct{}, 1)
}
if len(lock) == 1 {
cmd = g.echo("cmd already running")
} else {
l.Info().Interface("cmd", req).Msg("starting cmd")
locks[newCmd] <- struct{}{}
defer func() {
<-locks[newCmd]
close(locks[newCmd])
delete(locks, newCmd)
}()
}
}
}
} else {
cmd = g.defaultCmd()
}
upgrader := websocket.Upgrader{
HandshakeTimeout: 0,
ReadBufferSize: g.BufferSize,
@ -141,32 +202,28 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
l.Error(err)
l.Error().Err(err).Msg("upgrade error")
return
}
l.Info().Msg("connection established.")
cmd := exec.Command(g.Cmd, g.Args...)
cmd.Env = g.Envs
if g.Dir != "" && g.Dir != "." {
cmd.Dir = g.Dir
}
tty, err := pty.Start(cmd)
if err != nil {
l.Error(err)
l.Error().Err(err).Msg("start tty error")
conn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
}
defer func() {
if err := cmd.Process.Kill(); err != nil {
l.Error(err)
l.Error().Err(err).Msg("proccess kill error")
}
if _, err := cmd.Process.Wait(); err != nil {
l.Error(err)
l.Error().Err(err).Msg("proccess wait error")
}
if err := tty.Close(); err != nil {
l.Error(err)
l.Error().Err(err).Msg("tty close error")
}
if err := conn.Close(); err != nil {
l.Error(err)
l.Error().Err(err).Msg("conn close error")
}
}()
@ -182,16 +239,16 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
go func() {
for {
if err := conn.WriteMessage(websocket.PingMessage, []byte("keepalive")); err != nil {
l.Warn("failed to write ping message")
l.Warn().Msg("failed to write ping message")
return
}
time.Sleep(g.Timeout / 2)
if time.Since(lastPongTime) > g.Timeout {
l.Warn("failed to get response from ping, triggering disconnect now...")
l.Warn().Msg("failed to get response from ping, triggering disconnect now...")
waiter <- struct{}{}
return
}
l.Debug("received response from ping successfully")
l.Debug().Msg("received response from ping successfully")
}
}()
@ -209,19 +266,19 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
buffer := make([]byte, g.BufferSize)
readLength, err := tty.Read(buffer)
if err != nil {
l.Warn("failed to read from tty: ", err)
l.Warn().Err(err).Msg("failed to read from tty")
if err := conn.WriteMessage(websocket.TextMessage, []byte("bye!")); err != nil {
l.Warn("failed to send termination message from tty to xterm.js: ", err)
l.Warn().Err(err).Msg("failed to send termination message from tty to xterm.js")
}
waiter <- struct{}{}
return
}
if err := conn.WriteMessage(websocket.BinaryMessage, buffer[:readLength]); err != nil {
l.Warn("failed to send ", readLength, " bytes from tty to xterm.js")
l.Warn().Msgf("failed to send %s bytes from tty to xterm.js", readLength)
errorCounter++
continue
}
l.Debug("sent message of size ", readLength, " bytes from tty to xterm.js")
l.Debug().Msgf("sent message of size %s bytes from tty to xterm.js", readLength)
errorCounter = 0
}
}()
@ -233,7 +290,7 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
messageType, data, err := conn.ReadMessage()
if err != nil {
if !connectionClosed {
l.Warn("failed to get next reader: ", err)
l.Warn().Err(err).Msg("failed to get next reader")
}
return
}
@ -243,11 +300,11 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
if !ok {
dataType = "uunknown"
}
l.Debug(fmt.Sprintf("received %s (type: %v) message of size %v byte(s) from xterm.js with key sequence: %v", dataType, messageType, dataLength, dataBuffer))
l.Debug().Msgf("received %s (type: %v) message of size %v byte(s) from xterm.js with key sequence: %v", dataType, messageType, dataLength, dataBuffer)
// process
if dataLength == -1 { // invalid
l.Warn("failed to get the correct number of bytes read, ignoring message")
l.Warn().Msg("failed to get the correct number of bytes read, ignoring message")
continue
}
@ -257,15 +314,15 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
ttySize := &TTYSize{}
resizeMessage := bytes.Trim(dataBuffer[1:], " \n\r\t\x00\x01")
if err := json.Unmarshal(resizeMessage, ttySize); err != nil {
l.Warn(fmt.Sprintf("failed to unmarshal received resize message '%s': %s", string(resizeMessage), err))
l.Warn().Err(err).Msgf("failed to unmarshal received resize message '%s'", string(resizeMessage))
continue
}
l.DebugF(klog.H{"rows": ttySize.Rows, "columns": ttySize.Cols}, "resizing tty...")
l.Debug().Int("rows", int(ttySize.Rows)).Int("columns", int(ttySize.Cols)).Msg("resizing tty...")
if err := pty.Setsize(tty, &pty.Winsize{
Rows: ttySize.Rows,
Cols: ttySize.Cols,
}); err != nil {
l.Warn("failed to resize tty, error: ", err)
l.Warn().Err(err).Msg("failed to resize tty")
}
continue
}
@ -274,16 +331,16 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
// write to tty
bytesWritten, err := tty.Write(dataBuffer)
if err != nil {
l.Warn(fmt.Sprintf("failed to write %v bytes to tty: %s", len(dataBuffer), err))
l.Warn().Err(err).Msgf("failed to write %v bytes to tty", len(dataBuffer))
continue
}
l.Debug(bytesWritten, " bytes written to tty...")
l.Debug().Msgf("%d bytes written to tty...", bytesWritten)
}
}()
<-waiter
close(waiter)
l.Info("closing connection...")
l.Info().Msg("closing connection...")
connectionClosed = true
}

View File

@ -18,7 +18,7 @@ import 'xterm/css/xterm.css'
const fitAddon = new FitAddon();
terminal.loadAddon(fitAddon);
var protocol = (location.protocol === "https:") ? "wss://" : "ws://";
var url = protocol + location.host + location.pathname + "ws"
var url = protocol + location.host + location.pathname + "ws" + location.search
const ws = new WebSocket(url);
const attachAddon = new AttachAddon(ws);
const webLinksAddon = new WebLinksAddon();

10
make.sh
View File

@ -11,20 +11,16 @@ FAILURES=""
PLATFORMS="darwin/amd64 darwin/arm64"
PLATFORMS="$PLATFORMS linux/amd64"
PLATFORMS="$PLATFORMS linux/s390x"
for PLATFORM in $PLATFORMS; do
GOOS=${PLATFORM%/*}
GOARCH=${PLATFORM#*/}
BIN_FILENAME="${PROJ}"
CMD="GOOS=${GOOS} GOARCH=${GOARCH} go build ${LDFLAGS} -o ${DIST}/${BIN_FILENAME} cmd/gterm/main.go"
CMD="CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} go build ${LDFLAGS} -o ${DIST}/${BIN_FILENAME} cmd/gterm/main.go"
echo "${CMD}"
eval $CMD || FAILURES="${FAILURES} ${PLATFORM}"
sh -c "cd ${DIST} && tar -czf ${PROJ}-${VERSION}-${GOOS}-${GOARCH}.tar.gz ${BIN_FILENAME} && rm ${BIN_FILENAME}"
# build netgo ver
CMD="CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} go build ${LDFLAGS} -o ${DIST}/${BIN_FILENAME} cmd/gterm/main.go"
eval $CMD
sh -c "cd ${DIST} && tar -czf ${PROJ}-${VERSION}-${GOOS}-${GOARCH}-nocgo.tar.gz ${BIN_FILENAME} && rm ${BIN_FILENAME}"
done
@ -32,4 +28,4 @@ if [[ "${FAILURES}" != "" ]]; then
echo ""
echo "${SCRIPT_NAME} failed on: ${FAILURES}"
exit 1
fi
fi

View File

@ -1,9 +1,7 @@
export BASH_CONF="bash_profile"
export LSCOLORS="gxfxcxdxbxegedabagacad"
export CLICOLOR=1
export TERM="xterm-256color"
PS1='\[\e[0;33m\]\u\[\e[0m\]@\[\e[0;32m\]\h\[\e[0m\]:\[\033[01;34m\]\W\[\033[00m\]$(git_info)\[\033[00m\]\n\[\033[1;31m\]\$ \[\033[00m\]'
PS1='\[\e[0;33m\]\u\[\e[0m\]@\[\e[0;32m\]\h\[\e[0m\]:\[\033[01;34m\]\w\[\033[00m\]$(git_info)\[\033[00m\]\n\[\033[1;31m\]\$ \[\033[00m\]'
# functions
function git_info {
@ -31,7 +29,3 @@ fi
echo " ($(tput bold)${ref#refs/heads/}$uc$us$ut$st$(tput sgr0)$(tput setaf 254))";
# echo "(${ref#refs/heads/})";
}
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<!DOCTYPE html><html><head><link rel="stylesheet" href="index.6999253a.css"><title>{{.AppName}}</title><style>body::-webkit-scrollbar,div::-webkit-scrollbar,html::-webkit-scrollbar{display:none;width:0}body,html{margin:0;overflow:hidden;padding:0}div#terminal{height:100%;left:0;position:absolute;top:0;width:100%}div#terminal div{height:100%}.xterm-screen,.xterm-viewport{height:100%;margin:0;padding:0}</style></head><body> <div id="terminal"></div> <script type="module" src="index.52560dc1.js"></script> </body></html>
<!DOCTYPE html><html><head><link rel="stylesheet" href="index.6999253a.css"><title>{{.AppName}}</title><style>body::-webkit-scrollbar,div::-webkit-scrollbar,html::-webkit-scrollbar{display:none;width:0}body,html{margin:0;overflow:hidden;padding:0}div#terminal{height:100%;left:0;position:absolute;top:0;width:100%}div#terminal div{height:100%}.xterm-screen,.xterm-viewport{height:100%;margin:0;padding:0}</style></head><body> <div id="terminal"></div> <script type="module" src="index.a2a226ad.js"></script> </body></html>