v30.3-roots.1 · Commit 28: [PATCH 28/68] fix(wallet): secure asynchronous sweep cancellation
src/qt/sweepdialog.cpp
Before: src/qt/sweepdialog.cpp · After: src/qt/sweepdialog.cpp
File metadata
index c77b34aa8d609797ac24e4042c79037c993cfc42..c410a97daa2643469ab2a149605b2ae48d09a3fd 100644
Download original patch · Release notes
Diff rows 1–85 of 85. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.
src/qt/sweepdialog.cpp
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
#include <qt/bitcoinunits.h>
|
|
8
8
|
#include <qt/optionsmodel.h>
|
|
9
9
|
#include <qt/walletmodel.h>
|
|
10
|
+
#include <support/cleanse.h>
|
|
10
11
|
#include <util/translation.h>
|
|
11
12
|
#include <primitives/transaction_identifier.h>
|
|
12
13
|
|
|
13
|
-
#include <QDialogButtonBox>
|
|
14
|
+
#include <QByteArray>
|
|
14
15
|
#include <QCheckBox>
|
|
16
|
+
#include <QDialogButtonBox>
|
|
15
17
|
#include <QFormLayout>
|
|
16
18
|
#include <QKeyEvent>
|
|
17
19
|
#include <QKeySequence>
|
|
@@ -28,6 +30,18 @@ class SecureLineEdit final : public QLineEdit
|
|
|
28
30
|
public:
|
|
29
31
|
using QLineEdit::QLineEdit;
|
|
30
32
|
|
|
33
|
+
SecureString TakeText()
|
|
34
|
+
{
|
|
35
|
+
QByteArray encoded{text().toLatin1()};
|
|
36
|
+
SecureString result{encoded.constData(), static_cast<size_t>(encoded.size())};
|
|
37
|
+
if (!encoded.isEmpty()) memory_cleanse(encoded.data(), encoded.size());
|
|
38
|
+
// QLineEdit does not expose its internal buffer for cleansing. Replace
|
|
39
|
+
// its contents before clearing so the widget no longer retains the WIF.
|
|
40
|
+
setText(QString(text().size(), QChar{' '}));
|
|
41
|
+
clear();
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
31
45
|
protected:
|
|
32
46
|
void keyPressEvent(QKeyEvent* event) override
|
|
33
47
|
{
|
|
@@ -118,7 +132,10 @@ SweepDialog::~SweepDialog() { clearSensitive(); }
|
|
|
118
132
|
|
|
119
133
|
void SweepDialog::invalidate()
|
|
120
134
|
{
|
|
121
|
-
if (m_request_generation != 0) m_wallet_model->invalidateSweepRequests();
|
|
135
|
+
if (m_request_generation != 0 && !m_wallet_model->invalidateSweepRequests()) {
|
|
136
|
+
m_result->setText(tr("Sweep broadcast submission has started and can no longer be cancelled. Wait for its result."));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
122
139
|
m_request_generation = 0;
|
|
123
140
|
m_private_key_cache.clear();
|
|
124
141
|
m_preview_txid.clear();
|
|
@@ -147,13 +164,13 @@ void SweepDialog::preview()
|
|
|
147
164
|
{
|
|
148
165
|
const CTxDestination destination{DecodeDestination(m_destination->text().toStdString())};
|
|
149
166
|
if (!IsValidDestination(destination)) { setResult(tr("Enter a valid destination address."), false); return; }
|
|
150
|
-
m_private_key_cache = SecureString{m_private_key->text().toStdString()};
|
|
151
|
-
if (m_private_key_cache.empty()) { setResult(tr("Enter a private key."), false); return; }
|
|
152
167
|
const QSignalBlocker block{m_private_key};
|
|
153
|
-
m_private_key->clear();
|
|
168
|
+
m_private_key_cache = static_cast<SecureLineEdit*>(m_private_key)->TakeText();
|
|
169
|
+
if (m_private_key_cache.empty()) { setResult(tr("Enter a private key."), false); return; }
|
|
154
170
|
setBusy(true);
|
|
155
171
|
m_result->setText(tr("Scanning for eligible coins and preparing a preview…"));
|
|
156
172
|
m_request_generation = m_wallet_model->requestSweep(m_private_key_cache, destination, false);
|
|
173
|
+
if (m_request_generation == 0) setResult(tr("Another sweep broadcast is already being submitted."), false);
|
|
157
174
|
}
|
|
158
175
|
|
|
159
176
|
void SweepDialog::broadcast()
|
|
@@ -170,6 +187,18 @@ void SweepDialog::broadcast()
|
|
|
170
187
|
m_preview_current = false;
|
|
171
188
|
m_result->setText(tr("Rechecking the preview and broadcasting the sweep…"));
|
|
172
189
|
m_request_generation = m_wallet_model->requestSweep(m_private_key_cache, destination, true, expected_txid);
|
|
190
|
+
if (m_request_generation == 0) setResult(tr("Sweep broadcast submission has already started. Wait for its result."), false);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
void SweepDialog::reject()
|
|
194
|
+
{
|
|
195
|
+
if (m_request_generation != 0 && !m_wallet_model->invalidateSweepRequests()) {
|
|
196
|
+
m_result->setText(tr("Sweep broadcast submission has started and can no longer be cancelled. Wait for its result."));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
m_request_generation = 0;
|
|
200
|
+
clearSensitive();
|
|
201
|
+
QDialog::reject();
|
|
173
202
|
}
|
|
174
203
|
|
|
175
204
|
void SweepDialog::handleSweepFinished(uint64_t generation, bool broadcast, bool success, const QString& error,
|
|
@@ -204,7 +233,7 @@ void SweepDialog::handleSweepFinished(uint64_t generation, bool broadcast, bool
|
|
|
204
233
|
|
|
205
234
|
void SweepDialog::clearSensitive()
|
|
206
235
|
{
|
|
207
|
-
if (m_request_generation != 0) m_wallet_model->invalidateSweepRequests();
|
|
236
|
+
if (m_request_generation != 0 && !m_wallet_model->invalidateSweepRequests()) return;
|
|
208
237
|
m_request_generation = 0;
|
|
209
238
|
const QSignalBlocker block{m_private_key};
|
|
210
239
|
m_private_key->clear();
|