Skip to content

Commit 7e47232

Browse files
committed
args struct
1 parent d5a4e01 commit 7e47232

File tree

1 file changed

+105
-75
lines changed

1 file changed

+105
-75
lines changed

cmd/enpasscli/main.go

Lines changed: 105 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import (
66
"os"
77
"path/filepath"
88
"runtime"
9-
s "sort"
9+
"sort"
10+
"strconv"
1011
"strings"
1112

1213
"github.com/hazcod/enpass-cli/pkg/clipboard"
@@ -17,27 +18,61 @@ import (
1718
)
1819

1920
const (
20-
defaultLogLevel = logrus.InfoLevel
21-
cmdVersion = "version"
22-
cmdHelp = "help"
23-
cmdInit = "init"
24-
cmdList = "list"
25-
cmdShow = "show"
26-
cmdCopy = "copy"
27-
cmdPass = "pass"
21+
// commands
22+
cmdVersion = "version"
23+
cmdHelp = "help"
24+
cmdInit = "init"
25+
cmdList = "list"
26+
cmdShow = "show"
27+
cmdCopy = "copy"
28+
cmdPass = "pass"
29+
// defaults
30+
defaultLogLevel = logrus.InfoLevel
31+
pinMinLength = 8
32+
pinDefaultKdfIterCount = 100000
2833
)
2934

3035
var (
3136
// overwritten by go build
3237
version = "dev"
33-
// enables prompts
34-
interactive = true
35-
// complete command list
36-
commands = map[string]struct{}{cmdVersion: {}, cmdHelp: {}, cmdInit: {}, cmdList: {}, cmdShow: {}, cmdCopy: {}, cmdPass: {}}
38+
// set of all commands
39+
commands = map[string]struct{}{cmdVersion: {}, cmdHelp: {}, cmdInit: {}, cmdList: {},
40+
cmdShow: {}, cmdCopy: {}, cmdPass: {}}
3741
)
3842

39-
func prompt(logger *logrus.Logger, msg string) string {
40-
if interactive {
43+
type Args struct {
44+
command string
45+
// params
46+
filters []string
47+
// flags
48+
vaultPath *string
49+
cardType *string
50+
keyFilePath *string
51+
logLevelStr *string
52+
nonInteractive *bool
53+
pinEnable *bool
54+
sort *bool
55+
trashed *bool
56+
clipboardPrimary *bool
57+
}
58+
59+
func (args *Args) parse() {
60+
args.vaultPath = flag.String("vault", "", "Path to your Enpass vault.")
61+
args.cardType = flag.String("type", "password", "The type of your card. (password, ...)")
62+
args.keyFilePath = flag.String("keyfile", "", "Path to your Enpass vault keyfile.")
63+
args.logLevelStr = flag.String("log", defaultLogLevel.String(), "The log level from debug (5) to error (1).")
64+
args.nonInteractive = flag.Bool("nonInteractive", false, "Disable prompts and fail instead.")
65+
args.pinEnable = flag.Bool("pin", false, "Enable PIN.")
66+
args.sort = flag.Bool("sort", false, "Sort the output by title and username of the 'list' and 'show' command.")
67+
args.trashed = flag.Bool("trashed", false, "Show trashed items in the 'list' and 'show' command.")
68+
args.clipboardPrimary = flag.Bool("clipboardPrimary", false, "Use primary X selection instead of clipboard for the 'copy' command.")
69+
flag.Parse()
70+
args.command = strings.ToLower(flag.Arg(0))
71+
args.filters = flag.Args()[1:]
72+
}
73+
74+
func prompt(logger *logrus.Logger, args *Args, msg string) string {
75+
if !*args.nonInteractive {
4176
if response, err := ask.HiddenAsk("Enter " + msg + ": "); err != nil {
4277
logger.WithError(err).Fatal("could not prompt for " + msg)
4378
} else {
@@ -59,25 +94,25 @@ func printHelp() {
5994

6095
func sortEntries(cards []enpass.Card) {
6196
// Sort by username preserving original order
62-
s.SliceStable(cards, func(i, j int) bool {
97+
sort.SliceStable(cards, func(i, j int) bool {
6398
return strings.ToLower(cards[i].Subtitle) < strings.ToLower(cards[j].Subtitle)
6499
})
65100
// Sort by title, preserving username order
66-
s.SliceStable(cards, func(i, j int) bool {
101+
sort.SliceStable(cards, func(i, j int) bool {
67102
return strings.ToLower(cards[i].Title) < strings.ToLower(cards[j].Title)
68103
})
69104
}
70105

71-
func listEntries(logger *logrus.Logger, vault *enpass.Vault, cardType string, sort bool, trashed bool, filters []string) {
72-
cards, err := vault.GetEntries(cardType, filters)
106+
func listEntries(logger *logrus.Logger, vault *enpass.Vault, args *Args) {
107+
cards, err := vault.GetEntries(*args.cardType, args.filters)
73108
if err != nil {
74109
logger.WithError(err).Fatal("could not retrieve cards")
75110
}
76-
if sort {
111+
if *args.sort {
77112
sortEntries(cards)
78113
}
79114
for _, card := range cards {
80-
if card.IsTrashed() && !trashed {
115+
if card.IsTrashed() && !*args.trashed {
81116
continue
82117
}
83118
logger.Printf(
@@ -91,16 +126,16 @@ func listEntries(logger *logrus.Logger, vault *enpass.Vault, cardType string, so
91126
}
92127
}
93128

94-
func showEntries(logger *logrus.Logger, vault *enpass.Vault, cardType string, sort bool, trashed bool, filters []string) {
95-
cards, err := vault.GetEntries(cardType, filters)
129+
func showEntries(logger *logrus.Logger, vault *enpass.Vault, args *Args) {
130+
cards, err := vault.GetEntries(*args.cardType, args.filters)
96131
if err != nil {
97132
logger.WithError(err).Fatal("could not retrieve cards")
98133
}
99-
if sort {
134+
if *args.sort {
100135
sortEntries(cards)
101136
}
102137
for _, card := range cards {
103-
if card.IsTrashed() && !trashed {
138+
if card.IsTrashed() && !*args.trashed {
104139
continue
105140
}
106141
password, err := card.Decrypt()
@@ -122,8 +157,8 @@ func showEntries(logger *logrus.Logger, vault *enpass.Vault, cardType string, so
122157
}
123158
}
124159

125-
func copyEntry(logger *logrus.Logger, vault *enpass.Vault, cardType string, filters []string) {
126-
card, err := vault.GetUniqueEntry(cardType, filters)
160+
func copyEntry(logger *logrus.Logger, vault *enpass.Vault, args *Args) {
161+
card, err := vault.GetUniqueEntry(*args.cardType, args.filters)
127162
if err != nil {
128163
logger.WithError(err).Fatal("could not retrieve unique card")
129164
}
@@ -133,13 +168,18 @@ func copyEntry(logger *logrus.Logger, vault *enpass.Vault, cardType string, filt
133168
logger.WithError(err).Fatal("could not decrypt card")
134169
}
135170

171+
if *args.clipboardPrimary {
172+
clipboard.Primary = true
173+
logger.Debug("primary X selection enabled")
174+
}
175+
136176
if err := clipboard.WriteAll(password); err != nil {
137177
logger.WithError(err).Fatal("could not copy password to clipboard")
138178
}
139179
}
140180

141-
func entryPassword(logger *logrus.Logger, vault *enpass.Vault, cardType string, filters []string) {
142-
card, err := vault.GetUniqueEntry(cardType, filters)
181+
func entryPassword(logger *logrus.Logger, vault *enpass.Vault, args *Args) {
182+
card, err := vault.GetUniqueEntry(*args.cardType, args.filters)
143183
if err != nil {
144184
logger.WithError(err).Fatal("could not retrieve unique card")
145185
}
@@ -151,25 +191,35 @@ func entryPassword(logger *logrus.Logger, vault *enpass.Vault, cardType string,
151191
}
152192
}
153193

154-
func getVaultAccessData(logger *logrus.Logger, vaultPath string, enablePin bool) (*enpass.VaultAccessData, *pin.SecureStore) {
194+
func assembleVaultAccessData(logger *logrus.Logger, args *Args) (*enpass.VaultAccessData, *pin.SecureStore) {
155195
accessData := &enpass.VaultAccessData{
156196
Password: os.Getenv("MASTERPW"),
157197
}
158198

159199
var store *pin.SecureStore
160-
if !enablePin {
200+
if !*args.pinEnable {
161201
logger.Debug("PIN disabled")
162202
} else if !accessData.IsComplete() {
163203
logger.Debug("PIN enabled, using store")
164204

165-
storePin := os.Getenv("PIN")
166-
if storePin == "" {
167-
storePin = prompt(logger, "PIN")
205+
vaultPath, err := filepath.EvalSymlinks(*args.vaultPath)
206+
store, err = pin.NewSecureStore(filepath.Base(vaultPath), logger.Level)
207+
if err != nil {
208+
logger.WithError(err).Fatal("could not create store")
168209
}
169210

170-
vaultPath, err := filepath.EvalSymlinks(vaultPath)
171-
store, err = pin.NewSecureStore(filepath.Base(vaultPath), storePin, logger.Level)
211+
storePin := os.Getenv("ENP_PIN")
212+
if storePin == "" {
213+
storePin = prompt(logger, args, "PIN")
214+
}
215+
if len(storePin) < pinMinLength {
216+
logger.Fatal("PIN too short")
217+
}
218+
pinKdfIterCount, err := strconv.ParseInt(os.Getenv("ENP_PIN_ITER_COUNT"), 10, 64)
172219
if err != nil {
220+
pinKdfIterCount = pinDefaultKdfIterCount
221+
}
222+
if err := store.GeneratePassphrase(storePin, int(pinKdfIterCount)); err != nil {
173223
logger.WithError(err).Fatal("could not initialize store")
174224
}
175225
logger.Debug("initialized store")
@@ -181,41 +231,29 @@ func getVaultAccessData(logger *logrus.Logger, vaultPath string, enablePin bool)
181231
}
182232

183233
if !accessData.IsComplete() {
184-
accessData.Password = prompt(logger, "master password")
234+
accessData.Password = prompt(logger, args, "master password")
185235
}
186236

187237
return accessData, store
188238
}
189239

190240
func main() {
191-
vaultPath := flag.String("vault", "", "Path to your Enpass vault.")
192-
cardType := flag.String("type", "password", "The type of your card. (password, ...)")
193-
keyFilePath := flag.String("keyfile", "", "Path to your Enpass vault keyfile.")
194-
logLevelStr := flag.String("log", defaultLogLevel.String(), "The log level from debug (5) to error (1).")
195-
nonInteractive := flag.Bool("nonInteractive", false, "Disable prompts and fail instead.")
196-
enablePin := flag.Bool("pin", false, "Enable PIN.")
197-
sort := flag.Bool("sort", false, "Sort the output by title and username of the 'list' and 'show' command.")
198-
trashed := flag.Bool("trashed", false, "Show trashed items in the 'list' and 'show' command.")
199-
clipboardPrimary := flag.Bool("clipboardPrimary", false, "Use primary X selection instead of clipboard for the 'copy' command.")
241+
args := &Args{}
242+
args.parse()
200243

201-
flag.Parse()
202-
203-
logLevel, err := logrus.ParseLevel(*logLevelStr)
244+
logLevel, err := logrus.ParseLevel(*args.logLevelStr)
204245
if err != nil {
205246
logrus.WithError(err).Fatal("invalid log level specified")
206247
}
207248
logger := logrus.New()
208249
logger.SetLevel(logLevel)
209250

210-
cmd := strings.ToLower(flag.Arg(0))
211-
filters := flag.Args()[1:]
212-
213-
if _, contains := commands[cmd]; !contains {
251+
if _, contains := commands[args.command]; !contains {
214252
printHelp()
215253
logger.Exit(1)
216254
}
217255

218-
switch cmd {
256+
switch args.command {
219257
case cmdHelp:
220258
printHelp()
221259
return
@@ -227,44 +265,36 @@ func main() {
227265
return
228266
}
229267

230-
interactive = !*nonInteractive
231-
232-
if *clipboardPrimary {
233-
clipboard.Primary = true
234-
logger.Debug("primary X selection enabled")
235-
}
236-
237-
vault, err := enpass.NewVault(*vaultPath, logger.Level)
268+
vault, err := enpass.NewVault(*args.vaultPath, logger.Level)
238269
if err != nil {
239270
logger.WithError(err).Fatal("could not create vault")
240271
}
241272

242-
accessData, store := getVaultAccessData(logger, *vaultPath, *enablePin)
243-
accessData.KeyfilePath = *keyFilePath
273+
accessData, store := assembleVaultAccessData(logger, args)
274+
accessData.KeyfilePath = *args.keyFilePath
244275

276+
defer func() {
277+
vault.Close()
278+
}()
245279
if err := vault.Open(accessData); err != nil {
246280
logger.WithError(err).Error("could not open vault")
247281
logger.Exit(2)
248282
}
249283
logger.Debug("opened vault")
250-
defer func() {
251-
vault.Close()
252-
logger.Debug("closed vault")
253-
}()
254284

255-
switch cmd {
285+
switch args.command {
256286
case cmdInit:
257-
// just init vault and store without doing anything
287+
logger.Debug("init done") // just init vault and store without doing anything
258288
case cmdList:
259-
listEntries(logger, vault, *cardType, *sort, *trashed, filters)
289+
listEntries(logger, vault, args)
260290
case cmdShow:
261-
showEntries(logger, vault, *cardType, *sort, *trashed, filters)
291+
showEntries(logger, vault, args)
262292
case cmdCopy:
263-
copyEntry(logger, vault, *cardType, filters)
293+
copyEntry(logger, vault, args)
264294
case cmdPass:
265-
entryPassword(logger, vault, *cardType, filters)
295+
entryPassword(logger, vault, args)
266296
default:
267-
logger.WithField("command", cmd).Fatal("unknown command")
297+
logger.WithField("command", args.command).Fatal("unknown command")
268298
}
269299

270300
if store != nil {

0 commit comments

Comments
 (0)