Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyring overhaul - take #1 #5879

Merged
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
13a973d
temp commit
jgimeno Mar 26, 2020
d5c2018
temp commit
jgimeno Mar 26, 2020
1baf2b6
add test for list
jgimeno Mar 26, 2020
ece95ef
test adding new key
jgimeno Mar 26, 2020
cdada42
add test for list
jgimeno Mar 26, 2020
760b167
implement and test Key
jgimeno Mar 26, 2020
de39a80
create and test GetByAddress
jgimeno Mar 26, 2020
85c4fd5
add delete function
jgimeno Mar 27, 2020
36548a7
add delete by address function
jgimeno Mar 27, 2020
57f7d5a
add new pub key and test
jgimeno Mar 27, 2020
2d22fbd
create function for writing multisign
jgimeno Mar 27, 2020
a9aab77
use addrKeyByString
jgimeno Mar 27, 2020
63fbdf3
implement and test multisig
jgimeno Mar 27, 2020
7255a32
add test for unsupported signing algo
jgimeno Mar 27, 2020
f3e0624
refactor algorithm
jgimeno Mar 27, 2020
0edc2d8
supported algorithm changed
jgimeno Mar 27, 2020
758af07
update al keyring
jgimeno Mar 27, 2020
a990c74
update options
jgimeno Mar 27, 2020
d999ad1
add supported algorithm test and SAveLedgerKey
jgimeno Mar 27, 2020
04b03a7
fix imports
jgimeno Mar 27, 2020
1c736f1
add signature into keyring
jgimeno Mar 30, 2020
9ede030
add method to sign by address
jgimeno Mar 30, 2020
869b35a
implement import export
jgimeno Mar 30, 2020
67c4942
implement the alt keyring
jgimeno Mar 30, 2020
482f55f
finish implementing altKeyring
jgimeno Mar 30, 2020
6434960
refactor thekey
jgimeno Mar 30, 2020
d86b467
fix the tests
jgimeno Mar 30, 2020
a0304e5
fixt ci linter errors
jgimeno Mar 30, 2020
717dae3
fix other lint
jgimeno Mar 30, 2020
f58970d
New keyring interface
Mar 26, 2020
1ff6830
temp commit
jgimeno Mar 26, 2020
21121cb
temp commit
jgimeno Mar 26, 2020
f3e7d8a
add test for list
jgimeno Mar 26, 2020
518ace9
test adding new key
jgimeno Mar 26, 2020
195de90
add test for list
jgimeno Mar 26, 2020
cdc534c
implement and test Key
jgimeno Mar 26, 2020
516ec8b
create and test GetByAddress
jgimeno Mar 26, 2020
1d795bf
add delete function
jgimeno Mar 27, 2020
2e3a8ac
add delete by address function
jgimeno Mar 27, 2020
b94cfff
add new pub key and test
jgimeno Mar 27, 2020
de0976e
create function for writing multisign
jgimeno Mar 27, 2020
46a5436
use addrKeyByString
jgimeno Mar 27, 2020
b475b6c
implement and test multisig
jgimeno Mar 27, 2020
5f961e3
add test for unsupported signing algo
jgimeno Mar 27, 2020
b704745
refactor algorithm
jgimeno Mar 27, 2020
0f4e1ed
supported algorithm changed
jgimeno Mar 27, 2020
a9fdd20
update al keyring
jgimeno Mar 27, 2020
d5ca45e
update options
jgimeno Mar 27, 2020
5c66495
add supported algorithm test and SAveLedgerKey
jgimeno Mar 27, 2020
cc2b794
fix imports
jgimeno Mar 27, 2020
a39fd3d
add signature into keyring
jgimeno Mar 30, 2020
59f9b4d
add method to sign by address
jgimeno Mar 30, 2020
a7c397e
implement import export
jgimeno Mar 30, 2020
dabff2d
implement the alt keyring
jgimeno Mar 30, 2020
639b1ca
finish implementing altKeyring
jgimeno Mar 30, 2020
8ad06f9
refactor thekey
jgimeno Mar 30, 2020
39ab64a
fix the tests
jgimeno Mar 30, 2020
ce541b1
fixt ci linter errors
jgimeno Mar 30, 2020
e98322a
fix other lint
jgimeno Mar 30, 2020
c0201b1
Merge branch 'jonathan/keyring-refactor-interface' of github.com:cosm…
jgimeno Mar 31, 2020
7a79f58
Merge branch 'alessio/new-keyring-interface' into jonathan/keyring-re…
Mar 31, 2020
ec5a657
clean up the diff
Mar 31, 2020
f62f1d2
fix tests after merge
jgimeno Mar 31, 2020
fbf08c2
add interface for signing algo
jgimeno Mar 31, 2020
54f27e1
add option to provide signingalgos and testse
jgimeno Mar 31, 2020
dbeea70
change Name to String in AltSigningAlgo
jgimeno Mar 31, 2020
0f73f74
Revert "change Name to String in AltSigningAlgo"
jgimeno Mar 31, 2020
b06b3ec
Update crypto/keyring/altkeyring.go
jgimeno Apr 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 295 additions & 0 deletions crypto/keyring/altkeyring.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
package keyring

