mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Correct issues with TOTP Setup
* Fix #3142 - Warn user when entering invalid TOTP secret key. * Fix #773 - The TOTP dialog now listens for the copy shortcut without having to press the Copy button. * Add ability to choose hash algorithm from the TOTP setup dialog * Add upgrade to "otp" attribute when custom attributes are chosen to prevent data loss Ran make format
This commit is contained in:
parent
71085838db
commit
99a2d66086
@ -442,16 +442,16 @@ QString Entry::totp() const
|
|||||||
void Entry::setTotp(QSharedPointer<Totp::Settings> settings)
|
void Entry::setTotp(QSharedPointer<Totp::Settings> settings)
|
||||||
{
|
{
|
||||||
beginUpdate();
|
beginUpdate();
|
||||||
|
m_attributes->remove(Totp::ATTRIBUTE_OTP);
|
||||||
|
m_attributes->remove(Totp::ATTRIBUTE_SEED);
|
||||||
|
m_attributes->remove(Totp::ATTRIBUTE_SETTINGS);
|
||||||
|
|
||||||
if (settings->key.isEmpty()) {
|
if (settings->key.isEmpty()) {
|
||||||
m_data.totpSettings.reset();
|
m_data.totpSettings.reset();
|
||||||
m_attributes->remove(Totp::ATTRIBUTE_OTP);
|
|
||||||
m_attributes->remove(Totp::ATTRIBUTE_SEED);
|
|
||||||
m_attributes->remove(Totp::ATTRIBUTE_SETTINGS);
|
|
||||||
} else {
|
} else {
|
||||||
m_data.totpSettings = std::move(settings);
|
m_data.totpSettings = std::move(settings);
|
||||||
|
|
||||||
auto text = Totp::writeSettings(m_data.totpSettings, title(), username());
|
auto text = Totp::writeSettings(m_data.totpSettings, title(), username());
|
||||||
if (m_attributes->hasKey(Totp::ATTRIBUTE_OTP)) {
|
if (m_data.totpSettings->format != Totp::StorageFormat::LEGACY) {
|
||||||
m_attributes->set(Totp::ATTRIBUTE_OTP, text, true);
|
m_attributes->set(Totp::ATTRIBUTE_OTP, text, true);
|
||||||
} else {
|
} else {
|
||||||
m_attributes->set(Totp::ATTRIBUTE_SEED, m_data.totpSettings->key, true);
|
m_attributes->set(Totp::ATTRIBUTE_SEED, m_data.totpSettings->key, true);
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
#include "core/Clock.h"
|
#include "core/Clock.h"
|
||||||
#include "core/Config.h"
|
#include "core/Config.h"
|
||||||
#include "gui/Clipboard.h"
|
#include "gui/Clipboard.h"
|
||||||
|
#include "gui/MainWindow.h"
|
||||||
|
|
||||||
|
#include <QShortcut>
|
||||||
|
|
||||||
TotpDialog::TotpDialog(QWidget* parent, Entry* entry)
|
TotpDialog::TotpDialog(QWidget* parent, Entry* entry)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
@ -39,6 +42,7 @@ TotpDialog::TotpDialog(QWidget* parent, Entry* entry)
|
|||||||
resetCounter();
|
resetCounter();
|
||||||
updateProgressBar();
|
updateProgressBar();
|
||||||
|
|
||||||
|
connect(parent, SIGNAL(lockedDatabase()), SLOT(close()));
|
||||||
connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateProgressBar()));
|
connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateProgressBar()));
|
||||||
connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateSeconds()));
|
connect(&m_totpUpdateTimer, SIGNAL(timeout()), this, SLOT(updateSeconds()));
|
||||||
m_totpUpdateTimer.start(m_step * 10);
|
m_totpUpdateTimer.start(m_step * 10);
|
||||||
@ -46,6 +50,8 @@ TotpDialog::TotpDialog(QWidget* parent, Entry* entry)
|
|||||||
|
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
|
new QShortcut(QKeySequence(QKeySequence::Copy), this, SLOT(copyToClipboard()));
|
||||||
|
|
||||||
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Copy"));
|
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Copy"));
|
||||||
|
|
||||||
connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(close()));
|
connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(close()));
|
||||||
@ -61,9 +67,9 @@ void TotpDialog::copyToClipboard()
|
|||||||
clipboard()->setText(m_entry->totp());
|
clipboard()->setText(m_entry->totp());
|
||||||
if (config()->get("HideWindowOnCopy").toBool()) {
|
if (config()->get("HideWindowOnCopy").toBool()) {
|
||||||
if (config()->get("MinimizeOnCopy").toBool()) {
|
if (config()->get("MinimizeOnCopy").toBool()) {
|
||||||
qobject_cast<DatabaseWidget*>(parent())->window()->showMinimized();
|
getMainWindow()->showMinimized();
|
||||||
} else if (config()->get("DropToBackgroundOnCopy").toBool()) {
|
} else if (config()->get("DropToBackgroundOnCopy").toBool()) {
|
||||||
qobject_cast<DatabaseWidget*>(parent())->window()->lower();
|
getMainWindow()->lower();
|
||||||
window()->lower();
|
window()->lower();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "TotpExportSettingsDialog.h"
|
#include "TotpExportSettingsDialog.h"
|
||||||
|
|
||||||
#include "core/Config.h"
|
#include "core/Config.h"
|
||||||
#include "core/Entry.h"
|
#include "core/Entry.h"
|
||||||
#include "gui/Clipboard.h"
|
#include "gui/Clipboard.h"
|
||||||
#include "gui/DatabaseWidget.h"
|
#include "gui/DatabaseWidget.h"
|
||||||
|
#include "gui/MainWindow.h"
|
||||||
#include "gui/SquareSvgWidget.h"
|
#include "gui/SquareSvgWidget.h"
|
||||||
#include "qrcode/QrCode.h"
|
#include "qrcode/QrCode.h"
|
||||||
#include "totp/totp.h"
|
#include "totp/totp.h"
|
||||||
@ -29,6 +31,7 @@
|
|||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QShortcut>
|
||||||
#include <QSizePolicy>
|
#include <QSizePolicy>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
@ -55,10 +58,13 @@ TotpExportSettingsDialog::TotpExportSettingsDialog(DatabaseWidget* parent, Entry
|
|||||||
|
|
||||||
connect(m_buttonBox, SIGNAL(rejected()), SLOT(close()));
|
connect(m_buttonBox, SIGNAL(rejected()), SLOT(close()));
|
||||||
connect(m_buttonBox, SIGNAL(accepted()), SLOT(copyToClipboard()));
|
connect(m_buttonBox, SIGNAL(accepted()), SLOT(copyToClipboard()));
|
||||||
connect(m_timer, SIGNAL(timeout()), this, SLOT(autoClose()));
|
connect(m_timer, SIGNAL(timeout()), SLOT(autoClose()));
|
||||||
connect(parent, SIGNAL(lockedDatabase()), this, SLOT(close()));
|
connect(parent, SIGNAL(lockedDatabase()), SLOT(close()));
|
||||||
|
|
||||||
|
new QShortcut(QKeySequence(QKeySequence::Copy), this, SLOT(copyToClipboard()));
|
||||||
|
|
||||||
m_buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Copy"));
|
m_buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Copy"));
|
||||||
|
m_buttonBox->setFocus();
|
||||||
m_countDown->setAlignment(Qt::AlignCenter);
|
m_countDown->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
m_secTillClose = 45;
|
m_secTillClose = 45;
|
||||||
@ -92,8 +98,6 @@ TotpExportSettingsDialog::TotpExportSettingsDialog(DatabaseWidget* parent, Entry
|
|||||||
errorBox->exec();
|
errorBox->exec();
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TotpExportSettingsDialog::copyToClipboard()
|
void TotpExportSettingsDialog::copyToClipboard()
|
||||||
@ -101,9 +105,9 @@ void TotpExportSettingsDialog::copyToClipboard()
|
|||||||
clipboard()->setText(m_totpUri);
|
clipboard()->setText(m_totpUri);
|
||||||
if (config()->get("HideWindowOnCopy").toBool()) {
|
if (config()->get("HideWindowOnCopy").toBool()) {
|
||||||
if (config()->get("MinimizeOnCopy").toBool()) {
|
if (config()->get("MinimizeOnCopy").toBool()) {
|
||||||
static_cast<DatabaseWidget*>(parent())->window()->showMinimized();
|
getMainWindow()->showMinimized();
|
||||||
} else if (config()->get("DropToBackgroundOnCopy").toBool()) {
|
} else if (config()->get("DropToBackgroundOnCopy").toBool()) {
|
||||||
static_cast<DatabaseWidget*>(parent())->window()->lower();
|
getMainWindow()->lower();
|
||||||
window()->lower();
|
window()->lower();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#include "TotpSetupDialog.h"
|
#include "TotpSetupDialog.h"
|
||||||
#include "ui_TotpSetupDialog.h"
|
#include "ui_TotpSetupDialog.h"
|
||||||
|
|
||||||
|
#include "core/Base32.h"
|
||||||
|
#include "gui/MessageBox.h"
|
||||||
#include "totp/totp.h"
|
#include "totp/totp.h"
|
||||||
|
|
||||||
TotpSetupDialog::TotpSetupDialog(QWidget* parent, Entry* entry)
|
TotpSetupDialog::TotpSetupDialog(QWidget* parent, Entry* entry)
|
||||||
@ -43,38 +45,73 @@ TotpSetupDialog::~TotpSetupDialog()
|
|||||||
|
|
||||||
void TotpSetupDialog::saveSettings()
|
void TotpSetupDialog::saveSettings()
|
||||||
{
|
{
|
||||||
|
// Secret key sanity check
|
||||||
|
auto key = m_ui->seedEdit->text().toLatin1();
|
||||||
|
auto sanitizedKey = Base32::sanitizeInput(key);
|
||||||
|
if (sanitizedKey != key) {
|
||||||
|
MessageBox::information(this,
|
||||||
|
tr("Invalid TOTP Secret"),
|
||||||
|
tr("You have entered an invalid secret key. The key must be in Base32 format.\n"
|
||||||
|
"Example: JBSWY3DPEHPK3PXP"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString encShortName;
|
QString encShortName;
|
||||||
uint digits = Totp::DEFAULT_DIGITS;
|
uint digits = Totp::DEFAULT_DIGITS;
|
||||||
uint step = Totp::DEFAULT_STEP;
|
uint step = Totp::DEFAULT_STEP;
|
||||||
|
Totp::Algorithm algorithm = Totp::DEFAULT_ALGORITHM;
|
||||||
|
Totp::StorageFormat format = Totp::DEFAULT_FORMAT;
|
||||||
|
|
||||||
if (m_ui->radioSteam->isChecked()) {
|
if (m_ui->radioSteam->isChecked()) {
|
||||||
digits = Totp::STEAM_DIGITS;
|
digits = Totp::STEAM_DIGITS;
|
||||||
encShortName = Totp::STEAM_SHORTNAME;
|
encShortName = Totp::STEAM_SHORTNAME;
|
||||||
} else if (m_ui->radioCustom->isChecked()) {
|
} else if (m_ui->radioCustom->isChecked()) {
|
||||||
|
algorithm = static_cast<Totp::Algorithm>(m_ui->algorithmComboBox->currentData().toInt());
|
||||||
step = m_ui->stepSpinBox->value();
|
step = m_ui->stepSpinBox->value();
|
||||||
if (m_ui->radio8Digits->isChecked()) {
|
digits = m_ui->digitsSpinBox->value();
|
||||||
digits = 8;
|
}
|
||||||
} else if (m_ui->radio7Digits->isChecked()) {
|
|
||||||
digits = 7;
|
auto settings = m_entry->totpSettings();
|
||||||
|
if (settings) {
|
||||||
|
if (key.isEmpty()) {
|
||||||
|
auto answer = MessageBox::question(this,
|
||||||
|
tr("Confirm Remove TOTP Settings"),
|
||||||
|
tr("Are you sure you want to delete TOTP settings for this entry?"),
|
||||||
|
MessageBox::Delete | MessageBox::Cancel);
|
||||||
|
if (answer != MessageBox::Delete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format = settings->format;
|
||||||
|
if (format == Totp::StorageFormat::LEGACY && m_ui->radioCustom->isChecked()) {
|
||||||
|
// Implicitly upgrade to the OTPURL format to allow for custom settings
|
||||||
|
format = Totp::DEFAULT_FORMAT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto settings = Totp::createSettings(
|
m_entry->setTotp(Totp::createSettings(key, digits, step, format, encShortName, algorithm));
|
||||||
m_ui->seedEdit->text(), digits, step, encShortName, Totp::HashType::Sha1, m_entry->totpSettings());
|
|
||||||
m_entry->setTotp(settings);
|
|
||||||
emit totpUpdated();
|
emit totpUpdated();
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TotpSetupDialog::toggleCustom(bool status)
|
void TotpSetupDialog::toggleCustom(bool status)
|
||||||
{
|
{
|
||||||
m_ui->customGroup->setEnabled(status);
|
m_ui->customSettingsGroup->setEnabled(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TotpSetupDialog::init()
|
void TotpSetupDialog::init()
|
||||||
{
|
{
|
||||||
|
// Add algorithm choices
|
||||||
|
auto algorithms = Totp::supportedAlgorithms();
|
||||||
|
for (const auto& item : algorithms) {
|
||||||
|
m_ui->algorithmComboBox->addItem(item.first, item.second);
|
||||||
|
}
|
||||||
|
m_ui->algorithmComboBox->setCurrentIndex(0);
|
||||||
|
|
||||||
|
// Read entry totp settings
|
||||||
auto settings = m_entry->totpSettings();
|
auto settings = m_entry->totpSettings();
|
||||||
if (!settings.isNull()) {
|
if (settings) {
|
||||||
m_ui->seedEdit->setText(settings->key);
|
m_ui->seedEdit->setText(settings->key);
|
||||||
m_ui->stepSpinBox->setValue(settings->step);
|
m_ui->stepSpinBox->setValue(settings->step);
|
||||||
|
|
||||||
@ -82,12 +119,10 @@ void TotpSetupDialog::init()
|
|||||||
m_ui->radioSteam->setChecked(true);
|
m_ui->radioSteam->setChecked(true);
|
||||||
} else if (settings->custom) {
|
} else if (settings->custom) {
|
||||||
m_ui->radioCustom->setChecked(true);
|
m_ui->radioCustom->setChecked(true);
|
||||||
if (settings->digits == 8) {
|
m_ui->digitsSpinBox->setValue(settings->digits);
|
||||||
m_ui->radio8Digits->setChecked(true);
|
int index = m_ui->algorithmComboBox->findData(settings->algorithm);
|
||||||
} else if (settings->digits == 7) {
|
if (index != -1) {
|
||||||
m_ui->radio7Digits->setChecked(true);
|
m_ui->algorithmComboBox->setCurrentIndex(index);
|
||||||
} else {
|
|
||||||
m_ui->radio6Digits->setChecked(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,14 +25,26 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Key:</string>
|
<string>Secret Key:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLineEdit" name="seedEdit">
|
<widget class="QLineEdit" name="seedEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Secret key in Base32 format</string>
|
<string>Secret key must be in Base32 format</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="accessibleName">
|
<property name="accessibleName">
|
||||||
<string>Secret key field</string>
|
<string>Secret key field</string>
|
||||||
@ -93,13 +105,10 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="customGroup">
|
<widget class="QGroupBox" name="customSettingsGroup">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true"/>
|
|
||||||
</property>
|
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Custom Settings</string>
|
<string>Custom Settings</string>
|
||||||
</property>
|
</property>
|
||||||
@ -113,20 +122,36 @@
|
|||||||
<property name="labelAlignment">
|
<property name="labelAlignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set>
|
<set>Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="horizontalSpacing">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="verticalSpacing">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>5</number>
|
<number>20</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="rightMargin">
|
<property name="rightMargin">
|
||||||
<number>5</number>
|
<number>20</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="algorithmLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Algorithm:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="algorithmComboBox"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="stepLabel">
|
<widget class="QLabel" name="stepLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Time step:</string>
|
<string>Time step:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QSpinBox" name="stepSpinBox">
|
<widget class="QSpinBox" name="stepSpinBox">
|
||||||
<property name="accessibleName">
|
<property name="accessibleName">
|
||||||
<string>Time step field</string>
|
<string>Time step field</string>
|
||||||
@ -145,34 +170,26 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="digitsLabel">
|
<widget class="QLabel" name="digitsLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Code size:</string>
|
<string>Code size:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QRadioButton" name="radio6Digits">
|
|
||||||
<property name="text">
|
|
||||||
<string>6 digits</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QRadioButton" name="radio7Digits">
|
<widget class="QSpinBox" name="digitsSpinBox">
|
||||||
<property name="text">
|
<property name="suffix">
|
||||||
<string>7 digits</string>
|
<string> digits</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="minimum">
|
||||||
</item>
|
<number>6</number>
|
||||||
<item row="4" column="1">
|
</property>
|
||||||
<widget class="QRadioButton" name="radio8Digits">
|
<property name="maximum">
|
||||||
<property name="text">
|
<number>10</number>
|
||||||
<string>8 digits</string>
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -190,6 +207,9 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
<zorder>customSettingsGroup</zorder>
|
||||||
|
<zorder>buttonBox</zorder>
|
||||||
|
<zorder>groupBox</zorder>
|
||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>seedEdit</tabstop>
|
<tabstop>seedEdit</tabstop>
|
||||||
@ -197,9 +217,6 @@
|
|||||||
<tabstop>radioSteam</tabstop>
|
<tabstop>radioSteam</tabstop>
|
||||||
<tabstop>radioCustom</tabstop>
|
<tabstop>radioCustom</tabstop>
|
||||||
<tabstop>stepSpinBox</tabstop>
|
<tabstop>stepSpinBox</tabstop>
|
||||||
<tabstop>radio6Digits</tabstop>
|
|
||||||
<tabstop>radio7Digits</tabstop>
|
|
||||||
<tabstop>radio8Digits</tabstop>
|
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
@ -962,8 +962,9 @@ void EditEntryWidget::setForms(Entry* entry, bool restore)
|
|||||||
|
|
||||||
#ifdef WITH_XC_BROWSER
|
#ifdef WITH_XC_BROWSER
|
||||||
if (m_customData->contains(BrowserService::OPTION_SKIP_AUTO_SUBMIT)) {
|
if (m_customData->contains(BrowserService::OPTION_SKIP_AUTO_SUBMIT)) {
|
||||||
m_browserUi->skipAutoSubmitCheckbox->setChecked(m_customData->value(BrowserService::OPTION_SKIP_AUTO_SUBMIT)
|
// clang-format off
|
||||||
== "true");
|
m_browserUi->skipAutoSubmitCheckbox->setChecked(m_customData->value(BrowserService::OPTION_SKIP_AUTO_SUBMIT) == "true");
|
||||||
|
// clang-format on
|
||||||
} else {
|
} else {
|
||||||
m_browserUi->skipAutoSubmitCheckbox->setChecked(false);
|
m_browserUi->skipAutoSubmitCheckbox->setChecked(false);
|
||||||
}
|
}
|
||||||
|
@ -23,35 +23,34 @@
|
|||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QMessageAuthenticationCode>
|
#include <QMessageAuthenticationCode>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QRegularExpressionMatch>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QtEndian>
|
#include <QtEndian>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
static QList<Totp::Encoder> encoders{
|
static QList<Totp::Encoder> totpEncoders{
|
||||||
{"", "", "0123456789", Totp::DEFAULT_DIGITS, Totp::DEFAULT_STEP, false},
|
{"", "", "0123456789", Totp::DEFAULT_DIGITS, Totp::DEFAULT_STEP, false},
|
||||||
{"steam", Totp::STEAM_SHORTNAME, "23456789BCDFGHJKMNPQRTVWXY", Totp::STEAM_DIGITS, Totp::DEFAULT_STEP, true},
|
{"steam", Totp::STEAM_SHORTNAME, "23456789BCDFGHJKMNPQRTVWXY", Totp::STEAM_DIGITS, Totp::DEFAULT_STEP, true},
|
||||||
};
|
};
|
||||||
|
|
||||||
static Totp::HashType getHashTypeByName(const QString& name)
|
static Totp::Algorithm getHashTypeByName(const QString& name)
|
||||||
{
|
{
|
||||||
if (name.compare(QString("SHA512"), Qt::CaseInsensitive) == 0) {
|
if (name.compare(QString("SHA512"), Qt::CaseInsensitive) == 0) {
|
||||||
return Totp::HashType::Sha512;
|
return Totp::Algorithm::Sha512;
|
||||||
}
|
}
|
||||||
if (name.compare(QString("SHA256"), Qt::CaseInsensitive) == 0) {
|
if (name.compare(QString("SHA256"), Qt::CaseInsensitive) == 0) {
|
||||||
return Totp::HashType::Sha256;
|
return Totp::Algorithm::Sha256;
|
||||||
}
|
}
|
||||||
return Totp::HashType::Sha1;
|
return Totp::Algorithm::Sha1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString getNameForHashType(const Totp::HashType hashType)
|
static QString getNameForHashType(const Totp::Algorithm hashType)
|
||||||
{
|
{
|
||||||
switch (hashType) {
|
switch (hashType) {
|
||||||
case Totp::HashType::Sha512:
|
case Totp::Algorithm::Sha512:
|
||||||
return QString("SHA512");
|
return QString("SHA512");
|
||||||
case Totp::HashType::Sha256:
|
case Totp::Algorithm::Sha256:
|
||||||
return QString("SHA256");
|
return QString("SHA256");
|
||||||
default:
|
default:
|
||||||
return QString("SHA1");
|
return QString("SHA1");
|
||||||
@ -67,24 +66,26 @@ QSharedPointer<Totp::Settings> Totp::parseSettings(const QString& rawSettings, c
|
|||||||
if (url.isValid() && url.scheme() == "otpauth") {
|
if (url.isValid() && url.scheme() == "otpauth") {
|
||||||
// Default OTP url format
|
// Default OTP url format
|
||||||
QUrlQuery query(url);
|
QUrlQuery query(url);
|
||||||
settings->otpUrl = true;
|
settings->format = StorageFormat::OTPURL;
|
||||||
settings->key = query.queryItemValue("secret");
|
settings->key = query.queryItemValue("secret");
|
||||||
settings->digits = query.queryItemValue("digits").toUInt();
|
if (query.hasQueryItem("digits")) {
|
||||||
settings->step = query.queryItemValue("period").toUInt();
|
settings->digits = query.queryItemValue("digits").toUInt();
|
||||||
|
}
|
||||||
|
if (query.hasQueryItem("period")) {
|
||||||
|
settings->step = query.queryItemValue("period").toUInt();
|
||||||
|
}
|
||||||
if (query.hasQueryItem("encoder")) {
|
if (query.hasQueryItem("encoder")) {
|
||||||
settings->encoder = getEncoderByName(query.queryItemValue("encoder"));
|
settings->encoder = getEncoderByName(query.queryItemValue("encoder"));
|
||||||
}
|
}
|
||||||
if (query.hasQueryItem("algorithm")) {
|
if (query.hasQueryItem("algorithm")) {
|
||||||
settings->hashType = getHashTypeByName(query.queryItemValue("algorithm"));
|
settings->algorithm = getHashTypeByName(query.queryItemValue("algorithm"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QUrlQuery query(rawSettings);
|
QUrlQuery query(rawSettings);
|
||||||
if (query.hasQueryItem("key")) {
|
if (query.hasQueryItem("key")) {
|
||||||
// Compatibility with "KeeOtp" plugin
|
// Compatibility with "KeeOtp" plugin
|
||||||
settings->keeOtp = true;
|
settings->format = StorageFormat::KEEOTP;
|
||||||
settings->key = query.queryItemValue("key");
|
settings->key = query.queryItemValue("key");
|
||||||
settings->digits = DEFAULT_DIGITS;
|
|
||||||
settings->step = DEFAULT_STEP;
|
|
||||||
if (query.hasQueryItem("size")) {
|
if (query.hasQueryItem("size")) {
|
||||||
settings->digits = query.queryItemValue("size").toUInt();
|
settings->digits = query.queryItemValue("size").toUInt();
|
||||||
}
|
}
|
||||||
@ -92,10 +93,11 @@ QSharedPointer<Totp::Settings> Totp::parseSettings(const QString& rawSettings, c
|
|||||||
settings->step = query.queryItemValue("step").toUInt();
|
settings->step = query.queryItemValue("step").toUInt();
|
||||||
}
|
}
|
||||||
if (query.hasQueryItem("otpHashMode")) {
|
if (query.hasQueryItem("otpHashMode")) {
|
||||||
settings->hashType = getHashTypeByName(query.queryItemValue("otpHashMode"));
|
settings->algorithm = getHashTypeByName(query.queryItemValue("otpHashMode"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Parse semi-colon separated values ([step];[digits|S])
|
// Parse semi-colon separated values ([step];[digits|S])
|
||||||
|
settings->format = StorageFormat::LEGACY;
|
||||||
auto vars = rawSettings.split(";");
|
auto vars = rawSettings.split(";");
|
||||||
if (vars.size() >= 2) {
|
if (vars.size() >= 2) {
|
||||||
if (vars[1] == STEAM_SHORTNAME) {
|
if (vars[1] == STEAM_SHORTNAME) {
|
||||||
@ -116,7 +118,8 @@ QSharedPointer<Totp::Settings> Totp::parseSettings(const QString& rawSettings, c
|
|||||||
|
|
||||||
// Detect custom settings, used by setup GUI
|
// Detect custom settings, used by setup GUI
|
||||||
if (settings->encoder.shortName.isEmpty()
|
if (settings->encoder.shortName.isEmpty()
|
||||||
&& (settings->digits != DEFAULT_DIGITS || settings->step != DEFAULT_STEP)) {
|
&& (settings->digits != DEFAULT_DIGITS || settings->step != DEFAULT_STEP
|
||||||
|
|| settings->algorithm != DEFAULT_ALGORITHM)) {
|
||||||
settings->custom = true;
|
settings->custom = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,23 +129,13 @@ QSharedPointer<Totp::Settings> Totp::parseSettings(const QString& rawSettings, c
|
|||||||
QSharedPointer<Totp::Settings> Totp::createSettings(const QString& key,
|
QSharedPointer<Totp::Settings> Totp::createSettings(const QString& key,
|
||||||
const uint digits,
|
const uint digits,
|
||||||
const uint step,
|
const uint step,
|
||||||
|
const Totp::StorageFormat format,
|
||||||
const QString& encoderShortName,
|
const QString& encoderShortName,
|
||||||
const Totp::HashType hashType,
|
const Totp::Algorithm algorithm)
|
||||||
QSharedPointer<Totp::Settings> prevSettings)
|
|
||||||
{
|
{
|
||||||
bool isCustom = digits != DEFAULT_DIGITS || step != DEFAULT_STEP;
|
bool isCustom = digits != DEFAULT_DIGITS || step != DEFAULT_STEP || algorithm != DEFAULT_ALGORITHM;
|
||||||
if (prevSettings) {
|
return QSharedPointer<Totp::Settings>(
|
||||||
prevSettings->key = key;
|
new Totp::Settings{format, getEncoderByShortName(encoderShortName), algorithm, key, isCustom, digits, step});
|
||||||
prevSettings->hashType = hashType;
|
|
||||||
prevSettings->digits = digits;
|
|
||||||
prevSettings->step = step;
|
|
||||||
prevSettings->encoder = Totp::getEncoderByShortName(encoderShortName);
|
|
||||||
prevSettings->custom = isCustom;
|
|
||||||
return prevSettings;
|
|
||||||
} else {
|
|
||||||
return QSharedPointer<Totp::Settings>(new Totp::Settings{
|
|
||||||
getEncoderByShortName(encoderShortName), hashType, key, false, false, isCustom, digits, step});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Totp::writeSettings(const QSharedPointer<Totp::Settings>& settings,
|
QString Totp::writeSettings(const QSharedPointer<Totp::Settings>& settings,
|
||||||
@ -155,7 +148,7 @@ QString Totp::writeSettings(const QSharedPointer<Totp::Settings>& settings,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OTP Url output
|
// OTP Url output
|
||||||
if (settings->otpUrl || forceOtp) {
|
if (settings->format == StorageFormat::OTPURL || forceOtp) {
|
||||||
auto urlstring = QString("otpauth://totp/%1:%2?secret=%3&period=%4&digits=%5&issuer=%1")
|
auto urlstring = QString("otpauth://totp/%1:%2?secret=%3&period=%4&digits=%5&issuer=%1")
|
||||||
.arg(title.isEmpty() ? "KeePassXC" : QString(QUrl::toPercentEncoding(title)),
|
.arg(title.isEmpty() ? "KeePassXC" : QString(QUrl::toPercentEncoding(title)),
|
||||||
username.isEmpty() ? "none" : QString(QUrl::toPercentEncoding(username)),
|
username.isEmpty() ? "none" : QString(QUrl::toPercentEncoding(username)),
|
||||||
@ -166,18 +159,18 @@ QString Totp::writeSettings(const QSharedPointer<Totp::Settings>& settings,
|
|||||||
if (!settings->encoder.name.isEmpty()) {
|
if (!settings->encoder.name.isEmpty()) {
|
||||||
urlstring.append("&encoder=").append(settings->encoder.name);
|
urlstring.append("&encoder=").append(settings->encoder.name);
|
||||||
}
|
}
|
||||||
if (settings->hashType != Totp::DEFAULT_HASHTYPE) {
|
if (settings->algorithm != Totp::DEFAULT_ALGORITHM) {
|
||||||
urlstring.append("&algorithm=").append(getNameForHashType(settings->hashType));
|
urlstring.append("&algorithm=").append(getNameForHashType(settings->algorithm));
|
||||||
}
|
}
|
||||||
return urlstring;
|
return urlstring;
|
||||||
} else if (settings->keeOtp) {
|
} else if (settings->format == StorageFormat::KEEOTP) {
|
||||||
// KeeOtp output
|
// KeeOtp output
|
||||||
auto keyString = QString("key=%1&size=%2&step=%3")
|
auto keyString = QString("key=%1&size=%2&step=%3")
|
||||||
.arg(QString(Base32::sanitizeInput(settings->key.toLatin1())))
|
.arg(QString(Base32::sanitizeInput(settings->key.toLatin1())))
|
||||||
.arg(settings->digits)
|
.arg(settings->digits)
|
||||||
.arg(settings->step);
|
.arg(settings->step);
|
||||||
if (settings->hashType != Totp::DEFAULT_HASHTYPE) {
|
if (settings->algorithm != Totp::DEFAULT_ALGORITHM) {
|
||||||
keyString.append("&otpHashMode=").append(getNameForHashType(settings->hashType));
|
keyString.append("&otpHashMode=").append(getNameForHashType(settings->algorithm));
|
||||||
}
|
}
|
||||||
return keyString;
|
return keyString;
|
||||||
} else if (!settings->encoder.shortName.isEmpty()) {
|
} else if (!settings->encoder.shortName.isEmpty()) {
|
||||||
@ -213,11 +206,11 @@ QString Totp::generateTotp(const QSharedPointer<Totp::Settings>& settings, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
QCryptographicHash::Algorithm cryptoHash;
|
QCryptographicHash::Algorithm cryptoHash;
|
||||||
switch (settings->hashType) {
|
switch (settings->algorithm) {
|
||||||
case Totp::HashType::Sha512:
|
case Totp::Algorithm::Sha512:
|
||||||
cryptoHash = QCryptographicHash::Sha512;
|
cryptoHash = QCryptographicHash::Sha512;
|
||||||
break;
|
break;
|
||||||
case Totp::HashType::Sha256:
|
case Totp::Algorithm::Sha256:
|
||||||
cryptoHash = QCryptographicHash::Sha256;
|
cryptoHash = QCryptographicHash::Sha256;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -256,11 +249,29 @@ QString Totp::generateTotp(const QSharedPointer<Totp::Settings>& settings, const
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QPair<QString, QString>> Totp::supportedEncoders()
|
||||||
|
{
|
||||||
|
QList<QPair<QString, QString>> encoders;
|
||||||
|
for (auto& encoder : totpEncoders) {
|
||||||
|
encoders << QPair<QString, QString>(encoder.name, encoder.shortName);
|
||||||
|
}
|
||||||
|
return encoders;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QPair<QString, Totp::Algorithm>> Totp::supportedAlgorithms()
|
||||||
|
{
|
||||||
|
QList<QPair<QString, Algorithm>> algorithms;
|
||||||
|
algorithms << QPair<QString, Algorithm>(QStringLiteral("SHA-1"), Algorithm::Sha1);
|
||||||
|
algorithms << QPair<QString, Algorithm>(QStringLiteral("SHA-256"), Algorithm::Sha256);
|
||||||
|
algorithms << QPair<QString, Algorithm>(QStringLiteral("SHA-512"), Algorithm::Sha512);
|
||||||
|
return algorithms;
|
||||||
|
}
|
||||||
|
|
||||||
Totp::Encoder& Totp::defaultEncoder()
|
Totp::Encoder& Totp::defaultEncoder()
|
||||||
{
|
{
|
||||||
// The first encoder is always the default
|
// The first encoder is always the default
|
||||||
Q_ASSERT(!encoders.empty());
|
Q_ASSERT(!totpEncoders.empty());
|
||||||
return encoders[0];
|
return totpEncoders[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Totp::Encoder& Totp::steamEncoder()
|
Totp::Encoder& Totp::steamEncoder()
|
||||||
@ -270,7 +281,7 @@ Totp::Encoder& Totp::steamEncoder()
|
|||||||
|
|
||||||
Totp::Encoder& Totp::getEncoderByShortName(const QString& shortName)
|
Totp::Encoder& Totp::getEncoderByShortName(const QString& shortName)
|
||||||
{
|
{
|
||||||
for (auto& encoder : encoders) {
|
for (auto& encoder : totpEncoders) {
|
||||||
if (encoder.shortName == shortName) {
|
if (encoder.shortName == shortName) {
|
||||||
return encoder;
|
return encoder;
|
||||||
}
|
}
|
||||||
@ -280,7 +291,7 @@ Totp::Encoder& Totp::getEncoderByShortName(const QString& shortName)
|
|||||||
|
|
||||||
Totp::Encoder& Totp::getEncoderByName(const QString& name)
|
Totp::Encoder& Totp::getEncoderByName(const QString& name)
|
||||||
{
|
{
|
||||||
for (auto& encoder : encoders) {
|
for (auto& encoder : totpEncoders) {
|
||||||
if (encoder.name == name) {
|
if (encoder.name == name) {
|
||||||
return encoder;
|
return encoder;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ class QUrl;
|
|||||||
|
|
||||||
namespace Totp
|
namespace Totp
|
||||||
{
|
{
|
||||||
|
|
||||||
struct Encoder
|
struct Encoder
|
||||||
{
|
{
|
||||||
QString name;
|
QString name;
|
||||||
@ -39,20 +38,26 @@ namespace Totp
|
|||||||
bool reverse;
|
bool reverse;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum HashType
|
enum Algorithm
|
||||||
{
|
{
|
||||||
Sha1,
|
Sha1,
|
||||||
Sha256,
|
Sha256,
|
||||||
Sha512,
|
Sha512,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum StorageFormat
|
||||||
|
{
|
||||||
|
OTPURL,
|
||||||
|
KEEOTP,
|
||||||
|
LEGACY,
|
||||||
|
};
|
||||||
|
|
||||||
struct Settings
|
struct Settings
|
||||||
{
|
{
|
||||||
|
Totp::StorageFormat format;
|
||||||
Totp::Encoder encoder;
|
Totp::Encoder encoder;
|
||||||
Totp::HashType hashType;
|
Totp::Algorithm algorithm;
|
||||||
QString key;
|
QString key;
|
||||||
bool otpUrl;
|
|
||||||
bool keeOtp;
|
|
||||||
bool custom;
|
bool custom;
|
||||||
uint digits;
|
uint digits;
|
||||||
uint step;
|
uint step;
|
||||||
@ -61,7 +66,8 @@ namespace Totp
|
|||||||
constexpr uint DEFAULT_STEP = 30u;
|
constexpr uint DEFAULT_STEP = 30u;
|
||||||
constexpr uint DEFAULT_DIGITS = 6u;
|
constexpr uint DEFAULT_DIGITS = 6u;
|
||||||
constexpr uint STEAM_DIGITS = 5u;
|
constexpr uint STEAM_DIGITS = 5u;
|
||||||
constexpr Totp::HashType DEFAULT_HASHTYPE = Sha1;
|
constexpr Totp::Algorithm DEFAULT_ALGORITHM = Sha1;
|
||||||
|
constexpr Totp::StorageFormat DEFAULT_FORMAT = OTPURL;
|
||||||
static const QString STEAM_SHORTNAME = "S";
|
static const QString STEAM_SHORTNAME = "S";
|
||||||
|
|
||||||
static const QString ATTRIBUTE_OTP = "otp";
|
static const QString ATTRIBUTE_OTP = "otp";
|
||||||
@ -72,9 +78,9 @@ namespace Totp
|
|||||||
QSharedPointer<Totp::Settings> createSettings(const QString& key,
|
QSharedPointer<Totp::Settings> createSettings(const QString& key,
|
||||||
const uint digits,
|
const uint digits,
|
||||||
const uint step,
|
const uint step,
|
||||||
|
const Totp::StorageFormat format = DEFAULT_FORMAT,
|
||||||
const QString& encoderShortName = {},
|
const QString& encoderShortName = {},
|
||||||
const Totp::HashType hashType = DEFAULT_HASHTYPE,
|
const Totp::Algorithm algorithm = DEFAULT_ALGORITHM);
|
||||||
QSharedPointer<Totp::Settings> prevSettings = {});
|
|
||||||
QString writeSettings(const QSharedPointer<Totp::Settings>& settings,
|
QString writeSettings(const QSharedPointer<Totp::Settings>& settings,
|
||||||
const QString& title = {},
|
const QString& title = {},
|
||||||
const QString& username = {},
|
const QString& username = {},
|
||||||
@ -82,6 +88,9 @@ namespace Totp
|
|||||||
|
|
||||||
QString generateTotp(const QSharedPointer<Totp::Settings>& settings, const quint64 time = 0ull);
|
QString generateTotp(const QSharedPointer<Totp::Settings>& settings, const quint64 time = 0ull);
|
||||||
|
|
||||||
|
QList<QPair<QString, QString>> supportedEncoders();
|
||||||
|
QList<QPair<QString, Algorithm>> supportedAlgorithms();
|
||||||
|
|
||||||
Encoder& defaultEncoder();
|
Encoder& defaultEncoder();
|
||||||
Encoder& steamEncoder();
|
Encoder& steamEncoder();
|
||||||
Encoder& getEncoderByShortName(const QString& shortName);
|
Encoder& getEncoderByShortName(const QString& shortName);
|
||||||
|
@ -39,9 +39,10 @@ void TestTotp::testParseSecret()
|
|||||||
QVERIFY(!settings.isNull());
|
QVERIFY(!settings.isNull());
|
||||||
QCOMPARE(settings->key, QString("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ"));
|
QCOMPARE(settings->key, QString("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ"));
|
||||||
QCOMPARE(settings->custom, false);
|
QCOMPARE(settings->custom, false);
|
||||||
|
QCOMPARE(settings->format, Totp::StorageFormat::OTPURL);
|
||||||
QCOMPARE(settings->digits, 6u);
|
QCOMPARE(settings->digits, 6u);
|
||||||
QCOMPARE(settings->step, 30u);
|
QCOMPARE(settings->step, 30u);
|
||||||
QCOMPARE(settings->hashType, Totp::HashType::Sha1);
|
QCOMPARE(settings->algorithm, Totp::Algorithm::Sha1);
|
||||||
|
|
||||||
// OTP URL with non-default hash type
|
// OTP URL with non-default hash type
|
||||||
secret = "otpauth://totp/"
|
secret = "otpauth://totp/"
|
||||||
@ -50,10 +51,11 @@ void TestTotp::testParseSecret()
|
|||||||
settings = Totp::parseSettings(secret);
|
settings = Totp::parseSettings(secret);
|
||||||
QVERIFY(!settings.isNull());
|
QVERIFY(!settings.isNull());
|
||||||
QCOMPARE(settings->key, QString("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ"));
|
QCOMPARE(settings->key, QString("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ"));
|
||||||
QCOMPARE(settings->custom, false);
|
QCOMPARE(settings->custom, true);
|
||||||
|
QCOMPARE(settings->format, Totp::StorageFormat::OTPURL);
|
||||||
QCOMPARE(settings->digits, 6u);
|
QCOMPARE(settings->digits, 6u);
|
||||||
QCOMPARE(settings->step, 30u);
|
QCOMPARE(settings->step, 30u);
|
||||||
QCOMPARE(settings->hashType, Totp::HashType::Sha512);
|
QCOMPARE(settings->algorithm, Totp::Algorithm::Sha512);
|
||||||
|
|
||||||
// KeeOTP Parsing
|
// KeeOTP Parsing
|
||||||
secret = "key=HXDMVJECJJWSRBY%3d&step=25&size=8&otpHashMode=Sha256";
|
secret = "key=HXDMVJECJJWSRBY%3d&step=25&size=8&otpHashMode=Sha256";
|
||||||
@ -61,9 +63,10 @@ void TestTotp::testParseSecret()
|
|||||||
QVERIFY(!settings.isNull());
|
QVERIFY(!settings.isNull());
|
||||||
QCOMPARE(settings->key, QString("HXDMVJECJJWSRBY="));
|
QCOMPARE(settings->key, QString("HXDMVJECJJWSRBY="));
|
||||||
QCOMPARE(settings->custom, true);
|
QCOMPARE(settings->custom, true);
|
||||||
|
QCOMPARE(settings->format, Totp::StorageFormat::KEEOTP);
|
||||||
QCOMPARE(settings->digits, 8u);
|
QCOMPARE(settings->digits, 8u);
|
||||||
QCOMPARE(settings->step, 25u);
|
QCOMPARE(settings->step, 25u);
|
||||||
QCOMPARE(settings->hashType, Totp::HashType::Sha256);
|
QCOMPARE(settings->algorithm, Totp::Algorithm::Sha256);
|
||||||
|
|
||||||
// Semi-colon delineated "TOTP Settings"
|
// Semi-colon delineated "TOTP Settings"
|
||||||
secret = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq";
|
secret = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq";
|
||||||
@ -71,9 +74,10 @@ void TestTotp::testParseSecret()
|
|||||||
QVERIFY(!settings.isNull());
|
QVERIFY(!settings.isNull());
|
||||||
QCOMPARE(settings->key, QString("gezdgnbvgy3tqojqgezdgnbvgy3tqojq"));
|
QCOMPARE(settings->key, QString("gezdgnbvgy3tqojqgezdgnbvgy3tqojq"));
|
||||||
QCOMPARE(settings->custom, true);
|
QCOMPARE(settings->custom, true);
|
||||||
|
QCOMPARE(settings->format, Totp::StorageFormat::LEGACY);
|
||||||
QCOMPARE(settings->digits, 8u);
|
QCOMPARE(settings->digits, 8u);
|
||||||
QCOMPARE(settings->step, 30u);
|
QCOMPARE(settings->step, 30u);
|
||||||
QCOMPARE(settings->hashType, Totp::HashType::Sha1);
|
QCOMPARE(settings->algorithm, Totp::Algorithm::Sha1);
|
||||||
|
|
||||||
// Bare secret (no "TOTP Settings" attribute)
|
// Bare secret (no "TOTP Settings" attribute)
|
||||||
secret = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq";
|
secret = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq";
|
||||||
@ -81,9 +85,10 @@ void TestTotp::testParseSecret()
|
|||||||
QVERIFY(!settings.isNull());
|
QVERIFY(!settings.isNull());
|
||||||
QCOMPARE(settings->key, QString("gezdgnbvgy3tqojqgezdgnbvgy3tqojq"));
|
QCOMPARE(settings->key, QString("gezdgnbvgy3tqojqgezdgnbvgy3tqojq"));
|
||||||
QCOMPARE(settings->custom, false);
|
QCOMPARE(settings->custom, false);
|
||||||
|
QCOMPARE(settings->format, Totp::StorageFormat::LEGACY);
|
||||||
QCOMPARE(settings->digits, 6u);
|
QCOMPARE(settings->digits, 6u);
|
||||||
QCOMPARE(settings->step, 30u);
|
QCOMPARE(settings->step, 30u);
|
||||||
QCOMPARE(settings->hashType, Totp::HashType::Sha1);
|
QCOMPARE(settings->algorithm, Totp::Algorithm::Sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestTotp::testTotpCode()
|
void TestTotp::testTotpCode()
|
||||||
@ -119,6 +124,7 @@ void TestTotp::testSteamTotp()
|
|||||||
|
|
||||||
QCOMPARE(settings->key, QString("63BEDWCQZKTQWPESARIERL5DTTQFCJTK"));
|
QCOMPARE(settings->key, QString("63BEDWCQZKTQWPESARIERL5DTTQFCJTK"));
|
||||||
QCOMPARE(settings->encoder.shortName, Totp::STEAM_SHORTNAME);
|
QCOMPARE(settings->encoder.shortName, Totp::STEAM_SHORTNAME);
|
||||||
|
QCOMPARE(settings->format, Totp::StorageFormat::OTPURL);
|
||||||
QCOMPARE(settings->digits, Totp::STEAM_DIGITS);
|
QCOMPARE(settings->digits, Totp::STEAM_DIGITS);
|
||||||
QCOMPARE(settings->step, 30u);
|
QCOMPARE(settings->step, 30u);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user