forked from grafana/k6
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathform_fields.go
130 lines (113 loc) · 3.25 KB
/
form_fields.go
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package ui
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"strings"
"golang.org/x/term"
)
// Verify that the fields implement the interface
var (
_ Field = StringField{}
_ Field = PasswordField{}
)
// StringField is just a simple field for reading cleartext strings
type StringField struct {
Key string
Label string
Default string
// Length constraints.
Min, Max int
}
// GetKey returns the field's key
func (f StringField) GetKey() string {
return f.Key
}
// GetLabel returns the field's label
func (f StringField) GetLabel() string {
return f.Label
}
// GetLabelExtra returns the field's default value
func (f StringField) GetLabelExtra() string {
return f.Default
}
// GetContents simply reads a string in cleartext from the supplied reader
// It's compllicated and doesn't use t he bufio utils because we can't read ahead
// of the newline and consume more of the stdin, because we'll mess up the next form field
func (f StringField) GetContents(r io.Reader) (string, error) {
result := make([]byte, 0, 20)
buf := make([]byte, 1)
for {
n, err := io.ReadAtLeast(r, buf, 1)
if err != nil {
return string(result), err
}
if n != 1 {
// Shouldn't happen, but just in case
return string(result), errors.New("unexpected input when reading string field")
} else if buf[0] == '\n' {
return string(result), nil
}
result = append(result, buf[0])
}
}
// Clean trims the spaces in the string and checks for min and max length
func (f StringField) Clean(s string) (string, error) {
s = strings.TrimSpace(s)
if f.Min != 0 && len(s) < f.Min {
return "", fmt.Errorf("invalid input, min length is %d", f.Min)
}
if f.Max != 0 && len(s) > f.Max {
return "", fmt.Errorf("invalid input, max length is %d", f.Max)
}
if s == "" {
s = f.Default
}
return s, nil
}
// PasswordField masks password input
type PasswordField struct {
Key string
Label string
Min int
}
// GetKey returns the field's key
func (f PasswordField) GetKey() string {
return f.Key
}
// GetLabel returns the field's label
func (f PasswordField) GetLabel() string {
return f.Label
}
// GetLabelExtra doesn't return anything so we don't expose the current password
func (f PasswordField) GetLabelExtra() string {
return ""
}
// GetContents simply reads a string in cleartext from the supplied reader
func (f PasswordField) GetContents(r io.Reader) (string, error) {
stdin, ok := r.(*os.File) //nolint:forbidigo
if !ok {
return "", errors.New("cannot read password from the supplied terminal")
}
password, err := term.ReadPassword(int(stdin.Fd()))
if err != nil {
// Possibly running on Cygwin/mintty which doesn't emulate
// pseudo terminals properly, so fallback to plain text input.
// Note that passwords will be echoed if this is the case.
// See https://github.com/mintty/mintty/issues/56
// A workaround is to use winpty or mintty compiled with
// Cygwin >=3.1.0 which supports the new ConPTY Windows API.
bufR := bufio.NewReader(r)
password, err = bufR.ReadBytes('\n')
}
return string(password), err
}
// Clean just checks if the minimum length is exceeded, it doesn't trim the string!
func (f PasswordField) Clean(s string) (string, error) {
if f.Min != 0 && len(s) < f.Min {
return "", fmt.Errorf("invalid input, min length is %d", f.Min)
}
return s, nil
}