/
import.go
152 lines (125 loc) · 3.35 KB
/
import.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package cmd
import (
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/google/shlex"
"github.com/urfave/cli"
"github.com/manifoldco/torus-cli/apitypes"
"github.com/manifoldco/torus-cli/errs"
"github.com/manifoldco/torus-cli/hints"
)
type secretPair struct {
key string
value string
}
func init() {
c := cli.Command{
Name: "import",
Usage: "Import multiple secrets from an env file",
ArgsUsage: "[path to file] or use stdin redirection (e.g. `torus import < secrets.env`)",
Category: "SECRETS",
Flags: setUnsetFlags,
Action: chain(
ensureDaemon, ensureSession, loadDirPrefs, loadPrefDefaults,
setSliceDefaults, importCmd,
),
}
Cmds = append(Cmds, c)
}
func importCmd(ctx *cli.Context) error {
args := ctx.Args()
secrets, err := importSecretFile(args)
if err != nil {
return errs.NewUsageExitError(err.Error(), ctx)
}
path, err := determinePathFromFlags(ctx)
if err != nil {
return err
}
makers := valueMakers{}
for _, secret := range secrets {
makers[secret.key] = func(value string) valueMaker {
return func() *apitypes.CredentialValue {
return apitypes.NewStringCredentialValue(value)
}
}(secret.value)
}
s, p := spinner("Attempting to set credentials")
s.Start()
creds, err := setCredentials(ctx, path, makers, p)
s.Stop()
if err != nil {
return errs.NewErrorExitError("Could not set credentials.", err)
}
fmt.Println()
for _, cred := range creds {
name := (*cred.Body).GetName()
pe := (*cred.Body).GetPathExp()
fmt.Printf("Credential %s has been set at %s/%s\n", name, displayPathExp(pe), name)
}
hints.Display(hints.View, hints.Set)
return nil
}
// importSecretFile returns a list of secret pairs either reading a file
// provided or from the standard input. It returns an error if there is a
// problem parsing secrets or stdin fails to read.
func importSecretFile(args []string) ([]secretPair, error) {
switch len(args) {
case 0:
return readStdin()
case 1:
return readFile(args[0])
default:
return nil, errors.New("Too many arguments were provided")
}
}
func readFile(filename string) ([]secretPair, error) {
flags := os.O_RDONLY
f, err := os.OpenFile(filename, flags, 0644)
if os.IsNotExist(err) {
return nil, fmt.Errorf("%s does not exist", filename)
}
if err != nil {
return nil, fmt.Errorf("Error reading %s file %s", filename, err)
}
defer f.Close()
return scanSecrets(f)
}
func readStdin() ([]secretPair, error) {
stat, err := os.Stdin.Stat()
if err != nil {
return nil, fmt.Errorf("Could not from stdin. %s", err)
}
if (stat.Mode() & os.ModeNamedPipe) != 0 {
return nil, errors.New("Could not read from piped input")
}
return scanSecrets(os.Stdin)
}
// scanSecrets reads secret pairs using an UNIX shell-like syntax parser. Empty
// lines and comments are ignored.
func scanSecrets(r io.Reader) ([]secretPair, error) {
var pairs []secretPair
lexer := shlex.NewLexer(r)
for {
word, err := lexer.Next()
if err != nil {
if err == io.EOF {
return pairs, nil
}
return nil, fmt.Errorf("Error reading input file. %s", err)
}
tokens := strings.SplitN(word, "=", 2)
if len(tokens) < 2 {
return nil, fmt.Errorf("Error parsing secret %q", word)
}
key := tokens[0]
value := tokens[1]
if key == "" || value == "" {
return nil, fmt.Errorf("Error parsing secret %q", word)
}
pairs = append(pairs, secretPair{key: key, value: value})
}
}