QtPass 2.0.0
Developer documentation
Loading...
Searching...
No Matches
realpass.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
2// SPDX-License-Identifier: GPL-3.0-or-later
9#include "realpass.h"
10#include "executor.h"
11#include "gpgidsigner.h"
12#include "pathvalidator.h"
13#include "qtpasslogging.h"
14#include "util.h"
15
16#include <QCoreApplication>
17#include <QCryptographicHash>
18#include <QDir>
19#include <QFile>
20#include <QFileInfo>
21#include <QProcess>
22#include <QRegularExpression>
23#include <utility>
24
26using Enums::GIT_INIT;
27using Enums::GIT_PULL;
28using Enums::GIT_PUSH;
35
40
42
43void RealPass::GitInit() { executePass(GIT_INIT, {"git", "init"}); }
44
46 int result =
48 if (result != 0) {
49 qCDebug(lcQtPass) << "Git pull failed with code:" << result;
50 }
51}
52
53void RealPass::GitPull() { executePass(GIT_PULL, {"git", "pull"}); }
54
55void RealPass::GitPush() { executePass(GIT_PUSH, {"git", "push"}); }
56
57void RealPass::Show(QString file) {
58 // pass follows links as readily as gpg does.
59 if (refuseLinkedPath(file + ".gpg")) {
60 return;
61 }
62 queueShow(file);
63 executePass(PASS_SHOW, {"show", file}, "", true);
64}
65
67 return {m_settings.gpgExecutable,
69 [this](const QString &app, const QStringList &args,
70 const QString &input, QString *out, QString *err) {
71 QProcess gpg;
72 gpg.setProcessEnvironment(exec.environment());
73 return Executor::executeBlocking(gpg, app, args, input, out, err);
74 }};
75}
76
77auto RealPass::refuseList(const QString &file, const GpgIdSigner &signer,
78 QSet<QString> &verified, const QString &within,
79 const QString &except) -> bool {
80 if (refuseSkippedGpgId(file, true, except)) {
81 return true;
82 }
83 const QString gpgIdFile = Pass::getGpgIdPath(file, m_settings.passStore);
84 const QString absolute =
85 QDir::cleanPath(QFileInfo(gpgIdFile).absoluteFilePath());
86 if (verified.contains(gpgIdFile) ||
87 (!except.isEmpty() &&
88 absolute == QDir::cleanPath(QFileInfo(except).absoluteFilePath())) ||
89 (!within.isEmpty() && !absolute.startsWith(within))) {
90 return false;
91 }
92 QString why =
93 QCoreApplication::translate("ImitatePass", "Signature for %1 is invalid.")
94 .arg(gpgIdFile);
95 QByteArray contents;
96 if (!verifySignedList(signer, gpgIdFile, &contents, &why)) {
97 emit critical(QCoreApplication::translate("ImitatePass",
98 "Check .gpg-id file signature!"),
99 why);
100 return true;
101 }
102 verified.insert(gpgIdFile);
103 return false;
104}
105
106auto RealPass::refuseUnverifiedList(const QString &file) -> bool {
107 // pass verifies the signature itself, but knows nothing of the generation
108 // and folder lines: an older authentic list put back, or one signed for
109 // another folder, would get the secret (#2077). The same checks as the
110 // native backend, with gpg in the store's environment. pass reads the list
111 // again afterwards; a swap in between is a concurrent writer, out of
112 // scope (SECURITY.md).
113 const GpgIdSigner signer = listSigner();
114 if (!signer.enabled()) {
115 return false;
116 }
117 QSet<QString> verified;
118 return refuseList(file, signer, verified);
119}
120
121namespace {
126auto passFoldersUnder(const QString &dir) -> QStringList {
127 QStringList folders{QDir::cleanPath(dir)};
128 const QFileInfoList children = QDir(dir).entryInfoList(
129 QDir::Dirs | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
130 for (const QFileInfo &child : children) {
131 if (child.isSymLink() || child.isJunction() ||
132 child.fileName() == QLatin1String(".git")) {
133 continue;
134 }
135 folders << passFoldersUnder(child.absoluteFilePath());
136 }
137 return folders;
138}
139} // namespace
140
141auto RealPass::refuseUnverifiedTree(const QString &dir, bool onlyListsWithin,
142 const QString &except) -> bool {
143 const GpgIdSigner signer = listSigner();
144 if (!signer.enabled()) {
145 return false;
146 }
147 // One gpg call per list, before pass runs: a store with many lists makes
148 // that a noticeable pause, so say what it is.
149 emit statusMsg(tr("Checking the recipient lists under %1…")
150 .arg(QDir::toNativeSeparators(QDir::cleanPath(dir))),
151 3000);
152 // pass mv and cp re-encrypt every entry of the folder they write to, each
153 // to its nearest list, walking as passFoldersUnder() does. For the folder
154 // that moves, the lists inside it go along: checked where they lie now
155 // (after the move their folder line names the old place until the
156 // recipients are saved there again), while a list above it is replaced
157 // by the destination's, which the caller checks. For entries already in
158 // the destination, their lists stay where they are: all of them count.
159 // Absolute, as getGpgIdPath() hands lists back: a relative or other
160 // spelling would match nothing and check nothing.
161 const QString within =
162 onlyListsWithin ? QDir::cleanPath(QFileInfo(dir).absoluteFilePath()) +
163 QLatin1Char('/')
164 : QString();
165 QSet<QString> verified;
166 // Every folder's list counts, also where no entry uses it yet: cp -r
167 // merges an incoming folder into one of the same name, so the entries it
168 // brings get a list already there, and a list it brings replaces the one
169 // there for the entries already in it.
170 for (const QString &folder : passFoldersUnder(dir)) {
171 if (refuseList(folder, signer, verified, within, except)) {
172 return true;
173 }
174 }
175 return false;
176}
177
178auto RealPass::storeGit(const QStringList &args, QString *out) -> bool {
179 if (!m_settings.useGit) {
180 return false;
181 }
182 // `pass git` runs git in the store with PASSWORD_STORE_DIR set, as the
183 // store's other quick lookups do; its exit code is git's own.
184 QString err;
186 exec.environment(), m_settings.passExecutable,
187 QStringList{QStringLiteral("git")} + args, out, &err) == 0;
188}
189
190void RealPass::Insert(QString file, QString newValue, bool overwrite) {
191 if (refuseLinkedPath(file + ".gpg")) {
192 return;
193 }
194 const QString entry =
195 QDir::cleanPath(QDir::isAbsolutePath(file)
196 ? file + ".gpg"
197 : QDir(m_settings.passStore).filePath(file) + ".gpg");
198 if (refuseUnverifiedList(entry)) {
199 return;
200 }
202 return;
203 }
204 m_insertQueue.enqueue(entry);
205 // Past every refusal: this insert is now queued and will report once.
206 queueInsert();
207 QStringList args = {"insert", "-m"};
208 if (overwrite) {
209 args.append("-f");
210 }
211 args.append(file);
212 executePass(PASS_INSERT, args, newValue);
213}
214
215void RealPass::onDequeuing(int id, bool completes) {
216 if (id != PASS_INSERT || m_insertQueue.isEmpty()) {
217 return;
218 }
219 const QString target = m_insertQueue.dequeue();
220 if (completes) {
221 m_insertPending.enqueue({target, entryFingerprint(target)});
222 }
223}
224
225auto RealPass::insertWritten(const QString &err) const -> bool {
226 if (m_insertDone.target.isEmpty()) {
227 return false;
228 }
229 // gpg broke off (a full disk, killed): pass says so, and what gpg left
230 // at the entry's name, if anything, is no entry. The line is pass's own
231 // (`die "Password encryption aborted."` after gpg in cmd_insert and
232 // cmd_edit of password-store.sh), which pass does not translate.
233 if (err.contains(QLatin1String("Password encryption aborted."))) {
234 return false;
235 }
236 // pass writes the new ciphertext to the entry's name before it commits,
237 // and an encryption never gives the same bytes twice (a fresh session
238 // key), so an edited entry has changed as surely as a new one appeared.
239 const QByteArray after = entryFingerprint(m_insertDone.target);
240 return !after.isEmpty() && after != m_insertDone.before;
241}
242
243auto RealPass::entryFingerprint(const QString &path) -> QByteArray {
244 QFile file;
245 if (!Util::openRegularFile(path, file)) {
246 return {};
247 }
248 QCryptographicHash hash(QCryptographicHash::Sha256);
249 if (!hash.addData(&file)) {
250 return {};
251 }
252 return hash.result();
253}
254
255void RealPass::Remove(QString file, bool isDir) {
256 // Nothing behind a link is the store's to delete.
257 if (refuseLinkedPath(isDir ? file : file + ".gpg", LinkScope::ParentsOnly)) {
258 return;
259 }
261 return;
262 }
263 // pass rm turns a folder into "<folder>/" and rm -rf then follows a link
264 // and empties its target, so a linked folder is unlinked here and pass's
265 // git is only asked to forget it. pass rm -f on a linked .gpg unlinks.
266 const QString full = QDir::cleanPath(m_settings.passStore + file);
267 if (isDir && Util::isLinkedFolder(full)) {
268 if (!Util::removeTree(full)) {
269 const QString why = tr("Could not remove the link %1.").arg(full);
270 emit critical(tr("Delete failed"), why);
271 emit processErrorExit(1, why);
272 return;
273 }
274 if (m_settings.useGit) {
275 // `pass git` exits 0 whatever git did, so ask by output whether git
276 // knew the link (these quick lookups block; the commit is queued).
277 const QString rel = QDir(m_settings.passStore).relativeFilePath(full);
278 // With the store's environment (PASSWORD_STORE_DIR), as executePass.
279 QString known;
280 QString err;
281 // The link is gone from disk either way. A failed lookup or rm leaves
282 // git tracking it: say so rather than report a clean removal.
283 bool recorded = Executor::executeBlocking(
285 {"git", "ls-files", "--", rel}, &known, &err) == 0;
286 if (recorded && !known.trimmed().isEmpty()) {
287 recorded =
290 {"git", "rm", "-q", "--cached", "--", rel}, &known, &err) == 0;
291 if (recorded) {
292 // `pass git commit` is git's commit as it is: pass adds -S only
293 // to the commits it makes itself, so ask as its git_commit() does.
294 QString signs;
295 const bool sign =
298 {"git", "config", "--bool", "--get", "pass.signcommits"},
299 &signs, nullptr) == 0 &&
300 signs.trimmed() == QLatin1String("true");
301 QStringList commit{"git", "commit", "-q"};
302 if (sign) {
303 commit << "-S";
304 }
305 // Queued, as every other commit, so a signer or hook that waits
306 // (a pinentry, an agent) does not freeze the window; finished()
307 // judges it by what is left staged, since `pass git` exits 0
308 // whatever git did.
309 m_linkCommits.enqueue(
313 commit + QStringList{"-m", "Remove for " + rel + " using QtPass.",
314 "--", rel});
315 return;
316 }
317 }
318 if (!recorded) {
319 const QString why =
320 tr("The link %1 was removed, but git could not record it: %2")
321 .arg(rel, err.trimmed());
322 emit critical(tr("Delete incomplete"), why);
323 emit processErrorExit(1, why);
324 }
325 }
326 // Nothing ran for pass to finish: the removal is done here, and the
327 // store changed.
328 emit finishedRemove(QString(), QString());
329 return;
330 }
331 executePass(PASS_REMOVE, {"rm", (isDir ? "-rf" : "-f"), file});
332}
333
334void RealPass::finished(int id, int exitCode, const QString &out,
335 const QString &err) {
336 if (static_cast<PROCESS>(id) == GIT_COMMIT && !m_linkCommits.isEmpty()) {
337 // Whatever the exit code (pass itself failing, or 0 whatever git
338 // did), what is left staged decides.
339 finishLinkCommit(m_linkCommits.dequeue(), out, err);
340 return;
341 }
342 if (static_cast<PROCESS>(id) == PASS_INSERT) {
343 // This completion's own insert, not whichever left the queue last.
345 m_insertPending.isEmpty() ? InsertRecord{} : m_insertPending.dequeue();
346 }
347 Pass::finished(id, exitCode, out, err);
348}
349
350void RealPass::finishLinkCommit(const LinkCommit &commit, const QString &out,
351 const QString &err) {
352 // In the store the commit ran in, which a profile switch meanwhile does
353 // not change.
354 const QString &rel = commit.rel;
355 QString staged;
356 const bool committed =
358 commit.environment, commit.passExecutable,
359 {"git", "diff", "--cached", "--name-only", "--", rel}, &staged,
360 nullptr) == 0 &&
361 staged.trimmed().isEmpty();
362 if (committed) {
363 // As Pass::finished() would: git's output (a hook's warning, say) for
364 // the output panel, then the removal.
365 emit finishedAnyWithPid(out, err, GIT_COMMIT);
366 emit finishedRemove(out, err);
367 return;
368 }
369 const QString why = tr("The link %1 was removed and git no longer tracks "
370 "it, but the commit failed: %2")
371 .arg(rel, err.trimmed());
372 emit critical(tr("Delete incomplete"), why);
373 emit processErrorExit(1, why);
374 emit finishedRemove(QString(), QString());
375}
376
377void RealPass::Init(QString path, const QList<UserInfo> &users) {
378 // A relative path names a folder in the store, as --path does for pass:
379 // resolved once, so the checks below look where pass writes, not in the
380 // working directory.
381 const QString folder = QDir::cleanPath(
382 QDir::isAbsolutePath(path) ? path
383 : QDir(m_settings.passStore).filePath(path));
384 // pass init writes .gpg-id with a shell redirection and gpg writes the
385 // signature with --output; both follow a link planted under those names.
386 // --path is store-relative, or pass creates passStore/passStore/dir: the
387 // store check hands it over as it judged it, so a store root reached
388 // through a link and a folder spelled through its target agree (a lexical
389 // relativeFilePath() made that ../../target/dir, which pass refuses).
390 QString dirWithoutPassdir;
391 const auto refusePlaced = [this](const QString &placed) {
394 };
395 if (refusePlaced(folder) ||
396 refusePlaced(folder + QStringLiteral("/.gpg-id")) ||
397 refusePlaced(folder + QStringLiteral("/.gpg-id.sig")) ||
398 refuseFolderOutsideStore(folder, &dirWithoutPassdir)) {
399 return;
400 }
401 // pass init writes this folder's list and then re-encrypts everything
402 // under it to each entry's nearest list, a deeper folder's own included:
403 // those are checked as for a move. This folder's list is the one being
404 // written, so it is neither verified nor missed. Walked in the store's
405 // own spelling: a folder spelled through the target of a linked store
406 // root is not under the store as named, and the lookup of each nearest
407 // list would stop at once and miss the deeper ones.
408 const QString inStore =
409 QDir::cleanPath(QDir(m_settings.passStore).filePath(dirWithoutPassdir));
410 if (refuseUnverifiedTree(inStore, true,
411 QDir(inStore).filePath(QStringLiteral(".gpg-id")))) {
412 return;
413 }
415 return;
416 }
417 QStringList args = {"init", "--path=" + dirWithoutPassdir};
418 for (const UserInfo &user : users) {
419 if (user.enabled) {
420 args.append(user.key_id);
421 }
422 }
423 executePass(PASS_INIT, args);
424}
425
426void RealPass::Move(const QString src, const QString dest, const bool force) {
427 passMoveOrCopy(PASS_MOVE, QStringLiteral("mv"), src, dest, force);
428}
429
430void RealPass::Copy(const QString src, const QString dest, const bool force) {
431 passMoveOrCopy(PASS_COPY, QStringLiteral("cp"), src, dest, force);
432}
433
434auto RealPass::passName(const QString &path, bool stripGpg) const -> QString {
435 QString name =
436 QDir(QDir::cleanPath(m_settings.passStore))
437 .relativeFilePath(QDir::cleanPath(QDir(path).absolutePath()));
438 if (stripGpg) {
439 name.replace(Util::endsWithGpg(), "");
440 }
441 return name;
442}
443
444void RealPass::passMoveOrCopy(PROCESS id, const QString &subcommand,
445 const QString &src, const QString &dest,
446 const bool force) {
447 if (refuseLinkedPath(src) || refuseLinkedPath(dest)) {
448 return;
449 }
450 QFileInfo srcFileInfo = QFileInfo(src);
451 QFileInfo destFileInfo = QFileInfo(dest);
452 // A drop hands over the folder; pass then writes <folder>/<name>, and cp
453 // writes through a link planted under that name.
454 if (destFileInfo.isDir() &&
455 refuseLinkedPath(QDir(dest).filePath(srcFileInfo.fileName()))) {
456 return;
457 }
458
459 // pass always forces when called from QtPass, so refuse file-onto-file.
460 if (!force && srcFileInfo.isFile() && destFileInfo.isFile()) {
461 return;
462 }
463
464 // pass re-encrypts what it moves or copies to the destination's list, a
465 // folder's entries also to the lists that go along with it, and, when it
466 // writes into an existing folder, everything already in that folder too
467 // (reencrypt_path on the whole destination).
468 if (refuseUnverifiedList(destFileInfo.isDir()
469 ? QDir(dest).filePath(srcFileInfo.fileName())
470 : dest) ||
471 (srcFileInfo.isDir() && refuseUnverifiedTree(src, true)) ||
472 (destFileInfo.isDir() && refuseUnverifiedTree(dest, false))) {
473 return;
474 }
476 return;
477 }
478
479 // pass appends .gpg itself, so an entry named with it would come out as
480 // "name.gpg.gpg"; the destination usually does not exist yet.
481 const QString passSrc =
482 passName(src, srcFileInfo.isFile() &&
483 srcFileInfo.suffix() == QLatin1String("gpg"));
484 const QString passDest =
485 passName(dest, !destFileInfo.isDir() &&
486 destFileInfo.suffix() == QLatin1String("gpg"));
487
488 QStringList args;
489 args << subcommand;
490 if (force) {
491 args << "-f";
492 }
493 args << passSrc;
494 args << passDest;
495 executePass(id, args);
496}
497
498// Not `pass grep` (find -L follows links out of the store): the native
499// search walks real files only (Util::regularFilesUnder), so it needs gpg.
500void RealPass::Grep(QString pattern, bool caseInsensitive) {
501 if (m_settings.gpgExecutable.isEmpty()) {
502 emit statusMsg(tr("Search needs the GPG executable to be configured."),
503 5000);
504 emit finishedGrep({});
505 return;
506 }
507 m_grep.search(pattern, caseInsensitive, m_settings.gpgExecutable,
509}
510
511void RealPass::executePass(PROCESS id, const QStringList &args, QString input,
512 bool readStdout, bool readStderr) {
513 executeWrapper(id, m_settings.passExecutable, args, std::move(input),
514 readStdout, readStderr);
515}
void dequeuing(int id, bool completes)
Emitted, synchronously, when the queue's head leaves it: just before it is started,...
static auto executeBlocking(const QString &app, const QStringList &args, const QString &input=QString(), QString *process_out=nullptr, QString *process_err=nullptr) -> int
Run a command synchronously and return its exit code.
Definition executor.cpp:422
auto environment() const -> QProcessEnvironment
Return the environment passed to child processes.
Definition executor.cpp:457
The detached signature on a store's .gpg-id: whether the configured signing key is usable,...
Definition gpgidsigner.h:28
auto enabled() const -> bool
Whether any signing key is configured at all.
Definition gpgidsigner.h:72
static auto keysFromSetting(const QString &passSigningKey) -> QStringList
Split the settings value into keys, upper-cased the way gpg prints fingerprints.
void finished(const QList< QPair< QString, QStringList > > &results)
The newest search is over.
void search(const QString &pattern, bool caseInsensitive, const QString &gpgExe, const QString &storeDir, const QProcessEnvironment &env)
Start a search; finished() follows asynchronously, also for an empty or invalid pattern (with no resu...
void cancel()
Ask running searches to stop without waiting for them: the walk ends at the next file and a gpg that ...
void finishedAnyWithPid(const QString &out, const QString &err, Enums::PROCESS pid)
A process of any kind finished successfully and its output cannot contain a secret.
AppSettings m_settings
Application settings snapshot injected at init() time.
Definition pass.h:117
static auto getGpgIdPath(const QString &for_file, const QString &passStore) -> QString
Get .gpg-id file path for a password file.
Definition pass.cpp:920
auto refusePendingPull() -> bool
Refuse a store change while a Git pull is still queued or running.
Definition pass.cpp:883
Enums::PROCESS PROCESS
Alias for Enums::PROCESS used throughout this class.
Definition pass.h:126
void queueShow(const QString &file)
Remember what a Show() asked for, so its completion can say so.
Definition pass.h:474
void statusMsg(const QString &msg, int timeout)
Progress or a non-fatal problem worth a line in the status bar ("Creating backup commit",...
auto refuseSkippedGpgId(const QString &file, bool signing, const QString &except=QString()) -> bool
With signing on, refuse to encrypt file when the lookup passed over its folder's own list (skippedGpg...
Definition pass.cpp:927
@ PlacedByCaller
Through the target of a linked store root, by a caller that places such a folder itself (Init()): not...
Definition pass.h:507
void executeWrapper(PROCESS id, const QString &app, const QStringList &args, bool readStdout=true, bool readStderr=true)
Execute external wrapper command.
Definition pass.cpp:113
auto refuseLinkedPath(const QString &path, LinkScope scope=LinkScope::EntryAndParents, PathSpelling spelling=PathSpelling::Configured) -> bool
Refuse an operation on something that is, or lies behind, a symbolic link or NTFS junction inside the...
Definition pass.cpp:791
void finishedGrep(const QList< QPair< QString, QStringList > > &results)
The newest Grep() is over; an empty list means no entry matched.
Executor exec
Internal command executor for queuing and running subprocesses.
Definition pass.h:121
void processErrorExit(int exitCode, const QString &err)
An operation ended in failure: its process exited non-zero, could not be started or crashed,...
auto verifySignedList(const GpgIdSigner &signer, const QString &gpgIdFile, QByteArray *contents, QString *why) const -> bool
Whether gpgIdFile is a signed list QtPass accepts: its signature verifies (GpgIdSigner::verifyFile())...
Definition pass.cpp:963
virtual void finished(int id, int exitCode, const QString &out, const QString &err)
Handle process completion.
Definition pass.cpp:523
void critical(const QString &title, const QString &message)
Something went wrong that the user has to be told about in a dialog, such as a refused path or a fail...
@ ParentsOnly
Only the folders above it: a removal unlinks a link and touches nothing behind it.
Definition pass.h:493
@ EntryAndParents
The entry itself and every folder above it in the store.
Definition pass.h:488
void finishedRemove(const QString &out, const QString &err)
A Remove() succeeded; the entry or folder is gone from the store.
auto refuseUnfinishedGitOperation() -> bool
Refuse to change the store while git is mid-rebase, -merge, -cherry-pick or -revert.
Definition pass.cpp:898
void queueInsert()
Count one insert that has started queueing but not yet reported.
Definition pass.h:484
auto refuseFolderOutsideStore(const QString &folder, QString *relative=nullptr) -> bool
Refuse recipients for a folder outside the store, as pass refuses a path with .. in it.
Definition pass.cpp:819
NativeGrep m_grep
Definition realpass.h:35
void finishLinkCommit(const LinkCommit &commit, const QString &out, const QString &err)
Judge a queued linked-folder removal commit by what is left staged in the store it ran in: pass git e...
Definition realpass.cpp:350
void Remove(QString file, bool isDir) override
Remove an entry or folder with pass rm.
Definition realpass.cpp:255
void Init(QString path, const QList< UserInfo > &users) override
Initialize password store.
Definition realpass.cpp:377
void Copy(const QString src, const QString dest, const bool force) override
Copy password file or directory.
Definition realpass.cpp:430
auto storeGit(const QStringList &args, QString *out) -> bool override
Run a git command in the store through pass git, blocking.
Definition realpass.cpp:178
QQueue< InsertRecord > m_insertPending
Definition realpass.h:191
auto refuseList(const QString &file, const GpgIdSigner &signer, QSet< QString > &verified, const QString &within=QString(), const QString &except=QString()) -> bool
The checks of refuseUnverifiedList() for file's nearest list, once per list.
Definition realpass.cpp:77
void Insert(QString file, QString newValue, bool overwrite) override
Insert new password.
Definition realpass.cpp:190
~RealPass() override
Destructor; lets the search workers wind down.
Definition realpass.cpp:41
void Show(QString file) override
Show decrypted password.
Definition realpass.cpp:57
InsertRecord m_insertDone
The insert whose completion is being handled.
Definition realpass.h:193
void GitPull_b() override
Pull with rebase.
Definition realpass.cpp:45
RealPass()
Construct a RealPass instance.
Definition realpass.cpp:36
void onDequeuing(int id, bool completes)
The executor is about to run (or drop) its next item: for an insert, take its entry from m_insertQueu...
Definition realpass.cpp:215
void passMoveOrCopy(PROCESS id, const QString &subcommand, const QString &src, const QString &dest, bool force)
Shared implementation of Move and Copy via pass mv/pass cp.
Definition realpass.cpp:444
auto passName(const QString &path, bool stripGpg) const -> QString
path as pass names it: relative to the store, without the .gpg pass appends itself.
Definition realpass.cpp:434
auto refuseUnverifiedList(const QString &file) -> bool
With signing on, refuse to have pass encrypt file when the signed list it would use is not one QtPass...
Definition realpass.cpp:106
static auto entryFingerprint(const QString &path) -> QByteArray
A SHA-256 of the regular file path (opened without following a link or blocking on a FIFO).
Definition realpass.cpp:243
void GitInit() override
Initialize Git repository in password store.
Definition realpass.cpp:43
void GitPull() override
Pull changes from remote.
Definition realpass.cpp:53
QQueue< LinkCommit > m_linkCommits
Definition realpass.h:47
void Move(const QString src, const QString dest, const bool force) override
Move password file or directory.
Definition realpass.cpp:426
void finished(int id, int exitCode, const QString &out, const QString &err) override
Finish a process; a linked-folder removal commit (GIT_COMMIT, which RealPass uses for nothing else) i...
Definition realpass.cpp:334
void executePass(PROCESS id, const QStringList &args, QString input=QString(), bool readStdout=true, bool readStderr=true)
Execute pass command with arguments.
Definition realpass.cpp:511
void GitPush() override
Push changes to remote.
Definition realpass.cpp:55
auto insertWritten(const QString &err) const -> bool override
Whether the failed pass insert wrote its entry before its git step failed. pass does not say,...
Definition realpass.cpp:225
void Grep(QString pattern, bool caseInsensitive) override
Search all password content by GPG-decrypting each real .gpg file, as ImitatePass does.
Definition realpass.cpp:500
auto refuseUnverifiedTree(const QString &dir, bool onlyListsWithin, const QString &except=QString()) -> bool
For a folder pass is about to re-encrypt in a move or copy: refuse when the signed list of one of its...
Definition realpass.cpp:141
auto listSigner() -> GpgIdSigner
The verifier for signed lists, gpg in the store's environment.
Definition realpass.cpp:66
QQueue< QString > m_insertQueue
The entries of the queued inserts, oldest first.
Definition realpass.h:187
static auto removeTree(const QString &dir) -> bool
Remove dir and everything in it, the way rm -rf does: a symbolic link or NTFS junction,...
Definition util.cpp:1239
static auto endsWithGpg() -> const QRegularExpression &
Returns a regex to match .gpg file extensions.
Definition util.cpp:582
static auto isLinkedFolder(const QString &path) -> bool
Whether path names a symbolic link or NTFS junction, with or without a trailing separator (which woul...
Definition util.cpp:761
static auto openRegularFile(const QString &path, QFile &file) -> bool
Open path for reading as the regular file it is, not as what a link under that name points to: the ob...
Definition util.cpp:913
Executor, the FIFO queue every gpg, git and pass child process of QtPass goes through,...
GpgIdSigner, which signs a store's .gpg-id and verifies an existing .gpg-id.sig against the configure...
@ PASS_INIT
Definition enums.h:53
@ PASS_INSERT
Definition enums.h:51
@ GIT_INIT
Definition enums.h:44
@ PASS_COPY
Definition enums.h:56
@ PASS_MOVE
Definition enums.h:55
@ PASS_REMOVE
Definition enums.h:52
@ GIT_COMMIT
Definition enums.h:46
@ PASS_SHOW
Definition enums.h:50
@ GIT_PULL
Definition enums.h:48
@ GIT_PUSH
Definition enums.h:49
@ PASS_INIT
Definition enums.h:53
@ PASS_INSERT
Definition enums.h:51
@ GIT_INIT
Definition enums.h:44
@ PASS_COPY
Definition enums.h:56
@ PASS_MOVE
Definition enums.h:55
@ PASS_REMOVE
Definition enums.h:52
@ GIT_COMMIT
Definition enums.h:46
@ PASS_SHOW
Definition enums.h:50
@ GIT_PULL
Definition enums.h:48
@ GIT_PUSH
Definition enums.h:49
PathValidator: is a path inside the password store, and how is it spelled relative to the store root.
The "qtpass" logging category.
RealPass, the backend that hands every store operation to the pass command-line tool.
QString gpgExecutable
Path to the gpg/gpg2 executable.
Definition appsettings.h:66
QString passStore
Password-store root path.
Definition appsettings.h:60
QString passExecutable
Path to the pass executable.
Definition appsettings.h:64
bool useGit
Enable git integration.
Stores GPG key info including validity, creation date, and more.
Definition userinfo.h:19
Util: static helpers for the process environment, binary discovery, store paths, URL safety and the l...