mirror of
https://github.com/feather-wallet/feather.git
synced 2025-01-03 17:39:49 +00:00
wizard: add diceware support
This commit is contained in:
parent
c23869cc32
commit
6225e0e389
9 changed files with 583 additions and 12 deletions
183
src/dialog/SeedDiceDialog.cpp
Normal file
183
src/dialog/SeedDiceDialog.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include "SeedDiceDialog.h"
|
||||
#include "ui_SeedDiceDialog.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
#include <QPasswordDigestor>
|
||||
|
||||
#include "utils/Seed.h"
|
||||
|
||||
SeedDiceDialog::SeedDiceDialog(QWidget *parent)
|
||||
: WindowModalDialog(parent)
|
||||
, ui(new Ui::SeedDiceDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->frame_dice->hide();
|
||||
ui->frame_coinflip->hide();
|
||||
|
||||
connect(ui->radio_dice, &QRadioButton::toggled, [this](bool toggled){
|
||||
ui->frame_dice->setVisible(toggled);
|
||||
this->updateRollsLeft();
|
||||
ui->label_rollsLeft2->setText("Rolls left:");
|
||||
ui->label_rolls->setText("Rolls:");
|
||||
});
|
||||
|
||||
connect(ui->radio_coinflip, &QRadioButton::toggled, [this](bool toggled){
|
||||
ui->frame_coinflip->setVisible(toggled);
|
||||
this->updateRollsLeft();
|
||||
ui->label_rollsLeft2->setText("Flips left:");
|
||||
ui->label_rolls->setText("Flips:");
|
||||
});
|
||||
|
||||
connect(ui->spin_sides, &QSpinBox::valueChanged, [this](int value){
|
||||
if (!ui->radio_dice->isChecked()) {
|
||||
return;
|
||||
}
|
||||
this->updateRollsLeft();
|
||||
});
|
||||
|
||||
connect(ui->line_roll, &QLineEdit::textChanged, this, &SeedDiceDialog::validateRollEntry);
|
||||
|
||||
connect(ui->btn_next, &QPushButton::clicked, [this]{
|
||||
this->setEnableMethodSelection(false);
|
||||
|
||||
if (!this->validateRollEntry()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList rolls = ui->line_roll->text().simplified().split(" ");
|
||||
for (const auto &roll : rolls) {
|
||||
this->addRoll(roll);
|
||||
}
|
||||
|
||||
ui->line_roll->clear();
|
||||
ui->line_roll->setFocus();
|
||||
});
|
||||
|
||||
connect(ui->btn_heads, &QPushButton::clicked, [this]{
|
||||
this->setEnableMethodSelection(false);
|
||||
this->addFlip(true);
|
||||
});
|
||||
|
||||
connect(ui->btn_tails, &QPushButton::clicked, [this]{
|
||||
this->setEnableMethodSelection(false);
|
||||
this->addFlip(false);
|
||||
});
|
||||
|
||||
connect(ui->btn_reset, &QPushButton::clicked, [this]{
|
||||
m_rolls.clear();
|
||||
this->update();
|
||||
this->setEnableMethodSelection(true);
|
||||
ui->btn_createPolyseed->setEnabled(false);
|
||||
});
|
||||
|
||||
connect(ui->btn_createPolyseed, &QPushButton::clicked, [this]{
|
||||
QByteArray salt = "POLYSEED";
|
||||
QByteArray data = m_rolls.join(" ").toUtf8();
|
||||
|
||||
// We already have enough entropy assuming unbiased throws, but a few extra rounds can't hurt
|
||||
// Polyseed requests 19 bytes of random data and discards two bits (for a total of 150 bits)
|
||||
m_key = QPasswordDigestor::deriveKeyPbkdf2(QCryptographicHash::Sha256, data, salt, 2048, 19);
|
||||
|
||||
this->accept();
|
||||
});
|
||||
|
||||
connect(ui->btn_cancel, &QPushButton::clicked, [this]{
|
||||
this->reject();
|
||||
});
|
||||
|
||||
ui->radio_dice->setChecked(true);
|
||||
|
||||
this->update();
|
||||
this->adjustSize();
|
||||
}
|
||||
|
||||
void SeedDiceDialog::addFlip(bool heads) {
|
||||
m_rolls << (heads ? "H" : "T");
|
||||
this->update();
|
||||
}
|
||||
|
||||
void SeedDiceDialog::addRoll(const QString &roll) {
|
||||
if (roll.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_rolls << roll;
|
||||
this->update();
|
||||
}
|
||||
|
||||
bool SeedDiceDialog::validateRollEntry() {
|
||||
ui->line_roll->setStyleSheet("");
|
||||
|
||||
QString errStyle = "QLineEdit{border: 1px solid red;}";
|
||||
QStringList rolls = ui->line_roll->text().simplified().split(" ");
|
||||
|
||||
for (const auto &rollstr : rolls) {
|
||||
if (rollstr.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
int roll = rollstr.toInt(&ok);
|
||||
if (!ok || roll < 1 || roll > ui->spin_sides->value()) {
|
||||
ui->line_roll->setStyleSheet(errStyle);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SeedDiceDialog::update() {
|
||||
this->updateRollsLeft();
|
||||
this->updateRolls();
|
||||
|
||||
if (this->updateEntropy()) {
|
||||
ui->btn_createPolyseed->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool SeedDiceDialog::updateEntropy() {
|
||||
double entropy = entropyPerRoll() * m_rolls.length();
|
||||
ui->label_entropy->setText(QString("%1 / %2 bits").arg(QString::number(entropy, 'f', 2), QString::number(entropyNeeded)));
|
||||
|
||||
return entropy > entropyNeeded;
|
||||
}
|
||||
|
||||
void SeedDiceDialog::updateRolls() {
|
||||
ui->rolls->setPlainText(m_rolls.join(" "));
|
||||
}
|
||||
|
||||
double SeedDiceDialog::entropyPerRoll() {
|
||||
if (ui->radio_dice->isChecked()) {
|
||||
return log(ui->spin_sides->value()) / log(2);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void SeedDiceDialog::updateRollsLeft() {
|
||||
int rollsLeft = std::max((int)(ceil((entropyNeeded - (this->entropyPerRoll() * m_rolls.length())) / this->entropyPerRoll())), 0);
|
||||
ui->label_rollsLeft->setText(QString::number(rollsLeft));
|
||||
}
|
||||
|
||||
void SeedDiceDialog::setEnableMethodSelection(bool enabled) {
|
||||
ui->radio_dice->setEnabled(enabled);
|
||||
ui->radio_coinflip->setEnabled(enabled);
|
||||
ui->spin_sides->setEnabled(enabled);
|
||||
}
|
||||
|
||||
const char* SeedDiceDialog::getSecret() {
|
||||
return m_key.data();
|
||||
}
|
||||
|
||||
const QString& SeedDiceDialog::getMnemonic() {
|
||||
return m_mnemonic;
|
||||
}
|
||||
|
||||
SeedDiceDialog::~SeedDiceDialog() = default;
|
47
src/dialog/SeedDiceDialog.h
Normal file
47
src/dialog/SeedDiceDialog.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "components.h"
|
||||
|
||||
#ifndef FEATHER_SEEDDICEDIALOG_H
|
||||
#define FEATHER_SEEDDICEDIALOG_H
|
||||
|
||||
namespace Ui {
|
||||
class SeedDiceDialog;
|
||||
}
|
||||
|
||||
class SeedDiceDialog : public WindowModalDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SeedDiceDialog(QWidget *parent);
|
||||
~SeedDiceDialog() override;
|
||||
|
||||
const char* getSecret();
|
||||
|
||||
const QString& getMnemonic();
|
||||
|
||||
private:
|
||||
void addFlip(bool heads);
|
||||
void addRoll(const QString &roll);
|
||||
double entropyPerRoll();
|
||||
bool validateRollEntry();
|
||||
|
||||
void update();
|
||||
bool updateEntropy();
|
||||
void updateRolls();
|
||||
void updateRollsLeft();
|
||||
void setEnableMethodSelection(bool enabled);
|
||||
|
||||
QScopedPointer<Ui::SeedDiceDialog> ui;
|
||||
QStringList m_rolls;
|
||||
QByteArray m_key;
|
||||
int entropyNeeded = 152; // Polyseed requests 19 bytes of random data
|
||||
QString m_mnemonic;
|
||||
};
|
||||
|
||||
|
||||
#endif //FEATHER_SEEDDICEDIALOG_H
|
292
src/dialog/SeedDiceDialog.ui
Normal file
292
src/dialog/SeedDiceDialog.ui
Normal file
|
@ -0,0 +1,292 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SeedDiceDialog</class>
|
||||
<widget class="QDialog" name="SeedDiceDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>881</width>
|
||||
<height>547</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Diceware</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Select method:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio_dice">
|
||||
<property name="text">
|
||||
<string>Dice rolls</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="spin_sides">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>6</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>-sided die</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio_coinflip">
|
||||
<property name="text">
|
||||
<string>Coinflips</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Entropy: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_entropy">
|
||||
<property name="text">
|
||||
<string>0 bits</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_rollsLeft2">
|
||||
<property name="text">
|
||||
<string>Rolls left:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_rollsLeft">
|
||||
<property name="text">
|
||||
<string>0 rolls</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_rolls">
|
||||
<property name="text">
|
||||
<string>Rolls:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPlainTextEdit" name="rolls">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Minimum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_dice">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enter roll:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="line_roll">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_next">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Next roll</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>(Use a space between each roll to enter multiple rolls in one go)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_coinflip">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Add flip:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_heads">
|
||||
<property name="text">
|
||||
<string>Heads</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_tails">
|
||||
<property name="text">
|
||||
<string>Tails</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_reset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_cancel">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btn_createPolyseed">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create polyseed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <QString>
|
||||
|
||||
#define POLYSEED_RANDBYTES 19
|
||||
|
||||
namespace polyseed {
|
||||
|
||||
static std::locale locale;
|
||||
|
@ -39,6 +41,18 @@ namespace polyseed {
|
|||
return size;
|
||||
}
|
||||
|
||||
static char seed[POLYSEED_RANDBYTES]{};
|
||||
|
||||
static void randombytes(void* const buf, const size_t size) {
|
||||
assert(size <= POLYSEED_RANDBYTES);
|
||||
if (std::all_of(seed, seed + size, [](char c) { return c == '\0'; })) {
|
||||
randombytes_buf(buf, size);
|
||||
} else {
|
||||
memcpy(buf, seed, size);
|
||||
sodium_memzero(seed, POLYSEED_RANDBYTES);
|
||||
}
|
||||
}
|
||||
|
||||
struct dependency {
|
||||
dependency();
|
||||
std::vector<language> languages;
|
||||
|
@ -55,8 +69,10 @@ namespace polyseed {
|
|||
gen.locale_cache_enabled(true);
|
||||
locale = gen("");
|
||||
|
||||
sodium_memzero(seed, POLYSEED_RANDBYTES);
|
||||
|
||||
polyseed_dependency pd;
|
||||
pd.randbytes = &randombytes_buf;
|
||||
pd.randbytes = &randombytes;
|
||||
pd.pbkdf2_sha256 = &crypto_pbkdf2_sha256;
|
||||
pd.memzero = &sodium_memzero;
|
||||
pd.u8_nfc = &utf8_nfc;
|
||||
|
@ -121,6 +137,15 @@ namespace polyseed {
|
|||
}
|
||||
}
|
||||
|
||||
void data::create_from_secret(feature_type features, const char* secret) {
|
||||
check_init();
|
||||
memcpy(seed, secret, POLYSEED_RANDBYTES);
|
||||
auto status = polyseed_create(features, &m_data);
|
||||
if (status != POLYSEED_OK) {
|
||||
throw get_error(status);
|
||||
}
|
||||
}
|
||||
|
||||
void data::load(polyseed_storage storage) {
|
||||
check_init();
|
||||
auto status = polyseed_load(storage, &m_data);
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace polyseed {
|
|||
}
|
||||
|
||||
void create(feature_type features);
|
||||
void create_from_secret(feature_type features, const char* secret);
|
||||
|
||||
void load(polyseed_storage storage);
|
||||
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
#include <iomanip>
|
||||
#include "Seed.h"
|
||||
|
||||
Seed::Seed(Type type, NetworkType::Type networkType, QString language)
|
||||
: type(type), networkType(networkType), language(std::move(language))
|
||||
Seed::Seed(Type type, NetworkType::Type networkType, QString language, const char* secret)
|
||||
: type(type)
|
||||
, networkType(networkType)
|
||||
, language(std::move(language))
|
||||
{
|
||||
// We only support the creation of Polyseeds
|
||||
if (this->type != Type::POLYSEED) {
|
||||
|
@ -23,7 +25,12 @@ Seed::Seed(Type type, NetworkType::Type networkType, QString language)
|
|||
|
||||
try {
|
||||
polyseed::data seed(POLYSEED_MONERO);
|
||||
seed.create(0);
|
||||
|
||||
if (secret) {
|
||||
seed.create_from_secret(0, secret);
|
||||
} else {
|
||||
seed.create(0);
|
||||
}
|
||||
|
||||
uint8_t key[32];
|
||||
seed.keygen(&key, sizeof(key));
|
||||
|
@ -129,7 +136,6 @@ void Seed::setRestoreHeight(int height) {
|
|||
void Seed::setRestoreHeight() {
|
||||
// Ignore the embedded restore date, new wallets should sync from the current block height.
|
||||
this->restoreHeight = appData()->restoreHeights[networkType]->dateToHeight(this->time);
|
||||
int a = 0;
|
||||
}
|
||||
|
||||
Seed::Seed() = default;
|
|
@ -41,7 +41,7 @@ struct Seed {
|
|||
bool encrypted = false;
|
||||
|
||||
explicit Seed();
|
||||
explicit Seed(Type type, NetworkType::Type networkType = NetworkType::MAINNET, QString language = "English");
|
||||
explicit Seed(Type type, NetworkType::Type networkType = NetworkType::MAINNET, QString language = "English", const char* secret = nullptr);
|
||||
explicit Seed(Type type, QStringList mnemonic, NetworkType::Type networkType = NetworkType::MAINNET);
|
||||
void setRestoreHeight(int height);
|
||||
|
||||
|
|
|
@ -8,10 +8,13 @@
|
|||
#include <QMessageBox>
|
||||
#include <QCheckBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QShortcut>
|
||||
|
||||
#include "constants.h"
|
||||
#include "Seed.h"
|
||||
#include "Icons.h"
|
||||
#include "dialog/SeedDiceDialog.h"
|
||||
|
||||
PageWalletSeed::PageWalletSeed(WizardFields *fields, QWidget *parent)
|
||||
: QWizardPage(parent)
|
||||
|
@ -29,6 +32,15 @@ PageWalletSeed::PageWalletSeed(WizardFields *fields, QWidget *parent)
|
|||
"Please contact the developers immediately.");
|
||||
ui->frame_invalidSeed->hide();
|
||||
|
||||
QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+K"), this);
|
||||
QObject::connect(shortcut, &QShortcut::activated, [&](){
|
||||
SeedDiceDialog dialog{this};
|
||||
int r = dialog.exec();
|
||||
if (r == QDialog::Accepted) {
|
||||
this->generateSeed(dialog.getSecret());
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->btnRoulette, &QPushButton::clicked, [=]{
|
||||
this->seedRoulette(0);
|
||||
});
|
||||
|
@ -55,10 +67,10 @@ void PageWalletSeed::seedRoulette(int count) {
|
|||
});
|
||||
}
|
||||
|
||||
void PageWalletSeed::generateSeed() {
|
||||
void PageWalletSeed::generateSeed(const char* secret) {
|
||||
QString mnemonic;
|
||||
|
||||
m_seed = Seed(Seed::Type::POLYSEED, constants::networkType);
|
||||
m_seed = Seed(Seed::Type::POLYSEED, constants::networkType, "English", secret);
|
||||
mnemonic = m_seed.mnemonic.join(" ");
|
||||
m_restoreHeight = m_seed.restoreHeight;
|
||||
|
||||
|
@ -99,6 +111,7 @@ void PageWalletSeed::onOptionsClicked() {
|
|||
QCheckBox checkbox("Extend this seed with a passphrase");
|
||||
checkbox.setChecked(m_fields->showSetSeedPassphrasePage);
|
||||
layout.addWidget(&checkbox);
|
||||
|
||||
QDialogButtonBox buttons(QDialogButtonBox::Ok);
|
||||
layout.addWidget(&buttons);
|
||||
dialog.setLayout(&layout);
|
||||
|
@ -117,12 +130,16 @@ int PageWalletSeed::nextId() const {
|
|||
}
|
||||
|
||||
bool PageWalletSeed::validatePage() {
|
||||
if (m_seed.mnemonic.isEmpty()) return false;
|
||||
if (!m_restoreHeight) return false;
|
||||
if (m_seed.mnemonic.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (!m_restoreHeight) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QMessageBox seedWarning(this);
|
||||
seedWarning.setWindowTitle("Warning!");
|
||||
seedWarning.setInformativeText("• Never disclose your seed\n"
|
||||
seedWarning.setText("• Never disclose your seed\n"
|
||||
"• Never type it on a website\n"
|
||||
"• Store it safely (offline)\n"
|
||||
"• Do not lose your seed!");
|
||||
|
|
|
@ -30,7 +30,7 @@ public slots:
|
|||
|
||||
private:
|
||||
void seedRoulette(int count);
|
||||
void generateSeed();
|
||||
void generateSeed(const char* secret = nullptr);
|
||||
void onOptionsClicked();
|
||||
|
||||
signals:
|
||||
|
|
Loading…
Reference in a new issue