Skip to content

Commit

Permalink
dexc: change application password feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
amass01 authored and chappjc committed Mar 27, 2021
1 parent 26ae0c8 commit 8d7163c
Show file tree
Hide file tree
Showing 18 changed files with 442 additions and 76 deletions.
12 changes: 6 additions & 6 deletions client/core/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func setupRigAccountProof(host string, rig *testRig) {

func TestAccountDisable(t *testing.T) {
activeTrades := map[order.OrderID]*trackedTrade{
order.OrderID{}: &trackedTrade{metaData: &db.OrderMetaData{Status: order.OrderStatusBooked}},
{}: {metaData: &db.OrderMetaData{Status: order.OrderStatusBooked}},
}

tests := []struct {
Expand Down Expand Up @@ -141,7 +141,7 @@ func TestAccountDisable(t *testing.T) {
rig := newTestRig()
defer rig.shutdown()
tCore := rig.core
rig.crypter.recryptErr = test.recryptErr
rig.crypter.(*tCrypter).recryptErr = test.recryptErr
rig.db.disableAccountErr = test.disableAcctErr
tCore.connMtx.Lock()
tCore.conns[tDexHost].trades = test.activeTrades
Expand Down Expand Up @@ -181,7 +181,7 @@ func TestAccountExportPasswordError(t *testing.T) {
rig := newTestRig()
tCore := rig.core
host := tCore.conns[tDexHost].acct.host
rig.crypter.recryptErr = tErr
rig.crypter.(*tCrypter).recryptErr = tErr
_, err := tCore.AccountExport(tPW, host)
if !errorHasCode(err, passwordErr) {
t.Fatalf("expected password error, actual error: '%v'", err)
Expand Down Expand Up @@ -216,7 +216,7 @@ func TestAccountExportAccountKeyError(t *testing.T) {
rig := newTestRig()
tCore := rig.core
host := tCore.conns[tDexHost].acct.host
rig.crypter.decryptErr = tErr
rig.crypter.(*tCrypter).decryptErr = tErr
_, err := tCore.AccountExport(tPW, host)
if !errorHasCode(err, acctKeyErr) {
t.Fatalf("expected account key error, actual error: '%v'", err)
Expand Down Expand Up @@ -338,7 +338,7 @@ func TestAccountImportPasswordError(t *testing.T) {
host := tCore.conns[tDexHost].acct.host
account := buildTestAccount(host)
rig.queueConfig()
rig.crypter.recryptErr = tErr
rig.crypter.(*tCrypter).recryptErr = tErr
err := tCore.AccountImport(tPW, account)
if !errorHasCode(err, passwordErr) {
t.Fatalf("expected password error, actual error: '%v'", err)
Expand Down Expand Up @@ -441,7 +441,7 @@ func TestAccountImportEncryptPrivKeyError(t *testing.T) {
tCore := rig.core
host := tCore.conns[tDexHost].acct.host
account := buildTestAccount(host)
rig.crypter.encryptErr = tErr
rig.crypter.(*tCrypter).encryptErr = tErr
rig.queueConfig()
err := tCore.AccountImport(tPW, account)
if !errorHasCode(err, encryptionErr) {
Expand Down
115 changes: 99 additions & 16 deletions client/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -1568,7 +1568,7 @@ func (c *Core) loadWallet(dbWallet *db.Wallet) (*xcWallet, error) {
OrderLocked: orderLockedAmt,
ContractLocked: contractLockedAmt,
},
encPW: dbWallet.EncryptedPW,
encPass: dbWallet.EncryptedPW,
address: dbWallet.Address,
dbID: dbWallet.ID(),
}, nil
Expand Down Expand Up @@ -1664,6 +1664,96 @@ func (c *Core) WalletSettings(assetID uint32) (map[string]string, error) {
return dbWallet.Settings, nil
}

func (c *Core) setAppPass(pw []byte) (encrypt.Crypter, error) {
if len(pw) == 0 {
return nil, fmt.Errorf("empty password not allowed")
}

crypter := c.newCrypter(pw)
err := c.db.Store(keyParamsKey, crypter.Serialize())
if err != nil {
return nil, fmt.Errorf("error storing key parameters: %w", err)
}

return crypter, nil
}

func (c *Core) updateWalletsEncPW(oldCrypter, newCrypter encrypt.Crypter) error {
updateWalletPW := func(w *xcWallet) error {
// If encrypted password set, decrypt using old app pw then encrypt again
// using new app pw.
oldEncPW := w.encPW()
if len(oldEncPW) == 0 {
return nil
}

// Decrypt with old app pw.
pwB, err := oldCrypter.Decrypt(oldEncPW)
if err != nil {
return err
}
// Re-encrypt with new app pw.
encPW, err := newCrypter.Encrypt(pwB)
if err != nil {
return err
}
// Store encrypted pw.
w.setEncPW(encPW)
err = c.db.SetWalletPassword(w.dbID, encPW)
if err != nil {
return codedError(dbErr, err)
}
return nil
}

for _, w := range c.xcWallets() {
err := updateWalletPW(w)
if err != nil {
return err
}
}

return nil
}

// ChangeAppPass updates the application password to the provided new password
// after validating the current password.
func (c *Core) ChangeAppPass(appPW, newAppPW []byte) error {
// Validate current password.
oldCrypter, err := c.encryptionKey(appPW)
if err != nil {
return newError(authErr, "ChangeAppPass password error: %v", err)
}
// Set new password.
newCrypter, err := c.setAppPass(newAppPW)
if err != nil {
return err
}
// Update xcWallets' encrypted passwords.
err = c.updateWalletsEncPW(oldCrypter, newCrypter)
if err != nil {
return fmt.Errorf("failed to update encrypted wallet password: %w", err)
}
// Update dexConnections' dexAccount key encryption.
c.connMtx.Lock()
defer c.connMtx.Unlock()
for _, dc := range c.conns {
// Re-encrypt private keys.
err = dc.acct.updateKeysEncryption(oldCrypter, newCrypter)
if err != nil {
return fmt.Errorf("ChangeAppPass error updating account's keys"+
" encryption: %v", err)
}
// Update account's db entry.
err = c.db.UpdateAccount(dc.acct.dbInfo())
if err != nil {
return codedError(dbErr, err)
}
}

return nil
}

// ReconfigureWallet updates the wallet configuration settings, it also updates
// the password if newWalletPW is non-nil. Do not make concurrent calls to
// ReconfigureWallet for the same asset.
Expand All @@ -1681,7 +1771,7 @@ func (c *Core) ReconfigureWallet(appPW, newWalletPW []byte, assetID uint32, cfg
AssetID: oldWallet.AssetID,
Settings: cfg,
Balance: &db.Balance{}, // in case retrieving new balance after connect fails
EncryptedPW: oldWallet.encPW,
EncryptedPW: oldWallet.encPW(),
Address: oldWallet.currentDepositAddress(),
}
// Reload the wallet with the new settings.
Expand Down Expand Up @@ -1840,7 +1930,7 @@ func (c *Core) setWalletPassword(wallet *xcWallet, newPW []byte, crypter encrypt
// otherwise does not require a password. Perhaps an
// asset.Wallet.RequiresPassword wallet method?
if newPasswordSet {
// Encrypt password if it's not an empty string
// Encrypt password if it's not an empty string.
encNewPW, err := crypter.Encrypt(newPW)
if err != nil {
return newError(encryptionErr, "encryption error: %v", err)
Expand All @@ -1850,12 +1940,12 @@ func (c *Core) setWalletPassword(wallet *xcWallet, newPW []byte, crypter encrypt
return newError(authErr,
"setWalletPassword unlocking wallet error, is the new password correct?: %v", err)
}
wallet.encPW = encNewPW
wallet.setEncPW(encNewPW)
} else {
wallet.encPW = nil
wallet.setEncPW(nil)
}

err := c.db.SetWalletPassword(wallet.dbID, wallet.encPW)
err := c.db.SetWalletPassword(wallet.dbID, wallet.encPW())
if err != nil {
return codedError(dbErr, err)
}
Expand Down Expand Up @@ -2192,16 +2282,9 @@ func (c *Core) InitializeClient(pw []byte) error {
return fmt.Errorf("already initialized, login instead")
}

if len(pw) == 0 {
return fmt.Errorf("empty password not allowed")
}

crypter := c.newCrypter(pw)
err := c.db.Store(keyParamsKey, crypter.Serialize())
if err != nil {
return fmt.Errorf("error storing key parameters: %w", err)
}
return nil
// Set app password.
_, err := c.setAppPass(pw)
return err
}

// Login logs the user in, decrypting the account keys for all known DEXes.
Expand Down
Loading

0 comments on commit 8d7163c

Please sign in to comment.