diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b987636e0..7d9d032b7 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -132,7 +132,7 @@ 0 0 1617 - 22 + 24 @@ -187,7 +187,6 @@ - @@ -1381,6 +1380,11 @@ font-size: 14pt Dump &Block State as JSON... + + + &Bulk Inject Transactions... + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 1f3b3ffc9..5d5250ac1 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -667,9 +667,10 @@ std::string Main::render(dev::Address const& _a) const if (p.size() == 9 && p.find_first_not_of("QWERYUOPASDFGHJKLZXCVBNM1234567890") == string::npos) p = ICAP(p, "XREG").encoded(); else - DEV_IGNORE_EXCEPTIONS(n = ICAP(_a).encoded()); - if (n.empty()) - n = _a.abridged(); + DEV_IGNORE_EXCEPTIONS(n = ICAP(_a).encoded().substr(0, 8)); + if (!n.empty()) + n += " "; + n += _a.abridged(); return p.empty() ? n : (p + " " + n); } @@ -1586,25 +1587,6 @@ void Main::on_transactionQueue_currentItemChanged() ui->pendingInfo->moveCursor(QTextCursor::Start); } -void Main::on_inject_triggered() -{ - QString s = QInputDialog::getText(this, "Inject Transaction", "Enter transaction dump in hex"); - try - { - bytes b = fromHex(s.toStdString(), WhenError::Throw); - ethereum()->injectTransaction(b); - } - catch (BadHexCharacter& _e) - { - cwarn << "invalid hex character, transaction rejected"; - cwarn << boost::diagnostic_information(_e); - } - catch (...) - { - cwarn << "transaction rejected"; - } -} - void Main::on_injectBlock_triggered() { QString s = QInputDialog::getText(this, "Inject Block", "Enter block dump in hex"); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index e528d0fee..69b4d920a 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -179,7 +179,6 @@ private slots: void on_paranoia_triggered(); void on_killBlockchain_triggered(); void on_clearPending_triggered(); - void on_inject_triggered(); void on_injectBlock_triggered(); void on_forceMining_triggered(); void on_usePrivate_triggered(); diff --git a/alethzero/plugins/namers/OtherAccounts.cpp b/alethzero/plugins/namers/OtherAccounts.cpp index fc2d518bc..19b602b91 100644 --- a/alethzero/plugins/namers/OtherAccounts.cpp +++ b/alethzero/plugins/namers/OtherAccounts.cpp @@ -21,6 +21,7 @@ #include "OtherAccounts.h" #include +#include #include #include #include @@ -46,12 +47,22 @@ void OtherAccounts::import() if (d.exec() == QDialog::Accepted) { QStringList sl = u.accounts->toPlainText().split("\n"); + unsigned line = 1; for (QString const& s: sl) { - Address addr = dev::eth::toAddress(s.section(QRegExp("[ \\0\\t]+"), 0, 0).toStdString()); - string name = s.section(QRegExp("[ \\0\\t]+"), 1).toStdString(); - m_toName[addr] = name; - m_toAddress[name] = addr; + try + { + Address addr = dev::eth::toAddress(s.section(QRegExp("[ \\0\\t]+"), 0, 0).trimmed().toStdString()); + string name = s.section(QRegExp("[ \\0\\t]+"), 1).trimmed().toStdString(); + m_toName[addr] = name; + m_toAddress[name] = addr; + } + catch (...) + { + if (QMessageBox::warning(&d, "Invalid Line Format", "Line format or address given on line " + QString::number(line) + " is invalid:\n" + s, QMessageBox::Abort, QMessageBox::Ignore) == QMessageBox::Abort) + break; + } + line++; } main()->noteSettingsChanged(); noteKnownChanged(); diff --git a/alethzero/plugins/special/InjectTransactions.cpp b/alethzero/plugins/special/InjectTransactions.cpp new file mode 100644 index 000000000..f1535f56e --- /dev/null +++ b/alethzero/plugins/special/InjectTransactions.cpp @@ -0,0 +1,87 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file InjectTransactions.h + * @author Gav Wood + * @date 2015 + */ + +#include "InjectTransactions.h" +#include +#include +#include +#include +#include "ui_InjectTransactions.h" +using namespace std; +using namespace dev; +using namespace az; +using namespace eth; + +DEV_AZ_NOTE_PLUGIN(InjectTransactions); + +InjectTransactions::InjectTransactions(MainFace* _m): + Plugin(_m, "InjectTransactions") +{ + connect(addMenuItem("Inject Transaction...", "menuSpecial", true), SIGNAL(triggered()), SLOT(injectOne())); + connect(addMenuItem("Bulk Inject Transactions...", "menuSpecial", false), SIGNAL(triggered()), SLOT(injectBulk())); +} + +InjectTransactions::~InjectTransactions() +{ +} + +void InjectTransactions::injectOne() +{ + bool ok; + QString s = QInputDialog::getText(main(), "Inject Transaction", "Enter transaction dump in hex", QLineEdit::Normal, QString(), &ok); + if (ok) + doInject(s); +} + +void InjectTransactions::injectBulk() +{ + QDialog d; + Ui_InjectTransactions u; + u.setupUi(&d); + d.setWindowTitle("Bulk Inject Transactions"); + if (d.exec() == QDialog::Accepted) + for (QString const& s: u.transactions->toPlainText().split("\n")) + doInject(s); +} + +void InjectTransactions::doInject(QString _txHex) +{ + try + { + bytes b = fromHex(_txHex.toStdString(), WhenError::Throw); + main()->ethereum()->injectTransaction(b); + } + catch (BadHexCharacter& _e) + { + if (QMessageBox::warning(main(), "Invalid Transaction Hex", "Invalid hex character in:\n" + _txHex + "\nTransaction rejected.", QMessageBox::Ignore, QMessageBox::Abort) == QMessageBox::Abort) + return; + } + catch (Exception& _e) + { + if (QMessageBox::warning(main(), "Transaction Rejected", "Invalid transaction; due to" + QString::fromStdString(_e.what()) + "\n" + _txHex + "\nTransaction rejected.", QMessageBox::Ignore, QMessageBox::Abort) == QMessageBox::Abort) + return; + } + catch (...) + { + // Should not happen under normal circumstances. + return; + } +} diff --git a/alethzero/plugins/special/InjectTransactions.h b/alethzero/plugins/special/InjectTransactions.h new file mode 100644 index 000000000..76941027d --- /dev/null +++ b/alethzero/plugins/special/InjectTransactions.h @@ -0,0 +1,48 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file InjectTransactions.h + * @author Gav Wood + * @date 2015 + */ + +#pragma once + +#include "MainFace.h" + +namespace dev +{ +namespace az +{ + +class InjectTransactions: public QObject, public Plugin +{ + Q_OBJECT + +public: + InjectTransactions(MainFace* _m); + ~InjectTransactions(); + +private slots: + void injectOne(); + void injectBulk(); + +private: + void doInject(QString _txHex); +}; + +} +} diff --git a/alethzero/plugins/special/InjectTransactions.ui b/alethzero/plugins/special/InjectTransactions.ui new file mode 100644 index 000000000..e135130eb --- /dev/null +++ b/alethzero/plugins/special/InjectTransactions.ui @@ -0,0 +1,95 @@ + + + InjectTransactions + + + + 0 + 0 + 511 + 508 + + + + Dialog + + + + + + Write the transactions you wish to inject here, in hex, one per line. + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + &Import + + + true + + + + + + + + + + + inject + clicked() + InjectTransactions + accept() + + + 462 + 484 + + + 449 + 504 + + + + + cancel + clicked() + InjectTransactions + reject() + + + 381 + 483 + + + 351 + 506 + + + + + diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index 74f89ad4a..d69b801bb 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -33,6 +33,7 @@ #include #include #include +#include #include "BuildInfo.h" using namespace std; using namespace dev; @@ -108,6 +109,9 @@ public: Export, Recode, Kill, + NewBrain, + ImportBrain, + InspectBrain, SignTx, DecodeTx, }; @@ -175,6 +179,18 @@ public: m_inputs = strings(1, argv[++i]); m_name = argv[++i]; } + else if (arg == "--new-brain" && i + 1 < argc) + { + m_mode = OperationMode::NewBrain; + m_name = argv[++i]; + } + else if (arg == "--import-brain" && i + 1 < argc) + { + m_mode = OperationMode::ImportBrain; + m_name = argv[++i]; + } + else if (arg == "--inspect-brain") + m_mode = OperationMode::InspectBrain; else if (arg == "--import-with-address" && i + 3 < argc) { m_mode = OperationMode::ImportWithAddress; @@ -203,9 +219,34 @@ public: return k; } + Secret getSecret(std::string const& _signKey) + { + string json = contentsString(_signKey); + if (!json.empty()) + return Secret(secretStore().secret(secretStore().readKeyContent(json), [&](){ return getPassword("Enter password for key: "); })); + else + { + if (h128 u = fromUUID(_signKey)) + return Secret(secretStore().secret(u, [&](){ return getPassword("Enter password for key: "); })); + else if (Address a = Address(_signKey)) + return keyManager().secret(a, [&](){ return getPassword("Enter password for key (hint:" + keyManager().passwordHint(a) + "): "); }); + else if (_signKey.substr(0, 6) == "brain:") + return KeyManager::brain(_signKey.substr(6)); + else if (_signKey == "brain") + return KeyManager::brain(getPassword("Enter brain wallet phrase: ")); + else + { + cerr << "Bad file, UUID and address: " << _signKey << endl; + exit(-1); + } + } + } + void execute() { - if (m_mode == OperationMode::CreateWallet) + switch (m_mode) + { + case OperationMode::CreateWallet: { KeyManager wallet(m_walletPath, m_secretsPath); if (m_masterPassword.empty()) @@ -223,8 +264,9 @@ public: cerr << "unable to create wallet" << endl << boost::diagnostic_information(_e); } } + break; } - else if (m_mode == OperationMode::DecodeTx) + case OperationMode::DecodeTx: { bytes b = inputData(m_inputs[0]); if (b.empty()) @@ -269,50 +311,11 @@ public: { cerr << "Invalid transaction: " << ex.what() << endl; } + break; } - else if (m_mode == OperationMode::SignTx) + case OperationMode::SignTx: { - Secret s; - - string json = contentsString(m_signKey); - if (!json.empty()) - { - SecretStore store(m_secretsPath); - s = Secret(store.secret(store.readKeyContent(json), [&](){ return getPassword("Enter password for key: "); })); - } - else - { - if (h128 u = fromUUID(m_signKey)) - { - SecretStore store(m_secretsPath); - s = Secret(store.secret(u, [&](){ return getPassword("Enter password for key: "); })); - } - else if (Address a = Address(m_signKey)) - { - KeyManager wallet(m_walletPath, m_secretsPath); - if (wallet.exists()) - { - openWallet(wallet); - s = wallet.secret(a, [&](){ return getPassword("Enter password for key: "); }); - } - else - { - cerr << "Wallet doesn't exist." << endl; - exit(-1); - } - } - else - { - cerr << "Bad file, UUID and address: " << m_signKey << endl; - exit(-1); - } - } - if (!s) - { - cerr << "UUID/address not found: " << m_signKey << endl; - exit(-1); - } - + Secret s = getSecret(m_signKey); for (string const& i: m_inputs) { bool isFile; @@ -338,182 +341,208 @@ public: cerr << "Invalid transaction: " << ex.what() << endl; } } + break; } - else if (m_mode < OperationMode::CreateWallet) + case OperationMode::NewBrain: { - SecretStore store(m_secretsPath); - switch (m_mode) - { - case OperationMode::ListBare: - for (h128 const& u: std::set() + store.keys()) - cout << toUUID(u) << endl; - break; - case OperationMode::NewBare: + if (m_name != "--") + keyManager(); + boost::random_device d; + boost::random::uniform_int_distribution pickWord(0, WordList.size() - 1); + string seed; + for (int i = 0; i < 13; ++i) + seed += (seed.size() ? " " : "") + WordList[pickWord(d)]; + cout << "Your brain key phrase: <<" << seed << ">>" << endl; + if (m_name != "--") { - if (m_lock.empty()) - m_lock = createPassword("Enter a password with which to secure this account: "); - auto k = makeKey(); - h128 u = store.importSecret(k.secret().ref(), m_lock); - cout << "Created key " << toUUID(u) << endl; - cout << " Address: " << k.address().hex() << endl; - cout << " ICAP: " << ICAP(k.address()).encoded() << endl; - break; - } - case OperationMode::ImportBare: - for (string const& input: m_inputs) - { - h128 u; - bytesSec b; - b.writable() = fromHex(input); - if (b.size() != 32) - { - std::string s = contentsString(input); - b.writable() = fromHex(s); - if (b.size() != 32) - u = store.importKey(input); - } - if (!u && b.size() == 32) - u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); - if (!u) - { - cerr << "Cannot import " << input << " not a file or secret." << endl; - continue; - } - cout << "Successfully imported " << input << " as " << toUUID(u); - } - break; - case OperationMode::InspectBare: - for (auto const& i: m_inputs) - if (!contents(i).empty()) - { - h128 u = store.readKey(i, false); - bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); - cout << "Key " << i << ":" << endl; - cout << " UUID: " << toUUID(u) << ":" << endl; - cout << " Address: " << toAddress(Secret(s)).hex() << endl; - cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; - } - else if (h128 u = fromUUID(i)) - { - bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); - cout << "Key " << i << ":" << endl; - cout << " Address: " << toAddress(Secret(s)).hex() << endl; - cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; - } - else - cerr << "Couldn't inspect " << i << "; not found." << endl; - break; - case OperationMode::ExportBare: break; - case OperationMode::RecodeBare: - for (auto const& i: m_inputs) - if (h128 u = fromUUID(i)) - if (store.recode(u, lockPassword(toUUID(u)), [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }, kdf())) - cerr << "Re-encoded " << toUUID(u) << endl; - else - cerr << "Couldn't re-encode " << toUUID(u) << "; key corrupt or incorrect password supplied." << endl; - else - cerr << "Couldn't re-encode " << i << "; not found." << endl; - break; - case OperationMode::KillBare: - for (auto const& i: m_inputs) - if (h128 u = fromUUID(i)) - store.kill(u); - else - cerr << "Couldn't kill " << i << "; not found." << endl; - break; - default: break; + std::string hint; + cout << "Enter a hint for the phrase if you want: " << flush; + getline(cin, hint); + Address a = keyManager().importBrain(seed, m_name, hint); + cout << a.abridged() << endl; + cout << " ICAP: " << ICAP(a).encoded() << endl; + cout << " Address: " << a.hex() << endl; } + break; } - else + case OperationMode::InspectBrain: { - KeyManager wallet(m_walletPath, m_secretsPath); - if (wallet.exists()) - openWallet(wallet); - else - { - cerr << "Couldn't open wallet. Does it exist?" << endl; - exit(-1); - } - switch (m_mode) - { - case OperationMode::New: - { - tie(m_lock, m_lockHint) = createPassword(wallet, "Enter a password with which to secure this account (or nothing to use the master password): ", m_lock, m_lockHint); - auto k = makeKey(); - bool usesMaster = m_lock.empty(); - h128 u = usesMaster ? wallet.import(k.secret(), m_name) : wallet.import(k.secret(), m_name, m_lock, m_lockHint); - cout << "Created key " << toUUID(u) << endl; - cout << " Name: " << m_name << endl; - if (usesMaster) - cout << " Uses master password." << endl; - else - cout << " Password hint: " << m_lockHint << endl; - cout << " Address: " << k.address().hex() << endl; - cout << " ICAP: " << ICAP(k.address()).encoded() << endl; - break; - } - case OperationMode::ImportWithAddress: + Address a = toAddress(KeyManager::brain(getPassword("Enter brain wallet key phrase: "))); + cout << a.abridged() << endl; + cout << " ICAP: " << ICAP(a).encoded() << endl; + cout << " Address: " << a.hex() << endl; + break; + } + case OperationMode::ListBare: + for (h128 const& u: std::set() + secretStore().keys()) + cout << toUUID(u) << endl; + break; + case OperationMode::NewBare: + { + if (m_lock.empty()) + m_lock = createPassword("Enter a password with which to secure this account: "); + auto k = makeKey(); + h128 u = secretStore().importSecret(k.secret().ref(), m_lock); + cout << "Created key " << toUUID(u) << endl; + cout << " Address: " << k.address().hex() << endl; + cout << " ICAP: " << ICAP(k.address()).encoded() << endl; + break; + } + case OperationMode::ImportBare: + for (string const& input: m_inputs) { - string const& i = m_inputs[0]; h128 u; bytesSec b; - b.writable() = fromHex(i); + b.writable() = fromHex(input); if (b.size() != 32) { - std::string s = contentsString(i); + std::string s = contentsString(input); b.writable() = fromHex(s); if (b.size() != 32) - u = wallet.store().importKey(i); + u = secretStore().importKey(input); } if (!u && b.size() == 32) - u = wallet.store().importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); + u = secretStore().importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); if (!u) { - cerr << "Cannot import " << i << " not a file or secret." << endl; - break; + cerr << "Cannot import " << input << " not a file or secret." << endl; + continue; } - wallet.importExisting(u, m_name, m_address); - cout << "Successfully imported " << i << ":" << endl; - cout << " Name: " << m_name << endl; - cout << " Address: " << m_address << endl; - cout << " UUID: " << toUUID(u) << endl; - break; + cout << "Successfully imported " << input << " as " << toUUID(u); } - case OperationMode::ImportPresale: + break; + case OperationMode::InspectBare: + for (auto const& i: m_inputs) + if (!contents(i).empty()) + { + h128 u = secretStore().readKey(i, false); + bytesSec s = secretStore().secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); + cout << "Key " << i << ":" << endl; + cout << " UUID: " << toUUID(u) << ":" << endl; + cout << " Address: " << toAddress(Secret(s)).hex() << endl; + cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; + } + else if (h128 u = fromUUID(i)) + { + bytesSec s = secretStore().secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); + cout << "Key " << i << ":" << endl; + cout << " Address: " << toAddress(Secret(s)).hex() << endl; + cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl; + } + else + cerr << "Couldn't inspect " << i << "; not found." << endl; + break; + case OperationMode::ExportBare: break; + case OperationMode::RecodeBare: + for (auto const& i: m_inputs) + if (h128 u = fromUUID(i)) + if (secretStore().recode(u, lockPassword(toUUID(u)), [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }, kdf())) + cerr << "Re-encoded " << toUUID(u) << endl; + else + cerr << "Couldn't re-encode " << toUUID(u) << "; key corrupt or incorrect password supplied." << endl; + else + cerr << "Couldn't re-encode " << i << "; not found." << endl; + break; + case OperationMode::KillBare: + for (auto const& i: m_inputs) + if (h128 u = fromUUID(i)) + secretStore().kill(u); + else + cerr << "Couldn't kill " << i << "; not found." << endl; + break; + case OperationMode::New: + { + keyManager(); + tie(m_lock, m_lockHint) = createPassword(keyManager(), "Enter a password with which to secure this account (or nothing to use the master password): ", m_lock, m_lockHint); + auto k = makeKey(); + bool usesMaster = m_lock.empty(); + h128 u = usesMaster ? keyManager().import(k.secret(), m_name) : keyManager().import(k.secret(), m_name, m_lock, m_lockHint); + cout << "Created key " << toUUID(u) << endl; + cout << " Name: " << m_name << endl; + if (usesMaster) + cout << " Uses master password." << endl; + else + cout << " Password hint: " << m_lockHint << endl; + cout << " Address: " << k.address().hex() << endl; + cout << " ICAP: " << ICAP(k.address()).encoded() << endl; + break; + } + case OperationMode::ImportWithAddress: + { + keyManager(); + string const& i = m_inputs[0]; + h128 u; + bytesSec b; + b.writable() = fromHex(i); + if (b.size() != 32) { - std::string pw; - KeyPair k = wallet.presaleSecret(contentsString(m_inputs[0]), [&](bool){ return (pw = getPassword("Enter the password for the presale key: ")); }); - wallet.import(k.secret(), m_name, pw, "Same password as used for presale key"); - break; + std::string s = contentsString(i); + b.writable() = fromHex(s); + if (b.size() != 32) + u = keyManager().store().importKey(i); } - case OperationMode::List: + if (!u && b.size() == 32) + u = keyManager().store().importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); + if (!u) { - vector bare; - vector nonIcap; - for (auto const& u: wallet.store().keys()) - if (Address a = wallet.address(u)) - if (a[0]) - nonIcap.push_back(u); - else - { - cout << toUUID(u) << " " << a.abridged(); - cout << " " << ICAP(a).encoded(); - cout << " " << wallet.accountName(a) << endl; - } - else - bare.push_back(u); - for (auto const& u: nonIcap) - if (Address a = wallet.address(u)) - { - cout << toUUID(u) << " " << a.abridged(); - cout << " " << ICAP(a).encoded(); - cout << " " << wallet.accountName(a) << endl; - } - for (auto const& u: bare) - cout << toUUID(u) << " (Bare)" << endl; - } - default: break; + cerr << "Cannot import " << i << " not a file or secret." << endl; + break; } + keyManager().importExisting(u, m_name, m_address); + cout << "Successfully imported " << i << ":" << endl; + cout << " Name: " << m_name << endl; + cout << " Address: " << m_address << endl; + cout << " UUID: " << toUUID(u) << endl; + break; + } + case OperationMode::ImportBrain: + { + keyManager(); + std::string seed = getPassword("Enter brain wallet key phrase: "); + std::string hint; + cout << "Enter a hint for the phrase if you want: " << flush; + getline(cin, hint); + Address a = keyManager().importBrain(seed, m_name, hint); + cout << a << endl; + cout << " ICAP: " << ICAP(a).encoded() << endl; + cout << " Address: " << a.hex() << endl; + break; + } + case OperationMode::ImportPresale: + { + keyManager(); + std::string pw; + KeyPair k = keyManager().presaleSecret(contentsString(m_inputs[0]), [&](bool){ return (pw = getPassword("Enter the password for the presale key: ")); }); + keyManager().import(k.secret(), m_name, pw, "Same password as used for presale key"); + break; + } + case OperationMode::List: + { + vector bare; + AddressHash got; + + for (auto const& u: keyManager().store().keys()) + if (Address a = keyManager().address(u)) + { + got.insert(a); + cout << toUUID(u) << " " << a.abridged(); + string s = ICAP(a).encoded(); + cout << " " << s << string(35 - s.size(), ' '); + cout << " " << keyManager().accountName(a) << endl; + } + else + bare.push_back(u); + for (auto const& a: keyManager().accounts()) + if (!got.count(a)) + { + cout << " (Brain) " << a.abridged(); + cout << " " << ICAP(a).encoded() << " "; + cout << " " << keyManager().accountName(a) << endl; + } + for (auto const& u: bare) + cout << toUUID(u) << " (Bare)" << endl; + } + default: break; } } @@ -544,6 +573,12 @@ public: << " --import-with-address [||]
Import keys from given source with given address and place in wallet." << endl << " -e,--export [
| , ... ] Export given keys." << endl << " -r,--recode [
|| , ... ] Decrypt and re-encrypt given keys." << endl + << "Brain wallet operating modes:" << endl + << "WARNING: Brain wallets with human-generated passphrasses are highly susceptible to attack. Don't use such a thing for" << endl + << "anything important." << endl + << " --new-brain [ |-- ] Create a new 13-word brain wallet; argument is the name or if --, do not add to wallet."<< endl + << " --import-brain Import your own brain wallet." << endl + << " --inspect-brain Check the address of a particular brain wallet." << endl << "Wallet configuration:" << endl << " --create-wallet Create an Ethereum master wallet." << endl << " --wallet-path Specify Ethereum wallet path (default: " << KeyManager::defaultPath() << ")" << endl @@ -551,7 +586,7 @@ public: << endl << "Transaction operating modes:" << endl << " -d,--decode-tx [|] Decode given transaction." << endl - << " -s,--sign-tx [
|| ] [ | , ... ] (Re-)Sign given transaction." << endl + << " -s,--sign-tx [
|||brain(:) ] [ | , ... ] (Re-)Sign given transaction." << endl << endl << "Encryption configuration:" << endl << " --kdf Specify KDF to use when encrypting (default: sc rypt)" << endl @@ -613,6 +648,35 @@ private: KDF kdf() const { return m_kdf == "pbkdf2" ? KDF::PBKDF2_SHA256 : KDF::Scrypt; } + KeyManager& keyManager() + { + if (!m_keyManager) + { + m_keyManager.reset(new KeyManager(m_walletPath, m_secretsPath)); + if (m_keyManager->exists()) + openWallet(*m_keyManager); + else + { + cerr << "Couldn't open wallet. Does it exist?" << endl; + exit(-1); + } + } + return *m_keyManager; + } + + SecretStore& secretStore() + { + if (m_keyManager) + return m_keyManager->store(); + if (!m_secretStore) + m_secretStore.reset(new SecretStore(m_secretsPath)); + return *m_secretStore; + } + + /// Where the keys are. + unique_ptr m_secretStore; + unique_ptr m_keyManager; + /// Operating mode. OperationMode m_mode;