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

Signs a GPG ID file and verifies its signature.

bool result = ImitatePass::signGpgIdFile(gpgIdFile, signingKeys); std::cout << result << std::endl; // Expected output: true if signing and verification succeed.

Signs a GPG ID file and verifies its signature.

bool result = ImitatePass::signGpgIdFile(gpgIdFile, signingKeys); std::cout << result << std::endl; // Expected output: true if signing and verification succeed

Parameters
QString&gpgIdFile - Path to the .gpgid file to be signed.
QStringList&signingKeys - List of signing keys; only the first key is used.
Returns
bool - True if the file was signed and its signature verified successfully; otherwise false.
// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
// SPDX-License-Identifier: GPL-3.0-or-later
#include "imitatepass.h"
#include "qtpasssettings.h"
#include "util.h"
#include <QDirIterator>
#include <QRegularExpression>
#include <utility>
#ifdef QT_DEBUG
#include "debughelper.h"
#endif
static auto pgit(const QString &path) -> QString {
if (!QtPassSettings::getGitExecutable().startsWith("wsl ")) {
return path;
}
QString res = "$(wslpath " + path + ")";
return res.replace('\\', '/');
}
static auto pgpg(const QString &path) -> QString {
if (!QtPassSettings::getGpgExecutable().startsWith("wsl ")) {
return path;
}
QString res = "$(wslpath " + path + ")";
return res.replace('\\', '/');
}
}
}
executeGit(GIT_PUSH, {"push"});
}
}
void ImitatePass::Show(QString file) {
file = QtPassSettings::getPassStore() + file + ".gpg";
QStringList args = {"-d", "--quiet", "--yes", "--no-encrypt-to",
"--batch", "--use-agent", pgpg(file)};
}
void ImitatePass::OtpGenerate(QString file) {
#ifdef QT_DEBUG
dbg() << "No OTP generation code for fake pass yet, attempting for file: " +
file;
#else
Q_UNUSED(file)
#endif
}
void ImitatePass::Insert(QString file, QString newValue, bool overwrite) {
file = file + ".gpg";
QString gpgIdPath = Pass::getGpgIdPath(file);
if (!verifyGpgIdFile(gpgIdPath)) {
emit critical(tr("Check .gpgid file signature!"),
tr("Signature for %1 is invalid.").arg(gpgIdPath));
return;
}
QStringList recipients = Pass::getRecipientList(file);
if (recipients.isEmpty()) {
// Already emit critical signal to notify user of error - no need to throw
emit critical(tr("Can not edit"),
tr("Could not read encryption key to use, .gpg-id "
"file missing or invalid."));
return;
}
QStringList args = {"--batch", "-eq", "--output", pgpg(file)};
for (auto &r : recipients) {
args.append("-r");
args.append(r);
}
if (overwrite) {
args.append("--yes");
}
args.append("-");
executeGpg(PASS_INSERT, args, newValue);
// Git is used when enabled - this is the standard pass workflow
if (!overwrite) {
executeGit(GIT_ADD, {"add", pgit(file)});
}
QString path = QDir(QtPassSettings::getPassStore()).relativeFilePath(file);
path.replace(Util::endsWithGpg(), "");
QString msg =
QString(overwrite ? "Edit" : "Add") + " for " + path + " using QtPass.";
gitCommit(file, msg);
}
}
void ImitatePass::gitCommit(const QString &file, const QString &msg) {
if (file.isEmpty()) {
executeGit(GIT_COMMIT, {"commit", "-m", msg});
} else {
executeGit(GIT_COMMIT, {"commit", "-m", msg, "--", pgit(file)});
}
}
void ImitatePass::Remove(QString file, bool isDir) {
if (!isDir) {
file += ".gpg";
}
executeGit(GIT_RM, {"rm", (isDir ? "-rf" : "-f"), pgit(file)});
// Normalize path the same way as add/edit operations
QString path = QDir(QtPassSettings::getPassStore()).relativeFilePath(file);
path.replace(Util::endsWithGpg(), "");
gitCommit(file, "Remove for " + path + " using QtPass.");
} else {
if (isDir) {
QDir dir(file);
dir.removeRecursively();
} else {
QFile(file).remove();
}
}
}
auto ImitatePass::checkSigningKeys(const QStringList &signingKeys) -> bool {
QString out;
QStringList args =
QStringList{"--status-fd=1", "--list-secret-keys"} + signingKeys;
int result =
if (result != 0) {
#ifdef QT_DEBUG
dbg() << "GPG list-secret-keys failed with code:" << result;
#endif
return false;
}
for (auto &key : signingKeys) {
if (out.contains("[GNUPG:] KEY_CONSIDERED " + key)) {
return true;
}
}
return false;
}
void ImitatePass::writeGpgIdFile(const QString &gpgIdFile,
const QList<UserInfo> &users) {
QFile gpgId(gpgIdFile);
if (!gpgId.open(QIODevice::WriteOnly | QIODevice::Text)) {
emit critical(tr("Cannot update"),
tr("Failed to open .gpg-id for writing."));
return;
}
bool secret_selected = false;
for (const UserInfo &user : users) {
if (user.enabled) {
gpgId.write((user.key_id + "\n").toUtf8());
secret_selected |= user.have_secret;
}
}
gpgId.close();
if (!secret_selected) {
emit critical(
tr("Check selected users!"),
tr("None of the selected keys have a secret key available.\n"
"You will not be able to decrypt any newly added passwords!"));
}
}
auto ImitatePass::signGpgIdFile(const QString &gpgIdFile,
const QStringList &signingKeys) -> bool {
QStringList args;
// Use only the first signing key; multiple --default-key options would
// override each other and only the last one would take effect.
if (!signingKeys.isEmpty()) {
#ifdef QT_DEBUG
if (signingKeys.size() > 1) {
dbg() << "Multiple signing keys configured; using only the first key:"
<< signingKeys.first();
}
#endif
args.append(QStringList{"--default-key", signingKeys.first()});
}
args.append(QStringList{"--yes", "--detach-sign", gpgIdFile});
int result =
if (result != 0) {
#ifdef QT_DEBUG
dbg() << "GPG signing failed with code:" << result;
#endif
emit critical(tr("GPG signing failed!"),
tr("Failed to sign %1.").arg(gpgIdFile));
return false;
}
if (!verifyGpgIdFile(gpgIdFile)) {
emit critical(tr("Check .gpgid file signature!"),
tr("Signature for %1 is invalid.").arg(gpgIdFile));
return false;
}
return true;
}
void ImitatePass::gitAddGpgId(const QString &gpgIdFile,
const QString &gpgIdSigFile, bool addFile,
bool addSigFile) {
if (addFile) {
executeGit(GIT_ADD, {"add", pgit(gpgIdFile)});
}
QString commitPath = gpgIdFile;
commitPath.replace(Util::endsWithGpg(), "");
gitCommit(gpgIdFile, "Added " + commitPath + " using QtPass.");
if (!addSigFile) {
return;
}
executeGit(GIT_ADD, {"add", pgit(gpgIdSigFile)});
commitPath = gpgIdSigFile;
commitPath.replace(QRegularExpression("\\.gpg$"), "");
gitCommit(gpgIdSigFile, "Added " + commitPath + " using QtPass.");
}
void ImitatePass::Init(QString path, const QList<UserInfo> &users) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QStringList signingKeys =
QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
#else
QStringList signingKeys =
QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
#endif
QString gpgIdSigFile = path + ".gpg-id.sig";
bool addSigFile = false;
if (!signingKeys.isEmpty()) {
if (!checkSigningKeys(signingKeys)) {
emit critical(tr("No signing key!"),
tr("None of the secret signing keys is available.\n"
"You will not be able to change the user list!"));
return;
}
QFileInfo checkFile(gpgIdSigFile);
if (!checkFile.exists() || !checkFile.isFile()) {
addSigFile = true;
}
}
QString gpgIdFile = path + ".gpg-id";
bool addFile = false;
QFileInfo checkFile(gpgIdFile);
if (!checkFile.exists() || !checkFile.isFile()) {
addFile = true;
}
}
writeGpgIdFile(gpgIdFile, users);
if (!signingKeys.isEmpty()) {
if (!signGpgIdFile(gpgIdFile, signingKeys)) {
return;
}
}
gitAddGpgId(gpgIdFile, gpgIdSigFile, addFile, addSigFile);
}
}
auto ImitatePass::verifyGpgIdFile(const QString &file) -> bool {
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QStringList signingKeys =
QtPassSettings::getPassSigningKey().split(" ", Qt::SkipEmptyParts);
#else
QStringList signingKeys =
QtPassSettings::getPassSigningKey().split(" ", QString::SkipEmptyParts);
#endif
if (signingKeys.isEmpty()) {
return true;
}
QString out;
QStringList args =
QStringList{"--verify", "--status-fd=1", pgpg(file) + ".sig", pgpg(file)};
int result =
if (result != 0) {
#ifdef QT_DEBUG
dbg() << "GPG verify failed with code:" << result;
#endif
return false;
}
QRegularExpression re(
R"(^\‍[GNUPG:\‍] VALIDSIG ([A-F0-9]{40}) .* ([A-F0-9]{40})\r?$)",
QRegularExpression::MultilineOption);
QRegularExpressionMatch m = re.match(out);
if (!m.hasMatch()) {
return false;
}
QStringList fingerprints = m.capturedTexts();
fingerprints.removeFirst();
for (auto &key : signingKeys) {
if (fingerprints.contains(key)) {
return true;
}
}
return false;
}
auto ImitatePass::removeDir(const QString &dirName) -> bool {
bool result = true;
QDir dir(dirName);
if (dir.exists(dirName)) {
for (const QFileInfo &info :
dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden |
QDir::AllDirs | QDir::Files,
QDir::DirsFirst)) {
if (info.isDir()) {
result = removeDir(info.absoluteFilePath());
} else {
result = QFile::remove(info.absoluteFilePath());
}
if (!result) {
return result;
}
}
result = dir.rmdir(dirName);
}
return result;
}
auto ImitatePass::verifyGpgIdForDir(const QString &file,
QStringList &gpgIdFilesVerified,
QStringList &gpgId) -> bool {
QString gpgIdPath = Pass::getGpgIdPath(file);
if (gpgIdFilesVerified.contains(gpgIdPath)) {
return true;
}
if (!verifyGpgIdFile(gpgIdPath)) {
emit critical(tr("Check .gpgid file signature!"),
tr("Signature for %1 is invalid.").arg(gpgIdPath));
return false;
}
gpgIdFilesVerified.append(gpgIdPath);
gpgId = getRecipientList(file);
gpgId.sort();
return true;
}
auto ImitatePass::getKeysFromFile(const QString &fileName) -> QStringList {
QStringList args = {
"-v", "--no-secmem-warning", "--no-permission-warning",
"--list-only", "--keyid-format=long", pgpg(fileName)};
QString keys;
QString err;
const int result = Executor::executeBlocking(
QtPassSettings::getGpgExecutable(), args, &keys, &err);
if (result != 0 && keys.isEmpty() && err.isEmpty()) {
return QStringList();
}
QStringList actualKeys;
keys += err;
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QStringList key = keys.split(Util::newLinesRegex(), Qt::SkipEmptyParts);
#else
QStringList key = keys.split(Util::newLinesRegex(), QString::SkipEmptyParts);
#endif
QListIterator<QString> itr(key);
while (itr.hasNext()) {
QString current = itr.next();
QStringList cur = current.split(" ");
if (cur.length() > 4) {
QString actualKey = cur.takeAt(4);
if (actualKey.length() == 16) {
actualKeys << actualKey;
}
}
}
actualKeys.sort();
return actualKeys;
}
auto ImitatePass::reencryptSingleFile(const QString &fileName,
const QStringList &recipients) -> bool {
#ifdef QT_DEBUG
dbg() << "reencrypt " << fileName << " for " << recipients;
#endif
QString local_lastDecrypt;
QStringList args = {
"-d", "--quiet", "--yes", "--no-encrypt-to",
"--batch", "--use-agent", pgpg(fileName)};
args, &local_lastDecrypt);
if (result != 0 || local_lastDecrypt.isEmpty()) {
#ifdef QT_DEBUG
dbg() << "Decrypt error on re-encrypt for:" << fileName;
#endif
return false;
}
if (local_lastDecrypt.right(1) != "\n") {
local_lastDecrypt += "\n";
}
// Use passed recipients instead of re-reading from file
if (recipients.isEmpty()) {
emit critical(tr("Can not edit"),
tr("Could not read encryption key to use, .gpg-id "
"file missing or invalid."));
return false;
}
// Encrypt to temporary file for atomic replacement
QString tempPath = fileName + ".reencrypt.tmp";
args = QStringList{"--yes", "--batch", "-eq", "--output", pgpg(tempPath)};
for (const auto &i : recipients) {
args.append("-r");
args.append(i);
}
args.append("-");
local_lastDecrypt);
if (result != 0) {
#ifdef QT_DEBUG
dbg() << "Encrypt error on re-encrypt for:" << fileName;
#endif
QFile::remove(tempPath);
return false;
}
// Verify encryption worked by attempting to decrypt the temp file
QString verifyOutput;
args = QStringList{"-d", "--quiet", "--batch", "--use-agent", pgpg(tempPath)};
&verifyOutput);
if (result != 0 || verifyOutput.isEmpty()) {
#ifdef QT_DEBUG
dbg() << "Verification failed for:" << tempPath;
#endif
QFile::remove(tempPath);
return false;
}
// Verify content matches original decrypted content (defense in depth)
if (verifyOutput.trimmed() != local_lastDecrypt.trimmed()) {
#ifdef QT_DEBUG
dbg() << "Verification content mismatch for:" << tempPath;
#endif
QFile::remove(tempPath);
return false;
}
// Atomic replace with backup: rename original to .bak, rename temp to
// original, then remove backup
QString backupPath = fileName + ".reencrypt.bak";
if (!QFile::rename(fileName, backupPath)) {
#ifdef QT_DEBUG
dbg() << "Failed to backup original file:" << fileName;
#endif
QFile::remove(tempPath);
return false;
}
if (!QFile::rename(tempPath, fileName)) {
#ifdef QT_DEBUG
dbg() << "Failed to rename temp file to:" << fileName;
#endif
// Restore backup and clean up temp file
QFile::rename(backupPath, fileName);
QFile::remove(tempPath);
emit critical(
tr("Re-encryption failed"),
tr("Failed to replace %1. Original has been restored.").arg(fileName));
return false;
}
// Success - remove backup
QFile::remove(backupPath);
{"add", pgit(fileName)});
QString path =
QDir(QtPassSettings::getPassStore()).relativeFilePath(fileName);
path.replace(Util::endsWithGpg(), "");
{"commit", pgit(fileName), "-m",
"Re-encrypt for " + path + " using QtPass."});
}
return true;
}
return true;
}
emit statusMsg(tr("Creating backup commit"), 2000);
const QString git = QtPassSettings::getGitExecutable();
QString statusOut;
if (Executor::executeBlocking(git, {"status", "--porcelain"}, &statusOut) !=
0) {
emit critical(
tr("Backup commit failed"),
tr("Could not inspect git status. Re-encryption was aborted."));
return false;
}
if (!statusOut.trimmed().isEmpty()) {
if (Executor::executeBlocking(git, {"add", "-A"}) != 0 ||
git, {"commit", "-m", "Backup before re-encryption"}) != 0) {
emit critical(tr("Backup commit failed"),
tr("Re-encryption was aborted because a git backup could "
"not be created."));
return false;
}
}
return true;
}
void ImitatePass::reencryptPath(const QString &dir) {
emit statusMsg(tr("Re-encrypting from folder %1").arg(dir), 3000);
emit statusMsg(tr("Updating password-store"), 2000);
}
// Create backup before re-encryption - abort if it fails
return;
}
QDir currentDir;
QDirIterator gpgFiles(dir, QStringList() << "*.gpg", QDir::Files,
QDirIterator::Subdirectories);
QStringList gpgIdFilesVerified;
QStringList gpgId;
int successCount = 0;
int failCount = 0;
while (gpgFiles.hasNext()) {
QString fileName = gpgFiles.next();
if (gpgFiles.fileInfo().path() != currentDir.path()) {
if (!verifyGpgIdForDir(fileName, gpgIdFilesVerified, gpgId)) {
return;
}
if (gpgId.isEmpty() && !gpgIdFilesVerified.isEmpty()) {
emit critical(tr("GPG ID verification failed"),
tr("Could not verify .gpg-id for directory."));
return;
}
}
QStringList actualKeys = getKeysFromFile(fileName);
if (actualKeys != gpgId) {
if (reencryptSingleFile(fileName, gpgId)) {
successCount++;
} else {
failCount++;
emit critical(tr("Re-encryption failed"),
tr("Failed to re-encrypt %1").arg(fileName));
}
}
}
if (failCount > 0) {
emit statusMsg(tr("Re-encryption completed: %1 succeeded, %2 failed")
.arg(successCount)
.arg(failCount),
5000);
} else {
emit statusMsg(
tr("Re-encryption completed: %1 files re-encrypted").arg(successCount),
3000);
}
emit statusMsg(tr("Updating password-store"), 2000);
}
}
auto ImitatePass::resolveMoveDestination(const QString &src,
const QString &dest, bool force)
-> QString {
QFileInfo srcFileInfo(src);
QFileInfo destFileInfo(dest);
QString destFile;
QString srcFileBaseName = srcFileInfo.fileName();
if (srcFileInfo.isFile()) {
if (destFileInfo.isFile()) {
if (!force) {
#ifdef QT_DEBUG
dbg() << "Destination file already exists";
#endif
return QString();
}
destFile = dest;
} else if (destFileInfo.isDir()) {
destFile = QDir(dest).filePath(srcFileBaseName);
} else {
destFile = dest;
}
if (destFile.endsWith(".gpg", Qt::CaseInsensitive)) {
destFile.chop(4);
}
destFile.append(".gpg");
} else if (srcFileInfo.isDir()) {
if (destFileInfo.isDir()) {
destFile = QDir(dest).filePath(srcFileBaseName);
} else if (destFileInfo.isFile()) {
#ifdef QT_DEBUG
dbg() << "Destination is a file";
#endif
return QString();
} else {
destFile = dest;
}
} else {
#ifdef QT_DEBUG
dbg() << "Source file does not exist";
#endif
return QString();
}
return destFile;
}
void ImitatePass::executeMoveGit(const QString &src, const QString &destFile,
bool force) {
QStringList args;
args << "mv";
if (force) {
args << "-f";
}
args << pgit(src);
args << pgit(destFile);
QString relSrc = QDir(QtPassSettings::getPassStore()).relativeFilePath(src);
relSrc.replace(Util::endsWithGpg(), "");
QString relDest =
QDir(QtPassSettings::getPassStore()).relativeFilePath(destFile);
relDest.replace(Util::endsWithGpg(), "");
QString message = QString("Moved for %1 to %2 using QtPass.");
message = message.arg(relSrc, relDest);
gitCommit("", message);
}
void ImitatePass::Move(const QString src, const QString dest,
const bool force) {
QString destFile = resolveMoveDestination(src, dest, force);
if (destFile.isEmpty()) {
return;
}
#ifdef QT_DEBUG
dbg() << "Move Source: " << src;
dbg() << "Move Destination: " << destFile;
#endif
executeMoveGit(src, destFile, force);
} else {
QDir qDir;
if (force) {
qDir.remove(destFile);
}
qDir.rename(src, destFile);
}
}
void ImitatePass::Copy(const QString src, const QString dest,
const bool force) {
QFileInfo destFileInfo(dest);
QStringList args;
args << "cp";
if (force) {
args << "-f";
}
args << pgit(src);
args << pgit(dest);
QString message = QString("Copied from %1 to %2 using QtPass.");
message = message.arg(src, dest);
gitCommit("", message);
} else {
QDir qDir;
if (force) {
qDir.remove(dest);
}
QFile::copy(src, dest);
}
// reecrypt all files under the new folder
if (destFileInfo.isDir()) {
reencryptPath(destFileInfo.absoluteFilePath());
} else if (destFileInfo.isFile()) {
reencryptPath(destFileInfo.dir().path());
}
}
void ImitatePass::executeGpg(PROCESS id, const QStringList &args, QString input,
bool readStdout, bool readStderr) {
executeWrapper(id, QtPassSettings::getGpgExecutable(), args, std::move(input),
readStdout, readStderr);
}
void ImitatePass::executeGit(PROCESS id, const QStringList &args, QString input,
bool readStdout, bool readStderr) {
executeWrapper(id, QtPassSettings::getGitExecutable(), args, std::move(input),
readStdout, readStderr);
}
void ImitatePass::finished(int id, int exitCode, const QString &out,
const QString &err) {
#ifdef QT_DEBUG
dbg() << "Imitate Pass";
#endif
static QString transactionOutput;
PROCESS pid = transactionIsOver(static_cast<PROCESS>(id));
transactionOutput.append(out);
if (exitCode == 0) {
if (pid == INVALID) {
return;
}
} else {
while (pid == INVALID) {
id = exec.cancelNext();
if (id == -1) {
// this is probably irrecoverable and shall not happen
#ifdef QT_DEBUG
dbg() << "No such transaction!";
#endif
return;
}
pid = transactionIsOver(static_cast<PROCESS>(id));
}
}
Pass::finished(pid, exitCode, transactionOutput, err);
transactionOutput.clear();
}
void ImitatePass::executeWrapper(PROCESS id, const QString &app,
const QStringList &args, QString input,
bool readStdout, bool readStderr) {
Pass::executeWrapper(id, app, args, input, readStdout, readStderr);
}
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
RAII helper for wrapping operations in transactions.
auto createBackupCommit() -> bool
Create git backup commit before re-encryption.
void OtpGenerate(QString file) override
Generate OTP.
void GitInit() override
Initialize Git repository.
void executeGpg(PROCESS id, const QStringList &args, QString input=QString(), bool readStdout=true, bool readStderr=true)
Execute GPG command.
void GitPull_b() override
Pull with rebase.
auto checkSigningKeys(const QStringList &signingKeys) -> bool
Check if signing keys are valid.
ImitatePass()
Construct ImitatePass instance.
auto reencryptSingleFile(const QString &fileName, const QStringList &recipients) -> bool
Re-encrypt single file with new recipients.
auto verifyGpgIdFile(const QString &file) -> bool
Verify .gpg-id file exists and is valid.
void executeGit(PROCESS id, const QStringList &args, QString input=QString(), bool readStdout=true, bool readStderr=true)
Execute git command.
void Init(QString path, const QList< UserInfo > &users) override
Initialize store.
auto verifyGpgIdForDir(const QString &file, QStringList &gpgIdFilesVerified, QStringList &gpgId) -> bool
Verify .gpg-id file for a directory.
void Insert(QString file, QString newValue, bool overwrite=false) override
Insert new password.
auto removeDir(const QString &dirName) -> bool
Remove directory recursively.
void executeMoveGit(const QString &src, const QString &destFile, bool force)
Execute git move operation.
void Move(const QString src, const QString dest, const bool force=false) override
Move password file.
void Copy(const QString src, const QString dest, const bool force=false) override
Copy password file.
void endReencryptPath()
Emitted after finishing re-encryption.
void finished(int id, int exitCode, const QString &out, const QString &err) override
Handle process completion.
void executeWrapper(PROCESS id, const QString &app, const QStringList &args, QString input, bool readStdout=true, bool readStderr=true) override
Execute command wrapper.
auto signGpgIdFile(const QString &gpgIdFile, const QStringList &signingKeys) -> bool
Sign .gpg-id file with signing keys.
void Remove(QString file, bool isDir=false) override
Remove password.
void GitPull() override
Pull from remote.
void Show(QString file) override
Show decrypted password.
auto resolveMoveDestination(const QString &src, const QString &dest, bool force) -> QString
Resolve destination for move operation.
void GitPush() override
Push to remote.
void writeGpgIdFile(const QString &gpgIdFile, const QList< UserInfo > &users)
Write recipients to .gpg-id file.
void gitAddGpgId(const QString &gpgIdFile, const QString &gpgIdSigFile, bool addFile, bool addSigFile)
Add .gpg-id to git staging.
void startReencryptPath()
Emitted before starting re-encryption.
auto getKeysFromFile(const QString &fileName) -> QStringList
Read recipients from file.
void reencryptPath(const QString &dir)
Re-encrypt entire directory.
void gitCommit(const QString &file, const QString &msg)
Commit changes to git.
void critical(const QString &, const QString &)
Emit critical error.
Enums::PROCESS PROCESS
Definition pass.h:44
void statusMsg(const QString &, int)
Emit status message.
void executeWrapper(PROCESS id, const QString &app, const QStringList &args, bool readStdout=true, bool readStderr=true)
Execute external wrapper command.
Definition pass.cpp:57
static auto getRecipientList(const QString &for_file) -> QStringList
Get list of recipients for a password file.
Definition pass.cpp:550
static auto getGpgIdPath(const QString &for_file) -> QString
Get .gpg-id file path for a password file.
Definition pass.cpp:520
Executor exec
Definition pass.h:42
virtual void finished(int id, int exitCode, const QString &out, const QString &err)
Handle process completion.
Definition pass.cpp:429
static auto isAutoPull(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether automatic pull is enabled.
static auto isUseGit(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether Git integration is enabled.
static auto getPassStore(const QString &defaultValue=QVariant().toString()) -> QString
Get password store directory path.
static auto isAddGPGId(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to auto-add GPG ID when receiving files.
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 isUseWebDav(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether WebDAV integration is enabled.
static auto isAutoPush(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether automatic push is enabled.
static auto getGitExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get git executable path.
static auto endsWithGpg() -> const QRegularExpression &
Returns a regex to match .gpg file extensions.
Definition util.cpp:249
static auto newLinesRegex() -> const QRegularExpression &
Returns a regex to match newline characters.
Definition util.cpp:272
auto transactionIsOver(Enums::PROCESS) -> Enums::PROCESS
transactionIsOver checks wheather currently finished process is last in current transaction
void transactionAdd(Enums::PROCESS)
transactionAdd If called after call to transactionStart() and before transactionEnd(),...
Debug utilities for QtPass.
#define dbg()
Simple debug macro that includes file and line number.
Definition debughelper.h:21
@ PASS_INIT
Definition enums.h:36
@ PASS_INSERT
Definition enums.h:34
@ GIT_INIT
Definition enums.h:27
@ PASS_COPY
Definition enums.h:39
@ PASS_MOVE
Definition enums.h:38
@ GIT_MOVE
Definition enums.h:40
@ PASS_REMOVE
Definition enums.h:35
@ GIT_COPY
Definition enums.h:41
@ INVALID
Definition enums.h:43
@ GIT_COMMIT
Definition enums.h:29
@ GIT_RM
Definition enums.h:30
@ PASS_SHOW
Definition enums.h:33
@ GIT_ADD
Definition enums.h:28
@ GIT_PULL
Definition enums.h:31
@ GIT_PUSH
Definition enums.h:32
@ CLIPBOARD_ALWAYS
Definition enums.h:18
@ CLIPBOARD_NEVER
Definition enums.h:17
@ CLIPBOARD_ON_DEMAND
Definition enums.h:19
@ PASS_INIT
Definition enums.h:36
@ PASS_OTP_GENERATE
Definition enums.h:44
@ PASS_INSERT
Definition enums.h:34
@ GIT_INIT
Definition enums.h:27
@ PASS_COPY
Definition enums.h:39
@ PASS_MOVE
Definition enums.h:38
@ GIT_MOVE
Definition enums.h:40
@ GPG_GENKEYS
Definition enums.h:37
@ PASS_REMOVE
Definition enums.h:35
@ GIT_COPY
Definition enums.h:41
@ INVALID
Definition enums.h:43
@ GIT_COMMIT
Definition enums.h:29
@ GIT_RM
Definition enums.h:30
@ PASS_SHOW
Definition enums.h:33
@ GIT_ADD
Definition enums.h:28
@ PROCESS_COUNT
Definition enums.h:42
@ GIT_PULL
Definition enums.h:31
@ GIT_PUSH
Definition enums.h:32
PROCESS
Identifies different subprocess operations used in QtPass.
Definition enums.h:26