QtPass 2.0.0
Developer documentation
Loading...
Searching...
No Matches
pass.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
2// SPDX-License-Identifier: GPL-3.0-or-later
9#ifndef SRC_PASS_H_
10#define SRC_PASS_H_
11
12#include "appsettings.h"
13#include "enums.h"
14#include "executor.h"
15#include "gpgidgeneration.h"
16#include "userinfo.h"
17
18#include <QProcess>
19#include <QProcessEnvironment>
20#include <QQueue>
21#include <QString>
22#include <QStringList>
23
24class GpgIdSigner;
25#include <cassert>
26#include <map>
27#include <optional>
28
42 QString program;
47 QStringList arguments;
48};
49
75class Pass : public QObject {
76 Q_OBJECT
77
79 bool wrapperRunning{false};
85 QProcessEnvironment env;
86
87protected:
96 [[nodiscard]] auto storeEnvironment() const -> QProcessEnvironment {
97 return withCurrentGitPin(env);
98 }
99
108 [[nodiscard]] auto withCurrentGitPin(QProcessEnvironment base) const
109 -> QProcessEnvironment;
110
122
127
128public:
132 Pass();
137 void init(const AppSettings &settings);
143 static bool gpgSupportsEd25519(const QString &gpgExecutable = {});
149 static QString getDefaultKeyTemplate(const QString &gpgExecutable = {});
150
151 ~Pass() override = default;
152
153 // Git operations
157 virtual void GitInit() = 0;
161 virtual void GitPull() = 0;
165 virtual void GitPull_b() = 0;
169 virtual void GitPush() = 0;
170
171 // Password operations
176 virtual void Show(QString file) = 0;
183 virtual void Insert(QString file, QString value, bool force) = 0;
194 [[nodiscard]] auto insertsPending() const -> int { return m_insertsPending; }
200 virtual void Remove(QString file, bool isDir) = 0;
207 virtual void Move(const QString srcDir, const QString dest,
208 const bool force) = 0;
215 virtual void Copy(const QString srcDir, const QString dest,
216 const bool force) = 0;
222 virtual void Init(QString path, const QList<UserInfo> &users) = 0;
233 virtual void Grep(QString pattern, bool caseInsensitive) = 0;
234
241 virtual auto generatePassword(unsigned int length, const QString &charset)
242 -> QString;
243
244 // GPG operations
249 void GenerateGPGKeys(QString batch);
256 auto listKeys(QStringList keystrings, bool secret = false) -> QList<UserInfo>;
263 auto listKeys(const QString &keystring = "", bool secret = false)
264 -> QList<UserInfo>;
268 void updateEnv();
269
277 static constexpr qint64 kMaxPlaintextBytes = 64LL * 1024 * 1024;
278
283 static auto maxOutputArgs() -> QStringList;
284
285 // Static helpers
291 static auto resolveGpgconfCommand(const QString &gpgPath)
299 static auto getGpgIdPath(const QString &for_file, const QString &passStore)
300 -> QString;
324 static auto skippedGpgId(const QString &forFile, const QString &passStore,
325 QString *recordError = nullptr)
326 -> std::optional<QString>;
333 static auto getRecipientList(const QString &for_file,
334 const QString &passStore) -> QStringList;
335
342 enum class State {
344 Unsigned,
346 Verified,
352 VerifiedRollback,
358 Rejected,
359 };
360
363 QStringList recipients;
365 QString warning;
366 };
367
386 auto recipientsForEditing(const QString &dir, const QString &passStore)
395 static auto parseRecipients(const QByteArray &contents,
396 const QString &sourceName) -> QStringList;
403 static auto loggableArgs(const QStringList &args) -> QStringList;
416 static auto seedGpgIdFile(const QString &newDir, const QString &passStore)
417 -> bool;
418
423 [[nodiscard]] auto isIdle() const -> bool { return exec.isIdle(); }
424
425protected:
436 auto refuseSkippedGpgId(const QString &file, bool signing,
437 const QString &except = QString()) -> bool;
438
451 auto verifySignedList(const GpgIdSigner &signer, const QString &gpgIdFile,
452 QByteArray *contents, QString *why) const -> bool;
453
461 [[nodiscard]] virtual auto insertWritten(const QString &err) const -> bool {
462 Q_UNUSED(err);
463 return false;
464 }
465
474 void queueShow(const QString &file) { m_pendingShows.enqueue(file); }
486 enum class LinkScope {
488 EntryAndParents,
493 ParentsOnly,
494 };
495
496 enum class PathSpelling {
502 Configured,
507 PlacedByCaller,
508 };
509
527 auto refuseLinkedPath(const QString &path,
530 -> bool;
545 auto refuseFolderOutsideStore(const QString &folder,
546 QString *relative = nullptr) -> bool;
547
560 virtual auto storeGit(const QStringList &args, QString *out) -> bool {
561 Q_UNUSED(args);
562 Q_UNUSED(out);
563 return false;
564 }
565
582 auto refuseUnfinishedGitOperation() -> bool;
583
596 auto unfinishedGitOperationReason() -> QString;
597
611 auto refusePendingPull() -> bool;
612
621 void executeWrapper(PROCESS id, const QString &app, const QStringList &args,
622 bool readStdout = true, bool readStderr = true);
629 auto generateRandomPassword(const QString &charset, unsigned int length)
630 -> QString;
636 auto boundedRandom(quint32 bound) -> quint32;
643 void setEnvVar(const QString &name, const QString &value);
644
654 void executeWrapper(PROCESS id, const QString &app, const QStringList &args,
655 QString input, bool readStdout, bool readStderr);
664 virtual void beforeExecute(PROCESS id);
665
666protected slots:
674 virtual void finished(int id, int exitCode, const QString &out,
675 const QString &err);
676
677private:
679 QQueue<QString> m_pendingShows;
694 void handleProcessError(PROCESS pid, int exitCode, const QString &out,
695 const QString &err);
704 auto formatInsertError(const QString &friendly, const QString &err)
705 -> QString;
717 void emitProcessFinishedSignal(PROCESS pid, const QString &out,
718 const QString &err);
728 void refuseAsNotPartOfStore(const QString &why);
729
730signals:
738 void idle();
757 void statusMsg(const QString &msg, int timeout);
771 void critical(const QString &title, const QString &message);
772
801 void processErrorExit(int exitCode, const QString &err);
802
814 void finishedAnyWithPid(const QString &out, const QString &err,
815 Enums::PROCESS pid);
822 void finishedGitInit(const QString &out, const QString &err);
828 void finishedGitPull(const QString &out, const QString &err);
834 void finishedGitPush(const QString &out, const QString &err);
845 void finishedShow(const QString &out, const QString &file);
858 void finishedInsert(const QString &out, const QString &err);
864 void finishedRemove(const QString &out, const QString &err);
871 void finishedInit(const QString &out, const QString &err);
877 void finishedMove(const QString &out, const QString &err);
883 void finishedCopy(const QString &out, const QString &err);
892 void finishedGenerateGPGKeys(const QString &out, const QString &err);
899 void generateGPGKeysFailed(const QString &err);
912 void insertFailed(const QString &err, bool written);
921 void finishedGrep(const QList<QPair<QString, QStringList>> &results);
922};
923
939QString gpgErrorMessage(const QString &err);
940
941#endif // SRC_PASS_H_
AppSettings, the value object holding every flat QtPass setting.
Runs non-interactive external commands in FIFO order using a single QProcess.
Definition executor.h:31
auto isIdle() const -> bool
Whether no command is running and nothing is queued.
Definition executor.h:425
The detached signature on a store's .gpg-id: whether the configured signing key is usable,...
Definition gpgidsigner.h:28
auto storeEnvironment() const -> QProcessEnvironment
The environment QtPass runs the store's processes in.
Definition pass.h:96
void startingExecuteWrapper()
Emitted each time a queued process is about to start, and by the refusals that go on to emit processE...
bool wrapperRunning
Unused; kept from the time Pass tracked the running wrapper.
Definition pass.h:79
virtual void beforeExecute(PROCESS id)
Hook invoked just before a wrapped command is dispatched.
Definition pass.cpp:156
void GenerateGPGKeys(QString batch)
Generate GPG keys using batch script.
Definition pass.cpp:394
static QString getDefaultKeyTemplate(const QString &gpgExecutable={})
Get default key template for new GPG keys.
Definition pass.cpp:291
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.
void finishedInsert(const QString &out, const QString &err)
An Insert() succeeded: the entry is in the store and, with Git in use, committed.
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
void handleProcessError(PROCESS pid, int exitCode, const QString &out, const QString &err)
Report a process that exited non-zero; called by finished().
Definition pass.cpp:552
virtual void GitInit()=0
Initialize Git repository in password store.
auto refusePendingPull() -> bool
Refuse a store change while a Git pull is still queued or running.
Definition pass.cpp:883
void finishedGenerateGPGKeys(const QString &out, const QString &err)
GenerateGPGKeys() succeeded; the new key pair is in the keyring.
virtual void Copy(const QString srcDir, const QString dest, const bool force)=0
Copy password file or directory.
Enums::PROCESS PROCESS
Alias for Enums::PROCESS used throughout this class.
Definition pass.h:126
virtual void GitPull()=0
Pull changes from remote Git repository.
virtual auto generatePassword(unsigned int length, const QString &charset) -> QString
Generate random password.
Definition pass.cpp:218
void queueShow(const QString &file)
Remember what a Show() asked for, so its completion can say so.
Definition pass.h:474
virtual void Move(const QString srcDir, const QString dest, const bool force)=0
Move password file or directory.
void finishedShow(const QString &out, const QString &file)
Emitted when a Show() succeeds.
void statusMsg(const QString &msg, int timeout)
Progress or a non-fatal problem worth a line in the status bar ("Creating backup commit",...
QProcessEnvironment env
The environment the store's processes run in: the system environment plus what updateEnv() sets (PASS...
Definition pass.h:85
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
virtual void Grep(QString pattern, bool caseInsensitive)=0
Search password content for a pattern.
auto unfinishedGitOperationReason() -> QString
The unfinished git operation in progress in the store, if any.
Definition pass.cpp:835
PathSpelling
How a path handed to refuseLinkedPath() is spelled.
Definition pass.h:496
@ Configured
As the store is configured or relative to it, the class's path rule. A path spelled through the targe...
Definition pass.h:502
static auto skippedGpgId(const QString &forFile, const QString &passStore, QString *recordError=nullptr) -> std::optional< QString >
The folder list getGpgIdPath() passed over on its way up to the one it returns, if it passed one over...
Definition pass.cpp:982
auto boundedRandom(quint32 bound) -> quint32
Generate random number in range.
Definition pass.cpp:1206
void insertFailed(const QString &err, bool written)
Emitted when an Insert() fails through a queued command, before the generic processErrorExit(): the p...
void emitProcessFinishedSignal(PROCESS pid, const QString &out, const QString &err)
Emit the signals for a process that exited with 0; called by finished() for everything but PASS_SHOW.
Definition pass.cpp:595
static bool gpgSupportsEd25519(const QString &gpgExecutable={})
Check if GPG supports Ed25519 encryption.
Definition pass.cpp:273
void refuseAsNotPartOfStore(const QString &why)
Refuse an operation on something that is not part of the store.
Definition pass.cpp:912
static auto maxOutputArgs() -> QStringList
The gpg options that enforce kMaxPlaintextBytes.
Definition pass.cpp:701
static auto seedGpgIdFile(const QString &newDir, const QString &passStore) -> bool
Seed a new folder's .gpg-id from the recipients it inherits.
Definition pass.cpp:1182
virtual void Remove(QString file, bool isDir)=0
Remove password file or directory.
virtual auto storeGit(const QStringList &args, QString *out) -> bool
Run a git command in the store's repository, blocking.
Definition pass.h:560
Pass()
Construct a Pass instance.
Definition pass.cpp:61
virtual auto insertWritten(const QString &err) const -> bool
Whether the insert that just failed had put its entry in the store before a later step failed....
Definition pass.h:461
void finishedCopy(const QString &out, const QString &err)
A Copy() succeeded; the copy exists beside the original.
virtual void Show(QString file)=0
Show decrypted password file.
void finishedMove(const QString &out, const QString &err)
A Move() succeeded; the entry or folder is under its new name.
auto isIdle() const -> bool
Whether no gpg, git or pass of this backend runs or waits.
Definition pass.h:423
void executeWrapper(PROCESS id, const QString &app, const QStringList &args, bool readStdout=true, bool readStderr=true)
Execute external wrapper command.
Definition pass.cpp:113
static auto resolveGpgconfCommand(const QString &gpgPath) -> ResolvedGpgconfCommand
Resolve the gpgconf command to kill agents.
Definition pass.cpp:354
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
auto listKeys(QStringList keystrings, bool secret=false) -> QList< UserInfo >
List GPG keys matching patterns.
Definition pass.cpp:426
void finishedGrep(const QList< QPair< QString, QStringList > > &results)
The newest Grep() is over; an empty list means no entry matched.
virtual void GitPull_b()=0
Pull with rebase from remote.
void finishedGitPull(const QString &out, const QString &err)
git pull succeeded; entries may have changed on disk.
virtual void GitPush()=0
Push changes to remote Git repository.
void finishedGitPush(const QString &out, const QString &err)
git push succeeded.
auto recipientsForEditing(const QString &dir, const QString &passStore) -> RecipientsForEditing
The recipients a dialog may preselect for editing the list of dir.
Definition pass.cpp:1068
virtual void Insert(QString file, QString value, bool force)=0
Insert or update password.
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
void init(const AppSettings &settings)
Initialize the Pass instance with a settings snapshot.
Definition pass.cpp:158
auto insertsPending() const -> int
How many inserts have started queueing but not yet reported.
Definition pass.h:194
auto formatInsertError(const QString &friendly, const QString &err) -> QString
Put the translated reason for a failed insert above what gpg itself printed, leaving out the machine-...
Definition pass.cpp:582
void finishedGitInit(const QString &out, const QString &err)
git init in the store succeeded; the store is a repository now and the tree is re-read.
auto withCurrentGitPin(QProcessEnvironment base) const -> QProcessEnvironment
base with GIT_DIR and GIT_WORK_TREE as the store is now (Util::gitStoreVariables()),...
Definition pass.cpp:687
void setEnvVar(const QString &name, const QString &value)
Set or remove an environment variable.
Definition pass.cpp:624
static auto loggableArgs(const QStringList &args) -> QStringList
The arguments as they may appear in the debug log: the value of --passphrase and friends,...
Definition pass.cpp:128
void updateEnv()
Update environment for subprocesses.
Definition pass.cpp:631
void finishedInit(const QString &out, const QString &err)
An Init() succeeded: the folder's .gpg-id holds the new recipient list.
void idle()
Nothing of the store's runs or waits any more (isIdle()).
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...
void generateGPGKeysFailed(const QString &err)
Emitted when GPG key generation fails, alongside the generic processErrorExit(); lets the keygen dial...
static constexpr qint64 kMaxPlaintextBytes
Most bytes of plaintext a gpg decryption may produce.
Definition pass.h:277
int m_insertsPending
Inserts that have started queueing but not yet reported; see queueInsert.
Definition pass.h:681
static auto getRecipientList(const QString &for_file, const QString &passStore) -> QStringList
Get list of recipients for a password file.
Definition pass.cpp:1146
virtual void Init(QString path, const QList< UserInfo > &users)=0
Initialize new password store.
LinkScope
What refuseLinkedPath() judges.
Definition pass.h:486
@ 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
QQueue< QString > m_pendingShows
Files of the Show() calls still in flight, oldest first.
Definition pass.h:679
static auto parseRecipients(const QByteArray &contents, const QString &sourceName) -> QStringList
Parse the contents of a .gpg-id: one recipient per line, # starts a comment, unusable lines are logge...
Definition pass.cpp:1161
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
auto generateRandomPassword(const QString &charset, unsigned int length) -> QString
Generate random password from charset.
Definition pass.cpp:1223
The Enums namespace: clipboard behaviour and the identifiers of the subprocess kinds QtPass queues.
Executor, the FIFO queue every gpg, git and pass child process of QtPass goes through,...
Rollback detection for signed .gpg-id files: the generation counter and the record of what was last s...
PROCESS
Identifies different subprocess operations used in QtPass.
Definition enums.h:43
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:471
PROCESS
Identifies different subprocess operations used in QtPass.
Definition enums.h:43
Plain value-object holding all flat QtPass configuration.
Definition appsettings.h:36
What a dialog may do with the list of a folder (recipientsForEditing()).
Definition pass.h:340
QStringList recipients
The recipients to preselect; empty when Rejected.
Definition pass.h:363
State state
How the list on disk stood up.
Definition pass.h:361
QString warning
What the dialog should show, if anything.
Definition pass.h:365
State
How the list on disk stood up.
Definition pass.h:342
@ Unsigned
No signing key: the list as it is.
Definition pass.h:344
Represents a command invocation for gpgconf operations.
Definition pass.h:37
QStringList arguments
Full argv list, including any wrapper/prefix args followed by the actual gpgconf operation flags (e....
Definition pass.h:47
QString program
Executable to run — may be a bare name resolved via PATH or a wrapper (e.g. wsl.exe) rather than a di...
Definition pass.h:42
UserInfo, one GPG key as listed by gpg, with the selection flag the recipient dialogs use.