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 #ifndef MODEL_ACCOUNTS_H
0006 #define MODEL_ACCOUNTS_H
0007 
0008 #include "input.h"
0009 #include "../account/account.h"
0010 #include "../validators/namevalidator.h"
0011 
0012 #include <QAbstractListModel>
0013 #include <QByteArray>
0014 #include <QHash>
0015 #include <QModelIndex>
0016 #include <QObject>
0017 #include <QSortFilterProxyModel>
0018 #include <QString>
0019 #include <QValidator>
0020 #include <QVector>
0021 
0022 #include <optional>
0023 
0024 namespace model
0025 {
0026     qint64 millisecondsLeftForToken(const QDateTime &epoch, uint timeStep,
0027                                     const std::function<qint64(void)> &clock = &QDateTime::currentMSecsSinceEpoch);
0028 
0029     class AccountView : public QObject
0030     {
0031         Q_OBJECT
0032         Q_PROPERTY(bool isHotp READ isHotp CONSTANT)
0033         Q_PROPERTY(bool isTotp READ isTotp CONSTANT)
0034         Q_PROPERTY(QString name READ name CONSTANT)
0035         Q_PROPERTY(QString token READ token NOTIFY tokenChanged)
0036         Q_PROPERTY(QString issuer READ issuer CONSTANT)
0037         Q_PROPERTY(quint64 counter READ counter NOTIFY tokenChanged)
0038         Q_PROPERTY(QDateTime epoch READ epoch CONSTANT)
0039         Q_PROPERTY(uint timeStep READ timeStep CONSTANT)
0040         Q_PROPERTY(uint offset READ offset CONSTANT)
0041         Q_PROPERTY(int tokenLength READ tokenLength CONSTANT)
0042         Q_PROPERTY(QString hash READ hash CONSTANT)
0043     public:
0044         explicit AccountView(accounts::Account *model, QObject *parent = nullptr);
0045         bool isHotp(void) const;
0046         bool isTotp(void) const;
0047         QString name(void) const;
0048         QString token(void) const;
0049         QString issuer(void) const;
0050         quint64 counter(void) const;
0051         QDateTime epoch(void) const;
0052         uint timeStep(void) const;
0053         uint offset(void) const;
0054         int tokenLength(void) const;
0055         QString hash(void) const;
0056         Q_INVOKABLE qint64 millisecondsLeftForToken(void) const;
0057     Q_SIGNALS:
0058         void tokenChanged(void);
0059         void remove(void);
0060         void recompute(void);
0061         void advanceCounter(quint64 by = 1ULL);
0062         void setCounter(quint64 value);
0063     private:
0064         accounts::Account * const m_model;
0065     };
0066 
0067     class SimpleAccountListModel: public QAbstractListModel
0068     {
0069         Q_OBJECT
0070         Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
0071         Q_PROPERTY(bool error READ error WRITE setError NOTIFY errorChanged)
0072     public:
0073         enum NonStandardRoles {
0074             AccountRole = Qt::ItemDataRole::UserRole
0075         };
0076         Q_ENUM(NonStandardRoles)
0077         enum TOTPAlgorithms {
0078             Sha1, Sha256, Sha512
0079         };
0080         Q_ENUM(TOTPAlgorithms)
0081     private:
0082         static accounts::Account::Hash toHash(const TOTPAlgorithms value);
0083     public:
0084         explicit SimpleAccountListModel(accounts::AccountStorage *storage, QObject *parent = nullptr);
0085         Q_INVOKABLE void addAccount(model::AccountInput *input);
0086         Q_INVOKABLE bool isAccountStillAvailable(const QString &name, const QString &issuer) const;
0087         Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0088         Q_INVOKABLE QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
0089         QHash<int, QByteArray> roleNames(void) const override;
0090     public:
0091         bool loaded(void) const;
0092         bool error(void) const;
0093         void setError(bool markAsError);
0094     Q_SIGNALS:
0095         void loadedChanged(void);
0096         void errorChanged(void);
0097     private Q_SLOTS:
0098         void added(const QString &account);
0099         void removed(const QString &removed);
0100         void handleError(void);
0101     private:
0102         AccountView * createView(const QString &name);
0103         void populate(const QString &name, AccountView *account);
0104     private:
0105         accounts::AccountStorage * const m_storage;
0106     private:
0107         bool m_has_error;
0108         QVector<QString> m_index;
0109         QHash<QString, AccountView*> m_accounts;
0110     };
0111 
0112     class SortedAccountsListModel: public QSortFilterProxyModel
0113     {
0114         Q_OBJECT
0115     public:
0116         explicit SortedAccountsListModel(QObject *parent = nullptr);
0117         void setSourceModel(QAbstractItemModel *sourceModel) override;
0118     protected:
0119         bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
0120     };
0121 
0122     class AccountNameValidator: public QValidator
0123     {
0124         Q_OBJECT
0125         Q_PROPERTY(QString issuer READ issuer WRITE setIssuer NOTIFY issuerChanged)
0126         Q_PROPERTY(model::SimpleAccountListModel * accounts READ accounts WRITE setAccounts NOTIFY accountsChanged)
0127         Q_PROPERTY(
0128             bool validateAvailability
0129             READ validateAvailability
0130             WRITE setValidateAvailability
0131             NOTIFY validateAvailabilityChanged
0132         )
0133     public:
0134         explicit AccountNameValidator(QObject *parent = nullptr);
0135         QValidator::State validate(QString &input, int &pos) const override;
0136         void fixup(QString &input) const override;
0137         bool validateAvailability(void) const;
0138         void setValidateAvailability(bool enabled);
0139         QString issuer(void) const;
0140         void setIssuer(const QString &issuer);
0141         SimpleAccountListModel * accounts(void) const;
0142         void setAccounts(SimpleAccountListModel *accounts);
0143     Q_SIGNALS:
0144         void issuerChanged(void);
0145         void accountsChanged(void);
0146         void validateAvailabilityChanged(void);
0147     private:
0148         bool m_validateAvailability;
0149         std::optional<QString> m_issuer;
0150         SimpleAccountListModel * m_accounts;
0151         const validators::NameValidator m_delegate;
0152     };
0153 }
0154 
0155 Q_DECLARE_METATYPE(model::AccountView *);
0156 Q_DECLARE_METATYPE(model::SimpleAccountListModel *);
0157 
0158 #endif