Improve terminal handling and make server arg more helpful
This commit is contained in:
@@ -1,14 +1,17 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
@@ -196,7 +199,7 @@ func credReadCache(serverURL string, logf func(string, ...interface{})) (*ExecCr
|
|||||||
return &ec, true
|
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()
|
dir := credCacheDir()
|
||||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||||
logf("cache: failed to create dir: %v", err)
|
logf("cache: failed to create dir: %v", err)
|
||||||
@@ -218,10 +221,7 @@ func credWriteCache(serverURL string, ec *ExecCredential, logf func(string, ...i
|
|||||||
// ── Kerberos helpers ───────────────────────────────────────────────────────────
|
// ── Kerberos helpers ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func krb5ConfigPath() string {
|
func krb5ConfigPath() string {
|
||||||
if v := os.Getenv("KRB5_CONFIG"); v != "" {
|
return cmp.Or(os.Getenv("KRB5_CONFIG"), "/etc/krb5.conf")
|
||||||
return v
|
|
||||||
}
|
|
||||||
return "/etc/krb5.conf"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ccachePath returns the path to the active Kerberos credential cache.
|
// ccachePath returns the path to the active Kerberos credential cache.
|
||||||
@@ -238,14 +238,31 @@ func ccachePath() string {
|
|||||||
// ── Password prompt ────────────────────────────────────────────────────────────
|
// ── Password prompt ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
func credPromptPassword(username string) (string, error) {
|
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(
|
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")
|
"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()))
|
oldState, err := term.MakeRaw(int(terminal.Fd()))
|
||||||
fmt.Fprintln(os.Stderr) // newline after the hidden input
|
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 {
|
if err != nil {
|
||||||
return "", fmt.Errorf("reading password: %w", err)
|
return "", fmt.Errorf("reading password: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
11
main.go
11
main.go
@@ -253,6 +253,17 @@ Debug output goes to stderr (kubectl surfaces this to the terminal):
|
|||||||
return fmt.Errorf("--server is required")
|
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{}) {
|
logf := func(format string, a ...interface{}) {
|
||||||
if debugFlag {
|
if debugFlag {
|
||||||
fmt.Fprintf(os.Stderr, "[ward] "+format+"\n", a...)
|
fmt.Fprintf(os.Stderr, "[ward] "+format+"\n", a...)
|
||||||
|
|||||||
Reference in New Issue
Block a user