import (
"fmt"
"io"
"sort"
"strings"

"github.com/99designs/keyring"
"github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/go-bip39"
tmcrypto "github.com/tendermint/tendermint/crypto"

sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

var (
_ Keyring = &altKeyring{}
)

// Keyring exposes operations on a generic keystore
type Keyring interface {
// List all keys.
List() ([]Info, error)

// Key and KeyByAddress return keys by uid and address respectively.
Key(uid string) (Info, error)
KeyByAddress(address types.Address) (Info, error)

//// Delete and DeleteByAddress remove keys.
Delete(uid string) error
DeleteByAddress(address types.Address) error

// NewMnemonic generates a new mnemonic, derives a hierarchical deterministic
// key from that, and persists it to storage. Returns the generated mnemonic and the key
// Info. It returns an error if it fails to generate a key for the given algo type, or if
// another key is already stored under the same name.
NewMnemonic(uid string, language Language, algo SigningAlgo) (Info, string, error)

// NewAccount converts a mnemonic to a private key and BIP-39 HD Path and persists it.
NewAccount(uid, mnemonic, bip39Passwd, hdPath string, algo SigningAlgo) (Info, error)

//// SaveLedgerKey retrieves a public key reference from a Ledger device and persists it.
//SaveLedgerKey(uid string, algo SigningAlgo, hrp string, account, index uint32) (Info, error)
//
//// SavePubKey stores a public key and returns the persisted Info structure.
//SavePubKey(uid string, pubkey crypto.PubKey, algo SigningAlgo) (Info, error)
//
//// SaveMultisig stores, stores, and returns a new multsig (offline) key reference
//SaveMultisig(uid string, pubkey crypto.PubKey) (Info, error)
//
//// SupportedAlgos returns a list of signing algorithms supported by the keybase
//SupportedAlgos() []SigningAlgo
//
//// SupportedAlgosLedger returns a list of signing algorithms supported by the keybase's ledger integration
//SupportedAlgosLedger() []SigningAlgo
}

// Signer is implemented by key stores that want to provide signing capabilities.
type Signer interface {
// Sign and SignByAddress sign byte messages with a user key.
Sign(uid string, msg []byte) ([]byte, tmcrypto.PubKey, error)
SignByAddress(address types.Address, msg []byte) ([]byte, tmcrypto.PubKey, error)
}

// Importer is implemented by key stores that support import of public and private keys.
type Importer interface {
ImportPrivKey(uid, armor, passphrase string) error
ImportPubKey(uid string, armor string) error
}

// Exporter is implemented by key stores that support export of public and private keys.
type Exporter interface {
// Export public key
ExportPubKeyArmor(uid string) (string, error)
ExportPubKeyArmorByAddress(address types.Address) (string, error)
// 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.
ExportPrivKeyArmor(uid, encryptPassphrase string) (armor string, err error)
ExportPrivKeyArmorByAddress(address types.Address, encryptPassphrase string) (armor string, err error)
}

// NewKeyring creates a new instance of a keyring. Keybase
// options can be applied when generating this new Keybase.
// Available backends are "os", "file", "kwallet", "pass", "test".
func NewAltKeyring(
appName, backend, rootDir string, userInput io.Reader, opts ...KeybaseOption,
) (Keyring, error) {

var db keyring.Keyring
var err error

switch backend {
case BackendTest:
db, err = keyring.Open(lkbToKeyringConfig(appName, rootDir, nil, true))
case BackendFile:
db, err = keyring.Open(newFileBackendKeyringConfig(appName, rootDir, userInput))
case BackendOS:
db, err = keyring.Open(lkbToKeyringConfig(appName, rootDir, userInput, false))
case BackendKWallet:
db, err = keyring.Open(newKWalletBackendKeyringConfig(appName, rootDir, userInput))
case BackendPass:
db, err = keyring.Open(newPassBackendKeyringConfig(appName, rootDir, userInput))
default:
return nil, fmt.Errorf("unknown keyring backend %v", backend)
}

if err != nil {
return nil, err
}

return altKeyring{db: db}, nil
}

type altKeyring struct {
db keyring.Keyring
}

func (a altKeyring) DeleteByAddress(address types.Address) error {
info, err := a.KeyByAddress(address)
if err != nil {
return err
}

err = a.Delete(info.GetName())
if err != nil {
return err
}

return nil
}

func (a altKeyring) Delete(uid string) error {
info, err := a.Key(uid)
if err != nil {
return err
}

err = a.db.Remove(string(addrKey(info.GetAddress())))
if err != nil {
return err
}

err = a.db.Remove(string(infoKey(uid)))
if err != nil {
return err
}

return nil
}

func (a altKeyring) KeyByAddress(address types.Address) (Info, error) {
ik, err := a.db.Get(string(addrKey(address)))
if err != nil {
return nil, err
}

if len(ik.Data) == 0 {
return nil, fmt.Errorf("key with address %s not found", address)
}

bs, err := a.db.Get(string(ik.Data))
if err != nil {
return nil, err
}

return unmarshalInfo(bs.Data)
}

func (a altKeyring) List() ([]Info, error) {
var res []Info
keys, err := a.db.Keys()
if err != nil {
return nil, err
}

sort.Strings(keys)

for _, key := range keys {
if strings.HasSuffix(key, infoSuffix) {
rawInfo, err := a.db.Get(key)
if err != nil {
return nil, err
}

if len(rawInfo.Data) == 0 {
return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, key)
}

info, err := unmarshalInfo(rawInfo.Data)
if err != nil {
return nil, err
}

res = append(res, info)
}
}

return res, nil
}

