Skip to content

Commit 32db351

Browse files
committed
improve main
1 parent 3a20cae commit 32db351

File tree

6 files changed

+171
-143
lines changed

6 files changed

+171
-143
lines changed

cmd/enpasscli/main.go

Lines changed: 91 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,21 @@ import (
1818

1919
const (
2020
defaultLogLevel = logrus.InfoLevel
21+
cmdVersion = "version"
22+
cmdHelp = "help"
23+
cmdInit = "init"
24+
cmdList = "list"
25+
cmdShow = "show"
26+
cmdCopy = "copy"
27+
cmdPass = "pass"
2128
)
2229

2330
var (
2431
// overwritten by go build
2532
version = "dev"
2633
// enables prompts
2734
interactive = true
35+
commands = map[string]struct{}{cmdVersion: {}, cmdHelp: {}, cmdInit: {}, cmdList: {}, cmdShow: {}, cmdCopy: {}, cmdPass: {}}
2836
)
2937

3038
func prompt(logger *logrus.Logger, msg string) string {
@@ -38,6 +46,16 @@ func prompt(logger *logrus.Logger, msg string) string {
3846
return ""
3947
}
4048

49+
func printHelp() {
50+
fmt.Print("Valid commands: ")
51+
for cmd := range commands {
52+
fmt.Printf("%s, ", cmd)
53+
}
54+
fmt.Println()
55+
flag.Usage()
56+
os.Exit(1)
57+
}
58+
4159
func sortEntries(cards []enpass.Card) {
4260
// Sort by username preserving original order
4361
s.SliceStable(cards, func(i, j int) bool {
@@ -132,6 +150,42 @@ func entryPassword(logger *logrus.Logger, vault *enpass.Vault, cardType string,
132150
}
133151
}
134152

153+
func getVaultAccessData(logger *logrus.Logger, vaultPath string, enablePin bool) (*enpass.VaultAccessData, *pin.SecureStore) {
154+
accessData := &enpass.VaultAccessData{
155+
Password: os.Getenv("MASTERPW"),
156+
}
157+
158+
var store *pin.SecureStore
159+
if !enablePin {
160+
logger.Debug("PIN disabled")
161+
} else if !accessData.IsComplete() {
162+
logger.Debug("PIN enabled, using store")
163+
164+
storePin := os.Getenv("PIN")
165+
if storePin == "" {
166+
storePin = prompt(logger, "PIN")
167+
}
168+
169+
var err error
170+
store, err = pin.NewSecureStore(filepath.Base(vaultPath), storePin, logger.Level)
171+
if err != nil {
172+
logger.WithError(err).Fatal("could not initialize store")
173+
}
174+
logger.Debug("initialized store")
175+
176+
if accessData.DBKey, err = store.Read(); err != nil {
177+
logger.WithError(err).Fatal("could not read access data from store")
178+
}
179+
logger.Debug("read access data from store")
180+
}
181+
182+
if !accessData.IsComplete() {
183+
accessData.Password = prompt(logger, "master password")
184+
}
185+
186+
return accessData, store
187+
}
188+
135189
func main() {
136190
vaultPath := flag.String("vault", "", "Path to your Enpass vault.")
137191
cardType := flag.String("type", "password", "The type of your card. (password, ...)")
@@ -145,83 +199,71 @@ func main() {
145199

146200
flag.Parse()
147201

148-
if flag.NArg() == 0 {
149-
fmt.Println("Specify a command: version, list, show, copy, pass")
150-
flag.Usage()
151-
os.Exit(1)
152-
}
153-
154202
logLevel, err := logrus.ParseLevel(*logLevelStr)
155203
if err != nil {
156204
logrus.WithError(err).Fatal("invalid log level specified")
157205
}
158206
logger := logrus.New()
159207
logger.SetLevel(logLevel)
160208

161-
command := strings.ToLower(flag.Arg(0))
209+
cmd := strings.ToLower(flag.Arg(0))
162210
filters := flag.Args()[1:]
163211

164-
interactive = !*nonInteractive
165-
166-
if *clipboardPrimary {
167-
clipboard.Primary = true
168-
logger.Debug("primary X selection enabled")
212+
if _, contains := commands[cmd]; !contains {
213+
printHelp()
214+
logger.Exit(1)
169215
}
170216

171-
if command == "version" {
217+
switch cmd {
218+
case cmdHelp:
219+
printHelp()
220+
return
221+
case cmdVersion:
172222
logger.Printf(
173223
"%s arch=%s os=%s version=%s",
174224
filepath.Base(os.Args[0]), runtime.GOARCH, runtime.GOOS, version,
175225
)
176226
return
177227
}
178228

179-
accessData := &enpass.VaultAccessData{
180-
VaultPath: *vaultPath,
181-
KeyfilePath: *keyFilePath,
182-
Password: os.Getenv("MASTERPW"),
183-
}
229+
interactive = !*nonInteractive
184230

185-
var store *pin.SecureStore
186-
if !*enablePin {
187-
logger.Debug("PIN disabled")
188-
} else if !accessData.IsComplete() {
189-
logger.Debug("PIN enabled, using store")
190-
store = initSecureStore(logger, accessData.VaultPath)
191-
if accessData.DBKey, err = store.Read(); err != nil {
192-
logger.WithError(err).Fatal("could not read access data from store")
193-
}
194-
logger.Debug("read access data from store")
231+
if *clipboardPrimary {
232+
clipboard.Primary = true
233+
logger.Debug("primary X selection enabled")
195234
}
196235

197-
if !accessData.IsComplete() {
198-
accessData.Password = prompt(logger, "master password")
236+
vault, err := enpass.NewVault(*vaultPath, logger.Level)
237+
if err != nil {
238+
logger.WithError(err).Fatal("could not create vault")
199239
}
200240

201-
vault := enpass.Vault{Logger: *logrus.New()}
202-
vault.Logger.SetLevel(logger.Level)
241+
accessData, store := getVaultAccessData(logger, *vaultPath, *enablePin)
242+
accessData.KeyfilePath = *keyFilePath
203243

204-
if err := vault.Initialize(accessData); err != nil {
244+
if err := vault.Open(accessData); err != nil {
205245
logger.WithError(err).Error("could not open vault")
206246
logger.Exit(2)
207247
}
208-
defer func() { _ = vault.Close() }()
209-
210-
logger.Debug("initialized vault")
211-
212-
switch command {
213-
case "init":
214-
// just init vault without doing anything
215-
case "list":
216-
listEntries(logger, &vault, *cardType, *sort, *trashed, filters)
217-
case "show":
218-
showEntries(logger, &vault, *cardType, *sort, *trashed, filters)
219-
case "copy":
220-
copyEntry(logger, &vault, *cardType, filters)
221-
case "pass":
222-
entryPassword(logger, &vault, *cardType, filters)
248+
logger.Debug("opened vault")
249+
defer func() {
250+
vault.Close()
251+
logger.Debug("closed vault")
252+
}()
253+
254+
switch cmd {
255+
case cmdInit:
256+
// just init vault and store without doing anything
257+
case cmdList:
258+
listEntries(logger, vault, *cardType, *sort, *trashed, filters)
259+
case cmdShow:
260+
showEntries(logger, vault, *cardType, *sort, *trashed, filters)
261+
case cmdCopy:
262+
copyEntry(logger, vault, *cardType, filters)
263+
case cmdPass:
264+
entryPassword(logger, vault, *cardType, filters)
223265
default:
224-
logger.WithField("command", command).Fatal("unknown command")
266+
logger.WithField("command", cmd).Fatal("unknown command")
225267
}
226268

227269
if store != nil {
@@ -230,17 +272,3 @@ func main() {
230272
}
231273
}
232274
}
233-
234-
func initSecureStore(logger *logrus.Logger, vaultPath string) *pin.SecureStore {
235-
store := pin.SecureStore{Logger: *logrus.New()}
236-
store.Logger.SetLevel(logger.Level)
237-
storePin := os.Getenv("PIN")
238-
if storePin == "" {
239-
storePin = prompt(logger, "PIN")
240-
}
241-
if err := store.Initialize(storePin, vaultPath); err != nil {
242-
logger.WithError(err).Fatal("could not initialize store")
243-
}
244-
logger.Debug("initialized store")
245-
return &store
246-
}

pkg/enpass/key.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const (
2323
// generateMasterPassword : generates the master password to decrypt the vault database
2424
func (v *Vault) generateMasterPassword(password []byte, keyfilePath string) ([]byte, error) {
2525
if keyfilePath == "" {
26-
v.Logger.Debug("not using keyfile")
26+
v.logger.Debug("not using keyfile")
2727

2828
if password == nil {
2929
return nil, errors.New("empty master password provided")
@@ -32,7 +32,7 @@ func (v *Vault) generateMasterPassword(password []byte, keyfilePath string) ([]b
3232
return password, nil
3333
}
3434

35-
v.Logger.Debug("using keyfile")
35+
v.logger.Debug("using keyfile")
3636

3737
keyfileBytes, err := loadKeyFilePassword(keyfilePath)
3838
if err != nil {

pkg/enpass/vault.go

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const (
2424
// Vault : vault is the container object for vault-related operations
2525
type Vault struct {
2626
// Logger : the logger instance
27-
Logger logrus.Logger
27+
logger logrus.Logger
2828

2929
// vault.enpassdb : SQLCipher database
3030
databaseFilename string
@@ -43,7 +43,6 @@ type Vault struct {
4343
}
4444

4545
type VaultAccessData struct {
46-
VaultPath string
4746
KeyfilePath string
4847
Password string
4948
DBKey []byte
@@ -53,6 +52,42 @@ func (accessData *VaultAccessData) IsComplete() bool {
5352
return accessData.Password != "" || accessData.DBKey != nil
5453
}
5554

55+
// NewVault : Create new instance of vault and load vault info
56+
func NewVault(vaultPath string, logLevel logrus.Level) (*Vault, error) {
57+
v := Vault{logger: *logrus.New()}
58+
v.logger.SetLevel(logLevel)
59+
60+
if vaultPath == "" {
61+
return nil, errors.New("empty vault path provided")
62+
}
63+
64+
vaultPath, _ = filepath.EvalSymlinks(vaultPath)
65+
v.databaseFilename = filepath.Join(vaultPath, vaultFileName)
66+
v.vaultInfoFilename = filepath.Join(vaultPath, vaultInfoFileName)
67+
68+
v.logger.Debug("checking provided vault paths")
69+
if _, err := os.Stat(v.databaseFilename); os.IsNotExist(err) {
70+
return nil, errors.New("vault does not exist: " + v.databaseFilename)
71+
}
72+
if _, err := os.Stat(v.vaultInfoFilename); os.IsNotExist(err) {
73+
return nil, errors.New("vault info file does not exist: " + v.vaultInfoFilename)
74+
}
75+
76+
v.logger.Debug("loading vault info")
77+
var err error
78+
v.vaultInfo, err = v.loadVaultInfo()
79+
if err != nil {
80+
return nil, errors.Wrap(err, "could not load vault info")
81+
}
82+
83+
v.logger.
84+
WithField("db_path", vaultFileName).
85+
WithField("info_path", vaultInfoFileName).
86+
Debug("initialized paths")
87+
88+
return &v, nil
89+
}
90+
5691
func (v *Vault) openEncryptedDatabase(path string, dbKey []byte) (err error) {
5792
// The raw key for the sqlcipher database is given
5893
// by the first 64 characters of the hex-encoded key
@@ -72,7 +107,7 @@ func (v *Vault) openEncryptedDatabase(path string, dbKey []byte) (err error) {
72107

73108
func (v *Vault) generateAndSetDBKey(accessData *VaultAccessData) error {
74109
if accessData.DBKey != nil {
75-
v.Logger.Debug("skipping database key generation, already set")
110+
v.logger.Debug("skipping database key generation, already set")
76111
return nil
77112
}
78113

@@ -86,19 +121,19 @@ func (v *Vault) generateAndSetDBKey(accessData *VaultAccessData) error {
86121
return errors.New("you are specifying an unnecessary keyfile")
87122
}
88123

89-
v.Logger.Debug("generating master password")
124+
v.logger.Debug("generating master password")
90125
masterPassword, err := v.generateMasterPassword([]byte(accessData.Password), accessData.KeyfilePath)
91126
if err != nil {
92127
return errors.Wrap(err, "could not generate vault unlock key")
93128
}
94129

95-
v.Logger.Debug("extracting salt from database")
130+
v.logger.Debug("extracting salt from database")
96131
keySalt, err := v.extractSalt()
97132
if err != nil {
98133
return errors.Wrap(err, "could not get master password salt")
99134
}
100135

101-
v.Logger.Debug("deriving decryption key")
136+
v.logger.Debug("deriving decryption key")
102137
accessData.DBKey, err = v.deriveKey(masterPassword, keySalt)
103138
if err != nil {
104139
return errors.Wrap(err, "could not derive database key from master password")
@@ -107,56 +142,20 @@ func (v *Vault) generateAndSetDBKey(accessData *VaultAccessData) error {
107142
return nil
108143
}
109144

110-
func (v *Vault) checkPaths() error {
111-
if _, err := os.Stat(v.databaseFilename); os.IsNotExist(err) {
112-
return errors.New("vault does not exist: " + v.databaseFilename)
113-
}
114-
115-
if _, err := os.Stat(v.vaultInfoFilename); os.IsNotExist(err) {
116-
return errors.New("vault info file does not exist: " + v.vaultInfoFilename)
117-
}
118-
119-
return nil
120-
}
121-
122-
// Initialize : setup a connection to the Enpass database. Call this before doing anything.
123-
func (v *Vault) Initialize(accessData *VaultAccessData) error {
124-
if accessData.VaultPath == "" {
125-
return errors.New("empty vault path provided")
126-
}
127-
128-
v.databaseFilename = filepath.Join(accessData.VaultPath, vaultFileName)
129-
v.vaultInfoFilename = filepath.Join(accessData.VaultPath, vaultInfoFileName)
130-
131-
v.Logger.Debug("checking provided vault paths")
132-
if err := v.checkPaths(); err != nil {
133-
return errors.Wrap(err, "invalid vault path provided")
134-
}
135-
136-
v.Logger.Debug("loading vault info")
137-
var err error
138-
v.vaultInfo, err = v.loadVaultInfo()
139-
if err != nil {
140-
return errors.Wrap(err, "could not load vault info")
141-
}
142-
143-
v.Logger.
144-
WithField("db_path", vaultFileName).
145-
WithField("info_path", vaultInfoFileName).
146-
Debug("initialized paths")
147-
148-
v.Logger.Debug("generating database key")
145+
// Open : setup a connection to the Enpass database. Call this before doing anything.
146+
func (v *Vault) Open(accessData *VaultAccessData) error {
147+
v.logger.Debug("generating database key")
149148
if err := v.generateAndSetDBKey(accessData); err != nil {
150149
return errors.Wrap(err, "could not generate database key")
151150
}
152151

153-
v.Logger.Debug("opening encrypted database")
152+
v.logger.Debug("opening encrypted database")
154153
if err := v.openEncryptedDatabase(v.databaseFilename, accessData.DBKey); err != nil {
155154
return errors.Wrap(err, "could not open encrypted database")
156155
}
157156

158157
var tableName string
159-
err = v.db.QueryRow(`
158+
err := v.db.QueryRow(`
160159
SELECT name
161160
FROM sqlite_master
162161
WHERE type='table' AND name='item'

0 commit comments

Comments
 (0)