1/******************************************************************************
2 * Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
3 * *
4 * This program is distributed in the hope that it will be useful, but *
5 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
6 * or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
7 * details, check the accompanying file 'COPYING'. *
8 *****************************************************************************/
9#ifndef KEYCHAIN_H
10#define KEYCHAIN_H
11
12#if !defined(QTKEYCHAIN_NO_EXPORT)
13#include "qkeychain_export.h"
14#else
15#define QKEYCHAIN_EXPORT
16#endif
17
18#include <QtCore/QObject>
19#include <QtCore/QString>
20
21class QSettings;
22
23#define QTKEYCHAIN_VERSION 0x000100
24
25namespace QKeychain {
26
27/**
28 * Error codes
29 */
30enum Error {
31 NoError=0, /**< No error occurred, operation was successful */
32 EntryNotFound, /**< For the given key no data was found */
33 CouldNotDeleteEntry, /**< Could not delete existing secret data */
34 AccessDeniedByUser, /**< User denied access to keychain */
35 AccessDenied, /**< Access denied for other reasons */
36 NoBackendAvailable, /**< No platform-specific keychain service available */
37 NotImplemented, /**< Not implemented on platform */
38 OtherError /**< Something else went wrong (errorString() might provide details) */
39};
40
41class JobExecutor;
42class JobPrivate;
43
44/**
45 * @brief Abstract base class for all QKeychain jobs.
46 */
47class QKEYCHAIN_EXPORT Job : public QObject {
48 Q_OBJECT
49public:
50 ~Job() override;
51
52 /**
53 * @return The QSettings instance used as plaintext storage if insecureFallback() is true.
54 * @see setSettings()
55 * @see insecureFallback()
56 */
57 QSettings* settings() const;
58
59 /**
60 * @return Set the QSettings instance that will be used as plaintext storage if insecureFallback() is true.
61 * @see settings()
62 * @see insecureFallback()
63 */
64 void setSettings( QSettings* settings );
65
66 /**
67 * Call this method to start the job.
68 * Typically you want to connect some slot to the finished() signal first:
69 *
70 * \code
71 * SomeClass::startJob()
72 * {
73 * connect(job, &Job::finished, this, &SomeClass::slotJobFinished);
74 * job->start();
75 * }
76 *
77 * SomeClass::slotJobFinished(Job *job)
78 * {
79 * if (job->error()) {
80 * // handle error
81 * } else {
82 * // do job-specific stuff
83 * }
84 * }
85 * \endcode
86 *
87 * @see finished()
88 */
89 void start();
90
91 QString service() const;
92
93 /**
94 * @note Call this method only after finished() has been emitted.
95 * @return The error code of the job (0 if no error).
96 */
97 Error error() const;
98
99 /**
100 * @return An error message that might provide details if error() returns OtherError.
101 */
102 QString errorString() const;
103
104 /**
105 * @return Whether this job autodeletes itself once finished() has been emitted. Default is true.
106 * @see setAutoDelete()
107 */
108 bool autoDelete() const;
109
110 /**
111 * Set whether this job should autodelete itself once finished() has been emitted.
112 * @see autoDelete()
113 */
114 void setAutoDelete( bool autoDelete );
115
116 /**
117 * @return Whether this job will use plaintext storage on unsupported platforms. Default is false.
118 * @see setInsecureFallback()
119 */
120 bool insecureFallback() const;
121
122 /**
123 * Set whether this job should use plaintext storage on unsupported platforms.
124 * @see insecureFallback()
125 */
126 void setInsecureFallback( bool insecureFallback );
127
128 /**
129 * @return The string used as key by this job.
130 * @see setKey()
131 */
132 QString key() const;
133
134 /**
135 * Set the @p key that this job will use to read or write data from/to the keychain.
136 * The key can be an empty string.
137 * @see key()
138 */
139 void setKey( const QString& key );
140
141 void emitFinished();
142 void emitFinishedWithError(Error, const QString& errorString);
143
144Q_SIGNALS:
145 /**
146 * Emitted when this job is finished.
147 * You can connect to this signal to be notified about the job's completion.
148 * @see start()
149 */
150 void finished( QKeychain::Job* );
151
152protected:
153 explicit Job( JobPrivate *q, QObject* parent=nullptr );
154 Q_INVOKABLE void doStart();
155
156private:
157 void setError( Error error );
158 void setErrorString( const QString& errorString );
159
160 void scheduledStart();
161
162protected:
163 JobPrivate* const d;
164
165friend class JobExecutor;
166friend class JobPrivate;
167friend class ReadPasswordJobPrivate;
168friend class WritePasswordJobPrivate;
169friend class DeletePasswordJobPrivate;
170};
171
172class ReadPasswordJobPrivate;
173
174/**
175 * @brief Job for reading secrets from the keychain.
176 * You can use a ReadPasswordJob to read passwords or binary data from the keychain.
177 * This job requires a "service" string, which is basically a namespace of keys within the keychain.
178 * This means that you can read all the pairs <key, secret> stored in the same service string.
179 */
180class QKEYCHAIN_EXPORT ReadPasswordJob : public Job {
181 Q_OBJECT
182public:
183 /**
184 * Create a new ReadPasswordJob.
185 * @param service The service string used by this job (can be empty).
186 * @param parent The parent of this job.
187 */
188 explicit ReadPasswordJob( const QString& service, QObject* parent=nullptr );
189 ~ReadPasswordJob() override;
190
191 /**
192 * @return The binary data stored as value of this job's key().
193 * @see Job::key()
194 */
195 QByteArray binaryData() const;
196
197 /**
198 * @return The string stored as value of this job's key().
199 * @see Job::key()
200 * @warning Returns meaningless data if the data was stored as binary data.
201 * @see WritePasswordJob::setTextData()
202 */
203 QString textData() const;
204
205private:
206 friend class QKeychain::ReadPasswordJobPrivate;
207};
208
209class WritePasswordJobPrivate;
210
211/**
212 * @brief Job for writing secrets to the keychain.
213 * You can use a WritePasswordJob to store passwords or binary data in the keychain.
214 * This job requires a "service" string, which is basically a namespace of keys within the keychain.
215 * This means that you can store different pairs <key, secret> under the same service string.
216 */
217class QKEYCHAIN_EXPORT WritePasswordJob : public Job {
218 Q_OBJECT
219public:
220 /**
221 * Create a new WritePasswordJob.
222 * @param service The service string used by this job (can be empty).
223 * @param parent The parent of this job.
224 */
225 explicit WritePasswordJob( const QString& service, QObject* parent=nullptr );
226 ~WritePasswordJob() override;
227
228 /**
229 * Set the @p data that the job will store in the keychain as binary data.
230 * @warning setBinaryData() and setTextData() are mutually exclusive.
231 */
232 void setBinaryData( const QByteArray& data );
233
234 /**
235 * Set the @p data that the job will store in the keychain as string.
236 * Typically @p data is a password.
237 * @warning setBinaryData() and setTextData() are mutually exclusive.
238 */
239 void setTextData( const QString& data );
240
241private:
242
243 friend class QKeychain::WritePasswordJobPrivate;
244};
245
246class DeletePasswordJobPrivate;
247
248/**
249 * @brief Job for deleting secrets from the keychain.
250 * You can use a DeletePasswordJob to delete passwords or binary data from the keychain.
251 * This job requires a "service" string, which is basically a namespace of keys within the keychain.
252 * This means that you can delete all the pairs <key, secret> stored in the same service string.
253 */
254class QKEYCHAIN_EXPORT DeletePasswordJob : public Job {
255 Q_OBJECT
256public:
257 /**
258 * Create a new DeletePasswordJob.
259 * @param service The service string used by this job (can be empty).
260 * @param parent The parent of this job.
261 */
262 explicit DeletePasswordJob( const QString& service, QObject* parent=nullptr );
263 ~DeletePasswordJob() override;
264
265private:
266 friend class QKeychain::DeletePasswordJobPrivate;
267};
268
269/**
270 * Checks whether there is a viable secure backend available.
271 * This particularly matters on UNIX platforms where multiple different backends
272 * exist and none might be available.
273 *
274 * Note that using the insecure fallback will work even if no secure backend is available.
275 *
276 * @since 0.14.0
277 */
278QKEYCHAIN_EXPORT bool isAvailable();
279
280} // namespace QtKeychain
281
282#endif
283