File indexing completed on 2024-04-28 05:50:06
0001 /* 0002 * SPDX-License-Identifier: GPL-3.0-or-later 0003 * SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com> 0004 */ 0005 #include "account_p.h" 0006 #include "validation.h" 0007 0008 #include "../logging_p.h" 0009 0010 #include <QObject> 0011 #include <QTimer> 0012 0013 KEYSMITH_LOGGER(logger, ".accounts.account_p") 0014 0015 namespace accounts 0016 { 0017 QUuid AccountPrivate::id(void) const 0018 { 0019 return m_id; 0020 } 0021 0022 std::optional<uint> AccountPrivate::offset(void) const 0023 { 0024 return m_offset; 0025 } 0026 0027 QString AccountPrivate::name(void) const 0028 { 0029 return m_name; 0030 } 0031 0032 QString AccountPrivate::issuer(void) const 0033 { 0034 return m_issuer; 0035 } 0036 0037 QString AccountPrivate::token(void) const 0038 { 0039 return m_token; 0040 } 0041 0042 quint64 AccountPrivate::counter(void) const 0043 { 0044 return m_counter; 0045 } 0046 0047 QDateTime AccountPrivate::epoch(void) const 0048 { 0049 return m_epoch; 0050 } 0051 0052 uint AccountPrivate::timeStep(void) const 0053 { 0054 return m_timeStep; 0055 } 0056 0057 Account::Hash AccountPrivate::hash(void) const 0058 { 0059 return m_hash; 0060 } 0061 0062 Account::Algorithm AccountPrivate::algorithm(void) const 0063 { 0064 return m_algorithm; 0065 } 0066 0067 int AccountPrivate::tokenLength(void) const 0068 { 0069 return m_tokenLength; 0070 } 0071 0072 bool AccountPrivate::checksum(void) const 0073 { 0074 return m_checksum; 0075 } 0076 0077 void AccountPrivate::setCounter(quint64 counter) 0078 { 0079 Q_Q(Account); 0080 if (!m_is_still_alive) { 0081 qCDebug(logger) 0082 << "Will not set counter for account:" << m_id 0083 << "Object marked for death"; 0084 return; 0085 } 0086 0087 if (!m_storage->isStillOpen()) { 0088 qCDebug(logger) 0089 << "Will not set counter for account:" << m_id 0090 << "Storage no longer open"; 0091 return; 0092 } 0093 0094 if (m_algorithm != Account::Algorithm::Hotp) { 0095 qCDebug(logger) 0096 << "Will not set counter for account:" << m_id 0097 << "Algorithm not applicable:" << m_algorithm; 0098 return; 0099 } 0100 0101 qCDebug(logger) << "Requesting to store updated details for account:" << m_id; 0102 SaveHotp *job = new SaveHotp(m_storage->settings(), 0103 m_id, m_name, m_issuer, m_secret, m_tokenLength, 0104 counter, m_offset, m_checksum); 0105 m_actions->queueAndProceed(job, [counter, job, q, this](void) -> void 0106 { 0107 new HandleCounterUpdate(this, m_storage, counter, job, q); 0108 }); 0109 } 0110 0111 void AccountPrivate::acceptCounter(quint64 counter) 0112 { 0113 Q_Q(Account); 0114 if (!m_is_still_alive) { 0115 qCDebug(logger) 0116 << "Ignoring counter update for account:" << m_id 0117 << "Object marked for death"; 0118 return; 0119 } 0120 0121 if (!m_storage->isStillOpen()) { 0122 qCDebug(logger) 0123 << "Ignoring counter update for account:" << m_id 0124 << "Storage no longer open"; 0125 return; 0126 } 0127 0128 if (m_algorithm != Account::Algorithm::Hotp) { 0129 qCDebug(logger) 0130 << "Ignoring counter update for account:" << m_id 0131 << "Algorithm not applicable:" << m_algorithm; 0132 return; 0133 } 0134 0135 if (m_counter != counter) { 0136 qCDebug(logger) << "Counter is updated for account:" << m_id; 0137 m_counter = counter; 0138 Q_EMIT q->updated(); 0139 recompute(); 0140 } 0141 } 0142 0143 void AccountPrivate::acceptTotpTokens(const QString &token, const QString &nextToken, 0144 const QDateTime &validFrom, const QDateTime &validUntil) 0145 { 0146 if (!m_is_still_alive) { 0147 qCDebug(logger) 0148 << "Ignoring token update for account:" << m_id 0149 << "Object marked for death"; 0150 return; 0151 } 0152 0153 if (!m_storage->isStillOpen()) { 0154 qCDebug(logger) 0155 << "Ignoring token update for account:" << m_id 0156 << "Storage no longer open"; 0157 return; 0158 } 0159 0160 m_nextToken = nextToken; 0161 m_nextTotpValidFrom = validFrom; 0162 m_nextTotpValidUntil = validUntil; 0163 setToken(token); 0164 } 0165 0166 void AccountPrivate::acceptHotpTokens(const QString &token, const QString &nextToken, quint64 nextCounter) 0167 { 0168 if (!m_is_still_alive) { 0169 qCDebug(logger) 0170 << "Ignoring token update for account:" << m_id 0171 << "Object marked for death"; 0172 return; 0173 } 0174 0175 if (!m_storage->isStillOpen()) { 0176 qCDebug(logger) 0177 << "Ignoring token update for account:" << m_id 0178 << "Storage no longer open"; 0179 return; 0180 } 0181 0182 m_nextToken = nextToken; 0183 m_nextCounter = nextCounter; 0184 setToken(token); 0185 } 0186 0187 void AccountPrivate::setToken(const QString &token) 0188 { 0189 Q_Q(Account); 0190 if (m_token != token) { 0191 qCDebug(logger) << "Token is updated for account:" << m_id; 0192 m_token = token; 0193 Q_EMIT q->tokenChanged(m_token); 0194 } 0195 } 0196 0197 void AccountPrivate::shiftTokens(void) 0198 { 0199 if (m_nextToken.isEmpty()) { 0200 qCDebug(logger) 0201 << "Not shifting to next token for account:" << m_id 0202 << "It is not yet available"; 0203 return; 0204 } 0205 0206 QDateTime now = QDateTime::currentDateTime(); 0207 switch (m_algorithm) { 0208 case Account::Algorithm::Hotp: 0209 if (m_counter != m_nextCounter) { 0210 qCDebug(logger) 0211 << "Not shifting to next token for account:" << m_id 0212 << "It is not valid anymore"; 0213 return; 0214 } 0215 break; 0216 case Account::Algorithm::Totp: 0217 if (now < m_nextTotpValidFrom || now > m_nextTotpValidUntil) { 0218 qCDebug(logger) 0219 << "Not shifting to next token for account:" << m_id 0220 << "It is not valid at this time"; 0221 return; 0222 } 0223 break; 0224 default: 0225 Q_ASSERT_X(false, Q_FUNC_INFO, "unknown algorithm value"); 0226 return; 0227 } 0228 0229 setToken(m_nextToken); 0230 } 0231 0232 void AccountPrivate::recompute(void) 0233 { 0234 Q_Q(Account); 0235 if (!m_is_still_alive) { 0236 qCDebug(logger) 0237 << "Will not recompute token for account:" << m_id 0238 << "Object marked for death"; 0239 return; 0240 } 0241 0242 if (!m_storage->isStillOpen()) { 0243 qCDebug(logger) 0244 << "Will not recompute token for account:" << m_id 0245 << "Storage no longer open"; 0246 return; 0247 } 0248 0249 shiftTokens(); 0250 0251 qCDebug(logger) << "Requesting recomputed tokens for account:" << m_id; 0252 ComputeHotp *hotpJob = nullptr; 0253 ComputeTotp *totpJob = nullptr; 0254 0255 switch (m_algorithm) { 0256 case Account::Algorithm::Hotp: 0257 hotpJob = new ComputeHotp(m_storage->secret(), m_secret, m_tokenLength, m_counter, m_offset, m_checksum); 0258 m_actions->queueAndProceed(hotpJob, [hotpJob, q, this](void) -> void { 0259 new HandleTokenUpdate(this, hotpJob, q); 0260 }); 0261 break; 0262 case Account::Algorithm::Totp: 0263 totpJob = new ComputeTotp(m_storage->secret(), m_secret, m_tokenLength, m_epoch, m_timeStep, m_hash); 0264 m_actions->queueAndProceed(totpJob, [totpJob, q, this](void) -> void 0265 { 0266 new HandleTokenUpdate(this, totpJob, q); 0267 }); 0268 break; 0269 default: 0270 Q_ASSERT_X(false, Q_FUNC_INFO, "unknown algorithm value"); 0271 break; 0272 } 0273 } 0274 0275 void AccountPrivate::remove(void) 0276 { 0277 if (!m_is_still_alive) { 0278 qCDebug(logger) 0279 << "Will not remove account:" << m_id 0280 << "Object marked for death"; 0281 return; 0282 } 0283 0284 if (!m_storage->isStillOpen()) { 0285 qCDebug(logger) 0286 << "Will not remove account:" << m_id 0287 << "Storage no longer open"; 0288 return; 0289 } 0290 0291 QSet<QString> self; 0292 self.insert(AccountPrivate::toFullName(m_name, m_issuer)); 0293 m_storage->removeAccounts(self); 0294 } 0295 0296 void AccountPrivate::markForRemoval(void) 0297 { 0298 m_is_still_alive = false; 0299 } 0300 0301 bool AccountPrivate::isStillAlive(void) const 0302 { 0303 return m_is_still_alive; 0304 } 0305 0306 AccountPrivate::AccountPrivate(const std::function<Account*(AccountPrivate*)> &account, 0307 AccountStoragePrivate *storage, Dispatcher *dispatcher, 0308 const QUuid id, const QString &name, const QString &issuer, 0309 const secrets::EncryptedSecret &secret, uint tokenLength, 0310 quint64 counter, const std::optional<uint> offset, bool addChecksum) : 0311 q_ptr(account(this)), m_storage(storage), m_actions(dispatcher), m_is_still_alive(true), 0312 m_algorithm(Account::Algorithm::Hotp), m_id(id), m_token(QString()), m_nextToken(QString()), 0313 m_nextTotpValidFrom(QDateTime::fromMSecsSinceEpoch(0)), // not a totp token so does not really matter 0314 m_nextTotpValidUntil(QDateTime::fromMSecsSinceEpoch(0)), // not a totp token so does not really matter 0315 m_nextCounter(1ULL), m_name(name), m_issuer(issuer), 0316 m_secret(secret), m_tokenLength(tokenLength), 0317 m_counter(counter), m_offset(offset), m_checksum(addChecksum), 0318 // not a totp token so these values don't really matter 0319 m_epoch(QDateTime::fromMSecsSinceEpoch(0)), m_timeStep(30), m_hash(Account::Hash::Sha1) 0320 { 0321 } 0322 0323 AccountPrivate::AccountPrivate(const std::function<Account*(AccountPrivate*)> &account, 0324 AccountStoragePrivate *storage, Dispatcher *dispatcher, 0325 const QUuid id, const QString &name, const QString &issuer, 0326 const secrets::EncryptedSecret &secret, uint tokenLength, 0327 const QDateTime &epoch, uint timeStep, Account::Hash hash) : 0328 q_ptr(account(this)), m_storage(storage), m_actions(dispatcher), m_is_still_alive(true), 0329 m_algorithm(Account::Algorithm::Totp), m_id(id), m_token(QString()), m_nextToken(QString()), 0330 m_nextTotpValidFrom(epoch), m_nextTotpValidUntil(epoch), 0331 m_nextCounter(0ULL), // not a hotp token so does not really matter 0332 m_name(name), m_issuer(issuer), m_secret(secret), m_tokenLength(tokenLength), 0333 // not a hotp token so these values don't really matter 0334 m_counter(0ULL), m_offset(std::nullopt), m_checksum(false), 0335 m_epoch(epoch), m_timeStep(timeStep), m_hash(hash) 0336 { 0337 } 0338 0339 QVector<QString> AccountStoragePrivate::activeAccounts(void) const 0340 { 0341 QVector<QString> active; 0342 if (!m_is_still_open) { 0343 qCDebug(logger) << "Not returning accounts: account storage no longer open"; 0344 return active; 0345 } 0346 0347 const QList<QString> all = m_names.keys(); 0348 for (const QString &account : all) { 0349 const QUuid id = m_names[account]; 0350 if (m_accountsPrivate[id]->isStillAlive()) { 0351 active.append(account); 0352 } else { 0353 qCDebug(logger) 0354 << "Not returning account:" << id 0355 << "Object marked for death"; 0356 } 0357 } 0358 0359 return active; 0360 } 0361 0362 bool AccountStoragePrivate::isStillOpen(void) const 0363 { 0364 return m_is_still_open; 0365 } 0366 0367 bool AccountStoragePrivate::isAccountStillAvailable(const QString &account) const 0368 { 0369 if (!m_is_still_open) { 0370 qCDebug(logger) << "Pretending no name is available: account storage no longer open"; 0371 return false; 0372 } 0373 0374 return !m_names.contains(account); 0375 } 0376 0377 QString AccountPrivate::toFullName(const QString &name, const QString &issuer) 0378 { 0379 return issuer.isEmpty() ? name : issuer + QLatin1Char(':') + name; 0380 } 0381 0382 bool AccountStoragePrivate::contains(const QString &account) const 0383 { 0384 /* 0385 * Pretend an account which is marked for removal is already fully purged 0386 * This lets the behaviour of get() and contains() be mutually consistent 0387 * without having to hand out pointers which may be about to go stale in get() 0388 */ 0389 if (!m_is_still_open) { 0390 qCDebug(logger) << "Pretending no account exists: account storage no longer open"; 0391 return false; 0392 } 0393 0394 if (!m_names.contains(account)) { 0395 return false; 0396 } 0397 0398 const QUuid id = m_names[account]; 0399 if (!m_accountsPrivate[id]->isStillAlive()) { 0400 qCDebug(logger) 0401 << "Pretending account does not exist:" << id 0402 << "Object marked for death"; 0403 return false; 0404 } 0405 0406 return true; 0407 } 0408 0409 Account * AccountStoragePrivate::get(const QString &account) const 0410 { 0411 return contains(account) ? m_accounts[m_names[account]] : nullptr; 0412 } 0413 0414 SettingsProvider AccountStoragePrivate::settings(void) const 0415 { 0416 return m_settings; 0417 } 0418 0419 AccountSecret * AccountStoragePrivate::secret(void) const 0420 { 0421 return m_secret; 0422 } 0423 0424 void AccountStoragePrivate::removeAccounts(const QSet<QString> &accountNames) 0425 { 0426 if (!m_is_still_open) { 0427 qCDebug(logger) << "Not removing accounts: account storage no longer open"; 0428 return; 0429 } 0430 0431 QSet<QUuid> ids; 0432 for (const QString &accountName : accountNames) { 0433 if (m_names.contains(accountName)) { 0434 const QUuid id = m_names[accountName]; 0435 AccountPrivate *p = m_accountsPrivate[id]; 0436 /* 0437 * Avoid doing anything with accounts which are already about to be removed from the maps 0438 */ 0439 if (p->isStillAlive()) { 0440 p->markForRemoval(); 0441 ids.insert(id); 0442 } else { 0443 qCDebug(logger) 0444 << "Not removing account:" << id 0445 << "Object marked for death"; 0446 } 0447 } 0448 } 0449 0450 DeleteAccounts *job = new DeleteAccounts(m_settings, ids); 0451 m_actions->queueAndProceed(job, [&ids, job, this](void) -> void 0452 { 0453 for (const QUuid &id : qAsConst(ids)) { 0454 Account *account = m_accounts[id]; 0455 QObject::connect(job, &DeleteAccounts::finished, account, &Account::removed); 0456 } 0457 }); 0458 } 0459 0460 void AccountStoragePrivate::acceptAccountRemoval(const QString &accountName) 0461 { 0462 if (!m_names.contains(accountName)) { 0463 qCDebug(logger) << "Not accepting account removal: account name unknown"; 0464 return; 0465 } 0466 0467 const QUuid id = m_names[accountName]; 0468 qCDebug(logger) << "Handling account cleanup for account:" << id; 0469 0470 Account *account = m_accounts[id]; 0471 m_accounts.remove(id); 0472 m_accountsPrivate.remove(id); 0473 m_names.remove(accountName); 0474 m_ids.remove(id); 0475 QTimer::singleShot(0, account, &accounts::Account::deleteLater); 0476 } 0477 0478 void AccountStoragePrivate::dispose(const std::function<void(Null*)> &handler) 0479 { 0480 if (!m_is_still_open) { 0481 qCDebug(logger) << "Not disposing of storage: account storage no longer open"; 0482 return; 0483 } 0484 0485 qCDebug(logger) << "Disposing of storage"; 0486 0487 m_is_still_open = false; 0488 Null *job = new Null(); 0489 m_secret->cancelRequests(); 0490 m_actions->queueAndProceed(job, [job, &handler](void) -> void 0491 { 0492 handler(job); 0493 }); 0494 } 0495 0496 void AccountStoragePrivate::acceptDisposal(void) 0497 { 0498 Q_Q(AccountStorage); 0499 if (m_is_still_open) { 0500 qCDebug(logger) << "Ignoring disposal of storage: account storage is still open"; 0501 return; 0502 } 0503 0504 qCDebug(logger) << "Handling storage disposal"; 0505 0506 const auto &names = m_names.keys(); 0507 for (const QString &accountName : names) { 0508 const QUuid id = m_names[accountName]; 0509 qCDebug(logger) << "Handling account cleanup for account:" << id; 0510 0511 Account *account = m_accounts[id]; 0512 m_accounts.remove(id); 0513 m_accountsPrivate.remove(id); 0514 m_names.remove(accountName); 0515 m_ids.remove(id); 0516 QTimer::singleShot(0, account, &accounts::Account::deleteLater); 0517 } 0518 QTimer::singleShot(0, m_secret, &accounts::AccountSecret::deleteLater); 0519 Q_EMIT q->disposed(); 0520 } 0521 0522 QUuid AccountStoragePrivate::generateId(const QString &name) const 0523 { 0524 QUuid attempt = QUuid::createUuidV5(QUuid(), name); 0525 while (attempt.isNull() || m_ids.contains(attempt)) { 0526 attempt = QUuid::createUuid(); 0527 } 0528 return attempt; 0529 } 0530 0531 std::optional<secrets::EncryptedSecret> AccountStoragePrivate::encrypt(const QString &secret) const 0532 { 0533 if (!m_is_still_open) { 0534 qCDebug(logger) << "Will not encrypt account secret: storage no longer open"; 0535 return std::nullopt; 0536 } 0537 0538 if (!m_secret || !m_secret->key()) { 0539 qCDebug(logger) << "Will not encrypt account secret: encryption key not available"; 0540 return std::nullopt; 0541 } 0542 0543 QScopedPointer<secrets::SecureMemory> decoded(secrets::decodeBase32(secret)); 0544 if (!decoded) { 0545 qCDebug(logger) << "Will not encrypt account secret: failed to decode base32"; 0546 return std::nullopt; 0547 } 0548 0549 return m_secret->encrypt(decoded.data()); 0550 } 0551 0552 bool AccountStoragePrivate::validateGenericNewToken(const QString &name, const QString &issuer, 0553 const QString &secret, uint tokenLength) const 0554 { 0555 return checkTokenLength(tokenLength) && checkName(name) && checkIssuer(issuer) 0556 && isAccountStillAvailable(AccountPrivate::toFullName(name, issuer)) && checkSecret(secret); 0557 } 0558 0559 bool AccountStoragePrivate::addHotp(const std::function<void(SaveHotp*)> &handler, 0560 const QString &name, const QString &issuer, 0561 const QString &secret, uint tokenLength, 0562 quint64 counter, const std::optional<uint> offset, bool checksum) 0563 { 0564 if (!m_is_still_open) { 0565 qCDebug(logger) << "Will not add new HOTP account: storage no longer open"; 0566 return false; 0567 } 0568 0569 if (!validateGenericNewToken(name, issuer, secret, tokenLength) || 0570 !checkOffset(offset, QCryptographicHash::Sha1)) { 0571 qCDebug(logger) << "Will not add new HOTP account: invalid account details"; 0572 return false; 0573 } 0574 0575 std::optional<secrets::EncryptedSecret> encryptedSecret = encrypt(secret); 0576 if (!encryptedSecret) { 0577 qCDebug(logger) << "Will not add new HOTP account: failed to encrypt secret"; 0578 return false; 0579 } 0580 0581 QUuid id = generateId(AccountPrivate::toFullName(name, issuer)); 0582 qCDebug(logger) << "Requesting to store details for new HOTP account:" << id; 0583 0584 m_ids.insert(id); 0585 SaveHotp *job = new SaveHotp(m_settings, id, name, issuer, *encryptedSecret, tokenLength, 0586 counter, offset, checksum); 0587 m_actions->queueAndProceed(job, [job, &handler](void) -> void 0588 { 0589 handler(job); 0590 }); 0591 return true; 0592 } 0593 0594 bool AccountStoragePrivate::addTotp(const std::function<void(SaveTotp*)> &handler, 0595 const QString &name, const QString &issuer, 0596 const QString &secret, uint tokenLength, 0597 uint timeStep, const QDateTime &epoch, Account::Hash hash) 0598 { 0599 if (!m_is_still_open) { 0600 qCDebug(logger) << "Will not add new TOTP account: storage no longer open"; 0601 return false; 0602 } 0603 0604 if (!validateGenericNewToken(name, issuer, secret, tokenLength) || 0605 !checkTimeStep(timeStep) || !checkEpoch(epoch)) { 0606 qCDebug(logger) << "Will not add new TOTP account: invalid account details"; 0607 return false; 0608 } 0609 0610 std::optional<secrets::EncryptedSecret> encryptedSecret = encrypt(secret); 0611 if (!encryptedSecret) { 0612 qCDebug(logger) << "Will not add new TOTP account: failed to encrypt secret"; 0613 return false; 0614 } 0615 0616 QUuid id = generateId(AccountPrivate::toFullName(name, issuer)); 0617 qCDebug(logger) << "Requesting to store details for new TOTP account:" << id; 0618 0619 m_ids.insert(id); 0620 SaveTotp *job = new SaveTotp(m_settings, id, name, issuer, *encryptedSecret, tokenLength, 0621 timeStep, epoch, hash); 0622 m_actions->queueAndProceed(job, [job, &handler](void) -> void 0623 { 0624 handler(job); 0625 }); 0626 return true; 0627 } 0628 0629 void AccountStoragePrivate::unlock(const std::function<void(RequestAccountPassword*)> &handler) 0630 { 0631 if (!m_is_still_open) { 0632 qCDebug(logger) << "Will not attempt to unlock accounts: storage no longer open"; 0633 return; 0634 } 0635 0636 qCDebug(logger) << "Requesting to unlock account storage"; 0637 RequestAccountPassword *job = new RequestAccountPassword(m_settings, m_secret); 0638 m_actions->queueAndProceed(job, [job, &handler](void) -> void 0639 { 0640 handler(job); 0641 }); 0642 } 0643 0644 void AccountStoragePrivate::load(const std::function<void(LoadAccounts*)> &handler) 0645 { 0646 if (!m_is_still_open) { 0647 qCDebug(logger) << "Will not load accounts: storage no longer open"; 0648 return; 0649 } 0650 0651 LoadAccounts *job = new LoadAccounts(m_settings, m_secret); 0652 m_actions->queueAndProceed(job, [job, &handler](void) -> void 0653 { 0654 handler(job); 0655 }); 0656 } 0657 0658 Account * AccountStoragePrivate::acceptHotpAccount(const QUuid id, const QString &name, const QString &issuer, 0659 const secrets::EncryptedSecret &secret, uint tokenLength, 0660 quint64 counter, const std::optional<uint> offset, bool checksum) 0661 { 0662 Q_Q(AccountStorage); 0663 qCDebug(logger) << "Registering HOTP account:" << id; 0664 const std::function<Account*(AccountPrivate*)> registration([this, q, &id](AccountPrivate *p) -> Account * 0665 { 0666 Account *account = new Account(p, q); 0667 m_accounts.insert(id, account); 0668 return account; 0669 }); 0670 m_ids.insert(id); 0671 m_names.insert(AccountPrivate::toFullName(name, issuer), id); 0672 const auto p = new AccountPrivate(registration, this, m_actions, 0673 id, name, issuer, secret, tokenLength, counter, offset, checksum); 0674 m_accountsPrivate.insert(id, p); 0675 0676 Q_ASSERT_X(m_accounts.contains(id), Q_FUNC_INFO, "account should have been registered"); 0677 return m_accounts[id]; 0678 } 0679 0680 Account * AccountStoragePrivate::acceptTotpAccount(const QUuid id, const QString &name, const QString &issuer, 0681 const secrets::EncryptedSecret &secret, uint tokenLength, 0682 uint timeStep, const QDateTime &epoch, Account::Hash hash) 0683 { 0684 Q_Q(AccountStorage); 0685 qCDebug(logger) << "Registering TOTP account:" << id; 0686 const std::function<Account*(AccountPrivate*)> registration([this, q, &id](AccountPrivate *p) -> Account * 0687 { 0688 Account *account = new Account(p, q); 0689 m_accounts.insert(id, account); 0690 return account; 0691 }); 0692 m_ids.insert(id); 0693 m_names.insert(AccountPrivate::toFullName(name, issuer), id); 0694 const auto p = new AccountPrivate(registration, this, m_actions, 0695 id, name, issuer, secret, tokenLength, epoch, timeStep, hash); 0696 m_accountsPrivate.insert(id, p); 0697 0698 Q_ASSERT_X(m_accounts.contains(id), Q_FUNC_INFO, "account should have been registered"); 0699 return m_accounts[id]; 0700 } 0701 0702 bool AccountStoragePrivate::isLoaded(void) const 0703 { 0704 return m_is_loaded; 0705 } 0706 0707 void AccountStoragePrivate::notifyLoaded(void) 0708 { 0709 Q_Q(AccountStorage); 0710 m_is_loaded = true; 0711 Q_EMIT q->loaded(); 0712 } 0713 0714 void AccountStoragePrivate::notifyError(void) 0715 { 0716 Q_Q(AccountStorage); 0717 m_has_error = true; 0718 Q_EMIT q->error(); 0719 } 0720 0721 void AccountStoragePrivate::clearError(void) 0722 { 0723 m_has_error = false; 0724 } 0725 0726 bool AccountStoragePrivate::hasError(void) const 0727 { 0728 return m_has_error; 0729 } 0730 0731 AccountStoragePrivate::AccountStoragePrivate(const SettingsProvider &settings, 0732 AccountSecret *secret, AccountStorage *storage, Dispatcher *dispatcher) : 0733 q_ptr(storage), m_is_loaded(false), m_has_error(false), m_is_still_open(true), 0734 m_actions(dispatcher), m_settings(settings), m_secret(secret) 0735 { 0736 } 0737 0738 HandleCounterUpdate::HandleCounterUpdate(AccountPrivate *account, AccountStoragePrivate *storage, 0739 quint64 counter, SaveHotp *job, QObject *parent) : 0740 QObject(parent), m_accept_on_finish(true), m_counter(counter), m_account(account), m_storage(storage) 0741 { 0742 QObject::connect(job, &SaveHotp::invalid, this, &HandleCounterUpdate::rejected); 0743 QObject::connect(job, &SaveHotp::finished, this, &HandleCounterUpdate::finished); 0744 } 0745 0746 void HandleCounterUpdate::rejected(void) 0747 { 0748 m_accept_on_finish = false; 0749 m_storage->notifyError(); 0750 } 0751 0752 void HandleCounterUpdate::finished(void) 0753 { 0754 if (m_accept_on_finish) { 0755 m_account->acceptCounter(m_counter); 0756 } else { 0757 qCWarning(logger) 0758 << "Rejecting counter update for account:" << m_account->id() 0759 << "Failed to save the updated account details to storage"; 0760 } 0761 deleteLater(); 0762 } 0763 0764 HandleTokenUpdate::HandleTokenUpdate(AccountPrivate *account, ComputeHotp *job, QObject *parent) : 0765 QObject(parent), m_account(account) 0766 { 0767 QObject::connect(job, &ComputeHotp::otp, this, &HandleTokenUpdate::hotp); 0768 QObject::connect(job, &ComputeHotp::finished, this, &HandleTokenUpdate::deleteLater); 0769 } 0770 0771 HandleTokenUpdate::HandleTokenUpdate(AccountPrivate *account, ComputeTotp *job, QObject *parent) : 0772 QObject(parent), m_account(account) 0773 { 0774 QObject::connect(job, &ComputeTotp::otp, this, &HandleTokenUpdate::totp); 0775 QObject::connect(job, &ComputeTotp::finished, this, &HandleTokenUpdate::deleteLater); 0776 } 0777 0778 void HandleTokenUpdate::totp(const QString &otp, const QString &nextOtp, const QDateTime &validFrom, 0779 const QDateTime &validUntil) 0780 { 0781 m_account->acceptTotpTokens(otp, nextOtp, validFrom, validUntil); 0782 } 0783 0784 void HandleTokenUpdate::hotp(const QString &otp, const QString &nextOtp, quint64 validUntil) 0785 { 0786 m_account->acceptHotpTokens(otp, nextOtp, validUntil); 0787 } 0788 }