Statefull login with keycard (#1587)

This commit is contained in:
Dmitry Shulyak 2019-09-02 22:03:15 +03:00 committed by Adam Babik
parent 1a47893e75
commit 63dcdd4e94
4 changed files with 134 additions and 7 deletions

View File

@ -222,14 +222,18 @@ func (m *Manager) SelectAccount(loginParams LoginParams) error {
if err != nil {
return err
}
m.watchAddresses = loginParams.WatchAddresses
m.mainAccountAddress = loginParams.MainAccount
m.selectedChatAccount = selectedChatAccount
return nil
}
func (m *Manager) SetAccountAddresses(main common.Address, secondary ...common.Address) {
m.watchAddresses = []common.Address{main}
m.watchAddresses = append(m.watchAddresses, secondary...)
m.mainAccountAddress = main
}
// SetChatAccount initializes selectedChatAccount with privKey
func (m *Manager) SetChatAccount(privKey *ecdsa.PrivateKey) {
m.mu.Lock()

View File

@ -189,6 +189,54 @@ func (b *StatusBackend) ensureAppDBOpened(account multiaccounts.Account, passwor
return nil
}
func (b *StatusBackend) SaveAccountAndStartNodeWithKey(acc multiaccounts.Account, conf *params.NodeConfig, password string, keyHex string) error {
err := b.SaveAccount(acc)
if err != nil {
return err
}
err = b.ensureAppDBOpened(acc, password)
if err != nil {
return err
}
err = b.saveNodeConfig(conf)
if err != nil {
return err
}
return b.StartNodeWithKey(acc, password, keyHex)
}
// StartNodeWithKey instead of loading addresses from database this method derives address from key
// and uses it in application.
func (b *StatusBackend) StartNodeWithKey(acc multiaccounts.Account, password string, keyHex string) error {
err := b.ensureAppDBOpened(acc, password)
if err != nil {
return err
}
conf, err := b.loadNodeConfig()
if err != nil {
return err
}
if err := logutils.OverrideRootLogWithConfig(conf, false); err != nil {
return err
}
chatKey, err := ethcrypto.HexToECDSA(keyHex)
if err != nil {
return err
}
err = b.StartNode(conf)
if err != nil {
return err
}
b.accountManager.SetChatAccount(chatKey)
chatAcc, err := b.accountManager.SelectedChatAccount()
if err != nil {
return err
}
b.accountManager.SetAccountAddresses(chatAcc.Address)
return b.injectAccountIntoServices()
}
func (b *StatusBackend) StartNodeWithAccount(acc multiaccounts.Account, password string) error {
err := b.ensureAppDBOpened(acc, password)
if err != nil {
@ -753,6 +801,10 @@ func (b *StatusBackend) SelectAccount(loginParams account.LoginParams) error {
return err
}
return b.injectAccountIntoServices()
}
func (b *StatusBackend) injectAccountIntoServices() error {
chatAccount, err := b.accountManager.SelectedChatAccount()
if err != nil {
return err
@ -779,10 +831,10 @@ func (b *StatusBackend) SelectAccount(loginParams account.LoginParams) error {
return err
}
}
return b.startWallet(loginParams.Password)
return b.startWallet()
}
func (b *StatusBackend) startWallet(password string) error {
func (b *StatusBackend) startWallet() error {
if !b.statusNode.Config().WalletConfig.Enabled {
return nil
}

View File

@ -537,3 +537,35 @@ func TestBackendGetVerifiedAccount(t *testing.T) {
require.Equal(t, address, key.Address)
})
}
func TestLoginWithKey(t *testing.T) {
b := NewStatusBackend()
pkey, err := crypto.GenerateKey()
require.NoError(t, err)
main := multiaccounts.Account{
Address: crypto.PubkeyToAddress(pkey.PublicKey),
}
tmpdir, err := ioutil.TempDir("", "login-with-key-test-")
require.NoError(t, err)
defer os.Remove(tmpdir)
conf, err := params.NewNodeConfig(tmpdir, 1777)
require.NoError(t, err)
keyhex := hex.EncodeToString(crypto.FromECDSA(pkey))
require.NoError(t, b.accountManager.InitKeystore(conf.KeyStoreDir))
b.UpdateRootDataDir(conf.DataDir)
require.NoError(t, b.OpenAccounts())
require.NoError(t, b.SaveAccountAndStartNodeWithKey(main, conf, "test-pass", keyhex))
require.NoError(t, b.Logout())
require.NoError(t, b.StopNode())
require.NoError(t, b.StartNodeWithKey(main, "test-pass", keyhex))
defer func() {
assert.NoError(t, b.Logout())
assert.NoError(t, b.StopNode())
}()
extkey, err := b.accountManager.SelectedChatAccount()
require.NoError(t, err)
require.Equal(t, crypto.PubkeyToAddress(pkey.PublicKey), extkey.Address)
}

View File

@ -376,11 +376,50 @@ func InitKeystore(keydir string) string {
return makeJSONResponse(err)
}
// SaveAccountAndLoginWithKeycard saves account in status-go database..
func SaveAccountAndLoginWithKeycard(accountData, password, configJSON, keyHex string) string {
var account multiaccounts.Account
err := json.Unmarshal([]byte(accountData), &account)
if err != nil {
return makeJSONResponse(err)
}
var conf params.NodeConfig
err = json.Unmarshal([]byte(configJSON), &conf)
if err != nil {
return makeJSONResponse(err)
}
api.RunAsync(func() error {
log.Debug("starting a node, and saving account with configuration", "address", account.Address)
err := statusBackend.SaveAccountAndStartNodeWithKey(account, &conf, password, keyHex)
if err != nil {
log.Error("failed to start node and save account", "address", account.Address, "error", err)
return err
}
log.Debug("started a node, and saved account", "address", account.Address)
return nil
})
return makeJSONResponse(nil)
}
// LoginWithKeycard initializes an account with a chat key and encryption key used for PFS.
// It purges all the previous identities from Whisper, and injects the key as shh identity.
func LoginWithKeycard(chatKeyData, encryptionKeyData string) string {
err := statusBackend.InjectChatAccount(chatKeyData, encryptionKeyData)
return makeJSONResponse(err)
func LoginWithKeycard(accountData, password, keyHex string) string {
var account multiaccounts.Account
err := json.Unmarshal([]byte(accountData), &account)
if err != nil {
return makeJSONResponse(err)
}
api.RunAsync(func() error {
log.Debug("start a node with account", "address", account.Address)
err := statusBackend.StartNodeWithKey(account, password, keyHex)
if err != nil {
log.Error("failed to start a node", "address", account.Address, "error", err)
return err
}
log.Debug("started a node with", "address", account.Address)
return nil
})
return makeJSONResponse(nil)
}
// Logout is equivalent to clearing whisper identities.