func (a altKeyring) NewMnemonic(uid string, language Language, algo SigningAlgo) (Info, string, error) {
if language != English {
return nil, "", ErrUnsupportedLanguage
}

//if !IsSupportedAlgorithm(a.SupportedAlgos(), algo) {
// return nil, "", ErrUnsupportedSigningAlgo
//}

// Default number of words (24): This generates a mnemonic directly from the
// number of words by reading system entropy.
entropy, err := bip39.NewEntropy(defaultEntropySize)
if err != nil {
return nil, "", err
}

mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
return nil, "", err
}

info, err := a.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, types.GetConfig().GetFullFundraiserPath(), algo)
if err != nil {
return nil, "", err
}

return info, mnemonic, err
}

func (a altKeyring) NewAccount(uid string, mnemonic string, bip39Passphrase string, hdPath string, algo SigningAlgo) (Info, error) {
// create master key and derive first key for keyring
derivedPriv, err := StdDeriveKey(mnemonic, bip39Passphrase, hdPath, algo)
if err != nil {
return nil, err
}

privKey, err := StdPrivKeyGen(derivedPriv, algo)
if err != nil {
return nil, err
}

var info Info
jgimeno marked this conversation as resolved.
Show resolved Hide resolved

info = a.writeLocalKey(uid, privKey, algo)

return info, nil
}

func (a altKeyring) Key(uid string) (Info, error) {
key := infoKey(uid)

bs, err := a.db.Get(string(key))
if err != nil {
return nil, err
}

if len(bs.Data) == 0 {
return nil, sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, uid)
}

return unmarshalInfo(bs.Data)
}

func (a altKeyring) writeLocalKey(name string, priv tmcrypto.PrivKey, algo SigningAlgo) Info {
// encrypt private key using keyring
pub := priv.PubKey()

info := newLocalInfo(name, pub, string(priv.Bytes()), algo)
a.writeInfo(name, info)

return info
}

func (a altKeyring) writeInfo(name string, info Info) {
// write the info by key
key := infoKey(name)
serializedInfo := marshalInfo(info)

err := a.db.Set(keyring.Item{
Key: string(key),
Data: serializedInfo,
})
if err != nil {
panic(err)
}

err = a.db.Set(keyring.Item{
Key: string(addrKey(info.GetAddress())),
Data: key,
})
if err != nil {
panic(err)
}
}
Loading