mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-06 18:53:21 +01:00
Move util/message to common/signmessage so it is named more clearly, and because the util library is not supposed to depend on other libraries besides the crypto library. The signmessage functions use CKey, CPubKey, PKHash, and DecodeDestination functions in the consensus and common libraries.
299 lines
11 KiB
C++
299 lines
11 KiB
C++
// Copyright (c) 2011-2022 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <qt/signverifymessagedialog.h>
|
|
#include <qt/forms/ui_signverifymessagedialog.h>
|
|
|
|
#include <qt/addressbookpage.h>
|
|
#include <qt/guiutil.h>
|
|
#include <qt/platformstyle.h>
|
|
#include <qt/walletmodel.h>
|
|
|
|
#include <common/signmessage.h> // For MessageSign(), MessageVerify()
|
|
#include <config/bitcoin-config.h> // IWYU pragma: keep
|
|
#include <key_io.h>
|
|
#include <wallet/wallet.h>
|
|
|
|
#include <vector>
|
|
|
|
#include <QClipboard>
|
|
|
|
SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
|
|
QDialog(parent, GUIUtil::dialog_flags),
|
|
ui(new Ui::SignVerifyMessageDialog),
|
|
platformStyle(_platformStyle)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
ui->addressBookButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
|
|
ui->pasteButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
|
|
ui->copySignatureButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
|
|
ui->signMessageButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/edit"));
|
|
ui->clearButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
|
|
ui->addressBookButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
|
|
ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/transaction_0"));
|
|
ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
|
|
|
|
GUIUtil::setupAddressWidget(ui->addressIn_SM, this);
|
|
GUIUtil::setupAddressWidget(ui->addressIn_VM, this);
|
|
|
|
ui->addressIn_SM->installEventFilter(this);
|
|
ui->messageIn_SM->installEventFilter(this);
|
|
ui->signatureOut_SM->installEventFilter(this);
|
|
ui->addressIn_VM->installEventFilter(this);
|
|
ui->messageIn_VM->installEventFilter(this);
|
|
ui->signatureIn_VM->installEventFilter(this);
|
|
|
|
ui->signatureOut_SM->setFont(GUIUtil::fixedPitchFont());
|
|
ui->signatureIn_VM->setFont(GUIUtil::fixedPitchFont());
|
|
|
|
GUIUtil::handleCloseWindowShortcut(this);
|
|
}
|
|
|
|
SignVerifyMessageDialog::~SignVerifyMessageDialog()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
void SignVerifyMessageDialog::setModel(WalletModel *_model)
|
|
{
|
|
this->model = _model;
|
|
}
|
|
|
|
void SignVerifyMessageDialog::setAddress_SM(const QString &address)
|
|
{
|
|
ui->addressIn_SM->setText(address);
|
|
ui->messageIn_SM->setFocus();
|
|
}
|
|
|
|
void SignVerifyMessageDialog::setAddress_VM(const QString &address)
|
|
{
|
|
ui->addressIn_VM->setText(address);
|
|
ui->messageIn_VM->setFocus();
|
|
}
|
|
|
|
void SignVerifyMessageDialog::showTab_SM(bool fShow)
|
|
{
|
|
ui->tabWidget->setCurrentIndex(0);
|
|
if (fShow)
|
|
this->show();
|
|
}
|
|
|
|
void SignVerifyMessageDialog::showTab_VM(bool fShow)
|
|
{
|
|
ui->tabWidget->setCurrentIndex(1);
|
|
if (fShow)
|
|
this->show();
|
|
}
|
|
|
|
void SignVerifyMessageDialog::on_addressBookButton_SM_clicked()
|
|
{
|
|
if (model && model->getAddressTableModel())
|
|
{
|
|
model->refresh(/*pk_hash_only=*/true);
|
|
AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
|
|
dlg.setModel(model->getAddressTableModel());
|
|
if (dlg.exec())
|
|
{
|
|
setAddress_SM(dlg.getReturnValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
void SignVerifyMessageDialog::on_pasteButton_SM_clicked()
|
|
{
|
|
setAddress_SM(QApplication::clipboard()->text());
|
|
}
|
|
|
|
void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
|
|
{
|
|
if (!model)
|
|
return;
|
|
|
|
/* Clear old signature to ensure users don't get confused on error with an old signature displayed */
|
|
ui->signatureOut_SM->clear();
|
|
|
|
CTxDestination destination = DecodeDestination(ui->addressIn_SM->text().toStdString());
|
|
if (!IsValidDestination(destination)) {
|
|
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
|
|
ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
|
|
return;
|
|
}
|
|
const PKHash* pkhash = std::get_if<PKHash>(&destination);
|
|
if (!pkhash) {
|
|
ui->addressIn_SM->setValid(false);
|
|
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
|
|
ui->statusLabel_SM->setText(tr("The entered address does not refer to a legacy (P2PKH) key. Message signing for SegWit and other non-P2PKH address types is not supported in this version of %1. Please check the address and try again.").arg(PACKAGE_NAME));
|
|
return;
|
|
}
|
|
|
|
WalletModel::UnlockContext ctx(model->requestUnlock());
|
|
if (!ctx.isValid())
|
|
{
|
|
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
|
|
ui->statusLabel_SM->setText(tr("Wallet unlock was cancelled."));
|
|
return;
|
|
}
|
|
|
|
const std::string& message = ui->messageIn_SM->document()->toPlainText().toStdString();
|
|
std::string signature;
|
|
SigningResult res = model->wallet().signMessage(message, *pkhash, signature);
|
|
|
|
QString error;
|
|
switch (res) {
|
|
case SigningResult::OK:
|
|
error = tr("No error");
|
|
break;
|
|
case SigningResult::PRIVATE_KEY_NOT_AVAILABLE:
|
|
error = tr("Private key for the entered address is not available.");
|
|
break;
|
|
case SigningResult::SIGNING_FAILED:
|
|
error = tr("Message signing failed.");
|
|
break;
|
|
// no default case, so the compiler can warn about missing cases
|
|
}
|
|
|
|
if (res != SigningResult::OK) {
|
|
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
|
|
ui->statusLabel_SM->setText(QString("<nobr>") + error + QString("</nobr>"));
|
|
return;
|
|
}
|
|
|
|
ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }");
|
|
ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>"));
|
|
|
|
ui->signatureOut_SM->setText(QString::fromStdString(signature));
|
|
}
|
|
|
|
void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked()
|
|
{
|
|
GUIUtil::setClipboard(ui->signatureOut_SM->text());
|
|
}
|
|
|
|
void SignVerifyMessageDialog::on_clearButton_SM_clicked()
|
|
{
|
|
ui->addressIn_SM->clear();
|
|
ui->messageIn_SM->clear();
|
|
ui->signatureOut_SM->clear();
|
|
ui->statusLabel_SM->clear();
|
|
|
|
ui->addressIn_SM->setFocus();
|
|
}
|
|
|
|
void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
|
|
{
|
|
if (model && model->getAddressTableModel())
|
|
{
|
|
AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
|
|
dlg.setModel(model->getAddressTableModel());
|
|
if (dlg.exec())
|
|
{
|
|
setAddress_VM(dlg.getReturnValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
|
|
{
|
|
const std::string& address = ui->addressIn_VM->text().toStdString();
|
|
const std::string& signature = ui->signatureIn_VM->text().toStdString();
|
|
const std::string& message = ui->messageIn_VM->document()->toPlainText().toStdString();
|
|
|
|
const auto result = MessageVerify(address, signature, message);
|
|
|
|
if (result == MessageVerificationResult::OK) {
|
|
ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }");
|
|
} else {
|
|
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
|
|
}
|
|
|
|
switch (result) {
|
|
case MessageVerificationResult::OK:
|
|
ui->statusLabel_VM->setText(
|
|
QString("<nobr>") + tr("Message verified.") + QString("</nobr>")
|
|
);
|
|
return;
|
|
case MessageVerificationResult::ERR_INVALID_ADDRESS:
|
|
ui->statusLabel_VM->setText(
|
|
tr("The entered address is invalid.") + QString(" ") +
|
|
tr("Please check the address and try again.")
|
|
);
|
|
return;
|
|
case MessageVerificationResult::ERR_ADDRESS_NO_KEY:
|
|
ui->addressIn_VM->setValid(false);
|
|
ui->statusLabel_VM->setText(tr("The entered address does not refer to a legacy (P2PKH) key. Message signing for SegWit and other non-P2PKH address types is not supported in this version of %1. Please check the address and try again.").arg(PACKAGE_NAME));
|
|
return;
|
|
case MessageVerificationResult::ERR_MALFORMED_SIGNATURE:
|
|
ui->signatureIn_VM->setValid(false);
|
|
ui->statusLabel_VM->setText(
|
|
tr("The signature could not be decoded.") + QString(" ") +
|
|
tr("Please check the signature and try again.")
|
|
);
|
|
return;
|
|
case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED:
|
|
ui->signatureIn_VM->setValid(false);
|
|
ui->statusLabel_VM->setText(
|
|
tr("The signature did not match the message digest.") + QString(" ") +
|
|
tr("Please check the signature and try again.")
|
|
);
|
|
return;
|
|
case MessageVerificationResult::ERR_NOT_SIGNED:
|
|
ui->statusLabel_VM->setText(
|
|
QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>")
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void SignVerifyMessageDialog::on_clearButton_VM_clicked()
|
|
{
|
|
ui->addressIn_VM->clear();
|
|
ui->signatureIn_VM->clear();
|
|
ui->messageIn_VM->clear();
|
|
ui->statusLabel_VM->clear();
|
|
|
|
ui->addressIn_VM->setFocus();
|
|
}
|
|
|
|
bool SignVerifyMessageDialog::eventFilter(QObject *object, QEvent *event)
|
|
{
|
|
if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::FocusIn)
|
|
{
|
|
if (ui->tabWidget->currentIndex() == 0)
|
|
{
|
|
/* Clear status message on focus change */
|
|
ui->statusLabel_SM->clear();
|
|
|
|
/* Select generated signature */
|
|
if (object == ui->signatureOut_SM)
|
|
{
|
|
ui->signatureOut_SM->selectAll();
|
|
return true;
|
|
}
|
|
}
|
|
else if (ui->tabWidget->currentIndex() == 1)
|
|
{
|
|
/* Clear status message on focus change */
|
|
ui->statusLabel_VM->clear();
|
|
}
|
|
}
|
|
return QDialog::eventFilter(object, event);
|
|
}
|
|
|
|
void SignVerifyMessageDialog::changeEvent(QEvent* e)
|
|
{
|
|
if (e->type() == QEvent::PaletteChange) {
|
|
ui->addressBookButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/address-book")));
|
|
ui->pasteButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/editpaste")));
|
|
ui->copySignatureButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/editcopy")));
|
|
ui->signMessageButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/edit")));
|
|
ui->clearButton_SM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/remove")));
|
|
ui->addressBookButton_VM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/address-book")));
|
|
ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/transaction_0")));
|
|
ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/remove")));
|
|
}
|
|
|
|
QDialog::changeEvent(e);
|
|
}
|