Browse Source

ImportKey dialog.

cl-refactor
Gav Wood 10 years ago
parent
commit
441105ec4c
  1. 15
      alethzero/Transact.cpp
  2. 181
      alethzero/plugins/keys/ImportKey.cpp
  3. 44
      alethzero/plugins/keys/ImportKey.h
  4. 291
      alethzero/plugins/keys/ImportKey.ui
  5. 10
      libdevcrypto/SecretStore.cpp
  6. 3
      libdevcrypto/SecretStore.h
  7. 7
      libethcore/KeyManager.cpp
  8. 3
      libethcore/KeyManager.h

15
alethzero/Transact.cpp

@ -136,11 +136,12 @@ void Transact::updateDestination()
// TODO: should be a Qt model.
ui->destination->clear();
ui->destination->addItem("(Create Contract)");
QMultiMap<QString, QString> in;
for (Address const& a: m_main->allKnownAddresses())
{
cdebug << "Adding" << a << m_main->toName(a) << " -> " << (m_main->toName(a) + " (" + ICAP(a).encoded() + ")");
ui->destination->addItem(QString::fromStdString(m_main->toName(a) + " (" + ICAP(a).encoded() + ")"), QString::fromStdString(a.hex()));
}
in.insert(QString::fromStdString(m_main->toName(a) + " (" + ICAP(a).encoded() + ")"), QString::fromStdString(a.hex()));
for (auto i = in.begin(); i != in.end(); ++i)
ui->destination->addItem(i.key(), i.value());
}
void Transact::updateFee()
@ -361,9 +362,8 @@ void Transact::timerEvent(QTimerEvent*)
}
updateBounds();
if (m_lowerBound == m_upperBound)
finaliseBounds();
}
finaliseBounds();
}
void Transact::updateBounds()
@ -380,6 +380,8 @@ void Transact::updateBounds()
void Transact::finaliseBounds()
{
killTimer(m_gasCalcTimer);
quint64 baseGas = (quint64)Transaction::gasRequired(m_data, 0);
ui->progressGas->setVisible(false);
@ -420,7 +422,6 @@ void Transact::finaliseBounds()
updateFee();
ui->code->setHtml(htmlInfo + m_dataInfo);
ui->send->setEnabled(true);
killTimer(m_gasCalcTimer);
}
GasRequirements Transact::determineGasRequirements()

181
alethzero/plugins/keys/ImportKey.cpp

