diff --git a/VERSION b/VERSION index 36de6e551..556c27710 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.108.4 \ No newline at end of file +0.108.5 \ No newline at end of file diff --git a/appdatabase/migrations/bindata.go b/appdatabase/migrations/bindata.go index 662d47ad0..d0ad27613 100644 --- a/appdatabase/migrations/bindata.go +++ b/appdatabase/migrations/bindata.go @@ -31,6 +31,7 @@ // 1660134070_add_wakuv2_store.up.sql (269B) // 1660134072_waku2_store_messages.up.sql (497B) // 1662365868_add_key_uid_accounts.up.sql (68B) +// 1662447680_add_keypairs_table.up.sql (218B) // 1662738097_add_base_fee_transaction.up.sql (112B) // doc.go (74B) @@ -721,6 +722,26 @@ func _1662365868_add_key_uid_accountsUpSql() (*asset, error) { return a, nil } +var __1662447680_add_keypairs_tableUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x0e\x72\x75\x0c\x71\x55\x08\x71\x74\xf2\x71\x55\xf0\x74\x53\xf0\xf3\x0f\x51\x70\x8d\xf0\x0c\x0e\x09\x56\xc8\x4e\xad\x2c\x48\xcc\x2c\x2a\x56\xd0\xe0\x52\x50\x50\x00\x71\x93\x13\x8b\x52\xe2\x4b\x33\x53\x14\xc2\x1c\x83\x9c\x3d\x1c\x83\xc0\xaa\xfd\x42\x7d\x7c\x74\x50\x54\xe4\x25\xe6\xa6\x12\x50\x92\x93\x9f\x9c\x9d\x9a\xa2\xe0\xe4\xef\xef\xe3\xea\xe8\xa7\xe0\xe2\xea\xe6\x18\xea\x13\xa2\xe0\xe6\xe8\x13\xec\x0a\x51\x99\x98\x9c\x9c\x5f\x9a\x57\x12\x9f\x98\x92\x52\x94\x5a\x5c\x8c\xdb\x3c\xac\x0e\xe2\xd2\xb4\x06\x04\x00\x00\xff\xff\x6d\xd5\x43\xca\xda\x00\x00\x00") + +func _1662447680_add_keypairs_tableUpSqlBytes() ([]byte, error) { + return bindataRead( + __1662447680_add_keypairs_tableUpSql, + "1662447680_add_keypairs_table.up.sql", + ) +} + +func _1662447680_add_keypairs_tableUpSql() (*asset, error) { + bytes, err := _1662447680_add_keypairs_tableUpSqlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "1662447680_add_keypairs_table.up.sql", size: 218, mode: os.FileMode(0644), modTime: time.Unix(1662964340, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xdc, 0x25, 0xa9, 0xc7, 0x63, 0x27, 0x97, 0x35, 0x5f, 0x6b, 0xab, 0x26, 0xcb, 0xf9, 0xbd, 0x5e, 0xac, 0x3, 0xa0, 0x5e, 0xb9, 0x71, 0xa3, 0x1f, 0xb3, 0x4f, 0x7f, 0x79, 0x28, 0x48, 0xbe, 0xc}} + return a, nil +} + var __1662738097_add_base_fee_transactionUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\x29\x4a\xcc\x2b\x4e\x4b\x2d\x2a\x56\x70\x74\x71\x51\x70\xf6\xf7\x09\xf5\xf5\x53\x48\x4a\x2c\x4e\x8d\x4f\x4f\x2c\x8e\x4f\x4b\x4d\x55\x08\x71\x8d\x08\x51\xf0\xf3\x0f\x51\xf0\x0b\xf5\xf1\x51\x70\x71\x75\x73\x0c\xf5\x09\x51\x50\x52\xb2\xe6\x0a\x0d\x70\x71\x0c\x41\x36\x22\xd8\x35\x04\x55\xaf\x2d\x58\x1d\x20\x00\x00\xff\xff\x3f\x07\xa7\xa2\x70\x00\x00\x00") func _1662738097_add_base_fee_transactionUpSqlBytes() ([]byte, error) { @@ -736,7 +757,7 @@ func _1662738097_add_base_fee_transactionUpSql() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "1662738097_add_base_fee_transaction.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1662964111, 0)} + info := bindataFileInfo{name: "1662738097_add_base_fee_transaction.up.sql", size: 112, mode: os.FileMode(0644), modTime: time.Unix(1662964340, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6b, 0xfb, 0x10, 0xae, 0xfc, 0x77, 0x70, 0x98, 0x6f, 0xec, 0xaa, 0xcd, 0x7, 0xc7, 0x74, 0x23, 0xc, 0xd5, 0x1e, 0x82, 0xdd, 0xfe, 0xff, 0x3b, 0xd2, 0x49, 0x10, 0x5b, 0x30, 0xc, 0x2d, 0xb0}} return a, nil } @@ -914,6 +935,8 @@ var _bindata = map[string]func() (*asset, error){ "1662365868_add_key_uid_accounts.up.sql": _1662365868_add_key_uid_accountsUpSql, + "1662447680_add_keypairs_table.up.sql": _1662447680_add_keypairs_tableUpSql, + "1662738097_add_base_fee_transaction.up.sql": _1662738097_add_base_fee_transactionUpSql, "doc.go": docGo, @@ -991,6 +1014,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "1660134070_add_wakuv2_store.up.sql": &bintree{_1660134070_add_wakuv2_storeUpSql, map[string]*bintree{}}, "1660134072_waku2_store_messages.up.sql": &bintree{_1660134072_waku2_store_messagesUpSql, map[string]*bintree{}}, "1662365868_add_key_uid_accounts.up.sql": &bintree{_1662365868_add_key_uid_accountsUpSql, map[string]*bintree{}}, + "1662447680_add_keypairs_table.up.sql": &bintree{_1662447680_add_keypairs_tableUpSql, map[string]*bintree{}}, "1662738097_add_base_fee_transaction.up.sql": &bintree{_1662738097_add_base_fee_transactionUpSql, map[string]*bintree{}}, "doc.go": &bintree{docGo, map[string]*bintree{}}, }} diff --git a/appdatabase/migrations/sql/1662447680_add_keypairs_table.up.sql b/appdatabase/migrations/sql/1662447680_add_keypairs_table.up.sql new file mode 100644 index 000000000..fb3d91631 --- /dev/null +++ b/appdatabase/migrations/sql/1662447680_add_keypairs_table.up.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS keypairs ( + keycard_uid VARCHAR NOT NULL, + keycard_name VARCHAR NOT NULL, + keycard_locked BOOLEAN DEFAULT FALSE, + account_address VARCHAR NOT NULL, + key_uid VARCHAR NOT NULL +); \ No newline at end of file diff --git a/multiaccounts/accounts/database.go b/multiaccounts/accounts/database.go index d0754f45a..9ed28ff95 100644 --- a/multiaccounts/accounts/database.go +++ b/multiaccounts/accounts/database.go @@ -6,6 +6,7 @@ import ( "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/multiaccounts/errors" + "github.com/status-im/status-go/multiaccounts/keypairs" "github.com/status-im/status-go/multiaccounts/settings" notificationssettings "github.com/status-im/status-go/multiaccounts/settings_notifications" sociallinkssettings "github.com/status-im/status-go/multiaccounts/settings_social_links" @@ -101,6 +102,7 @@ type Database struct { *settings.Database *notificationssettings.NotificationsSettings *sociallinkssettings.SocialLinksSettings + *keypairs.KeyPairs db *sql.DB } @@ -112,8 +114,9 @@ func NewDB(db *sql.DB) (*Database, error) { } sn := notificationssettings.NewNotificationsSettings(db) ssl := sociallinkssettings.NewSocialLinksSettings(db) + kp := keypairs.NewKeyPairs(db) - return &Database{sDB, sn, ssl, db}, nil + return &Database{sDB, sn, ssl, kp, db}, nil } // DB Gets db sql.DB diff --git a/multiaccounts/accounts/database_test.go b/multiaccounts/accounts/database_test.go index 7d44ca120..52cf04b66 100644 --- a/multiaccounts/accounts/database_test.go +++ b/multiaccounts/accounts/database_test.go @@ -9,6 +9,7 @@ import ( "github.com/status-im/status-go/appdatabase" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/multiaccounts/errors" + "github.com/status-im/status-go/multiaccounts/keypairs" ) func setupTestDB(t *testing.T) (*Database, func()) { @@ -190,3 +191,110 @@ func TestAddressDoesntExist(t *testing.T) { require.NoError(t, err) require.False(t, exists) } + +func TestKeypairs(t *testing.T) { + db, stop := setupTestDB(t) + defer stop() + + keyPair1 := keypairs.KeyPair{ + KeycardUID: "00000000000000000000000000000001", + KeycardName: "Card01", + KeycardLocked: false, + AccountsAddresses: []types.Address{{0x01}, {0x02}, {0x03}}, + KeyUID: "0000000000000000000000000000000000000000000000000000000000000001", + } + keyPair2 := keypairs.KeyPair{ + KeycardUID: "00000000000000000000000000000002", + KeycardName: "Card02", + KeycardLocked: false, + AccountsAddresses: []types.Address{{0x01}, {0x02}}, + KeyUID: "0000000000000000000000000000000000000000000000000000000000000002", + } + + // Test adding key pairs + err := db.AddMigratedKeyPair(keyPair1.KeycardUID, keyPair1.KeycardName, keyPair1.KeyUID, keyPair1.AccountsAddresses) + require.NoError(t, err) + err = db.AddMigratedKeyPair(keyPair2.KeycardUID, keyPair2.KeycardName, keyPair2.KeyUID, keyPair2.AccountsAddresses) + require.NoError(t, err) + + // Test reading migrated key pairs + rows, err := db.GetAllMigratedKeyPairs() + require.NoError(t, err) + require.Equal(t, 2, len(rows)) + for _, kp := range rows { + if kp.KeyUID == keyPair1.KeyUID { + require.Equal(t, keyPair1.KeycardUID, kp.KeycardUID) + require.Equal(t, keyPair1.KeycardName, kp.KeycardName) + require.Equal(t, keyPair1.KeycardLocked, kp.KeycardLocked) + require.Equal(t, len(keyPair1.AccountsAddresses), len(kp.AccountsAddresses)) + } else { + require.Equal(t, keyPair2.KeycardUID, kp.KeycardUID) + require.Equal(t, keyPair2.KeycardName, kp.KeycardName) + require.Equal(t, keyPair2.KeycardLocked, kp.KeycardLocked) + require.Equal(t, len(keyPair2.AccountsAddresses), len(kp.AccountsAddresses)) + } + } + + rows, err = db.GetMigratedKeyPairByKeyUID(keyPair1.KeyUID) + require.NoError(t, err) + require.Equal(t, 1, len(rows)) + require.Equal(t, keyPair1.KeyUID, rows[0].KeyUID) + require.Equal(t, keyPair1.KeycardUID, rows[0].KeycardUID) + require.Equal(t, keyPair1.KeycardName, rows[0].KeycardName) + require.Equal(t, keyPair1.KeycardLocked, rows[0].KeycardLocked) + require.Equal(t, len(keyPair1.AccountsAddresses), len(rows[0].AccountsAddresses)) + + // Test seting a new keycard name + err = db.SetKeycardName(keyPair1.KeycardUID, "Card101") + require.NoError(t, err) + rows, err = db.GetAllMigratedKeyPairs() + require.NoError(t, err) + newKeycardName := "" + for _, kp := range rows { + if kp.KeyUID == keyPair1.KeyUID { + newKeycardName = kp.KeycardName + } + } + require.Equal(t, "Card101", newKeycardName) + + // Test locking a keycard + err = db.KeycardLocked(keyPair1.KeycardUID) + require.NoError(t, err) + rows, err = db.GetAllMigratedKeyPairs() + require.NoError(t, err) + locked := false + for _, kp := range rows { + if kp.KeyUID == keyPair1.KeyUID { + locked = kp.KeycardLocked + } + } + require.Equal(t, true, locked) + + // Test unlocking a locked keycard + err = db.KeycardUnlocked(keyPair1.KeycardUID) + require.NoError(t, err) + rows, err = db.GetAllMigratedKeyPairs() + require.NoError(t, err) + locked = true + for _, kp := range rows { + if kp.KeyUID == keyPair1.KeyUID { + locked = kp.KeycardLocked + } + } + require.Equal(t, false, locked) + + // Test detleting a keycard + err = db.DeleteKeycard(keyPair1.KeycardUID) + require.NoError(t, err) + rows, err = db.GetAllMigratedKeyPairs() + require.NoError(t, err) + require.Equal(t, 1, len(rows)) + // Test if correct keycard is deleted + deletedKeyPair1 := true + for _, kp := range rows { + if kp.KeyUID == keyPair1.KeyUID { + deletedKeyPair1 = false + } + } + require.Equal(t, true, deletedKeyPair1) +} diff --git a/multiaccounts/keypairs/database.go b/multiaccounts/keypairs/database.go new file mode 100644 index 000000000..53e423c55 --- /dev/null +++ b/multiaccounts/keypairs/database.go @@ -0,0 +1,207 @@ +package keypairs + +import ( + "database/sql" + + "github.com/status-im/status-go/eth-node/types" +) + +type KeyPair struct { + KeycardUID string `json:"keycard-uid"` + KeycardName string `json:"keycard-name"` + KeycardLocked bool `json:"keycard-locked"` + AccountsAddresses []types.Address `json:"accounts-addresses"` + KeyUID string `json:"key-uid"` +} + +type KeyPairs struct { + db *sql.DB +} + +func NewKeyPairs(db *sql.DB) *KeyPairs { + return &KeyPairs{ + db: db, + } +} + +func (kp *KeyPairs) processResult(rows *sql.Rows) ([]*KeyPair, error) { + keyPairs := []*KeyPair{} + for rows.Next() { + keyPair := &KeyPair{} + addr := types.Address{} + err := rows.Scan(&keyPair.KeycardUID, &keyPair.KeycardName, &keyPair.KeycardLocked, &addr, &keyPair.KeyUID) + if err != nil { + return nil, err + } + + foundAtIndex := -1 + for i := range keyPairs { + if keyPairs[i].KeyUID == keyPair.KeyUID { + foundAtIndex = i + break + } + } + if foundAtIndex == -1 { + keyPair.AccountsAddresses = append(keyPair.AccountsAddresses, addr) + keyPairs = append(keyPairs, keyPair) + } else { + keyPairs[foundAtIndex].AccountsAddresses = append(keyPairs[foundAtIndex].AccountsAddresses, addr) + } + } + + return keyPairs, nil +} + +func (kp *KeyPairs) GetAllMigratedKeyPairs() ([]*KeyPair, error) { + rows, err := kp.db.Query(` + SELECT + keycard_uid, + keycard_name, + keycard_locked, + account_address, + key_uid + FROM + keypairs + ORDER BY + key_uid + `) + if err != nil { + return nil, err + } + + defer rows.Close() + return kp.processResult(rows) +} + +func (kp *KeyPairs) GetMigratedKeyPairByKeyUID(keyUID string) ([]*KeyPair, error) { + rows, err := kp.db.Query(` + SELECT + keycard_uid, + keycard_name, + keycard_locked, + account_address, + key_uid + FROM + keypairs + WHERE + key_uid = ? + ORDER BY + keycard_uid + `, keyUID) + if err != nil { + return nil, err + } + + defer rows.Close() + return kp.processResult(rows) +} + +func (kp *KeyPairs) AddMigratedKeyPair(kcUID string, kpName string, KeyUID string, accountAddresses []types.Address) (err error) { + var ( + tx *sql.Tx + insert *sql.Stmt + ) + tx, err = kp.db.Begin() + if err != nil { + return + } + defer func() { + if err == nil { + err = tx.Commit() + return + } + _ = tx.Rollback() + }() + + insert, err = tx.Prepare(` + INSERT INTO + keypairs + ( + keycard_uid, + keycard_name, + keycard_locked, + account_address, + key_uid + ) + VALUES + (?, ?, ?, ?, ?); + `) + if err != nil { + return err + } + defer insert.Close() + + for i := range accountAddresses { + addr := accountAddresses[i] + + _, err = insert.Exec(kcUID, kpName, false, addr, KeyUID) + if err != nil { + return err + } + } + return nil +} + +func (kp *KeyPairs) SetKeycardName(kcUID string, kpName string) (err error) { + update, err := kp.db.Prepare(` + UPDATE + keypairs + SET + keycard_name = ? + WHERE + keycard_uid = ? + `) + if err != nil { + return err + } + defer update.Close() + + _, err = update.Exec(kpName, kcUID) + + return err +} + +func (kp *KeyPairs) updateKeycardLocked(kcUID string, locked bool) (err error) { + update, err := kp.db.Prepare(` + UPDATE + keypairs + SET + keycard_locked = ? + WHERE + keycard_uid = ? + `) + if err != nil { + return err + } + defer update.Close() + + _, err = update.Exec(locked, kcUID) + + return err +} + +func (kp *KeyPairs) KeycardLocked(kcUID string) (err error) { + return kp.updateKeycardLocked(kcUID, true) +} + +func (kp *KeyPairs) KeycardUnlocked(kcUID string) (err error) { + return kp.updateKeycardLocked(kcUID, false) +} + +func (kp *KeyPairs) DeleteKeycard(kcUID string) (err error) { + delete, err := kp.db.Prepare(` + DELETE + FROM + keypairs + WHERE + keycard_uid = ? + `) + if err != nil { + return err + } + defer delete.Close() + + _, err = delete.Exec(kcUID) + + return err +} diff --git a/services/accounts/accounts.go b/services/accounts/accounts.go index ab6632ede..9c49cd2a3 100644 --- a/services/accounts/accounts.go +++ b/services/accounts/accounts.go @@ -13,6 +13,7 @@ import ( "github.com/status-im/status-go/account" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/multiaccounts/accounts" + "github.com/status-im/status-go/multiaccounts/keypairs" "github.com/status-im/status-go/multiaccounts/settings" "github.com/status-im/status-go/params" "github.com/status-im/status-go/protocol" @@ -316,3 +317,36 @@ func (api *API) VerifyPassword(password string) bool { } return true } + +func (api *API) AddMigratedKeyPair(ctx context.Context, kcUID string, kpName string, keyUID string, accountAddresses []string) error { + var addresses []types.Address + for _, addr := range accountAddresses { + addresses = append(addresses, types.Address(common.HexToAddress(addr))) + } + + return api.db.AddMigratedKeyPair(kcUID, kpName, keyUID, addresses) +} + +func (api *API) GetAllMigratedKeyPairs(ctx context.Context) ([]*keypairs.KeyPair, error) { + return api.db.GetAllMigratedKeyPairs() +} + +func (api *API) GetMigratedKeyPairByKeyUID(ctx context.Context, keyUID string) ([]*keypairs.KeyPair, error) { + return api.db.GetMigratedKeyPairByKeyUID(keyUID) +} + +func (api *API) SetKeycardName(ctx context.Context, kcUID string, kpName string) error { + return api.db.SetKeycardName(kcUID, kpName) +} + +func (api *API) KeycardLocked(ctx context.Context, kcUID string) error { + return api.db.KeycardLocked(kcUID) +} + +func (api *API) KeycardUnlocked(ctx context.Context, kcUID string) error { + return api.db.KeycardUnlocked(kcUID) +} + +func (api *API) DeleteKeycard(ctx context.Context, kcUID string) error { + return api.db.DeleteKeycard(kcUID) +}