QtPass 1.6.0
Multi-platform GUI for pass, the standard unix password manager.
Loading...
Searching...
No Matches
util.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2014 Anne Jan Brouwer
2// SPDX-License-Identifier: GPL-3.0-or-later
3
13
14#include "util.h"
15#include <QDir>
16#include <QFileInfo>
17#ifdef Q_OS_WIN
18#include <windows.h>
19#else
20#include <sys/time.h>
21#endif
22#include "qtpasssettings.h"
23
24#ifdef QT_DEBUG
25#include "debughelper.h"
26#endif
27
28QProcessEnvironment Util::_env;
29bool Util::_envInitialised = false;
30
41void Util::initialiseEnvironment() {
42 if (!_envInitialised) {
43 _env = QProcessEnvironment::systemEnvironment();
44#ifdef __APPLE__
45 QString path = _env.value("PATH");
46 if (!path.contains("/usr/local/MacGPG2/bin") &&
47 QDir("/usr/local/MacGPG2/bin").exists())
48 path += ":/usr/local/MacGPG2/bin";
49 if (!path.contains("/usr/local/bin"))
50 path += ":/usr/local/bin";
51 _env.insert("PATH", path);
52#endif
53#ifdef Q_OS_WIN
54 QString path = _env.value("PATH");
55 if (!path.contains("C:\\Program Files\\WinGPG\\x86") &&
56 QDir("C:\\Program Files\\WinGPG\\x86").exists())
57 path += ";C:\\Program Files\\WinGPG\\x86";
58 if (!path.contains("C:\\Program Files\\GnuPG\\bin") &&
59 QDir("C:\\Program Files\\GnuPG\\bin").exists())
60 path += ";C:\\Program Files\\GnuPG\\bin";
61 _env.insert("PATH", path);
62#endif
63#ifdef QT_DEBUG
64 dbg() << _env.value("PATH");
65#endif
66 _envInitialised = true;
67 }
68}
69
77auto Util::findPasswordStore() -> QString {
78 QString path;
79 initialiseEnvironment();
80 if (_env.contains("PASSWORD_STORE_DIR")) {
81 path = _env.value("PASSWORD_STORE_DIR");
82 } else {
83#ifdef Q_OS_WIN
84 path = QDir::homePath() + QDir::separator() + "password-store" +
85 QDir::separator();
86#else
87 path = QDir::homePath() + QDir::separator() + ".password-store" +
88 QDir::separator();
89#endif
90 }
91 return Util::normalizeFolderPath(path);
92}
93
94auto Util::normalizeFolderPath(const QString &path) -> QString {
95 QString normalizedPath = path;
96 if (!normalizedPath.endsWith("/") &&
97 !normalizedPath.endsWith(QDir::separator())) {
98 normalizedPath += QDir::separator();
99 }
100 return QDir::toNativeSeparators(normalizedPath);
101}
102
120auto Util::findBinaryInPath(QString binary) -> QString {
121 initialiseEnvironment();
122
123 QString ret;
124
125 const QString binaryWithSep = QDir::separator() + binary;
126
127 if (_env.contains("PATH")) {
128 QString path = _env.value("PATH");
129 const QChar delimiter = QDir::separator() == '\\' ? ';' : ':';
130 QStringList entries = path.split(delimiter);
131
132 for (const QString &entryConst : entries) {
133 QString fullPath = entryConst + binaryWithSep;
134 QFileInfo qfi(fullPath);
135#ifdef Q_OS_WIN
136 if (!qfi.exists()) {
137 QString fullPathExe = fullPath + ".exe";
138 qfi = QFileInfo(fullPathExe);
139 }
140#endif
141 if (!qfi.exists()) {
142 continue;
143 }
144 if (!qfi.isExecutable()) {
145 continue;
146 }
147
148 ret = qfi.absoluteFilePath();
149 break;
150 }
151 }
152#ifdef Q_OS_WIN
153 if (ret.isEmpty()) {
154 static const QRegularExpression whitespaceRegex(QStringLiteral("\\s"));
155 const bool hasWhitespace = binary.contains(whitespaceRegex);
156 if (!binary.isEmpty() && !hasWhitespace) {
157 QString wslCommand = QStringLiteral("wsl ") + binary;
158#ifdef QT_DEBUG
159 dbg() << "Util::findBinaryInPath(): falling back to WSL for binary"
160 << binary;
161#endif
162 QString out, err;
163 if (Executor::executeBlocking(wslCommand, {"--version"}, &out, &err) ==
164 0 &&
165 !out.isEmpty() && err.isEmpty()) {
166#ifdef QT_DEBUG
167 dbg() << "Util::findBinaryInPath(): using WSL binary" << wslCommand;
168#endif
169 ret = wslCommand;
170 }
171 }
172 }
173#endif
174
175 return ret;
176}
177
188auto Util::configIsValid() -> bool {
189 const QString configFilePath =
190 QDir(QtPassSettings::getPassStore()).filePath(".gpg-id");
191 if (!QFile(configFilePath).exists()) {
192 return false;
193 }
194
195 const QString executable = QtPassSettings::isUsePass()
198
199 if (executable.startsWith(QStringLiteral("wsl "))) {
200 QString out;
201 QString err;
202 if (Executor::executeBlocking(QStringLiteral("wsl"),
203 {QStringLiteral("--version")}, &out,
204 &err) == 0 &&
205 !out.isEmpty() && err.isEmpty()) {
206 return true;
207 }
208 }
209 return QFile(executable).exists();
210}
211
231auto Util::getDir(const QModelIndex &index, bool forPass,
232 const QFileSystemModel &model, const StoreModel &storeModel)
233 -> QString {
234 QString abspath =
235 QDir(QtPassSettings::getPassStore()).absolutePath() + QDir::separator();
236 if (!index.isValid()) {
237 return forPass ? "" : abspath;
238 }
239 QFileInfo info = model.fileInfo(storeModel.mapToSource(index));
240 QString filePath =
241 (info.isFile() ? info.absolutePath() : info.absoluteFilePath());
242 if (forPass) {
243 filePath = QDir(abspath).relativeFilePath(filePath);
244 }
245 filePath += QDir::separator();
246 return filePath;
247}
248
249auto Util::endsWithGpg() -> const QRegularExpression & {
250 static const QRegularExpression expr{"\\.gpg$"};
251 return expr;
252}
253
266auto Util::protocolRegex() -> const QRegularExpression & {
267 static const QRegularExpression regex{
268 "((?:https?|ftp|ssh|sftp|ftps|webdav|webdavs)://[^\" <>\\)\\]\\[]+)"};
269 return regex;
270}
271
272auto Util::newLinesRegex() -> const QRegularExpression & {
273 static const QRegularExpression regex{"[\r\n]"};
274 return regex;
275}
276
277auto Util::isValidKeyId(const QString &keyId) -> bool {
278 static const QRegularExpression hexPrefixRegex{"^0[xX]"};
279 static const QRegularExpression specialPrefixRegex{"^[@/#&]"};
280 static const QRegularExpression hexKeyIdRegex{"^[0-9A-Fa-f]{8,40}$"};
281
282 if (keyId.isEmpty()) {
283 return false;
284 }
285
286 QString normalized = keyId;
287 if (normalized.startsWith('<') && normalized.endsWith('>')) {
288 normalized = normalized.mid(1, normalized.length() - 2);
289 }
290 normalized.remove(hexPrefixRegex);
291
292 if (specialPrefixRegex.match(normalized).hasMatch() ||
293 normalized.contains('@')) {
294 return true;
295 }
296
297 return hexKeyIdRegex.match(normalized).hasMatch();
298}
static auto executeBlocking(QString app, const QStringList &args, const QString &input=QString(), QString *process_out=nullptr, QString *process_err=nullptr) -> int
Executor::executeBlocking blocking version of the executor, takes input and presents it as stdin.
Definition executor.cpp:223
static auto isUsePass(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to use pass (true) or GPG (false).
static auto getPassStore(const QString &defaultValue=QVariant().toString()) -> QString
Get password store directory path.
static auto getGpgExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get GPG executable path.
static auto getPassExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get pass executable path.
QSortFilterProxyModel for filtering and displaying password store.
Definition storemodel.h:31
static auto protocolRegex() -> const QRegularExpression &
Returns a regex to match URL protocols.
Definition util.cpp:266
static auto endsWithGpg() -> const QRegularExpression &
Returns a regex to match .gpg file extensions.
Definition util.cpp:249
static auto findPasswordStore() -> QString
Locate the password store directory.
Definition util.cpp:77
static auto getDir(const QModelIndex &index, bool forPass, const QFileSystemModel &model, const StoreModel &storeModel) -> QString
Get the selected folder path, either relative to the configured pass store or absolute.
Definition util.cpp:231
static auto isValidKeyId(const QString &keyId) -> bool
Check if a string looks like a valid GPG key ID. Validates a GPG key ID after normalization:
Definition util.cpp:277
static auto newLinesRegex() -> const QRegularExpression &
Returns a regex to match newline characters.
Definition util.cpp:272
static auto normalizeFolderPath(const QString &path) -> QString
Ensure a folder path always ends with the native directory separator.
Definition util.cpp:94
static auto findBinaryInPath(QString binary) -> QString
Locate an executable by searching the process PATH and (on Windows) falling back to WSL.
Definition util.cpp:120
static auto configIsValid() -> bool
Verify that the required configuration is complete.
Definition util.cpp:188
Debug utilities for QtPass.
#define dbg()
Simple debug macro that includes file and line number.
Definition debughelper.h:21