@ -0,0 +1,181 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file ImportKey.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#include "ImportKey.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QInputDialog>
#include <libdevcore/Log.h>
#include <libethcore/KeyManager.h>
#include <libethcore/ICAP.h>
#include <libethereum/Client.h>
#include "ui_ImportKey.h"
using namespace std;
using namespace dev;
using namespace az;
using namespace eth;
DEV_AZ_NOTE_PLUGIN(ImportKey);
ImportKey::ImportKey(MainFace* _m):
Plugin(_m, "ImportKey")
{
connect(addMenuItem("Import Key...", "menuTools", true), SIGNAL(triggered()), SLOT(import()));
}
ImportKey::~ImportKey()
{
}
void ImportKey::import()
{
QDialog d;
Ui_ImportKey u;
u.setupUi(&d);
d.setWindowTitle("Import Key");
string lastKey;
Secret lastSecret;
string lastPassword;
auto updateImport = [&](){
u.import_2->setDisabled(u.addressOut->text().isEmpty() || u.name->text().isEmpty());
};
auto updateAddress = [&](){
string as = u.address->text().toStdString();
try
{
u.addressOut->setText(QString::fromStdString(main()->render(eth::toAddress(as))));
}
catch (...)
{
u.addressOut->setText("");
}
updateImport();
};
auto updatePassword = [&](){
u.passwordHash->setText(QString::fromStdString(sha3(u.password->text().toStdString()).hex()));
};
function<void()> updateKey = [&](){
// update according to key.
if (lastKey == u.key->text().toStdString())
return;
lastKey = u.key->text().toStdString();
lastSecret.clear();
u.address->clear();
u.oldPassword->setEnabled(false);
u.oldPassword->setChecked(false);
bytes b;
DEV_IGNORE_EXCEPTIONS(b = fromHex(lastKey, WhenError::Throw));
if (b.size() == 32)
{
lastSecret = Secret(b);
bytesRef(&b).cleanse();
}
while (!lastKey.empty() && !lastSecret)
{
bool ok;
lastPassword = QInputDialog::getText(&d, "Open Key File", "Enter the password protecting this key file. Cancel if you do not want to provide te password.", QLineEdit::Password, QString(), &ok).toStdString();
if (!ok)
{
lastSecret.clear();
break;
}
// Try to open as a file.
lastSecret = KeyManager::presaleSecret(contentsString(lastKey), [&](bool first){ return first ? lastPassword : string(); }).secret();
if (!lastSecret)
lastSecret = Secret(SecretStore::secret(contentsString(lastKey), lastPassword));
if (!lastSecret && QMessageBox::warning(&d, "Invalid Password or Key File", "The given password could not be used to decrypt the key file given. Are you sure it is a valid key file and that the password is correct?", QMessageBox::Abort, QMessageBox::Retry) == QMessageBox::Abort)
{
u.key->clear();
updateKey();
return;
}
}
u.oldPassword->setEnabled(!!lastSecret);
u.newPassword->setEnabled(!!lastSecret);
u.noPassword->setEnabled(!!lastSecret);
u.password->setEnabled(!!lastSecret);
u.passwordHash->setReadOnly(!!lastSecret);
u.address->setReadOnly(!lastSecret);
if (lastSecret)
{
u.oldPassword->setEnabled(!lastPassword.empty());
if (lastPassword.empty())
u.oldPassword->setChecked(false);
u.address->setText(QString::fromStdString(ICAP(toAddress(lastSecret)).encoded()));
updateAddress();
}
else
u.address->clear();
};
connect(u.noPassword, &QRadioButton::clicked, [&](){
u.passwordHash->clear();
u.hint->setText("Same as master password.");
});
connect(u.oldPassword, &QRadioButton::clicked, [&](){
u.passwordHash->setText(QString::fromStdString(sha3(lastPassword).hex()));
u.hint->setText("Same as original password for file " + QString::fromStdString(lastKey));
});
connect(u.newPassword, &QRadioButton::clicked, [&](){
u.hint->setText("");
updatePassword();
});
connect(u.password, &QLineEdit::textChanged, [&](){ updatePassword(); });
connect(u.address, &QLineEdit::textChanged, [&](){ updateAddress(); });
connect(u.key, &QLineEdit::textEdited, [&](){ updateKey(); });
connect(u.name, &QLineEdit::textEdited, [&](){ updateImport(); });
connect(u.openKey, &QToolButton::clicked, [&](){
QString fn = QFileDialog::getOpenFileName(main(), "Open Key File", QDir::homePath(), "JSON Files (*.json);;All Files (*)");
if (!fn.isEmpty())
{
u.key->setText(fn);
updateKey();
}
});
if (d.exec() == QDialog::Accepted)
{
Address a = ICAP::decoded(u.addressOut->text().toStdString()).direct();
string n = u.name->text().toStdString();
h256 ph;
DEV_IGNORE_EXCEPTIONS(ph = h256(u.passwordHash->text().toStdString()));
string h = u.hint->text().toStdString();
bool mp = u.noPassword->isChecked();
string p = mp ? string() : u.oldPassword ? lastPassword : u.password->text().toStdString();
// check for a brain wallet import
if (lastKey.empty() && !lastSecret)
main()->keyManager().importExistingBrain(a, n, h);
else if (!lastKey.empty() && !lastSecret)
main()->keyManager().importExisting(main()->keyManager().store().importKey(lastKey), n, a, ph, h);
else if (mp)
main()->keyManager().import(lastSecret, n);
else
main()->keyManager().import(lastSecret, n, p, h);
main()->noteKeysChanged();
}
}

44
alethzero/plugins/keys/ImportKey.h

@ -0,0 +1,44 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file ImportKey.h
* @author Gav Wood <i@gavwood.com>
* @date 2015
*/
#pragma once
#include "MainFace.h"
namespace dev
{
namespace az
{
class ImportKey: public QObject, public Plugin
{
Q_OBJECT
public:
ImportKey(MainFace* _m);
~ImportKey();
private slots:
void import();
};
}
}

291
alethzero/plugins/keys/ImportKey.ui

