QtPass Developer documentation
QtPass test coverage
Current view: top level - src/firstrunwizard.h Coverage Total Hit
Test: QtPass Lines: 100.0 % 5 5
Test Date: 2026-11-14 13:19:18 Functions: - 0 0

            Line data    Source code
       1              : // SPDX-FileCopyrightText: 2026 Anne Jan Brouwer
       2              : // SPDX-License-Identifier: GPL-3.0-or-later
       3              : /**
       4              :  * @file
       5              :  * @brief The first-run wizard and its four pages: programs, key, store and
       6              :  * summary.
       7              :  */
       8              : #ifndef SRC_FIRSTRUNWIZARD_H_
       9              : #define SRC_FIRSTRUNWIZARD_H_
      10              : 
      11              : #include "appsettings.h"
      12              : #include "userinfo.h"
      13              : #include <QList>
      14              : #include <QString>
      15              : #include <QWizard>
      16              : #include <QWizardPage>
      17              : 
      18              : class QCheckBox;
      19              : class QLabel;
      20              : class QLineEdit;
      21              : class QListWidget;
      22              : class QPushButton;
      23              : 
      24              : /**
      25              :  * @class FirstRunWizard
      26              :  * @ingroup ui
      27              :  * @brief The first start of QtPass: find GnuPG (and pass and Git), make sure
      28              :  * there is a secret key, pick or create the password store. Replaces the
      29              :  * chain of message boxes ConfigDialog::wizard() used to run before showing
      30              :  * the whole configuration dialog.
      31              :  *
      32              :  * The wizard works on a copy of the settings and writes it back on Finish,
      33              :  * after it has created and initialised the store when that was needed
      34              :  * (ProfileInit). Cancel leaves the settings as they were; the caller keeps
      35              :  * asking until the configuration is usable or the user gives up.
      36              :  */
      37              : class FirstRunWizard : public QWizard {
      38          167 :   Q_OBJECT
      39              : 
      40              : public:
      41              :   /**
      42              :    * @brief Build the wizard from the current settings.
      43              :    * @param parent The main window.
      44              :    */
      45              :   explicit FirstRunWizard(QWidget *parent = nullptr);
      46              : 
      47              :   /**
      48              :    * @brief The settings as the pages have edited them so far.
      49              :    * @return A copy.
      50              :    */
      51              :   auto settings() const -> AppSettings { return m_settings; }
      52              : 
      53              :   /**
      54              :    * @brief The secret keys gpg lists for @p gpgExecutable.
      55              :    * @param gpgExecutable The gpg binary.
      56              :    * @return The keys, or an empty list when gpg cannot run.
      57              :    */
      58              :   static auto secretKeys(const QString &gpgExecutable) -> QList<UserInfo>;
      59              : 
      60              :   /**
      61              :    * @brief Whether @p path points at an initialised store.
      62              :    * @param path A directory.
      63              :    * @return true when it holds a `.gpg-id`.
      64              :    */
      65              :   static auto isStore(const QString &path) -> bool;
      66              : 
      67              :   /// Page ids, in order.
      68              :   enum Page {
      69              :     IntroPage,    ///< What QtPass is and what the wizard will do.
      70              :     ProgramsPage, ///< ProgramsWizardPage: where gpg, pass and git are.
      71              :     KeyPage,      ///< KeyWizardPage: the secret keys, with generation.
      72              :     StorePage,    ///< StoreWizardPage: the store folder and the Git choice.
      73              :     DonePage      ///< DoneWizardPage: summary and two preferences.
      74              :   };
      75              : 
      76              :   /**
      77              :    * @brief Write the settings and, when the chosen store has no `.gpg-id`
      78              :    * yet, create and initialise it for the chosen keys first.
      79              :    */
      80              :   void accept() override;
      81              : 
      82              : private:
      83              :   /**
      84              :    * @brief Make @p store a password store for the ticked keys: create the
      85              :    * folder when it is missing, write and sign its `.gpg-id`, and set up Git
      86              :    * when chosen. On failure what was written is taken back, so a second
      87              :    * Finish runs the whole initialisation again.
      88              :    * @param store The folder, cleaned.
      89              :    * @return Whether the store is ready (the user was told otherwise).
      90              :    */
      91              :   auto initialiseStore(const QString &store) -> bool;
      92              :   /**
      93              :    * @brief Give an existing store the Git repository it was chosen to have.
      94              :    * @param store The folder, cleaned.
      95              :    * @return Whether the repository is ready (the user was told otherwise).
      96              :    */
      97              :   auto initialiseGit(const QString &store) -> bool;
      98              : 
      99              :   friend class ProgramsWizardPage;
     100              :   friend class KeyWizardPage;
     101              :   friend class StoreWizardPage;
     102              :   friend class DoneWizardPage;
     103              : 
     104              :   /// The pages' working copy of the settings, loaded in the constructor and
     105              :   /// saved by accept(); the pages edit it through their friend access.
     106              :   AppSettings m_settings;
     107              :   /// The secret keys as listed on the key page; the enabled ones become the
     108              :   /// recipients of a new store.
     109              :   QList<UserInfo> m_keys;
     110              : };
     111              : 
     112              : /**
     113              :  * @class ProgramsWizardPage
     114              :  * @ingroup ui
     115              :  * @brief Where gpg, pass and git are; gpg is required, the rest optional. A
     116              :  * stored path that no longer runs is replaced by what PATH has.
     117              :  */
     118              : class ProgramsWizardPage : public QWizardPage {
     119          166 :   Q_OBJECT
     120              : 
     121              : public:
     122              :   /**
     123              :    * @brief Build the page.
     124              :    * @param wizard Owner.
     125              :    */
     126              :   explicit ProgramsWizardPage(FirstRunWizard *wizard);
     127              :   /**
     128              :    * @brief Fill the fields from the settings (autodetection already ran).
     129              :    */
     130              :   void initializePage() override;
     131              :   /**
     132              :    * @brief Whether the gpg path points at something that can run.
     133              :    * @return true when gpg exists (or is a `wsl` command).
     134              :    */
     135              :   auto isComplete() const -> bool override;
     136              :   /**
     137              :    * @brief Store the paths and the pass/Git choices in the settings.
     138              :    * @return Always true; isComplete() gates Next.
     139              :    */
     140              :   auto validatePage() -> bool override;
     141              : 
     142              : private:
     143              :   FirstRunWizard *m_wizard; ///< Owner; its settings are what the page edits.
     144              :   QLineEdit *m_gpg;         ///< The gpg executable; required.
     145              :   QLineEdit *m_git;         ///< The git executable; optional.
     146              :   QLineEdit *m_pass;        ///< The pass executable; optional.
     147              :   QCheckBox *m_usePass;     ///< Run pass instead of gpg/git; needs m_pass.
     148              :   QLabel *m_gpgStatus;      ///< Under the gpg field: why it cannot be used.
     149              : 
     150              :   /**
     151              :    * @brief After an edit: say under the gpg field when it is missing or not
     152              :    * executable, allow "use pass" only for a runnable pass (unticking it
     153              :    * otherwise), and re-evaluate isComplete().
     154              :    */
     155              :   void updateStatus();
     156              : };
     157              : 
     158              : /**
     159              :  * @class KeyWizardPage
     160              :  * @ingroup ui
     161              :  * @brief The secret keys gpg knows; a new pair can be generated here. The
     162              :  * enabled ones become the recipients of a store that still has to be
     163              :  * initialised.
     164              :  */
     165              : class KeyWizardPage : public QWizardPage {
     166           72 :   Q_OBJECT
     167              : 
     168              : public:
     169              :   /**
     170              :    * @brief Build the page.
     171              :    * @param wizard Owner.
     172              :    */
     173              :   explicit KeyWizardPage(FirstRunWizard *wizard);
     174              :   /**
     175              :    * @brief List the secret keys for the gpg chosen on the previous page.
     176              :    */
     177              :   void initializePage() override;
     178              :   /**
     179              :    * @brief Always passable: an existing store needs no recipient choice
     180              :    * here (and its key may not be imported yet); the store page insists on a
     181              :    * ticked key when it has to initialise.
     182              :    * @return true.
     183              :    */
     184              :   auto isComplete() const -> bool override;
     185              :   /**
     186              :    * @brief Remember which keys are enabled.
     187              :    * @return Always true.
     188              :    */
     189              :   auto validatePage() -> bool override;
     190              : 
     191              : private:
     192              :   FirstRunWizard *m_wizard; ///< Owner; holds the key list this page fills.
     193              :   QListWidget *m_list;      ///< One checkable row per secret key.
     194              :   QPushButton *m_generate;  ///< Opens KeygenDialog.
     195              :   QLabel *m_status;         ///< Says so when gpg has no secret key yet.
     196              : 
     197              :   /**
     198              :    * @brief List the secret keys of the chosen gpg into the wizard and the
     199              :    * widget, ticking every usable key and greying out expired or invalid
     200              :    * ones.
     201              :    */
     202              :   void reload();
     203              :   /**
     204              :    * @brief Run KeygenDialog on a private ImitatePass built from the wizard's
     205              :    * settings, so the chosen gpg is used and nothing is saved, then reload().
     206              :    */
     207              :   void generate();
     208              : };
     209              : 
     210              : /**
     211              :  * @class StoreWizardPage
     212              :  * @ingroup ui
     213              :  * @brief The folder the passwords live in: an existing store is used as-is,
     214              :  * a folder without `.gpg-id` (or no folder) is initialised on Finish. The
     215              :  * Git box lives here because its sensible default depends on the folder: on
     216              :  * for a repository or a store still to be created, off for an existing
     217              :  * store that is no repository.
     218              :  */
     219              : class StoreWizardPage : public QWizardPage {
     220          143 :   Q_OBJECT
     221              : 
     222              : public:
     223              :   /**
     224              :    * @brief Build the page.
     225              :    * @param wizard Owner.
     226              :    */
     227              :   explicit StoreWizardPage(FirstRunWizard *wizard);
     228              :   /**
     229              :    * @brief Show the configured store path.
     230              :    */
     231              :   void initializePage() override;
     232              :   /**
     233              :    * @brief Whether a path is given and, for a folder that is not a store
     234              :    * yet, at least one key was ticked to encrypt it to.
     235              :    * @return true when Finish can do its job.
     236              :    */
     237              :   auto isComplete() const -> bool override;
     238              :   /**
     239              :    * @brief Store the path and the Git choice.
     240              :    * @return Always true.
     241              :    */
     242              :   auto validatePage() -> bool override;
     243              : 
     244              : private:
     245              :   FirstRunWizard *m_wizard; ///< Owner; its settings get the path and flag.
     246              :   QLineEdit *m_path;        ///< The store folder, in native separators.
     247              :   QCheckBox *m_useGit;      ///< Keep the store under Git; off without git.
     248              :   QLabel *m_status;         ///< What Finish will do with the folder.
     249              : 
     250              :   /**
     251              :    * @brief How many keys are ticked on the key page.
     252              :    * @return The number of enabled entries in the wizard's key list.
     253              :    */
     254              :   auto recipients() const -> int;
     255              :   /**
     256              :    * @brief After an edit: describe the folder (existing store with its
     257              :    * entry count, empty folder, not a store yet, missing) and ask for a
     258              :    * ticked key when it has to be initialised, then re-evaluate isComplete().
     259              :    */
     260              :   void updateStatus();
     261              : };
     262              : 
     263              : /**
     264              :  * @class DoneWizardPage
     265              :  * @ingroup ui
     266              :  * @brief Last page: a summary of what Finish will do and the two
     267              :  * preferences worth asking on day one.
     268              :  *
     269              :  * The summary names the store and says whether it is used as it is or set
     270              :  * up for the ticked keys, with or without Git. The two checkboxes are
     271              :  * "hide passwords until asked" and "show an icon in the system tray";
     272              :  * everything else is left to the settings dialog.
     273              :  */
     274              : class DoneWizardPage : public QWizardPage {
     275          151 :   Q_OBJECT
     276              : 
     277              : public:
     278              :   /**
     279              :    * @brief Build the page.
     280              :    * @param wizard Owner.
     281              :    */
     282              :   explicit DoneWizardPage(FirstRunWizard *wizard);
     283              :   /**
     284              :    * @brief Fill the summary from the settings.
     285              :    */
     286              :   void initializePage() override;
     287              :   /**
     288              :    * @brief Store the preferences.
     289              :    * @return Always true.
     290              :    */
     291              :   auto validatePage() -> bool override;
     292              : 
     293              : private:
     294              :   FirstRunWizard *m_wizard;  ///< Owner; its settings get the preferences.
     295              :   QLabel *m_summary;         ///< Store, what Finish does with it, gpg, mode.
     296              :   QCheckBox *m_hidePassword; ///< Show the password line as dots; on.
     297              :   QCheckBox *m_trayIcon;     ///< Tray icon; hidden when there is no tray.
     298              : };
     299              : 
     300              : #endif // SRC_FIRSTRUNWIZARD_H_
        

Generated by: LCOV version 2.0-1