forked from gopasspw/gopass
/
mount.go
129 lines (115 loc) · 3.2 KB
/
mount.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
package root
import (
"fmt"
"sort"
"strings"
"github.com/fatih/color"
"github.com/justwatchcom/gopass/fsutil"
"github.com/justwatchcom/gopass/store"
"github.com/justwatchcom/gopass/store/sub"
)
// AddMount adds a new mount
func (r *Store) AddMount(alias, path string, keys ...string) error {
path = fsutil.CleanPath(path)
if _, found := r.mounts[alias]; found {
return fmt.Errorf("%s is already mounted", alias)
}
if err := r.addMount(alias, path, keys...); err != nil {
return err
}
// check for duplicate mounts
return r.checkMounts()
}
func (r *Store) addMount(alias, path string, keys ...string) error {
if alias == "" {
return fmt.Errorf("alias must not be empty")
}
if r.mounts == nil {
r.mounts = make(map[string]*sub.Store, 1)
}
if _, found := r.mounts[alias]; found {
return fmt.Errorf("%s is already mounted", alias)
}
// propagate our config settings to the sub store
cfg := r.Config()
cfg.Path = fsutil.CleanPath(path)
s, err := sub.New(alias, cfg)
if err != nil {
return err
}
if !s.Initialized() {
if len(keys) < 1 {
return fmt.Errorf("password store %s is not initialized. Try gopass init --store %s --path %s", alias, alias, path)
}
if err := s.Init(path, keys...); err != nil {
return err
}
fmt.Printf("Password store %s initialized for:", path)
for _, r := range s.Recipients() {
color.Yellow(r)
}
}
r.mounts[alias] = s
return nil
}
// RemoveMount removes and existing mount
func (r *Store) RemoveMount(alias string) error {
if _, found := r.mounts[alias]; !found {
return fmt.Errorf("%s is not mounted", alias)
}
if _, found := r.mounts[alias]; !found {
fmt.Println(color.YellowString("%s is not initialized", alias))
}
delete(r.mounts, alias)
return nil
}
// Mounts returns a map of mounts with their paths
func (r *Store) Mounts() map[string]string {
m := make(map[string]string, len(r.mounts))
for alias, sub := range r.mounts {
m[alias] = sub.Path()
}
return m
}
// MountPoints returns a sorted list of mount points. It encodes the logic that
// the longer a mount point the more specific it is. This allows to "shadow" a
// shorter mount point by a longer one.
func (r *Store) MountPoints() []string {
mps := make([]string, 0, len(r.mounts))
for k := range r.mounts {
mps = append(mps, k)
}
sort.Sort(sort.Reverse(store.ByPathLen(mps)))
return mps
}
// mountPoint returns the most-specific mount point for the given key
func (r *Store) mountPoint(name string) string {
for _, mp := range r.MountPoints() {
if strings.HasPrefix(name+"/", mp+"/") {
return mp
}
}
return ""
}
// getStore returns the Store object at the most-specific mount point for the
// given key
func (r *Store) getStore(name string) *sub.Store {
name = strings.TrimSuffix(name, "/")
mp := r.mountPoint(name)
if sub, found := r.mounts[mp]; found {
return sub
}
return r.store
}
// checkMounts performs some sanity checks on our mounts. At the moment it
// only checks if some path is mounted twice.
func (r *Store) checkMounts() error {
paths := make(map[string]string, len(r.mounts))
for k, v := range r.mounts {
if _, found := paths[v.Path()]; found {
return fmt.Errorf("Doubly mounted path at %s: %s", v.Path(), k)
}
paths[v.Path()] = k
}
return nil
}