QtPass 2.0.0
Developer documentation
Loading...
Searching...
No Matches
qtpasssettings.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
2// SPDX-License-Identifier: GPL-3.0-or-later
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
27
29// Portable mode: a qtpass.ini next to the executable wins over the platform
30// settings store.
33 QString portable_ini = QCoreApplication::applicationDirPath() +
34 QDir::separator() + "qtpass.ini";
35 if (QFile(portable_ini).exists()) {
36 m_instance = new QtPassSettings(portable_ini, QSettings::IniFormat);
37 } else {
38 m_instance = new QtPassSettings("IJHack", "QtPass");
39 }
40
41 initialized = true;
42 }
43
44 return m_instance;
45}
46
49 if (!s.passStore.isEmpty()) {
50 s.passStore = QDir::cleanPath(QDir(s.passStore).absolutePath());
51 if (!s.passStore.endsWith('/'))
52 s.passStore += '/';
53 }
54 return s;
55}
56
57void QtPassSettings::save(const AppSettings &settings) {
59 // The "use pass" mode may have changed; rebuild the backend on next use.
61}
62
66
68 getInstance()->beginGroup(SettingsConstants::profile);
69 Profiles profiles;
70
71 // migration from version <= v1.3.2: profiles datastructure
72 QStringList childKeys = getInstance()->childKeys();
73 for (const auto &key : std::as_const(childKeys)) {
74 Profile profile;
75 profile.path = getInstance()->value(key).toString();
76 profiles.insert(key, profile);
77 }
78 // /migration from version <= v1.3.2
79
80 QStringList childGroups = getInstance()->childGroups();
81 for (const auto &group : std::as_const(childGroups)) {
82 Profile profile;
83 profile.path = getInstance()->value(group + "/path").toString();
84 profile.signingKey = getInstance()->value(group + "/signingKey").toString();
86 getInstance()->value(group + "/useGit").toString());
88 getInstance()->value(group + "/autoPush").toString());
90 getInstance()->value(group + "/autoPull").toString());
91 profiles.insert(group, profile);
92 }
93
94 getInstance()->endGroup();
95
96 return profiles;
97}
98
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 getInstance()->value(SettingsConstants::profile).toString();
105 getInstance()->remove(SettingsConstants::profile);
106 if (!activeProfile.isEmpty()) {
107 getInstance()->setValue(SettingsConstants::profile, activeProfile);
108 }
109 getInstance()->beginGroup(SettingsConstants::profile);
110
111 for (auto i = profiles.cbegin(); i != profiles.cend(); ++i) {
112 getInstance()->setValue(i.key() + "/path", i.value().path);
113 getInstance()->setValue(i.key() + "/signingKey", i.value().signingKey);
114 getInstance()->setValue(i.key() + "/useGit",
115 Profile::flagToString(i.value().useGit));
116 getInstance()->setValue(i.key() + "/autoPush",
117 Profile::flagToString(i.value().autoPush));
118 getInstance()->setValue(i.key() + "/autoPull",
119 Profile::flagToString(i.value().autoPull));
120 }
121
122 getInstance()->endGroup();
123}
124
128
129auto QtPassSettings::getVersion(const QString &defaultValue) -> QString {
130 return getInstance()
131 ->value(SettingsConstants::version, defaultValue)
132 .toString();
133}
134void QtPassSettings::setVersion(const QString &version) {
135 getInstance()->setValue(SettingsConstants::version, version);
136}
137
138auto QtPassSettings::getGeometry(const QByteArray &defaultValue) -> QByteArray {
139 return getInstance()
140 ->value(SettingsConstants::geometry, defaultValue)
141 .toByteArray();
142}
143void QtPassSettings::setGeometry(const QByteArray &geometry) {
144 getInstance()->setValue(SettingsConstants::geometry, geometry);
145}
146
147auto QtPassSettings::getSavestate(const QByteArray &defaultValue)
148 -> QByteArray {
149 return getInstance()
150 ->value(SettingsConstants::savestate, defaultValue)
151 .toByteArray();
152}
153void QtPassSettings::setSavestate(const QByteArray &saveState) {
154 getInstance()->setValue(SettingsConstants::savestate, saveState);
155}
156
157auto QtPassSettings::getDialogGeometry(const QString &key,
158 const QByteArray &defaultValue)
159 -> QByteArray {
160 return getInstance()
161 ->value(SettingsConstants::dialogGeometry + "/" + key, defaultValue)
162 .toByteArray();
163}
164void QtPassSettings::setDialogGeometry(const QString &key,
165 const QByteArray &geometry) {
166 getInstance()->setValue(SettingsConstants::dialogGeometry + "/" + key,
167 geometry);
168}
169
170void QtPassSettings::setUsePass(const bool &usePass) {
171 getInstance()->setValue(SettingsConstants::usePass, usePass);
172 // Backend selection changed: force re-selection on next getPass().
174}
175
176auto QtPassSettings::getAutoclearSeconds(const int &defaultValue) -> int {
177 return getInstance()
178 ->value(SettingsConstants::autoclearSeconds, defaultValue)
179 .toInt();
180}
181// Creates the directory if missing; the result always ends in a separator.
182auto QtPassSettings::getPassStore(const QString &defaultValue) -> QString {
183 QString returnValue = getInstance()
184 ->value(SettingsConstants::passStore, defaultValue)
185 .toString();
186
187 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 if (!QDir(returnValue).exists()) {
192 if (!Util::mkpathForStore(returnValue)) {
193 qWarning() << "Failed to create password store directory:" << returnValue;
194 }
195 }
196
197 if (!returnValue.endsWith("/") && !returnValue.endsWith(QDir::separator())) {
198 returnValue += QDir::separator();
199 }
200
201 return returnValue;
202}
203void QtPassSettings::setPassStore(const QString &passStore) {
204 getInstance()->setValue(SettingsConstants::passStore, passStore);
205}
208 if (s.passExecutable.isEmpty())
210 if (s.gitExecutable.isEmpty())
212 if (s.gpgExecutable.isEmpty()) {
214 if (s.gpgExecutable.isEmpty())
216 }
217 if (s.pwgenExecutable.isEmpty())
220}
221auto QtPassSettings::getPassExecutable(const QString &defaultValue) -> QString {
222 return getInstance()
223 ->value(SettingsConstants::passExecutable, defaultValue)
224 .toString();
225}
226
227auto QtPassSettings::getProfile(const QString &defaultValue) -> QString {
228 return getInstance()
229 ->value(SettingsConstants::profile, defaultValue)
230 .toString();
231}
232// With a true default and nothing stored, a store with a .git dir means Git.
233auto QtPassSettings::isUseGit(const bool &defaultValue) -> bool {
234 bool storedValue =
235 getInstance()->value(SettingsConstants::useGit, defaultValue).toBool();
236 if (storedValue == defaultValue && defaultValue) {
237 QString passStore = getPassStore();
238 if (QFileInfo(passStore).isDir() &&
239 QFileInfo(passStore + QDir::separator() + ".git").isDir()) {
240 return true;
241 }
242 }
243 return storedValue;
244}
245auto QtPassSettings::isUseGrepSearch(const bool &defaultValue) -> bool {
246 return getInstance()
247 ->value(SettingsConstants::useGrepSearch, defaultValue)
248 .toBool();
249}
250
251auto QtPassSettings::isUseOtp(const bool &defaultValue) -> bool {
252 return getInstance()->value(SettingsConstants::useOtp, defaultValue).toBool();
253}
254
255void QtPassSettings::setQrencodeExecutable(const QString &qrencodeExecutable) {
256 getInstance()->setValue(SettingsConstants::qrencodeExecutable,
257 qrencodeExecutable);
258}
259
260auto QtPassSettings::isHideOnClose(const bool &defaultValue) -> bool {
261 return getInstance()
262 ->value(SettingsConstants::hideOnClose, defaultValue)
263 .toBool();
264}
265auto QtPassSettings::isAlwaysOnTop(const bool &defaultValue) -> bool {
266 return getInstance()
267 ->value(SettingsConstants::alwaysOnTop, defaultValue)
268 .toBool();
269}
270
271auto QtPassSettings::isAutoPush(const bool &defaultValue) -> bool {
272 return getInstance()
273 ->value(SettingsConstants::autoPush, defaultValue)
274 .toBool();
275}
276
277auto QtPassSettings::isShowProcessOutput(const bool &defaultValue) -> bool {
278 return getInstance()
279 ->value(SettingsConstants::showProcessOutput, defaultValue)
280 .toBool();
281}
288
Implementation that imitates 'pass' when the real tool is unavailable.
Definition imitatepass.h:40
static auto getPass() -> Pass *
Get the active backend, constructing and initialising it on first use after construction or invalidat...
static auto getRealPass() -> RealPass *
Get the lazily-constructed RealPass backend.
static auto isIdle() -> bool
Whether neither backend runs or waits for anything: after a switch of backend the previous one is kep...
static auto getImitatePass() -> ImitatePass *
Get the lazily-constructed ImitatePass backend.
static void invalidate()
Forget the currently active backend.
Abstract base class for password store operations.
Definition pass.h:75
Singleton that stores QtPass settings, handles persistence and defaults.
static bool initialized
Whether getInstance() has chosen the store and built m_instance.
static auto getInstance() -> QtPassSettings *
Get the singleton instance.
static void setPassStore(const QString &passStore)
Save password store path.
static auto getPass() -> Pass *
Get currently active pass backend instance.
static auto getPasswordConfiguration() -> PasswordConfiguration
Get complete password generation configuration.
static auto isUseGit(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether Git integration is enabled.
static auto isUseOtp(const bool &defaultValue=true) -> bool
Check whether OTP support is enabled.
static auto getPassStore(const QString &defaultValue=QVariant().toString()) -> QString
Get password store directory path.
static auto getVersion(const QString &defaultValue=QVariant().toString()) -> QString
Get saved application version.
static void initExecutables()
Initialize executable paths by auto-detecting them.
static auto load() -> AppSettings
Load all flat settings into an AppSettings value object.
static auto isUseGrepSearch(const bool &defaultValue=false) -> bool
Check whether content search is enabled.
QtPassSettings()=delete
Private default constructor to enforce singleton usage and prevent direct instantiation.
static void setVersion(const QString &version)
Save application version.
static auto getProfiles() -> Profiles
Get all configured profiles.
static auto getRealPass() -> RealPass *
Get real pass backend instance.
static void setQrencodeExecutable(const QString &qrencodeExecutable)
Save qrencode executable path.
static auto getProfile(const QString &defaultValue=QVariant().toString()) -> QString
Get active profile name.
static auto isShowProcessOutput(const bool &defaultValue=false) -> bool
Get showProcessOutput setting.
static void setProfiles(const Profiles &profiles)
Save all configured profiles.
static void setUsePass(const bool &usePass)
Save use pass setting.
static void setSavestate(const QByteArray &saveState)
Save window state.
static auto isAlwaysOnTop(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether main window should stay always on top.
static void setDialogGeometry(const QString &key, const QByteArray &geometry)
Save dialog geometry.
static auto getPassExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get pass executable path.
static auto getDialogGeometry(const QString &key, const QByteArray &defaultValue=QVariant().toByteArray()) -> QByteArray
Get saved dialog geometry.
static auto getImitatePass() -> ImitatePass *
Get imitate pass backend instance.
static auto isHideOnClose(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether closing the window hides the application.
static void save(const AppSettings &settings)
Persist an AppSettings value object to the singleton store.
static QtPassSettings * m_instance
static auto getAutoclearSeconds(const int &defaultValue=QVariant().toInt()) -> int
Get autoclear delay in seconds.
static auto isAutoPush(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether automatic push is enabled.
static void setGeometry(const QByteArray &geometry)
Save window geometry.
static auto getGeometry(const QByteArray &defaultValue=QVariant().toByteArray()) -> QByteArray
Get saved window geometry.
static auto getSavestate(const QByteArray &defaultValue=QVariant().toByteArray()) -> QByteArray
Get saved window state.
static auto backendsIdle() -> bool
Whether no backend, the active one or one kept from before a switch, runs or waits for anything (Pass...
Implementation of Pass that wraps the 'pass' command-line tool.
Definition realpass.h:32
static auto loadPasswordConfiguration(QSettings &qs) -> PasswordConfiguration
Read only the password generation settings from a QSettings store.
static void save(QSettings &qs, const AppSettings &settings)
Write all flat settings to a QSettings store.
static auto load(QSettings &qs) -> AppSettings
Read all flat settings from a QSettings store.
static auto mkpathForStore(const QString &path) -> bool
Create path and any missing parents as pass would.
Definition util.cpp:438
static auto findBinaryInPath(const QString &binary) -> QString
Locate an executable by searching the process PATH and (on Windows) falling back to WSL.
Definition util.cpp:474
Pass, the abstract password-store backend that RealPass and ImitatePass implement,...
PassBackendFactory, which constructs the two Pass backends on demand and hands out the one the settin...
QMap< QString, Profile > Profiles
All profiles by name. QMap so iteration order is the name order.
Definition profile.h:81
QtPassSettings, the QSettings singleton behind every saved setting, the profiles and the Pass backend...
SettingsSerializer: the flat AppSettings fields to and from their QSettings keys, without side effect...
Plain value-object holding all flat QtPass configuration.
Definition appsettings.h:36
QString gpgExecutable
Path to the gpg/gpg2 executable.
Definition appsettings.h:66
QString pwgenExecutable
Path to the pwgen executable.
Definition appsettings.h:67
QString passStore
Password-store root path.
Definition appsettings.h:60
QString gitExecutable
Path to the git executable.
Definition appsettings.h:65
QString passExecutable
Path to the pass executable.
Definition appsettings.h:64
Holds the password generator settings: which character set is selected, the alphabet of every set,...
One named password store: where it is, how its .gpg-id is signed and, optionally, its own Git switche...
Definition profile.h:26
std::optional< bool > autoPush
Push after commits; unset = global.
Definition profile.h:30
QString path
Password store directory.
Definition profile.h:27
std::optional< bool > autoPull
Pull on start; unset = global.
Definition profile.h:31
std::optional< bool > useGit
Git on/off; unset follows the global.
Definition profile.h:29
static auto flagToString(std::optional< bool > flag) -> QString
Format a flag the way it is stored.
Definition profile.h:53
static auto flagFromString(const QString &value) -> std::optional< bool >
Parse the on-disk tri-state.
Definition profile.h:38
QString signingKey
Key(s) that sign this store's .gpg-id.
Definition profile.h:28
Util: static helpers for the process environment, binary discovery, store paths, URL safety and the l...