Fix TODO items about logging for C++ code
parent
b4dada08d8
commit
f04b15340f
|
@ -6,11 +6,14 @@
|
|||
#include "account_p.h"
|
||||
#include "actions_p.h"
|
||||
|
||||
#include "../logging_p.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
KEYSMITH_LOGGER(logger, ".accounts.account")
|
||||
|
||||
namespace accounts
|
||||
{
|
||||
|
||||
Account::Account(AccountPrivate *d, QObject *parent) : QObject(parent), m_dptr(d)
|
||||
{
|
||||
}
|
||||
|
@ -189,25 +192,47 @@ namespace accounts
|
|||
void AccountStorage::handleHotp(const QUuid id, const QString name, const QString secret, quint64 counter, int tokenLength)
|
||||
{
|
||||
Q_D(AccountStorage);
|
||||
if (d->isStillOpen() && isNameStillAvailable(name)) {
|
||||
Account *accepted = d->acceptHotpAccount(id, name, secret, counter, tokenLength);
|
||||
QObject::connect(accepted, &Account::removed, this, &AccountStorage::accountRemoved);
|
||||
|
||||
Q_EMIT added(name);
|
||||
if (!d->isStillOpen()) {
|
||||
qCDebug(logger)
|
||||
<< "Not handling HOTP account:" << id
|
||||
<< "Storage no longer open";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
if (!isNameStillAvailable(name)) {
|
||||
qCDebug(logger)
|
||||
<< "Not handling HOTP account:" << id
|
||||
<< "Account name not available";
|
||||
return;
|
||||
}
|
||||
|
||||
Account *accepted = d->acceptHotpAccount(id, name, secret, counter, tokenLength);
|
||||
QObject::connect(accepted, &Account::removed, this, &AccountStorage::accountRemoved);
|
||||
|
||||
Q_EMIT added(name);
|
||||
}
|
||||
|
||||
void AccountStorage::handleTotp(const QUuid id, const QString name, const QString secret, uint timeStep, int tokenLength)
|
||||
{
|
||||
Q_D(AccountStorage);
|
||||
if (d->isStillOpen() && isNameStillAvailable(name)) {
|
||||
Account *accepted = d->acceptTotpAccount(id, name, secret, timeStep, tokenLength);
|
||||
QObject::connect(accepted, &Account::removed, this, &AccountStorage::accountRemoved);
|
||||
|
||||
Q_EMIT added(name);
|
||||
if (!d->isStillOpen()) {
|
||||
qCDebug(logger)
|
||||
<< "Not handling TOTP account:" << id
|
||||
<< "Storage no longer open";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
if (!isNameStillAvailable(name)) {
|
||||
qCDebug(logger)
|
||||
<< "Not handling TOTP account:" << id
|
||||
<< "Account name not available";
|
||||
return;
|
||||
}
|
||||
|
||||
Account *accepted = d->acceptTotpAccount(id, name, secret, timeStep, tokenLength);
|
||||
QObject::connect(accepted, &Account::removed, this, &AccountStorage::accountRemoved);
|
||||
|
||||
Q_EMIT added(name);
|
||||
}
|
||||
|
||||
void AccountStorage::dispose(void)
|
||||
|
|
|
@ -30,9 +30,11 @@ namespace accounts
|
|||
Totp,
|
||||
Hotp
|
||||
};
|
||||
Q_ENUM(Algorithm)
|
||||
enum Hash {
|
||||
Default, Sha256, Sha512
|
||||
};
|
||||
Q_ENUM(Hash)
|
||||
explicit Account(AccountPrivate *d, QObject *parent = nullptr);
|
||||
QString name(void) const;
|
||||
QString token(void) const;
|
||||
|
|
|
@ -5,9 +5,13 @@
|
|||
#include "account_p.h"
|
||||
#include "validation.h"
|
||||
|
||||
#include "../logging_p.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
KEYSMITH_LOGGER(logger, ".accounts.account_p")
|
||||
|
||||
namespace accounts
|
||||
{
|
||||
QUuid AccountPrivate::id(void) const
|
||||
|
@ -68,71 +72,145 @@ namespace accounts
|
|||
void AccountPrivate::setCounter(quint64 counter)
|
||||
{
|
||||
Q_Q(Account);
|
||||
if (m_is_still_alive && m_storage->isStillOpen() && m_algorithm == Account::Algorithm::Hotp) {
|
||||
SaveHotp *job = new SaveHotp(m_storage->settings(),m_id, m_name, m_secret, counter, m_tokenLength);
|
||||
m_actions->queueAndProceed(job, [counter, job, q, this](void) -> void
|
||||
{
|
||||
new HandleCounterUpdate(this, counter, job, q);
|
||||
});
|
||||
if (!m_is_still_alive) {
|
||||
qCDebug(logger)
|
||||
<< "Will not set counter for account:" << m_id
|
||||
<< "Object marked for death";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
if (!m_storage->isStillOpen()) {
|
||||
qCDebug(logger)
|
||||
<< "Will not set counter for account:" << m_id
|
||||
<< "Storage no longer open";
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_algorithm != Account::Algorithm::Hotp) {
|
||||
qCDebug(logger)
|
||||
<< "Will not set counter for account:" << m_id
|
||||
<< "Algorithm not applicable:" << m_algorithm;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Requesting to store updated details for account:" << m_id;
|
||||
SaveHotp *job = new SaveHotp(m_storage->settings(),m_id, m_name, m_secret, counter, m_tokenLength);
|
||||
m_actions->queueAndProceed(job, [counter, job, q, this](void) -> void
|
||||
{
|
||||
new HandleCounterUpdate(this, counter, job, q);
|
||||
});
|
||||
}
|
||||
|
||||
void AccountPrivate::acceptCounter(quint64 counter)
|
||||
{
|
||||
if (m_is_still_alive && m_storage->isStillOpen() && m_algorithm == Account::Algorithm::Hotp) {
|
||||
m_counter = counter;
|
||||
recompute();
|
||||
if (!m_is_still_alive) {
|
||||
qCDebug(logger)
|
||||
<< "Ignoring counter update for account:" << m_id
|
||||
<< "Object marked for death";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
if (!m_storage->isStillOpen()) {
|
||||
qCDebug(logger)
|
||||
<< "Ignoring counter update for account:" << m_id
|
||||
<< "Storage no longer open";
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_algorithm != Account::Algorithm::Hotp) {
|
||||
qCDebug(logger)
|
||||
<< "Ignoring counter update for account:" << m_id
|
||||
<< "Algorithm not applicable:" << m_algorithm;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Counter is updated for account:" << m_id;
|
||||
m_counter = counter;
|
||||
recompute();
|
||||
}
|
||||
|
||||
void AccountPrivate::acceptToken(QString token)
|
||||
{
|
||||
Q_Q(Account);
|
||||
if (m_is_still_alive && m_storage->isStillOpen()) {
|
||||
m_token = token;
|
||||
Q_EMIT q->tokenChanged(m_token);
|
||||
if (!m_is_still_alive) {
|
||||
qCDebug(logger)
|
||||
<< "Ignoring token update for account:" << m_id
|
||||
<< "Object marked for death";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
if (!m_storage->isStillOpen()) {
|
||||
qCDebug(logger)
|
||||
<< "Ignoring token update for account:" << m_id
|
||||
<< "Storage no longer open";
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Token is updated for account:" << m_id;
|
||||
m_token = token;
|
||||
Q_EMIT q->tokenChanged(m_token);
|
||||
}
|
||||
|
||||
void AccountPrivate::recompute(void)
|
||||
{
|
||||
Q_Q(Account);
|
||||
if (m_is_still_alive && m_storage->isStillOpen()) {
|
||||
ComputeHotp *hotpJob = nullptr;
|
||||
ComputeTotp *totpJob = nullptr;
|
||||
|
||||
switch (m_algorithm) {
|
||||
case Account::Algorithm::Hotp:
|
||||
hotpJob = new ComputeHotp(m_secret, m_counter, m_tokenLength, m_offset, m_checksum);
|
||||
m_actions->queueAndProceed(hotpJob, [hotpJob, q, this](void) -> void {
|
||||
new HandleTokenUpdate(this, hotpJob, q);
|
||||
});
|
||||
break;
|
||||
case Account::Algorithm::Totp:
|
||||
totpJob = new ComputeTotp(m_secret, m_epoch, m_timeStep, m_tokenLength, m_hash);
|
||||
m_actions->queueAndProceed(totpJob, [totpJob, q, this](void) -> void
|
||||
{
|
||||
new HandleTokenUpdate(this, totpJob, q);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!m_is_still_alive) {
|
||||
qCDebug(logger)
|
||||
<< "Will not recompute token for account:" << m_id
|
||||
<< "Object marked for death";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_storage->isStillOpen()) {
|
||||
qCDebug(logger)
|
||||
<< "Will not recompute token for account:" << m_id
|
||||
<< "Storage no longer open";
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Requesting recomputed token for account:" << m_id;
|
||||
ComputeHotp *hotpJob = nullptr;
|
||||
ComputeTotp *totpJob = nullptr;
|
||||
|
||||
switch (m_algorithm) {
|
||||
case Account::Algorithm::Hotp:
|
||||
hotpJob = new ComputeHotp(m_secret, m_counter, m_tokenLength, m_offset, m_checksum);
|
||||
m_actions->queueAndProceed(hotpJob, [hotpJob, q, this](void) -> void {
|
||||
new HandleTokenUpdate(this, hotpJob, q);
|
||||
});
|
||||
break;
|
||||
case Account::Algorithm::Totp:
|
||||
totpJob = new ComputeTotp(m_secret, m_epoch, m_timeStep, m_tokenLength, m_hash);
|
||||
m_actions->queueAndProceed(totpJob, [totpJob, q, this](void) -> void
|
||||
{
|
||||
new HandleTokenUpdate(this, totpJob, q);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "unknown algorithm value");
|
||||
break;
|
||||
}
|
||||
// TODO: warn if not
|
||||
}
|
||||
|
||||
void AccountPrivate::remove(void)
|
||||
{
|
||||
if (m_is_still_alive && m_storage->isStillOpen()) {
|
||||
QSet<QString> self;
|
||||
self.insert(m_name);
|
||||
m_storage->removeAccounts(self);
|
||||
if (!m_is_still_alive) {
|
||||
qCDebug(logger)
|
||||
<< "Will not remove account:" << m_id
|
||||
<< "Object marked for death";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
if (!m_storage->isStillOpen()) {
|
||||
qCDebug(logger)
|
||||
<< "Will not remove account:" << m_id
|
||||
<< "Storage no longer open";
|
||||
return;
|
||||
}
|
||||
|
||||
QSet<QString> self;
|
||||
self.insert(m_name);
|
||||
m_storage->removeAccounts(self);
|
||||
}
|
||||
|
||||
void AccountPrivate::markForRemoval(void)
|
||||
|
@ -166,14 +244,20 @@ namespace accounts
|
|||
QVector<QString> AccountStoragePrivate::activeAccounts(void) const
|
||||
{
|
||||
QVector<QString> active;
|
||||
if (!m_is_still_open) {
|
||||
qCDebug(logger) << "Not returning accounts: account storage no longer open";
|
||||
return active;
|
||||
}
|
||||
|
||||
if (m_is_still_open) {
|
||||
const QList<QString> all = m_names.keys();
|
||||
for (const QString &account : all) {
|
||||
if (m_accountsPrivate[m_names[account]]->isStillAlive()) {
|
||||
active.append(account);
|
||||
}
|
||||
// TODO: log if not
|
||||
const QList<QString> all = m_names.keys();
|
||||
for (const QString &account : all) {
|
||||
const QUuid id = m_names[account];
|
||||
if (m_accountsPrivate[id]->isStillAlive()) {
|
||||
active.append(account);
|
||||
} else {
|
||||
qCDebug(logger)
|
||||
<< "Not returning account:" << id
|
||||
<< "Object marked for death";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,7 +271,12 @@ namespace accounts
|
|||
|
||||
bool AccountStoragePrivate::isNameStillAvailable(const QString &name) const
|
||||
{
|
||||
return m_is_still_open && !m_names.contains(name);
|
||||
if (!m_is_still_open) {
|
||||
qCDebug(logger) << "Pretending no name is available: account storage no longer open";
|
||||
return false;
|
||||
}
|
||||
|
||||
return !m_names.contains(name);
|
||||
}
|
||||
|
||||
bool AccountStoragePrivate::contains(const QString &account) const
|
||||
|
@ -197,13 +286,28 @@ namespace accounts
|
|||
* This lets the behaviour of get() and contains() be mutually consistent
|
||||
* without having to hand out pointers which may be about to go stale in get()
|
||||
*/
|
||||
return m_is_still_open && m_names.contains(account) && m_accountsPrivate[m_names[account]]->isStillAlive();
|
||||
// TODO: warn if not still open, log if account not alive
|
||||
if (!m_is_still_open) {
|
||||
qCDebug(logger) << "Pretending no account exists: account storage no longer open";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_names.contains(account)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QUuid id = m_names[account];
|
||||
if (!m_accountsPrivate[id]->isStillAlive()) {
|
||||
qCDebug(logger)
|
||||
<< "Pretending account does not exist:" << id
|
||||
<< "Object marked for death";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Account * AccountStoragePrivate::get(const QString &account) const
|
||||
{
|
||||
// TODO: warn if not
|
||||
return contains(account) ? m_accounts[m_names[account]] : nullptr;
|
||||
}
|
||||
|
||||
|
@ -214,39 +318,89 @@ namespace accounts
|
|||
|
||||
void AccountStoragePrivate::removeAccounts(const QSet<QString> &accountNames)
|
||||
{
|
||||
if (m_is_still_open) {
|
||||
QSet<QUuid> ids;
|
||||
for (const QString &accountName : accountNames) {
|
||||
if (m_names.contains(accountName)) {
|
||||
const QUuid id = m_names[accountName];
|
||||
AccountPrivate *p = m_accountsPrivate[id];
|
||||
/*
|
||||
* Avoid doing anything with accounts which are already about to be removed from the maps
|
||||
*/
|
||||
if (p->isStillAlive()) {
|
||||
p->markForRemoval();
|
||||
ids.insert(id);
|
||||
}
|
||||
// TODO: log if not
|
||||
if (!m_is_still_open) {
|
||||
qCDebug(logger) << "Not removing accounts: account storage no longer open";
|
||||
return;
|
||||
}
|
||||
|
||||
QSet<QUuid> ids;
|
||||
for (const QString &accountName : accountNames) {
|
||||
if (m_names.contains(accountName)) {
|
||||
const QUuid id = m_names[accountName];
|
||||
AccountPrivate *p = m_accountsPrivate[id];
|
||||
/*
|
||||
* Avoid doing anything with accounts which are already about to be removed from the maps
|
||||
*/
|
||||
if (p->isStillAlive()) {
|
||||
p->markForRemoval();
|
||||
ids.insert(id);
|
||||
} else {
|
||||
qCDebug(logger)
|
||||
<< "Not removing account:" << id
|
||||
<< "Object marked for death";
|
||||
}
|
||||
}
|
||||
|
||||
DeleteAccounts *job = new DeleteAccounts(m_settings, ids);
|
||||
m_actions->queueAndProceed(job, [&ids, job, this](void) -> void
|
||||
{
|
||||
for (const QUuid &id : ids) {
|
||||
Account *account = m_accounts[id];
|
||||
QObject::connect(job, &DeleteAccounts::finished, account, &Account::removed);
|
||||
}
|
||||
});
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
DeleteAccounts *job = new DeleteAccounts(m_settings, ids);
|
||||
m_actions->queueAndProceed(job, [&ids, job, this](void) -> void
|
||||
{
|
||||
for (const QUuid &id : ids) {
|
||||
Account *account = m_accounts[id];
|
||||
QObject::connect(job, &DeleteAccounts::finished, account, &Account::removed);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AccountStoragePrivate::acceptAccountRemoval(const QString &accountName)
|
||||
{
|
||||
if (m_names.contains(accountName)) {
|
||||
if (!m_names.contains(accountName)) {
|
||||
qCDebug(logger) << "Not accepting account removal: account name unknown";
|
||||
return;
|
||||
}
|
||||
|
||||
const QUuid id = m_names[accountName];
|
||||
qCDebug(logger) << "Handling account cleanup for account:" << id;
|
||||
|
||||
Account *account = m_accounts[id];
|
||||
m_accounts.remove(id);
|
||||
m_accountsPrivate.remove(id);
|
||||
m_names.remove(accountName);
|
||||
m_ids.remove(id);
|
||||
QTimer::singleShot(0, account, &accounts::Account::deleteLater);
|
||||
}
|
||||
|
||||
void AccountStoragePrivate::dispose(const std::function<void(Null*)> &handler)
|
||||
{
|
||||
if (!m_is_still_open) {
|
||||
qCDebug(logger) << "Not disposing of storage: account storage no longer open";
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Disposing of storage";
|
||||
|
||||
m_is_still_open = false;
|
||||
Null *job = new Null();
|
||||
m_actions->queueAndProceed(job, [job, &handler](void) -> void
|
||||
{
|
||||
handler(job);
|
||||
});
|
||||
}
|
||||
|
||||
void AccountStoragePrivate::acceptDisposal(void)
|
||||
{
|
||||
Q_Q(AccountStorage);
|
||||
if (m_is_still_open) {
|
||||
qCDebug(logger) << "Ignoring disposal of storage: account storage is still open";
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Handling storage disposal";
|
||||
|
||||
for (const QString &accountName : m_names.keys()) {
|
||||
const QUuid id = m_names[accountName];
|
||||
qCDebug(logger) << "Handling account cleanup for account:" << id;
|
||||
|
||||
Account *account = m_accounts[id];
|
||||
m_accounts.remove(id);
|
||||
m_accountsPrivate.remove(id);
|
||||
|
@ -254,38 +408,7 @@ namespace accounts
|
|||
m_ids.remove(id);
|
||||
QTimer::singleShot(0, account, &accounts::Account::deleteLater);
|
||||
}
|
||||
// TODO: warn if not
|
||||
}
|
||||
|
||||
void AccountStoragePrivate::dispose(const std::function<void(Null*)> &handler)
|
||||
{
|
||||
if (m_is_still_open) {
|
||||
m_is_still_open = false;
|
||||
Null *job = new Null();
|
||||
m_actions->queueAndProceed(job, [job, &handler](void) -> void
|
||||
{
|
||||
handler(job);
|
||||
});
|
||||
}
|
||||
// TODO: warn if not
|
||||
}
|
||||
|
||||
void AccountStoragePrivate::acceptDisposal(void)
|
||||
{
|
||||
Q_Q(AccountStorage);
|
||||
if (!m_is_still_open) {
|
||||
for (const QString &accountName : m_names.keys()) {
|
||||
const QUuid id = m_names[accountName];
|
||||
Account *account = m_accounts[id];
|
||||
m_accounts.remove(id);
|
||||
m_accountsPrivate.remove(id);
|
||||
m_names.remove(accountName);
|
||||
m_ids.remove(id);
|
||||
QTimer::singleShot(0, account, &accounts::Account::deleteLater);
|
||||
}
|
||||
Q_EMIT q->disposed();
|
||||
}
|
||||
// TODO: warn if not
|
||||
Q_EMIT q->disposed();
|
||||
}
|
||||
|
||||
QUuid AccountStoragePrivate::generateId(const QString &name) const
|
||||
|
@ -301,53 +424,78 @@ namespace accounts
|
|||
{
|
||||
Q_UNUSED(offset);
|
||||
Q_UNUSED(addChecksum);
|
||||
if (m_is_still_open && isNameStillAvailable(name)) {
|
||||
QUuid id = generateId(name);
|
||||
if (checkHotpAccount(id, name, secret, tokenLength)) {
|
||||
m_ids.insert(id);
|
||||
SaveHotp *job = new SaveHotp(m_settings, id, name, secret, counter, tokenLength);
|
||||
m_actions->queueAndProceed(job, [job, &handler](void) -> void
|
||||
{
|
||||
handler(job);
|
||||
});
|
||||
}
|
||||
if (!m_is_still_open) {
|
||||
qCDebug(logger) << "Will not add new HOTP account: storage no longer open";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
if (!isNameStillAvailable(name)) {
|
||||
qCDebug(logger) << "Will not add new HOTP account: account name not available";
|
||||
return;
|
||||
}
|
||||
|
||||
QUuid id = generateId(name);
|
||||
if (!checkHotpAccount(id, name, secret, tokenLength)) {
|
||||
qCDebug(logger) << "Will not add new HOTP account: invalid account details";
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Requesting to store details for new HOTP account:" << id;
|
||||
|
||||
m_ids.insert(id);
|
||||
SaveHotp *job = new SaveHotp(m_settings, id, name, secret, counter, tokenLength);
|
||||
m_actions->queueAndProceed(job, [job, &handler](void) -> void
|
||||
{
|
||||
handler(job);
|
||||
});
|
||||
}
|
||||
|
||||
void AccountStoragePrivate::addTotp(const std::function<void(SaveTotp*)> &handler, const QString &name, const QString &secret, uint timeStep, int tokenLength, const QDateTime &epoch, Account::Hash hash)
|
||||
{
|
||||
Q_UNUSED(epoch);
|
||||
Q_UNUSED(hash);
|
||||
if (m_is_still_open && isNameStillAvailable(name)) {
|
||||
QUuid id = generateId(name);
|
||||
if (checkTotpAccount(id, name, secret, tokenLength, timeStep)) {
|
||||
m_ids.insert(id);
|
||||
SaveTotp *job = new SaveTotp(m_settings, id, name, secret, timeStep, tokenLength);
|
||||
m_actions->queueAndProceed(job, [job, &handler](void) -> void
|
||||
{
|
||||
handler(job);
|
||||
});
|
||||
}
|
||||
if (!m_is_still_open) {
|
||||
qCDebug(logger) << "Will not add new TOTP account: storage no longer open";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
if (!isNameStillAvailable(name)) {
|
||||
qCDebug(logger) << "Will not add new TOTP account: account name not available";
|
||||
return;
|
||||
}
|
||||
|
||||
QUuid id = generateId(name);
|
||||
if (!checkTotpAccount(id, name, secret, tokenLength, timeStep)) {
|
||||
qCDebug(logger) << "Will not add new TOTP account: invalid account details";
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(logger) << "Requesting to store details for new TOTP account:" << id;
|
||||
|
||||
m_ids.insert(id);
|
||||
SaveTotp *job = new SaveTotp(m_settings, id, name, secret, timeStep, tokenLength);
|
||||
m_actions->queueAndProceed(job, [job, &handler](void) -> void
|
||||
{
|
||||
handler(job);
|
||||
});
|
||||
}
|
||||
|
||||
void AccountStoragePrivate::load(const std::function<void(LoadAccounts*)> &handler)
|
||||
{
|
||||
if (m_is_still_open) {
|
||||
LoadAccounts *job = new LoadAccounts(m_settings);
|
||||
m_actions->queueAndProceed(job, [job, &handler](void) -> void
|
||||
{
|
||||
handler(job);
|
||||
});
|
||||
if (!m_is_still_open) {
|
||||
qCDebug(logger) << "Will not load accounts: storage no longer open";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
LoadAccounts *job = new LoadAccounts(m_settings);
|
||||
m_actions->queueAndProceed(job, [job, &handler](void) -> void
|
||||
{
|
||||
handler(job);
|
||||
});
|
||||
}
|
||||
|
||||
Account * AccountStoragePrivate::acceptHotpAccount(const QUuid &id, const QString &name, const QString &secret, quint64 counter, int tokenLength, int offset, bool addChecksum)
|
||||
{
|
||||
Q_Q(AccountStorage);
|
||||
qCDebug(logger) << "Registering HOTP account:" << id;
|
||||
const std::function<Account*(AccountPrivate*)> registration([this, q, &id](AccountPrivate *p) -> Account *
|
||||
{
|
||||
Account *account = new Account(p, q);
|
||||
|
@ -365,6 +513,7 @@ namespace accounts
|
|||
Account * AccountStoragePrivate::acceptTotpAccount(const QUuid &id, const QString &name, const QString &secret, uint timeStep, int tokenLength, const QDateTime &epoch, Account::Hash hash)
|
||||
{
|
||||
Q_Q(AccountStorage);
|
||||
qCDebug(logger) << "Registering TOTP account:" << id;
|
||||
const std::function<Account*(AccountPrivate*)> registration([this, q, &id](AccountPrivate *p) -> Account *
|
||||
{
|
||||
Account *account = new Account(p, q);
|
||||
|
@ -400,8 +549,11 @@ namespace accounts
|
|||
{
|
||||
if (m_accept_on_finish) {
|
||||
m_account->acceptCounter(m_counter);
|
||||
} else {
|
||||
qCWarning(logger)
|
||||
<< "Rejecting counter update for account:" << m_account->id()
|
||||
<< "Failed to save the updated account details to storage";
|
||||
}
|
||||
// TODO: warn if not
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,14 @@
|
|||
#include "validation.h"
|
||||
|
||||
#include "../base32/base32.h"
|
||||
#include "../logging_p.h"
|
||||
#include "../oath/oath.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
KEYSMITH_LOGGER(logger, ".accounts.actions")
|
||||
KEYSMITH_LOGGER(dispatcherLogger, ".accounts.dispatcher")
|
||||
|
||||
namespace accounts
|
||||
{
|
||||
AccountJob::AccountJob() : QObject()
|
||||
|
@ -55,6 +59,9 @@ namespace accounts
|
|||
void SaveHotp::run(void)
|
||||
{
|
||||
if (!checkHotpAccount(m_id, m_accountName, m_secret, m_tokenLength)) {
|
||||
qCDebug(logger)
|
||||
<< "Unable to save HOTP account:" << m_id
|
||||
<< "Invalid account details";
|
||||
Q_EMIT invalid();
|
||||
Q_EMIT finished();
|
||||
return;
|
||||
|
@ -63,11 +70,15 @@ namespace accounts
|
|||
const PersistenceAction act([this](QSettings &settings) -> void
|
||||
{
|
||||
if (!settings.isWritable()) {
|
||||
// TODO: warn if not
|
||||
qCWarning(logger)
|
||||
<< "Unable to save HOTP account:" << m_id
|
||||
<< "Storage not writable";
|
||||
Q_EMIT invalid();
|
||||
return;
|
||||
}
|
||||
|
||||
qCInfo(logger) << "Saving HOTP account:" << m_id;
|
||||
|
||||
const QString group = m_id.toString();
|
||||
settings.remove(group);
|
||||
settings.beginGroup(group);
|
||||
|
@ -91,7 +102,9 @@ namespace accounts
|
|||
void SaveTotp::run(void)
|
||||
{
|
||||
if (!checkTotpAccount(m_id, m_accountName, m_secret, m_tokenLength, m_timeStep)) {
|
||||
// TODO: warn if not
|
||||
qCDebug(logger)
|
||||
<< "Unable to save TOTP account:" << m_id
|
||||
<< "Invalid account details";
|
||||
Q_EMIT invalid();
|
||||
Q_EMIT finished();
|
||||
return;
|
||||
|
@ -100,11 +113,15 @@ namespace accounts
|
|||
const PersistenceAction act([this](QSettings &settings) -> void
|
||||
{
|
||||
if (!settings.isWritable()) {
|
||||
// TODO: warn if not
|
||||
qCWarning(logger)
|
||||
<< "Unable to save TOTP account:" << m_id
|
||||
<< "Storage not writable";
|
||||
Q_EMIT invalid();
|
||||
return;
|
||||
}
|
||||
|
||||
qCInfo(logger) << "Saving TOTP account:" << m_id;
|
||||
|
||||
const QString group = m_id.toString();
|
||||
settings.remove(group);
|
||||
settings.beginGroup(group);
|
||||
|
@ -130,11 +147,13 @@ namespace accounts
|
|||
const PersistenceAction act([this](QSettings &settings) -> void
|
||||
{
|
||||
if (!settings.isWritable()) {
|
||||
// TODO: warn if not
|
||||
qCWarning(logger) << "Unable to delete accounts: storage not writable";
|
||||
Q_EMIT invalid();
|
||||
return;
|
||||
}
|
||||
|
||||
qCInfo(logger) << "Deleting accounts";
|
||||
|
||||
for (const QUuid &id : m_ids) {
|
||||
settings.remove(id.toString());
|
||||
}
|
||||
|
@ -148,11 +167,15 @@ namespace accounts
|
|||
{
|
||||
const PersistenceAction act([this](QSettings &settings) -> void
|
||||
{
|
||||
qCInfo(logger, "Loading accounts from storage");
|
||||
const QStringList entries = settings.childGroups();
|
||||
for (const QString &group : entries) {
|
||||
const QUuid id(group);
|
||||
|
||||
if (id.isNull()) {
|
||||
qCDebug(logger)
|
||||
<< "Ignoring:" << group
|
||||
<< "Not an account section";
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -165,6 +188,7 @@ namespace accounts
|
|||
const int tokenLength = settings.value("pinLength").toInt(&ok);
|
||||
|
||||
if (!ok || (type != "hotp" && type != "totp")) {
|
||||
qCWarning(logger) << "Skipping invalid account:" << id;
|
||||
settings.endGroup();
|
||||
continue;
|
||||
}
|
||||
|
@ -173,6 +197,7 @@ namespace accounts
|
|||
ok = false;
|
||||
const uint timeStep = settings.value("timeStep").toUInt(&ok);
|
||||
if (ok && checkTotpAccount(id, accountName, secret, tokenLength, timeStep)) {
|
||||
qCInfo(logger) << "Found valid TOTP account:" << id;
|
||||
Q_EMIT foundTotp(
|
||||
id,
|
||||
accountName,
|
||||
|
@ -186,6 +211,7 @@ namespace accounts
|
|||
ok = false;
|
||||
const quint64 counter = settings.value("counter").toULongLong(&ok);
|
||||
if (ok && checkHotpAccount(id, accountName, secret, tokenLength)) {
|
||||
qCInfo(logger) << "Found valid HOTP account:" << id;
|
||||
Q_EMIT foundHotp(
|
||||
id,
|
||||
accountName,
|
||||
|
@ -212,15 +238,15 @@ namespace accounts
|
|||
void ComputeTotp::run(void)
|
||||
{
|
||||
if (!checkTotp(m_secret, m_tokenLength, m_timeStep)) {
|
||||
qCDebug(logger) << "Unable to compute TOTP token: invalid token details";
|
||||
Q_EMIT finished();
|
||||
// TODO warn about this
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<QByteArray> secret = base32::decode(m_secret);
|
||||
if (!secret.has_value()) {
|
||||
qCDebug(logger) << "Unable to compute TOTP token: unable to decode secret";
|
||||
Q_EMIT finished();
|
||||
// TODO warn about this
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -237,31 +263,32 @@ namespace accounts
|
|||
hash = QCryptographicHash::Sha1;
|
||||
break;
|
||||
default:
|
||||
qCDebug(logger) << "Unable to compute TOTP token: unknown hashing algorithm:" << m_hash;
|
||||
Q_EMIT finished();
|
||||
// TODO warn about this
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
const std::optional<oath::Algorithm> algorithm = oath::Algorithm::usingDynamicTruncation(hash, m_tokenLength);
|
||||
if (!algorithm) {
|
||||
qCDebug(logger) << "Unable to compute TOTP token: unable to set up truncation for token length:" << m_tokenLength;
|
||||
Q_EMIT finished();
|
||||
// TODO warn about this
|
||||
return;
|
||||
}
|
||||
|
||||
const std::optional<quint64> counter = oath::count(m_epoch, m_timeStep, m_clock);
|
||||
if (!counter) {
|
||||
qCDebug(logger) << "Unable to compute TOTP token: unable to count time steps";
|
||||
Q_EMIT finished();
|
||||
// TODO warn about this
|
||||
return;
|
||||
}
|
||||
|
||||
const std::optional<QString> token = algorithm->compute(*counter, secret->data(), secret->size());
|
||||
if (token) {
|
||||
Q_EMIT otp(*token);
|
||||
} else {
|
||||
qCDebug(logger) << "Failed to compute TOTP token";
|
||||
}
|
||||
// TODO warn if not
|
||||
|
||||
Q_EMIT finished();
|
||||
}
|
||||
|
@ -274,15 +301,15 @@ namespace accounts
|
|||
void ComputeHotp::run(void)
|
||||
{
|
||||
if (!checkHotp(m_secret, m_tokenLength)) {
|
||||
qCDebug(logger) << "Unable to compute HOTP token: invalid token details";
|
||||
Q_EMIT finished();
|
||||
// TODO warn about this
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<QByteArray> secret = base32::decode(m_secret);
|
||||
if (!secret.has_value()) {
|
||||
qCDebug(logger) << "Unable to compute HOTP token: unable to decode secret";
|
||||
Q_EMIT finished();
|
||||
// TODO warn about this
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -291,16 +318,17 @@ namespace accounts
|
|||
? oath::Algorithm::usingTruncationOffset(QCryptographicHash::Sha1, (uint) m_offset, encoder)
|
||||
: oath::Algorithm::usingDynamicTruncation(QCryptographicHash::Sha1, encoder);
|
||||
if (!algorithm) {
|
||||
qCDebug(logger) << "Unable to compute HOTP token: unable to set up truncation for token length:" << m_tokenLength;
|
||||
Q_EMIT finished();
|
||||
// TODO warn about this
|
||||
return;
|
||||
}
|
||||
|
||||
const std::optional<QString> token = algorithm->compute(m_counter, secret->data(), secret->size());
|
||||
if (token) {
|
||||
Q_EMIT otp(*token);
|
||||
} else {
|
||||
qCDebug(logger) << "Failed to compute HOTP token";
|
||||
}
|
||||
// TODO warn if not
|
||||
|
||||
Q_EMIT finished();
|
||||
}
|
||||
|
@ -317,6 +345,7 @@ namespace accounts
|
|||
void Dispatcher::queueAndProceed(AccountJob *job, const std::function<void(void)> &setup_callbacks)
|
||||
{
|
||||
if (job) {
|
||||
qCDebug(dispatcherLogger) << "Queuing job for dispatcher";
|
||||
job->moveToThread(m_thread);
|
||||
setup_callbacks();
|
||||
m_pending.append(job);
|
||||
|
@ -326,7 +355,11 @@ namespace accounts
|
|||
|
||||
void Dispatcher::dispatchNext(void)
|
||||
{
|
||||
qCDebug(dispatcherLogger) << "Handling request to dispatch next job";
|
||||
|
||||
if (!empty() && !m_current) {
|
||||
qCDebug(dispatcherLogger) << "Dispatching next job";
|
||||
|
||||
m_current = m_pending.takeFirst();
|
||||
QObject::connect(m_current, &AccountJob::finished, this, &Dispatcher::next);
|
||||
QObject::connect(this, &Dispatcher::dispatch, m_current, &AccountJob::run);
|
||||
|
@ -336,6 +369,8 @@ namespace accounts
|
|||
|
||||
void Dispatcher::next(void)
|
||||
{
|
||||
qCDebug(dispatcherLogger) << "Handling next continuation in dispatcher";
|
||||
|
||||
QObject *from = sender();
|
||||
AccountJob *job = from ? qobject_cast<AccountJob*>(from) : nullptr;
|
||||
if (job) {
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
#include "keysmith.h"
|
||||
#include "../logging_p.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QGuiApplication>
|
||||
|
||||
KEYSMITH_LOGGER(logger, ".app")
|
||||
|
||||
namespace app
|
||||
{
|
||||
Keysmith::Keysmith(QObject *parent): QObject(parent), m_storage(nullptr)
|
||||
|
@ -15,7 +18,7 @@ namespace app
|
|||
|
||||
Keysmith::~Keysmith()
|
||||
{
|
||||
//TODO: log about this
|
||||
qCDebug(logger) << "Tearing down Keysmith application; requesting disposal of account storage";
|
||||
if (m_storage) {
|
||||
m_storage->dispose();
|
||||
}
|
||||
|
@ -24,10 +27,12 @@ namespace app
|
|||
void Keysmith::copyToClipboard(const QString &text)
|
||||
{
|
||||
QClipboard * clipboard = QGuiApplication::clipboard();
|
||||
if (clipboard) {
|
||||
clipboard->setText(text);
|
||||
if (!clipboard) {
|
||||
qCWarning(logger) << "Unable to copy text: clipboard not available";
|
||||
return;
|
||||
}
|
||||
// TODO warn about this
|
||||
|
||||
clipboard->setText(text);
|
||||
}
|
||||
|
||||
model::SimpleAccountListModel * Keysmith::accountListModel(void)
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
* SPDX-FileCopyrightText: 2019-2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
#include "base32.h"
|
||||
#include "../logging_p.h"
|
||||
|
||||
KEYSMITH_LOGGER(logger, ".base32")
|
||||
|
||||
static const QChar alphaMinLowerCase(QLatin1Char('a'));
|
||||
static const QChar alphaMaxLowerCase(QLatin1Char('z'));
|
||||
|
@ -47,11 +50,12 @@ static std::optional<quint64> decode(const QString &encoded, int index)
|
|||
quint64 result = 0ULL;
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
std::optional<int> v = decode(encoded[index + i]);
|
||||
const QChar inputChar = encoded[index + i];
|
||||
std::optional<int> v = decode(inputChar);
|
||||
if (v) {
|
||||
result = (result << 5) | *v;
|
||||
} else {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Not a valid base32 character:" << inputChar;
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
@ -229,19 +233,19 @@ namespace base32
|
|||
{
|
||||
int max = until == -1 ? encoded.size() : until;
|
||||
if (!checkInputRange(encoded, from, max)) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Invalid input range from:" << from << "until:" << until << "implied limit:" << max;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<int> padding = isBase32(encoded, from, max);
|
||||
if (!padding) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Unable to decode: input range is not valid base32";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t needed = requiredCapacity(*padding, from, max);
|
||||
if (outlen < needed) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Unable to decode: required capacity:" << needed << "exceeds allocated output buffer size:" << outlen;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -265,7 +269,7 @@ namespace base32
|
|||
std::optional<size_t> capacity = validate(encoded);
|
||||
|
||||
if (!capacity) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Unable to decode input: invalid base32";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -274,8 +278,9 @@ namespace base32
|
|||
decoded.resize((int) *capacity);
|
||||
if (decode(encoded, decoded.data(), *capacity)) {
|
||||
result.emplace(decoded);
|
||||
} else {
|
||||
qCDebug(logger) << "Failed to decode base32";
|
||||
}
|
||||
// TODO warn if not
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
|
||||
*/
|
||||
#include "hmac.h"
|
||||
#include "../logging_p.h"
|
||||
|
||||
KEYSMITH_LOGGER(logger, ".hmac")
|
||||
|
||||
static QByteArray hmac_stage(QCryptographicHash::Algorithm algorithm, char * const keyBuf, int ksize, int blockSize, const char fillPad, const char xorKey, const QByteArray &message)
|
||||
{
|
||||
|
@ -98,12 +101,14 @@ namespace hmac
|
|||
|
||||
std::optional<int> maybeBlockSize = blockSize(algorithm);
|
||||
if (!maybeBlockSize) {
|
||||
// TODO warn
|
||||
qCDebug(logger) << "Unable to determine block size for hashing algorithm:" << algorithm;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!validateKeySize(algorithm, ksize, requireSaneKeyLength)) {
|
||||
// TODO warn
|
||||
qCDebug(logger)
|
||||
<< "Invalid HMAC key size:" << ksize << "for hashing algorithm:" << algorithm
|
||||
<< "Sane key length requirements apply:" << requireSaneKeyLength;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,31 +4,35 @@
|
|||
*/
|
||||
#include "accounts.h"
|
||||
|
||||
#include "../logging_p.h"
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
KEYSMITH_LOGGER(logger, ".model.accounts")
|
||||
|
||||
namespace model
|
||||
{
|
||||
qint64 millisecondsLeftForToken(const QDateTime &epoch, uint timeStep, const std::function<qint64(void)> &clock)
|
||||
{
|
||||
QDateTime now = QDateTime::fromMSecsSinceEpoch(clock());
|
||||
if (epoch.isValid() && now.isValid() && timeStep > 0) {
|
||||
/*
|
||||
* Avoid integer overflow by casting to the wider type first before multiplying.
|
||||
* Not likely to happen 'in the wild', but good practice nevertheless
|
||||
*/
|
||||
qint64 step = ((qint64) timeStep) * 1000LL;
|
||||
|
||||
qint64 diff = epoch.msecsTo(now);
|
||||
|
||||
/*
|
||||
* Compensate for the fact that % operator is not the same as mathematical mod in case diff is negative.
|
||||
* diff is negative when the given epoch is in the 'future' compared to the current clock value.
|
||||
*/
|
||||
return diff < 0 ? - (diff % step) : step - (diff % step);
|
||||
if (!epoch.isValid() || !now.isValid() || timeStep == 0) {
|
||||
qCDebug(logger) << "Unable to compute milliseconds left: invalid arguments";
|
||||
return -1;
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
return -1;
|
||||
/*
|
||||
* Avoid integer overflow by casting to the wider type first before multiplying.
|
||||
* Not likely to happen 'in the wild', but good practice nevertheless
|
||||
*/
|
||||
qint64 step = ((qint64) timeStep) * 1000LL;
|
||||
|
||||
qint64 diff = epoch.msecsTo(now);
|
||||
|
||||
/*
|
||||
* Compensate for the fact that % operator is not the same as mathematical mod in case diff is negative.
|
||||
* diff is negative when the given epoch is in the 'future' compared to the current clock value.
|
||||
*/
|
||||
return diff < 0 ? - (diff % step) : step - (diff % step);
|
||||
}
|
||||
|
||||
AccountView::AccountView(accounts::Account *model, QObject *parent) : QObject(parent), m_model(model)
|
||||
|
@ -72,11 +76,12 @@ namespace model
|
|||
|
||||
qint64 AccountView::millisecondsLeftForToken(void) const
|
||||
{
|
||||
if (isTotp()) {
|
||||
return model::millisecondsLeftForToken(m_model->epoch(), m_model->timeStep());
|
||||
if (!isTotp()) {
|
||||
qCDebug(logger) << "Unable to compute milliseconds left for token, wrong account type:" << m_model->algorithm();
|
||||
return -1;
|
||||
}
|
||||
// TODO: warn if not
|
||||
return -1;
|
||||
|
||||
return model::millisecondsLeftForToken(m_model->epoch(), m_model->timeStep());
|
||||
}
|
||||
|
||||
SimpleAccountListModel::SimpleAccountListModel(accounts::AccountStorage *storage, QObject *parent) : QAbstractListModel(parent), m_storage(storage), m_index(QVector<QString>())
|
||||
|
@ -91,8 +96,9 @@ namespace model
|
|||
m_index.append(name);
|
||||
m_accounts[name] = existingAccount;
|
||||
existingAccount->recompute();
|
||||
} else {
|
||||
qCDebug(logger) << "Account storage reported an account (name) but did not yield a valid account object";
|
||||
}
|
||||
// TODO: warn if not
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
@ -117,27 +123,29 @@ namespace model
|
|||
QVariant SimpleAccountListModel::data(const QModelIndex &account, int role) const
|
||||
{
|
||||
if (!account.isValid()) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Not returning any data, model index is invalid";
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int accountIndex = account.row();
|
||||
if (accountIndex < 0 || m_index.size() < accountIndex) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Not returning any data, model index is out of bounds:" << accountIndex << "model size is:" << m_index.size();
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (role == NonStandardRoles::AccountRole) {
|
||||
const QString accountName = m_index.at(accountIndex);
|
||||
accounts::Account * model = m_accounts.value(accountName, nullptr);
|
||||
if (model) {
|
||||
// assume QML ownership: don't worry about object lifecycle
|
||||
return QVariant::fromValue(new AccountView(model));
|
||||
}
|
||||
if (role != NonStandardRoles::AccountRole) {
|
||||
qCDebug(logger) << "Not returning any data, unknown role:" << role;
|
||||
}
|
||||
|
||||
// TODO warn about this
|
||||
return QVariant();
|
||||
const QString accountName = m_index.at(accountIndex);
|
||||
accounts::Account * model = m_accounts.value(accountName, nullptr);
|
||||
if (model) {
|
||||
// assume QML ownership: don't worry about object lifecycle
|
||||
return QVariant::fromValue(new AccountView(model));
|
||||
} else {
|
||||
qCDebug(logger) << "Not returning any data, unable to find associated account model for:" << accountIndex;
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
int SimpleAccountListModel::rowCount(const QModelIndex &parent) const
|
||||
|
@ -149,33 +157,40 @@ namespace model
|
|||
void SimpleAccountListModel::added(const QString &account)
|
||||
{
|
||||
accounts::Account * newAccount = m_storage->get(account);
|
||||
if (newAccount) {
|
||||
if (m_accounts.contains(account)) {
|
||||
//TODO warn about this
|
||||
removed(account);
|
||||
}
|
||||
|
||||
int accountIndex = m_index.size();
|
||||
beginInsertRows(QModelIndex(), accountIndex, accountIndex);
|
||||
m_index.append(account);
|
||||
m_accounts[account] = newAccount;
|
||||
newAccount->recompute();
|
||||
endInsertRows();
|
||||
if (!newAccount) {
|
||||
qCDebug(logger) << "Unable to handle added account: underlying storage did not return a valid object";
|
||||
return;
|
||||
}
|
||||
// TODO: warn if not
|
||||
|
||||
if (m_accounts.contains(account)) {
|
||||
qCDebug(logger) << "Added account already/still part of the model: requesting removal of the old one from the model first";
|
||||
removed(account);
|
||||
}
|
||||
|
||||
int accountIndex = m_index.size();
|
||||
qCDebug(logger) << "Adding (new) account to the model at position:" << accountIndex;
|
||||
|
||||
beginInsertRows(QModelIndex(), accountIndex, accountIndex);
|
||||
m_index.append(account);
|
||||
m_accounts[account] = newAccount;
|
||||
newAccount->recompute();
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void SimpleAccountListModel::removed(const QString &account)
|
||||
{
|
||||
int accountIndex = m_index.indexOf(account);
|
||||
if (accountIndex >= 0) {
|
||||
qCDebug(logger) << "Removing (old) account from the model at position:" << accountIndex;
|
||||
|
||||
beginRemoveRows(QModelIndex(), accountIndex, accountIndex);
|
||||
m_index.remove(accountIndex);
|
||||
|
||||
m_accounts.remove(account);
|
||||
endRemoveRows();
|
||||
} else {
|
||||
qCDebug(logger) << "Unable to handle account removal: account not part of the model";
|
||||
}
|
||||
// TODO: warn if not
|
||||
}
|
||||
|
||||
bool SimpleAccountListModel::isNameStillAvailable(const QString &account) const
|
||||
|
@ -190,7 +205,7 @@ namespace model
|
|||
QValidator::State AccountNameValidator::validate(QString &input, int &pos) const
|
||||
{
|
||||
if (!m_accounts) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Unable to validat account name: missing accounts model object";
|
||||
return QValidator::Invalid;
|
||||
}
|
||||
|
||||
|
@ -213,7 +228,8 @@ namespace model
|
|||
if (accounts) {
|
||||
m_accounts = accounts;
|
||||
Q_EMIT accountsChanged();
|
||||
} else {
|
||||
qCDebug(logger) << "Ignoring new accounts model: not a valid object";
|
||||
}
|
||||
// TODO warn if not
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#include "oath.h"
|
||||
|
||||
#include "../hmac/hmac.h"
|
||||
#include "../logging_p.h"
|
||||
|
||||
KEYSMITH_LOGGER(logger, ".oath")
|
||||
|
||||
static QString encodeDefaults(quint32 value, uint tokenLength)
|
||||
{
|
||||
|
@ -100,17 +103,17 @@ namespace oath
|
|||
{
|
||||
std::optional<uint> digestSize = hmac::outputSize(algorithm);
|
||||
if (!digestSize) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Unable to determine digest size for algorithm:" << algorithm;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if ((*digestSize) < 20) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Digest is too small for dynamic truncation with algorithm:" << algorithm << "digest size:" << *digestSize << "needed:" << 20;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!validate(encoder)) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Invalid token encoder";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -122,17 +125,17 @@ namespace oath
|
|||
{
|
||||
std::optional<uint> digestSize = hmac::outputSize(algorithm);
|
||||
if (!digestSize) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Unable to determine digest size for algorithm:" << algorithm;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (offset >= ((*digestSize) - 4)) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Digest is too small for truncation offset:" << offset << "with algorithm:" << algorithm << "digest size:" << *digestSize << "needed:" << offset + 4;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!validate(encoder)) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Invalid token encoder";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -155,7 +158,9 @@ namespace oath
|
|||
}
|
||||
|
||||
if (!hmac::validateKeySize(m_algorithm, length, m_enforceKeyLength)) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger)
|
||||
<< "Invalid key size:" << length << "for algorithm:" << m_algorithm
|
||||
<< "Sane key length requirements apply:" << m_enforceKeyLength;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -172,8 +177,8 @@ namespace oath
|
|||
result = Encoder::reduceMod10(result, m_encoder.tokenLength());
|
||||
return std::optional<QString>(m_encoder.encode(result));
|
||||
}
|
||||
// TODO warn if not
|
||||
|
||||
qCDebug(logger) << "Failed to compute token";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -214,12 +219,12 @@ namespace oath
|
|||
qint64 now = clock();
|
||||
|
||||
if (now < epochMillis) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Unable to count time steps: epoch is in the future";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (timeStep == 0UL) {
|
||||
// TODO warn about this
|
||||
qCDebug(logger) << "Unable to count time steps: invalid step size:" << timeStep;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue