diff --git a/src/keychainbackupwizard.cpp b/src/keychainbackupwizard.cpp index 9a1de71d..93e3a3b8 100644 --- a/src/keychainbackupwizard.cpp +++ b/src/keychainbackupwizard.cpp @@ -25,17 +25,35 @@ KeychainBackupWizard::KeychainBackupWizard(const QString& name, const secure_bytes_t& seed, QWidget* parent) : QWizard(parent) { - addPage(new WordlistViewPage(name, seed)); - addPage(new WordlistVerifyPage(name, seed)); - addPage(new WordlistCompletePage(name)); + addPage(new WordlistViewPage(1, name, seed)); + addPage(new WordlistVerifyPage(2, name, seed)); + addPage(new WordlistCompletePage(3)); + setWindowTitle(tr("Keychain Backup")); +} + +KeychainBackupWizard::KeychainBackupWizard(const QList& names, const QList& seeds, QWidget* parent) + : QWizard(parent) +{ + if (names.size() != seeds.size()) throw std::runtime_error("Number of names does not match number of seeds."); + if (names.isEmpty()) throw std::runtime_error("At least one keychain is required."); + + int i = 0; + for (auto& name: names) + { + const secure_bytes_t& seed = seeds.at(i); + addPage(new WordlistViewPage(2*i + 1, name, seed)); + addPage(new WordlistVerifyPage(2*i + 2, name, seed)); + i++; + } + addPage(new WordlistCompletePage(2*i + 1)); setWindowTitle(tr("Keychain Backup")); } -WordlistViewPage::WordlistViewPage(const QString& name, const secure_bytes_t& seed, QWidget* parent) +WordlistViewPage::WordlistViewPage(int i, const QString& name, const secure_bytes_t& seed, QWidget* parent) : QWizardPage(parent) { - setTitle(tr("Step 1: Copy")); + setTitle(tr("Step ") + QString::number(i) + tr(": Copy")); setSubTitle(tr("Keychain: ") + name); 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.")); @@ -51,12 +69,12 @@ WordlistViewPage::WordlistViewPage(const QString& name, const secure_bytes_t& se setLayout(layout); } -WordlistVerifyPage::WordlistVerifyPage(const QString& name, const secure_bytes_t& seed, QWidget* parent) +WordlistVerifyPage::WordlistVerifyPage(int i, const QString& name, const secure_bytes_t& seed, QWidget* parent) : QWizardPage(parent) { using namespace Coin; - setTitle(tr("Step 2: Verify")); + setTitle(tr("Step ") + QString::number(i) + tr(": Verify")); setSubTitle(tr("Keychain: ") + name); QLabel* promptLabel = new QLabel(tr("Please enter the words in the correct order below:")); @@ -87,13 +105,12 @@ bool WordlistVerifyPage::isComplete() const return (wordlist == wordlistEdit->text()); } -WordlistCompletePage::WordlistCompletePage(const QString& name, QWidget* parent) +WordlistCompletePage::WordlistCompletePage(int i, QWidget* parent) : QWizardPage(parent) { - setTitle(tr("Step 3: Put in safe, secure place")); - setSubTitle(tr("Keychain: ") + name); + setTitle(tr("Step ") + QString::number(i) + tr(": Put in safe, secure place")); - QLabel* promptLabel = new QLabel(tr("IMPORTANT: Keep the wordlist in a safe place.")); + QLabel* promptLabel = new QLabel(tr("IMPORTANT: Keep all wordlists in a safe place.")); promptLabel->setWordWrap(true); QVBoxLayout* layout = new QVBoxLayout(); diff --git a/src/keychainbackupwizard.h b/src/keychainbackupwizard.h index 2e22c90a..9f490191 100644 --- a/src/keychainbackupwizard.h +++ b/src/keychainbackupwizard.h @@ -13,6 +13,7 @@ #include #include +#include class QPlainTextEdit; class QLineEdit; @@ -23,6 +24,7 @@ class KeychainBackupWizard : public QWizard public: KeychainBackupWizard(const QString& name, const secure_bytes_t& seed, QWidget* parent = NULL); + KeychainBackupWizard(const QList& names, const QList& seeds, QWidget* parent = NULL); }; @@ -31,7 +33,7 @@ class WordlistViewPage : public QWizardPage Q_OBJECT public: - WordlistViewPage(const QString& name, const secure_bytes_t& seed, QWidget* parent = NULL); + WordlistViewPage(int i, const QString& name, const secure_bytes_t& seed, QWidget* parent = NULL); protected: QPlainTextEdit* wordlistEdit; @@ -42,7 +44,7 @@ class WordlistVerifyPage : public QWizardPage Q_OBJECT public: - WordlistVerifyPage(const QString& name, const secure_bytes_t& seed, QWidget* parent = NULL); + WordlistVerifyPage(int i, const QString& name, const secure_bytes_t& seed, QWidget* parent = NULL); bool isComplete() const; @@ -58,5 +60,5 @@ class WordlistCompletePage : public QWizardPage Q_OBJECT public: - WordlistCompletePage(const QString& name, QWidget* parent = NULL); + WordlistCompletePage(int i, QWidget* parent = NULL); }; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 612c696d..5efda9dc 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1382,7 +1382,8 @@ void MainWindow::quickNewAccount() if (!synchedVault.isVaultOpen()) throw std::runtime_error("No vault is open."); QuickNewAccountDialog dlg(this); - while (dlg.exec()) { + while (dlg.exec()) + { try { QString accountName = dlg.getName(); if (accountName.isEmpty()) @@ -1397,23 +1398,39 @@ void MainWindow::quickNewAccount() const int MAX_KEYCHAIN_INDEX = 1000; int i = 0; QList keychainNames; - while (keychainNames.size() < dlg.getMaxSigs() && ++i <= MAX_KEYCHAIN_INDEX) { + QList keychainSeeds; + while (keychainNames.size() < dlg.getMaxSigs() && ++i <= MAX_KEYCHAIN_INDEX) + { QString keychainName = accountName + " " + QString::number(i); if (!keychainModel->exists(keychainName)) + { + // TODO: Randomize using user input for seed entropy keychainNames << keychainName; + keychainSeeds << getRandomBytes(32); + } } + if (i > MAX_KEYCHAIN_INDEX) throw std::runtime_error(tr("Ran out of keychain indices.").toStdString()); - for (auto& keychainName: keychainNames) { - // TODO: Randomize using user input for entropy + // Require user to copy down the wordlists + KeychainBackupWizard backupDlg(keychainNames, keychainSeeds, this); + if (!backupDlg.exec()) return; + + { CoinDB::VaultLock lock(synchedVault); if (!synchedVault.isVaultOpen()) throw std::runtime_error("No vault is open."); - secure_bytes_t entropy = getRandomBytes(32); - synchedVault.getVault()->newKeychain(keychainName.toStdString(), entropy); + + int i = 0; + for (auto& keychainName: keychainNames) + { + const secure_bytes_t& keychainSeed = keychainSeeds.at(i++); + synchedVault.getVault()->newKeychain(keychainName.toStdString(), keychainSeed); + } + + accountModel->newAccount(accountName, dlg.getMinSigs(), keychainNames, dlg.getCreationTime()); } - accountModel->newAccount(accountName, dlg.getMinSigs(), keychainNames, dlg.getCreationTime()); accountModel->update(); accountView->updateColumns(); keychainModel->update();