refactor: introduce model class to collate validated input from add account forms (flow)
This change prepares the UI for supporting alternative and more complex flows for adding accounts. All parameters are now collated into a single "validated input" object which is more convenient to pass around between views This makes it possible to support back- and forth navigation between "basic" and "advanced/details" forms for adding accounts. Additionally it provides a fundamental building block for adding alternative ways to add accounts (e.g. via OTP token URI/QR code). Issues: #7master
parent
170d7f1811
commit
63033b568d
|
@ -19,6 +19,9 @@ Kirigami.Page {
|
|||
property Models.AccountListModel accounts: Keysmith.accountListModel()
|
||||
property bool acceptable: accountName.acceptableInput && issuerName.acceptableInput && tokenDetails.acceptable
|
||||
|
||||
property Models.ValidatedAccountInput validatedInput: Models.ValidatedAccountInput {
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
|
@ -26,15 +29,22 @@ Kirigami.Page {
|
|||
Kirigami.FormLayout {
|
||||
Controls.TextField {
|
||||
id: accountName
|
||||
text: validatedInput.name
|
||||
Kirigami.FormData.label: i18nc("@label:textbox", "Account Name:")
|
||||
validator: Validators.AccountNameValidator {
|
||||
id: accountNameValidator
|
||||
accounts: root.accounts
|
||||
issuer: issuerName.text
|
||||
issuer: validatedInput.issuer
|
||||
}
|
||||
onTextChanged: {
|
||||
if (acceptableInput) {
|
||||
validatedInput.name = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
Controls.TextField {
|
||||
id: issuerName
|
||||
text: validatedInput.issuer
|
||||
Kirigami.FormData.label: i18nc("@label:textbox", "Account Issuer:")
|
||||
validator: Validators.AccountIssuerValidator {}
|
||||
/*
|
||||
|
@ -51,11 +61,15 @@ Kirigami.Page {
|
|||
*/
|
||||
accountNameValidator.issuer = issuerName.text;
|
||||
accountName.insert(accountName.text.length, "");
|
||||
if (acceptableInput) {
|
||||
validatedInput.issuer = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TokenDetailsForm {
|
||||
id: tokenDetails
|
||||
validatedInput: root.validatedInput
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,13 +78,7 @@ Kirigami.Page {
|
|||
iconName: "answer-correct"
|
||||
enabled: acceptable
|
||||
onTriggered: {
|
||||
if (tokenDetails.isTotp) {
|
||||
console.log("WTF: ", Models.AccountListModel.Sha1);
|
||||
accounts.addTotp(accountName.text, issuerName.text, tokenDetails.secret, tokenDetails.tokenLength, parseInt(tokenDetails.timeStep), new Date(0), Models.AccountListModel.Sha1);
|
||||
}
|
||||
if (tokenDetails.isHotp) {
|
||||
accounts.addHotp(accountName.text, issuerName.text, tokenDetails.secret, tokenDetails.tokenLength, parseInt(tokenDetails.counter), false, 0, false);
|
||||
}
|
||||
root.accounts.addAccount(root.validatedInput);
|
||||
root.dismissed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-FileCopyrightText: 2019-2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
|
||||
import Keysmith.Models 1.0 as Models
|
||||
import Keysmith.Validators 1.0 as Validators
|
||||
import QtQuick 2.1
|
||||
import QtQuick.Layouts 1.2
|
||||
|
@ -12,17 +13,12 @@ import org.kde.kirigami 2.8 as Kirigami
|
|||
|
||||
Kirigami.FormLayout {
|
||||
id: root
|
||||
property bool isTotp: totpRadio.checked && !hotpRadio.checked
|
||||
property bool isHotp: hotpRadio.checked && !totpRadio.checked
|
||||
property int tokenLength: tokenLengthField.value
|
||||
property string timeStep: timeStepField.text
|
||||
property string secret: accountSecret.text
|
||||
property string counter: counterField.text
|
||||
property Models.ValidatedAccountInput validatedInput
|
||||
|
||||
property bool secretAcceptable: accountSecret.acceptableInput
|
||||
property bool timeStepAcceptable: timeStepField.acceptableInput || isHotp
|
||||
property bool counterAcceptable: counterField.acceptableInput || isTotp
|
||||
property bool tokenTypeAcceptable: isHotp || isTotp
|
||||
property bool timeStepAcceptable: timeStepField.acceptableInput || hotpRadio.checked
|
||||
property bool counterAcceptable: counterField.acceptableInput || totpRadio.checked
|
||||
property bool tokenTypeAcceptable: hotpRadio.checked || totpRadio.checked
|
||||
property bool acceptable: counterAcceptable && timeStepAcceptable && secretAcceptable && tokenTypeAcceptable
|
||||
|
||||
ColumnLayout {
|
||||
|
@ -31,44 +27,69 @@ Kirigami.FormLayout {
|
|||
Kirigami.FormData.buddyFor: totpRadio
|
||||
Controls.RadioButton {
|
||||
id: totpRadio
|
||||
checked: true
|
||||
checked: validatedInput && validatedInput.type === Models.ValidatedAccountInput.Totp
|
||||
text: i18nc("@option:radio", "Time-based OTP")
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
validatedInput.type = Models.ValidatedAccountInput.Totp;
|
||||
}
|
||||
}
|
||||
}
|
||||
Controls.RadioButton {
|
||||
id: hotpRadio
|
||||
checked: false
|
||||
checked: validatedInput && validatedInput.type === Models.ValidatedAccountInput.Hotp
|
||||
text: i18nc("@option:radio", "Hash-based OTP")
|
||||
onCheckedChanged: {
|
||||
if (checked) {
|
||||
validatedInput.type = Models.ValidatedAccountInput.Hotp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Kirigami.PasswordField {
|
||||
id: accountSecret
|
||||
placeholderText: i18n("Token secret")
|
||||
text: ""
|
||||
text: validatedInput ? validatedInput.secret : ""
|
||||
Kirigami.FormData.label: i18nc("@label:textbox", "Secret key:")
|
||||
validator: Validators.Base32SecretValidator {
|
||||
id: secretValidator
|
||||
}
|
||||
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText | Qt.ImhSensitiveData | Qt.ImhHiddenText
|
||||
onTextChanged: {
|
||||
if (acceptableInput) {
|
||||
validatedInput.secret = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
Controls.TextField {
|
||||
id: timeStepField
|
||||
Kirigami.FormData.label: i18nc("@label:textbox", "Timer:")
|
||||
enabled: totpRadio.checked
|
||||
text: "30"
|
||||
enabled: validatedInput.type === Models.ValidatedAccountInput.Totp
|
||||
text: validatedInput ? "" + validatedInput.timeStep : ""
|
||||
validator: IntValidator {
|
||||
bottom: 1
|
||||
}
|
||||
inputMethodHints: Qt.ImhDigitsOnly
|
||||
onTextChanged: {
|
||||
if (acceptableInput) {
|
||||
validatedInput.timeStep = parseInt(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
Controls.TextField {
|
||||
id: counterField
|
||||
text: "0"
|
||||
text: validatedInput ? validatedInput.counter : ""
|
||||
Kirigami.FormData.label: i18nc("@label:textbox", "Counter:")
|
||||
enabled: hotpRadio.checked
|
||||
validator: Validators.HOTPCounterValidator {
|
||||
id: counterValidator
|
||||
}
|
||||
inputMethodHints: Qt.ImhDigitsOnly
|
||||
onTextChanged: {
|
||||
if (acceptableInput) {
|
||||
validatedInput.setCounter(text, validator);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* OATH tokens are derived from a 32bit value, base-10 encoded.
|
||||
|
@ -82,6 +103,9 @@ Kirigami.FormLayout {
|
|||
Kirigami.FormData.label: i18nc("@label:spinbox", "Token length:")
|
||||
from: 6
|
||||
to: 10
|
||||
value: 6
|
||||
value: validatedInput ? validatedInput.tokenLength : 6
|
||||
onValueChanged: {
|
||||
validatedInput.tokenLength = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "app/keysmith.h"
|
||||
#include "model/accounts.h"
|
||||
#include "model/input.h"
|
||||
#include "validators/countervalidator.h"
|
||||
#include "validators/datetimevalidator.h"
|
||||
#include "validators/issuervalidator.h"
|
||||
|
@ -36,6 +37,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
|||
qmlRegisterUncreatableType<model::SimpleAccountListModel>("Keysmith.Models", 1, 0, "AccountListModel", "Use the Keysmith singleton to obtain an AccountListModel");
|
||||
qmlRegisterUncreatableType<model::PasswordRequest>("Keysmith.Models", 1, 0, "PasswordRequestModel", "Use the Keysmith singleton to obtain an PasswordRequestModel");
|
||||
qmlRegisterUncreatableType<model::AccountView>("Keysmith.Models", 1, 0, "Account", "Use an AccountListModel from the Keysmith singleton to obtain an Account");
|
||||
qmlRegisterType<model::AccountInput>("Keysmith.Models", 1, 0, "ValidatedAccountInput");
|
||||
qmlRegisterType<model::SortedAccountsListModel>("Keysmith.Models", 1, 0, "SortedAccountListModel");
|
||||
qmlRegisterType<model::AccountNameValidator>("Keysmith.Validators", 1, 0, "AccountNameValidator");
|
||||
qmlRegisterType<validators::EpochValidator>("Keysmith.Validators", 1, 0, "TOTPEpochValidator");
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
set(model_SRCS
|
||||
accounts.cpp
|
||||
password.cpp
|
||||
input.cpp
|
||||
)
|
||||
|
||||
add_library(model_lib STATIC ${model_SRCS})
|
||||
|
|
|
@ -153,19 +153,13 @@ namespace model
|
|||
}
|
||||
}
|
||||
|
||||
void SimpleAccountListModel::addTotp(const QString &account, const QString &issuer,
|
||||
const QString &secret, uint tokenLength,
|
||||
uint timeStep, const QDateTime &epoch, TOTPAlgorithms hash)
|
||||
void SimpleAccountListModel::addAccount(AccountInput *input)
|
||||
{
|
||||
m_storage->addTotp(account, issuer, secret, tokenLength, timeStep, epoch, toHash(hash));
|
||||
}
|
||||
|
||||
void SimpleAccountListModel::addHotp(const QString &account, const QString &issuer,
|
||||
const QString &secret, uint tokenLength,
|
||||
quint64 counter, bool fixedTruncation, uint offset, bool checksum)
|
||||
{
|
||||
const auto o = fixedTruncation ? std::optional<uint>(offset) : std::nullopt;
|
||||
m_storage->addHotp(account, issuer, secret, tokenLength, counter, o, checksum);
|
||||
if (!input) {
|
||||
qCDebug(logger) << "Not adding account, no input provided";
|
||||
return;
|
||||
}
|
||||
input->createNewAccount(m_storage);
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> SimpleAccountListModel::roleNames(void) const
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef MODEL_ACCOUNTS_H
|
||||
#define MODEL_ACCOUNTS_H
|
||||
|
||||
#include "input.h"
|
||||
#include "../account/account.h"
|
||||
#include "../validators/namevalidator.h"
|
||||
|
||||
|
@ -74,10 +75,7 @@ namespace model
|
|||
static accounts::Account::Hash toHash(const TOTPAlgorithms value);
|
||||
public:
|
||||
explicit SimpleAccountListModel(accounts::AccountStorage *storage, QObject *parent = nullptr);
|
||||
Q_INVOKABLE void addTotp(const QString &account, const QString &issuer, const QString &secret, uint tokenLength,
|
||||
uint timeStep, const QDateTime &epoch, model::SimpleAccountListModel::TOTPAlgorithms hash);
|
||||
Q_INVOKABLE void addHotp(const QString &account, const QString &issuer, const QString &secret, uint tokenLength,
|
||||
quint64 counter, bool fixedTruncation, uint offset, bool checksum);
|
||||
Q_INVOKABLE void addAccount(AccountInput *input);
|
||||
Q_INVOKABLE bool isAccountStillAvailable(const QString &name, const QString &issuer) const;
|
||||
Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
Q_INVOKABLE QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
#include "input.h"
|
||||
|
||||
#include <QLocale>
|
||||
|
||||
static QDateTime DEFAULT_EPOCH_VALUE = QDateTime::fromMSecsSinceEpoch(0, Qt::UTC);
|
||||
static QString DEFAULT_EPOCH = DEFAULT_EPOCH_VALUE.toString(Qt::ISODate);
|
||||
static QString DEFAULT_COUNTER = QLocale::c().toString(0ULL);
|
||||
|
||||
namespace model
|
||||
{
|
||||
|
||||
static accounts::Account::Hash toHash(AccountInput::TOTPAlgorithm algorithm)
|
||||
{
|
||||
switch(algorithm) {
|
||||
case AccountInput::TOTPAlgorithm::Sha1:
|
||||
return accounts::Account::Hash::Sha1;
|
||||
case AccountInput::TOTPAlgorithm::Sha256:
|
||||
return accounts::Account::Hash::Sha256;
|
||||
case AccountInput::TOTPAlgorithm::Sha512:
|
||||
return accounts::Account::Hash::Sha512;
|
||||
default:
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown/unsupported TOTP hashing algorithm?");
|
||||
return accounts::Account::Hash::Sha1;
|
||||
}
|
||||
}
|
||||
|
||||
AccountInput::AccountInput(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_type(TokenType::Totp), m_name(QString()), m_issuer(QString()), m_secret(QString()), m_tokenLength(6U),
|
||||
m_timeStep(30U), m_algorithm(TOTPAlgorithm::Sha1), m_epoch(DEFAULT_EPOCH), m_epochValue(DEFAULT_EPOCH_VALUE),
|
||||
m_checksum(false), m_counter(DEFAULT_COUNTER), m_counterValue(0ULL), m_truncation(std::nullopt)
|
||||
{
|
||||
}
|
||||
|
||||
void AccountInput::createNewAccount(accounts::AccountStorage *storage) const
|
||||
{
|
||||
if (!storage) {
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Storage must be provided");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(m_type) {
|
||||
case Hotp:
|
||||
storage->addHotp(m_name, m_issuer, m_secret, m_tokenLength, m_counterValue, m_truncation, m_checksum);
|
||||
break;
|
||||
case Totp:
|
||||
storage->addTotp(m_name, m_issuer, m_secret, m_tokenLength, m_timeStep, m_epochValue, toHash(m_algorithm));
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown/unsupported token type?");
|
||||
}
|
||||
}
|
||||
|
||||
AccountInput::TokenType AccountInput::type(void) const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void AccountInput::setType(model::AccountInput::TokenType type)
|
||||
{
|
||||
if (m_type != type) {
|
||||
m_type = type;
|
||||
Q_EMIT typeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString AccountInput::name(void) const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void AccountInput::setName(const QString &name)
|
||||
{
|
||||
if (m_name != name) {
|
||||
m_name = name;
|
||||
Q_EMIT nameChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString AccountInput::issuer(void) const
|
||||
{
|
||||
return m_issuer;
|
||||
}
|
||||
|
||||
void AccountInput::setIssuer(const QString &issuer)
|
||||
{
|
||||
if (m_issuer != issuer) {
|
||||
m_issuer = issuer;
|
||||
Q_EMIT issuerChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString AccountInput::secret(void) const
|
||||
{
|
||||
return m_secret;
|
||||
}
|
||||
|
||||
void AccountInput::setSecret(QString &secret)
|
||||
{
|
||||
if (m_secret != secret) {
|
||||
m_secret = secret;
|
||||
Q_EMIT secretChanged();
|
||||
}
|
||||
}
|
||||
|
||||
uint AccountInput::tokenLength(void) const
|
||||
{
|
||||
return m_tokenLength;
|
||||
}
|
||||
|
||||
void AccountInput::setTokenLength(uint tokenLength)
|
||||
{
|
||||
if (m_tokenLength != tokenLength) {
|
||||
m_tokenLength = tokenLength;
|
||||
Q_EMIT tokenLengthChanged();
|
||||
}
|
||||
}
|
||||
|
||||
uint AccountInput::timeStep(void) const
|
||||
{
|
||||
return m_timeStep;
|
||||
}
|
||||
|
||||
void AccountInput::setTimeStep(uint timeStep)
|
||||
{
|
||||
if (m_timeStep != timeStep) {
|
||||
m_timeStep = timeStep;
|
||||
Q_EMIT timeStepChanged();
|
||||
}
|
||||
}
|
||||
|
||||
AccountInput::TOTPAlgorithm AccountInput::algorithm(void) const
|
||||
{
|
||||
return m_algorithm;
|
||||
}
|
||||
|
||||
void AccountInput::setAlgorithm(model::AccountInput::TOTPAlgorithm algorithm)
|
||||
{
|
||||
if (m_algorithm != algorithm) {
|
||||
m_algorithm = algorithm;
|
||||
Q_EMIT algorithmChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString AccountInput::epoch(void) const
|
||||
{
|
||||
return m_epoch;
|
||||
}
|
||||
|
||||
void AccountInput::setEpoch(const QString &epoch)
|
||||
{
|
||||
if (m_epoch != epoch) {
|
||||
m_epoch = epoch;
|
||||
m_epochValue = validators::parseDateTime(epoch).value_or(DEFAULT_EPOCH_VALUE);
|
||||
Q_EMIT epochChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool AccountInput::checksum(void) const
|
||||
{
|
||||
return m_checksum;
|
||||
}
|
||||
|
||||
void AccountInput::setChecksum(bool checksum)
|
||||
{
|
||||
if (m_checksum != checksum) {
|
||||
m_checksum = checksum;
|
||||
Q_EMIT checksumChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString AccountInput::counter(void) const
|
||||
{
|
||||
return m_counter;
|
||||
}
|
||||
|
||||
void AccountInput::setCounter(const QString &counter, validators::UnsignedLongValidator *validator)
|
||||
{
|
||||
if (!validator) {
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Validator must be provided");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_counter != counter) {
|
||||
m_counter = counter;
|
||||
m_counterValue = validators::parse(counter, validator->locale()).value_or(0ULL);
|
||||
Q_EMIT counterChanged();
|
||||
}
|
||||
}
|
||||
|
||||
uint AccountInput::truncationOffset(void) const
|
||||
{
|
||||
return m_truncation.value_or(0U);
|
||||
}
|
||||
|
||||
void AccountInput::setTruncationOffset(uint truncationOffset)
|
||||
{
|
||||
if (!m_truncation || *m_truncation != truncationOffset) {
|
||||
m_truncation = std::optional<uint>(truncationOffset);
|
||||
Q_EMIT truncationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool AccountInput::fixedTruncation(void) const
|
||||
{
|
||||
return (bool) m_truncation;
|
||||
}
|
||||
|
||||
void AccountInput::setDynamicTruncation(void)
|
||||
{
|
||||
if (m_truncation) {
|
||||
m_truncation = std::nullopt;
|
||||
Q_EMIT truncationChanged();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
#ifndef MODEL_INPUT_H
|
||||
#define MODEL_INPUT_H
|
||||
|
||||
#include "../account/account.h"
|
||||
#include "../validators/countervalidator.h"
|
||||
#include "../validators/datetimevalidator.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace model
|
||||
{
|
||||
class AccountInput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(model::AccountInput::TokenType type READ type WRITE setType NOTIFY typeChanged)
|
||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
||||
Q_PROPERTY(QString issuer READ issuer WRITE setIssuer NOTIFY issuerChanged)
|
||||
Q_PROPERTY(QString secret READ secret WRITE setSecret NOTIFY secretChanged)
|
||||
Q_PROPERTY(uint tokenLength READ tokenLength WRITE setTokenLength NOTIFY tokenLengthChanged);
|
||||
Q_PROPERTY(uint timeStep READ timeStep WRITE setTimeStep NOTIFY timeStepChanged)
|
||||
Q_PROPERTY(model::AccountInput::TOTPAlgorithm algorithm READ algorithm WRITE setAlgorithm NOTIFY algorithmChanged)
|
||||
Q_PROPERTY(QString epoch READ epoch WRITE setEpoch NOTIFY epochChanged)
|
||||
Q_PROPERTY(bool checksum READ checksum WRITE setChecksum NOTIFY checksumChanged)
|
||||
Q_PROPERTY(QString counter READ counter NOTIFY counterChanged)
|
||||
Q_PROPERTY(uint truncationOffset READ truncationOffset NOTIFY truncationChanged);
|
||||
Q_PROPERTY(bool fixedTruncation READ fixedTruncation NOTIFY truncationChanged);
|
||||
public:
|
||||
enum TOTPAlgorithm {
|
||||
Sha1, Sha256, Sha512
|
||||
};
|
||||
Q_ENUM(TOTPAlgorithm)
|
||||
enum TokenType {
|
||||
Hotp, Totp
|
||||
};
|
||||
Q_ENUM(TokenType)
|
||||
AccountInput(QObject *parent = nullptr);
|
||||
void createNewAccount(accounts::AccountStorage *storage) const;
|
||||
public:
|
||||
TokenType type(void) const;
|
||||
void setType(model::AccountInput::TokenType type);
|
||||
QString name(void) const;
|
||||
void setName(const QString &name);
|
||||
QString issuer(void) const;
|
||||
void setIssuer(const QString &issuer);
|
||||
QString secret(void) const;
|
||||
void setSecret(QString &secret);
|
||||
uint tokenLength(void) const;
|
||||
void setTokenLength(uint tokenLength);
|
||||
uint timeStep(void) const;
|
||||
void setTimeStep(uint timeStep);
|
||||
TOTPAlgorithm algorithm(void) const;
|
||||
void setAlgorithm(model::AccountInput::TOTPAlgorithm algorithm);
|
||||
QString epoch(void) const;
|
||||
void setEpoch(const QString &epoch);
|
||||
bool checksum(void) const;
|
||||
void setChecksum(bool checksum);
|
||||
QString counter(void) const;
|
||||
Q_INVOKABLE void setCounter(const QString &counter, validators::UnsignedLongValidator *validator);
|
||||
uint truncationOffset(void) const;
|
||||
bool fixedTruncation(void) const;
|
||||
Q_INVOKABLE void setTruncationOffset(uint truncationOffset);
|
||||
Q_INVOKABLE void setDynamicTruncation(void);
|
||||
Q_SIGNALS:
|
||||
void typeChanged(void);
|
||||
void nameChanged(void);
|
||||
void issuerChanged(void);
|
||||
void secretChanged(void);
|
||||
void tokenLengthChanged(void);
|
||||
void timeStepChanged(void);
|
||||
void algorithmChanged(void);
|
||||
void epochChanged(void);
|
||||
void checksumChanged(void);
|
||||
void counterChanged(void);
|
||||
void truncationChanged(void);
|
||||
private:
|
||||
TokenType m_type;
|
||||
QString m_name;
|
||||
QString m_issuer;
|
||||
QString m_secret;
|
||||
uint m_tokenLength;
|
||||
uint m_timeStep;
|
||||
TOTPAlgorithm m_algorithm;
|
||||
QString m_epoch;
|
||||
QDateTime m_epochValue;
|
||||
bool m_checksum;
|
||||
QString m_counter;
|
||||
quint64 m_counterValue;
|
||||
std::optional<uint> m_truncation;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue