Line data Source code
1 : // SPDX-FileCopyrightText: 2026 Anne Jan Brouwer
2 : // SPDX-License-Identifier: GPL-3.0-or-later
3 : /**
4 : * @file
5 : * @brief Initialising a new profile's store (.gpg-id, signature, Git) with
6 : * blocking processes, apart from the active store's backend.
7 : */
8 : #ifndef SRC_PROFILEINIT_H_
9 : #define SRC_PROFILEINIT_H_
10 :
11 : #include <QCoreApplication>
12 : #include <QList>
13 : #include <QProcessEnvironment>
14 : #include <QString>
15 :
16 : struct AppSettings;
17 : struct UserInfo;
18 :
19 : /**
20 : * @class ProfileInit
21 : * @ingroup settings
22 : * @brief Turn a directory into a password store without going through the
23 : * Pass backend of the currently active store.
24 : *
25 : * The backend is a shared singleton bound to the active store (settings
26 : * snapshot, PASSWORD_STORE_DIR, one FIFO of asynchronous processes), so a
27 : * new profile cannot be initialised through it without racing the active
28 : * store (#1774). Everything here is synchronous and touches only @p dir.
29 : */
30 : class ProfileInit {
31 21 : Q_DECLARE_TR_FUNCTIONS(ProfileInit)
32 :
33 : public:
34 : /**
35 : * @brief The environment QtPass runs gpg in outside the active store's
36 : * backend: the system's, with GNUPGHOME set to the configured GPG home
37 : * when there is one, so lookups and signatures use the keyring that signs.
38 : * @param s The settings naming the GPG home.
39 : * @return The environment for a gpg process.
40 : */
41 : static auto gpgEnvironment(const AppSettings &s) -> QProcessEnvironment;
42 : /**
43 : * @brief Check if a profile path needs initialization.
44 : * @param path The profile path to check.
45 : * @return true if the path exists but has no .gpg-id file.
46 : */
47 : static auto needsInit(const QString &path) -> bool;
48 :
49 : /**
50 : * @brief Write the recipients and, if wanted, put the folder under git.
51 : *
52 : * Writes `<dir>/.gpg-id` with the enabled key ids, signs it when
53 : * @p s.passSigningKey is set, and when @p useGit runs `git init`,
54 : * `git add` and `git commit` inside @p dir with blocking processes.
55 : * Existing `*.gpg` files are left alone: re-encrypting them needs the
56 : * backend, i.e. the profile has to be the active store; @p note says so.
57 : * @param dir Directory to initialise; created if missing.
58 : * @param users Key list; only entries with enabled == true are written.
59 : * @param s Settings for the gpg/git executables and the signing key.
60 : * @param useGit Whether to create a repository and commit the file.
61 : * @param note Receives a translated message for the user (empty on a quiet
62 : * success): the error, or the warning about existing entries.
63 : * @return true when the .gpg-id (and signature/commit if requested) is in
64 : * place.
65 : */
66 : static auto initialise(const QString &dir, const QList<UserInfo> &users,
67 : const AppSettings &s, bool useGit, QString *note)
68 : -> bool;
69 :
70 : /**
71 : * @brief Put an existing store under Git: `git init`, stage the `.gpg`
72 : * entries and the `.gpg-id` files (nothing else that may lie around in the
73 : * folder) and make a first commit, with blocking processes of their own in
74 : * @p dir.
75 : * @param dir The store.
76 : * @param s Settings for the git executable.
77 : * @param note Receives a translated error on failure.
78 : * @return true when the repository exists and the commit is made.
79 : */
80 : static auto initGit(const QString &dir, const AppSettings &s, QString *note)
81 : -> bool;
82 :
83 : /**
84 : * @brief Whether git has a name and e-mail to commit with, i.e.
85 : * `user.name` and `user.email` resolve (globally or in @p dir).
86 : * @param dir Directory to ask in; a repository's own config counts.
87 : * @param s Settings for the git executable.
88 : * @return true when a commit would not fail for lack of an identity.
89 : */
90 : static auto gitIdentityConfigured(const QString &dir, const AppSettings &s)
91 : -> bool;
92 :
93 : private:
94 : ProfileInit() = default;
95 : /**
96 : * @brief Write the enabled recipients to @p gpgIdFile, whole or not at
97 : * all; with @p signed_ the list carries the generation and folder header a
98 : * signed store's lists are checked against (GpgIdGeneration).
99 : * @param gpgIdFile The `.gpg-id` to write.
100 : * @param users The recipients; the enabled ones are written.
101 : * @param signed_ Whether the store gets a signing key, i.e. the header.
102 : * @param note Receives the reason on failure.
103 : * @param written Receives the exact bytes written, if not null.
104 : * @return Whether the file was written.
105 : */
106 : static auto writeGpgId(const QString &gpgIdFile, const QList<UserInfo> &users,
107 : bool signed_, QString *note,
108 : QByteArray *written = nullptr) -> bool;
109 : /**
110 : * @brief Sign the list just written as @p gpgIdFile, over the bytes
111 : * @p contents that were written.
112 : * @param gpgIdFile The `.gpg-id`; `<gpgIdFile>.sig` is written.
113 : * @param contents The bytes written as that file.
114 : * @param s The settings naming gpg and the signing key.
115 : * @param note Receives the reason on failure.
116 : * @return Whether the signature is in place.
117 : */
118 : static auto signGpgId(const QString &gpgIdFile, const QByteArray &contents,
119 : const AppSettings &s, QString *note) -> bool;
120 : /**
121 : * @brief `git init` in @p dir, stage the `.gpg-id` and its signature, and
122 : * commit them (signed when `pass.signcommits` is set), with a QProcess of
123 : * its own in the store's Git environment.
124 : * @param dir The store, absolute.
125 : * @param gpgIdFile The `.gpg-id` just written.
126 : * @param sigFile Its `.sig`, or empty when the store is not signed.
127 : * @param s Settings for the git executable and the GPG home.
128 : * @param note Receives a translated error naming the failed git command.
129 : * @return Whether the commit was made.
130 : */
131 : static auto commitGpgId(const QString &dir, const QString &gpgIdFile,
132 : const QString &sigFile, const AppSettings &s,
133 : QString *note) -> bool;
134 : };
135 :
136 : #endif // SRC_PROFILEINIT_H_
|