Skip to content

Commit 7bfeea6

Browse files
committed
Wordlist validator on keychain backup wizard.
1 parent b758e57 commit 7bfeea6

4 files changed

+88
-18
lines changed

src/keychainbackupwizard.cpp

+11-7
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ KeychainBackupWizard::KeychainBackupWizard(const QString& name, const secure_byt
2727
{
2828
addPage(new WordlistViewPage(name, seed));
2929
addPage(new WordlistVerifyPage(name, seed));
30-
addPage(new WordlistCompletePage());
30+
addPage(new WordlistCompletePage(name));
3131
setWindowTitle(tr("Keychain Backup"));
3232
}
3333

@@ -36,6 +36,7 @@ WordlistViewPage::WordlistViewPage(const QString& name, const secure_bytes_t& se
3636
: QWizardPage(parent)
3737
{
3838
setTitle(tr("Step 1: Copy"));
39+
setSubTitle(tr("Keychain: ") + name);
3940

4041
QLabel* promptLabel = new QLabel(tr("IMPORTANT: Please write down the following list of words. In the event you lose your data you can recover your keychain by entering this list."));
4142
promptLabel->setWordWrap(true);
@@ -53,22 +54,24 @@ WordlistViewPage::WordlistViewPage(const QString& name, const secure_bytes_t& se
5354
WordlistVerifyPage::WordlistVerifyPage(const QString& name, const secure_bytes_t& seed, QWidget* parent)
5455
: QWizardPage(parent)
5556
{
56-
setTitle(tr("Step 2: Verify"));
57+
using namespace Coin;
5758

58-
wordlist = Coin::BIP39::toWordlist(seed).c_str();
59+
setTitle(tr("Step 2: Verify"));
60+
setSubTitle(tr("Keychain: ") + name);
5961

6062
QLabel* promptLabel = new QLabel(tr("Please enter the words in the correct order below:"));
6163
promptLabel->setWordWrap(true);
6264

65+
wordlist = BIP39::toWordlist(seed).c_str();
66+
6367
wordlistEdit = new QLineEdit();
64-
wordlistEdit->setValidator(new WordlistValidator(this));
68+
wordlistEdit->setValidator(new WordlistValidator(BIP39::minWordLen(), BIP39::maxWordLen(), this));
69+
QObject::connect(wordlistEdit, &QLineEdit::textChanged, [=]() { emit completeChanged(); });
6570

6671
QVBoxLayout* layout = new QVBoxLayout();
6772
layout->addWidget(promptLabel);
6873
layout->addWidget(wordlistEdit);
6974
setLayout(layout);
70-
71-
QObject::connect(wordlistEdit, &QLineEdit::textChanged, [=]() { emit completeChanged(); });
7275
}
7376

7477
/*
@@ -84,10 +87,11 @@ bool WordlistVerifyPage::isComplete() const
8487
return (wordlist == wordlistEdit->text());
8588
}
8689

87-
WordlistCompletePage::WordlistCompletePage(QWidget* parent)
90+
WordlistCompletePage::WordlistCompletePage(const QString& name, QWidget* parent)
8891
: QWizardPage(parent)
8992
{
9093
setTitle(tr("Step 3: Put in safe, secure place"));
94+
setSubTitle(tr("Keychain: ") + name);
9195

9296
QLabel* promptLabel = new QLabel(tr("IMPORTANT: Keep the wordlist in a safe place."));
9397
promptLabel->setWordWrap(true);

src/keychainbackupwizard.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,5 @@ class WordlistCompletePage : public QWizardPage
5858
Q_OBJECT
5959

6060
public:
61-
WordlistCompletePage(QWidget* parent = NULL);
61+
WordlistCompletePage(const QString& name, QWidget* parent = NULL);
6262
};

src/wordlistvalidator.cpp

+70-8
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,81 @@
1010

1111
#include "wordlistvalidator.h"
1212

13-
WordlistValidator::WordlistValidator(QObject* parent) :
14-
QValidator(parent)
15-
{
16-
}
13+
#include <string>
1714

18-
void WordlistValidator::fixup(QString& input) const
15+
WordlistValidator::WordlistValidator(int minlen, int maxlen, QObject* parent) :
16+
QValidator(parent), minlen_(minlen), maxlen_(maxlen)
1917
{
20-
input = input.toLower();
2118
}
2219

23-
QValidator::State WordlistValidator::validate(QString& input, int& /*pos*/) const
20+
QValidator::State WordlistValidator::validate(QString& input, int& pos) const
2421
{
2522
if (input.isEmpty()) return Intermediate;
26-
return Acceptable;
23+
input = input.toLower();
24+
25+
// Backspace over spaces if we're not at the end.
26+
if ((pos < input.size()) && (input.size() + 1 == lastInput.size()) && (lastInput[pos] == ' '))
27+
{
28+
QString temp = input.left(pos) + ' ' + input.right(input.size() - pos);
29+
if (temp == lastInput) input = lastInput;
30+
}
31+
32+
QString newInput;
33+
int newPos = pos;
34+
35+
std::string wordlist = input.toStdString();
36+
int len = wordlist.size();
37+
38+
bool removeSpaces = true;
39+
bool final = true;
40+
QString lastWord;
41+
int i = 0;
42+
for (auto c: wordlist)
43+
{
44+
i++;
45+
if (c == ' ')
46+
{
47+
if (lastWord.isEmpty())
48+
{
49+
// Strip extra spaces
50+
if (newPos > newInput.size()) newPos--;
51+
}
52+
else if (lastWord.size() >= minlen_)
53+
{
54+
newInput += lastWord + ' ';
55+
lastWord.clear();
56+
}
57+
else if (i < wordlist.size() && newPos > newInput.size())
58+
{
59+
// Remove words that are too short.
60+
newPos = newInput.size() - 1;
61+
lastWord.clear();
62+
}
63+
else
64+
{
65+
// Disallow adding a space that makes a word too short.
66+
return Invalid;
67+
}
68+
}
69+
else if (c >= 'a' && c <= 'z' && lastWord.size() < maxlen_)
70+
{
71+
lastWord += c;
72+
}
73+
else
74+
{
75+
return Invalid;
76+
}
77+
}
78+
79+
newInput += lastWord;
80+
81+
if (lastWord.size() < minlen_) final = false;
82+
83+
input = newInput;
84+
pos = newPos;
85+
86+
lastInput = input;
87+
88+
return final ? Acceptable : Intermediate;
2789
}
2890

src/wordlistvalidator.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ class WordlistValidator : public QValidator
1818
Q_OBJECT
1919

2020
public:
21-
explicit WordlistValidator(QObject* parent = nullptr);
21+
explicit WordlistValidator(int minlen, int maxlen, QObject* parent = nullptr);
2222
QValidator::State validate(QString& input, int& pos) const;
23-
void fixup(QString& input) const;
23+
24+
private:
25+
mutable QString lastInput;
26+
int minlen_;
27+
int maxlen_;
2428
};
2529

0 commit comments

Comments
 (0)