1 // Aleth: Ethereum C++ client, tools and libraries.
2 // Copyright 2016-2019 Aleth Authors.
3 // Licensed under the GNU General Public License, Version 3.
4
5 #include <libdevcore/SHA3.h>
6 #include <libdevcore/FileSystem.h>
7 #include <libdevcore/CommonIO.h>
8 #include <libethcore/KeyManager.h>
9 #include "AccountManager.h"
10 using namespace std;
11 using namespace dev;
12 using namespace dev::eth;
13
streamAccountHelp(ostream & _out)14 void AccountManager::streamAccountHelp(ostream& _out)
15 {
16 _out << " account list List all keys available in wallet\n"
17 << " account new Create a new key and add it to wallet\n"
18 << " account update [<uuid>|<address> , ... ] Decrypt and re-encrypt keys\n"
19 << " account import [<uuid>|<file>|<secret-hex>] Import keys from given source and "
20 "place in wallet\n";
21 }
22
streamWalletHelp(ostream & _out)23 void AccountManager::streamWalletHelp(ostream& _out)
24 {
25 _out << " wallet import <file> Import a presale wallet\n\n";
26 }
27
execute(int argc,char ** argv)28 bool AccountManager::execute(int argc, char** argv)
29 {
30 if (string(argv[1]) == "wallet")
31 {
32 if (3 < argc && string(argv[2]) == "import")
33 {
34 if (!openWallet())
35 return false;
36 string file = argv[3];
37 string name = "presale wallet";
38 string pw;
39 try
40 {
41 KeyPair k = m_keyManager->presaleSecret(
42 contentsString(file),
43 [&](bool){ return (pw = getPassword("Enter the passphrase for the presale key: "));}
44 );
45 m_keyManager->import(k.secret(), name, pw, "Same passphrase as used for presale key");
46 cout << " Address: {" << k.address().hex() << "}\n";
47 }
48 catch (Exception const& _e)
49 {
50 if (auto err = boost::get_error_info<errinfo_comment>(_e))
51 cout << " Decryption failed: " << *err << "\n";
52 else
53 cout << " Decryption failed: Unknown reason.\n";
54 return false;
55 }
56 }
57 else
58 streamWalletHelp(cout);
59 return true;
60 }
61 else if (string(argv[1]) == "account")
62 {
63 if (argc < 3 || string(argv[2]) == "list")
64 {
65 openWallet();
66 if (m_keyManager->store().keys().empty())
67 cout << "No keys found.\n";
68 else
69 {
70 vector<u128> bare;
71 AddressHash got;
72 int k = 0;
73 for (auto const& u: m_keyManager->store().keys())
74 {
75 if (Address a = m_keyManager->address(u))
76 {
77 got.insert(a);
78 cout << "Account #" << k << ": {" << a.hex() << "}\n";
79 k++;
80 }
81 else
82 bare.push_back(u);
83 }
84 for (auto const& a: m_keyManager->accounts())
85 if (!got.count(a))
86 {
87 cout << "Account #" << k << ": {" << a.hex() << "}" << " (Brain)\n";
88 k++;
89 }
90 for (auto const& u: bare)
91 {
92 cout << "Account #" << k << ": " << toUUID(u) << " (Bare)\n";
93 k++;
94 }
95 }
96 }
97 else if (2 < argc && string(argv[2]) == "new")
98 {
99 openWallet();
100 string name;
101 string lock;
102 string lockHint;
103 lock = createPassword("Enter a passphrase with which to secure this account:");
104 auto k = makeKey();
105 h128 u = m_keyManager->import(k.secret(), name, lock, lockHint);
106 cout << "Created key " << toUUID(u) << "\n";
107 cout << " Address: " << k.address().hex() << "\n";
108 }
109 else if (3 < argc && string(argv[2]) == "import")
110 {
111 openWallet();
112 h128 u = m_keyManager->store().importKey(argv[3]);
113 if (!u)
114 {
115 cerr << "Error: reading key file failed\n";
116 return false;
117 }
118 string pw;
119 bytesSec s = m_keyManager->store().secret(u, [&](){ return (pw = getPassword("Enter the passphrase for the key: ")); });
120 if (s.empty())
121 {
122 cerr << "Error: couldn't decode key or invalid secret size.\n";
123 return false;
124 }
125 else
126 {
127 string lockHint;
128 string name;
129 m_keyManager->importExisting(u, name, pw, lockHint);
130 auto a = m_keyManager->address(u);
131 cout << "Imported key " << toUUID(u) << "\n";
132 cout << " Address: " << a.hex() << "\n";
133 }
134 }
135 else if (3 < argc && string(argv[2]) == "update")
136 {
137 openWallet();
138 for (int k = 3; k < argc; k++)
139 {
140 string i = argv[k];
141 h128 u = fromUUID(i);
142 if (isHex(i) || u != h128())
143 {
144 string newP = createPassword("Enter the new passphrase for the account " + i);
145 auto oldP = [&](){ return getPassword("Enter the current passphrase for the account " + i + ": "); };
146 bool recoded = false;
147 if (isHex(i))
148 {
149 recoded = m_keyManager->store().recode(
150 Address(i),
151 newP,
152 oldP,
153 dev::KDF::Scrypt
154 );
155 }
156 else if (u != h128())
157 {
158 recoded = m_keyManager->store().recode(
159 u,
160 newP,
161 oldP,
162 dev::KDF::Scrypt
163 );
164 }
165 if (recoded)
166 cerr << "Re-encoded " << i << "\n";
167 else
168 cerr << "Couldn't re-encode " << i << "; key does not exist, corrupt or incorrect passphrase supplied." << "\n";
169 }
170 else
171 cerr << "Couldn't re-encode " << i << "; does not represent an address or uuid." << "\n";
172 }
173 }
174 else
175 streamAccountHelp(cout);
176 return true;
177 }
178 else
179 return false;
180 }
181
createPassword(string const & _prompt) const182 string AccountManager::createPassword(string const& _prompt) const
183 {
184 string ret;
185 while (true)
186 {
187 ret = getPassword(_prompt);
188 string confirm = getPassword("Please confirm the passphrase by entering it again: ");
189 if (ret == confirm)
190 break;
191 cout << "Passwords were different. Try again." << "\n";
192 }
193 return ret;
194 }
195
makeKey() const196 KeyPair AccountManager::makeKey() const
197 {
198 bool icap = true;
199 KeyPair k(Secret::random());
200 while (icap && k.address()[0])
201 k = KeyPair(Secret(sha3(k.secret().ref())));
202 return k;
203 }
204
openWallet()205 bool AccountManager::openWallet()
206 {
207 if (!m_keyManager)
208 {
209 m_keyManager.reset(new KeyManager());
210 if (m_keyManager->exists())
211 {
212 if (m_keyManager->load(std::string()) || m_keyManager->load(getPassword("Please enter your MASTER passphrase: ")))
213 return true;
214 else
215 {
216 cerr << "Couldn't open wallet. Please check passphrase." << "\n";
217 return false;
218 }
219 }
220 else
221 {
222 cerr << "Couldn't open wallet. Does it exist?" << "\n";
223 return false;
224 }
225 }
226 return true;
227 }
228