added tabs to terminal, split single .go to separate files
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
package internals
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Run is the application entry point, called from main().
|
||||
func Run() {
|
||||
addr := flag.String("addr", "127.0.0.1:5000", "listen address")
|
||||
nopw := flag.Bool("nopw", false, "disable password authentication")
|
||||
setlogin := flag.String("setlogin", "", "set login username (next arg is password)")
|
||||
certFlag := flag.String("cert", "", "set custom TLS certificate PEM file (stored encrypted)")
|
||||
cetkeyFlag := flag.String("certkey", "", "set custom TLS private key PEM file")
|
||||
certreset := flag.Bool("certreset", false, "remove stored custom certificate, revert to self-signed")
|
||||
flag.Parse()
|
||||
|
||||
initialCwd, _ = os.Getwd()
|
||||
|
||||
// Credentials file lives next to the executable.
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
exe = "."
|
||||
}
|
||||
credsPath = filepath.Join(filepath.Dir(exe), credsFilename)
|
||||
|
||||
// ── -certreset: remove stored cert paths ─────────────────────
|
||||
if *certreset {
|
||||
c := loadCreds()
|
||||
c.CertFile = ""
|
||||
c.KeyFile = ""
|
||||
if err := saveCreds(c); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error saving config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("custom certificate removed — will use self-signed on next start")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// ── -cert / -certkey: store custom cert paths (encrypted) ─────
|
||||
if *certFlag != "" {
|
||||
keyPath := *cetkeyFlag
|
||||
if keyPath == "" {
|
||||
keyPath = *certFlag // allow combined cert+key PEM
|
||||
}
|
||||
// Validate the files are readable and form a valid keypair before storing.
|
||||
if _, err := tls.LoadX509KeyPair(*certFlag, keyPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "certificate error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
c := loadCreds()
|
||||
c.CertFile = *certFlag
|
||||
c.KeyFile = keyPath
|
||||
if err := saveCreds(c); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error saving config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("custom certificate stored")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// ── -setlogin username password ────────────────────────────────
|
||||
if *setlogin != "" {
|
||||
args := flag.Args()
|
||||
if len(args) < 1 {
|
||||
fmt.Fprintln(os.Stderr, "usage: -setlogin <username> <password>")
|
||||
os.Exit(1)
|
||||
}
|
||||
existing := loadCreds() // preserve cert paths across credential changes
|
||||
salt := newSalt()
|
||||
c := storedCreds{
|
||||
Username: *setlogin,
|
||||
Salt: salt,
|
||||
Hash: hashPassword(args[0], salt),
|
||||
CertFile: existing.CertFile,
|
||||
KeyFile: existing.KeyFile,
|
||||
}
|
||||
if err := saveCreds(c); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error saving credentials: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("credentials saved user=%q file=%s\n", *setlogin, credsPath)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
nopwMode = *nopw
|
||||
appCreds = loadCreds()
|
||||
initAuthSecret()
|
||||
|
||||
if nopwMode {
|
||||
fmt.Println("auth: DISABLED (-nopw)")
|
||||
} else {
|
||||
fmt.Printf("auth: enabled user=%q creds=%s\n", appCreds.Username, credsPath)
|
||||
}
|
||||
|
||||
// Reap idle sessions.
|
||||
go func() {
|
||||
t := time.NewTicker(10 * time.Minute)
|
||||
defer t.Stop()
|
||||
for range t.C {
|
||||
sessionsMu.Lock()
|
||||
for id, s := range sessions {
|
||||
s.mu.Lock()
|
||||
idle := time.Since(s.lastSeen)
|
||||
s.mu.Unlock()
|
||||
if idle > sessionTTL {
|
||||
s.ptty.Close()
|
||||
delete(sessions, id)
|
||||
}
|
||||
}
|
||||
sessionsMu.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
// Load TLS certificate — custom (stored encrypted) or auto-generated.
|
||||
// The cert path is never printed to avoid leaking it in logs or terminal history.
|
||||
var tlsCert tls.Certificate
|
||||
if appCreds.CertFile != "" && appCreds.KeyFile != "" {
|
||||
if cert, err := tls.LoadX509KeyPair(appCreds.CertFile, appCreds.KeyFile); err == nil {
|
||||
tlsCert = cert
|
||||
fmt.Println("TLS: custom certificate")
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, "TLS: custom certificate failed to load, falling back to self-signed")
|
||||
tlsCert, _ = generateSelfSignedCert()
|
||||
}
|
||||
} else {
|
||||
tlsCert, _ = generateSelfSignedCert()
|
||||
fmt.Println("TLS: self-signed (auto-generated)")
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", handleIndex)
|
||||
mux.HandleFunc("/s/", handleShell)
|
||||
mux.HandleFunc("/ws/", handleWS)
|
||||
mux.HandleFunc("/auth", handleAuth)
|
||||
mux.HandleFunc("/upload", handleUpload)
|
||||
mux.HandleFunc("/download", handleDownload)
|
||||
mux.HandleFunc("/favicon.svg", handleFavicon)
|
||||
mux.HandleFunc("/static/app.css", handleStaticCSS)
|
||||
mux.HandleFunc("/static/app.js", handleStaticJS)
|
||||
|
||||
ln, _ := net.Listen("tcp", *addr)
|
||||
fmt.Printf("Go Web Shell https://%s\n", *addr)
|
||||
fmt.Println(" / new session (URL stays clean)")
|
||||
fmt.Println(" /s/<id> reconnect to a specific session")
|
||||
|
||||
// Suppress the noisy "TLS handshake error" lines that appear whenever a
|
||||
// browser rejects the self-signed certificate during the initial TLS dance.
|
||||
srv := &http.Server{
|
||||
Handler: mux,
|
||||
ErrorLog: log.New(tlsHandshakeFilter{log.Writer()}, "", log.LstdFlags),
|
||||
}
|
||||
srv.Serve(tls.NewListener(ln, &tls.Config{Certificates: []tls.Certificate{tlsCert}})) //nolint:errcheck
|
||||
}
|
||||
Reference in New Issue
Block a user