-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
legacy.go
192 lines (152 loc) · 4.69 KB
/
legacy.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package keyring
import (
"fmt"
"strings"
"github.com/pkg/errors"
tmos "github.com/tendermint/tendermint/libs/os"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/crypto"
"github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// LegacyKeybase is implemented by the legacy keybase implementation.
type LegacyKeybase interface {
List() ([]Info, error)
Export(name string) (armor string, err error)
ExportPrivKey(name, decryptPassphrase, encryptPassphrase string) (armor string, err error)
ExportPubKey(name string) (armor string, err error)
Close() error
}
// NewLegacy creates a new instance of a legacy keybase.
func NewLegacy(name, dir string, opts ...KeybaseOption) (LegacyKeybase, error) {
if err := tmos.EnsureDir(dir, 0o700); err != nil {
return nil, fmt.Errorf("failed to create Keybase directory: %s", err)
}
db, err := sdk.NewLevelDB(name, dir)
if err != nil {
return nil, err
}
return newDBKeybase(db), nil
}
var _ LegacyKeybase = dbKeybase{}
// dbKeybase combines encryption and storage implementation to provide a
// full-featured key manager.
//
// Deprecated: dbKeybase will be removed in favor of keyringKeybase.
type dbKeybase struct {
db dbm.DB
}
// newDBKeybase creates a new dbKeybase instance using the provided DB for
// reading and writing keys.
func newDBKeybase(db dbm.DB) dbKeybase {
return dbKeybase{
db: db,
}
}
// List returns the keys from storage in alphabetical order.
func (kb dbKeybase) List() ([]Info, error) {
var res []Info
iter, err := kb.db.Iterator(nil, nil)
if err != nil {
return nil, err
}
defer iter.Close()
for ; iter.Valid(); iter.Next() {
key := string(iter.Key())
// need to include only keys in storage that have an info suffix
if strings.HasSuffix(key, infoSuffix) {
info, err := unmarshalInfo(iter.Value())
if err != nil {
return nil, err
}
res = append(res, info)
}
}
return res, nil
}
// Get returns the public information about one key.
func (kb dbKeybase) Get(name string) (Info, error) {
bs, err := kb.db.Get(infoKeyBz(name))
if err != nil {
return nil, err
}
if len(bs) == 0 {
return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, name)
}
return unmarshalInfo(bs)
}
// ExportPrivateKeyObject returns a PrivKey object given the key name and
// passphrase. An error is returned if the key does not exist or if the Info for
// the key is invalid.
func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (types.PrivKey, error) {
info, err := kb.Get(name)
if err != nil {
return nil, err
}
var priv types.PrivKey
switch i := info.(type) {
case localInfo:
linfo := i
if linfo.PrivKeyArmor == "" {
err = fmt.Errorf("private key not available")
return nil, err
}
priv, _, err = crypto.UnarmorDecryptPrivKey(linfo.PrivKeyArmor, passphrase)
if err != nil {
return nil, err
}
case ledgerInfo, offlineInfo, multiInfo:
return nil, errors.New("only works on local private keys")
}
return priv, nil
}
func (kb dbKeybase) Export(name string) (armor string, err error) {
bz, err := kb.db.Get(infoKeyBz(name))
if err != nil {
return "", err
}
if bz == nil {
return "", fmt.Errorf("no key to export with name %s", name)
}
return crypto.ArmorInfoBytes(bz), nil
}
// ExportPubKey returns public keys in ASCII armored format. It retrieves a Info
// object by its name and return the public key in a portable format.
func (kb dbKeybase) ExportPubKey(name string) (armor string, err error) {
bz, err := kb.db.Get(infoKeyBz(name))
if err != nil {
return "", err
}
if bz == nil {
return "", fmt.Errorf("no key to export with name %s", name)
}
info, err := unmarshalInfo(bz)
if err != nil {
return
}
return crypto.ArmorPubKeyBytes(info.GetPubKey().Bytes(), string(info.GetAlgo())), nil
}
// ExportPrivKey returns a private key in ASCII armored format.
// It returns an error if the key does not exist or a wrong encryption passphrase
// is supplied.
func (kb dbKeybase) ExportPrivKey(name string, decryptPassphrase string,
encryptPassphrase string,
) (armor string, err error) {
priv, err := kb.ExportPrivateKeyObject(name, decryptPassphrase)
if err != nil {
return "", err
}
info, err := kb.Get(name)
if err != nil {
return "", err
}
return crypto.EncryptArmorPrivKey(priv, encryptPassphrase, string(info.GetAlgo())), nil
}
// Close the underlying storage.
func (kb dbKeybase) Close() error { return kb.db.Close() }
func infoKey(name string) string { return fmt.Sprintf("%s.%s", name, infoSuffix) }
func infoKeyBz(name string) []byte { return []byte(infoKey(name)) }
// KeybaseOption overrides options for the db.
type KeybaseOption func(*kbOptions)
type kbOptions struct{}