11package keyring
22
33import (
4- "bufio"
5- "fmt"
64 "io"
7- "os"
8- "path/filepath"
95
106 "github.com/99designs/keyring"
11- "golang.org/x/crypto/bcrypt"
127
13- errorsmod "cosmossdk.io/errors"
14- "github.com/cosmos/cosmos-sdk/client/input"
158 sdkkeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
169)
1710
18- const (
19- keyringFileDirName = "e2ee-keyring-file"
20- keyringTestDirName = "e2ee-keyring-test"
21- passKeyringPrefix = "e2ee-keyring-%s" //nolint: gosec
22- maxPassphraseEntryAttempts = 3
23- )
24-
2511type Keyring interface {
2612 Get (string ) ([]byte , error )
2713 Set (string , []byte ) error
@@ -30,60 +16,17 @@ type Keyring interface {
3016func New (
3117 appName , backend , rootDir string , userInput io.Reader ,
3218) (Keyring , error ) {
33- var (
34- db keyring.Keyring
35- err error
36- )
3719 serviceName := appName + "-e2ee"
38- switch backend {
39- case sdkkeyring .BackendMemory :
40- return newKeystore (keyring .NewArrayKeyring (nil ), sdkkeyring .BackendMemory ), nil
41- case sdkkeyring .BackendTest :
42- db , err = keyring .Open (keyring.Config {
43- AllowedBackends : []keyring.BackendType {keyring .FileBackend },
44- ServiceName : serviceName ,
45- FileDir : filepath .Join (rootDir , keyringTestDirName ),
46- FilePasswordFunc : func (_ string ) (string , error ) {
47- return "test" , nil
48- },
49- })
50- case sdkkeyring .BackendFile :
51- fileDir := filepath .Join (rootDir , keyringFileDirName )
52- db , err = keyring .Open (keyring.Config {
53- AllowedBackends : []keyring.BackendType {keyring .FileBackend },
54- ServiceName : serviceName ,
55- FileDir : fileDir ,
56- FilePasswordFunc : newRealPrompt (fileDir , userInput ),
57- })
58- case sdkkeyring .BackendOS :
59- db , err = keyring .Open (keyring.Config {
60- ServiceName : serviceName ,
61- FileDir : rootDir ,
62- KeychainTrustApplication : true ,
63- FilePasswordFunc : newRealPrompt (rootDir , userInput ),
64- })
65- case sdkkeyring .BackendKWallet :
66- db , err = keyring .Open (keyring.Config {
67- AllowedBackends : []keyring.BackendType {keyring .KWalletBackend },
68- ServiceName : "kdewallet" ,
69- KWalletAppID : serviceName ,
70- KWalletFolder : "" ,
71- })
72- case sdkkeyring .BackendPass :
73- prefix := fmt .Sprintf (passKeyringPrefix , serviceName )
74- db , err = keyring .Open (keyring.Config {
75- AllowedBackends : []keyring.BackendType {keyring .PassBackend },
76- ServiceName : serviceName ,
77- PassPrefix : prefix ,
78- })
79- default :
80- return nil , errorsmod .Wrap (sdkkeyring .ErrUnknownBacked , backend )
81- }
82-
83- if err != nil {
84- return nil , err
20+ var db keyring.Keyring
21+ if backend == sdkkeyring .BackendMemory {
22+ db = keyring .NewArrayKeyring (nil )
23+ } else {
24+ kr , err := sdkkeyring .New (serviceName , backend , rootDir , userInput , nil )
25+ if err != nil {
26+ return nil , err
27+ }
28+ db = kr .DB ()
8529 }
86-
8730 return newKeystore (db , backend ), nil
8831}
8932
@@ -117,86 +60,3 @@ func (ks keystore) Set(name string, secret []byte) error {
11760 Label : name ,
11861 })
11962}
120-
121- func newRealPrompt (dir string , buf io.Reader ) func (string ) (string , error ) {
122- return func (prompt string ) (string , error ) {
123- keyhashStored := false
124- keyhashFilePath := filepath .Join (dir , "keyhash" )
125-
126- var keyhash []byte
127-
128- _ , err := os .Stat (keyhashFilePath )
129-
130- switch {
131- case err == nil :
132- keyhash , err = os .ReadFile (keyhashFilePath )
133- if err != nil {
134- return "" , errorsmod .Wrap (err , fmt .Sprintf ("failed to read %s" , keyhashFilePath ))
135- }
136-
137- keyhashStored = true
138-
139- case os .IsNotExist (err ):
140- keyhashStored = false
141-
142- default :
143- return "" , errorsmod .Wrap (err , fmt .Sprintf ("failed to open %s" , keyhashFilePath ))
144- }
145-
146- failureCounter := 0
147-
148- for {
149- failureCounter ++
150- if failureCounter > maxPassphraseEntryAttempts {
151- return "" , sdkkeyring .ErrMaxPassPhraseAttempts
152- }
153-
154- buf := bufio .NewReader (buf )
155- pass , err := input .GetPassword (fmt .Sprintf ("Enter keyring passphrase (attempt %d/%d):" , failureCounter , maxPassphraseEntryAttempts ), buf )
156- if err != nil {
157- // NOTE: LGTM.io reports a false positive alert that states we are printing the password,
158- // but we only log the error.
159- //
160- // lgtm [go/clear-text-logging]
161- fmt .Fprintln (os .Stderr , err )
162- continue
163- }
164-
165- if keyhashStored {
166- if err := bcrypt .CompareHashAndPassword (keyhash , []byte (pass )); err != nil {
167- fmt .Fprintln (os .Stderr , "incorrect passphrase" )
168- continue
169- }
170-
171- return pass , nil
172- }
173-
174- reEnteredPass , err := input .GetPassword ("Re-enter keyring passphrase:" , buf )
175- if err != nil {
176- // NOTE: LGTM.io reports a false positive alert that states we are printing the password,
177- // but we only log the error.
178- //
179- // lgtm [go/clear-text-logging]
180- fmt .Fprintln (os .Stderr , err )
181- continue
182- }
183-
184- if pass != reEnteredPass {
185- fmt .Fprintln (os .Stderr , "passphrase do not match" )
186- continue
187- }
188-
189- passwordHash , err := bcrypt .GenerateFromPassword ([]byte (pass ), 2 )
190- if err != nil {
191- fmt .Fprintln (os .Stderr , err )
192- continue
193- }
194-
195- if err := os .WriteFile (keyhashFilePath , passwordHash , 0o600 ); err != nil {
196- return "" , err
197- }
198-
199- return pass , nil
200- }
201- }
202- }
0 commit comments