File indexing completed on 2024-04-28 05:50:08

0001 /*
0002  * SPDX-License-Identifier: GPL-3.0-or-later
0003  * SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
0004  */
0005 #include "input.h"
0006 
0007 #include <QLocale>
0008 
0009 static QDateTime DEFAULT_EPOCH_VALUE = QDateTime::fromMSecsSinceEpoch(0, Qt::UTC);
0010 static QString DEFAULT_EPOCH = DEFAULT_EPOCH_VALUE.toString(Qt::ISODate);
0011 static QString DEFAULT_COUNTER = QLocale::c().toString(0ULL);
0012 
0013 namespace model
0014 {
0015 
0016     static accounts::Account::Hash toHash(AccountInput::TOTPAlgorithm algorithm)
0017     {
0018         switch(algorithm) {
0019         case AccountInput::TOTPAlgorithm::Sha1:
0020             return accounts::Account::Hash::Sha1;
0021         case AccountInput::TOTPAlgorithm::Sha256:
0022             return accounts::Account::Hash::Sha256;
0023         case AccountInput::TOTPAlgorithm::Sha512:
0024             return accounts::Account::Hash::Sha512;
0025         default:
0026             Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown/unsupported TOTP hashing algorithm?");
0027             return accounts::Account::Hash::Sha1;
0028         }
0029     }
0030 
0031     AccountInput::AccountInput(QObject *parent) :
0032         QObject(parent),
0033         m_type(TokenType::Totp), m_name(QString()), m_issuer(QString()), m_secret(QString()), m_tokenLength(6U),
0034         m_timeStep(30U), m_algorithm(TOTPAlgorithm::Sha1), m_epoch(DEFAULT_EPOCH), m_epochValue(DEFAULT_EPOCH_VALUE),
0035         m_checksum(false), m_counter(DEFAULT_COUNTER), m_counterValue(0ULL), m_truncation(std::nullopt)
0036     {
0037     }
0038 
0039     void AccountInput::reset(void)
0040     {
0041         setType(TokenType::Totp);
0042         setName(QString());
0043         setIssuer(QString());
0044         setSecret(QString());
0045         setTokenLength(6U);
0046         setTimeStep(30U);
0047         setAlgorithm(TOTPAlgorithm::Sha1);
0048         setEpoch(DEFAULT_EPOCH);
0049         setChecksum(false);
0050         setCounter(0ULL);
0051         setDynamicTruncation();
0052     }
0053 
0054     void AccountInput::createNewAccount(accounts::AccountStorage *storage) const
0055     {
0056         if (!storage) {
0057             Q_ASSERT_X(false, Q_FUNC_INFO, "Storage must be provided");
0058             return;
0059         }
0060 
0061         switch(m_type) {
0062         case Hotp:
0063             storage->addHotp(m_name, m_issuer, m_secret, m_tokenLength, m_counterValue, m_truncation, m_checksum);
0064             break;
0065         case Totp:
0066             storage->addTotp(m_name, m_issuer, m_secret, m_tokenLength, m_timeStep, m_epochValue, toHash(m_algorithm));
0067             break;
0068         default:
0069             Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown/unsupported token type?");
0070         }
0071     }
0072 
0073     AccountInput::TokenType AccountInput::type(void) const
0074     {
0075         return m_type;
0076     }
0077 
0078     void AccountInput::setType(model::AccountInput::TokenType type)
0079     {
0080         if (m_type != type) {
0081             m_type = type;
0082             Q_EMIT typeChanged();
0083         }
0084     }
0085 
0086     QString AccountInput::name(void) const
0087     {
0088         return m_name;
0089     }
0090 
0091     void AccountInput::setName(const QString &name)
0092     {
0093         if (m_name != name) {
0094             m_name = name;
0095             Q_EMIT nameChanged();
0096         }
0097     }
0098 
0099     QString AccountInput::issuer(void) const
0100     {
0101         return m_issuer;
0102     }
0103 
0104     void AccountInput::setIssuer(const QString &issuer)
0105     {
0106         if (m_issuer != issuer) {
0107             m_issuer = issuer;
0108             Q_EMIT issuerChanged();
0109         }
0110     }
0111 
0112     QString AccountInput::secret(void) const
0113     {
0114         return m_secret;
0115     }
0116 
0117     void AccountInput::setSecret(const QString &secret)
0118     {
0119         if (m_secret != secret) {
0120             m_secret = secret;
0121             Q_EMIT secretChanged();
0122         }
0123     }
0124 
0125     uint AccountInput::tokenLength(void) const
0126     {
0127         return m_tokenLength;
0128     }
0129 
0130     void AccountInput::setTokenLength(uint tokenLength)
0131     {
0132         if (m_tokenLength != tokenLength) {
0133             m_tokenLength = tokenLength;
0134             Q_EMIT tokenLengthChanged();
0135         }
0136     }
0137 
0138     uint AccountInput::timeStep(void) const
0139     {
0140         return m_timeStep;
0141     }
0142 
0143     void AccountInput::setTimeStep(uint timeStep)
0144     {
0145         if (m_timeStep != timeStep) {
0146             m_timeStep = timeStep;
0147             Q_EMIT timeStepChanged();
0148         }
0149     }
0150 
0151     AccountInput::TOTPAlgorithm AccountInput::algorithm(void) const
0152     {
0153         return m_algorithm;
0154     }
0155 
0156     void AccountInput::setAlgorithm(model::AccountInput::TOTPAlgorithm algorithm)
0157     {
0158         if (m_algorithm != algorithm) {
0159             m_algorithm = algorithm;
0160             Q_EMIT algorithmChanged();
0161         }
0162     }
0163 
0164     QString AccountInput::epoch(void) const
0165     {
0166         return m_epoch;
0167     }
0168 
0169     void AccountInput::setEpoch(const QString &epoch)
0170     {
0171         if (m_epoch != epoch) {
0172             m_epoch = epoch;
0173             m_epochValue = validators::parseDateTime(epoch).value_or(DEFAULT_EPOCH_VALUE);
0174             Q_EMIT epochChanged();
0175         }
0176     }
0177 
0178     bool AccountInput::checksum(void) const
0179     {
0180         return m_checksum;
0181     }
0182 
0183     void AccountInput::setChecksum(bool checksum)
0184     {
0185         if (m_checksum != checksum) {
0186             m_checksum = checksum;
0187             Q_EMIT checksumChanged();
0188         }
0189     }
0190 
0191     QString AccountInput::counter(void) const
0192     {
0193         return m_counter;
0194     }
0195 
0196     void AccountInput::setCounter(const QString &counter, validators::UnsignedLongValidator *validator)
0197     {
0198         if (!validator) {
0199             Q_ASSERT_X(false, Q_FUNC_INFO, "Validator must be provided");
0200             return;
0201         }
0202 
0203         if (m_counter != counter) {
0204             m_counter = counter;
0205             m_counterValue = validators::parseUnsignedInteger(counter, validator->locale()).value_or(0ULL);
0206             Q_EMIT counterChanged();
0207         }
0208     }
0209 
0210     void AccountInput::setCounter(quint64 counter)
0211     {
0212         if (m_counterValue != counter) {
0213             m_counter.setNum(counter);
0214             m_counterValue = counter;
0215             Q_EMIT counterChanged();
0216         }
0217     }
0218 
0219     uint AccountInput::truncationOffset(void) const
0220     {
0221         return m_truncation.value_or(0U);
0222     }
0223 
0224     void AccountInput::setTruncationOffset(uint truncationOffset)
0225     {
0226         if (!m_truncation || *m_truncation != truncationOffset) {
0227             m_truncation = std::optional<uint>(truncationOffset);
0228             Q_EMIT truncationChanged();
0229         }
0230     }
0231 
0232     bool AccountInput::fixedTruncation(void) const
0233     {
0234         return (bool) m_truncation;
0235     }
0236 
0237     void AccountInput::setDynamicTruncation(void)
0238     {
0239         if (m_truncation) {
0240             m_truncation = std::nullopt;
0241             Q_EMIT truncationChanged();
0242         }
0243     }
0244 }