Skip to content

Commit

Permalink
Support changing password for nep6 wallet (#1504)
Browse files Browse the repository at this point in the history
  • Loading branch information
Qiao-Jin authored Apr 3, 2020
1 parent c00f648 commit 98ec169
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 1 deletion.
46 changes: 45 additions & 1 deletion src/neo/Wallets/NEP6/NEP6Account.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using Neo.IO.Json;
using System;
using System.Threading;

namespace Neo.Wallets.NEP6
{
internal class NEP6Account : WalletAccount
{
private readonly NEP6Wallet wallet;
private readonly string nep2key;
private string nep2key;
private string nep2KeyNew = null;
private KeyPair key;
public JObject Extra;

Expand Down Expand Up @@ -83,5 +85,47 @@ public bool VerifyPassword(string password)
return false;
}
}

/// <summary>
/// Cache draft nep2key during wallet password changing process. Should not be called alone for a single account
/// </summary>
internal bool ChangePasswordPrepare(string password_old, string password_new)
{
if (WatchOnly) return true;
KeyPair keyTemplate = key;
if (nep2key == null)
{
if (keyTemplate == null)
{
return true;
}
}
else
{
try
{
keyTemplate = new KeyPair(Wallet.GetPrivateKeyFromNEP2(nep2key, password_old, wallet.Scrypt.N, wallet.Scrypt.R, wallet.Scrypt.P));
}
catch
{
return false;
}
}
nep2KeyNew = keyTemplate.Export(password_new, wallet.Scrypt.N, wallet.Scrypt.R, wallet.Scrypt.P);
return true;
}

internal void ChangePasswordCommit()
{
if (nep2KeyNew != null)
{
nep2key = Interlocked.Exchange(ref nep2KeyNew, null);
}
}

internal void ChangePasswordRoolback()
{
nep2KeyNew = null;
}
}
}
30 changes: 30 additions & 0 deletions src/neo/Wallets/NEP6/NEP6Wallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using UserWallet = Neo.Wallets.SQLite.UserWallet;

namespace Neo.Wallets.NEP6
Expand Down Expand Up @@ -300,5 +301,34 @@ public override bool VerifyPassword(string password)
}
}
}

public bool ChangePassword(string password_old, string password_new)
{
bool succeed = true;
lock (accounts)
{
Parallel.ForEach(accounts.Values, (account, state) =>
{
if (!account.ChangePasswordPrepare(password_old, password_new))
{
state.Stop();
succeed = false;
}
});
}
if (succeed)
{
foreach (NEP6Account account in accounts.Values)
account.ChangePasswordCommit();
if (password != null)
password = password_new;
}
else
{
foreach (NEP6Account account in accounts.Values)
account.ChangePasswordRoolback();
}
return succeed;
}
}
}
20 changes: 20 additions & 0 deletions tests/neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@ public void TestSetup()
_account = new NEP6Account(_wallet, _hash);
}

[TestMethod]
public void TestChangePassword()
{
_account = new NEP6Account(_wallet, _hash, _nep2);
_account.ChangePasswordPrepare("b", "Satoshi").Should().BeTrue();
_account.ChangePasswordCommit();
_account.Contract = new Contract();
_wallet.Unlock("Satoshi");
_account.ChangePasswordPrepare("b", "Satoshi").Should().BeFalse();
_account.ChangePasswordPrepare("Satoshi", "b").Should().BeTrue();
_account.ChangePasswordCommit();
_account.VerifyPassword("b").Should().BeTrue();
_account.ChangePasswordPrepare("b", "Satoshi").Should().BeTrue();
_account.ChangePasswordCommit();
_account.ChangePasswordPrepare("Satoshi", "b").Should().BeTrue();
_account.ChangePasswordRoolback();
_account.VerifyPassword("Satoshi").Should().BeTrue();
_wallet.Lock();
}

[TestMethod]
public void TestConstructorWithNep2Key()
{
Expand Down
20 changes: 20 additions & 0 deletions tests/neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@ public void TestCleanUp()
if (Directory.Exists(rootPath)) Directory.Delete(rootPath);
}

[TestMethod]
public void TestChangePassword()
{
JObject wallet = new JObject();
wallet["name"] = "name";
wallet["version"] = new System.Version("3.0").ToString();
wallet["scrypt"] = new ScryptParameters(0, 0, 0).ToJson();
wallet["accounts"] = new JArray();
wallet["extra"] = new JObject();
File.WriteAllText(wPath, wallet.ToString());
uut = new NEP6Wallet(wPath);
uut.Unlock("123");
uut.CreateAccount(keyPair.PrivateKey);
uut.ChangePassword("456", "123").Should().BeFalse();
uut.ChangePassword("123", "456").Should().BeTrue();
uut.VerifyPassword("456").Should().BeTrue();
uut.ChangePassword("456", "123").Should().BeTrue();
uut.Lock();
}

[TestMethod]
public void TestConstructorWithPathAndName()
{
Expand Down

0 comments on commit 98ec169

Please sign in to comment.