QtPass Developer documentation
QtPass test coverage
Current view: top level - src/qtpasssettings.cpp (source / functions) Coverage Total Hit
Test: QtPass Lines: 93.7 % 175 164
Test Date: 2026-11-14 13:19:18 Functions: 97.0 % 33 32

            Line data    Source code
       1              : // SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
       2              : // SPDX-License-Identifier: GPL-3.0-or-later
       3              : /**
       4              :  * @file
       5              :  * @brief Implements QtPassSettings; getInstance() picks the portable
       6              :  * `qtpass.ini` over the platform store, and getProfiles()/setProfiles()
       7              :  * read and write the `profile/<name>/` groups.
       8              :  */
       9              : #include "qtpasssettings.h"
      10              : #include "pass.h"
      11              : #include "passbackendfactory.h"
      12              : #include "settingsserializer.h"
      13              : 
      14              : #include "util.h"
      15              : 
      16              : #include <QCoreApplication>
      17              : #include <QCursor>
      18              : #include <QDebug>
      19              : #include <QDir>
      20              : #include <QFile>
      21              : #include <QFileInfo>
      22              : #include <QGuiApplication>
      23              : #include <QScreen>
      24              : #include <utility>
      25              : 
      26              : bool QtPassSettings::initialized = false;
      27              : 
      28              : QtPassSettings *QtPassSettings::m_instance = nullptr;
      29              : // Portable mode: a qtpass.ini next to the executable wins over the platform
      30              : // settings store.
      31         8332 : auto QtPassSettings::getInstance() -> QtPassSettings * {
      32         8332 :   if (!QtPassSettings::initialized) {
      33           15 :     QString portable_ini = QCoreApplication::applicationDirPath() +
      34           15 :                            QDir::separator() + "qtpass.ini";
      35           15 :     if (QFile(portable_ini).exists()) {
      36            0 :       m_instance = new QtPassSettings(portable_ini, QSettings::IniFormat);
      37              :     } else {
      38           15 :       m_instance = new QtPassSettings("IJHack", "QtPass");
      39              :     }
      40              : 
      41           15 :     initialized = true;
      42              :   }
      43              : 
      44         8332 :   return m_instance;
      45              : }
      46              : 
      47         2557 : auto QtPassSettings::load() -> AppSettings {
      48         2557 :   AppSettings s = SettingsSerializer::load(*getInstance());
      49         2557 :   if (!s.passStore.isEmpty()) {
      50         4260 :     s.passStore = QDir::cleanPath(QDir(s.passStore).absolutePath());
      51         2130 :     if (!s.passStore.endsWith('/'))
      52         2097 :       s.passStore += '/';
      53              :   }
      54         2557 :   return s;
      55            0 : }
      56              : 
      57          765 : void QtPassSettings::save(const AppSettings &settings) {
      58          765 :   SettingsSerializer::save(*getInstance(), settings);
      59              :   // The "use pass" mode may have changed; rebuild the backend on next use.
      60          765 :   PassBackendFactory::invalidate();
      61          765 : }
      62              : 
      63           13 : auto QtPassSettings::getPasswordConfiguration() -> PasswordConfiguration {
      64           13 :   return SettingsSerializer::loadPasswordConfiguration(*getInstance());
      65              : }
      66              : 
      67          276 : auto QtPassSettings::getProfiles() -> Profiles {
      68          276 :   getInstance()->beginGroup(SettingsConstants::profile);
      69          276 :   Profiles profiles;
      70              : 
      71              :   // migration from version <= v1.3.2: profiles datastructure
      72          276 :   QStringList childKeys = getInstance()->childKeys();
      73          276 :   for (const auto &key : std::as_const(childKeys)) {
      74            0 :     Profile profile;
      75            0 :     profile.path = getInstance()->value(key).toString();
      76            0 :     profiles.insert(key, profile);
      77              :   }
      78              :   // /migration from version <= v1.3.2
      79              : 
      80          276 :   QStringList childGroups = getInstance()->childGroups();
      81          335 :   for (const auto &group : std::as_const(childGroups)) {
      82           59 :     Profile profile;
      83          118 :     profile.path = getInstance()->value(group + "/path").toString();
      84          118 :     profile.signingKey = getInstance()->value(group + "/signingKey").toString();
      85           59 :     profile.useGit = Profile::flagFromString(
      86          118 :         getInstance()->value(group + "/useGit").toString());
      87           59 :     profile.autoPush = Profile::flagFromString(
      88          118 :         getInstance()->value(group + "/autoPush").toString());
      89           59 :     profile.autoPull = Profile::flagFromString(
      90          118 :         getInstance()->value(group + "/autoPull").toString());
      91           59 :     profiles.insert(group, profile);
      92              :   }
      93              : 
      94          276 :   getInstance()->endGroup();
      95              : 
      96          276 :   return profiles;
      97              : }
      98              : 
      99           84 : void QtPassSettings::setProfiles(const Profiles &profiles) {
     100              :   // "profile" is both the active-profile scalar (getProfile()) and the
     101              :   // profile/<name>/ group; remove() wipes both, which would switch the active
     102              :   // store on every save, so preserve the active name across the rewrite.
     103              :   const QString activeProfile =
     104           84 :       getInstance()->value(SettingsConstants::profile).toString();
     105           84 :   getInstance()->remove(SettingsConstants::profile);
     106           84 :   if (!activeProfile.isEmpty()) {
     107           26 :     getInstance()->setValue(SettingsConstants::profile, activeProfile);
     108              :   }
     109           84 :   getInstance()->beginGroup(SettingsConstants::profile);
     110              : 
     111          128 :   for (auto i = profiles.cbegin(); i != profiles.cend(); ++i) {
     112           88 :     getInstance()->setValue(i.key() + "/path", i.value().path);
     113           88 :     getInstance()->setValue(i.key() + "/signingKey", i.value().signingKey);
     114           88 :     getInstance()->setValue(i.key() + "/useGit",
     115           88 :                             Profile::flagToString(i.value().useGit));
     116           88 :     getInstance()->setValue(i.key() + "/autoPush",
     117           88 :                             Profile::flagToString(i.value().autoPush));
     118           88 :     getInstance()->setValue(i.key() + "/autoPull",
     119          132 :                             Profile::flagToString(i.value().autoPull));
     120              :   }
     121              : 
     122           84 :   getInstance()->endGroup();
     123           84 : }
     124              : 
     125          498 : auto QtPassSettings::getPass() -> Pass * {
     126          498 :   return PassBackendFactory::getPass();
     127              : }
     128              : 
     129          138 : auto QtPassSettings::getVersion(const QString &defaultValue) -> QString {
     130          138 :   return getInstance()
     131          276 :       ->value(SettingsConstants::version, defaultValue)
     132          276 :       .toString();
     133              : }
     134          136 : void QtPassSettings::setVersion(const QString &version) {
     135          136 :   getInstance()->setValue(SettingsConstants::version, version);
     136          136 : }
     137              : 
     138          143 : auto QtPassSettings::getGeometry(const QByteArray &defaultValue) -> QByteArray {
     139          143 :   return getInstance()
     140          286 :       ->value(SettingsConstants::geometry, defaultValue)
     141          286 :       .toByteArray();
     142              : }
     143          138 : void QtPassSettings::setGeometry(const QByteArray &geometry) {
     144          138 :   getInstance()->setValue(SettingsConstants::geometry, geometry);
     145          138 : }
     146              : 
     147          141 : auto QtPassSettings::getSavestate(const QByteArray &defaultValue)
     148              :     -> QByteArray {
     149          141 :   return getInstance()
     150          282 :       ->value(SettingsConstants::savestate, defaultValue)
     151          282 :       .toByteArray();
     152              : }
     153          134 : void QtPassSettings::setSavestate(const QByteArray &saveState) {
     154          134 :   getInstance()->setValue(SettingsConstants::savestate, saveState);
     155          134 : }
     156              : 
     157          141 : auto QtPassSettings::getDialogGeometry(const QString &key,
     158              :                                        const QByteArray &defaultValue)
     159              :     -> QByteArray {
     160          141 :   return getInstance()
     161          423 :       ->value(SettingsConstants::dialogGeometry + "/" + key, defaultValue)
     162          282 :       .toByteArray();
     163              : }
     164           34 : void QtPassSettings::setDialogGeometry(const QString &key,
     165              :                                        const QByteArray &geometry) {
     166           68 :   getInstance()->setValue(SettingsConstants::dialogGeometry + "/" + key,
     167           68 :                           geometry);
     168           34 : }
     169              : 
     170          118 : void QtPassSettings::setUsePass(const bool &usePass) {
     171          118 :   getInstance()->setValue(SettingsConstants::usePass, usePass);
     172              :   // Backend selection changed: force re-selection on next getPass().
     173          118 :   PassBackendFactory::invalidate();
     174          118 : }
     175              : 
     176          160 : auto QtPassSettings::getAutoclearSeconds(const int &defaultValue) -> int {
     177          160 :   return getInstance()
     178          320 :       ->value(SettingsConstants::autoclearSeconds, defaultValue)
     179          320 :       .toInt();
     180              : }
     181              : // Creates the directory if missing; the result always ends in a separator.
     182          287 : auto QtPassSettings::getPassStore(const QString &defaultValue) -> QString {
     183          287 :   QString returnValue = getInstance()
     184          574 :                             ->value(SettingsConstants::passStore, defaultValue)
     185          287 :                             .toString();
     186              : 
     187          574 :   returnValue = QDir(returnValue).absolutePath();
     188              : 
     189              :   // ensure directory exists if never used pass or misconfigured.
     190              :   // otherwise process->setWorkingDirectory(passStore); will fail on execution.
     191          287 :   if (!QDir(returnValue).exists()) {
     192            3 :     if (!Util::mkpathForStore(returnValue)) {
     193            0 :       qWarning() << "Failed to create password store directory:" << returnValue;
     194              :     }
     195              :   }
     196              : 
     197          574 :   if (!returnValue.endsWith("/") && !returnValue.endsWith(QDir::separator())) {
     198          287 :     returnValue += QDir::separator();
     199              :   }
     200              : 
     201          287 :   return returnValue;
     202              : }
     203          287 : void QtPassSettings::setPassStore(const QString &passStore) {
     204          287 :   getInstance()->setValue(SettingsConstants::passStore, passStore);
     205          287 : }
     206          134 : void QtPassSettings::initExecutables() {
     207          134 :   AppSettings s = QtPassSettings::load();
     208          134 :   if (s.passExecutable.isEmpty())
     209          268 :     s.passExecutable = Util::findBinaryInPath("pass");
     210          134 :   if (s.gitExecutable.isEmpty())
     211           12 :     s.gitExecutable = Util::findBinaryInPath("git");
     212          134 :   if (s.gpgExecutable.isEmpty()) {
     213            4 :     s.gpgExecutable = Util::findBinaryInPath("gpg2");
     214            2 :     if (s.gpgExecutable.isEmpty())
     215            0 :       s.gpgExecutable = Util::findBinaryInPath("gpg");
     216              :   }
     217          134 :   if (s.pwgenExecutable.isEmpty())
     218          266 :     s.pwgenExecutable = Util::findBinaryInPath("pwgen");
     219          134 :   QtPassSettings::save(s);
     220          134 : }
     221            0 : auto QtPassSettings::getPassExecutable(const QString &defaultValue) -> QString {
     222            0 :   return getInstance()
     223            0 :       ->value(SettingsConstants::passExecutable, defaultValue)
     224            0 :       .toString();
     225              : }
     226              : 
     227           90 : auto QtPassSettings::getProfile(const QString &defaultValue) -> QString {
     228           90 :   return getInstance()
     229          180 :       ->value(SettingsConstants::profile, defaultValue)
     230          180 :       .toString();
     231              : }
     232              : // With a true default and nothing stored, a store with a .git dir means Git.
     233           11 : auto QtPassSettings::isUseGit(const bool &defaultValue) -> bool {
     234              :   bool storedValue =
     235           11 :       getInstance()->value(SettingsConstants::useGit, defaultValue).toBool();
     236           11 :   if (storedValue == defaultValue && defaultValue) {
     237            4 :     QString passStore = getPassStore();
     238            4 :     if (QFileInfo(passStore).isDir() &&
     239            6 :         QFileInfo(passStore + QDir::separator() + ".git").isDir()) {
     240              :       return true;
     241              :     }
     242              :   }
     243              :   return storedValue;
     244              : }
     245          133 : auto QtPassSettings::isUseGrepSearch(const bool &defaultValue) -> bool {
     246          133 :   return getInstance()
     247          266 :       ->value(SettingsConstants::useGrepSearch, defaultValue)
     248          266 :       .toBool();
     249              : }
     250              : 
     251          267 : auto QtPassSettings::isUseOtp(const bool &defaultValue) -> bool {
     252          267 :   return getInstance()->value(SettingsConstants::useOtp, defaultValue).toBool();
     253              : }
     254              : 
     255            1 : void QtPassSettings::setQrencodeExecutable(const QString &qrencodeExecutable) {
     256            2 :   getInstance()->setValue(SettingsConstants::qrencodeExecutable,
     257            2 :                           qrencodeExecutable);
     258            1 : }
     259              : 
     260            2 : auto QtPassSettings::isHideOnClose(const bool &defaultValue) -> bool {
     261            2 :   return getInstance()
     262            4 :       ->value(SettingsConstants::hideOnClose, defaultValue)
     263            4 :       .toBool();
     264              : }
     265          142 : auto QtPassSettings::isAlwaysOnTop(const bool &defaultValue) -> bool {
     266          142 :   return getInstance()
     267          284 :       ->value(SettingsConstants::alwaysOnTop, defaultValue)
     268          284 :       .toBool();
     269              : }
     270              : 
     271            8 : auto QtPassSettings::isAutoPush(const bool &defaultValue) -> bool {
     272            8 :   return getInstance()
     273           16 :       ->value(SettingsConstants::autoPush, defaultValue)
     274           16 :       .toBool();
     275              : }
     276              : 
     277          306 : auto QtPassSettings::isShowProcessOutput(const bool &defaultValue) -> bool {
     278          306 :   return getInstance()
     279          612 :       ->value(SettingsConstants::showProcessOutput, defaultValue)
     280          612 :       .toBool();
     281              : }
     282          285 : auto QtPassSettings::getRealPass() -> RealPass * {
     283          285 :   return PassBackendFactory::getRealPass();
     284              : }
     285          411 : auto QtPassSettings::getImitatePass() -> ImitatePass * {
     286          411 :   return PassBackendFactory::getImitatePass();
     287              : }
     288              : 
     289          134 : auto QtPassSettings::backendsIdle() -> bool {
     290          134 :   return PassBackendFactory::isIdle();
     291              : }
        

Generated by: LCOV version 2.0-1