// Copyright 2019-2024 The Hush developers // Released under the GPLv3 #include "firsttimewizard.h" #include "ui_newseed.h" #include "ui_restoreseed.h" #include "ui_verifyseed.h" #include "ui_newwallet.h" #include "mainwindow.h" #include "DataStore/DataStore.h" #include "../lib/silentdragonlitelib.h" #ifdef Q_OS_WIN auto dirwalletfirst = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet.dat"); auto dirwalletencfirst = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet-enc.dat"); auto dirwalletbackupfirst = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet.datBackup"); #endif #ifdef Q_OS_MACOS auto dirwalletfirst = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet.dat"); auto dirwalletencfirst = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet-enc.dat"); auto dirwalletbackupfirst = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("silentdragonlite/silentdragonlite-wallet.datBackup"); #endif #ifdef Q_OS_LINUX auto dirwalletfirst = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".silentdragonlite/silentdragonlite-wallet.dat"); auto dirwalletencfirst = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".silentdragonlite/silentdragonlite-wallet-enc.dat"); auto dirwalletbackupfirst = QDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).filePath(".silentdragonlite/silentdragonlite-wallet.datBackup"); #endif void FirstTimeWizard::slot_change_theme(const QString& theme_name) { Settings::getInstance()->set_theme_name(theme_name); // Include css QString saved_theme_name; try { saved_theme_name = Settings::getInstance()->get_theme_name(); } catch (...) { saved_theme_name = "Dark"; } QFile qFile(":/css/res/css/" + saved_theme_name +".css"); if (qFile.open(QFile::ReadOnly)) { QString styleSheet = QLatin1String(qFile.readAll()); this->setStyleSheet(""); // resets styles, makes app restart unnecessary this->setStyleSheet(styleSheet); } } FirstTimeWizard::FirstTimeWizard(bool dangerous, QString server){ qDebug() << __func__ << ": dangerous=" << dangerous << " server=" << server; // Set window flags and disable close button - force user to use Wizard's cancel button to prevent funk this->setWindowFlags(this->windowFlags() | Qt::CustomizeWindowHint); this->setWindowFlags(this->windowFlags() & ~Qt::WindowCloseButtonHint); // Include css QString theme_name; try { theme_name = Settings::getInstance()->get_theme_name(); } catch (...) { theme_name = "Dark"; } this->slot_change_theme(theme_name); setWindowTitle(tr("New wallet wizard")); this->dangerous = dangerous; this->server = server; //backup addresslabels.dat if there is one, to restore it later auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); QString addressbook = dir.filePath("addresslabels.dat.enc"); QFile file(addressbook); if (file.exists()) { file.rename(dir.filePath("addresslabels.dat.enc-backup")); qDebug() << __func__ << ": backed up old addresslabels"; } // Create the pages setPage(Page_NewOrRestore, new NewOrRestorePage(this)); setPage(Page_New, new NewSeedPage(this)); setPage(Page_Restore,new RestoreSeedPage(this)); } int FirstTimeWizard::nextId() const { switch (currentId()) { case Page_NewOrRestore: if (field("intro.new").toBool()) { return Page_New; } else { return Page_Restore; } case Page_New: case Page_Restore: default: return -1; } } QString FirstTimeWizard::getSeed() { return _seed; } void FirstTimeWizard::setSeed(QString seed) { _seed = seed; } QString FirstTimeWizard::getBirthday() { return _birthday; } void FirstTimeWizard::setBirthday(QString birthday) { _birthday = birthday; } void FirstTimeWizard::initializePage() { qDebug() << "FirstTimeWizard:" <<__func__; } void NewOrRestorePage::initializePage() { qDebug() << "NewOrRestorePage:" <<__func__; } NewOrRestorePage::NewOrRestorePage(FirstTimeWizard *parent) : QWizardPage(parent) { qDebug() << __func__; setTitle(tr("Create or Restore wallet.")); QWidget* pageWidget = new QWidget(); Ui_CreateWalletForm form; form.setupUi(pageWidget); QGraphicsScene* scene = new QGraphicsScene(); form.Logo->setScene(scene); QPixmap pixmap(":/icons/res/dark-01.png"); scene->addPixmap(pixmap); form.Logo->show(); setButtonText(QWizard::CommitButton, tr("Next")); // Remove back button parent->setOption(QWizard::NoBackButtonOnStartPage); parent->setOption(QWizard::NoBackButtonOnLastPage); form.txtPassword->setEnabled(false); form.txtConfirmPassword->setEnabled(false); QObject::connect(form.TOS, &QRadioButton::clicked, [=](bool checked) { qDebug() << __func__ << ": TOS radio button clicked"; if (checked) { form.txtPassword->setEnabled(true); form.txtConfirmPassword->setEnabled(true); }else{ qDebug() << __func__ << ": disabling next/commit buttons"; parent->button(QWizard::CommitButton)->setEnabled(false); parent->button(QWizard::NextButton)->setEnabled(false); } }); auto fnPasswordEdited = [=](const QString&) { // Enable the Finish button if the passwords match. QString passphraseBlank = form.txtPassword->text(); QString passphrase = QString("HUSH3") + passphraseBlank + QString("SDL"); if (!form.txtPassword->text().isEmpty() && form.txtPassword->text() == form.txtConfirmPassword->text() && passphraseBlank.size() >= 16 ){ form.lblPasswordMatch->setText(""); form.radioRestoreWallet->setEnabled(true); form.radioNewWallet->setEnabled(true); parent->button(QWizard::NextButton)->setEnabled(false); int length = passphrase.length(); //qDebug() << __func__ << ": passphrase length=" << length; char *sequence = NULL; sequence = new char[length+1]; strncpy(sequence, passphrase.toUtf8(), length +1); QString passphraseHash = blake3_PW(sequence); char *sequence1 = NULL; sequence1 = new char[length+1]; strncpy(sequence1, passphraseHash.toUtf8(), length+1); #define MESSAGE ((const unsigned char *) sequence) #define MESSAGE_LEN length #define hash ((const unsigned char *) sequence1) #define PASSWORD sequence #define KEY_LEN crypto_box_SEEDBYTES unsigned char key[KEY_LEN]; if (crypto_pwhash(key, sizeof key, PASSWORD, strlen(PASSWORD), hash, crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE, crypto_pwhash_ALG_DEFAULT) != 0) { /* out of memory */ qDebug() << __func__ << ": crypto_pwhash failed! Possibly out of memory"; exit(1); } QString passphraseHash1 = QByteArray(reinterpret_cast(key), KEY_LEN).toHex(); DataStore::getChatDataStore()->setPassword(passphraseHash1); // Exclusive buttons QObject::connect(form.radioNewWallet, &QRadioButton::clicked, [=](bool checked) { if (checked) { qDebug() << __func__ << ": new wallet radio button clicked"; form.radioRestoreWallet->setChecked(false); parent->button(QWizard::CommitButton)->setEnabled(true); } }); QObject::connect(form.radioRestoreWallet, &QRadioButton::clicked, [=](bool checked) { if (checked) { qDebug() << __func__ << ": restore wallet radio button clicked"; form.radioNewWallet->setChecked(false); parent->button(QWizard::CommitButton)->setEnabled(true); } }); } else { qDebug() << __func__ << ": passphrases do not match"; form.lblPasswordMatch->setText(tr("Passphrase don't match or You have entered too few letters (16 minimum)")); parent->button(QWizard::CommitButton)->setEnabled(false); form.radioRestoreWallet->setEnabled(false); form.radioNewWallet->setEnabled(false); } }; QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(pageWidget); setLayout(layout); QObject::connect(form.txtConfirmPassword, &QLineEdit::textChanged, fnPasswordEdited); QObject::connect(form.txtPassword, &QLineEdit::textChanged, fnPasswordEdited); registerField("intro.new", form.radioNewWallet); registerField("intro.restore", form.radioRestoreWallet); // A trailing * means these are REQUIRED fields and "Next" button will be disabled // until they are filled registerField("TOS*", form.TOS); registerField("txtPassword*", form.txtPassword); registerField("txtConfirmPassword*", form.txtPassword); form.radioRestoreWallet->setEnabled(false); form.radioNewWallet->setEnabled(false); qDebug() << __func__ << ": disabling next/commit buttons"; setCommitPage(true); parent->button(QWizard::CommitButton)->setEnabled(false); parent->button(QWizard::NextButton)->setEnabled(false); // Connect cancelEvent disconnect(parent->button(QWizard::CancelButton ), SIGNAL( clicked() ), parent, SLOT( reject() ) ); connect(parent->button(QWizard::CancelButton ), SIGNAL( clicked() ), parent, SLOT( cancelEvent() ) ); } NewSeedPage::NewSeedPage(FirstTimeWizard *parent) : QWizardPage(parent) { qDebug() << __func__; this->parent = parent; setTitle(tr("Your new wallet")); QWidget* pageWidget = new QWidget(); form.setupUi(pageWidget); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(pageWidget); setLayout(layout); } void NewSeedPage::initializePage() { // Call the library to create a new wallet. qDebug() << __func__; QString reply = ""; try { char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str()); reply = litelib_process_response(resp); } catch (const std::exception& e) { qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); } qDebug() << __func__ << ": reply=" << reply; if (reply.isEmpty()) { qDebug() << "Lite server " << parent->server << " is down, getting a random one"; parent->server = Settings::getRandomServer(); qDebug() << __func__ << ": new server is " << parent->server; // retry with the new server // we use litelib_initialize_existing because the call to litelib_initialize_new above // has already created a wallet on disk char* resp = litelib_initialize_existing(parent->dangerous,parent->server.toStdString().c_str()); reply = litelib_process_response(resp); } auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); if (parsed.is_discarded() || parsed.is_null() || parsed.find("seed") == parsed.end()) { form.txtSeed->setPlainText(tr("Error creating a wallet") + "\n" + reply); } else { QString birthday = QString::number(parsed["birthday"].get()); QString seed = QString::fromStdString(parsed["seed"].get()); form.txtSeed->setPlainText(seed); parent->setSeed(seed); parent->setBirthday(birthday); form.birthday->setPlainText(birthday); qDebug() << __func__ << ": page initialized with birthday=" << birthday; } } void FirstTimeWizard::cancelEvent() { qDebug() << __func__; if( QMessageBox::question( this, tr(( "Quit Setup" )), tr(( "Setup is not complete yet. Are you sure you want to quit setup and close the app?" )), QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes ) { qDebug() << __func__ << ": wizard canceled"; // Allow cancel reject(); // Close the app qApp->exit(); } } // Will be called just before closing. Make sure we can save the seed in the wallet // before we allow the page to be closed bool NewSeedPage::validatePage() { qDebug() << __func__; Ui_verifyseed verifyseed; QDialog dialog(this); verifyseed.setupUi(&dialog); Settings::saveRestore(&dialog); form.birthday->setVisible(false); form.txtSeed->setVisible(false); QString seed = parent->getSeed(); QString birthday = parent->getBirthday(); QString word1 = seed.split(" ").at(13); verifyseed.word1->setText(word1); QString word2 = seed.split(" ").at(23); verifyseed.word2->setText(word2); QString word3 = seed.split(" ").at(11); verifyseed.word3->setText(word3); QString word4 = seed.split(" ").at(15); verifyseed.word4->setText(word4); QString word5 = seed.split(" ").at(20); verifyseed.word5->setText(word5); QString word6 = seed.split(" ").at(12); verifyseed.word6->setText(word6); QString word7 = seed.split(" ").at(16); verifyseed.word7->setText(word7); QString word8 = seed.split(" ").at(19); verifyseed.word8->setText(word8); QString word9 = seed.split(" ").at(21); verifyseed.word9->setText(word9); QString word10 = seed.split(" ").at(17); verifyseed.word10->setText(word10); QString word11 = seed.split(" ").at(14); verifyseed.word11->setText(word11); QString word12 = seed.split(" ").at(2); verifyseed.word12->setText(word12); QString word13 = seed.split(" ").at(5); verifyseed.word13->setText(word13); QString word14 = seed.split(" ").at(0); verifyseed.word14->setText(word14); QString word15 = seed.split(" ").at(10); verifyseed.word15->setText(word15); QString word16 = seed.split(" ").at(3); verifyseed.word16->setText(word16); QString word17 = seed.split(" ").at(6); verifyseed.word17->setText(word17); QString word18 = seed.split(" ").at(9); verifyseed.word18->setText(word18); QString word19 = seed.split(" ").at(22); verifyseed.word19->setText(word19); QString word20 = seed.split(" ").at(7); verifyseed.word20->setText(word20); QString word21 = seed.split(" ").at(4); verifyseed.word21->setText(word21); QString word22 = seed.split(" ").at(8); verifyseed.word22->setText(word22); QString word23 = seed.split(" ").at(18); verifyseed.word23->setText(word23); QString word24 = seed.split(" ").at(1); verifyseed.word24->setText(word24); QObject::connect(verifyseed.word1, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word1 + " "); verifyseed.word1->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word1->font(); button.setStrikeOut(true); verifyseed.word1->setFont(button); verifyseed.word1->setEnabled(false); }); QObject::connect(verifyseed.word2, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word2); verifyseed.word2->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word2->font(); button.setStrikeOut(true); verifyseed.word2->setFont(button); verifyseed.word2->setEnabled(false); }); QObject::connect(verifyseed.word3, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word3 + " "); verifyseed.word3->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word3->font(); button.setStrikeOut(true); verifyseed.word3->setFont(button); verifyseed.word3->setEnabled(false); }); QObject::connect(verifyseed.word4, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word4 + " "); verifyseed.word4->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word4->font(); button.setStrikeOut(true); verifyseed.word4->setFont(button); verifyseed.word4->setEnabled(false); }); QObject::connect(verifyseed.word5, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word5 + " "); verifyseed.word5->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word5->font(); button.setStrikeOut(true); verifyseed.word5->setFont(button); verifyseed.word5->setEnabled(false); }); QObject::connect(verifyseed.word6, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word6 + " "); verifyseed.word6->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word6->font(); button.setStrikeOut(true); verifyseed.word6->setFont(button); verifyseed.word6->setEnabled(false); }); QObject::connect(verifyseed.word7, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word7 + " "); verifyseed.word7->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word7->font(); button.setStrikeOut(true); verifyseed.word7->setFont(button); verifyseed.word7->setEnabled(false); }); QObject::connect(verifyseed.word8, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word8 + " "); verifyseed.word8->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word8->font(); button.setStrikeOut(true); verifyseed.word8->setFont(button); verifyseed.word8->setEnabled(false); }); QObject::connect(verifyseed.word9, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word9 + " "); verifyseed.word9->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word9->font(); button.setStrikeOut(true); verifyseed.word9->setFont(button); verifyseed.word9->setEnabled(false); }); QObject::connect(verifyseed.word10, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word10 + " "); verifyseed.word10->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word10->font(); button.setStrikeOut(true); verifyseed.word10->setFont(button); verifyseed.word10->setEnabled(false); }); QObject::connect(verifyseed.word11, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word11 + " "); verifyseed.word11->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word11->font(); button.setStrikeOut(true); verifyseed.word11->setFont(button); verifyseed.word11->setEnabled(false); }); QObject::connect(verifyseed.word12, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word12 + " "); verifyseed.word12->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word12->font(); button.setStrikeOut(true); verifyseed.word12->setFont(button); verifyseed.word12->setEnabled(false); }); QObject::connect(verifyseed.word13, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word13 + " "); verifyseed.word13->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word13->font(); button.setStrikeOut(true); verifyseed.word13->setFont(button); verifyseed.word13->setEnabled(false); }); QObject::connect(verifyseed.word14, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word14 + " "); verifyseed.word14->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word14->font(); button.setStrikeOut(true); verifyseed.word14->setFont(button); verifyseed.word14->setEnabled(false); }); QObject::connect(verifyseed.word15, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word15 + " "); verifyseed.word15->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word15->font(); button.setStrikeOut(true); verifyseed.word15->setFont(button); verifyseed.word15->setEnabled(false); }); QObject::connect(verifyseed.word16, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word16 + " "); verifyseed.word16->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word16->font(); button.setStrikeOut(true); verifyseed.word16->setFont(button); verifyseed.word16->setEnabled(false); }); QObject::connect(verifyseed.word17, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word17 + " "); verifyseed.word17->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word17->font(); button.setStrikeOut(true); verifyseed.word17->setFont(button); verifyseed.word17->setEnabled(false); }); QObject::connect(verifyseed.word18, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word18 + " "); verifyseed.word18->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word18->font(); button.setStrikeOut(true); verifyseed.word18->setFont(button); verifyseed.word18->setEnabled(false); }); QObject::connect(verifyseed.word19, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word19 + " "); verifyseed.word19->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word19->font(); button.setStrikeOut(true); verifyseed.word19->setFont(button); verifyseed.word19->setEnabled(false); }); QObject::connect(verifyseed.word20, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word20 + " "); verifyseed.word20->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word20->font(); button.setStrikeOut(true); verifyseed.word20->setFont(button); verifyseed.word20->setEnabled(false); }); QObject::connect(verifyseed.word21, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word21 + " "); verifyseed.word21->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word21->font(); button.setStrikeOut(true); verifyseed.word21->setFont(button); verifyseed.word21->setEnabled(false); }); QObject::connect(verifyseed.word22, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word22 + " "); verifyseed.word22->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word22->font(); button.setStrikeOut(true); verifyseed.word22->setFont(button); verifyseed.word22->setEnabled(false); }); QObject::connect(verifyseed.word23, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word23 + " "); verifyseed.word23->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word23->font(); button.setStrikeOut(true); verifyseed.word23->setFont(button); verifyseed.word23->setEnabled(false); }); QObject::connect(verifyseed.word24, &QPushButton::clicked, [&] () { verifyseed.verify->insertPlainText(word24 + " "); verifyseed.word24->setStyleSheet("background-color: rgb(182,182,182);"); QFont button = verifyseed.word24->font(); button.setStrikeOut(true); verifyseed.word24->setFont(button); verifyseed.word24->setEnabled(false); }); dialog.exec(); QString reply = ""; if ((verifyseed.verify->toPlainText() == seed) && (verifyseed.verifyBirthday->toPlainText() == birthday)) { try { char* resp = litelib_execute("save", ""); reply = litelib_process_response(resp); } catch (const std::exception& e) { qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); } qDebug() << __func__ << ": reply=" << reply; // TODO: this is duplicated code that should be refactored // into a dedicated function if (reply.isEmpty()) { qDebug() << "Lite server " << parent->server << " is down, getting a random one"; parent->server = Settings::getRandomServer(); qDebug() << __func__ << ": new server is " << parent->server; // make a new connection to the new server char* resp = litelib_initialize_new(parent->dangerous,parent->server.toStdString().c_str()); reply = litelib_process_response(resp); // retry with the new server try { resp = litelib_execute("save", ""); reply = litelib_process_response(resp); } catch (const std::exception& e) { qDebug() << __func__ << ": caught an exception with new server, something is fucky: " << e.what(); } } qDebug() << __func__ << ": reply=" << reply; auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) { QMessageBox::warning(this, tr("Failed to save wallet"), tr("Couldn't save the wallet") + "\n" + "server=" + parent->server + "\n" + reply, QMessageBox::Ok); return false; } else { return true; } }else{ qDebug()<<"Wrong Seed"; QFile file(dirwalletencfirst); QFile file1(dirwalletfirst); file.remove(); file1.remove(); QMessageBox::warning(this, tr("Wrong Seed"), tr("Please try again") + "\n" , QMessageBox::Ok); form.birthday->setVisible(true); form.txtSeed->setVisible(true); return false; this->validatePage(); } return false; } RestoreSeedPage::RestoreSeedPage(FirstTimeWizard *parent) : QWizardPage(parent) { this->parent = parent; setTitle(tr("Restore wallet from seed")); QWidget* pageWidget = new QWidget(); form.setupUi(pageWidget); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(pageWidget); setLayout(layout); } bool RestoreSeedPage::validatePage() { // 1. Validate that we do have 24 words QString seed = form.txtSeed->toPlainText().replace(QRegExp("[ \n\r\t]+"), " "); //TODO: use .simplified() auto seedLength = seed.trimmed().split(" ").length(); qDebug() << __func__ << ": seed length=" << seedLength; if (seedLength != 24) { QMessageBox::warning(this, tr("Failed to restore wallet"), tr("SilentDragonLite needs 24 words to restore wallet"), QMessageBox::Ok); return false; } // 2. Validate birthday QString birthday_str = form.txtBirthday->text(); bool ok; // simplified() Returns a string that has whitespace removed from the start and the end, and that has each sequence of internal whitespace replaced with a single space. qint64 birthday = birthday_str.simplified().toUInt(&ok); if (!ok) { qDebug() << __func__ << ": Failed to parse wallet birthday=" << birthday_str; QMessageBox::warning(this, tr("Failed to parse wallet birthday"), tr("Couldn't understand wallet birthday. This should be a block height from where to rescan the wallet. You can leave the default if you don't know what it should be."), QMessageBox::Ok); return false; } // 3. Initialize wallet with number QString number_str = form.number->text(); qint64 number = number_str.toUInt(); qDebug() << __func__ << ": Initializing wallet with number: " << number; QString reply = ""; try { char *resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), seed.toStdString().c_str(), birthday, number); if (resp != nullptr) { reply = litelib_process_response(resp); } else { qDebug() << __func__ << ": Null response from litelib_initialize_new_from_phrase"; } } catch (const std::exception &e) { qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); } qDebug() << __func__ << ": reply=" << reply; if (reply.toUpper().trimmed() != "OK") { qDebug() << "Lite server " << parent->server << " is down, getting a random one"; parent->server = Settings::getRandomServer(); qDebug() << __func__ << ": new server is " << parent->server; char *resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), seed.toStdString().c_str(), birthday, number); if (resp != nullptr) { reply = litelib_process_response(resp); } else { qDebug() << __func__ << ": Null response on retry from litelib_initialize_new_from_phrase"; } } // 4. Finally attempt to save the wallet { QString reply = ""; try { char* resp = litelib_execute("save", ""); reply = litelib_process_response(resp); } catch (const std::exception& e) { qDebug() << __func__ << ": caught an exception, ignoring: " << e.what(); } // TODO: this is duplicated code that should be refactored // into a dedicated function if (reply.isEmpty()) { qDebug() << "Lite server " << parent->server << " is down, getting a random one"; parent->server = Settings::getRandomServer(); qDebug() << __func__ << ": new server is " << parent->server; // make a new connection to the new server char* resp = litelib_initialize_new_from_phrase(parent->dangerous, parent->server.toStdString().c_str(), seed.toStdString().c_str(), birthday, number); reply = litelib_process_response(resp); // retry with the new server try { resp = litelib_execute("save", ""); reply = litelib_process_response(resp); } catch (const std::exception& e) { qDebug() << __func__ << ": caught an exception with new server, something is fucky: " << e.what(); } } qDebug() << __func__ << ": reply=" << reply; auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); if (parsed.is_discarded() || parsed.is_null() || parsed.find("result") == parsed.end()) { qDebug() << __func__ << ": Failed to save wallet, reply=" << reply; QMessageBox::warning(this, tr("Failed to save wallet"), tr("Couldn't save the wallet") + "\n" + "server=" + parent->server + "\n" + reply, QMessageBox::Ok); return false; } else { return true; } } }