Merge pull request #10032 from brave/import-legacy-brave-mnemonic
Import legacy brave mnemonic
This commit is contained in:
+1
-1
@@ -84,7 +84,7 @@ public class RestoreWalletFragment extends CryptoOnboardingFragment {
|
||||
KeyringController keyringController = getKeyringController();
|
||||
if (keyringController != null) {
|
||||
keyringController.restoreWallet(recoveryPhraseText.getText().toString().trim(),
|
||||
passwordEdittext.getText().toString().trim(), result -> {
|
||||
passwordEdittext.getText().toString().trim(), false, result -> {
|
||||
if (result) {
|
||||
Utils.hideKeyboard(getActivity());
|
||||
onNextPage.gotoNextPage(true);
|
||||
|
||||
@@ -274,10 +274,10 @@ TEST_F(KeyringControllerUnitTest, CreateEncryptorForKeyring) {
|
||||
TEST_F(KeyringControllerUnitTest, CreateDefaultKeyringInternal) {
|
||||
KeyringController controller(GetPrefs());
|
||||
// encryptor is nullptr
|
||||
ASSERT_FALSE(controller.CreateDefaultKeyringInternal(kMnemonic1));
|
||||
ASSERT_FALSE(controller.CreateDefaultKeyringInternal(kMnemonic1, false));
|
||||
|
||||
EXPECT_TRUE(controller.CreateEncryptorForKeyring("brave", "default"));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1, false));
|
||||
controller.default_keyring_->AddAccounts(1);
|
||||
EXPECT_EQ(controller.default_keyring_->GetAddress(0),
|
||||
"0xf81229FE54D8a20fBc1e1e2a3451D1c7489437Db");
|
||||
@@ -291,7 +291,7 @@ TEST_F(KeyringControllerUnitTest, CreateDefaultKeyringInternal) {
|
||||
encrypted_mnemonic1);
|
||||
|
||||
// default keyring will be overwritten
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic2));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic2, false));
|
||||
controller.default_keyring_->AddAccounts(1);
|
||||
EXPECT_EQ(controller.default_keyring_->GetAddress(0),
|
||||
"0xf83C3cBfF68086F276DD4f87A82DF73B57b28820");
|
||||
@@ -349,7 +349,8 @@ TEST_F(KeyringControllerUnitTest, RestoreDefaultKeyring) {
|
||||
const std::string mnemonic = controller.GetMnemonicForDefaultKeyringImpl();
|
||||
|
||||
// Restore with same mnemonic and same password
|
||||
EXPECT_NE(controller.RestoreDefaultKeyring(mnemonic, "brave"), nullptr);
|
||||
EXPECT_NE(controller.RestoreDefaultKeyring(mnemonic, "brave", false),
|
||||
nullptr);
|
||||
EXPECT_EQ(GetStringPrefForKeyring(kEncryptedMnemonic, "default"),
|
||||
encrypted_mnemonic);
|
||||
EXPECT_EQ(GetStringPrefForKeyring(kPasswordEncryptorSalt, "default"), salt);
|
||||
@@ -357,7 +358,8 @@ TEST_F(KeyringControllerUnitTest, RestoreDefaultKeyring) {
|
||||
EXPECT_EQ(controller.default_keyring_->GetAccountsNumber(), 1u);
|
||||
|
||||
// Restore with same mnemonic but different password
|
||||
EXPECT_NE(controller.RestoreDefaultKeyring(mnemonic, "brave377"), nullptr);
|
||||
EXPECT_NE(controller.RestoreDefaultKeyring(mnemonic, "brave377", false),
|
||||
nullptr);
|
||||
EXPECT_NE(GetStringPrefForKeyring(kEncryptedMnemonic, "default"),
|
||||
encrypted_mnemonic);
|
||||
EXPECT_NE(GetStringPrefForKeyring(kPasswordEncryptorSalt, "default"), salt);
|
||||
@@ -371,7 +373,7 @@ TEST_F(KeyringControllerUnitTest, RestoreDefaultKeyring) {
|
||||
nonce = GetStringPrefForKeyring(kPasswordEncryptorNonce, "default");
|
||||
|
||||
// Restore with invalid mnemonic but same password
|
||||
EXPECT_EQ(controller.RestoreDefaultKeyring("", "brave"), nullptr);
|
||||
EXPECT_EQ(controller.RestoreDefaultKeyring("", "brave", false), nullptr);
|
||||
// Keyring prefs won't be cleared
|
||||
EXPECT_EQ(GetStringPrefForKeyring(kEncryptedMnemonic, "default"),
|
||||
encrypted_mnemonic);
|
||||
@@ -380,7 +382,7 @@ TEST_F(KeyringControllerUnitTest, RestoreDefaultKeyring) {
|
||||
EXPECT_EQ(controller.default_keyring_->GetAccountsNumber(), 0u);
|
||||
|
||||
// Restore with same mnemonic but empty password
|
||||
EXPECT_EQ(controller.RestoreDefaultKeyring(mnemonic, ""), nullptr);
|
||||
EXPECT_EQ(controller.RestoreDefaultKeyring(mnemonic, "", false), nullptr);
|
||||
// Keyring prefs won't be cleared
|
||||
EXPECT_EQ(GetStringPrefForKeyring(kEncryptedMnemonic, "default"),
|
||||
encrypted_mnemonic);
|
||||
@@ -390,7 +392,8 @@ TEST_F(KeyringControllerUnitTest, RestoreDefaultKeyring) {
|
||||
|
||||
// default keyring will be overwritten by new seed which will be encrypted by
|
||||
// new key even though the passphrase is same.
|
||||
EXPECT_NE(controller.RestoreDefaultKeyring(kMnemonic1, "brave"), nullptr);
|
||||
EXPECT_NE(controller.RestoreDefaultKeyring(kMnemonic1, "brave", false),
|
||||
nullptr);
|
||||
EXPECT_NE(GetStringPrefForKeyring(kEncryptedMnemonic, "default"),
|
||||
encrypted_mnemonic);
|
||||
// salt is regenerated and account num is cleared
|
||||
@@ -461,7 +464,7 @@ TEST_F(KeyringControllerUnitTest, GetMnemonicForDefaultKeyring) {
|
||||
base::RunLoop().RunUntilIdle();
|
||||
EXPECT_TRUE(string_value().empty());
|
||||
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1, false));
|
||||
controller.GetMnemonicForDefaultKeyring(base::BindOnce(
|
||||
&KeyringControllerUnitTest::GetStringCallback, base::Unretained(this)));
|
||||
base::RunLoop().RunUntilIdle();
|
||||
@@ -655,7 +658,7 @@ TEST_F(KeyringControllerUnitTest, BackupComplete) {
|
||||
TEST_F(KeyringControllerUnitTest, AccountMetasForKeyring) {
|
||||
KeyringController controller(GetPrefs());
|
||||
EXPECT_TRUE(controller.CreateEncryptorForKeyring("brave", "default"));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1, false));
|
||||
controller.default_keyring_->AddAccounts(2);
|
||||
const std::string address1 = controller.default_keyring_->GetAddress(0);
|
||||
const std::string name1 = "Account1";
|
||||
@@ -718,21 +721,27 @@ TEST_F(KeyringControllerUnitTest, CreateAndRestoreWallet) {
|
||||
EXPECT_EQ(account_infos[0]->name, "Account 1");
|
||||
|
||||
controller.Reset();
|
||||
callback_called = false;
|
||||
controller.RestoreWallet(mnemonic_to_be_restored, "brave1",
|
||||
base::BindLambdaForTesting([&](bool success) {
|
||||
EXPECT_TRUE(success);
|
||||
callback_called = true;
|
||||
}));
|
||||
base::RunLoop().RunUntilIdle();
|
||||
EXPECT_TRUE(callback_called);
|
||||
{
|
||||
std::vector<mojom::AccountInfoPtr> account_infos =
|
||||
controller.GetAccountInfosForKeyring("default");
|
||||
EXPECT_EQ(account_infos.size(), 1u);
|
||||
EXPECT_EQ(account_infos[0]->address, address0);
|
||||
EXPECT_EQ(account_infos[0]->name, "Account 1");
|
||||
}
|
||||
auto verify_restore_wallet = base::BindLambdaForTesting(
|
||||
[&mnemonic_to_be_restored, &controller, &address0]() {
|
||||
bool callback_called = false;
|
||||
controller.RestoreWallet(mnemonic_to_be_restored, "brave1", false,
|
||||
base::BindLambdaForTesting([&](bool success) {
|
||||
EXPECT_TRUE(success);
|
||||
callback_called = true;
|
||||
}));
|
||||
base::RunLoop().RunUntilIdle();
|
||||
EXPECT_TRUE(callback_called);
|
||||
{
|
||||
std::vector<mojom::AccountInfoPtr> account_infos =
|
||||
controller.GetAccountInfosForKeyring("default");
|
||||
EXPECT_EQ(account_infos.size(), 1u);
|
||||
EXPECT_EQ(account_infos[0]->address, address0);
|
||||
EXPECT_EQ(account_infos[0]->name, "Account 1");
|
||||
}
|
||||
});
|
||||
verify_restore_wallet.Run();
|
||||
// Restore twice consecutively should succeed and have only one account
|
||||
verify_restore_wallet.Run();
|
||||
}
|
||||
|
||||
TEST_F(KeyringControllerUnitTest, AddAccount) {
|
||||
@@ -1089,7 +1098,7 @@ TEST_F(KeyringControllerUnitTest, ImportedAccountFromJson) {
|
||||
TEST_F(KeyringControllerUnitTest, GetPrivateKeyForDefaultKeyringAccount) {
|
||||
KeyringController controller(GetPrefs());
|
||||
EXPECT_TRUE(controller.CreateEncryptorForKeyring("brave", "default"));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1, false));
|
||||
|
||||
bool callback_called = false;
|
||||
controller.GetPrivateKeyForDefaultKeyringAccount(
|
||||
@@ -1158,7 +1167,7 @@ TEST_F(KeyringControllerUnitTest, SetDefaultKeyringDerivedAccountName) {
|
||||
EXPECT_TRUE(callback_called);
|
||||
|
||||
EXPECT_TRUE(controller.CreateEncryptorForKeyring("brave", "default"));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1));
|
||||
ASSERT_TRUE(controller.CreateDefaultKeyringInternal(kMnemonic1, false));
|
||||
controller.default_keyring_->AddAccounts(2);
|
||||
const std::string address1 = controller.default_keyring_->GetAddress(0);
|
||||
const std::string name1 = "Account1";
|
||||
@@ -1341,4 +1350,52 @@ TEST_F(KeyringControllerUnitTest, SetDefaultKeyringImportedAccountName) {
|
||||
EXPECT_TRUE(callback_called);
|
||||
}
|
||||
|
||||
TEST_F(KeyringControllerUnitTest, RestoreLegacyBraveWallet) {
|
||||
const char* mnemonic24 =
|
||||
"cushion pitch impact album daring marine much annual budget social "
|
||||
"clarify balance rose almost area busy among bring hidden bind later "
|
||||
"capable pulp laundry";
|
||||
const char* mnemonic12 =
|
||||
"drip caution abandon festival order clown oven regular absorb evidence "
|
||||
"crew where";
|
||||
KeyringController controller(GetPrefs());
|
||||
auto verify_restore_wallet = base::BindLambdaForTesting(
|
||||
[&controller](const char* mnemonic, const char* address, bool is_legacy,
|
||||
bool expect_result) {
|
||||
bool callback_called = false;
|
||||
controller.RestoreWallet(mnemonic, "brave1", is_legacy,
|
||||
base::BindLambdaForTesting([&](bool success) {
|
||||
EXPECT_EQ(success, expect_result);
|
||||
callback_called = true;
|
||||
}));
|
||||
base::RunLoop().RunUntilIdle();
|
||||
EXPECT_TRUE(callback_called);
|
||||
if (expect_result) {
|
||||
std::vector<mojom::AccountInfoPtr> account_infos =
|
||||
controller.GetAccountInfosForKeyring("default");
|
||||
ASSERT_EQ(account_infos.size(), 1u);
|
||||
EXPECT_EQ(account_infos[0]->address, address);
|
||||
EXPECT_EQ(account_infos[0]->name, "Account 1");
|
||||
|
||||
// Test lock & unlock to check if it read the right
|
||||
// legacy_brave_wallet pref so it will use the right seed
|
||||
controller.Lock();
|
||||
controller.Unlock("brave1", base::DoNothing::Once<bool>());
|
||||
base::RunLoop().RunUntilIdle();
|
||||
account_infos.clear();
|
||||
account_infos = controller.GetAccountInfosForKeyring("default");
|
||||
ASSERT_EQ(account_infos.size(), 1u);
|
||||
EXPECT_EQ(account_infos[0]->address, address);
|
||||
}
|
||||
});
|
||||
verify_restore_wallet.Run(
|
||||
mnemonic24, "0xea3C17c81E3baC3472d163b2c8b12ddDAa027874", true, true);
|
||||
verify_restore_wallet.Run(
|
||||
mnemonic24, "0xe026eBd81C1A64807F9Cbf21d89a67211eF48717", false, true);
|
||||
// brave legacy menmonic can only be 24 words
|
||||
verify_restore_wallet.Run(mnemonic12, "", true, false);
|
||||
verify_restore_wallet.Run(
|
||||
mnemonic12, "0x084DCb94038af1715963F149079cE011C4B22961", false, true);
|
||||
}
|
||||
|
||||
} // namespace brave_wallet
|
||||
|
||||
@@ -51,6 +51,15 @@ std::string GenerateMnemonicInternal(uint8_t* entropy, size_t size) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsValidEntropySize(size_t entropy_size) {
|
||||
// entropy size should be 128, 160, 192, 224, 256 bits
|
||||
if (entropy_size < 16 || entropy_size > 32 || entropy_size % 4 != 0) {
|
||||
LOG(ERROR) << __func__ << ": Entropy should be 16, 20, 24, 28, 32 bytes";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GetInfuraProjectID() {
|
||||
std::string project_id(BRAVE_INFURA_PROJECT_ID);
|
||||
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
||||
@@ -332,11 +341,8 @@ std::string Uint256ValueToHex(uint256_t input) {
|
||||
}
|
||||
|
||||
std::string GenerateMnemonic(size_t entropy_size) {
|
||||
// entropy size should be 128, 160, 192, 224, 256 bits
|
||||
if (entropy_size < 16 || entropy_size > 32 || entropy_size % 4 != 0) {
|
||||
LOG(ERROR) << __func__ << ": Entropy should be 16, 20, 24, 28, 32 bytes";
|
||||
if (!IsValidEntropySize(entropy_size))
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<uint8_t> entropy(entropy_size);
|
||||
crypto::RandBytes(&entropy[0], entropy.size());
|
||||
@@ -352,10 +358,9 @@ std::string GenerateMnemonicForTest(const std::vector<uint8_t>& entropy) {
|
||||
std::unique_ptr<std::vector<uint8_t>> MnemonicToSeed(
|
||||
const std::string& mnemonic,
|
||||
const std::string& passphrase) {
|
||||
if (!IsValidMnemonic(mnemonic)) {
|
||||
LOG(ERROR) << __func__ << ": Invalid mnemonic: " << mnemonic;
|
||||
if (!IsValidMnemonic(mnemonic))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<uint8_t>> seed =
|
||||
std::make_unique<std::vector<uint8_t>>(64);
|
||||
const std::string salt = "mnemonic" + passphrase;
|
||||
@@ -366,8 +371,54 @@ std::unique_ptr<std::vector<uint8_t>> MnemonicToSeed(
|
||||
return rv == 1 ? std::move(seed) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<uint8_t>> MnemonicToEntropy(
|
||||
const std::string& mnemonic) {
|
||||
if (!IsValidMnemonic(mnemonic))
|
||||
return nullptr;
|
||||
|
||||
const std::vector<std::string> words = SplitString(
|
||||
mnemonic, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
||||
// size in bytes
|
||||
size_t entropy_size = 0;
|
||||
switch (words.size()) {
|
||||
case 12:
|
||||
entropy_size = 16;
|
||||
break;
|
||||
case 15:
|
||||
entropy_size = 20;
|
||||
break;
|
||||
case 18:
|
||||
entropy_size = 24;
|
||||
break;
|
||||
case 21:
|
||||
entropy_size = 28;
|
||||
break;
|
||||
case 24:
|
||||
entropy_size = 32;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
DCHECK(IsValidEntropySize(entropy_size)) << entropy_size;
|
||||
|
||||
std::unique_ptr<std::vector<uint8_t>> entropy =
|
||||
std::make_unique<std::vector<uint8_t>>(entropy_size);
|
||||
|
||||
size_t written;
|
||||
if (bip39_mnemonic_to_bytes(nullptr, mnemonic.c_str(), entropy->data(),
|
||||
entropy->size(), &written) != WALLY_OK) {
|
||||
LOG(ERROR) << "bip39_mnemonic_to_bytes failed";
|
||||
return nullptr;
|
||||
}
|
||||
return entropy;
|
||||
}
|
||||
|
||||
bool IsValidMnemonic(const std::string& mnemonic) {
|
||||
return bip39_mnemonic_validate(nullptr, mnemonic.c_str()) == WALLY_OK;
|
||||
if (bip39_mnemonic_validate(nullptr, mnemonic.c_str()) != WALLY_OK) {
|
||||
LOG(ERROR) << __func__ << ": Invalid mnemonic: " << mnemonic;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EncodeString(const std::string& input, std::string* output) {
|
||||
|
||||
@@ -65,6 +65,9 @@ std::string GenerateMnemonicForTest(const std::vector<uint8_t>& entropy);
|
||||
std::unique_ptr<std::vector<uint8_t>> MnemonicToSeed(
|
||||
const std::string& mnemonic,
|
||||
const std::string& passphrase);
|
||||
// This is mainly used for restoring legacy brave crypto wallet
|
||||
std::unique_ptr<std::vector<uint8_t>> MnemonicToEntropy(
|
||||
const std::string& mnemonic);
|
||||
bool IsValidMnemonic(const std::string& mnemonic);
|
||||
|
||||
bool EncodeString(const std::string& input, std::string* output);
|
||||
|
||||
@@ -292,6 +292,9 @@ TEST(BraveWalletUtilsUnitTest, Mnemonic) {
|
||||
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); ++i) {
|
||||
std::vector<uint8_t> bytes;
|
||||
EXPECT_TRUE(base::HexStringToBytes(cases[i].entropy, &bytes));
|
||||
std::unique_ptr<std::vector<uint8_t>> entropy =
|
||||
MnemonicToEntropy(cases[i].mnemonic);
|
||||
EXPECT_EQ(base::ToLowerASCII(base::HexEncode(*entropy)), cases[i].entropy);
|
||||
|
||||
EXPECT_EQ(GenerateMnemonicForTest(bytes), cases[i].mnemonic);
|
||||
std::unique_ptr<std::vector<uint8_t>> seed =
|
||||
@@ -315,21 +318,23 @@ TEST(BraveWalletUtilsUnitTest, Mnemonic) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BraveWalletUtilsUnitTest, MnemonicToSeed) {
|
||||
EXPECT_NE(MnemonicToSeed("kingdom possible coast island six arrow fluid "
|
||||
"spell chunk loud glue street",
|
||||
""),
|
||||
nullptr);
|
||||
EXPECT_EQ(MnemonicToSeed("lingdom possible coast island six arrow fluid "
|
||||
"spell chunk loud glue street",
|
||||
""),
|
||||
nullptr);
|
||||
EXPECT_EQ(
|
||||
MnemonicToSeed(
|
||||
"kingdom possible coast island six arrow fluid spell chunk loud glue",
|
||||
""),
|
||||
nullptr);
|
||||
TEST(BraveWalletUtilsUnitTest, MnemonicToSeedAndEntropy) {
|
||||
const char* valid_mnemonic =
|
||||
"kingdom possible coast island six arrow fluid spell chunk loud glue "
|
||||
"street";
|
||||
const char* invalid_mnemonic1 =
|
||||
"lingdom possible coast island six arrow fluid spell chunk loud glue "
|
||||
"street";
|
||||
const char* invalid_mnemonic2 =
|
||||
"kingdom possible coast island six arrow fluid spell chunk loud glue";
|
||||
EXPECT_NE(MnemonicToSeed(valid_mnemonic, ""), nullptr);
|
||||
EXPECT_NE(MnemonicToEntropy(valid_mnemonic), nullptr);
|
||||
EXPECT_EQ(MnemonicToSeed(invalid_mnemonic1, ""), nullptr);
|
||||
EXPECT_EQ(MnemonicToEntropy(invalid_mnemonic1), nullptr);
|
||||
EXPECT_EQ(MnemonicToSeed(invalid_mnemonic2, ""), nullptr);
|
||||
EXPECT_EQ(MnemonicToEntropy(invalid_mnemonic2), nullptr);
|
||||
EXPECT_EQ(MnemonicToSeed("", ""), nullptr);
|
||||
EXPECT_EQ(MnemonicToEntropy(""), nullptr);
|
||||
}
|
||||
|
||||
TEST(BraveWalletUtilsUnitTest, IsValidMnemonic) {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
* { "default":
|
||||
* { "backup_complete": false,
|
||||
* "encrypted_mnemonic": [mnemonic],
|
||||
* "legacy_brave_wallet": false,
|
||||
* "account_metas": {
|
||||
* "m/44'/60'/0'/0/0": {
|
||||
* "account_name": "account 1",
|
||||
@@ -69,6 +70,7 @@ const char kAccountName[] = "account_name";
|
||||
const char kImportedAccounts[] = "imported_accounts";
|
||||
const char kAccountAddress[] = "account_address";
|
||||
const char kEncryptedPrivateKey[] = "encrypted_private_key";
|
||||
const char kLegacyBraveWallet[] = "legacy_brave_wallet";
|
||||
|
||||
static base::span<const uint8_t> ToSpan(base::StringPiece sp) {
|
||||
return base::as_bytes(base::make_span(sp));
|
||||
@@ -298,7 +300,7 @@ KeyringController::GetImportedAccountsForKeyring(PrefService* prefs,
|
||||
const std::string* encrypted_private_key =
|
||||
imported_account.FindStringKey(kEncryptedPrivateKey);
|
||||
if (!account_name || !account_address || !encrypted_private_key) {
|
||||
LOG(ERROR) << "Imported accounts corruppted";
|
||||
VLOG(0) << __func__ << "Imported accounts corruppted";
|
||||
continue;
|
||||
}
|
||||
result.push_back(ImportedAccountInfo(
|
||||
@@ -335,7 +337,7 @@ HDKeyring* KeyringController::CreateDefaultKeyring(
|
||||
return nullptr;
|
||||
|
||||
const std::string mnemonic = GenerateMnemonic(16);
|
||||
if (!CreateDefaultKeyringInternal(mnemonic)) {
|
||||
if (!CreateDefaultKeyringInternal(mnemonic, false)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -353,7 +355,13 @@ HDKeyring* KeyringController::ResumeDefaultKeyring(
|
||||
}
|
||||
|
||||
const std::string mnemonic = GetMnemonicForDefaultKeyringImpl();
|
||||
if (mnemonic.empty() || !CreateDefaultKeyringInternal(mnemonic)) {
|
||||
bool is_legacy_brave_wallet = false;
|
||||
const base::Value* value =
|
||||
GetPrefForKeyring(prefs_, kLegacyBraveWallet, kDefaultKeyringId);
|
||||
if (value)
|
||||
is_legacy_brave_wallet = value->GetBool();
|
||||
if (mnemonic.empty() ||
|
||||
!CreateDefaultKeyringInternal(mnemonic, is_legacy_brave_wallet)) {
|
||||
return nullptr;
|
||||
}
|
||||
size_t account_no = GetAccountMetasNumberForKeyring(kDefaultKeyringId);
|
||||
@@ -380,7 +388,8 @@ HDKeyring* KeyringController::ResumeDefaultKeyring(
|
||||
|
||||
HDKeyring* KeyringController::RestoreDefaultKeyring(
|
||||
const std::string& mnemonic,
|
||||
const std::string& password) {
|
||||
const std::string& password,
|
||||
bool is_legacy_brave_wallet) {
|
||||
if (!IsValidMnemonic(mnemonic))
|
||||
return nullptr;
|
||||
|
||||
@@ -388,7 +397,13 @@ HDKeyring* KeyringController::RestoreDefaultKeyring(
|
||||
if (CreateEncryptorForKeyring(password, kDefaultKeyringId)) {
|
||||
const std::string current_mnemonic = GetMnemonicForDefaultKeyringImpl();
|
||||
// Restore with same mnmonic and same password, resume current keyring
|
||||
if (!current_mnemonic.empty() && current_mnemonic == mnemonic) {
|
||||
// Also need to make sure is_legacy_brave_wallet are the same, users might
|
||||
// choose the option wrongly and then want to start over with same mnemonic
|
||||
// but different is_legacy_brave_wallet value
|
||||
const base::Value* value =
|
||||
GetPrefForKeyring(prefs_, kLegacyBraveWallet, kDefaultKeyringId);
|
||||
if (!current_mnemonic.empty() && current_mnemonic == mnemonic && value &&
|
||||
value->GetBool() == is_legacy_brave_wallet) {
|
||||
return ResumeDefaultKeyring(password);
|
||||
} else {
|
||||
// We have no way to check if new mnemonic is same as current mnemonic so
|
||||
@@ -401,7 +416,7 @@ HDKeyring* KeyringController::RestoreDefaultKeyring(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!CreateDefaultKeyringInternal(mnemonic)) {
|
||||
if (!CreateDefaultKeyringInternal(mnemonic, is_legacy_brave_wallet)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -446,9 +461,11 @@ void KeyringController::CreateWallet(const std::string& password,
|
||||
|
||||
void KeyringController::RestoreWallet(const std::string& mnemonic,
|
||||
const std::string& password,
|
||||
bool is_legacy_brave_wallet,
|
||||
RestoreWalletCallback callback) {
|
||||
auto* keyring = RestoreDefaultKeyring(mnemonic, password);
|
||||
if (keyring) {
|
||||
auto* keyring =
|
||||
RestoreDefaultKeyring(mnemonic, password, is_legacy_brave_wallet);
|
||||
if (keyring && !keyring->GetAccountsNumber()) {
|
||||
AddAccountForDefaultKeyring(kFirstAccountName);
|
||||
}
|
||||
// TODO(darkdh): add account discovery mechanism
|
||||
@@ -458,7 +475,7 @@ void KeyringController::RestoreWallet(const std::string& mnemonic,
|
||||
|
||||
const std::string KeyringController::GetMnemonicForDefaultKeyringImpl() {
|
||||
if (IsLocked()) {
|
||||
LOG(ERROR) << __func__ << ": Must Unlock controller first";
|
||||
VLOG(1) << __func__ << ": Must Unlock controller first";
|
||||
return std::string();
|
||||
}
|
||||
DCHECK(encryptor_);
|
||||
@@ -796,14 +813,24 @@ bool KeyringController::CreateEncryptorForKeyring(const std::string& password,
|
||||
}
|
||||
|
||||
bool KeyringController::CreateDefaultKeyringInternal(
|
||||
const std::string& mnemonic) {
|
||||
const std::string& mnemonic,
|
||||
bool is_legacy_brave_wallet) {
|
||||
if (!encryptor_)
|
||||
return false;
|
||||
|
||||
const std::unique_ptr<std::vector<uint8_t>> seed =
|
||||
MnemonicToSeed(mnemonic, "");
|
||||
std::unique_ptr<std::vector<uint8_t>> seed = nullptr;
|
||||
if (is_legacy_brave_wallet)
|
||||
seed = MnemonicToEntropy(mnemonic);
|
||||
else
|
||||
seed = MnemonicToSeed(mnemonic, "");
|
||||
if (!seed)
|
||||
return false;
|
||||
if (is_legacy_brave_wallet && seed->size() != 32) {
|
||||
VLOG(1) << __func__
|
||||
<< "mnemonic for legacy brave wallet must be 24 words which will "
|
||||
"produce 32 bytes seed";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> encrypted_mnemonic;
|
||||
if (!encryptor_->Encrypt(ToSpan(mnemonic),
|
||||
@@ -814,6 +841,12 @@ bool KeyringController::CreateDefaultKeyringInternal(
|
||||
|
||||
SetPrefInBytesForKeyring(kEncryptedMnemonic, encrypted_mnemonic,
|
||||
kDefaultKeyringId);
|
||||
if (is_legacy_brave_wallet)
|
||||
SetPrefForKeyring(prefs_, kLegacyBraveWallet, base::Value(true),
|
||||
kDefaultKeyringId);
|
||||
else
|
||||
SetPrefForKeyring(prefs_, kLegacyBraveWallet, base::Value(false),
|
||||
kDefaultKeyringId);
|
||||
|
||||
default_keyring_ = std::make_unique<HDKeyring>();
|
||||
default_keyring_->ConstructRootHDKey(*seed, kRootPath);
|
||||
|
||||
@@ -95,6 +95,7 @@ class KeyringController : public KeyedService, public mojom::KeyringController {
|
||||
CreateWalletCallback callback) override;
|
||||
void RestoreWallet(const std::string& mnemonic,
|
||||
const std::string& password,
|
||||
bool is_legacy_brave_wallet,
|
||||
RestoreWalletCallback callback) override;
|
||||
void Unlock(const std::string& password, UnlockCallback callback) override;
|
||||
void Lock() override;
|
||||
@@ -170,6 +171,7 @@ class KeyringController : public KeyedService, public mojom::KeyringController {
|
||||
GetPrivateKeyForDefaultKeyringAccount);
|
||||
FRIEND_TEST_ALL_PREFIXES(KeyringControllerUnitTest,
|
||||
SetDefaultKeyringDerivedAccountName);
|
||||
FRIEND_TEST_ALL_PREFIXES(KeyringControllerUnitTest, RestoreLegacyBraveWallet);
|
||||
|
||||
void AddAccountForDefaultKeyring(const std::string& account_name);
|
||||
|
||||
@@ -194,14 +196,16 @@ class KeyringController : public KeyedService, public mojom::KeyringController {
|
||||
std::vector<uint8_t> GetOrCreateNonceForKeyring(const std::string& id);
|
||||
bool CreateEncryptorForKeyring(const std::string& password,
|
||||
const std::string& id);
|
||||
bool CreateDefaultKeyringInternal(const std::string& mnemonic);
|
||||
bool CreateDefaultKeyringInternal(const std::string& mnemonic,
|
||||
bool is_legacy_brave_wallet);
|
||||
|
||||
// Currently only support one default keyring, `CreateDefaultKeyring` and
|
||||
// `RestoreDefaultKeyring` will overwrite existing one if success
|
||||
HDKeyring* CreateDefaultKeyring(const std::string& password);
|
||||
// Restore default keyring from backup seed phrase
|
||||
HDKeyring* RestoreDefaultKeyring(const std::string& mnemonic,
|
||||
const std::string& password);
|
||||
const std::string& password,
|
||||
bool is_legacy_brave_wallet);
|
||||
// It's used to reconstruct same default keyring between browser relaunch
|
||||
HDKeyring* ResumeDefaultKeyring(const std::string& password);
|
||||
|
||||
|
||||
@@ -184,7 +184,8 @@ interface ERCTokenRegistry {
|
||||
interface KeyringController {
|
||||
CreateWallet(string password) => (string mnemonic);
|
||||
GetMnemonicForDefaultKeyring() => (string mnemonic);
|
||||
RestoreWallet(string mnemonic, string password) => (bool isValidMnemonic);
|
||||
RestoreWallet(string mnemonic, string password, bool isLegacyBraveWallet)
|
||||
=> (bool isValidMnemonic);
|
||||
Lock();
|
||||
Unlock(string password) => (bool success);
|
||||
IsLocked() => (bool isLocked);
|
||||
|
||||
@@ -507,7 +507,7 @@ export interface AssetRatioController {
|
||||
|
||||
export interface KeyringController {
|
||||
createWallet: (password: string) => Promise<CreateWalletReturnInfo>
|
||||
restoreWallet: (mnemonic: string, password: string) => Promise<RestoreWalletReturnInfo>
|
||||
restoreWallet: (mnemonic: string, password: string, isLegacy: boolean) => Promise<RestoreWalletReturnInfo>
|
||||
lock: () => Promise<void>
|
||||
unlock: (password: string) => Promise<UnlockReturnInfo>
|
||||
addAccount: (accountName: string) => Promise<AddAccountReturnInfo>
|
||||
|
||||
@@ -45,7 +45,7 @@ handler.on(WalletPageActions.createWallet.getType(), async (store, payload: Crea
|
||||
|
||||
handler.on(WalletPageActions.restoreWallet.getType(), async (store, payload: RestoreWalletPayloadType) => {
|
||||
const keyringController = (await getAPIProxy()).keyringController
|
||||
const result = await keyringController.restoreWallet(payload.mnemonic, payload.password)
|
||||
const result = await keyringController.restoreWallet(payload.mnemonic, payload.password, payload.isLegacy)
|
||||
if (!result.isValidMnemonic) {
|
||||
store.dispatch(WalletPageActions.hasMnemonicError(!result.isValidMnemonic))
|
||||
return
|
||||
|
||||
@@ -34,7 +34,8 @@ export type RemoveImportedAccountPayloadType = {
|
||||
|
||||
export type RestoreWalletPayloadType = {
|
||||
mnemonic: string,
|
||||
password: string
|
||||
password: string,
|
||||
isLegacy: boolean
|
||||
}
|
||||
|
||||
export type WalletCreatedPayloadType = {
|
||||
|
||||
@@ -204,7 +204,7 @@ function Container (props: Props) {
|
||||
|
||||
const restoreWallet = (mnemonic: string, password: string, isLegacy: boolean) => {
|
||||
// isLegacy prop will be passed into the restoreWallet action once the keyring is setup handle the derivation.
|
||||
props.walletPageActions.restoreWallet({ mnemonic, password })
|
||||
props.walletPageActions.restoreWallet({ mnemonic, password, isLegacy })
|
||||
}
|
||||
|
||||
const passwordProvided = (password: string) => {
|
||||
|
||||
@@ -136,7 +136,7 @@ export const _DesktopWalletConcept = (args: { onboarding: boolean, locked: boole
|
||||
setShowBackup(false)
|
||||
}
|
||||
|
||||
const onRestore = (phrase: string, password: string) => {
|
||||
const onRestore = (phrase: string, password: string, isLegacy: boolean) => {
|
||||
if (JSON.stringify(phrase.split(' ')) === JSON.stringify(recoveryPhrase)) {
|
||||
completeWalletSetup(true)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user