QtPass 2.0.0
Developer documentation
Loading...
Searching...
No Matches
imitatepass.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
2// SPDX-License-Identifier: GPL-3.0-or-later
8#ifndef SRC_IMITATEPASS_H_
9#define SRC_IMITATEPASS_H_
10
11#include "gpgidsigner.h"
12#include "nativegrep.h"
13#include "pass.h"
14#include "simpletransaction.h"
15#include <QQueue>
16#include <QTemporaryDir>
17
18#include <atomic>
19#include <memory>
20#include <optional>
21
22class QRegularExpression;
23class QThread;
24
40class ImitatePass : public Pass {
41 Q_OBJECT
42
43 friend class tst_util;
44 friend class tst_imitatepass;
45
46protected:
53 auto gpgIdSigner() -> GpgIdSigner;
70 auto loadVerifiedRecipients(const QString &gpgIdFile, QStringList *recipients,
71 QString *why = nullptr) -> bool;
84 auto writeGpgIdFile(const QString &gpgIdFile, const QList<UserInfo> &users,
85 QByteArray *written = nullptr) -> bool;
94 auto signGpgIdFile(const QString &gpgIdFile, const QByteArray &contents)
95 -> bool;
102 auto refuseLinkedGpgIdFolder(const QString &path) -> bool;
110 auto recipientsForEntry(const QString &file, QStringList *recipients) -> bool;
120 auto copyDestination(const QString &src, const QString &dest, bool force)
121 -> QString;
133 auto addGenerationHeader(const QString &gpgIdFile, const GpgIdSigner &signer,
134 QByteArray *contents) -> bool;
146 auto settleSignature(const QString &gpgIdFile, const QByteArray &written,
147 const GpgIdSigner &signer, bool useGit,
148 QString *sigToCommit) -> bool;
161 auto gitAddGpgId(const QString &gpgIdFile, const QString &gpgIdSigFile,
162 QString *out, QString *err) -> int;
168 auto gitTracks(const QString &file) -> bool;
174 auto commitArgs() -> QStringList;
185 auto verifyGpgIdForDir(const QString &file,
186 QHash<QString, QStringList> &verified,
187 QStringList &gpgId) -> bool;
192 auto createBackupCommit() -> bool;
198 auto getKeysFromFile(const QString &fileName) -> QStringList;
208 auto reencryptSingleFile(const QString &fileName,
209 const QStringList &recipients, QString *why) -> bool;
216 auto decryptEntry(const QString &fileName, QString *plaintext) -> bool;
224 auto encryptFor(const QString &output, const QStringList &recipients,
225 const QString &plaintext) -> bool;
233 auto ciphertextHolds(const QString &ciphertext, const QString &plaintext)
234 -> bool;
242 auto commitReencrypted(const QString &fileName) -> bool;
250 auto resolveMoveDestination(const QString &src, const QString &dest,
251 bool force) -> QString;
252
253public:
260 void executeMoveGit(const QString &src, const QString &destFile, bool force);
261
267 void gitCommit(const QString &file, const QString &msg);
268
277 void executeGit(PROCESS id, const QStringList &args,
278 QString input = QString(), bool readStdout = true,
279 bool readStderr = true);
284 auto gitConfigured() const -> bool;
290 auto gitReady() -> bool;
299 void executeGpg(PROCESS id, const QStringList &args,
300 QString input = QString(), bool readStdout = true,
301 bool readStderr = true);
302
328
329protected:
332 QProcessEnvironment m_reencryptEnv;
351 [[nodiscard]] auto execBlocking(const QString &app, const QStringList &args,
352 const QString &input = QString(),
353 QString *process_out = nullptr,
354 QString *process_err = nullptr) -> int;
363 [[nodiscard]] auto execBlocking(const QString &app, const QStringList &args,
364 QString *process_out,
365 QString *process_err = nullptr) -> int;
372 auto storeGit(const QStringList &args, QString *out) -> bool override;
380 void finished(int id, int exitCode, const QString &out,
381 const QString &err) override;
382
389 [[nodiscard]] auto insertWritten(const QString &err) const -> bool override {
390 Q_UNUSED(err);
391 return m_insertPlaced;
392 }
393
401 void beforeExecute(PROCESS id) override;
402
403public:
407 ImitatePass();
412 ~ImitatePass() override;
413
414 // Git operations
418 void GitInit() override;
422 void GitPull() override;
426 void GitPull_b() override;
430 void GitPush() override;
431
432 // Password operations
437 void Show(QString file) override;
444 void Insert(QString file, QString newValue, bool overwrite) override;
450 void Remove(QString file, bool isDir) override;
462 void Init(QString path, const QList<UserInfo> &users) override;
463
474 void reencryptPath(const QString &dir);
486 void reencryptPath(const QString &dir, const AppSettings &settings);
502 void cancelReencryptPath();
503
504signals:
528 void reencryptProgress(int current, int total);
529
530 // Pass interface
531public:
538 void Move(const QString src, const QString dest, const bool force) override;
545 void Copy(const QString src, const QString dest, const bool force) override;
555 void Grep(QString pattern, bool caseInsensitive) override;
556
557private:
568
575 std::shared_ptr<QTemporaryDir> scratch;
577 QString output;
579 QString file;
581 bool overwrite = false;
582 };
583
584 QQueue<PendingInsert> m_pendingInserts;
589 bool m_insertPlaced = false;
590
606 auto placeEncryptedFile(const QString &output, const QString &file,
607 bool overwrite, QString *error) -> bool;
608
613 struct ReencryptResult;
615 bool m_reencryptActive = false;
621 std::atomic<bool> m_reencryptCancel{false};
626 QThread *m_reencryptThread = nullptr;
631 void startReencryptWorker(const QString &dir);
637 auto reencryptFiles(const QString &dir) -> ReencryptResult;
644 auto pullBeforeReencrypt() -> bool;
651 auto entriesToReencrypt(const QString &dir) -> QStringList;
660 auto recipientsForDir(const QString &fileName,
661 QHash<QString, QStringList> &verified,
662 QStringList &gpgId, ReencryptResult &result) -> bool;
675 auto recoverReencryptLeftovers(const QString &dir) -> bool;
682 void dropStaleTemporary(const QString &path);
690 auto restoreBackup(const QString &path) -> bool;
695 void reportUnrestorable(const QString &path);
700 void finishReencrypt(const ReencryptResult &result);
701
706 QString folder;
707 QString gitError;
708 };
709
714 std::optional<UncommittedGpgId> m_uncommittedGpgId;
720 auto reencryptUsesGit() const -> bool;
728 void reencryptWithoutGit(const QString &dir, const QString &gitError);
738 void reportUncommittedGpgId(const QString &dir, const QString &gitError,
739 bool reencrypted);
740
748 auto translatePathForWsl(const QString &path, const QString &exe) const
749 -> QString;
756 auto pgit(const QString &path) const -> QString;
763 auto pgpg(const QString &path) const -> QString;
764};
765
766#endif // SRC_IMITATEPASS_H_
The detached signature on a store's .gpg-id: whether the configured signing key is usable,...
Definition gpgidsigner.h:28
TransactionHelper(SimpleTransaction *trans, PROCESS result)
Start transaction.
~TransactionHelper()
End transaction on destruction.
SimpleTransaction * m_transaction
The transaction being bracketed; not owned.
PROCESS m_result
What the transaction reports as once its last step ends.
Implementation that imitates 'pass' when the real tool is unavailable.
Definition imitatepass.h:40
auto commitReencrypted(const QString &fileName) -> bool
Stage and commit a re-encrypted entry, when the store is a Git repository QtPass manages.
auto encryptFor(const QString &output, const QStringList &recipients, const QString &plaintext) -> bool
Encrypt plaintext to recipients, into output.
auto createBackupCommit() -> bool
Create git backup commit before re-encryption.
void finishReencrypt(const ReencryptResult &result)
Report the outcome of a run and emit endReencryptPath().
void Remove(QString file, bool isDir) override
Remove password.
bool m_insertPlaced
QString m_transactionOutput
stdout of the steps of the transaction in flight, collected by finished() and handed on,...
auto execBlocking(const QString &app, const QStringList &args, const QString &input=QString(), QString *process_out=nullptr, QString *process_err=nullptr) -> int
Executor::executeBlocking() for the re-encryption helpers.
void GitInit() override
Initialize Git repository.
auto recipientsForEntry(const QString &file, QStringList *recipients) -> bool
The recipients to encrypt file to: its folder's .gpg-id, verified when a signing key is set.
void executeGpg(PROCESS id, const QStringList &args, QString input=QString(), bool readStdout=true, bool readStderr=true)
Execute GPG command.
auto ciphertextHolds(const QString &ciphertext, const QString &plaintext) -> bool
Decrypt ciphertext again and compare it with plaintext, so nothing replaces an entry until it is know...
auto reencryptSingleFile(const QString &fileName, const QStringList &recipients, QString *why) -> bool
Re-encrypt single file with new recipients.
void reportUncommittedGpgId(const QString &dir, const QString &gitError, bool reencrypted)
Tell the user that the recipients of dir changed on disk but the change is not committed,...
auto copyDestination(const QString &src, const QString &dest, bool force) -> QString
The file a copy of src to dest writes: like pass cp, into an existing folder with ....
bool m_reencryptActive
Set while a re-encryption run is pending or on the worker thread.
void startReencryptWorker(const QString &dir)
Start the worker thread once the Executor queue is idle.
auto entriesToReencrypt(const QString &dir) -> QStringList
The entries under dir a run considers, telling the user about anything skipped for not being a regula...
auto writeGpgIdFile(const QString &gpgIdFile, const QList< UserInfo > &users, QByteArray *written=nullptr) -> bool
Write the enabled recipients to a .gpg-id, atomically: a write that fails halfway (full disk,...
auto commitArgs() -> QStringList
The start of a git commit for the store: "commit", and "-S" when git config pass.signcommits is true ...
auto verifyGpgIdForDir(const QString &file, QHash< QString, QStringList > &verified, QStringList &gpgId) -> bool
Recipients for the directory of file, from its verified .gpg-id.
void Grep(QString pattern, bool caseInsensitive) override
Search all password content by GPG-decrypting each .gpg file.
void Insert(QString file, QString newValue, bool overwrite) override
Insert new password.
auto insertWritten(const QString &err) const -> bool override
Whether the failed insert had placed its entry (see placeEncryptedFile()) before a later git step fai...
auto recipientsForDir(const QString &fileName, QHash< QString, QStringList > &verified, QStringList &gpgId, ReencryptResult &result) -> bool
The verified recipients for the folder fileName sits in.
auto gitTracks(const QString &file) -> bool
Check whether git already tracks a file in the store.
void GitPull_b() override
Pull with rebase.
void cancelReencryptPath()
Ask a running reencryptPath() to stop.
ImitatePass()
Construct the backend and connect its content search.
auto gitReady() -> bool
gitConfigured() plus a status message when git is enabled but no executable is configured.
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 loadVerifiedRecipients(const QString &gpgIdFile, QStringList *recipients, QString *why=nullptr) -> bool
Read a .gpg-id, verify its detached signature and parse the recipients from the bytes that were verif...
void Copy(const QString src, const QString dest, const bool force) override
Copy password file.
QThread * m_reencryptThread
The re-encryption worker while it runs, null otherwise. The destructor sets m_reencryptCancel and joi...
auto reencryptFiles(const QString &dir) -> ReencryptResult
Worker-thread body: scan dir and re-encrypt stale files.
auto placeEncryptedFile(const QString &output, const QString &file, bool overwrite, QString *error) -> bool
Bring the ciphertext gpg wrote to output into the store as file (Util::copyFileReplacing): through a ...
auto settleSignature(const QString &gpgIdFile, const QByteArray &written, const GpgIdSigner &signer, bool useGit, QString *sigToCommit) -> bool
Bring the signature in line with the list just written: a new one when signing is on,...
SimpleTransaction m_transaction
auto signGpgIdFile(const QString &gpgIdFile, const QByteArray &contents) -> bool
Sign a .gpg-id with the configured key and verify the result; failures are reported through critical(...
QProcessEnvironment m_reencryptEnv
void reencryptProgress(int current, int total)
Re-encryption progress: current of total files checked.
void executeMoveGit(const QString &src, const QString &destFile, bool force)
Execute git move operation.
void endReencryptPath()
A reencryptPath() run is over, whether it finished, failed, was cancelled or was refused; the main wi...
auto translatePathForWsl(const QString &path, const QString &exe) const -> QString
Translate path for the given exe when WSL-routed: wraps in wslpath substitution, otherwise returns pa...
void finished(int id, int exitCode, const QString &out, const QString &err) override
Handle process completion.
void reencryptWithoutGit(const QString &dir, const QString &gitError)
Re-encrypt dir to the .gpg-id Init() wrote although its commit failed, without any Git step (they wou...
auto addGenerationHeader(const QString &gpgIdFile, const GpgIdSigner &signer, QByteArray *contents) -> bool
Put the generation header on a list that is about to be signed: reserve a generation above what this ...
auto gitAddGpgId(const QString &gpgIdFile, const QString &gpgIdSigFile, QString *out, QString *err) -> int
Stage a .gpg-id and, when given, its .sig, and commit both in one commit, so no commit in the history...
std::optional< UncommittedGpgId > m_uncommittedGpgId
std::atomic< bool > m_reencryptCancel
void GitPull() override
Pull from remote.
auto refuseLinkedGpgIdFolder(const QString &path) -> bool
Refuse a folder, or a .gpg-id/.gpg-id.sig in it, that is a link: writing there would reach outside th...
void Show(QString file) override
Show decrypted password.
auto pgpg(const QString &path) const -> QString
Translate path for gpg when WSL-routed: wraps in wslpath substitution, otherwise returns path unchang...
auto storeGit(const QStringList &args, QString *out) -> bool override
Run git with -C <store> in the store, blocking.
QQueue< PendingInsert > m_pendingInserts
The inserts whose gpg step has not ended yet, oldest first.
NativeGrep m_grep
Background search over the decrypted store; relays to finishedGrep.
auto resolveMoveDestination(const QString &src, const QString &dest, bool force) -> QString
Resolve destination for move operation.
auto recoverReencryptLeftovers(const QString &dir) -> bool
Deal with what a crashed or failed earlier run left under dir before touching anything: stale tempora...
void GitPush() override
Push to remote.
void Move(const QString src, const QString dest, const bool force) override
Move password file.
auto restoreBackup(const QString &path) -> bool
Put a 1.8.x backup back in its entry's place when the entry is missing; report it when both exist (bo...
void dropStaleTemporary(const QString &path)
Remove a stale temporary a crashed run left, unless it was modified within the hour: on a shared stor...
void startReencryptPath()
A reencryptPath() run is about to start its worker thread.
auto decryptEntry(const QString &fileName, QString *plaintext) -> bool
Decrypt fileName for re-encryption.
auto getKeysFromFile(const QString &fileName) -> QStringList
Read recipients from file.
auto reencryptUsesGit() const -> bool
gitConfigured(), unless the current run is one reencryptWithoutGit() started.
auto gitConfigured() const -> bool
Git is enabled and an executable is configured.
void reencryptPath(const QString &dir)
Re-encrypt entire directory.
auto pgit(const QString &path) const -> QString
Translate path for git when WSL-routed: wraps in wslpath substitution, otherwise returns path unchang...
void reportUnrestorable(const QString &path)
Tell the user a leftover is not a regular file and was left.
auto pullBeforeReencrypt() -> bool
Pull before a run, when the store is a Git repository and automatic pulling is on.
void gitCommit(const QString &file, const QString &msg)
Commit changes to git.
void beforeExecute(PROCESS id) override
Open a transaction for every execution.
auto gpgIdSigner() -> GpgIdSigner
The signer for this store's .gpg-id, bound to the configured gpg and signing keys and to execBlocking...
Full-text search over a password store without pass grep: every .gpg file is decrypted with gpg on a ...
Definition nativegrep.h:31
Enums::PROCESS PROCESS
Alias for Enums::PROCESS used throughout this class.
Definition pass.h:126
Pass()
Construct a Pass instance.
Definition pass.cpp:61
Tracks a sequence of processes that should be treated as one atomic operation.
void transactionStart()
Open a transaction: the processes added until the matching transactionEnd() are reported as one opera...
void transactionEnd(Enums::PROCESS process)
Close the transaction opened by the matching transactionStart().
GpgIdSigner, which signs a store's .gpg-id and verifies an existing .gpg-id.sig against the configure...
NativeGrep, the content search that decrypts every entry on a worker thread instead of running pass g...
Pass, the abstract password-store backend that RealPass and ImitatePass implement,...
PROCESS
Identifies different subprocess operations used in QtPass.
Definition enums.h:43
SimpleTransaction, the bookkeeping that lets ImitatePass report several queued processes as one finis...
Plain value-object holding all flat QtPass configuration.
Definition appsettings.h:36
QString file
The entry's path in the store, where output goes.
std::shared_ptr< QTemporaryDir > scratch
The private directory gpg writes into; removed with this.
bool overwrite
Whether an entry already at file may be replaced.
QString output
The ciphertext file gpg writes, inside scratch.
Outcome of one reencryptPath() run; filled on the worker thread and consumed by finishReencrypt() on ...
A .gpg-id Init() wrote but could not commit.
QString folder
The folder whose recipients changed.
QString gitError
What Git said when the commit failed.