File: prompter.go

package info (click to toggle)
pat 0.19.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,296 kB
  • sloc: javascript: 3,891; sh: 124; makefile: 11
file content (107 lines) | stat: -rw-r--r-- 3,169 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package cli

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/la5nta/pat/app"

	"github.com/howeyc/gopass"
)

type TerminalPrompter struct{}

func (t TerminalPrompter) Prompt(prompt app.Prompt) {
	q := make(chan struct{}, 1)
	defer close(q)
	go func() {
		select {
		case <-prompt.Done():
			fmt.Printf(" Prompt Aborted - Press ENTER to continue...")
		case <-q:
			return
		}
	}()

	switch prompt.Kind {
	case app.PromptKindMultiSelect:
		fmt.Println(prompt.Message + ":")
		answers := map[string]app.PromptOption{}
		for idx, opt := range prompt.Options {
			answers[strconv.Itoa(idx+1)] = opt
			answers[opt.Value] = opt
			fmt.Printf("  %d: %s (%s)\n", idx+1, opt.Desc, opt.Value)
		}

		fmt.Printf("Select [1-%d, ...]: ", len(prompt.Options))
		ans := strings.FieldsFunc(readLine(), SplitFunc)
		var selected []string
		for _, str := range ans {
			opt, ok := answers[str]
			if !ok {
				log.Printf("Skipping unknown option %q", str)
				continue
			}
			selected = append(selected, opt.Value)
		}
		prompt.Respond(strings.Join(selected, ","), nil)
	case app.PromptKindPassword:
		passwd, err := gopass.GetPasswdPrompt(prompt.Message+": ", true, os.Stdin, os.Stdout)
		prompt.Respond(string(passwd), err)
	case app.PromptKindBusyChannel:
		fmt.Println(prompt.Message + ":")
		for prompt.Err() == nil {
			fmt.Printf("Answer [c(ontinue), a(bort)]: ")
			switch ans := readLine(); strings.TrimSpace(ans) {
			case "c", "continue":
				prompt.Respond("continue", nil)
				return
			case "a", "abort":
				prompt.Respond("abort", nil)
				return
			}
		}
	case app.PromptKindPreAccountActivation:
		fmt.Println()
		fmt.Println("WARNING: We were unable to confirm that your Winlink account is active.")
		fmt.Println("If you continue, an over-the-air activation will be initiated and you will receive a message with a new password.")
		fmt.Println("This password will be the only key to your account. If you lose it, it cannot be recovered.")
		fmt.Printf("It is strongly recommended to use '%s init' or the web gui to create your account before proceeding.\n", os.Args[0])
		fmt.Println()
		for prompt.Err() == nil {
			fmt.Printf("Answer [c(ontinue), a(bort)]: ")
			switch ans := readLine(); strings.TrimSpace(ans) {
			case "c", "continue":
				prompt.Respond("confirmed", nil)
				return
			case "a", "abort":
				prompt.Respond("abort", nil)
				return
			}
		}
	case app.PromptKindAccountActivation:
		fmt.Println()
		fmt.Println("WARNING:")
		fmt.Println("You are about to receive a computer-generated password for your new Winlink account.")
		fmt.Println("Once you download this message, the password inside is the only key to your account.")
		fmt.Println("If you lose it, it cannot be recovered.")
		fmt.Println()
		fmt.Println("Are you ready to receive this message and save the password securely right now?")
		for prompt.Err() == nil {
			fmt.Printf("Answer (yes/no): ")
			switch ans := readLine(); strings.TrimSpace(ans) {
			case "y", "yes":
				prompt.Respond("accept", nil)
				return
			case "n", "no":
				prompt.Respond("defer", nil)
				return
			}
		}
	default:
		log.Printf("Prompt kind %q not implemented", prompt.Kind)
	}
}