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