/
keyring_file.go
134 lines (110 loc) · 2.7 KB
/
keyring_file.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
/*
* keyring_file.go
*
* Copyright 2018-2021 Bill Zissimopoulos
*/
/*
* This file is part of golib.
*
* It is licensed under the MIT license. The full license text can be found
* in the License.txt file at the root of this project.
*/
package keyring
import (
"bytes"
"fmt"
"os"
"sync"
"github.com/billziss-gh/golib/config"
"github.com/billziss-gh/golib/errors"
"github.com/billziss-gh/golib/util"
)
// FileKeyring is a keyring that stores passwords in a file.
type FileKeyring struct {
Path string
Key []byte
mux sync.Mutex
}
func (self *FileKeyring) getConf() (conf config.Config, err error) {
var data []byte
if nil == self.Key {
data, err = util.ReadData(self.Path)
} else {
data, err = util.ReadAeData(self.Path, self.Key)
}
if nil != err {
if e, ok := err.(*os.PathError); ok && "open" == e.Op {
conf = config.Config{}
err = nil
}
return
}
conf, err = config.Read(bytes.NewReader(data))
return
}
func (self *FileKeyring) setConf(conf config.Config) (err error) {
var buf bytes.Buffer
err = config.Write(&buf, conf)
if nil != err {
return
}
if nil == self.Key {
err = util.WriteData(self.Path, 0600, buf.Bytes())
} else {
err = util.WriteAeData(self.Path, 0600, buf.Bytes(), self.Key)
}
return
}
func (self *FileKeyring) Get(service, user string) (string, error) {
self.mux.Lock()
defer self.mux.Unlock()
conf, err := self.getConf()
if nil != err {
return "", errors.New(fmt.Sprintf("cannot get key %s/%s", service, user), err, ErrKeyring)
}
if sect, ok := conf[service]; ok {
if pass, ok := sect[user]; ok {
return pass, nil
}
}
return "", errors.New(fmt.Sprintf("cannot get key %s/%s", service, user), nil, ErrKeyring)
}
func (self *FileKeyring) Set(service, user, pass string) error {
self.mux.Lock()
defer self.mux.Unlock()
conf, err := self.getConf()
if nil != err {
return errors.New(fmt.Sprintf("cannot set key %s/%s", service, user), err, ErrKeyring)
}
if sect, ok := conf[service]; ok {
sect[user] = pass
} else {
sect = config.Section{}
conf[service] = sect
sect[user] = pass
}
err = self.setConf(conf)
if nil != err {
return errors.New(fmt.Sprintf("cannot set key %s/%s", service, user), err, ErrKeyring)
}
return nil
}
func (self *FileKeyring) Delete(service, user string) error {
self.mux.Lock()
defer self.mux.Unlock()
conf, err := self.getConf()
if nil != err {
return errors.New(fmt.Sprintf("cannot delete key %s/%s", service, user), err, ErrKeyring)
}
if sect, ok := conf[service]; ok {
delete(sect, user)
if 0 == len(sect) {
delete(conf, service)
}
}
err = self.setConf(conf)
if nil != err {
return errors.New(fmt.Sprintf("cannot delete key %s/%s", service, user), err, ErrKeyring)
}
return nil
}