| 1 | /* |
| 2 | SPDX-FileCopyrightText: 2009-2012 Dario Freddi <drf@kde.org> |
| 3 | SPDX-FileCopyrightText: 2008 Nicola Gigante <nicola.gigante@gmail.com> |
| 4 | SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org> |
| 5 | |
| 6 | SPDX-License-Identifier: LGPL-2.1-or-later |
| 7 | */ |
| 8 | |
| 9 | #ifndef KAUTH_ACTION_H |
| 10 | #define KAUTH_ACTION_H |
| 11 | |
| 12 | #include "kauthcore_export.h" |
| 13 | |
| 14 | #include <QHash> |
| 15 | #include <QSharedDataPointer> |
| 16 | #include <QString> |
| 17 | #include <QVariant> |
| 18 | |
| 19 | #if __has_include(<chrono>) |
| 20 | #include <chrono> |
| 21 | #endif |
| 22 | |
| 23 | class QWindow; |
| 24 | |
| 25 | /*! |
| 26 | * \namespace KAuth |
| 27 | * \inmodule KAuth |
| 28 | */ |
| 29 | namespace KAuth |
| 30 | { |
| 31 | class ExecuteJob; |
| 32 | |
| 33 | class ActionData; |
| 34 | /*! |
| 35 | * \class KAuth::Action |
| 36 | * \inmodule KAuth |
| 37 | * \inheaderfile KAuth/Action |
| 38 | * |
| 39 | * \brief Class to access, authorize and execute actions. |
| 40 | * |
| 41 | * This is the main class of the KAuth API. It provides the interface to |
| 42 | * manipulate actions. Every action is identified by its name. Every instance |
| 43 | * of the Action class with the same name refers to the same action. |
| 44 | * |
| 45 | * Once you have an action object you can tell the helper to execute it |
| 46 | * (asking the user to authenticate if needed) with the execute() method. |
| 47 | * The simplest thing to do is to execute a single action synchronously |
| 48 | * blocking for the reply by calling KJob::exec() on the job object returned by |
| 49 | * execute(). |
| 50 | * |
| 51 | * For asynchronous calls, use KAuth::ExecuteJob::start() instead. |
| 52 | * It sends the request |
| 53 | * to the helper and returns immediately. Before doing so you should however |
| 54 | * connect to at least the KJob::result(KJob *) signal to receive a slot call |
| 55 | * once the action is done executing. |
| 56 | * |
| 57 | * To use the execute() method you have to set the default helper's ID using |
| 58 | * the setHelperId() static method. Alternatively, you can specify the helperID using |
| 59 | * the overloaded version of the methods that takes it as a parameter. |
| 60 | * |
| 61 | * Each action object contains a QVariantMap object that is passed directly to the |
| 62 | * helper when the action is executed. You can access this map using the arguments() |
| 63 | * method. You can insert into it any kind of custom data you need to pass to the helper. |
| 64 | * |
| 65 | * \code |
| 66 | * void MyApp::runAction() |
| 67 | * { |
| 68 | * action = KAuth::Action("org.kde.myapp.action"); |
| 69 | * KAuth::ExecuteJob *job = action.execute(); |
| 70 | * connect(job, &KAuth::ExecuteJob::result, this, &MyApp::actionResult); |
| 71 | * job->start(); |
| 72 | * } |
| 73 | * |
| 74 | * void MyApp::actionResult(KJob *kjob) |
| 75 | * { |
| 76 | * auto job = qobject_cast<KAuth::ExecuteJob *>(kjob); |
| 77 | * qDebug() << job.error() << job.data(); |
| 78 | * } |
| 79 | * \endcode |
| 80 | * |
| 81 | * \since 4.4 |
| 82 | */ |
| 83 | class KAUTHCORE_EXPORT Action |
| 84 | { |
| 85 | Q_GADGET |
| 86 | public: |
| 87 | /*! |
| 88 | * The values set by authorization methods |
| 89 | * |
| 90 | * \value DeniedStatus The authorization has been denied by the authorization backend |
| 91 | * \value ErrorStatus An error occurred |
| 92 | * \value InvalidStatus An invalid action cannot be authorized |
| 93 | * \value AuthorizedStatus The authorization has been granted by the authorization backend |
| 94 | * \value AuthRequiredStatus The user could obtain the authorization after authentication |
| 95 | * \value UserCancelledStatus The user pressed Cancel the authentication dialog. Currently used only on the mac |
| 96 | */ |
| 97 | enum AuthStatus { |
| 98 | DeniedStatus, |
| 99 | ErrorStatus, |
| 100 | InvalidStatus, |
| 101 | AuthorizedStatus, |
| 102 | AuthRequiredStatus, |
| 103 | UserCancelledStatus, |
| 104 | }; |
| 105 | Q_ENUM(AuthStatus) |
| 106 | |
| 107 | /*! |
| 108 | * \value ExecuteMode |
| 109 | * \value AuthorizeOnlyMode |
| 110 | * |
| 111 | */ |
| 112 | enum ExecutionMode { |
| 113 | ExecuteMode, |
| 114 | AuthorizeOnlyMode, |
| 115 | }; |
| 116 | Q_ENUM(ExecutionMode) |
| 117 | |
| 118 | /*! |
| 119 | * The backend specific details. |
| 120 | * |
| 121 | * \value DetailOther |
| 122 | * \value DetailMessage The message to show in authentication dialog. |
| 123 | */ |
| 124 | enum class AuthDetail { |
| 125 | DetailOther = 0, |
| 126 | DetailMessage, |
| 127 | }; |
| 128 | Q_ENUM(AuthDetail) |
| 129 | |
| 130 | /*! |
| 131 | * Map of details. |
| 132 | */ |
| 133 | typedef QMap<AuthDetail, QVariant> DetailsMap; |
| 134 | |
| 135 | /*! |
| 136 | * \brief Default constructor |
| 137 | * |
| 138 | * This constructor sets the name to the empty string. |
| 139 | * Such an action is invalid and cannot be authorized nor executed, so |
| 140 | * you need to call setName() before you can use the object. |
| 141 | */ |
| 142 | Action(); |
| 143 | |
| 144 | /*! Copy constructor */ |
| 145 | Action(const Action &action); |
| 146 | |
| 147 | /*! |
| 148 | * This creates a new action object with this name |
| 149 | * \a name The name of the new action |
| 150 | */ |
| 151 | Action(const QString &name); |
| 152 | |
| 153 | /*! |
| 154 | * This creates a new action object with this name and details |
| 155 | * \a name The name of the new action |
| 156 | * \a details The details of the action |
| 157 | * |
| 158 | * \sa setDetailsV2 |
| 159 | * \since 5.68 |
| 160 | */ |
| 161 | Action(const QString &name, const DetailsMap &details); |
| 162 | |
| 163 | ~Action(); |
| 164 | |
| 165 | Action &operator=(const Action &action); |
| 166 | |
| 167 | /*! |
| 168 | * \brief Comparison operator |
| 169 | * |
| 170 | * This comparison operator compares the \e names of this and \a action |
| 171 | * and returns whether they are the same. It does not |
| 172 | * care about the arguments stored in the actions. However, |
| 173 | * if two actions are invalid they'll match as equal, even |
| 174 | * if the invalid names are different. |
| 175 | * |
| 176 | * Returns true if the two actions are the same or both invalid |
| 177 | */ |
| 178 | bool operator==(const Action &action) const; |
| 179 | |
| 180 | /*! |
| 181 | * \brief Negated comparison operator |
| 182 | * |
| 183 | * Returns the negation of operator== |
| 184 | * |
| 185 | * \a action the action to compare to |
| 186 | * |
| 187 | * Returns true if the two actions are different and not both invalid |
| 188 | */ |
| 189 | bool operator!=(const Action &action) const; |
| 190 | |
| 191 | /*! |
| 192 | * \brief Gets the action's name. |
| 193 | * |
| 194 | * This is the unique attribute that identifies |
| 195 | * an action object. Two action objects with the same |
| 196 | * name always refer to the same action. |
| 197 | * |
| 198 | * Returns The action name |
| 199 | */ |
| 200 | QString name() const; |
| 201 | |
| 202 | /*! |
| 203 | * \brief Sets the action's name. |
| 204 | * |
| 205 | * It's not common to change the action name |
| 206 | * after its creation. Usually you set the name |
| 207 | * with the constructor (and you have to, because |
| 208 | * there's no default constructor) |
| 209 | */ |
| 210 | void setName(const QString &name); |
| 211 | |
| 212 | /*! |
| 213 | * \brief Gets the action's timeout. |
| 214 | * |
| 215 | * The timeout of the action in milliseconds |
| 216 | * -1 means the default D-Bus timeout (usually 25 seconds) |
| 217 | * |
| 218 | * \since 5.29 |
| 219 | * |
| 220 | * Returns The action timeouts |
| 221 | */ |
| 222 | int timeout() const; |
| 223 | |
| 224 | /*! |
| 225 | * \brief Sets the action's timeout. |
| 226 | * |
| 227 | * The \a timeout of the action in milliseconds |
| 228 | * -1 means the default D-Bus timeout (usually 25 seconds) |
| 229 | * |
| 230 | * \since 5.29 |
| 231 | * |
| 232 | */ |
| 233 | void setTimeout(int timeout); |
| 234 | |
| 235 | #if __has_include(<chrono>) |
| 236 | /*! |
| 237 | * Convenience overload suporting C++ chrono types. May also be used with chrono literals. |
| 238 | * \since 5.93 |
| 239 | */ |
| 240 | void setTimeout(std::chrono::milliseconds msec) |
| 241 | { |
| 242 | setTimeout(int(msec.count())); |
| 243 | } |
| 244 | #endif |
| 245 | |
| 246 | /*! |
| 247 | * \brief Sets the action's details |
| 248 | * |
| 249 | * You can use this function to provide the user more details |
| 250 | * (if the backend supports it) on the action being authorized in |
| 251 | * the authorization dialog |
| 252 | * |
| 253 | * \a details the details describing the action. For e.g, "DetailMessage" key can |
| 254 | * be used to give a customized authentication message. |
| 255 | * |
| 256 | * \since 5.68 |
| 257 | */ |
| 258 | void setDetailsV2(const DetailsMap &details); |
| 259 | |
| 260 | /*! |
| 261 | * \brief Gets the action's details |
| 262 | * |
| 263 | * The details that will be shown in the authorization dialog, if the |
| 264 | * backend supports it. |
| 265 | * |
| 266 | * Returns The action's details |
| 267 | * \since 5.68 |
| 268 | */ |
| 269 | DetailsMap detailsV2() const; |
| 270 | |
| 271 | /*! |
| 272 | * \brief Returns if the object represents a valid action |
| 273 | * |
| 274 | * Action names have to respect a simple syntax. |
| 275 | * They have to be all in lowercase characters, separated |
| 276 | * by dots. Dots can't appear at the beginning and at the end of |
| 277 | * the name. |
| 278 | * |
| 279 | * In other words, the action name has to match this perl-like |
| 280 | * regular expression: |
| 281 | * \badcode |
| 282 | * /^[a-z]+(\.[a-z]+)*$/ |
| 283 | * \endcode |
| 284 | * |
| 285 | * This method returns \c false if the action name doesn't match the |
| 286 | * valid syntax. |
| 287 | * |
| 288 | * If the backend supports it, this method also checks if the action is |
| 289 | * valid and recognized by the backend itself. |
| 290 | * \note This may spawn a nested event loop. |
| 291 | * |
| 292 | * Invalid actions cannot be authorized nor executed. |
| 293 | * The empty string is not a valid action name, so the default |
| 294 | * constructor returns an invalid action. |
| 295 | */ |
| 296 | bool isValid() const; |
| 297 | |
| 298 | /*! |
| 299 | * \brief Gets the default helper ID used for actions execution |
| 300 | * |
| 301 | * The helper ID is the string that uniquely identifies the helper in |
| 302 | * the system. It is the string passed to the KAUTH_HELPER_MAIN() macro |
| 303 | * in the helper source. Because one could have different helpers, |
| 304 | * you need to specify an helper ID for each execution, or set a default |
| 305 | * ID by calling setHelperId(). This method returns the current default |
| 306 | * value. |
| 307 | * |
| 308 | * Returns the default helper ID. |
| 309 | */ |
| 310 | QString helperId() const; |
| 311 | |
| 312 | /*! |
| 313 | * \brief Sets the default helper ID used for actions execution |
| 314 | * |
| 315 | * This method sets the helper ID which contains the body of this action. |
| 316 | * If the string is non-empty, the corresponding helper will be fired and |
| 317 | * the action executed inside the helper. Otherwise, the action will be just |
| 318 | * authorized. |
| 319 | * |
| 320 | * \note To unset a previously set helper, just pass an empty string |
| 321 | * |
| 322 | * \a id The default helper ID. |
| 323 | * |
| 324 | * \sa hasHelper |
| 325 | * \sa helperId |
| 326 | */ |
| 327 | void setHelperId(const QString &id); |
| 328 | |
| 329 | /*! |
| 330 | * \brief Checks if the action has an helper |
| 331 | * |
| 332 | * This function can be used to check if an helper will be called upon the |
| 333 | * execution of an action. Such an helper can be set through setHelperId(). If |
| 334 | * this function returns false, upon execution the action will be just authorized. |
| 335 | * |
| 336 | * \since 4.5 |
| 337 | * |
| 338 | * Returns Whether the action has an helper or not |
| 339 | * |
| 340 | * \sa setHelperId |
| 341 | */ |
| 342 | bool hasHelper() const; |
| 343 | |
| 344 | /*! |
| 345 | * \brief Sets the map object used to pass arguments to the helper. |
| 346 | * |
| 347 | * This method sets the variant map that the application |
| 348 | * can use to pass arbitrary data to the helper when executing the action. |
| 349 | * |
| 350 | * Only non-gui variants are supported. |
| 351 | * |
| 352 | * \a arguments The new arguments map |
| 353 | */ |
| 354 | void setArguments(const QVariantMap &arguments); |
| 355 | |
| 356 | /*! |
| 357 | * \brief Returns map object used to pass arguments to the helper. |
| 358 | * |
| 359 | * This method returns the variant map that the application |
| 360 | * can use to pass arbitrary data to the helper when executing the action. |
| 361 | * |
| 362 | * Returns the arguments map that will be passed to the helper. |
| 363 | */ |
| 364 | QVariantMap arguments() const; |
| 365 | |
| 366 | /*! |
| 367 | * \brief Convenience method to add an argument. |
| 368 | * |
| 369 | * This method adds the pair \c key/value to the QVariantMap used to |
| 370 | * send custom data to the helper. |
| 371 | * |
| 372 | * Use this method if you don't want to create a new QVariantMap only to |
| 373 | * add a new entry. |
| 374 | * |
| 375 | * \a key The new entry's key |
| 376 | * |
| 377 | * \a value The value of the new entry |
| 378 | */ |
| 379 | void addArgument(const QString &key, const QVariant &value); |
| 380 | |
| 381 | /*! |
| 382 | * \brief Gets information about the authorization status of an action |
| 383 | * |
| 384 | * This methods query the authorization backend to know if the user can try |
| 385 | * to acquire the authorization for this action. If the result is Action::AuthRequired, |
| 386 | * the user can try to acquire the authorization by authenticating. |
| 387 | * |
| 388 | * It should not be needed to call this method directly, because the execution methods |
| 389 | * already take care of all the authorization stuff. |
| 390 | * |
| 391 | * Returns |
| 392 | * \list |
| 393 | * \li Action::Denied if the user doesn't have the authorization to execute the action, |
| 394 | * \li Action::Authorized if the action can be executed, |
| 395 | * \li Action::AuthRequired if the user could acquire the authorization after authentication, |
| 396 | * \li Action::UserCancelled if the user cancels the authentication dialog. Not currently supported by the Polkit backend |
| 397 | * \endlist |
| 398 | */ |
| 399 | AuthStatus status() const; |
| 400 | |
| 401 | /*! |
| 402 | * \brief Get the job object used to execute the action |
| 403 | * |
| 404 | * Returns the KAuth::ExecuteJob object to be used to run the action. |
| 405 | */ |
| 406 | ExecuteJob *execute(ExecutionMode mode = ExecuteMode); |
| 407 | |
| 408 | /*! |
| 409 | * \brief Sets a parent window for the authentication dialog |
| 410 | * |
| 411 | * This function is used for explicitly setting a parent window for an eventual authentication dialog required when |
| 412 | * authorization is triggered. Some backends, in fact, (like polkit-1) need to have a parent explicitly set for displaying |
| 413 | * the dialog correctly. |
| 414 | * |
| 415 | * \note If you are using KAuth through one of KDE's GUI components (KPushButton, KCModule...) you do not need and should not |
| 416 | * call this function, as it is already done by the component itself. |
| 417 | * |
| 418 | * \since 6.0 |
| 419 | * |
| 420 | * \a parent A QWidget which will be used as the dialog's parent |
| 421 | */ |
| 422 | void setParentWindow(QWindow *parent); |
| 423 | |
| 424 | /*! |
| 425 | * \brief Returns the parent widget for the authentication dialog for this action |
| 426 | * |
| 427 | * \since 6.0 |
| 428 | * |
| 429 | * Returns a QWindow which will is being used as the dialog's parent |
| 430 | */ |
| 431 | QWindow *parentWindow() const; |
| 432 | |
| 433 | private: |
| 434 | QSharedDataPointer<ActionData> d; |
| 435 | }; |
| 436 | |
| 437 | } // namespace Auth |
| 438 | |
| 439 | Q_DECLARE_TYPEINFO(KAuth::Action, Q_RELOCATABLE_TYPE); |
| 440 | |
| 441 | #endif |
| 442 | |