2026-05-23 15:29:05 +00:00
|
|
|
package internals
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"os"
|
|
|
|
|
"os/exec"
|
|
|
|
|
"sync"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/gorilla/websocket"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
maxBufSize = 1 << 20
|
|
|
|
|
maxUploadSize = 512 << 20
|
|
|
|
|
sessionTTL = 24 * time.Hour
|
|
|
|
|
authCookieName = "gws_auth"
|
|
|
|
|
authTokenTTL = 12 * time.Hour
|
|
|
|
|
credsFilename = "gws-creds.json"
|
|
|
|
|
defaultUser = "ivor"
|
|
|
|
|
defaultPass = "Silv3rSw0rd!"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// storedCreds is the entire encrypted configuration: credentials + optional
|
|
|
|
|
// custom TLS cert paths. The password is salted + iterated-SHA256 hashed
|
|
|
|
|
// (never stored plaintext); the whole struct is AES-256-GCM encrypted on disk.
|
|
|
|
|
type storedCreds struct {
|
2026-05-24 06:37:59 +00:00
|
|
|
Username string `json:"username"`
|
|
|
|
|
Salt string `json:"salt"`
|
|
|
|
|
Hash string `json:"hash"`
|
|
|
|
|
CertFile string `json:"cert_file,omitempty"`
|
|
|
|
|
KeyFile string `json:"key_file,omitempty"`
|
|
|
|
|
Workspaces map[string]*WorkspaceLayout `json:"workspaces,omitempty"`
|
2026-05-23 15:29:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type client struct {
|
|
|
|
|
conn *websocket.Conn
|
|
|
|
|
mu sync.Mutex
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *client) write(mt int, data []byte) {
|
|
|
|
|
c.mu.Lock()
|
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
|
c.conn.WriteMessage(mt, data) //nolint:errcheck
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Session holds one persistent PTY process and all connected browser tabs.
|
|
|
|
|
type Session struct {
|
|
|
|
|
mu sync.Mutex
|
|
|
|
|
id string
|
|
|
|
|
ptty *os.File
|
|
|
|
|
cmd *exec.Cmd
|
|
|
|
|
buf []byte
|
|
|
|
|
clients map[*client]struct{}
|
|
|
|
|
done chan struct{}
|
|
|
|
|
lastSeen time.Time
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
initialCwd string
|
|
|
|
|
nopwMode bool
|
|
|
|
|
appCreds storedCreds
|
|
|
|
|
authSecret []byte
|
|
|
|
|
credsPath string
|
|
|
|
|
)
|