feat: Support configuring the issuer when adding a new account in Keysmith.
With this change, issuers are now fully supported. Resolves: #13master
parent
0d40912360
commit
d358d8abcc
|
@ -1,11 +1,12 @@
|
|||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
# SPDX-FileCopyrightText: 2019 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
# SPDX-FileCopyrightText: 2019-2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
#
|
||||
|
||||
set(validator_lib_test_SRCS
|
||||
base32-validator.cpp
|
||||
name-validator.cpp
|
||||
issuer-validator.cpp
|
||||
unsigned-long-validator.cpp
|
||||
unsigned-long-parsing.cpp
|
||||
)
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
|
||||
#include "test-util.h"
|
||||
|
||||
#include "validators/issuervalidator.h"
|
||||
|
||||
using namespace validators::test;
|
||||
|
||||
static void define_valid_table(void)
|
||||
{
|
||||
define_test_case(QLatin1String(""), QLatin1String(""), QValidator::Acceptable);
|
||||
define_test_case(QLatin1String("Issuer"), QLatin1String("Issuer"), QValidator::Acceptable);
|
||||
define_test_case(QLatin1String("test issuer"), QLatin1String("test issuer"), QValidator::Acceptable);
|
||||
}
|
||||
|
||||
static void define_invalid_table(void)
|
||||
{
|
||||
define_test_case(QLatin1String("test\tissuer"), QLatin1String("test issuer"), QValidator::Invalid);
|
||||
define_test_case(QLatin1String("\r \n\ttest\r\t \nissuer \r\t\n"), QLatin1String("test issuer"), QValidator::Invalid);
|
||||
define_test_case(QLatin1String("test "), QLatin1String("test "), QValidator::Invalid);
|
||||
define_test_case(QLatin1String("test:issuer"), QLatin1String("testissuer"), QValidator::Invalid);
|
||||
}
|
||||
|
||||
static void define_empty_table(void)
|
||||
{
|
||||
define_test_case(QLatin1String(" "), QLatin1String(""), QValidator::Invalid);
|
||||
define_test_case(QLatin1String("\t"), QLatin1String(""), QValidator::Invalid);
|
||||
define_test_case(QLatin1String("\r\n"), QLatin1String(""), QValidator::Invalid);
|
||||
}
|
||||
|
||||
static void define_data(void)
|
||||
{
|
||||
define_empty_table();
|
||||
define_valid_table();
|
||||
define_invalid_table();
|
||||
}
|
||||
|
||||
DEFINE_VALIDATOR_TEST(IssuerValidatorTest, validators::IssuerValidator, define_data);
|
||||
|
||||
QTEST_APPLESS_MAIN(IssuerValidatorTest)
|
||||
|
||||
#include "issuer-validator.moc"
|
|
@ -17,7 +17,7 @@ Kirigami.Page {
|
|||
title: i18nc("@title:window", "Add new account")
|
||||
signal dismissed
|
||||
property Models.AccountListModel accounts: Keysmith.accountListModel()
|
||||
property bool acceptable: accountName.acceptableInput && tokenDetails.acceptable
|
||||
property bool acceptable: accountName.acceptableInput && issuerName.acceptableInput && tokenDetails.acceptable
|
||||
|
||||
ColumnLayout {
|
||||
anchors {
|
||||
|
@ -28,8 +28,29 @@ Kirigami.Page {
|
|||
id: accountName
|
||||
Kirigami.FormData.label: i18nc("@label:textbox", "Account Name:")
|
||||
validator: Validators.AccountNameValidator {
|
||||
id: accountNameValidator
|
||||
accounts: root.accounts
|
||||
issuer: ""
|
||||
issuer: issuerName.text
|
||||
}
|
||||
}
|
||||
Controls.TextField {
|
||||
id: issuerName
|
||||
Kirigami.FormData.label: i18nc("@label:textbox", "Account Issuer:")
|
||||
validator: Validators.AccountIssuerValidator {}
|
||||
/*
|
||||
* When the issuer changes, the account name should be revalidated as well. It may have become eligible or in-eligible depending on
|
||||
* whether or not other accounts with the same name for the same new issuer value already exist.
|
||||
*
|
||||
* Unfortunately because the property binding only affects the validator, there seems to be nothing to explicitly trigger revalidation
|
||||
* on the text field. Work around is to force revalidation to happen by "editing" the value in the text field directly.
|
||||
*/
|
||||
onTextChanged: {
|
||||
/*
|
||||
* This signal handler may run before property bindings have been fully (re-)evaluated.
|
||||
* First update the account name validator to the correct new issuer value before triggering revalidation.
|
||||
*/
|
||||
accountNameValidator.issuer = issuerName.text;
|
||||
accountName.insert(accountName.text.length, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,10 +65,10 @@ Kirigami.Page {
|
|||
enabled: acceptable
|
||||
onTriggered: {
|
||||
if (tokenDetails.isTotp) {
|
||||
accounts.addTotp(accountName.text, "", tokenDetails.secret, parseInt(tokenDetails.timeStep), tokenDetails.tokenLength);
|
||||
accounts.addTotp(accountName.text, issuerName.text, tokenDetails.secret, parseInt(tokenDetails.timeStep), tokenDetails.tokenLength);
|
||||
}
|
||||
if (tokenDetails.isHotp) {
|
||||
accounts.addHotp(accountName.text, "", tokenDetails.secret, parseInt(tokenDetails.counter), tokenDetails.tokenLength);
|
||||
accounts.addHotp(accountName.text, issuerName.text, tokenDetails.secret, parseInt(tokenDetails.counter), tokenDetails.tokenLength);
|
||||
}
|
||||
root.dismissed();
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "app/keysmith.h"
|
||||
#include "model/accounts.h"
|
||||
#include "validators/countervalidator.h"
|
||||
#include "validators/issuervalidator.h"
|
||||
#include "validators/secretvalidator.h"
|
||||
|
||||
Q_DECL_EXPORT int main(int argc, char *argv[])
|
||||
|
@ -36,6 +37,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
|||
qmlRegisterUncreatableType<model::AccountView>("Keysmith.Models", 1, 0, "Account", "Use an AccountListModel from the Keysmith singleton to obtain an Account");
|
||||
qmlRegisterType<model::SortedAccountsListModel>("Keysmith.Models", 1, 0, "SortedAccountListModel");
|
||||
qmlRegisterType<model::AccountNameValidator>("Keysmith.Validators", 1, 0, "AccountNameValidator");
|
||||
qmlRegisterType<validators::IssuerValidator>("Keysmith.Validators", 1, 0, "AccountIssuerValidator");
|
||||
qmlRegisterType<validators::Base32Validator>("Keysmith.Validators", 1, 0, "Base32SecretValidator");
|
||||
qmlRegisterType<validators::UnsignedLongValidator>("Keysmith.Validators", 1, 0, "HOTPCounterValidator");
|
||||
qmlRegisterSingletonType<app::Keysmith>("Keysmith.Application", 1, 0, "Keysmith", [](QQmlEngine *qml, QJSEngine *js) -> QObject *
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
set(validator_SRCS
|
||||
countervalidator.cpp
|
||||
namevalidator.cpp
|
||||
issuervalidator.cpp
|
||||
secretvalidator.cpp
|
||||
util.cpp
|
||||
)
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
|
||||
#include "issuervalidator.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
|
||||
static const QRegularExpression& match_pattern(void)
|
||||
{
|
||||
/*
|
||||
* Pattern to check that issuer names:
|
||||
*
|
||||
* - do not contain colons
|
||||
* - start and end with a character which is not whitespace
|
||||
* - do not contain any other whitespace besides spaces
|
||||
* - have at most one space between non-whitespace characters
|
||||
*/
|
||||
static const QRegularExpression re(QLatin1String("^[^\\s:]+( [^\\s:]+)*$"));
|
||||
re.optimize();
|
||||
return re;
|
||||
}
|
||||
|
||||
namespace validators
|
||||
{
|
||||
IssuerValidator::IssuerValidator(QObject *parent):
|
||||
QValidator(parent),
|
||||
m_pattern(match_pattern())
|
||||
{
|
||||
}
|
||||
|
||||
void IssuerValidator::fixup(QString &input) const
|
||||
{
|
||||
QString fixed = input.simplified().remove(QLatin1Char(':'));
|
||||
|
||||
// make sure the user can type in at least one space
|
||||
if (input.endsWith(QLatin1Char(' ')) && fixed.size() > 0) {
|
||||
fixed += QLatin1Char(' ');
|
||||
}
|
||||
|
||||
input = fixed;
|
||||
}
|
||||
|
||||
QValidator::State IssuerValidator::validate(QString &input, int &cursor) const
|
||||
{
|
||||
return input.isEmpty() ? QValidator::Acceptable : m_pattern.validate(input, cursor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef ISSUER_VALIDATOR_H
|
||||
#define ISSUER_VALIDATOR_H
|
||||
|
||||
#include <QRegularExpressionValidator>
|
||||
#include <QValidator>
|
||||
|
||||
namespace validators
|
||||
{
|
||||
class IssuerValidator: public QValidator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IssuerValidator(QObject *parent = nullptr);
|
||||
QValidator::State validate(QString &input, int &pos) const override;
|
||||
void fixup(QString &input) const override;
|
||||
private:
|
||||
const QRegularExpressionValidator m_pattern;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue