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(const QString &binary) -> QString {
121 if (binary.isEmpty())
122 return QString();
123
124 initialiseEnvironment();
125
126 QString ret;
127
128 const QString binaryWithSep = QDir::separator() + binary;
129
130 if (_env.contains("PATH")) {
131 QString path = _env.value("PATH");
132 const QChar delimiter = QDir::separator() == '\\' ? ';' : ':';
133 QStringList entries = path.split(delimiter);
134
135 for (const QString &entryConst : entries) {
136 QString fullPath = entryConst + binaryWithSep;
137 QFileInfo qfi(fullPath);
138#ifdef Q_OS_WIN
139 if (!qfi.exists()) {
140 QString fullPathExe = fullPath + ".exe";
141 qfi = QFileInfo(fullPathExe);
142 }
143#endif
144 if (!qfi.exists()) {
145 continue;
146 }
147 if (!qfi.isExecutable()) {
148 continue;
149 }
150
151 ret = qfi.absoluteFilePath();
152 break;
153 }
154 }
155#ifdef Q_OS_WIN
156 if (ret.isEmpty()) {
157 static const QRegularExpression whitespaceRegex(QStringLiteral("\\s"));
158 const bool hasWhitespace = binary.contains(whitespaceRegex);
159 if (!binary.isEmpty() && !hasWhitespace) {
160 QString wslCommand = QStringLiteral("wsl ") + binary;
161#ifdef QT_DEBUG
162 dbg() << "Util::findBinaryInPath(): falling back to WSL for binary"
163 << binary;
164#endif
165 QString out, err;
166 if (Executor::executeBlocking(wslCommand, {"--version"}, &out, &err) ==
167 0 &&
168 !out.isEmpty() && err.isEmpty()) {
169#ifdef QT_DEBUG
170 dbg() << "Util::findBinaryInPath(): using WSL binary" << wslCommand;
171#endif
172 ret = wslCommand;
173 }
174 }
175 }
176#endif
177
178 return ret;
179}
180
191auto Util::configIsValid() -> bool {
192 const QString configFilePath =
193 QDir(QtPassSettings::getPassStore()).filePath(".gpg-id");
194 if (!QFile(configFilePath).exists()) {
195 return false;
196 }
197
198 const QString executable = QtPassSettings::isUsePass()
201
202 if (executable.startsWith(QStringLiteral("wsl "))) {
203 QString out;
204 QString err;
205 if (Executor::executeBlocking(QStringLiteral("wsl"),
206 {QStringLiteral("--version")}, &out,
207 &err) == 0 &&
208 !out.isEmpty() && err.isEmpty()) {
209 return true;
210 }
211 }
212 return QFile(executable).exists();
213}
214
234auto Util::getDir(const QModelIndex &index, bool forPass,
235 const QFileSystemModel &model, const StoreModel &storeModel)
236 -> QString {
237 QString abspath =
238 QDir(QtPassSettings::getPassStore()).absolutePath() + QDir::separator();
239 if (!index.isValid()) {
240 return forPass ? "" : abspath;
241 }
242 QFileInfo info = model.fileInfo(storeModel.mapToSource(index));
243 QString filePath =
244 (info.isFile() ? info.absolutePath() : info.absoluteFilePath());
245 if (forPass) {
246 filePath = QDir(abspath).relativeFilePath(filePath);
247 }
248 filePath += QDir::separator();
249 return filePath;
250}
251
252auto Util::endsWithGpg() -> const QRegularExpression & {
253 static const QRegularExpression expr{"\\.gpg$"};
254 return expr;
255}
256
269auto Util::protocolRegex() -> const QRegularExpression & {
270 static const QRegularExpression regex{
271 "((?:https?|ftp|ssh|sftp|ftps|webdav|webdavs)://[^\" <>\\)\\]\\[]+)"};
272 return regex;
273}
274
275auto Util::newLinesRegex() -> const QRegularExpression & {
276 static const QRegularExpression regex{"[\r\n]"};
277 return regex;
278}
279
280auto Util::isValidKeyId(const QString &keyId) -> bool {
281 static const QRegularExpression hexPrefixRegex{"^0[xX]"};
282 static const QRegularExpression specialPrefixRegex{"^[@/#&]"};
283 static const QRegularExpression hexKeyIdRegex{"^[0-9A-Fa-f]{8,40}$"};
284
285 if (keyId.isEmpty()) {
286 return false;
287 }
288
289 QString normalized = keyId;
290 if (normalized.startsWith('<') && normalized.endsWith('>')) {
291 normalized = normalized.mid(1, normalized.length() - 2);
292 }
293 normalized.remove(hexPrefixRegex);
294
295 if (specialPrefixRegex.match(normalized).hasMatch() ||
296 normalized.contains('@')) {
297 return true;
298 }
299
300 return hexKeyIdRegex.match(normalized).hasMatch();
301}
static auto executeBlocking(const 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:37
static auto protocolRegex() -> const QRegularExpression &
Returns a regex to match URL protocols.
Definition util.cpp:269
static auto endsWithGpg() -> const QRegularExpression &
Returns a regex to match .gpg file extensions.
Definition util.cpp:252
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:234
static auto isValidKeyId(const QString &keyId) -> bool
Check if a string looks like a valid GPG key ID. Accepts:
Definition util.cpp:280
static auto newLinesRegex() -> const QRegularExpression &
Returns a regex to match newline characters.
Definition util.cpp:275
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(const 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:191
Debug utilities for QtPass.
#define dbg()
Simple debug macro that includes file and line number.
Definition debughelper.h:21