diff --git a/crypto/keyring/keyring_test.go b/crypto/keyring/keyring_test.go index 8eee0a79634b1..af6aab4da99ce 100644 --- a/crypto/keyring/keyring_test.go +++ b/crypto/keyring/keyring_test.go @@ -4,13 +4,14 @@ import ( "encoding/hex" "errors" "fmt" + "io" "os" "path/filepath" + "strconv" "strings" "testing" "github.com/99designs/keyring" - "github.com/cosmos/go-bip39" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/codec" @@ -44,131 +45,316 @@ func getCodec() codec.Codec { } func TestNewKeyring(t *testing.T) { - dir := t.TempDir() - mockIn := strings.NewReader("") cdc := getCodec() - kr, err := New("cosmos", BackendFile, dir, mockIn, cdc) - require.NoError(t, err) + tests := []struct { + name string + appName string + backend string + dir string + userInput io.Reader + cdc codec.Codec + expectedErr error + }{ + { + name: "file backend", + appName: "cosmos", + backend: BackendFile, + dir: t.TempDir(), + userInput: strings.NewReader(""), + cdc: cdc, + expectedErr: nil, + }, + { + name: "unknown backend", + appName: "cosmos", + backend: "unknown", + dir: t.TempDir(), + userInput: strings.NewReader(""), + cdc: cdc, + expectedErr: ErrUnknownBacked, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(tt.appName, tt.backend, tt.dir, tt.userInput, tt.cdc) + if tt.expectedErr == nil { + require.NoError(t, err) + } else { + require.Error(t, err) + require.Nil(t, kr) + require.True(t, errors.Is(err, tt.expectedErr)) + } + }) + } +} - nilKr, err := New("cosmos", "fuzzy", dir, mockIn, cdc) - require.Error(t, err) - require.Nil(t, nilKr) - require.True(t, errors.Is(err, ErrUnknownBacked)) +func TestNewMnemonic(t *testing.T) { + cdc := getCodec() + tests := []struct { + name string + backend string + reader *strings.Reader + userInput string + path string + algo SignatureAlgo + uid string + language Language + expectedError error + }{ + { + name: "create new mnemonic", + backend: BackendMemory, + reader: strings.NewReader(""), + userInput: "password\npassword\n", + path: sdk.FullFundraiserPath, + algo: hd.Secp256k1, + uid: "foo", + language: English, + expectedError: nil, + }, + { + name: "not supported algo", + backend: BackendMemory, + reader: strings.NewReader(""), + userInput: "password\npassword\n", + path: sdk.FullFundraiserPath, + algo: notSupportedAlgo{}, + uid: "foo", + language: English, + expectedError: ErrUnsupportedSigningAlgo, + }, + { + name: "unsupported language", + backend: BackendMemory, + reader: strings.NewReader(""), + userInput: "password\npassword\n", + path: sdk.FullFundraiserPath, + algo: hd.Secp256k1, + uid: "foo", + language: Spanish, + expectedError: ErrUnsupportedLanguage, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New("cosmos", tt.backend, t.TempDir(), tt.reader, cdc) + require.NoError(t, err) + tt.reader.Reset(tt.userInput) + k, _, err := kr.NewMnemonic(tt.uid, tt.language, tt.path, DefaultBIP39Passphrase, tt.algo) + if tt.expectedError == nil { + require.NoError(t, err) + require.Equal(t, tt.uid, k.Name) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedError)) + } + }) + } +} - mockIn.Reset("password\npassword\n") - k, _, err := kr.NewMnemonic("foo", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) +func TestKeyringDirectory(t *testing.T) { + dir := t.TempDir() + kb, err := New("keybasename", "test", dir, nil, getCodec()) require.NoError(t, err) - require.Equal(t, "foo", k.Name) -} -func TestKeyManagementKeyRing(t *testing.T) { - cdc := getCodec() - tempDir := t.TempDir() - kb, err := New("keybasename", "test", tempDir, nil, cdc) + // create some random directory inside the keyring directory to check migrate ignores + // all files other than *.info + newPath := filepath.Join(dir, "random") + require.NoError(t, os.Mkdir(newPath, 0o755)) + items, err := os.ReadDir(dir) require.NoError(t, err) - require.NotNil(t, cdc) + require.GreaterOrEqual(t, len(items), 1) + keys, err := kb.List() + require.NoError(t, err) + require.Empty(t, keys) - algo := hd.Secp256k1 - n1, n2, n3 := "personal", "business", "other" + _, _, err = kb.NewMnemonic("uid", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) - // Check empty state - records, err := kb.List() + items, err = os.ReadDir(dir) require.NoError(t, err) - require.Empty(t, records) + require.GreaterOrEqual(t, len(items), 2) +} - _, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) - require.Error(t, err, "ed25519 keys are currently not supported by keybase") +func TestNewKey(t *testing.T) { + cdc := getCodec() + tests := []struct { + name string + backend string + uid string + }{ + { + name: "key creation", + backend: BackendTest, + uid: "newKey", + }, + { + name: "in memory key creation", + backend: BackendMemory, + uid: "newKey", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) - // create some keys - _, err = kb.Key(n1) - require.Error(t, err) - // save localKey with "n1`" - k, _, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) - require.NoError(t, err) - require.Equal(t, n1, k.Name) + // Check empty state + l, err := kb.List() + require.NoError(t, err) + require.Empty(t, l) - // save localKey with "n2" - k1, _, err := kb.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) - require.NoError(t, err) - require.Equal(t, n2, k1.Name) + _, err = kb.Key(tt.uid) + require.Error(t, err) - k2, err := kb.Key(n2) - require.NoError(t, err) - _, err = kb.Key(n3) - require.NotNil(t, err) - addr, err := k2.GetAddress() - require.NoError(t, err) - _, err = kb.KeyByAddress(addr) - require.NoError(t, err) - addr, err = sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") - require.NoError(t, err) - _, err = kb.KeyByAddress(addr) - require.Error(t, err) + r, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + require.Equal(t, tt.uid, r.Name) - // list shows them in order - keyS, err := kb.List() - require.NoError(t, err) - require.Equal(t, 2, len(keyS)) - // note these are in alphabetical order - require.Equal(t, n2, keyS[0].Name) - require.Equal(t, n1, keyS[1].Name) + k, err := kb.Key(tt.uid) + require.NoError(t, err) - key1, err := k2.GetPubKey() - require.NoError(t, err) - require.NotNil(t, key1) - key2, err := keyS[0].GetPubKey() - require.NoError(t, err) - require.NotNil(t, key2) - require.Equal(t, key1, key2) + addr, err := accAddr(k) + require.NoError(t, err) + _, err = kb.KeyByAddress(addr) + require.NoError(t, err) - // deleting a key removes it - err = kb.Delete("bad name") - require.NotNil(t, err) - err = kb.Delete(n1) - require.NoError(t, err) - keyS, err = kb.List() - require.NoError(t, err) - require.Equal(t, 1, len(keyS)) - _, err = kb.Key(n1) - require.Error(t, err) + addr, err = sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") + require.NoError(t, err) + _, err = kb.KeyByAddress(addr) + require.NotNil(t, err) - // create an offline key - o1 := "offline" - priv1 := ed25519.GenPrivKey() - pub1 := priv1.PubKey() - k3, err := kb.SaveOfflineKey(o1, pub1) - require.Nil(t, err) + // list shows them in order + keyS, err := kb.List() + require.NoError(t, err) + require.Equal(t, 1, len(keyS)) + require.Equal(t, tt.uid, keyS[0].Name) + }) + } +} - key1, err = k3.GetPubKey() - require.NoError(t, err) - require.NotNil(t, key1) - require.Equal(t, pub1, key1) +func TestGetPub(t *testing.T) { + cdc := getCodec() + tests := []struct { + name string + backend string + uid string + }{ + { + name: "correct get", + backend: BackendTest, + uid: "getKey", + }, + { + name: "in memory correct get", + backend: BackendMemory, + uid: "getMemoryKey", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) - require.Equal(t, o1, k3.Name) - keyS, err = kb.List() - require.NoError(t, err) - require.Equal(t, 2, len(keyS)) + r, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + require.Equal(t, tt.uid, r.Name) - // delete the offline key - err = kb.Delete(o1) - require.NoError(t, err) - keyS, err = kb.List() - require.NoError(t, err) - require.Equal(t, 1, len(keyS)) + k, err := kb.Key(tt.uid) + require.NoError(t, err) + _, err = k.GetPubKey() + require.NoError(t, err) - // create some random directory inside the keyring directory to check migrate ignores - // all files other than *.info - newPath := filepath.Join(tempDir, "random") - require.NoError(t, os.Mkdir(newPath, 0o755)) - items, err := os.ReadDir(tempDir) - require.NoError(t, err) - require.GreaterOrEqual(t, len(items), 2) - _, err = kb.List() - require.NoError(t, err) + keyS, err := kb.List() + require.NoError(t, err) + require.Equal(t, 1, len(keyS)) - // addr cache gets nuked - and test skip flag - require.NoError(t, kb.Delete(n2)) + }) + } +} + +func TestDeleteKey(t *testing.T) { + cdc := getCodec() + tests := []struct { + name string + backend string + uid string + }{ + { + name: "delete", + backend: BackendTest, + uid: "key", + }, + { + name: "in memory delete", + backend: BackendMemory, + uid: "key", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + + r, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + require.Equal(t, tt.uid, r.Name) + + err = kb.Delete(tt.uid) + require.NoError(t, err) + list, err := kb.List() + require.NoError(t, err) + require.Empty(t, list) + }) + } +} + +func TestOfflineKey(t *testing.T) { + cdc := getCodec() + tests := []struct { + name string + backend string + uid string + }{ + { + name: "offline creation", + backend: BackendTest, + uid: "offline", + }, + { + name: "in memory offline creation", + backend: BackendMemory, + uid: "offline", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + + priv := ed25519.GenPrivKey() + pub := priv.PubKey() + k, err := kb.SaveOfflineKey(tt.uid, pub) + require.NoError(t, err) + require.Equal(t, tt.uid, k.Name) + + key, err := k.GetPubKey() + require.NoError(t, err) + require.Equal(t, pub, key) + + require.NotNil(t, k.GetOffline()) + keys, err := kb.List() + require.NoError(t, err) + require.Equal(t, 1, len(keys)) + + err = kb.Delete(tt.uid) + require.NoError(t, err) + keys, err = kb.List() + require.NoError(t, err) + require.Empty(t, keys) + }) + } } func TestSignVerifyKeyRing(t *testing.T) { @@ -258,368 +444,704 @@ func TestSignVerifyKeyRing(t *testing.T) { require.Equal(t, "cannot sign with offline keys", err.Error()) } -func TestExportImportKeyRing(t *testing.T) { - cdc := getCodec() - kb, err := New("keybasename", "test", t.TempDir(), nil, cdc) - require.NoError(t, err) - - k, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - name := k.Name - require.NoError(t, err) - require.Equal(t, name, "john") - - john, err := kb.Key("john") - require.NoError(t, err) - require.Equal(t, name, "john") - key, err := k.GetPubKey() - require.NoError(t, err) - johnAddr := key.Address() - - armor, err := kb.ExportPrivKeyArmor("john", "apassphrase") - require.NoError(t, err) - err = kb.Delete("john") - require.NoError(t, err) - - err = kb.ImportPrivKey("john2", armor, "apassphrase") - require.NoError(t, err) - - john2, err := kb.Key("john2") - require.NoError(t, err) - - require.Equal(t, key.Address(), johnAddr) - require.Equal(t, john.Name, "john") - - addr, err := john.GetAddress() - require.NoError(t, err) - addr2, err := john2.GetAddress() - require.NoError(t, err) - require.Equal(t, addr, addr2) - - key, err = john.GetPubKey() - require.NoError(t, err) - key2, err := john2.GetPubKey() - require.NoError(t, err) - - require.True(t, key.Equals(key2)) -} - -func TestExportImportPubKeyKeyRing(t *testing.T) { +func TestExportPrivKey(t *testing.T) { cdc := getCodec() - kb, err := New("keybasename", "test", t.TempDir(), nil, cdc) - require.NoError(t, err) - algo := hd.Secp256k1 - - // CreateMnemonic a private-public key pair and ensure consistency - k, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) - require.Nil(t, err) - require.NotNil(t, k) - require.Equal(t, k.Name, "john") - key, err := k.GetPubKey() - require.NoError(t, err) - addr := key.Address() - john, err := kb.Key("john") - require.NoError(t, err) - require.Equal(t, john.Name, "john") - - key, err = john.GetPubKey() - require.NoError(t, err) - require.Equal(t, key.Address(), addr) - - // Export the public key only - armor, err := kb.ExportPubKeyArmor("john") - require.NoError(t, err) - err = kb.Delete("john") - require.NoError(t, err) - - // Import it under a different name - err = kb.ImportPubKey("john-pubkey-only", armor) - require.NoError(t, err) - - // Ensure consistency - john2, err := kb.Key("john-pubkey-only") - require.NoError(t, err) - key2, err := john2.GetPubKey() - require.NoError(t, err) - - // Compare the public keys - require.True(t, key.Equals(key2)) - - // Ensure keys cannot be overwritten - err = kb.ImportPubKey("john-pubkey-only", armor) - require.NotNil(t, err) + tests := []struct { + name string + uid string + backend string + encryptPassphrase string + createKey func(keystore2 Keyring) (*Record, string, error) + expectedErr error + }{ + { + name: "correct export", + uid: "correctTest", + backend: BackendTest, + encryptPassphrase: "myPassphrase", + createKey: func(keystore Keyring) (*Record, string, error) { + return keystore.NewMnemonic("correctTest", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, + hd.Secp256k1) + }, + expectedErr: nil, + }, + { + name: "correct in memory export", + uid: "inMemory", + backend: BackendMemory, + encryptPassphrase: "myPassphrase", + createKey: func(keystore Keyring) (*Record, string, error) { + return keystore.NewMnemonic("inMemory", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, + hd.Secp256k1) + }, + expectedErr: nil, + }, + { + name: "key is not created", + uid: "noKeyTest", + backend: BackendTest, + encryptPassphrase: "myPassphrase", + createKey: func(keystore Keyring) (*Record, string, error) { + return nil, "", nil + }, + expectedErr: sdkerrors.ErrKeyNotFound, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("testExport", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + _, _, err = tt.createKey(kb) + require.NoError(t, err) + _, err = kb.ExportPrivKeyArmor(tt.uid, tt.encryptPassphrase) + if tt.expectedErr == nil { + require.NoError(t, err) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedErr)) + } + }) + } } -func TestAdvancedKeyManagementKeyRing(t *testing.T) { - dir := t.TempDir() +func TestImportPrivKey(t *testing.T) { cdc := getCodec() - - kb, err := New("keybasename", "test", dir, nil, cdc) - require.NoError(t, err) - - algo := hd.Secp256k1 - n1, n2 := "old-name", "new name" - - // make sure key works with initial password - _, _, err = kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) - require.Nil(t, err, "%+v", err) - - _, err = kb.ExportPubKeyArmor(n1 + ".notreal") - require.NotNil(t, err) - _, err = kb.ExportPubKeyArmor(" " + n1) - require.NotNil(t, err) - _, err = kb.ExportPubKeyArmor(n1 + " ") - require.NotNil(t, err) - _, err = kb.ExportPubKeyArmor("") - require.NotNil(t, err) - exported, err := kb.ExportPubKeyArmor(n1) - require.Nil(t, err, "%+v", err) - err = kb.Delete(n1) - require.NoError(t, err) - - // import succeeds - err = kb.ImportPubKey(n2, exported) - require.NoError(t, err) - - // second import fails - err = kb.ImportPubKey(n2, exported) - require.NotNil(t, err) + tests := []struct { + name string + uid string + backend string + encryptPassphrase string + armor string + expectedErr error + }{ + { + name: "correct import", + uid: "testOne", + backend: BackendTest, + encryptPassphrase: "this passphrase has been used for all test vectors", + armor: "-----BEGIN TENDERMINT PRIVATE KEY-----\nkdf: bcrypt\nsalt: 6BC5D5187F9DF241E1A1243EECFF9C17\ntype: secp256k1\n\nGDPpPfrSVZloiwufbal19fmd75QeiqwToZ949SwmnxxM03qL75xXVf3tTD/BrF4l\nFs14HuhwntDBM2xgZvymTBk2edHlEI20Phv6oC0=\n=/zZh\n-----END TENDERMINT PRIVATE KEY-----", + expectedErr: nil, + }, + { + name: "correct import", + uid: "inMemory", + backend: BackendMemory, + encryptPassphrase: "this passphrase has been used for all test vectors", + armor: "-----BEGIN TENDERMINT PRIVATE KEY-----\nkdf: bcrypt\nsalt: 6BC5D5187F9DF241E1A1243EECFF9C17\ntype: secp256k1\n\nGDPpPfrSVZloiwufbal19fmd75QeiqwToZ949SwmnxxM03qL75xXVf3tTD/BrF4l\nFs14HuhwntDBM2xgZvymTBk2edHlEI20Phv6oC0=\n=/zZh\n-----END TENDERMINT PRIVATE KEY-----", + expectedErr: nil, + }, + { + name: "wrong armor", + uid: "testWrongArmor", + backend: BackendTest, + encryptPassphrase: "this passphrase has been used for all test vectors", + armor: "-----BEGIN TENDERMINT PRIVATE KEY-----\nkdf: bcrypt\nsalt: 7BC5D5187F9DF241E1A1243EECFF9C17\ntype: secp256k1\n\nGDPpPfrSVZloiwufbal19fmd75QeiqwToZ949SwmnxxM03qL75xXVf3tTD/BrF4l\nFs14HuhwntDBM2xgZvymTBk2edHlEI20Phv6oC0=\n=/zZh\n-----END TENDERMINT PRIVATE KEY-----", + expectedErr: sdkerrors.ErrWrongPassword, + }, + { + name: "incorrect passphrase", + uid: "testIncorrectPassphrase", + backend: BackendTest, + encryptPassphrase: "wrong passphrase", + armor: "-----BEGIN TENDERMINT PRIVATE KEY-----\nkdf: bcrypt\nsalt: 6BC5D5187F9DF241E1A1243EECFF9C17\ntype: secp256k1\n\nGDPpPfrSVZloiwufbal19fmd75QeiqwToZ949SwmnxxM03qL75xXVf3tTD/BrF4l\nFs14HuhwntDBM2xgZvymTBk2edHlEI20Phv6oC0=\n=/zZh\n-----END TENDERMINT PRIVATE KEY-----", + expectedErr: sdkerrors.ErrWrongPassword, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("TestExport", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + err = kb.ImportPrivKey(tt.uid, tt.armor, tt.encryptPassphrase) + if tt.expectedErr == nil { + require.NoError(t, err) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedErr)) + } + }) + } } -func TestSeedPhraseKeyRing(t *testing.T) { - dir := t.TempDir() +func TestExportImportPrivKey(t *testing.T) { cdc := getCodec() + tests := []struct { + name string + uid string + backend string + userInput io.Reader + encryptPassphrase string + importUID string + importPassphrase string + }{ + { + name: "export import", + uid: "testOne", + backend: BackendTest, + userInput: nil, + encryptPassphrase: "apassphrase", + importUID: "importedKey", + importPassphrase: "apassphrase", + }, + { + name: "memory export import", + uid: "inMemory", + backend: BackendMemory, + userInput: nil, + encryptPassphrase: "apassphrase", + importUID: "importedKey", + importPassphrase: "apassphrase", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("TestExport", tt.backend, t.TempDir(), tt.userInput, cdc) + require.NoError(t, err) + k, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + require.NotNil(t, k) + require.Equal(t, k.Name, tt.uid) + + record, err := kb.Key(tt.uid) + require.NoError(t, err) + require.Equal(t, record.Name, tt.uid) + key, err := k.GetPubKey() + require.NoError(t, err) + + armor, err := kb.ExportPrivKeyArmor(tt.uid, tt.encryptPassphrase) + require.NoError(t, err) + + // Import while key has not been deleted + err = kb.ImportPrivKey(tt.uid, armor, tt.importPassphrase) + require.Error(t, err) + require.True(t, errors.Is(err, ErrOverwriteKey)) - kb, err := New("keybasename", "test", dir, nil, cdc) - require.NoError(t, err) + err = kb.Delete(tt.uid) + require.NoError(t, err) - algo := hd.Secp256k1 - n1, n2 := "lost-key", "found-again" - - // make sure key works with initial password - k, mnemonic, err := kb.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) - require.Nil(t, err, "%+v", err) - require.Equal(t, n1, k.Name) - require.NotEmpty(t, mnemonic) - key, err := k.GetPubKey() - require.NoError(t, err) + err = kb.ImportPrivKey(tt.importUID, armor, tt.importPassphrase) + require.NoError(t, err) - // now, let us delete this key - err = kb.Delete(n1) - require.Nil(t, err, "%+v", err) - _, err = kb.Key(n1) - require.NotNil(t, err) + importedRecord, err := kb.Key(tt.importUID) + require.NoError(t, err) + require.Equal(t, importedRecord.Name, tt.importUID) + importedKey, err := importedRecord.GetPubKey() + require.NoError(t, err) - // let us re-create it from the mnemonic-phrase - hdPath := hd.NewFundraiserParams(0, sdk.CoinType, 0).String() - k1, err := kb.NewAccount(n2, mnemonic, DefaultBIP39Passphrase, hdPath, hd.Secp256k1) - require.NoError(t, err) - require.Equal(t, n2, k1.Name) - newKey, err := k1.GetPubKey() - require.NoError(t, err) + require.Equal(t, key.Address(), importedKey.Address()) - require.Equal(t, key.Address(), newKey.Address()) - require.Equal(t, key, newKey) + addr, err := record.GetAddress() + require.NoError(t, err) + importedAddr, err := importedRecord.GetAddress() + require.NoError(t, err) + require.True(t, addr.Equals(importedAddr)) + }) + } } -func TestKeyringKeybaseExportImportPrivKey(t *testing.T) { +func TestImportExportPrivKeyByAddress(t *testing.T) { cdc := getCodec() - kb, err := New("keybasename", "test", t.TempDir(), nil, cdc) - require.NoError(t, err) - - _, _, err = kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - keystr, err := kb.ExportPrivKeyArmor("john", "somepassword") - require.NoError(t, err) - require.NotEmpty(t, keystr) - err = kb.Delete("john") - require.NoError(t, err) + tests := []struct { + name string + uid string + backend string + passphrase string + importPassphrase string + expectedErr error + }{ + { + name: "correct import export", + uid: "okTest", + backend: BackendTest, + passphrase: "exportKey", + importPassphrase: "exportKey", + expectedErr: nil, + }, + { + name: "correct in memory import export", + uid: "inMemory", + backend: BackendMemory, + passphrase: "exportKey", + importPassphrase: "exportKey", + expectedErr: nil, + }, + { + name: "wrong passphrase import", + uid: "incorrectPass", + backend: BackendTest, + passphrase: "exportKey", + importPassphrase: "incorrectPassphrase", + expectedErr: sdkerrors.ErrWrongPassword, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) - // try import the key - wrong password - err = kb.ImportPrivKey("john2", keystr, "bad pass") - require.True(t, errors.Is(err, sdkerrors.ErrWrongPassword)) + mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) - // try import the key with the correct password - require.NoError(t, kb.ImportPrivKey("john2", keystr, "somepassword")) + addr, err := mnemonic.GetAddress() + require.NoError(t, err) + armor, err := kr.ExportPrivKeyArmorByAddress(addr, tt.passphrase) + require.NoError(t, err) - // overwrite is not allowed - err = kb.ImportPrivKey("john2", keystr, "password") - require.True(t, errors.Is(err, ErrOverwriteKey)) + // Should fail importing private key on existing key. + err = kr.ImportPrivKey(tt.uid, armor, tt.passphrase) + require.True(t, errors.Is(err, ErrOverwriteKey)) - // try export non existing key - _, err = kb.ExportPrivKeyArmor("john3", "wrongpassword") - require.EqualError(t, err, "john3.info: key not found") -} + err = kr.Delete(tt.uid) + require.NoError(t, err) -func TestInMemoryLanguage(t *testing.T) { - cdc := getCodec() - kb := NewInMemory(cdc) - _, _, err := kb.NewMnemonic("something", Japanese, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.Error(t, err) - require.Equal(t, "unsupported language: only english is supported", err.Error()) + err = kr.ImportPrivKey(tt.uid, armor, tt.importPassphrase) + if tt.expectedErr == nil { + require.NoError(t, err) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedErr)) + } + }) + } } -func TestInMemoryWithKeyring(t *testing.T) { - priv := types.PrivKey(secp256k1.GenPrivKey()) - pub := priv.PubKey() - +func TestExportPubkey(t *testing.T) { cdc := getCodec() - _, err := NewLocalRecord("test record", priv, pub) - require.NoError(t, err) - - multi := multisig.NewLegacyAminoPubKey( - 1, []types.PubKey{ - pub, + tests := []struct { + name string + uid string + backend string + exportUID string + getPubkey func(r *Record) (types.PubKey, error) + codec codec.Codec + expectedErr error + }{ + { + name: "correct export", + uid: "correctExport", + backend: BackendTest, + exportUID: "correctExport", + getPubkey: func(r *Record) (types.PubKey, error) { + return r.GetPubKey() + }, + codec: cdc, + expectedErr: nil, }, - ) - - appName := "test-app" - - legacyMultiInfo, err := NewLegacyMultiInfo(appName, multi) - require.NoError(t, err) - serializedLegacyMultiInfo := MarshalInfo(legacyMultiInfo) - - kb := NewInMemoryWithKeyring(keyring.NewArrayKeyring([]keyring.Item{ { - Key: appName + ".info", - Data: serializedLegacyMultiInfo, - Description: "test description", + name: "wrong uid at export", + uid: "wrongUID", + backend: BackendTest, + exportUID: "notAValidUID", + getPubkey: func(r *Record) (types.PubKey, error) { + return r.GetPubKey() + }, + codec: cdc, + expectedErr: sdkerrors.ErrKeyNotFound, }, - }), cdc) - - t.Run("key exists", func(t *testing.T) { - _, err := kb.Key(appName) - require.NoError(t, err) - }) - - t.Run("key deleted", func(t *testing.T) { - err := kb.Delete(appName) - require.NoError(t, err) - - t.Run("key is gone", func(t *testing.T) { - _, err := kb.Key(appName) - require.Error(t, err) + { + name: "previous space on export uid", + uid: "prefixSpace", + backend: BackendTest, + exportUID: " prefixSpace", + getPubkey: func(r *Record) (types.PubKey, error) { + return r.GetPubKey() + }, + codec: cdc, + expectedErr: sdkerrors.ErrKeyNotFound, + }, + { + name: "export uid with suffix space", + uid: "suffixSpace", + backend: BackendTest, + exportUID: "suffixSpace ", + getPubkey: func(r *Record) (types.PubKey, error) { + return r.GetPubKey() + }, + codec: cdc, + expectedErr: sdkerrors.ErrKeyNotFound, + }, + { + name: "correct in memory export", + uid: "inMemory", + backend: BackendMemory, + exportUID: "inMemory", + getPubkey: func(r *Record) (types.PubKey, error) { + return r.GetPubKey() + }, + codec: cdc, + expectedErr: nil, + }, + { + name: "in memory wrong uid at export", + uid: "wrongUid", + backend: BackendMemory, + exportUID: "notAValidUid", + getPubkey: func(r *Record) (types.PubKey, error) { + return r.GetPubKey() + }, + codec: cdc, + expectedErr: sdkerrors.ErrKeyNotFound, + }, + { + name: "in memory previous space on export uid", + uid: "prefixSpace", + backend: BackendMemory, + exportUID: " prefixSpace", + getPubkey: func(r *Record) (types.PubKey, error) { + return r.GetPubKey() + }, + codec: cdc, + expectedErr: sdkerrors.ErrKeyNotFound, + }, + { + name: "in memory export uid with suffix space", + uid: "suffixSpace", + backend: BackendMemory, + exportUID: "suffixSpace ", + getPubkey: func(r *Record) (types.PubKey, error) { + return r.GetPubKey() + }, + codec: cdc, + expectedErr: sdkerrors.ErrKeyNotFound, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("keybase", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + k, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + require.NotNil(t, k) + _, err = tt.getPubkey(k) + require.NoError(t, err) + _, err = kb.ExportPubKeyArmor(tt.exportUID) + if tt.expectedErr == nil { + require.NoError(t, err) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedErr)) + } }) - }) + } } -func TestInMemoryCreateMultisig(t *testing.T) { +func TestImportPubKey(t *testing.T) { cdc := getCodec() - kb, err := New("keybasename", "memory", "", nil, cdc) - require.NoError(t, err) - multi := multisig.NewLegacyAminoPubKey( - 1, []types.PubKey{ - secp256k1.GenPrivKey().PubKey(), + tests := []struct { + name string + uid string + backend string + armor string + expectedErr error + }{ + { + name: "correct import", + uid: "correctTest", + backend: BackendTest, + armor: "-----BEGIN TENDERMINT PUBLIC KEY-----\nversion: 0.0.1\ntype: secp256k1\n\nCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOlcgxiZM4cR0LA\nwum483+L6zRnXC6zEKtQ4FEa6z0VrA==\n=CqBG\n-----END TENDERMINT PUBLIC KEY-----", + expectedErr: nil, }, - ) - _, err = kb.SaveMultisig("multi", multi) - require.NoError(t, err) + { + name: "modified armor", + uid: "modified", + backend: BackendTest, + armor: "-----BEGIN TENDERMINT PUBLIC KEY-----\nversion: 0.0.1\ntype: secp256k1\n\nCh8vY29zbW8zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOlcgxiZM4cR0LA\nwum483+L6zRnXC6zEKtQ4FEa6z0VrA==\n=CqBG\n-----END TENDERMINT PUBLIC KEY-----", + expectedErr: fmt.Errorf("couldn't unarmor bytes: openpgp: invalid data: armor invalid"), + }, + { + name: "empty armor", + uid: "empty", + backend: BackendTest, + armor: "", + expectedErr: fmt.Errorf("couldn't unarmor bytes: EOF"), + }, + { + name: "correct in memory import", + uid: "inMemory", + backend: BackendMemory, + armor: "-----BEGIN TENDERMINT PUBLIC KEY-----\nversion: 0.0.1\ntype: secp256k1\n\nCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQOlcgxiZM4cR0LA\nwum483+L6zRnXC6zEKtQ4FEa6z0VrA==\n=CqBG\n-----END TENDERMINT PUBLIC KEY-----", + expectedErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + err = kb.ImportPubKey(tt.uid, tt.armor) + if tt.expectedErr == nil { + require.NoError(t, err) + } else { + require.Equal(t, err, tt.expectedErr) + } + }) + } } -func TestInMemoryCreateAccountInvalidMnemonic(t *testing.T) { +func TestExportImportPubKeyKey(t *testing.T) { cdc := getCodec() - kb := NewInMemory(cdc) - _, err := kb.NewAccount( - "some_account", - "malarkey pair crucial catch public canyon evil outer stage ten gym tornado", - "", hd.CreateHDPath(118, 0, 0).String(), hd.Secp256k1) - require.Error(t, err) - require.Equal(t, "Invalid mnemonic", err.Error()) + tests := []struct { + name string + uid string + backend string + importUID string + }{ + { + name: "complete export import", + uid: "testOne", + backend: BackendTest, + importUID: "importedKey", + }, + { + name: "in memory export import", + uid: "inMemory", + backend: BackendMemory, + importUID: "importedKey", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + + k, _, err := kb.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.Nil(t, err) + require.NotNil(t, k) + require.Equal(t, k.Name, tt.uid) + + key, err := k.GetPubKey() + require.NoError(t, err) + + record, err := kb.Key(tt.uid) + require.NoError(t, err) + require.Equal(t, record.Name, tt.uid) + + pk, err := record.GetPubKey() + require.NoError(t, err) + require.Equal(t, key.Address(), pk.Address()) + + // Export the public key only + armor, err := kb.ExportPubKeyArmor(tt.uid) + require.NoError(t, err) + err = kb.Delete(tt.uid) + require.NoError(t, err) + + // Import it under a different name + err = kb.ImportPubKey(tt.importUID, armor) + require.NoError(t, err) + + // Ensure consistency + record2, err := kb.Key(tt.importUID) + require.NoError(t, err) + key2, err := record2.GetPubKey() + require.NoError(t, err) + + // Compare the public keys + require.True(t, key.Equals(key2)) + + // Ensure keys cannot be overwritten + err = kb.ImportPubKey(tt.importUID, armor) + require.NotNil(t, err) + }) + } } -// TestInMemoryKeyManagement makes sure we can manipulate these keys well -func TestInMemoryKeyManagement(t *testing.T) { - // make the storage with reasonable defaults +func TestImportExportPubKeyByAddress(t *testing.T) { cdc := getCodec() - cstore := NewInMemory(cdc) + tests := []struct { + name string + backend string + uid string + }{ + { + name: "import export", + backend: BackendTest, + uid: "okTest", + }, + { + name: "in memory import export", + backend: BackendMemory, + uid: "okTest", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) - algo := hd.Secp256k1 - n1, n2, n3 := "personal", "business", "other" + mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) - // Check empty state - l, err := cstore.List() - require.NoError(t, err) - require.Empty(t, l) + addr, err := mnemonic.GetAddress() + require.NoError(t, err) + armor, err := kr.ExportPubKeyArmorByAddress(addr) + require.NoError(t, err) - _, _, err = cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) - require.Error(t, err, "ed25519 keys are currently not supported by keybase") + // Should fail importing private key on existing key. + err = kr.ImportPubKey(tt.uid, armor) + require.True(t, errors.Is(err, ErrOverwriteKey)) - // create some keys - _, err = cstore.Key(n1) - require.Error(t, err) - k, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) + err = kr.Delete(tt.uid) + require.NoError(t, err) - require.NoError(t, err) - require.Equal(t, n1, k.Name) - _, _, err = cstore.NewMnemonic(n2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) - require.NoError(t, err) + err = kr.ImportPubKey(tt.uid, armor) + require.NoError(t, err) + }) + } +} - // we can get these keys - k2, err := cstore.Key(n2) - require.NoError(t, err) - _, err = cstore.Key(n3) - require.NotNil(t, err) - addr, err := accAddr(k2) - require.NoError(t, err) - _, err = cstore.KeyByAddress(addr) - require.NoError(t, err) - addr, err = sdk.AccAddressFromBech32("cosmos1yq8lgssgxlx9smjhes6ryjasmqmd3ts2559g0t") +func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) { + cdc := getCodec() + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) require.NoError(t, err) - _, err = cstore.KeyByAddress(addr) - require.NotNil(t, err) - // list shows them in order - keyS, err := cstore.List() - require.NoError(t, err) - require.Equal(t, 2, len(keyS)) - // note these are in alphabetical order - require.Equal(t, n2, keyS[0].Name) - require.Equal(t, n1, keyS[1].Name) + uid := theID - key1, err := k2.GetPubKey() - require.NoError(t, err) - key2, err := keyS[0].GetPubKey() + _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) require.NoError(t, err) - require.True(t, key1.Equals(key2)) + privKey, err := kr.(keystore).ExportPrivateKeyObject(uid) - // deleting a key removes it - err = cstore.Delete("bad name") - require.NotNil(t, err) - err = cstore.Delete(n1) - require.NoError(t, err) - keyS, err = cstore.List() require.NoError(t, err) - require.Equal(t, 1, len(keyS)) - _, err = cstore.Key(n1) + require.Equal(t, 64, len(hex.EncodeToString(privKey.Bytes()))) + + // test error on non existing key + _, err = kr.(keystore).ExportPrivateKeyObject("non-existing") require.Error(t, err) +} - // create an offline key - o1 := "offline" - priv1 := ed25519.GenPrivKey() - pub1 := priv1.PubKey() - k, err = cstore.SaveOfflineKey(o1, pub1) - require.Nil(t, err) +func TestNewAccount(t *testing.T) { + cdc := getCodec() - key, err := k.GetPubKey() - require.NoError(t, err) - require.Equal(t, pub1, key) + tests := []struct { + name string + backend string + uid string + bip39Passphrease string + hdpath string + algo SignatureAlgo + mnemonic string + expectedErr error + }{ + { + name: "correct mnemonic", + uid: "correctTest", + backend: BackendTest, + hdpath: sdk.FullFundraiserPath, + bip39Passphrease: "", + algo: hd.Secp256k1, + mnemonic: "aunt imitate maximum student guard unhappy guard rotate marine panel negative merit record priority zoo voice mixture boost describe fruit often occur expect teach", + expectedErr: nil, + }, + { + name: "correct in memory mnemonic", + uid: "inMemory", + backend: BackendMemory, + hdpath: sdk.FullFundraiserPath, + bip39Passphrease: "", + algo: hd.Secp256k1, + mnemonic: "aunt imitate maximum student guard unhappy guard rotate marine panel negative merit record priority zoo voice mixture boost describe fruit often occur expect teach", + expectedErr: nil, + }, + { + name: "unsupported Algo", + uid: "correctTest", + backend: BackendTest, + hdpath: sdk.FullFundraiserPath, + bip39Passphrease: "", + algo: notSupportedAlgo{}, + mnemonic: "aunt imitate maximum student guard unhappy guard rotate marine panel negative merit record priority zoo voice mixture boost describe fruit often occur expect teach", + expectedErr: ErrUnsupportedSigningAlgo, + }, + { + name: "wrong mnemonic", + uid: "wrongMnemonic", + backend: BackendTest, + hdpath: sdk.FullFundraiserPath, + bip39Passphrease: "", + algo: hd.Secp256k1, + mnemonic: "fresh enact fresh ski large bicycle marine abandon motor end pact mixture annual elite bind fan write warrior adapt common manual cool happy dutch", + expectedErr: fmt.Errorf("Invalid byte at position"), + }, + { + name: "in memory invalid mnemonic", + uid: "memoryInvalid", + backend: BackendMemory, + hdpath: sdk.FullFundraiserPath, + bip39Passphrease: "", + algo: hd.Secp256k1, + mnemonic: "malarkey pair crucial catch public canyon evil outer stage ten gym tornado", + expectedErr: fmt.Errorf("Invalid mnemonic"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kb, err := New("keybasename", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + k1, err := kb.NewAccount(tt.uid, tt.mnemonic, DefaultBIP39Passphrase, tt.hdpath, tt.algo) + if tt.expectedErr == nil { + require.NoError(t, err) + require.Equal(t, tt.uid, k1.Name) + } else { + require.Error(t, err) + require.ErrorContains(t, err, err.Error()) + } + }) + } +} - require.Equal(t, o1, k.Name) - require.NotNil(t, k.GetOffline()) - keyS, err = cstore.List() - require.NoError(t, err) - require.Equal(t, 2, len(keyS)) +func TestInMemoryWithKeyring(t *testing.T) { + priv := types.PrivKey(secp256k1.GenPrivKey()) + pub := priv.PubKey() - // delete the offline key - err = cstore.Delete(o1) + cdc := getCodec() + _, err := NewLocalRecord("test record", priv, pub) require.NoError(t, err) - keyS, err = cstore.List() + + multi := multisig.NewLegacyAminoPubKey( + 1, []types.PubKey{ + pub, + }, + ) + + appName := "test-app" + + legacyMultiInfo, err := NewLegacyMultiInfo(appName, multi) require.NoError(t, err) - require.Equal(t, 1, len(keyS)) + serializedLegacyMultiInfo := MarshalInfo(legacyMultiInfo) - // addr cache gets nuked - and test skip flag - err = cstore.Delete(n2) + kb := NewInMemoryWithKeyring(keyring.NewArrayKeyring([]keyring.Item{ + { + Key: appName + ".info", + Data: serializedLegacyMultiInfo, + Description: "test description", + }, + }), cdc) + + t.Run("key exists", func(t *testing.T) { + _, err := kb.Key(appName) + require.NoError(t, err) + }) + + t.Run("key deleted", func(t *testing.T) { + err := kb.Delete(appName) + require.NoError(t, err) + + t.Run("key is gone", func(t *testing.T) { + _, err := kb.Key(appName) + require.Error(t, err) + }) + }) +} + +func TestInMemoryCreateMultisig(t *testing.T) { + cdc := getCodec() + kb, err := New("keybasename", "memory", "", nil, cdc) + require.NoError(t, err) + multi := multisig.NewLegacyAminoPubKey( + 1, []types.PubKey{ + secp256k1.GenPrivKey().PubKey(), + }, + ) + _, err = kb.SaveMultisig("multi", multi) require.NoError(t, err) } @@ -706,189 +1228,50 @@ func TestInMemorySignVerify(t *testing.T) { require.Equal(t, "cannot sign with offline keys", err.Error()) } -// TestInMemoryExportImport tests exporting and importing -func TestInMemoryExportImport(t *testing.T) { - // make the storage with reasonable defaults - cdc := getCodec() - cstore := NewInMemory(cdc) - - k, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - require.Equal(t, k.Name, "john") - - john, err := cstore.Key("john") - require.NoError(t, err) - require.Equal(t, k.Name, "john") - johnKey, err := k.GetPubKey() - require.NoError(t, err) - johnAddr := johnKey.Address() - - armor, err := cstore.ExportPubKeyArmor("john") - require.NoError(t, err) - err = cstore.Delete("john") - require.NoError(t, err) - - err = cstore.ImportPubKey("john2", armor) - require.NoError(t, err) - - john2, err := cstore.Key("john2") - require.NoError(t, err) - - require.Equal(t, johnKey.Address(), johnAddr) - require.Equal(t, john.Name, "john") - - johnSdkAddress, err := john.GetAddress() - require.NoError(t, err) - john2SdkAddress, err := john2.GetAddress() - require.NoError(t, err) - require.Equal(t, johnSdkAddress, john2SdkAddress) - john2Key, err := john2.GetPubKey() - require.NoError(t, err) - - require.True(t, johnKey.Equals(john2Key)) -} - -func TestInMemoryExportImportPrivKey(t *testing.T) { - cdc := getCodec() - kb := NewInMemory(cdc) - - k, _, err := kb.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - require.Equal(t, k.Name, "john") - priv1, err := kb.Key("john") - require.NoError(t, err) - - armored, err := kb.ExportPrivKeyArmor("john", "secretcpw") - require.NoError(t, err) - - // delete exported key - require.NoError(t, kb.Delete("john")) - _, err = kb.Key("john") - require.Error(t, err) - - // import armored key - require.NoError(t, kb.ImportPrivKey("john", armored, "secretcpw")) - - // ensure old and new keys match - priv2, err := kb.Key("john") - require.NoError(t, err) - key1, err := priv1.GetPubKey() - require.NoError(t, err) - key2, err := priv2.GetPubKey() - require.NoError(t, err) - require.True(t, key1.Equals(key2)) -} - -func TestInMemoryExportImportPubKey(t *testing.T) { - // make the storage with reasonable defaults - cdc := getCodec() - cstore := NewInMemory(cdc) - - // CreateMnemonic a private-public key pair and ensure consistency - k, _, err := cstore.NewMnemonic("john", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - require.NotNil(t, k) - require.Equal(t, k.Name, "john") - key, err := k.GetPubKey() - require.NoError(t, err) - addr := key.Address() - john, err := cstore.Key("john") - require.NoError(t, err) - require.Equal(t, john.Name, "john") - johnKey, err := john.GetPubKey() - require.NoError(t, err) - require.Equal(t, johnKey.Address(), addr) - - // Export the public key only - armor, err := cstore.ExportPubKeyArmor("john") - require.NoError(t, err) - err = cstore.Delete("john") - require.NoError(t, err) - - // Import it under a different name - err = cstore.ImportPubKey("john-pubkey-only", armor) - require.NoError(t, err) - // Ensure consistency - john2, err := cstore.Key("john-pubkey-only") - require.NoError(t, err) - // Compare the public keys - john2Key, err := john2.GetPubKey() - require.NoError(t, err) - require.True(t, johnKey.Equals(john2Key)) - - // Ensure keys cannot be overwritten - err = cstore.ImportPubKey("john-pubkey-only", armor) - require.NotNil(t, err) -} - -// TestInMemoryAdvancedKeyManagement verifies update, import, export functionality -func TestInMemoryAdvancedKeyManagement(t *testing.T) { - // make the storage with reasonable defaults - cdc := getCodec() - cstore := NewInMemory(cdc) - - algo := hd.Secp256k1 - n1, n2 := "old-name", "new name" - - // make sure key works with initial password - _, _, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) - require.Nil(t, err, "%+v", err) - - // exporting requires the proper name and passphrase - _, err = cstore.ExportPubKeyArmor(n1 + ".notreal") - require.NotNil(t, err) - _, err = cstore.ExportPubKeyArmor(" " + n1) - require.NotNil(t, err) - _, err = cstore.ExportPubKeyArmor(n1 + " ") - require.NotNil(t, err) - _, err = cstore.ExportPubKeyArmor("") - require.NotNil(t, err) - exported, err := cstore.ExportPubKeyArmor(n1) - require.Nil(t, err, "%+v", err) - err = cstore.Delete(n1) - require.NoError(t, err) - - // import succeeds - err = cstore.ImportPubKey(n2, exported) - require.NoError(t, err) - - // second import fails - err = cstore.ImportPubKey(n2, exported) - require.NotNil(t, err) -} - // TestInMemorySeedPhrase verifies restoring from a seed phrase func TestInMemorySeedPhrase(t *testing.T) { // make the storage with reasonable defaults cdc := getCodec() - cstore := NewInMemory(cdc) - - algo := hd.Secp256k1 - n1, n2 := "lost-key", "found-again" - - // make sure key works with initial password - k, mnemonic, err := cstore.NewMnemonic(n1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, algo) - require.Nil(t, err, "%+v", err) - require.Equal(t, n1, k.Name) - require.NotEmpty(t, mnemonic) - - // now, let us delete this key - err = cstore.Delete(n1) - require.Nil(t, err, "%+v", err) - _, err = cstore.Key(n1) - require.NotNil(t, err) - - // let us re-create it from the mnemonic-phrase - hdPath := hd.NewFundraiserParams(0, sdk.CoinType, 0).String() - k1, err := cstore.NewAccount(n2, mnemonic, DefaultBIP39Passphrase, hdPath, algo) - require.NoError(t, err) - require.Equal(t, n2, k1.Name) - key, err := k.GetPubKey() - require.NoError(t, err) - key1, err := k1.GetPubKey() - require.NoError(t, err) - require.Equal(t, key.Address(), key1.Address()) - require.Equal(t, key, key1) + tests := []struct { + name string + uid string + importUID string + }{ + { + name: "correct in memory seed", + uid: "okTest", + importUID: "imported", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cstore := NewInMemory(cdc) + + // make sure key works with initial password + k, mnemonic, err := cstore.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.Nil(t, err, "%+v", err) + require.Equal(t, tt.uid, k.Name) + require.NotEmpty(t, mnemonic) + + // now, let us delete this key + err = cstore.Delete(tt.uid) + require.Nil(t, err, "%+v", err) + _, err = cstore.Key(tt.uid) + require.NotNil(t, err) + + // let us re-create it from the mnemonic-phrase + hdPath := hd.NewFundraiserParams(0, sdk.CoinType, 0).String() + k1, err := cstore.NewAccount(tt.importUID, mnemonic, DefaultBIP39Passphrase, hdPath, hd.Secp256k1) + require.NoError(t, err) + require.Equal(t, tt.importUID, k1.Name) + key, err := k.GetPubKey() + require.NoError(t, err) + key1, err := k1.GetPubKey() + require.NoError(t, err) + require.Equal(t, key.Address(), key1.Address()) + require.Equal(t, key, key1) + }) + } } func TestKeyChain_ShouldFailWhenAddingSameGeneratedAccount(t *testing.T) { @@ -965,163 +1348,332 @@ func ExampleNew() { } func TestAltKeyring_List(t *testing.T) { - dir := t.TempDir() cdc := getCodec() + tests := []struct { + name string + backend string + uids []string + }{ + { + name: "correct list", + backend: BackendTest, + uids: []string{"Bkey", "Rkey", "Zkey"}, + }, + { + name: "empty list", + backend: BackendTest, + uids: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New("listKeys", tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) - kr, err := New(t.Name(), BackendTest, dir, nil, cdc) - require.NoError(t, err) - - list, err := kr.List() - require.NoError(t, err) - require.Empty(t, list) - - // Fails on creating unsupported pubKeyType - _, _, err = kr.NewMnemonic("failing", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) - require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error()) - - // Create 3 keys - uid1, uid2, uid3 := "Zkey", "Bkey", "Rkey" - _, _, err = kr.NewMnemonic(uid1, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - _, _, err = kr.NewMnemonic(uid2, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - _, _, err = kr.NewMnemonic(uid3, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - list, err = kr.List() - require.NoError(t, err) - require.Len(t, list, 3) - - // Check they are in alphabetical order - require.Equal(t, uid2, list[0].Name) - require.Equal(t, uid3, list[1].Name) - require.Equal(t, uid1, list[2].Name) -} - -func TestAltKeyring_NewAccount(t *testing.T) { - cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - entropy, err := bip39.NewEntropy(defaultEntropySize) - require.NoError(t, err) - - mnemonic, err := bip39.NewMnemonic(entropy) - require.NoError(t, err) - - uid := "newUid" - - // Fails on creating unsupported pubKeyType - _, err = kr.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, notSupportedAlgo{}) - require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error()) - - k, err := kr.NewAccount(uid, mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, hd.Secp256k1) - require.NoError(t, err) - - require.Equal(t, uid, k.Name) + list, err := kr.List() + require.NoError(t, err) + require.Empty(t, list) - list, err := kr.List() - require.NoError(t, err) - require.Len(t, list, 1) + for _, uid := range tt.uids { + _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + } + list, err = kr.List() + require.NoError(t, err) + require.Len(t, list, len(tt.uids)) + + for i := range tt.uids { + require.Equal(t, tt.uids[i], list[i].Name) + } + }) + } } func TestAltKeyring_Get(t *testing.T) { cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) + tests := []struct { + name string + backend string + uid string + uidToFind string + expectedErr error + }{ + { + name: "correct get", + backend: BackendTest, + uid: "okTest", + uidToFind: "okTest", + expectedErr: nil, + }, + { + name: "not found key", + backend: BackendTest, + uid: "notFoundUid", + uidToFind: "notFound", + expectedErr: sdkerrors.ErrKeyNotFound, + }, + { + name: "in memory correct get", + backend: BackendMemory, + uid: "okTest", + uidToFind: "okTest", + expectedErr: nil, + }, + { + name: "in memory not found key", + backend: BackendMemory, + uid: "notFoundUid", + uidToFind: "notFound", + expectedErr: sdkerrors.ErrKeyNotFound, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(tt.name, tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) - uid := someKey - mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) + mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) - key, err := kr.Key(uid) - require.NoError(t, err) - requireEqualRenamedKey(t, mnemonic, key, true) + key, err := kr.Key(tt.uidToFind) + if tt.expectedErr == nil { + require.NoError(t, err) + requireEqualRenamedKey(t, mnemonic, key, true) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedErr)) + } + }) + } } func TestAltKeyring_KeyByAddress(t *testing.T) { cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - uid := someKey - mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - addr, err := mnemonic.GetAddress() - require.NoError(t, err) - key, err := kr.KeyByAddress(addr) - require.NoError(t, err) - requireEqualRenamedKey(t, key, mnemonic, true) + tests := []struct { + name string + backend string + uid string + getAddres func(*Record) (sdk.AccAddress, error) + expectedErr error + }{ + { + name: "correct get", + backend: BackendTest, + uid: "okTest", + getAddres: func(k *Record) (sdk.AccAddress, error) { + return k.GetAddress() + }, + expectedErr: nil, + }, + { + name: "not found key", + backend: BackendTest, + uid: "notFoundUid", + getAddres: func(k *Record) (sdk.AccAddress, error) { + return nil, nil + }, + expectedErr: sdkerrors.ErrKeyNotFound, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(tt.name, tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + + mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + addr, err := tt.getAddres(mnemonic) + require.NoError(t, err) + + key, err := kr.KeyByAddress(addr) + if tt.expectedErr == nil { + require.NoError(t, err) + requireEqualRenamedKey(t, mnemonic, key, true) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedErr)) + } + }) + } } func TestAltKeyring_Delete(t *testing.T) { cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - uid := someKey - _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - list, err := kr.List() - require.NoError(t, err) - require.Len(t, list, 1) - - err = kr.Delete(uid) - require.NoError(t, err) - - list, err = kr.List() - require.NoError(t, err) - require.Empty(t, list) + tests := []struct { + name string + backend string + uid string + uidToDelete string + expectedErr error + }{ + { + name: "correct delete", + backend: BackendTest, + uid: "deleteKey", + uidToDelete: "deleteKey", + expectedErr: nil, + }, + { + name: "not found delete", + backend: BackendTest, + uid: "deleteKey", + uidToDelete: "notFound", + expectedErr: sdkerrors.ErrKeyNotFound, + }, + { + name: "in memory correct delete", + backend: BackendMemory, + uid: "inMemoryDeleteKey", + uidToDelete: "inMemoryDeleteKey", + expectedErr: nil, + }, + { + name: "in memory not found delete", + backend: BackendMemory, + uid: "inMemoryDeleteKey", + uidToDelete: "notFound", + expectedErr: sdkerrors.ErrKeyNotFound, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + + _, _, err = kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + + list, err := kr.List() + require.NoError(t, err) + require.Len(t, list, 1) + + err = kr.Delete(tt.uidToDelete) + list, listErr := kr.List() + require.NoError(t, listErr) + if tt.expectedErr == nil { + require.NoError(t, err) + require.Empty(t, list) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedErr)) + require.Len(t, list, 1) + } + }) + } } func TestAltKeyring_DeleteByAddress(t *testing.T) { cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - uid := someKey - mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - list, err := kr.List() - require.NoError(t, err) - require.Len(t, list, 1) - - addr, err := mnemonic.GetAddress() - require.NoError(t, err) - err = kr.DeleteByAddress(addr) - require.NoError(t, err) - - list, err = kr.List() - require.NoError(t, err) - require.Empty(t, list) + tests := []struct { + name string + backend string + uid string + getAddres func(*Record) (sdk.AccAddress, error) + expectedErr error + }{ + { + name: "correct delete", + backend: BackendTest, + uid: "okTest", + getAddres: func(k *Record) (sdk.AccAddress, error) { + return k.GetAddress() + }, + expectedErr: nil, + }, + { + name: "not found", + backend: BackendTest, + uid: "notFoundUid", + getAddres: func(k *Record) (sdk.AccAddress, error) { + return nil, nil + }, + expectedErr: sdkerrors.ErrKeyNotFound, + }, + { + name: "in memory correct delete", + backend: BackendMemory, + uid: "inMemory", + getAddres: func(k *Record) (sdk.AccAddress, error) { + return k.GetAddress() + }, + expectedErr: nil, + }, + { + name: "in memory not found", + backend: BackendMemory, + uid: "inMemoryNotFoundUid", + getAddres: func(k *Record) (sdk.AccAddress, error) { + return nil, nil + }, + expectedErr: sdkerrors.ErrKeyNotFound, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(tt.name, tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + + mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) + addr, err := tt.getAddres(mnemonic) + require.NoError(t, err) + + err = kr.DeleteByAddress(addr) + list, listErr := kr.List() + require.NoError(t, listErr) + if tt.expectedErr == nil { + require.NoError(t, err) + require.Empty(t, list) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedErr)) + require.Len(t, list, 1) + } + }) + } } +// TODO: review func TestAltKeyring_SaveOfflineKey(t *testing.T) { cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - list, err := kr.List() - require.NoError(t, err) - require.Empty(t, list) - - key := someKey - priv := ed25519.GenPrivKey() - pub := priv.PubKey() - - k, err := kr.SaveOfflineKey(key, pub) - require.Nil(t, err) - pubKey, err := k.GetPubKey() - require.NoError(t, err) - require.Equal(t, pub, pubKey) - require.Equal(t, key, k.Name) - - list, err = kr.List() - require.NoError(t, err) - require.Len(t, list, 1) + tests := []struct { + name string + backend string + uid string + pubKey string + }{ + { + name: "correct save", + backend: BackendTest, + uid: "okSave", + pubKey: "cfd96f5e00069b64ddb8bfa433941400ab674db42436ae08bc9c74f3b5ade896", + }, + { + name: "in memory correct save", + backend: BackendMemory, + uid: "memorySave", + pubKey: "cfd96f5e00069b64ddb8bfa433941400ab674db42436ae08bc9c74f3b5ade896", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(tt.name, tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + priv := ed25519.GenPrivKey() + pub := priv.PubKey() + pub.Bytes() + k, err := kr.SaveOfflineKey(tt.uid, pub) + require.NoError(t, err) + pubKey, err := k.GetPubKey() + require.NoError(t, err) + require.Equal(t, pub, pubKey) + require.Equal(t, tt.uid, k.Name) + + list, err := kr.List() + require.NoError(t, err) + require.Len(t, list, 1) + }) + } } func TestNonConsistentKeyring_SavePubKey(t *testing.T) { @@ -1163,226 +1715,171 @@ func TestNonConsistentKeyring_SavePubKey(t *testing.T) { func TestAltKeyring_SaveMultisig(t *testing.T) { cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - mnemonic1, _, err := kr.NewMnemonic("key1", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - mnemonic2, _, err := kr.NewMnemonic("key2", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - key := "multi" - key1, err := mnemonic1.GetPubKey() - require.NoError(t, err) - key2, err := mnemonic2.GetPubKey() - require.NoError(t, err) - pub := multisig.NewLegacyAminoPubKey( - 2, - []types.PubKey{ - &secp256k1.PubKey{Key: key1.Bytes()}, - &secp256k1.PubKey{Key: key2.Bytes()}, + tests := []struct { + name string + uid string + backend string + mnemonics []string + }{ + { + name: "correct multisig", + uid: "multi", + backend: BackendTest, + mnemonics: []string{ + "faint misery damage shoot wedding chat dress joy page stand gun business dance amount amused pond smart rate inner ill loud agree two evil", + "window surprise chief blame huge umbrella pool home draw staff water brief modify depth whisper hawk floor come fury property pond cluster ethics super", + }, }, - ) - - k, err := kr.SaveMultisig(key, pub) - require.Nil(t, err) - infoKey, err := k.GetPubKey() - require.NoError(t, err) - require.Equal(t, pub, infoKey) - require.Equal(t, key, k.Name) - - list, err := kr.List() - require.NoError(t, err) - require.Len(t, list, 3) + { + name: "correct in memory multisig", + uid: "multiInMemory", + backend: BackendMemory, + mnemonics: []string{ + "faint misery damage shoot wedding chat dress joy page stand gun business dance amount amused pond smart rate inner ill loud agree two evil", + "window surprise chief blame huge umbrella pool home draw staff water brief modify depth whisper hawk floor come fury property pond cluster ethics super", + }, + }, + { + name: "one key multisig", + uid: "multi", + backend: BackendTest, + mnemonics: []string{"faint misery damage shoot wedding chat dress joy page stand gun business dance amount amused pond smart rate inner ill loud agree two evil"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) + pubKeys := make([]types.PubKey, len(tt.mnemonics)) + for i, mnemonic := range tt.mnemonics { + r, err := kr.NewAccount(strconv.FormatInt(int64(i), 10), mnemonic, DefaultBIP39Passphrase, sdk.FullFundraiserPath, hd.Secp256k1) + require.NoError(t, err) + key, err := r.GetPubKey() + require.NoError(t, err) + pubKeys[i] = key + } + pub := multisig.NewLegacyAminoPubKey(len(tt.mnemonics), pubKeys) + k, err := kr.SaveMultisig(tt.uid, pub) + require.Nil(t, err) + infoKey, err := k.GetPubKey() + require.NoError(t, err) + require.Equal(t, pub, infoKey) + require.Equal(t, tt.uid, k.Name) + + list, err := kr.List() + require.NoError(t, err) + require.Len(t, list, len(tt.mnemonics)+1) + }) + } } +// TODO: add more tests func TestAltKeyring_Sign(t *testing.T) { cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) + tests := []struct { + name string + backend string + uid string + msg []byte + mode signing.SignMode + }{ + { + name: "correct sign", + backend: BackendTest, + uid: "signKey", + msg: []byte("some message"), + mode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) - uid := "jack" - _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) + _, _, err = kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) - msg := []byte("some message") + sign, key, err := kr.Sign(tt.uid, tt.msg, tt.mode) + require.NoError(t, err) - sign, key, err := kr.Sign(uid, msg, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) - require.NoError(t, err) - - require.True(t, key.VerifySignature(msg, sign)) + require.True(t, key.VerifySignature(tt.msg, sign)) + }) + } } func TestAltKeyring_SignByAddress(t *testing.T) { cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - uid := "jack" - mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - msg := []byte("some message") - - addr, err := mnemonic.GetAddress() - require.NoError(t, err) - sign, key, err := kr.SignByAddress(addr, msg, signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) - require.NoError(t, err) - - require.True(t, key.VerifySignature(msg, sign)) -} - -func TestAltKeyring_ImportExportPrivKey(t *testing.T) { - cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - uid := theID - _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - passphrase := "somePass" - armor, err := kr.ExportPrivKeyArmor(uid, passphrase) - require.NoError(t, err) - err = kr.Delete(uid) - require.NoError(t, err) - newUID := otherID - // Should fail importing with wrong password - err = kr.ImportPrivKey(newUID, armor, "wrongPass") - require.True(t, errors.Is(err, sdkerrors.ErrWrongPassword)) - - err = kr.ImportPrivKey(newUID, armor, passphrase) - require.NoError(t, err) - - // Should fail importing private key on existing key. - err = kr.ImportPrivKey(newUID, armor, passphrase) - require.True(t, errors.Is(err, ErrOverwriteKey)) -} - -func TestAltKeyring_ImportExportPrivKey_ByAddress(t *testing.T) { - cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - uid := theID - mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - passphrase := "somePass" - addr, err := mnemonic.GetAddress() - require.NoError(t, err) - armor, err := kr.ExportPrivKeyArmorByAddress(addr, passphrase) - require.NoError(t, err) - err = kr.Delete(uid) - require.NoError(t, err) - - newUID := otherID - // Should fail importing with wrong password - err = kr.ImportPrivKey(newUID, armor, "wrongPass") - require.True(t, errors.Is(err, sdkerrors.ErrWrongPassword)) - - err = kr.ImportPrivKey(newUID, armor, passphrase) - require.NoError(t, err) - - // Should fail importing private key on existing key. - err = kr.ImportPrivKey(newUID, armor, passphrase) - require.True(t, errors.Is(err, ErrOverwriteKey)) -} - -func TestAltKeyring_ImportExportPubKey(t *testing.T) { - cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - uid := theID - _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - armor, err := kr.ExportPubKeyArmor(uid) - require.NoError(t, err) - err = kr.Delete(uid) - require.NoError(t, err) - - newUID := otherID - err = kr.ImportPubKey(newUID, armor) - require.NoError(t, err) - - // Should fail importing private key on existing key. - err = kr.ImportPubKey(newUID, armor) - require.True(t, errors.Is(err, ErrOverwriteKey)) -} - -func TestAltKeyring_ImportExportPubKey_ByAddress(t *testing.T) { - cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - uid := theID - mnemonic, _, err := kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - addr, err := mnemonic.GetAddress() - require.NoError(t, err) - armor, err := kr.ExportPubKeyArmorByAddress(addr) - require.NoError(t, err) - err = kr.Delete(uid) - require.NoError(t, err) - - newUID := otherID - err = kr.ImportPubKey(newUID, armor) - require.NoError(t, err) - - // Should fail importing private key on existing key. - err = kr.ImportPubKey(newUID, armor) - require.True(t, errors.Is(err, ErrOverwriteKey)) -} - -func TestAltKeyring_UnsafeExportPrivKeyHex(t *testing.T) { - cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - uid := theID - - _, _, err = kr.NewMnemonic(uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) + tests := []struct { + name string + backend string + uid string + msg []byte + mode signing.SignMode + }{ + { + name: "correct sign by address", + backend: BackendTest, + uid: "signKey", + msg: []byte("some message"), + mode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(t.Name(), tt.backend, t.TempDir(), nil, cdc) + require.NoError(t, err) - privKey, err := kr.(keystore).ExportPrivateKeyObject(uid) + mnemonic, _, err := kr.NewMnemonic(tt.uid, English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) + require.NoError(t, err) - require.NoError(t, err) - require.Equal(t, 64, len(hex.EncodeToString(privKey.Bytes()))) + addr, err := mnemonic.GetAddress() + require.NoError(t, err) + sign, key, err := kr.SignByAddress(addr, tt.msg, tt.mode) + require.NoError(t, err) - // test error on non existing key - _, err = kr.(keystore).ExportPrivateKeyObject("non-existing") - require.Error(t, err) + require.True(t, key.VerifySignature(tt.msg, sign)) + }) + } } func TestAltKeyring_ConstructorSupportedAlgos(t *testing.T) { cdc := getCodec() - kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc) - require.NoError(t, err) - - // should fail when using unsupported signing algorythm. - _, _, err = kr.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) - require.EqualError(t, err, "unsupported signing algo") - - // but works with default signing algo. - _, _, err = kr.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, hd.Secp256k1) - require.NoError(t, err) - - // but we can create a new keybase with our provided algos. - kr2, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc, func(options *Options) { - options.SupportedAlgos = SigningAlgoList{ - notSupportedAlgo{}, - } - }) - require.NoError(t, err) - - // now this new keyring does not fail when signing with provided algo - _, _, err = kr2.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) - require.NoError(t, err) + tests := []struct { + name string + algoOptions func(options *Options) + expectedErr error + }{ + { + name: "add new algo", + algoOptions: func(options *Options) { + options.SupportedAlgos = SigningAlgoList{ + notSupportedAlgo{}, + } + }, + expectedErr: nil, + }, + { + name: "not supported algo", + algoOptions: func(options *Options) {}, + expectedErr: ErrUnsupportedSigningAlgo, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kr, err := New(t.Name(), BackendTest, t.TempDir(), nil, cdc, tt.algoOptions) + require.NoError(t, err) + _, _, err = kr.NewMnemonic("test", English, sdk.FullFundraiserPath, DefaultBIP39Passphrase, notSupportedAlgo{}) + if tt.expectedErr == nil { + require.NoError(t, err) + } else { + require.Error(t, err) + require.True(t, errors.Is(err, tt.expectedErr)) + } + }) + } } +// TODO: review it func TestBackendConfigConstructors(t *testing.T) { backend := newKWalletBackendKeyringConfig("test", "", nil) require.Equal(t, []keyring.BackendType{keyring.KWalletBackend}, backend.AllowedBackends) diff --git a/crypto/keyring/signing_algorithms_test.go b/crypto/keyring/signing_algorithms_test.go index 3ec31da6bf174..dd61663497adb 100644 --- a/crypto/keyring/signing_algorithms_test.go +++ b/crypto/keyring/signing_algorithms_test.go @@ -1,6 +1,7 @@ package keyring import ( + "encoding/hex" "fmt" "testing" @@ -47,6 +48,45 @@ func TestNewSigningAlgoByString(t *testing.T) { } } +func TestDerive(t *testing.T) { + tests := []struct { + name string + algo SignatureAlgo + hdPath string + mnemonic string + bip39Passphrase string + derivedPriv string + }{ + { + name: "secp256k1", + algo: hd.Secp256k1, + hdPath: "m/44'/118'/0'/0/0", + mnemonic: "circle music snake select deal march this romance until often welcome rich staff trigger drip exit there reopen denial insect hockey just wealth process", + bip39Passphrase: "", + derivedPriv: "1b5884fab5c22aeffef369f3454076cec534c75a4ee71add1245e2c8342994a2", + }, + { + name: "secp256k1 with bip39Passphrase", + algo: hd.Secp256k1, + hdPath: "m/44'/118'/0'/0/0", + mnemonic: "circle music snake select deal march this romance until often welcome rich staff trigger drip exit there reopen denial insect hockey just wealth process", + bip39Passphrase: "test", + derivedPriv: "d5f925b9472b3793e839eae7722e5cef6766a91fad55cc42abea5e457ed5f648", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + derivedPriv, err := tt.algo.Derive()(tt.mnemonic, tt.bip39Passphrase, tt.hdPath) + require.NoError(t, err) + + decodedPriv, err := hex.DecodeString(tt.derivedPriv) + require.NoError(t, err) + require.Equal(t, derivedPriv, decodedPriv) + + }) + } +} + func TestAltSigningAlgoList_Contains(t *testing.T) { list := SigningAlgoList{hd.Secp256k1} diff --git a/crypto/keyring/types_test.go b/crypto/keyring/types_test.go index 60e8e549717d8..a0f9a02094f83 100644 --- a/crypto/keyring/types_test.go +++ b/crypto/keyring/types_test.go @@ -13,47 +13,62 @@ import ( ) func Test_writeReadLedgerInfo(t *testing.T) { - tmpKey := make([]byte, secp256k1.PubKeySize) - hexPK := "035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A" - bz, err := hex.DecodeString(hexPK) - require.NoError(t, err) - copy(tmpKey, bz) - - pk := &secp256k1.PubKey{Key: tmpKey} - path := hd.NewFundraiserParams(5, sdk.CoinType, 1) - k, err := NewLedgerRecord("some_name", pk, path) - require.NoError(t, err) - - l := k.GetLedger() - require.NotNil(t, l) - path = l.Path - require.Equal(t, "m/44'/118'/5'/0/1", path.String()) - pubKey, err := k.GetPubKey() - require.NoError(t, err) - require.Equal(t, - fmt.Sprintf("PubKeySecp256k1{%s}", hexPK), - pubKey.String()) - - // Serialize and restore - cdc := getCodec() - serialized, err := cdc.Marshal(k) - require.NoError(t, err) - var restoredRecord Record - err = cdc.Unmarshal(serialized, &restoredRecord) - require.NoError(t, err) - require.NotNil(t, restoredRecord) - - // Check both keys match - require.Equal(t, k.Name, restoredRecord.Name) - require.Equal(t, k.GetType(), restoredRecord.GetType()) - - restoredPubKey, err := restoredRecord.GetPubKey() - require.NoError(t, err) - require.Equal(t, pubKey, restoredPubKey) - - l = restoredRecord.GetLedger() - require.NotNil(t, l) - restoredPath := l.GetPath() - require.NoError(t, err) - require.Equal(t, path, restoredPath) + tests := []struct { + hexPK string + recordName string + expectedPath string + }{ + { + hexPK: "035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A", + recordName: "test_record", + expectedPath: "m/44'/118'/5'/0/1", + }, + } + for _, tt := range tests { + t.Run(tt.hexPK, func(t *testing.T) { + tmpKey := make([]byte, secp256k1.PubKeySize) + hexPK := tt.hexPK + bz, err := hex.DecodeString(hexPK) + require.NoError(t, err) + copy(tmpKey, bz) + + pk := &secp256k1.PubKey{Key: tmpKey} + path := hd.NewFundraiserParams(5, sdk.CoinType, 1) + k, err := NewLedgerRecord(tt.recordName, pk, path) + require.NoError(t, err) + + l := k.GetLedger() + require.NotNil(t, l) + path = l.Path + require.Equal(t, tt.expectedPath, path.String()) + pubKey, err := k.GetPubKey() + require.NoError(t, err) + require.Equal(t, + fmt.Sprintf("PubKeySecp256k1{%s}", hexPK), + pubKey.String()) + + // Serialize and restore + cdc := getCodec() + serialized, err := cdc.Marshal(k) + require.NoError(t, err) + var restoredRecord Record + err = cdc.Unmarshal(serialized, &restoredRecord) + require.NoError(t, err) + require.NotNil(t, restoredRecord) + + // Check both keys match + require.Equal(t, k.Name, restoredRecord.Name) + require.Equal(t, k.GetType(), restoredRecord.GetType()) + + restoredPubKey, err := restoredRecord.GetPubKey() + require.NoError(t, err) + require.Equal(t, pubKey, restoredPubKey) + + l = restoredRecord.GetLedger() + require.NotNil(t, l) + restoredPath := l.GetPath() + require.NoError(t, err) + require.Equal(t, path, restoredPath) + }) + } } diff --git a/server/util.go b/server/util.go index 712eec7492761..2a70f4b4edecb 100644 --- a/server/util.go +++ b/server/util.go @@ -444,6 +444,10 @@ func DefaultBaseappOptions(appOpts types.AppOptions) []func(*baseapp.BaseApp) { } snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") + if err = os.MkdirAll(snapshotDir, os.ModePerm); err != nil { + panic(fmt.Errorf("failed to create snapshots directory: %w", err)) + } + snapshotDB, err := dbm.NewDB("metadata", GetAppDBBackend(appOpts), snapshotDir) if err != nil { panic(err)