28QProcessEnvironment Util::_env;
29bool Util::_envInitialised =
false;
41void Util::initialiseEnvironment() {
42 if (!_envInitialised) {
43 _env = QProcessEnvironment::systemEnvironment();
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);
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);
64 dbg() << _env.value(
"PATH");
66 _envInitialised =
true;
79 initialiseEnvironment();
80 if (_env.contains(
"PASSWORD_STORE_DIR")) {
81 path = _env.value(
"PASSWORD_STORE_DIR");
84 path = QDir::homePath() + QDir::separator() +
"password-store" +
87 path = QDir::homePath() + QDir::separator() +
".password-store" +
95 QString normalizedPath = path;
96 if (!normalizedPath.endsWith(
"/") &&
97 !normalizedPath.endsWith(QDir::separator())) {
98 normalizedPath += QDir::separator();
100 return QDir::toNativeSeparators(normalizedPath);
121 initialiseEnvironment();
125 const QString binaryWithSep = QDir::separator() + binary;
127 if (_env.contains(
"PATH")) {
128 QString path = _env.value(
"PATH");
129 const QChar delimiter = QDir::separator() ==
'\\' ?
';' :
':';
130 QStringList entries = path.split(delimiter);
132 for (
const QString &entryConst : entries) {
133 QString fullPath = entryConst + binaryWithSep;
134 QFileInfo qfi(fullPath);
137 QString fullPathExe = fullPath +
".exe";
138 qfi = QFileInfo(fullPathExe);
144 if (!qfi.isExecutable()) {
148 ret = qfi.absoluteFilePath();
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;
159 dbg() <<
"Util::findBinaryInPath(): falling back to WSL for binary"
165 !out.isEmpty() && err.isEmpty()) {
167 dbg() <<
"Util::findBinaryInPath(): using WSL binary" << wslCommand;
189 const QString configFilePath =
191 if (!QFile(configFilePath).exists()) {
199 if (executable.startsWith(QStringLiteral(
"wsl "))) {
203 {QStringLiteral(
"--version")}, &out,
205 !out.isEmpty() && err.isEmpty()) {
209 return QFile(executable).exists();
232 const QFileSystemModel &model,
const StoreModel &storeModel)
236 if (!index.isValid()) {
237 return forPass ?
"" : abspath;
239 QFileInfo info = model.fileInfo(storeModel.mapToSource(index));
241 (info.isFile() ? info.absolutePath() : info.absoluteFilePath());
243 filePath = QDir(abspath).relativeFilePath(filePath);
245 filePath += QDir::separator();
250 static const QRegularExpression expr{
"\\.gpg$"};
267 static const QRegularExpression regex{
268 "((?:https?|ftp|ssh|sftp|ftps|webdav|webdavs)://[^\" <>\\)\\]\\[]+)"};
273 static const QRegularExpression regex{
"[\r\n]"};
278 static const QRegularExpression hexPrefixRegex{
"^0[xX]"};
279 static const QRegularExpression specialPrefixRegex{
"^[@/#&]"};
280 static const QRegularExpression hexKeyIdRegex{
"^[0-9A-Fa-f]{8,40}$"};
282 if (keyId.isEmpty()) {
286 QString normalized = keyId;
287 if (normalized.startsWith(
'<') && normalized.endsWith(
'>')) {
288 normalized = normalized.mid(1, normalized.length() - 2);
290 normalized.remove(hexPrefixRegex);
292 if (specialPrefixRegex.match(normalized).hasMatch() ||
293 normalized.contains(
'@')) {
297 return hexKeyIdRegex.match(normalized).hasMatch();
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.
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.
static auto protocolRegex() -> const QRegularExpression &
Returns a regex to match URL protocols.
static auto endsWithGpg() -> const QRegularExpression &
Returns a regex to match .gpg file extensions.
static auto findPasswordStore() -> QString
Locate the password store directory.
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.
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:
static auto newLinesRegex() -> const QRegularExpression &
Returns a regex to match newline characters.
static auto normalizeFolderPath(const QString &path) -> QString
Ensure a folder path always ends with the native directory separator.
static auto findBinaryInPath(QString binary) -> QString
Locate an executable by searching the process PATH and (on Windows) falling back to WSL.
static auto configIsValid() -> bool
Verify that the required configuration is complete.
Debug utilities for QtPass.
#define dbg()
Simple debug macro that includes file and line number.