forked from trustwallet/wallet-core
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathStoredKey.cpp
More file actions
238 lines (200 loc) · 7.25 KB
/
Copy pathStoredKey.cpp
File metadata and controls
238 lines (200 loc) · 7.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// Copyright © 2017-2020 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.
#include "StoredKey.h"
#include "Coin.h"
#define BOOST_UUID_RANDOM_PROVIDER_FORCE_POSIX 1
#include <boost/lexical_cast.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <nlohmann/json.hpp>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdexcept>
using namespace TW;
using namespace TW::Keystore;
StoredKey::StoredKey(StoredKeyType type, std::string name, EncryptionParameters payload)
: type(type), id(), name(std::move(name)), payload(std::move(payload)), accounts() {
boost::uuids::random_generator gen;
id = boost::lexical_cast<std::string>(gen());
}
StoredKey::StoredKey(StoredKeyType type, std::string name, const std::string& password, Data data)
: type(type), id(), name(std::move(name)), payload(password, data), accounts() {
boost::uuids::random_generator gen;
id = boost::lexical_cast<std::string>(gen());
}
StoredKey StoredKey::load(const std::string& path) {
std::ifstream stream(path);
if (!stream.is_open()) {
throw std::invalid_argument("Can't open file");
}
nlohmann::json j;
stream >> j;
StoredKey key(j);
return key;
}
void StoredKey::store(const std::string& path) {
auto stream = std::ofstream(path);
stream << json();
}
HDWallet StoredKey::wallet(const std::string& password) {
if (type != StoredKeyType::mnemonicPhrase) {
throw std::invalid_argument("Invalid account requested.");
}
const auto data = payload.decrypt(password);
const auto mnemonic = std::string(reinterpret_cast<const char*>(data.data()), data.size());
return HDWallet(mnemonic, "");
}
const Account* StoredKey::account(TWCoinType coin, const HDWallet* wallet) {
for (auto& account : accounts) {
if (account.coin() == coin) {
if (account.address.empty() && wallet != nullptr) {
account.address = wallet->deriveAddress(coin);
}
return &account;
}
}
if (wallet == nullptr) {
return nullptr;
}
const auto derivationPath = TW::derivationPath(coin);
const auto address = wallet->deriveAddress(coin);
const auto version = TW::xpubVersion(coin);
const auto extendedPublicKey = wallet->getExtendedPublicKey(derivationPath.purpose(), coin, version);
accounts.emplace_back(address, derivationPath, extendedPublicKey);
return &accounts.back();
}
const Account* StoredKey::account(TWCoinType coin) const {
for (auto& account : accounts) {
if (account.coin() == coin) {
return &account;
}
}
return nullptr;
}
void StoredKey::removeAccount(TWCoinType coin) {
accounts.erase(std::remove_if(accounts.begin(), accounts.end(), [coin](Account& account) -> bool {
return account.coin() == coin;
}
), accounts.end());
}
const PrivateKey StoredKey::privateKey(TWCoinType coin, const std::string& password) {
switch (type) {
case StoredKeyType::mnemonicPhrase: {
const auto wallet = this->wallet(password);
const auto account = *this->account(coin, &wallet);
return wallet.getKey(account.derivationPath);
}
case StoredKeyType::privateKey:
return PrivateKey(payload.decrypt(password));
}
}
void StoredKey::fixAddresses(const std::string& password) {
switch (type) {
case StoredKeyType::mnemonicPhrase: {
const auto wallet = this->wallet(password);
for (auto& account : accounts) {
if (!account.address.empty() && TW::validateAddress(account.coin(), account.address)) {
continue;
}
const auto& derivationPath = account.derivationPath;
const auto key = wallet.getKey(derivationPath);
account.address = TW::deriveAddress(derivationPath.coin(), key);
}
}
break;
case StoredKeyType::privateKey: {
auto key = PrivateKey(payload.decrypt(password));
for (auto& account : accounts) {
if (!account.address.empty() && TW::validateAddress(account.coin(), account.address)) {
continue;
}
account.address = TW::deriveAddress(account.coin(), key);
}
}
break;
}
}
// -----------------
// Encoding/Decoding
// -----------------
namespace CodingKeys {
static const auto address = "address";
static const auto type = "type";
static const auto name = "name";
static const auto id = "id";
static const auto crypto = "crypto";
static const auto activeAccounts = "activeAccounts";
static const auto version = "version";
static const auto coin = "coin";
} // namespace CodingKeys
namespace UppercaseCodingKeys {
static const auto crypto = "Crypto";
} // namespace UppercaseCodingKeys
namespace TypeString {
static const auto privateKey = "private-key";
static const auto mnemonic = "mnemonic";
} // namespace TypeString
StoredKey::StoredKey(const nlohmann::json& json) {
if (json.count(CodingKeys::type) != 0 &&
json[CodingKeys::type].get<std::string>() == TypeString::mnemonic) {
type = StoredKeyType::mnemonicPhrase;
} else {
type = StoredKeyType::privateKey;
}
if (json.count(CodingKeys::name) != 0) {
name = json[CodingKeys::name].get<std::string>();
}
if (json.count(CodingKeys::id) != 0) {
id = json[CodingKeys::id].get<std::string>();
}
if (json.count(CodingKeys::crypto) != 0) {
payload = EncryptionParameters(json[CodingKeys::crypto]);
} else if (json.count(UppercaseCodingKeys::crypto) != 0) {
// Workaround for myEtherWallet files
payload = EncryptionParameters(json[UppercaseCodingKeys::crypto]);
} else {
throw DecryptionError::invalidKeyFile;
}
if (json.count(CodingKeys::activeAccounts) != 0 &&
json[CodingKeys::activeAccounts].is_array()) {
for (auto& accountJSON : json[CodingKeys::activeAccounts]) {
accounts.emplace_back(accountJSON);
}
}
if (accounts.empty() && json.count(CodingKeys::address) != 0 && json[CodingKeys::address].is_string()) {
TWCoinType coin = TWCoinTypeEthereum;
if (json.count(CodingKeys::coin) != 0) {
coin = json[CodingKeys::coin].get<TWCoinType>();
}
auto address = json[CodingKeys::address].get<std::string>();
accounts.emplace_back(address, DerivationPath(TWPurposeBIP44, coin, 0, 0, 0));
}
}
nlohmann::json StoredKey::json() const {
nlohmann::json j;
j[CodingKeys::version] = 3;
switch (type) {
case StoredKeyType::privateKey:
j[CodingKeys::type] = TypeString::privateKey;
break;
case StoredKeyType::mnemonicPhrase:
j[CodingKeys::type] = TypeString::mnemonic;
break;
}
if (id) {
j[CodingKeys::id] = *id;
}
j[CodingKeys::name] = name;
j[CodingKeys::crypto] = payload.json();
nlohmann::json accountsJSON = nlohmann::json::array();
for (const auto& account : accounts) {
accountsJSON.push_back(account.json());
}
j[CodingKeys::activeAccounts] = accountsJSON;
return j;
}