@ -0,0 +1,291 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ImportKey</class>
<widget class="QDialog" name="ImportKey">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>575</width>
<height>315</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2" colspan="2">
<widget class="QLineEdit" name="key">
<property name="placeholderText">
<string>Leave blank for a brain wallet</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QToolButton" name="openKey">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="10" column="2" colspan="3">
<widget class="QLineEdit" name="passwordHash">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="3" colspan="2">
<widget class="QCheckBox" name="showPassword">
<property name="text">
<string>Show</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Address:</string>
</property>
<property name="buddy">
<cstring>address</cstring>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QRadioButton" name="newPassword">
<property name="text">
<string>New Password:</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="4" column="2" colspan="3">
<widget class="QLineEdit" name="address">
<property name="placeholderText">
<string>Place the address of the key here</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Name:</string>
</property>
<property name="buddy">
<cstring>name</cstring>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QRadioButton" name="noPassword">
<property name="text">
<string>Master password</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="11" column="2" colspan="3">
<widget class="QLineEdit" name="hint"/>
</item>
<item row="7" column="0" colspan="2">
<widget class="QRadioButton" name="oldPassword">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Old password</string>
</property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup</string>
</attribute>
</widget>
</item>
<item row="8" column="2">
<widget class="QLineEdit" name="password">
<property name="placeholderText">
<string>Enter the password you wish to use for the key here</string>
</property>
</widget>
</item>
<item row="5" column="2" colspan="3">
<widget class="QLineEdit" name="addressOut">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>Unknown Address</string>
</property>
</widget>
</item>
<item row="2" column="2" colspan="3">
<widget class="QLineEdit" name="name">
<property name="placeholderText">
<string>Enter this key's name here</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Password Hash:</string>
</property>
<property name="buddy">
<cstring>passwordHash</cstring>
</property>
</widget>
</item>
<item row="11" column="0" colspan="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Password Hint:</string>
</property>
<property name="buddy">
<cstring>hint</cstring>
</property>
</widget>
</item>
<item row="6" column="2" colspan="3">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Use same password for the key as for the master.</string>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>Key:</string>
</property>
<property name="buddy">
<cstring>key</cstring>
</property>
</widget>
</item>
<item row="7" column="2" colspan="3">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Use the same password as in the key file.</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="cancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="import_2">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Import</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>key</tabstop>
<tabstop>openKey</tabstop>
<tabstop>name</tabstop>
<tabstop>address</tabstop>
<tabstop>noPassword</tabstop>
<tabstop>oldPassword</tabstop>
<tabstop>newPassword</tabstop>
<tabstop>password</tabstop>
<tabstop>showPassword</tabstop>
<tabstop>passwordHash</tabstop>
<tabstop>hint</tabstop>
<tabstop>cancel</tabstop>
<tabstop>import_2</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>import_2</sender>
<signal>clicked()</signal>
<receiver>ImportKey</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>564</x>
<y>304</y>
</hint>
<hint type="destinationlabel">
<x>449</x>
<y>504</y>
</hint>
</hints>
</connection>
<connection>
<sender>cancel</sender>
<signal>clicked()</signal>
<receiver>ImportKey</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>478</x>
<y>304</y>
</hint>
<hint type="destinationlabel">
<x>351</x>
<y>506</y>
</hint>
</hints>
</connection>
</connections>
<buttongroups>
<buttongroup name="buttonGroup"/>
</buttongroups>
</ui>

10
libdevcrypto/SecretStore.cpp

@ -107,6 +107,14 @@ bytesSec SecretStore::secret(h128 const& _uuid, function<string()> const& _pass,
return key;
}
bytesSec SecretStore::secret(string const& _content, string const& _pass)
{
js::mValue u = upgraded(_content);
if (u.type() != js::obj_type)
return bytesSec();
return decrypt(js::write_string(u.get_obj()["crypto"], false), _pass);
}
h128 SecretStore::importSecret(bytesSec const& _s, string const& _pass)
{
h128 r;
@ -169,8 +177,6 @@ void SecretStore::save(string const& _keysPath)
void SecretStore::load(string const& _keysPath)
{
fs::path p(_keysPath);
fs::create_directories(p);
DEV_IGNORE_EXCEPTIONS(fs::permissions(p, fs::owner_all));
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
if (fs::is_regular_file(it->path()))
readKey(it->path().string(), true);

3
libdevcrypto/SecretStore.h

@ -53,6 +53,9 @@ public:
/// @param _pass function that returns the password for the key.
/// @param _useCache if true, allow previously decrypted keys to be returned directly.
bytesSec secret(h128 const& _uuid, std::function<std::string()> const& _pass, bool _useCache = true) const;
/// @returns the secret key stored by the given @a _uuid.
/// @param _pass function that returns the password for the key.
static bytesSec secret(std::string const& _content, std::string const& _pass);
/// Imports the (encrypted) key stored in the file @a _file and copies it to the managed directory.
h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; }
/// Imports the (encrypted) key contained in the json formatted @a _content and stores it in

7
libethcore/KeyManager.cpp

@ -243,6 +243,13 @@ Address KeyManager::importBrain(string const& _seed, string const& _accountName,
return addr;
}
void KeyManager::importExistingBrain(Address const& _a, string const& _accountName, string const& _passwordHint)
{
m_keyInfo[_a].accountName = _accountName;
m_keyInfo[_a].passwordHint = _passwordHint;
write();
}
void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint)
{
bytesSec key = m_store.secret(_uuid, [&](){ return _pass; });

3
libethcore/KeyManager.h

@ -108,6 +108,7 @@ public:
h128 import(Secret const& _s, std::string const& _accountName, std::string const& _pass, std::string const& _passwordHint);
h128 import(Secret const& _s, std::string const& _accountName) { return import(_s, _accountName, defaultPassword(), std::string()); }
Address importBrain(std::string const& _seed, std::string const& _accountName, std::string const& _seedHint);
void importExistingBrain(Address const& _a, std::string const& _accountName, std::string const& _seedHint);
SecretStore& store() { return m_store; }
void importExisting(h128 const& _uuid, std::string const& _accountName, std::string const& _pass, std::string const& _passwordHint);
@ -130,7 +131,7 @@ public:
static std::string defaultPath() { return getDataDir("ethereum") + "/keys.info"; }
/// Extracts the secret key from the presale wallet.
KeyPair presaleSecret(std::string const& _json, std::function<std::string(bool)> const& _password);
static KeyPair presaleSecret(std::string const& _json, std::function<std::string(bool)> const& _password);
/// @returns the brainwallet secret for the given seed.
static Secret brain(std::string const& _seed);

Loading…
Cancel
Save