// SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2020-2021, The Monero Project. #include "wizard/restorewallet.h" #include "wizard/walletwizard.h" #include "ui_restorewallet.h" #include #include #include #include // tevador 14 word #include "utils/WowletSeed.h" RestorePage::RestorePage(AppContext *ctx, QWidget *parent) : QWizardPage(parent), ui(new Ui::RestorePage), m_ctx(ctx) { ui->setupUi(this); this->setTitle("Restore wallet"); ui->restoreFrame->hide(); ui->label_errorString->hide(); QFont f("wowlet"); f.setStyleHint(QFont::Monospace); auto data = Utils::fileOpen(":/assets/mnemonic_25_english.txt"); for(const auto &seed_word: data.split('\n')) m_words25 << seed_word; for(int i = 0; i != 2048; i++) m_words14 << QString::fromStdString(wordlist::english.get_word(i)); // Restore has limited error correction capability, namely it can correct a single erasure // (illegible word with a known location). This can be tested by replacing a word with xxxx m_words14 << "xxxx"; // m_completer14Model = new QStringListModel(m_words14, m_completer14); m_completer14 = new QCompleter(this); m_completer14->setModel(m_completer14Model); m_completer14->setModelSorting(QCompleter::CaseInsensitivelySortedModel); m_completer14->setCaseSensitivity(Qt::CaseInsensitive); m_completer14->setWrapAround(false); // m_completer25Model = new QStringListModel(m_words25, m_completer25); m_completer25 = new QCompleter(this); m_completer25->setModel(m_completer25Model); m_completer25->setModelSorting(QCompleter::CaseInsensitivelySortedModel); m_completer25->setCaseSensitivity(Qt::CaseInsensitive); m_completer25->setWrapAround(false); // ui->seedEdit->setCompleter(m_completer14); ui->seedEdit->setAcceptRichText(false); ui->seedEdit->setMaximumHeight(80); ui->seedEdit->setFrameShape(QFrame::Box); ui->seedEdit->setFrameShadow(QFrame::Plain); ui->seedEdit->setFont(f); ui->seedEdit->setPlaceholderText("Insert your mnemonic 14 word seed..."); // auto *dummyRestoredSeed = new QLineEdit(this); dummyRestoredSeed->setVisible(false); auto *restoreHeightEdit = new QLineEdit(this); restoreHeightEdit->setVisible(false); this->registerField("mnemonicRestoredSeed", dummyRestoredSeed); this->registerField("restoreHeight", restoreHeightEdit); #ifndef QT_NO_CURSOR QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QGuiApplication::restoreOverrideCursor(); #endif connect(ui->seedBtnGroup, QOverload::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *button){ auto name = button->objectName(); if(name == "radio25") { m_mode = 25; ui->label_errorString->hide(); ui->seedEdit->setStyleSheet(""); ui->seedEdit->setCompleter(m_completer25); ui->restoreFrame->show(); ui->seedEdit->setPlaceholderText("Insert your mnemonic 25 word seed..."); } else if (name == "radio14") { m_mode = 14; ui->label_errorString->hide(); ui->seedEdit->setStyleSheet(""); ui->seedEdit->setCompleter(m_completer14); ui->restoreFrame->hide(); ui->seedEdit->setPlaceholderText("Insert your mnemonic 14 word seed..."); } ui->seedEdit->setText(""); }); if(m_ctx->networkType == NetworkType::Type::TESTNET) { ui->restoreHeightWidget->hideSlider(); } else { // load restoreHeight lookup db ui->restoreHeightWidget->initRestoreHeights(m_ctx->restoreHeights[m_ctx->networkType]); } } int RestorePage::nextId() const { return WalletWizard::Page_CreateWallet; } void RestorePage::initializePage() { ui->seedEdit->setText(""); ui->restoreHeightWidget->setHeight(1); } bool RestorePage::validatePage() { ui->label_errorString->hide(); auto errStyle = "QTextEdit{border: 1px solid red;}"; int restoreHeight = ui->restoreHeightWidget->getHeight(); auto seed = ui->seedEdit->toPlainText().replace("\n", "").replace("\r", "").trimmed(); auto seedSplit = seed.split(" "); if(m_mode == 14) { if(seedSplit.length() != 14) { ui->label_errorString->show(); ui->label_errorString->setText("The mnemonic seed should be 14 words."); ui->seedEdit->setStyleSheet(errStyle); return false; } for(const auto &word: seedSplit) { if(!m_words14.contains(word)) { ui->label_errorString->show(); ui->label_errorString->setText(QString("Mnemonic seed contains an unknown word: %1").arg(word)); ui->seedEdit->setStyleSheet(errStyle); return false; } } } else if(m_mode == 25) { if(seedSplit.length() != 25) { ui->label_errorString->show(); ui->label_errorString->setText("The mnemonic seed should be 25 words."); ui->seedEdit->setStyleSheet(errStyle); return false; } for(const auto &word: seedSplit) { if(!m_words25.contains(word)) { ui->label_errorString->show(); ui->label_errorString->setText(QString("Mnemonic seed contains an unknown word: %1").arg(word)); ui->seedEdit->setStyleSheet(errStyle); return false; } } } auto _seed = WowletSeed(m_ctx->restoreHeights[m_ctx->networkType], m_ctx->coinName, m_ctx->seedLanguage, seedSplit); if (!_seed.errorString.isEmpty()) { QMessageBox::warning(this, "Invalid seed", QString("Invalid seed:\n\n%1").arg(_seed.errorString)); ui->seedEdit->setStyleSheet(errStyle); return false; } if (!_seed.correction.isEmpty()) { QMessageBox::information(this, "Corrected erasure", QString("xxxx -> %1").arg(_seed.correction)); } restoreHeight = _seed.restoreHeight; this->setField("restoreHeight", restoreHeight); this->setField("mnemonicSeed", seed); this->setField("mnemonicRestoredSeed", seed); return true; }