askpass.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package ssh
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "os"
  7. "strings"
  8. "time"
  9. "kitty/tools/cli"
  10. "kitty/tools/tty"
  11. "kitty/tools/utils/shm"
  12. )
  13. var _ = fmt.Print
  14. func fatal(err error) {
  15. cli.ShowError(err)
  16. os.Exit(1)
  17. }
  18. func trigger_ask(name string) {
  19. term, err := tty.OpenControllingTerm()
  20. if err != nil {
  21. fatal(err)
  22. }
  23. defer term.Close()
  24. _, err = term.WriteString("\x1bP@kitty-ask|" + name + "\x1b\\")
  25. if err != nil {
  26. fatal(err)
  27. }
  28. }
  29. func RunSSHAskpass() {
  30. msg := os.Args[len(os.Args)-1]
  31. prompt := os.Getenv("SSH_ASKPASS_PROMPT")
  32. is_confirm := prompt == "confirm"
  33. q_type := "get_line"
  34. if is_confirm {
  35. q_type = "confirm"
  36. }
  37. is_fingerprint_check := strings.Contains(msg, "(yes/no/[fingerprint])")
  38. q := map[string]any{
  39. "message": msg,
  40. "type": q_type,
  41. "is_password": !is_fingerprint_check,
  42. }
  43. data, err := json.Marshal(q)
  44. if err != nil {
  45. fatal(err)
  46. }
  47. data_shm, err := shm.CreateTemp("askpass-*", uint64(len(data)+32))
  48. if err != nil {
  49. fatal(fmt.Errorf("Failed to create SHM file with error: %w", err))
  50. }
  51. defer data_shm.Close()
  52. defer func() { _ = data_shm.Unlink() }()
  53. data_shm.Slice()[0] = 0
  54. if err = shm.WriteWithSize(data_shm, data, 1); err != nil {
  55. fatal(fmt.Errorf("Failed to write to SHM file with error: %w", err))
  56. }
  57. if err = data_shm.Flush(); err != nil {
  58. fatal(fmt.Errorf("Failed to flush SHM file with error: %w", err))
  59. }
  60. trigger_ask(data_shm.Name())
  61. for {
  62. time.Sleep(50 * time.Millisecond)
  63. if data_shm.Slice()[0] == 1 {
  64. break
  65. }
  66. }
  67. data, err = shm.ReadWithSize(data_shm, 1)
  68. if err != nil {
  69. fatal(fmt.Errorf("Failed to read from SHM file with error: %w", err))
  70. }
  71. response := ""
  72. if is_confirm {
  73. var ok bool
  74. err = json.Unmarshal(data, &ok)
  75. if err != nil {
  76. fatal(fmt.Errorf("Failed to parse response data: %#v with error: %w", string(data), err))
  77. }
  78. response = "no"
  79. if ok {
  80. response = "yes"
  81. }
  82. } else {
  83. err = json.Unmarshal(data, &response)
  84. if err != nil {
  85. fatal(fmt.Errorf("Failed to parse response data: %#v with error: %w", string(data), err))
  86. }
  87. if is_fingerprint_check {
  88. response = strings.ToLower(response)
  89. if response == "y" {
  90. response = "yes"
  91. } else if response == "n" {
  92. response = "no"
  93. }
  94. }
  95. }
  96. if response != "" {
  97. fmt.Println(response)
  98. }
  99. }