| 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 | |
| 21 | class QSettings; |
| 22 | |
| 23 | #define QTKEYCHAIN_VERSION 0x000100 |
| 24 | |
| 25 | namespace QKeychain { |
| 26 | |
| 27 | /** |
| 28 | * Error codes |
| 29 | */ |
| 30 | enum 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 | |
| 41 | class JobExecutor; |
| 42 | class JobPrivate; |
| 43 | |
| 44 | /** |
| 45 | * @brief Abstract base class for all QKeychain jobs. |
| 46 | */ |
| 47 | class QKEYCHAIN_EXPORT Job : public QObject { |
| 48 | Q_OBJECT |
| 49 | public: |
| 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 | |
| 144 | Q_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 | |
| 152 | protected: |
| 153 | explicit Job( JobPrivate *q, QObject* parent=nullptr ); |
| 154 | Q_INVOKABLE void doStart(); |
| 155 | |
| 156 | private: |
| 157 | void setError( Error error ); |
| 158 | void setErrorString( const QString& errorString ); |
| 159 | |
| 160 | void scheduledStart(); |
| 161 | |
| 162 | protected: |
| 163 | JobPrivate* const d; |
| 164 | |
| 165 | friend class JobExecutor; |
| 166 | friend class JobPrivate; |
| 167 | friend class ReadPasswordJobPrivate; |
| 168 | friend class WritePasswordJobPrivate; |
| 169 | friend class DeletePasswordJobPrivate; |
| 170 | }; |
| 171 | |
| 172 | class 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 | */ |
| 180 | class QKEYCHAIN_EXPORT ReadPasswordJob : public Job { |
| 181 | Q_OBJECT |
| 182 | public: |
| 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 | |
| 205 | private: |
| 206 | friend class QKeychain::ReadPasswordJobPrivate; |
| 207 | }; |
| 208 | |
| 209 | class 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 | */ |
| 217 | class QKEYCHAIN_EXPORT WritePasswordJob : public Job { |
| 218 | Q_OBJECT |
| 219 | public: |
| 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 | |
| 241 | private: |
| 242 | |
| 243 | friend class QKeychain::WritePasswordJobPrivate; |
| 244 | }; |
| 245 | |
| 246 | class 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 | */ |
| 254 | class QKEYCHAIN_EXPORT DeletePasswordJob : public Job { |
| 255 | Q_OBJECT |
| 256 | public: |
| 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 | |
| 265 | private: |
| 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 | */ |
| 278 | QKEYCHAIN_EXPORT bool isAvailable(); |
| 279 | |
| 280 | } // namespace QtKeychain |
| 281 | |
| 282 | #endif |
| 283 | |