mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-23 08:47:47 +02:00
Move SSH askpass implementation into kitten
This commit is contained in:
118
tools/cmd/ssh/askpass.go
Normal file
118
tools/cmd/ssh/askpass.go
Normal file
@@ -0,0 +1,118 @@
|
||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kitty/tools/cli"
|
||||
"kitty/tools/tty"
|
||||
"kitty/tools/utils/shm"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
func fatal(err error) {
|
||||
cli.ShowError(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func trigger_ask(name string) {
|
||||
term, err := tty.OpenControllingTerm()
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
defer term.Close()
|
||||
_, err = term.WriteString("\x1bP@kitty-ask|" + name + "\x1b\\")
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func RunSSHAskpass() {
|
||||
msg := os.Args[len(os.Args)-1]
|
||||
prompt := os.Getenv("SSH_ASKPASS_PROMPT")
|
||||
is_confirm := prompt == "confirm"
|
||||
q_type := "get_line"
|
||||
if is_confirm {
|
||||
q_type = "confirm"
|
||||
}
|
||||
is_fingerprint_check := strings.Contains(msg, "(yes/no/[fingerprint])")
|
||||
q := map[string]any{
|
||||
"message": msg,
|
||||
"type": q_type,
|
||||
"is_password": !is_fingerprint_check,
|
||||
}
|
||||
data, err := json.Marshal(q)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
shm, err := shm.CreateTemp("askpass-*", uint64(len(data)+32))
|
||||
if err != nil {
|
||||
fatal(fmt.Errorf("Failed to create SHM file with error: %w", err))
|
||||
}
|
||||
defer shm.Close()
|
||||
defer shm.Unlink()
|
||||
|
||||
shm.Slice()[0] = 0
|
||||
binary.BigEndian.PutUint32(shm.Slice()[1:], uint32(len(data)))
|
||||
copy(shm.Slice()[5:], data)
|
||||
err = shm.Flush()
|
||||
if err != nil {
|
||||
fatal(fmt.Errorf("Failed to flush SHM file with error: %w", err))
|
||||
}
|
||||
trigger_ask(shm.Name())
|
||||
buf := []byte{0}
|
||||
for {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
_, err = shm.Seek(0, os.SEEK_SET)
|
||||
if err != nil {
|
||||
fatal(fmt.Errorf("Failed to seek into SHM file while waiting for response with error: %w", err))
|
||||
}
|
||||
_, err = shm.Read(buf)
|
||||
if err != nil {
|
||||
fatal(fmt.Errorf("Failed to read from SHM file while waiting for response with error: %w", err))
|
||||
}
|
||||
if buf[0] == 1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
data, err = shm.ReadWithSize()
|
||||
if err != nil {
|
||||
fatal(fmt.Errorf("Failed to read response data from SHM file with error: %w", err))
|
||||
}
|
||||
response := ""
|
||||
if is_confirm {
|
||||
var ok bool
|
||||
err = json.Unmarshal(data, &ok)
|
||||
if err != nil {
|
||||
fatal(fmt.Errorf("Failed to parse response data: %#v with error: %w", string(data), err))
|
||||
}
|
||||
response = "no"
|
||||
if ok {
|
||||
response = "yes"
|
||||
}
|
||||
} else {
|
||||
err = json.Unmarshal(data, &response)
|
||||
if err != nil {
|
||||
fatal(fmt.Errorf("Failed to parse response data: %#v with error: %w", string(data), err))
|
||||
}
|
||||
if is_fingerprint_check {
|
||||
response = strings.ToLower(response)
|
||||
if response == "y" {
|
||||
response = "yes"
|
||||
} else if response == "n" {
|
||||
response = "no"
|
||||
}
|
||||
}
|
||||
}
|
||||
if response != "" {
|
||||
fmt.Println(response)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user