Improve terminal handling and make server arg more helpful

This commit is contained in:
2026-03-26 14:03:09 +01:00
parent cd56349517
commit 24f1fd0477
2 changed files with 38 additions and 10 deletions

View File

@@ -1,14 +1,17 @@
package main
import (
"cmp"
"crypto/sha256"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"golang.org/x/term"
@@ -196,7 +199,7 @@ func credReadCache(serverURL string, logf func(string, ...interface{})) (*ExecCr
return &ec, true
}
func credWriteCache(serverURL string, ec *ExecCredential, logf func(string, ...interface{})) {
func credWriteCache(serverURL string, ec *ExecCredential, logf func(string, ...any)) {
dir := credCacheDir()
if err := os.MkdirAll(dir, 0700); err != nil {
logf("cache: failed to create dir: %v", err)
@@ -218,10 +221,7 @@ func credWriteCache(serverURL string, ec *ExecCredential, logf func(string, ...i
// ── Kerberos helpers ───────────────────────────────────────────────────────────
func krb5ConfigPath() string {
if v := os.Getenv("KRB5_CONFIG"); v != "" {
return v
}
return "/etc/krb5.conf"
return cmp.Or(os.Getenv("KRB5_CONFIG"), "/etc/krb5.conf")
}
// ccachePath returns the path to the active Kerberos credential cache.
@@ -238,14 +238,31 @@ func ccachePath() string {
// ── Password prompt ────────────────────────────────────────────────────────────
func credPromptPassword(username string) (string, error) {
if !term.IsTerminal(int(os.Stdin.Fd())) {
terminal, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
return "", fmt.Errorf(
"stdin is not a terminal and $WARD_PASSWORD is not set\n" +
"cannot open terminal and $WARD_PASSWORD is not set\n" +
"hint: run 'kinit' for Kerberos auth, or set $WARD_PASSWORD for non-interactive use")
}
fmt.Fprintf(os.Stderr, "Password for %s: ", username)
pw, err := term.ReadPassword(int(os.Stdin.Fd()))
fmt.Fprintln(os.Stderr) // newline after the hidden input
oldState, err := term.MakeRaw(int(terminal.Fd()))
if err != nil {
return "", fmt.Errorf("setting terminal raw mode: %w", err)
}
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
go func() {
<-sigCh
term.Restore(int(terminal.Fd()), oldState)
os.Exit(1)
}()
fmt.Fprintf(terminal, "Password for %s: ", username)
pw, err := term.ReadPassword(int(terminal.Fd()))
fmt.Fprintf(terminal, "\r\n") // newline after the hidden input
signal.Stop(sigCh)
term.Restore(int(terminal.Fd()), oldState)
if err != nil {
return "", fmt.Errorf("reading password: %w", err)
}

11
main.go
View File

@@ -253,6 +253,17 @@ Debug output goes to stderr (kubectl surfaces this to the terminal):
return fmt.Errorf("--server is required")
}
// prepend https if no scheme is given, for user convenience
if !strings.Contains(server, "://") {
server = "https://" + server
}
// append port 8443 if no port is given
parts := strings.Split(server, ":")
if len(parts) == 2 {
server += ":8443"
}
logf := func(format string, a ...interface{}) {
if debugFlag {
fmt.Fprintf(os.Stderr, "[ward] "+format+"\n", a...)