QtPass 1.6.0
Multi-platform GUI for pass, the standard unix password manager.
Loading...
Searching...
No Matches
/home/runner/work/QtPass/QtPass/src/pass.cpp

Finds the path to the gpgconf executable in the same directory as the given GPG path.

QString result = findGpgconfInGpgDir(gpgPath); std::cout << result.toStdString() << std::endl; // Expected output: path to gpgconf or empty string.

Finds the path to the gpgconf executable in the same directory as the given GPG path.

QString result = findGpgconfInGpgDir(gpgPath); std::cout << result.toStdString() << std::endl; // Expected output: path to gpgconf or empty string

Parameters
gpgPath- Absolute path to a GPG executable or related file used to locate gpgconf.
Returns
QString - The full path to gpgconf if found and executable; otherwise an empty QString.
// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
// SPDX-License-Identifier: GPL-3.0-or-later
#include "pass.h"
#include "gpgkeystate.h"
#include "helpers.h"
#include "qtpasssettings.h"
#include "util.h"
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QRandomGenerator>
#include <QRegularExpression>
#include <algorithm>
#include <utility>
#ifdef QT_DEBUG
#include "debughelper.h"
#endif
namespace {
auto fallbackCharset(const QString &input, const QString &fallback) -> QString {
return input.isEmpty() ? fallback : input;
}
auto effectiveCharset(const PasswordConfiguration &passConfig) -> QString {
int sel = passConfig.selected;
return fallbackCharset(
passConfig.Characters[sel],
}
} // namespace
Pass::Pass() : wrapperRunning(false), env(QProcess::systemEnvironment()) {
connect(&exec,
static_cast<void (Executor::*)(int, int, const QString &,
const QString &)>(&Executor::finished),
this, &Pass::finished);
// This was previously using direct QProcess signals.
// The code now uses Executor instead of raw QProcess for better control.
// connect(&process, SIGNAL(error(QProcess::ProcessError)), this,
// SIGNAL(error(QProcess::ProcessError)));
// Merge our vars into WSLENV rather than blindly appending a duplicate entry
const QStringList wslenvVars = {
QStringLiteral("PASSWORD_STORE_DIR/p"),
QStringLiteral("PASSWORD_STORE_GENERATED_LENGTH/w"),
QStringLiteral("PASSWORD_STORE_CHARACTER_SET/w")};
const QString wslenvPrefix = QStringLiteral("WSLENV=");
auto it =
std::find_if(env.begin(), env.end(), [&wslenvPrefix](const QString &s) {
return s.startsWith(wslenvPrefix);
});
if (it == env.end()) {
env.append(wslenvPrefix + wslenvVars.join(':'));
} else {
QStringList parts =
it->mid(wslenvPrefix.size()).split(':', Qt::SkipEmptyParts);
for (const QString &v : wslenvVars) {
if (!parts.contains(v))
parts.append(v);
}
*it = wslenvPrefix + parts.join(':');
}
}
void Pass::executeWrapper(PROCESS id, const QString &app,
const QStringList &args, bool readStdout,
bool readStderr) {
executeWrapper(id, app, args, QString(), readStdout, readStderr);
}
void Pass::executeWrapper(PROCESS id, const QString &app,
const QStringList &args, QString input,
bool readStdout, bool readStderr) {
#ifdef QT_DEBUG
dbg() << app << args;
#endif
exec.execute(id, QtPassSettings::getPassStore(), app, args, std::move(input),
readStdout, readStderr);
}
void Pass::init() {
#ifdef __APPLE__
// If it exists, add the gpgtools to PATH
if (QFile("/usr/local/MacGPG2/bin").exists())
env.replaceInStrings("PATH=", "PATH=/usr/local/MacGPG2/bin:");
// Add missing /usr/local/bin
if (env.filter("/usr/local/bin").isEmpty())
env.replaceInStrings("PATH=", "PATH=/usr/local/bin:");
#endif
if (!QtPassSettings::getGpgHome().isEmpty()) {
QDir absHome(QtPassSettings::getGpgHome());
absHome.makeAbsolute();
env << "GNUPGHOME=" + absHome.path();
}
}
auto Pass::generatePassword(unsigned int length, const QString &charset)
-> QString {
if (length == 0) {
emit critical(tr("Invalid password length"),
tr("Can't generate password with zero length."));
return {};
}
QString passwd;
// --secure goes first as it overrides --no-* otherwise
QStringList args;
args.append("-1");
args.append("--secure");
}
args.append(QtPassSettings::isAvoidCapitals() ? "--no-capitalize"
: "--capitalize");
args.append(QtPassSettings::isAvoidNumbers() ? "--no-numerals"
: "--numerals");
args.append("--symbols");
}
args.append(QString::number(length));
// executeBlocking returns 0 on success, non-zero on failure
&passwd) == 0) {
static const QRegularExpression literalNewLines{"[\\n\\r]"};
passwd.remove(literalNewLines);
} else {
passwd.clear();
#ifdef QT_DEBUG
qDebug() << __FILE__ << ":" << __LINE__ << "\t"
<< "pwgen fail";
#endif
// Error is already handled by clearing passwd; no need for critical
// signal here
}
} else {
// Validate charset - if CUSTOM is selected but chars are empty,
// fall back to ALLCHARS to prevent weak passwords (issue #780)
const QString cs = fallbackCharset(
if (cs.length() > 0) {
passwd = generateRandomPassword(cs, length);
} else {
emit critical(
tr("No characters chosen"),
tr("Can't generate password, there are no characters to choose from "
"set in the configuration!"));
}
}
return passwd;
}
QString out, err;
{"--version"}, &out, &err) != 0) {
return false;
}
QRegularExpression versionRegex(R"(gpg \‍(GnuPG\) (\d+)\.(\d+))");
QRegularExpressionMatch match = versionRegex.match(out);
if (!match.hasMatch()) {
return false;
}
int major = match.captured(1).toInt();
int minor = match.captured(2).toInt();
return major > 2 || (major == 2 && minor >= 1);
}
return QStringLiteral("%echo Generating a default key\n"
"Key-Type: EdDSA\n"
"Key-Curve: Ed25519\n"
"Subkey-Type: ECDH\n"
"Subkey-Curve: Curve25519\n"
"Name-Real: \n"
"Name-Comment: QtPass\n"
"Name-Email: \n"
"Expire-Date: 0\n"
"%no-protection\n"
"%commit\n"
"%echo done");
}
return QStringLiteral("%echo Generating a default key\n"
"Key-Type: RSA\n"
"Subkey-Type: RSA\n"
"Name-Real: \n"
"Name-Comment: QtPass\n"
"Name-Email: \n"
"Expire-Date: 0\n"
"%no-protection\n"
"%commit\n"
"%echo done");
}
namespace {
auto resolveWslGpgconfPath(const QString &lastPart) -> QString {
int lastSep = lastPart.lastIndexOf('/');
if (lastSep < 0) {
lastSep = lastPart.lastIndexOf('\\');
}
if (lastSep >= 0) {
return lastPart.left(lastSep + 1) + "gpgconf";
}
return QStringLiteral("gpgconf");
}
QString findGpgconfInGpgDir(const QString &gpgPath) {
QFileInfo gpgInfo(gpgPath);
if (!gpgInfo.isAbsolute()) {
return QString();
}
QDir dir(gpgInfo.absolutePath());
#ifdef Q_OS_WIN
QFileInfo candidateExe(dir.filePath("gpgconf.exe"));
if (candidateExe.isExecutable()) {
return candidateExe.filePath();
}
#endif
QFileInfo candidate(dir.filePath("gpgconf"));
if (candidate.isExecutable()) {
return candidate.filePath();
}
return QString();
}
// Compatibility shim for Qt < 5.15 where QProcess::splitCommand is not
// available. Keep this fallback while supporting pre-5.15 builds; remove once
// the project's minimum supported Qt version is raised to 5.15 or newer.
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
QStringList splitCommandCompat(const QString &command) {
QStringList result;
QString current;
bool inSingleQuote = false;
bool inDoubleQuote = false;
bool escaping = false;
for (QChar ch : command) {
if (escaping) {
current.append(ch);
escaping = false;
continue;
}
if (ch == '\\') {
escaping = true;
continue;
}
if (ch == '\'' && !inDoubleQuote) {
inSingleQuote = !inSingleQuote;
continue;
}
if (ch == '"' && !inSingleQuote) {
inDoubleQuote = !inDoubleQuote;
continue;
}
if (ch.isSpace() && !inSingleQuote && !inDoubleQuote) {
if (!current.isEmpty()) {
result.append(current);
current.clear();
}
continue;
}
current.append(ch);
}
if (escaping) {
current.append('\\');
}
if (!current.isEmpty()) {
result.append(current);
}
return result;
}
#endif
} // namespace
auto Pass::resolveGpgconfCommand(const QString &gpgPath)
if (gpgPath.trimmed().isEmpty()) {
return {"gpgconf", {}};
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QStringList parts = QProcess::splitCommand(gpgPath);
#else
QStringList parts = splitCommandCompat(gpgPath);
#endif
if (parts.isEmpty()) {
return {"gpgconf", {}};
}
const QString first = parts.first();
if (first.compare("wsl", Qt::CaseInsensitive) == 0 ||
first.compare("wsl.exe", Qt::CaseInsensitive) == 0) {
if (parts.size() >= 2 && parts.at(1).startsWith("sh")) {
return {"gpgconf", {}};
}
if (parts.size() >= 2 &&
QFileInfo(parts.last()).fileName().startsWith("gpg")) {
QString wslGpgconf = resolveWslGpgconfPath(parts.last());
parts.removeLast();
parts.append(wslGpgconf);
return {parts.first(), parts.mid(1)};
}
return {"gpgconf", {}};
}
if (!first.contains('/') && !first.contains('\\')) {
return {"gpgconf", {}};
}
QString gpgconfPath = findGpgconfInGpgDir(first);
if (!gpgconfPath.isEmpty()) {
return {gpgconfPath, {}};
}
return {"gpgconf", {}};
}
void Pass::GenerateGPGKeys(QString batch) {
// Kill any stale GPG agents that might be holding locks on the key database
// This helps avoid "database locked" timeouts during key generation
QString gpgPath = QtPassSettings::getGpgExecutable();
if (!gpgPath.isEmpty()) {
ResolvedGpgconfCommand resolvedGpgconf = resolveGpgconfCommand(gpgPath);
QStringList killArgs = resolvedGpgconf.arguments;
killArgs << "--kill";
killArgs << "gpg-agent";
// Use same environment as key generation to target correct gpg-agent
Executor::executeBlocking(env, resolvedGpgconf.program, killArgs);
}
executeWrapper(GPG_GENKEYS, gpgPath, {"--gen-key", "--no-tty", "--batch"},
std::move(batch));
}
auto Pass::listKeys(QStringList keystrings, bool secret) -> QList<UserInfo> {
QStringList args = {"--no-tty", "--with-colons", "--with-fingerprint"};
args.append(secret ? "--list-secret-keys" : "--list-keys");
for (const QString &keystring : AS_CONST(keystrings)) {
if (!keystring.isEmpty()) {
args.append(keystring);
}
}
QString p_out;
&p_out) != 0) {
return QList<UserInfo>();
}
return parseGpgColonOutput(p_out, secret);
}
auto Pass::listKeys(const QString &keystring, bool secret) -> QList<UserInfo> {
return listKeys(QStringList(keystring), secret);
}
namespace {
auto containsAny(const QString &str, const QStringList &patterns) -> bool {
for (const QString &p : patterns) {
if (str.contains(p)) {
return true;
}
}
return false;
}
auto containsAnyCaseInsensitive(const QString &str, const QStringList &patterns)
-> bool {
const QString lower = str.toLower();
for (const QString &p : patterns) {
if (lower.contains(p)) {
return true;
}
}
return false;
}
} // namespace
auto gpgErrorMessage(const QString &err) -> QString {
// Machine-readable status tokens added by --status-fd 2
if (containsAny(err, {QStringLiteral("[GNUPG:] KEYEXPIRED"),
QStringLiteral("[GNUPG:] INV_RECP 5 ")}))
return QCoreApplication::translate(
"Pass", "Encryption failed: GPG key has expired. Please renew or "
"replace it.");
if (containsAny(err, {QStringLiteral("[GNUPG:] KEYREVOKED"),
QStringLiteral("[GNUPG:] INV_RECP 4 ")}))
return QCoreApplication::translate(
"Pass", "Encryption failed: GPG key has been revoked.");
if (containsAny(err, {QStringLiteral("[GNUPG:] NO_PUBKEY"),
QStringLiteral("[GNUPG:] INV_RECP")}))
return QCoreApplication::translate(
"Pass", "Encryption failed: recipient GPG key not found or invalid. "
"Check that the key ID in .gpg-id is correct and imported.");
if (err.contains(QStringLiteral("[GNUPG:] FAILURE")))
return QCoreApplication::translate(
"Pass", "Encryption failed. Check that your GPG key is valid.");
// Locale-dependent fallbacks
if (containsAnyCaseInsensitive(err, {QLatin1String("key has expired"),
QLatin1String("key expired")}))
return QCoreApplication::translate(
"Pass", "Encryption failed: GPG key has expired. Please renew or "
"replace it.");
if (containsAnyCaseInsensitive(err, {QLatin1String("key has been revoked"),
QLatin1String("revoked")}))
return QCoreApplication::translate(
"Pass", "Encryption failed: GPG key has been revoked.");
if (containsAnyCaseInsensitive(err, {QLatin1String("no public key"),
QLatin1String("unusable public key"),
QLatin1String("no secret key")}))
return QCoreApplication::translate(
"Pass", "Encryption failed: recipient GPG key not found or invalid. "
"Check that the key ID in .gpg-id is correct and imported.");
if (containsAnyCaseInsensitive(err, {QLatin1String("encryption failed")}))
return QCoreApplication::translate(
"Pass", "Encryption failed. Check that your GPG key is valid.");
return {};
}
namespace {
auto isGrepHeaderLine(const QString &rawLine, const QString &trimmedLine)
-> bool {
// ANSI-colored header starts with the blue escape; plain-text fallback:
// a non-indented line ending with ':' (pass grep format without color)
return rawLine.startsWith(QStringLiteral("\x1B[94m")) ||
(!rawLine.startsWith(' ') && !rawLine.startsWith('\t') &&
trimmedLine.endsWith(':'));
}
} // namespace
auto parseGrepOutput(const QString &rawOut)
-> QList<QPair<QString, QStringList>> {
static const QRegularExpression ansi(
QStringLiteral(R"(\x1B\‍[[0-9;]*[a-zA-Z])"));
QList<QPair<QString, QStringList>> results;
QString currentEntry;
QStringList currentMatches;
for (const QString &rawLine : rawOut.split('\n')) {
QString line = rawLine;
line.remove('\r');
line.remove(ansi);
line = line.trimmed();
const bool isHeader = isGrepHeaderLine(rawLine, line);
if (isHeader) {
if (!currentEntry.isEmpty() && !currentMatches.isEmpty())
results.append({currentEntry, currentMatches});
currentEntry = line.endsWith(':') ? line.chopped(1) : line;
currentMatches.clear();
} else if (!currentEntry.isEmpty()) {
if (!line.isEmpty())
currentMatches << line;
}
}
if (!currentEntry.isEmpty() && !currentMatches.isEmpty())
results.append({currentEntry, currentMatches});
return results;
}
void Pass::finished(int id, int exitCode, const QString &out,
const QString &err) {
auto pid = static_cast<PROCESS>(id);
if (exitCode != 0) {
handleProcessError(pid, exitCode, out, err);
return;
}
emitProcessFinishedSignal(pid, out, err);
}
void Pass::handleProcessError(PROCESS pid, int exitCode, const QString &out,
const QString &err) {
if (pid == PASS_GREP) {
handleGrepError(exitCode, err);
return;
}
if (pid == PASS_INSERT) {
const QString friendly = gpgErrorMessage(err);
if (!friendly.isEmpty()) {
emit processErrorExit(exitCode, formatInsertError(friendly, err));
return;
}
}
emit processErrorExit(exitCode, err);
}
void Pass::handleGrepError(int exitCode, const QString &err) {
if (exitCode == 1) {
emit finishedGrep({});
} else {
emit processErrorExit(exitCode, err);
emit finishedGrep({});
}
}
auto Pass::formatInsertError(const QString &friendly, const QString &err)
-> QString {
QStringList humanLines;
for (const QString &line : err.split('\n')) {
QString cleanedLine = line;
cleanedLine.remove('\r');
if (!cleanedLine.startsWith(QLatin1String("[GNUPG:]")))
humanLines.append(cleanedLine);
}
const QString humanErr = humanLines.join('\n').trimmed();
return humanErr.isEmpty() ? friendly : friendly + "\n\n" + humanErr;
}
void Pass::emitProcessFinishedSignal(PROCESS pid, const QString &out,
const QString &err) {
switch (pid) {
case GIT_INIT:
emit finishedGitInit(out, err);
break;
case GIT_PULL:
emit finishedGitPull(out, err);
break;
case GIT_PUSH:
emit finishedGitPush(out, err);
break;
case PASS_SHOW:
emit finishedShow(out);
break;
break;
emit finishedInsert(out, err);
break;
emit finishedRemove(out, err);
break;
case PASS_INIT:
emit finishedInit(out, err);
break;
case PASS_MOVE:
emit finishedMove(out, err);
break;
case PASS_COPY:
emit finishedCopy(out, err);
break;
emit finishedGenerateGPGKeys(out, err);
break;
case PASS_GREP:
break;
default:
#ifdef QT_DEBUG
dbg() << "Unhandled process type" << pid;
#endif
break;
}
}
// key must include the trailing '=' (e.g. "FOO="); env.filter() does substring
// matching so the '=' anchors the lookup to avoid collisions with longer names.
void Pass::setEnvVar(const QString &key, const QString &value) {
const bool hasEq = key.endsWith('=');
Q_ASSERT_X(hasEq, "Pass::setEnvVar",
"called with malformed key (missing '=')");
if (!hasEq) {
qWarning() << "Pass::setEnvVar called with malformed key (missing '='):"
<< key;
return;
}
const QStringList existing = env.filter(key);
for (const QString &entry : existing)
env.removeAll(entry);
if (!value.isEmpty())
env.append(key + value);
}
setEnvVar(QStringLiteral("PASSWORD_STORE_SIGNING_KEY="),
setEnvVar(QStringLiteral("PASSWORD_STORE_DIR="),
PasswordConfiguration passConfig = QtPassSettings::getPasswordConfiguration();
setEnvVar(QStringLiteral("PASSWORD_STORE_GENERATED_LENGTH="),
QString::number(passConfig.length));
setEnvVar(QStringLiteral("PASSWORD_STORE_CHARACTER_SET="),
effectiveCharset(passConfig));
exec.setEnvironment(env);
}
auto Pass::getGpgIdPath(const QString &for_file) -> QString {
QString passStore =
QDir::fromNativeSeparators(QtPassSettings::getPassStore());
QString normalizedFile = QDir::fromNativeSeparators(for_file);
QString fullPath = normalizedFile.startsWith(passStore)
? normalizedFile
: passStore + "/" + normalizedFile;
QDir gpgIdDir(QFileInfo(fullPath).absoluteDir());
bool found = false;
while (gpgIdDir.exists() && gpgIdDir.absolutePath().startsWith(passStore)) {
if (QFile(gpgIdDir.absoluteFilePath(".gpg-id")).exists()) {
found = true;
break;
}
if (!gpgIdDir.cdUp()) {
break;
}
}
QString gpgIdPath(
found ? gpgIdDir.absoluteFilePath(".gpg-id")
: QDir(QtPassSettings::getPassStore()).filePath(".gpg-id"));
return gpgIdPath;
}
auto Pass::getRecipientList(const QString &for_file) -> QStringList {
QFile gpgId(getGpgIdPath(for_file));
if (!gpgId.open(QIODevice::ReadOnly | QIODevice::Text)) {
return {};
}
QStringList recipients;
while (!gpgId.atEnd()) {
QString recipient(gpgId.readLine());
recipient = recipient.split("#")[0].trimmed();
if (!recipient.isEmpty() && Util::isValidKeyId(recipient)) {
recipients += recipient;
}
}
return recipients;
}
auto Pass::getRecipientString(const QString &for_file, const QString &separator,
int *count) -> QStringList {
Q_UNUSED(separator)
QStringList recipients = Pass::getRecipientList(for_file);
if (count) {
*count = recipients.size();
}
return recipients;
}
/* Copyright (C) 2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
auto Pass::boundedRandom(quint32 bound) -> quint32 {
if (bound < 2) {
return 0;
}
quint32 randval;
// Rejection-sampling threshold to avoid modulo bias.
// This follows the well-known "arc4random_uniform"-style approach:
// reject values in the low range [0, min), where
// min = 2^32 % bound
// so that the remaining range size is an exact multiple of `bound`.
//
// In quint32 arithmetic, (1 + ~bound) wraps to (2^32 - bound), therefore
// (1 + ~bound) % bound == 2^32 % bound.
const quint32 rejectionThreshold = (1 + ~bound) % bound;
do {
randval = QRandomGenerator::system()->generate();
} while (randval < rejectionThreshold);
return randval % bound;
}
auto Pass::generateRandomPassword(const QString &charset, unsigned int length)
-> QString {
if (charset.isEmpty() || length == 0U) {
return {};
}
QString out;
for (unsigned int i = 0; i < length; ++i) {
out.append(charset.at(static_cast<int>(
boundedRandom(static_cast<quint32>(charset.length())))));
}
return out;
}
id Identifier provided by the caller for this queued request.
Definition executor.h:76
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
void starting()
starting signal that is emited when process starts
void init()
Initialize the Pass instance.
Definition pass.cpp:115
void startingExecuteWrapper()
Emitted before executing a command.
void GenerateGPGKeys(QString batch)
Generate GPG keys using batch script.
Definition pass.cpp:415
void finishedCopy(const QString &, const QString &)
Emitted when copy finishes.
void finishedShow(const QString &)
Emitted when show finishes.
void finishedRemove(const QString &, const QString &)
Emitted when remove finishes.
Enums::PROCESS PROCESS
Definition pass.h:44
virtual auto generatePassword(unsigned int length, const QString &charset) -> QString
Generate random password.
Definition pass.cpp:139
void finishedMove(const QString &, const QString &)
Emitted when move finishes.
static bool gpgSupportsEd25519()
Check if GPG supports Ed25519 encryption.
Definition pass.cpp:199
void setEnvVar(const QString &key, const QString &value)
Set or remove an environment variable.
Definition pass.cpp:711
auto boundedRandom(quint32 bound) -> quint32
Generate random number in range.
Definition pass.cpp:819
void finishedGitInit(const QString &, const QString &)
Emitted when Git init finishes.
Pass()
Construct a Pass instance.
Definition pass.cpp:53
void executeWrapper(PROCESS id, const QString &app, const QStringList &args, bool readStdout=true, bool readStderr=true)
Execute external wrapper command.
Definition pass.cpp:96
static auto getRecipientList(const QString &for_file) -> QStringList
Get list of recipients for a password file.
Definition pass.cpp:778
static auto resolveGpgconfCommand(const QString &gpgPath) -> ResolvedGpgconfCommand
Resolve the gpgconf command to kill agents.
Definition pass.cpp:367
auto listKeys(QStringList keystrings, bool secret=false) -> QList< UserInfo >
List GPG keys matching patterns.
Definition pass.cpp:438
void finishedInsert(const QString &, const QString &)
Emitted when insert finishes.
void finishedGrep(const QList< QPair< QString, QStringList > > &results)
Emitted when grep finishes with matching results.
void finishedInit(const QString &, const QString &)
Emitted when init finishes.
static auto getGpgIdPath(const QString &for_file) -> QString
Get .gpg-id file path for a password file.
Definition pass.cpp:748
void finishedOtpGenerate(const QString &)
Emitted when OTP generation finishes.
Executor exec
Definition pass.h:42
void processErrorExit(int exitCode, const QString &err)
Emitted on process error exit.
void finishedGitPull(const QString &, const QString &)
Emitted when Git pull finishes.
void finishedGitPush(const QString &, const QString &)
Emitted when Git push finishes.
void updateEnv()
Update environment for subprocesses.
Definition pass.cpp:727
virtual void finished(int id, int exitCode, const QString &out, const QString &err)
Handle process completion.
Definition pass.cpp:606
static auto getRecipientString(const QString &for_file, const QString &separator=" ", int *count=nullptr) -> QStringList
Get recipients as string.
Definition pass.cpp:801
static QString getDefaultKeyTemplate()
Get default key template for new GPG keys.
Definition pass.cpp:220
void finishedGenerateGPGKeys(const QString &, const QString &)
Emitted when GPG key generation finishes.
auto generateRandomPassword(const QString &charset, unsigned int length) -> QString
Generate random password from charset.
Definition pass.cpp:848
static auto getPwgenExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get pwgen executable path.
static auto getPasswordConfiguration() -> PasswordConfiguration
Get complete password generation configuration.
static auto getGpgHome(const QString &defaultValue=QVariant().toString()) -> QString
Get GPG home directory.
static auto getPassStore(const QString &defaultValue=QVariant().toString()) -> QString
Get password store directory path.
static auto isAvoidCapitals(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether uppercase characters should be avoided.
static auto getGpgExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get GPG executable path.
static auto getPassSigningKey(const QString &defaultValue=QVariant().toString()) -> QString
Get GPG signing key for pass.
static auto isUseSymbols(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether symbol characters are enabled.
static auto isLessRandom(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether less random password generation is enabled.
static auto isUsePwgen(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether pwgen support is enabled.
static auto isAvoidNumbers(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether numeric characters should be avoided.
static auto isValidKeyId(const QString &keyId) -> bool
Check if a string looks like a valid GPG key ID. Accepts:
Definition util.cpp:280
Debug utilities for QtPass.
#define dbg()
Simple debug macro that includes file and line number.
Definition debughelper.h:21
auto parseGpgColonOutput(const QString &output, bool secret) -> QList< UserInfo >
Parse GPG –with-colons output into a list of UserInfo.
Utility macros for QtPass.
#define AS_CONST(x)
Cross-platform const_cast for range-based for loops.
Definition helpers.h:20
@ PASS_INIT
Definition enums.h:36
@ PASS_OTP_GENERATE
Definition enums.h:42
@ PASS_INSERT
Definition enums.h:34
@ GIT_INIT
Definition enums.h:27
@ PASS_COPY
Definition enums.h:39
@ PASS_MOVE
Definition enums.h:38
@ PASS_GREP
Definition enums.h:43
@ GPG_GENKEYS
Definition enums.h:37
@ PASS_REMOVE
Definition enums.h:35
@ PASS_SHOW
Definition enums.h:33
@ GIT_PULL
Definition enums.h:31
@ GIT_PUSH
Definition enums.h:32
@ PASS_INIT
Definition enums.h:36
@ PASS_OTP_GENERATE
Definition enums.h:42
@ PASS_INSERT
Definition enums.h:34
@ GIT_INIT
Definition enums.h:27
@ PASS_COPY
Definition enums.h:39
@ PASS_MOVE
Definition enums.h:38
@ PASS_GREP
Definition enums.h:43
@ GPG_GENKEYS
Definition enums.h:37
@ PASS_REMOVE
Definition enums.h:35
@ PASS_SHOW
Definition enums.h:33
@ GIT_PULL
Definition enums.h:31
@ GIT_PUSH
Definition enums.h:32
auto gpgErrorMessage(const QString &err) -> QString
Maps GPG stderr (which may include –status-fd 2 tokens) to a translated user-friendly encryption erro...
Definition pass.cpp:507
auto parseGrepOutput(const QString &rawOut) -> QList< QPair< QString, QStringList > >
Parses 'pass grep' raw output into (entry, matches) pairs.
Definition pass.cpp:568
QList< QPair< QString, QStringList > > parseGrepOutput(const QString &rawOut)
Parses 'pass grep' raw output into (entry, matches) pairs.
Definition pass.cpp:568
QString gpgErrorMessage(const QString &err)
Maps GPG stderr (which may include –status-fd 2 tokens) to a translated user-friendly encryption erro...
Definition pass.cpp:507
PROCESS
Identifies different subprocess operations used in QtPass.
Definition enums.h:26
Holds the Password configuration settings.
int length
Length of the password.
enum PasswordConfiguration::characterSet selected
QString Characters[CHARSETS_COUNT]
The different character sets.
QStringList arguments
Definition pass.h:19