Skip to content

Commit 520effc

Browse files
authored
refactor: simplify vault type constants and improve config struct (#56)
- Rename TYPE_* constants to match vault package naming (ANDOTP, AEGIS, etc.) - Use typed vaults.Type instead of string for Config.Type field - Rename receiver variable from 'c' to 'cfg' for consistency
1 parent 85053fe commit 520effc

18 files changed

Lines changed: 172 additions & 170 deletions

File tree

‎cmd/andcli/main.go‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,17 @@ func open(cfg *config.Config) (vaults.Vault, error) {
6565
}()
6666

6767
switch cfg.Type {
68-
case vaults.TYPE_ANDOTP:
68+
case vaults.ANDOTP:
6969
return andotp.Open(cfg.File, pw)
70-
case vaults.TYPE_AEGIS:
70+
case vaults.AEGIS:
7171
return aegis.Open(cfg.File, pw)
72-
case vaults.TYPE_TWOFAS:
72+
case vaults.TWOFAS:
7373
return twofas.Open(cfg.File, pw)
74-
case vaults.TYPE_STRATUM:
74+
case vaults.STRATUM:
7575
return stratum.Open(cfg.File, pw)
76-
case vaults.TYPE_KEEPASS:
76+
case vaults.KEEPASS:
7777
return keepass.Open(cfg.File, pw)
78-
case vaults.TYPE_PROTON:
78+
case vaults.PROTON:
7979
return protonpass.Open(cfg.File, pw)
8080
}
8181

‎internal/config/config.go‎

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ import (
1010

1111
"github.com/goccy/go-yaml"
1212
"github.com/tjblackheart/andcli/v2/internal/buildinfo"
13+
"github.com/tjblackheart/andcli/v2/internal/vaults"
1314
)
1415

1516
type (
1617
Config struct {
17-
File string `yaml:"file"`
18-
Type string `yaml:"type"`
19-
ClipboardCmd string `yaml:"clipboard_cmd"`
20-
Options *Opts `yaml:"options"`
18+
File string `yaml:"file"`
19+
Type vaults.Type `yaml:"type"`
20+
ClipboardCmd string `yaml:"clipboard_cmd"`
21+
Options *Opts `yaml:"options"`
2122
//
2223
path string
2324
passwordFromStdin bool
@@ -70,81 +71,80 @@ func create(dir string) (*Config, error) {
7071
}
7172

7273
// Writes the current configuration to a yaml file.
73-
func (c Config) Persist() error {
74-
b, err := yaml.Marshal(c)
74+
func (cfg Config) Persist() error {
75+
b, err := yaml.Marshal(cfg)
7576
if err != nil {
7677
return err
7778
}
7879

79-
return os.WriteFile(c.path, b, 0600)
80+
return os.WriteFile(cfg.path, b, 0o600)
8081
}
8182

8283
// Returns true if the flag option "passwd-stdin" was set.
83-
func (c Config) PasswdStdin() bool {
84-
return c.passwordFromStdin
84+
func (cfg Config) PasswdStdin() bool {
85+
return cfg.passwordFromStdin
8586
}
8687

8788
// Reads an possibly existing config file and merges the content
8889
// into the current config.
89-
func (c *Config) mergeExisting() error {
90-
if _, err := os.Stat(c.path); os.IsNotExist(err) {
90+
func (cfg *Config) mergeExisting() error {
91+
if _, err := os.Stat(cfg.path); os.IsNotExist(err) {
9192
return nil
9293
}
9394

94-
b, err := os.ReadFile(c.path)
95+
b, err := os.ReadFile(cfg.path)
9596
if err != nil {
9697
return err
9798
}
9899

99-
var existing = new(Config)
100+
existing := new(Config)
100101
if err := yaml.Unmarshal(b, existing); err != nil {
101102
return err
102103
}
103104

104-
c.File = existing.File
105-
c.Type = existing.Type
106-
c.ClipboardCmd = existing.ClipboardCmd
105+
cfg.File = existing.File
106+
cfg.Type = existing.Type
107+
cfg.ClipboardCmd = existing.ClipboardCmd
107108

108109
if existing.Options != nil {
109-
c.Options = existing.Options
110+
cfg.Options = existing.Options
110111
}
111112

112113
return nil
113114
}
114115

115116
// Validates the current configuration.
116-
func (c *Config) validate() error {
117-
118-
if c.File == "" {
117+
func (cfg *Config) validate() error {
118+
if cfg.File == "" {
119119
return errors.New("no vault file specified")
120120
}
121121

122-
if c.Type == "" {
122+
if cfg.Type == "" {
123123
return errors.New("no vault type specified")
124124
}
125125

126126
var err error
127-
if c.File, err = filepath.Abs(c.File); err != nil {
128-
return fmt.Errorf("%s: %s", c.File, err)
127+
if cfg.File, err = filepath.Abs(cfg.File); err != nil {
128+
return fmt.Errorf("%s: %s", cfg.File, err)
129129
}
130130

131-
fi, err := os.Stat(c.File)
131+
fi, err := os.Stat(cfg.File)
132132
if err != nil {
133-
return fmt.Errorf("%s: %s", c.File, err)
133+
return fmt.Errorf("%s: %s", cfg.File, err)
134134
}
135135

136136
if fi.IsDir() {
137-
return fmt.Errorf("%s: is a directory, not a vault file", c.File)
137+
return fmt.Errorf("%s: is a directory, not a vault file", cfg.File)
138138
}
139139

140140
// if set, check if the basic clipboard cmd is available in system PATH.
141141
// the option parsing is done at a later time.
142-
if parts := strings.SplitN(c.ClipboardCmd, " ", 2); parts[0] != "" {
142+
if parts := strings.SplitN(cfg.ClipboardCmd, " ", 2); parts[0] != "" {
143143
path, err := exec.LookPath(parts[0])
144144
if err != nil {
145145
return fmt.Errorf("%s: %s", parts[0], err)
146146
}
147-
c.ClipboardCmd = strings.ReplaceAll(c.ClipboardCmd, parts[0], path)
147+
cfg.ClipboardCmd = strings.ReplaceAll(cfg.ClipboardCmd, parts[0], path)
148148
}
149149

150150
return nil

‎internal/config/config_test.go‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/goccy/go-yaml"
1111
"github.com/tjblackheart/andcli/v2/internal/buildinfo"
12+
"github.com/tjblackheart/andcli/v2/internal/vaults"
1213
)
1314

1415
func TestConfig_mergeExisting(t *testing.T) {
@@ -49,10 +50,11 @@ func TestConfig_mergeExisting(t *testing.T) {
4950
},
5051
{
5152
"handles custom options",
52-
&Config{Options: &Opts{
53-
ShowUsernames: true,
54-
ShowTokens: true,
55-
},
53+
&Config{
54+
Options: &Opts{
55+
ShowUsernames: true,
56+
ShowTokens: true,
57+
},
5658
path: path,
5759
},
5860
&Config{
@@ -77,7 +79,7 @@ func TestConfig_mergeExisting(t *testing.T) {
7779
t.Fatal(err)
7880
}
7981

80-
if err := os.WriteFile(tt.want.path, b, 0644); err != nil {
82+
if err := os.WriteFile(tt.want.path, b, 0o644); err != nil {
8183
t.Fatal(err)
8284
}
8385
} else {
@@ -102,7 +104,7 @@ func TestConfig_validate(t *testing.T) {
102104
path := filepath.Join(os.TempDir(), "andcli_test.json")
103105
defer os.Remove(path)
104106

105-
os.WriteFile(path, nil, 0644)
107+
os.WriteFile(path, nil, 0o644)
106108

107109
tests := []struct {
108110
name string
@@ -210,7 +212,7 @@ func Test_create(t *testing.T) {
210212
// default config
211213
want := &Config{
212214
File: abs,
213-
Type: *vtype,
215+
Type: vaults.Type(*vtype),
214216
ClipboardCmd: "",
215217
Options: &Opts{
216218
ShowUsernames: true,

‎internal/config/flags.go‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@ import (
55
"log"
66
"os"
77
"path/filepath"
8-
"strings"
98

109
flag "github.com/spf13/pflag"
1110
"github.com/tjblackheart/andcli/v2/internal/buildinfo"
1211
"github.com/tjblackheart/andcli/v2/internal/vaults"
1312
)
1413

1514
var (
16-
availableVaults = strings.Join(vaults.Types(), ", ")
17-
1815
set = flag.NewFlagSet("default", flag.ExitOnError)
1916
vfile = set.StringP("file", "f", "", "Path to the encrypted vault (deprecated: Pass the filename directly)")
20-
vtype = set.StringP("type", "t", "", fmt.Sprintf("Vault type (%s)", availableVaults))
17+
vtype = set.StringP("type", "t", "", fmt.Sprintf("Vault type (%s)", vaults.StrTypes()))
2118
cmd = set.StringP("clipboard-cmd", "c", "", "A custom clipboard command, including args (xclip, wl-copy, pbcopy etc.)")
2219
pwstdin = set.Bool("passwd-stdin", false, "Read the vault password from stdin. If set, skips the password input.")
2320
version = set.BoolP("version", "v", false, "Prints version info and exits")
@@ -26,7 +23,6 @@ var (
2623

2724
// Parses given flags into the existing config.
2825
func (cfg *Config) parseFlags() error {
29-
3026
set.Usage = func() { usage(true) }
3127

3228
if err := set.Parse(os.Args[1:]); err != nil {
@@ -54,7 +50,7 @@ func (cfg *Config) parseFlags() error {
5450
}
5551

5652
if *vtype != "" {
57-
cfg.Type = *vtype
53+
cfg.Type = vaults.Type(*vtype)
5854
}
5955

6056
if *cmd != "" {
@@ -78,7 +74,6 @@ func (cfg *Config) parseFlags() error {
7874

7975
// prints custom formatted usage information
8076
func usage(includeDescription bool) {
81-
8277
if includeDescription {
8378
fmt.Println("andcli - A 2FA TUI for your shell")
8479
}

‎internal/vaults/aegis/aegis.go‎

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ import (
1515
"golang.org/x/crypto/scrypt"
1616
)
1717

18-
const t = vaults.TYPE_AEGIS
18+
const vaultType = vaults.AEGIS
19+
20+
var _ vaults.Vault = &aegis{}
1921

2022
type (
21-
vault struct {
23+
aegis struct {
2224
Version int
2325
Header struct {
2426
Slots []struct {
@@ -57,37 +59,35 @@ type (
5759
)
5860

5961
func Open(filename string, pass []byte) (vaults.Vault, error) {
60-
61-
var v vault
62+
var v aegis
6263

6364
b, err := os.ReadFile(filename)
6465
if err != nil {
65-
return nil, fmt.Errorf("%s: %w", t, err)
66+
return nil, fmt.Errorf("%s: %w", vaultType, err)
6667
}
6768

6869
if err := json.Unmarshal(b, &v); err != nil {
69-
return nil, fmt.Errorf("%s: %w", t, err)
70+
return nil, fmt.Errorf("%s: %w", vaultType, err)
7071
}
7172

7273
key, err := v.masterKeyFromPass(pass)
7374
if err != nil {
74-
return nil, fmt.Errorf("%s: %w", t, err)
75+
return nil, fmt.Errorf("%s: %w", vaultType, err)
7576
}
7677

7778
b, err = v.decryptDB(key)
7879
if err != nil {
79-
return nil, fmt.Errorf("%s: %w", t, err)
80+
return nil, fmt.Errorf("%s: %w", vaultType, err)
8081
}
8182

8283
if err := json.Unmarshal(b, &v.db); err != nil {
83-
return nil, fmt.Errorf("%s: %w", t, err)
84+
return nil, fmt.Errorf("%s: %w", vaultType, err)
8485
}
8586

8687
return v, nil
8788
}
8889

89-
func (v vault) Entries() []vaults.Entry {
90-
90+
func (v aegis) Entries() []vaults.Entry {
9191
entries := make([]vaults.Entry, 0)
9292

9393
for _, e := range v.db.Entries {
@@ -109,7 +109,7 @@ func (v vault) Entries() []vaults.Entry {
109109
return entries
110110
}
111111

112-
func (v vault) masterKeyFromPass(password []byte) ([]byte, error) {
112+
func (v aegis) masterKeyFromPass(password []byte) ([]byte, error) {
113113
var salt, keyNonce, keyTag, key, derivedKey []byte
114114
var err error
115115

@@ -166,8 +166,7 @@ func (v vault) masterKeyFromPass(password []byte) ([]byte, error) {
166166
return masterKey, nil
167167
}
168168

169-
func (v vault) decryptDB(key []byte) ([]byte, error) {
170-
169+
func (v aegis) decryptDB(key []byte) ([]byte, error) {
171170
block, err := aes.NewCipher(key)
172171
if err != nil {
173172
return nil, err

‎internal/vaults/aegis/aegis_test.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func TestEntries(t *testing.T) {
6666

6767
for _, tt := range tests {
6868
t.Run(tt.name, func(t *testing.T) {
69-
entries := (&vault{db: db{Entries: tt.input}}).Entries()
69+
entries := (&aegis{db: db{Entries: tt.input}}).Entries()
7070
if !reflect.DeepEqual(entries, tt.want) {
7171
t.Fatalf("Entries(): want %#v\nhave %#v", tt.want, entries)
7272
}

‎internal/vaults/andotp/andotp.go‎

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import (
66
"os"
77
"strings"
88

9-
"github.com/grijul/go-andotp/andotp"
9+
gao "github.com/grijul/go-andotp/andotp"
1010
"github.com/tjblackheart/andcli/v2/internal/vaults"
1111
)
1212

13-
const t = vaults.TYPE_ANDOTP
13+
const vaultType = vaults.ANDOTP
14+
15+
var _ vaults.Vault = &andotp{}
1416

1517
type (
16-
vault struct {
17-
entries []entry
18-
}
18+
andotp struct{ entries []entry }
1919

2020
entry struct {
2121
Secret string
@@ -33,28 +33,25 @@ type (
3333
)
3434

3535
func Open(filename string, pass []byte) (vaults.Vault, error) {
36-
3736
b, err := os.ReadFile(filename)
3837
if err != nil {
39-
return nil, fmt.Errorf("%s: %w", t, err)
38+
return nil, fmt.Errorf("%s: %w", vaultType, err)
4039
}
4140

42-
b, err = andotp.Decrypt(b, string(pass))
41+
b, err = gao.Decrypt(b, string(pass))
4342
if err != nil {
44-
return nil, fmt.Errorf("%s: %w", t, err)
43+
return nil, fmt.Errorf("%s: %w", vaultType, err)
4544
}
4645

4746
entries := make([]entry, 0)
4847
if err := json.Unmarshal(b, &entries); err != nil {
49-
return nil, fmt.Errorf("%s: %w", t, err)
48+
return nil, fmt.Errorf("%s: %w", vaultType, err)
5049
}
5150

52-
return &vault{entries}, nil
53-
51+
return &andotp{entries}, nil
5452
}
5553

56-
func (v vault) Entries() []vaults.Entry {
57-
54+
func (v andotp) Entries() []vaults.Entry {
5855
entries := make([]vaults.Entry, 0)
5956

6057
for _, e := range v.entries {

‎internal/vaults/andotp/andotp_test.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func TestEntries(t *testing.T) {
6565

6666
for _, tt := range tests {
6767
t.Run(tt.name, func(t *testing.T) {
68-
entries := (&vault{entries: tt.input}).Entries()
68+
entries := (&andotp{entries: tt.input}).Entries()
6969
if !reflect.DeepEqual(entries, tt.want) {
7070
t.Fatalf("Entries(): want %#v\nhave %#v", tt.want, entries)
7171
}

0 commit comments

Comments
 (0)