File indexing completed on 2024-03-24 03:55:22

0001 /*
0002     SPDX-FileCopyrightText: 2009-2012 Dario Freddi <drf@kde.org>
0003     SPDX-FileCopyrightText: 2008 Nicola Gigante <nicola.gigante@gmail.com>
0004     SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-or-later
0007 */
0008 
0009 #ifndef KAUTH_ACTION_H
0010 #define KAUTH_ACTION_H
0011 
0012 #include "kauthcore_export.h"
0013 
0014 #include <QHash>
0015 #include <QSharedDataPointer>
0016 #include <QString>
0017 #include <QVariant>
0018 
0019 #if __has_include(<chrono>)
0020 #include <chrono>
0021 #endif
0022 
0023 class QWindow;
0024 
0025 namespace KAuth
0026 {
0027 class ExecuteJob;
0028 
0029 class ActionData;
0030 /**
0031  * @class Action action.h <KAuth/Action>
0032  *
0033  * @brief Class to access, authorize and execute actions.
0034  *
0035  * This is the main class of the KAuth API. It provides the interface to
0036  * manipulate actions. Every action is identified by its name. Every instance
0037  * of the Action class with the same name refers to the same action.
0038  *
0039  * Once you have an action object you can tell the helper to execute it
0040  * (asking the user to authenticate if needed) with the execute() method.
0041  * The simplest thing to do is to execute a single action synchronously
0042  * blocking for the reply by calling KJob::exec() on the job object returned by
0043  * execute().
0044  *
0045  * For asynchronous calls, use KAuth::ExecuteJob::start() instead.
0046  * It sends the request
0047  * to the helper and returns immediately. Before doing so you should however
0048  * connect to at least the KJob::result(KJob *) signal to receive a slot call
0049  * once the action is done executing.
0050  *
0051  * To use the execute() method you have to set the default helper's ID using
0052  * the setHelperId() static method. Alternatively, you can specify the helperID using
0053  * the overloaded version of the methods that takes it as a parameter.
0054  *
0055  * Each action object contains a QVariantMap object that is passed directly to the
0056  * helper when the action is executed. You can access this map using the arguments()
0057  * method. You can insert into it any kind of custom data you need to pass to the helper.
0058  *
0059  * @code
0060  * void MyApp::runAction()
0061  * {
0062  *     action = KAuth::Action("org.kde.myapp.action");
0063  *     KAuth::ExecuteJob *job = action.execute();
0064  *     connect(job, &KAuth::ExecuteJob::result, this, &MyApp::actionResult);
0065  *     job->start();
0066  * }
0067  *
0068  * void MyApp::actionResult(KJob *kjob)
0069  * {
0070  *     auto job = qobject_cast<KAuth::ExecuteJob *>(kjob);
0071  *     qDebug() << job.error() << job.data();
0072  * }
0073  * @endcode
0074  *
0075  * @since 4.4
0076  */
0077 class KAUTHCORE_EXPORT Action
0078 {
0079     Q_GADGET
0080 public:
0081     /**
0082      * The three values set by authorization methods
0083      */
0084     enum AuthStatus {
0085         DeniedStatus, ///< The authorization has been denied by the authorization backend
0086         ErrorStatus, ///< An error occurred
0087         InvalidStatus, ///< An invalid action cannot be authorized
0088         AuthorizedStatus, ///< The authorization has been granted by the authorization backend
0089         AuthRequiredStatus, ///< The user could obtain the authorization after authentication
0090         UserCancelledStatus, ///< The user pressed Cancel the authentication dialog. Currently used only on the mac
0091     };
0092     Q_ENUM(AuthStatus)
0093 
0094     enum ExecutionMode {
0095         ExecuteMode,
0096         AuthorizeOnlyMode,
0097     };
0098     Q_ENUM(ExecutionMode)
0099 
0100     /**
0101      * The backend specific details.
0102      */
0103     enum class AuthDetail {
0104         DetailOther = 0,
0105         DetailMessage, ///< The message to show in authentication dialog.
0106     };
0107     Q_ENUM(AuthDetail)
0108 
0109     /**
0110      * Map of details.
0111      */
0112     typedef QMap<AuthDetail, QVariant> DetailsMap;
0113 
0114     /**
0115      * @brief Default constructor
0116      *
0117      * This constructor sets the name to the empty string.
0118      * Such an action is invalid and cannot be authorized nor executed, so
0119      * you need to call setName() before you can use the object.
0120      */
0121     Action();
0122 
0123     /** Copy constructor */
0124     Action(const Action &action);
0125 
0126     /**
0127      * This creates a new action object with this name
0128      * @param name The name of the new action
0129      */
0130     Action(const QString &name);
0131 
0132     /**
0133      * This creates a new action object with this name and details
0134      * @param name The name of the new action
0135      * @param details The details of the action
0136      *
0137      * @see setDetails
0138      * @since 5.68
0139      */
0140     Action(const QString &name, const DetailsMap &details);
0141 
0142     /// Virtual destructor
0143     ~Action();
0144 
0145     /// Assignment operator
0146     Action &operator=(const Action &action);
0147 
0148     /**
0149      * @brief Comparison operator
0150      *
0151      * This comparison operator compares the <b>names</b> of two
0152      * actions and returns whether they are the same. It does not
0153      * care about the arguments stored in the actions. However,
0154      * if two actions are invalid they'll match as equal, even
0155      * if the invalid names are different.
0156      *
0157      * @returns true if the two actions are the same or both invalid
0158      */
0159     bool operator==(const Action &action) const;
0160 
0161     /**
0162      * @brief Negated comparison operator
0163      *
0164      * Returns the negation of operator==
0165      *
0166      * @returns true if the two actions are different and not both invalid
0167      */
0168     bool operator!=(const Action &action) const;
0169 
0170     /**
0171      * @brief Gets the action's name.
0172      *
0173      * This is the unique attribute that identifies
0174      * an action object. Two action objects with the same
0175      * name always refer to the same action.
0176      *
0177      * @return The action name
0178      */
0179     QString name() const;
0180 
0181     /**
0182      * @brief Sets the action's name.
0183      *
0184      * It's not common to change the action name
0185      * after its creation. Usually you set the name
0186      * with the constructor (and you have to, because
0187      * there's no default constructor)
0188      */
0189     void setName(const QString &name);
0190 
0191     /**
0192      * @brief Gets the action's timeout.
0193      *
0194      * The timeout of the action in milliseconds
0195      * -1 means the default D-Bus timeout (usually 25 seconds)
0196      *
0197      * @since 5.29
0198      *
0199      * @return The action timeouts
0200      */
0201     int timeout() const;
0202 
0203     /**
0204      * @brief Sets the action's timeout.
0205      *
0206      * The timeout of the action in milliseconds
0207      * -1 means the default D-Bus timeout (usually 25 seconds)
0208      *
0209      * @since 5.29
0210      *
0211      */
0212     void setTimeout(int timeout);
0213 
0214 #if __has_include(<chrono>)
0215     /**
0216      * Convenience overload suporting C++ chrono types. May also be used with chrono literals.
0217      * @since 5.93
0218      */
0219     void setTimeout(std::chrono::milliseconds msec)
0220     {
0221         setTimeout(int(msec.count()));
0222     }
0223 #endif
0224 
0225     /**
0226      * @brief Sets the action's details
0227      *
0228      * You can use this function to provide the user more details
0229      * (if the backend supports it) on the action being authorized in
0230      * the authorization dialog
0231      *
0232      * @param details the details describing the action. For e.g, "DetailMessage" key can
0233      * be used to give a customized authentication message.
0234      *
0235      * @since 5.68
0236      */
0237     void setDetailsV2(const DetailsMap &details);
0238 
0239     /**
0240      * @brief Gets the action's details
0241      *
0242      * The details that will be shown in the authorization dialog, if the
0243      * backend supports it.
0244      *
0245      * @return The action's details
0246      * @since 5.68
0247      */
0248     DetailsMap detailsV2() const;
0249 
0250     /**
0251      * @brief Returns if the object represents a valid action
0252      *
0253      * Action names have to respect a simple syntax.
0254      * They have to be all in lowercase characters, separated
0255      * by dots. Dots can't appear at the beginning and at the end of
0256      * the name.
0257      *
0258      * In other words, the action name has to match this perl-like
0259      * regular expression:
0260      * @code
0261      * /^[a-z]+(\.[a-z]+)*$/
0262      * @endcode
0263      *
0264      * This method returns @c false if the action name doesn't match the
0265      * valid syntax.
0266      *
0267      * If the backend supports it, this method also checks if the action is
0268      * valid and recognized by the backend itself.
0269      * @note This may spawn a nested event loop.
0270      *
0271      * Invalid actions cannot be authorized nor executed.
0272      * The empty string is not a valid action name, so the default
0273      * constructor returns an invalid action.
0274      */
0275     bool isValid() const;
0276 
0277     /**
0278      * @brief Gets the default helper ID used for actions execution
0279      *
0280      * The helper ID is the string that uniquely identifies the helper in
0281      * the system. It is the string passed to the KAUTH_HELPER_MAIN() macro
0282      * in the helper source. Because one could have different helpers,
0283      * you need to specify an helper ID for each execution, or set a default
0284      * ID by calling setHelperId(). This method returns the current default
0285      * value.
0286      *
0287      * @return The default helper ID.
0288      */
0289     QString helperId() const;
0290 
0291     /**
0292      * @brief Sets the default helper ID used for actions execution
0293      *
0294      * This method sets the helper ID which contains the body of this action.
0295      * If the string is non-empty, the corresponding helper will be fired and
0296      * the action executed inside the helper. Otherwise, the action will be just
0297      * authorized.
0298      *
0299      * @note To unset a previously set helper, just pass an empty string
0300      *
0301      * @param id The default helper ID.
0302      *
0303      * @see hasHelper
0304      * @see helperId
0305      */
0306     void setHelperId(const QString &id);
0307 
0308     /**
0309      * @brief Checks if the action has an helper
0310      *
0311      * This function can be used to check if an helper will be called upon the
0312      * execution of an action. Such an helper can be set through setHelperId(). If
0313      * this function returns false, upon execution the action will be just authorized.
0314      *
0315      * @since 4.5
0316      *
0317      * @return Whether the action has an helper or not
0318      *
0319      * @see setHelperId
0320      */
0321     bool hasHelper() const;
0322 
0323     /**
0324      * @brief Sets the map object used to pass arguments to the helper.
0325      *
0326      * This method sets the variant map that the application
0327      * can use to pass arbitrary data to the helper when executing the action.
0328      *
0329      * Only non-gui variants are supported.
0330      *
0331      * @param arguments The new arguments map
0332      */
0333     void setArguments(const QVariantMap &arguments);
0334 
0335     /**
0336      * @brief Returns map object used to pass arguments to the helper.
0337      *
0338      * This method returns the variant map that the application
0339      * can use to pass arbitrary data to the helper when executing the action.
0340      *
0341      * @return The arguments map that will be passed to the helper.
0342      */
0343     QVariantMap arguments() const;
0344 
0345     /**
0346      * @brief Convenience method to add an argument.
0347      *
0348      * This method adds the pair @c key/value to the QVariantMap used to
0349      * send custom data to the helper.
0350      *
0351      * Use this method if you don't want to create a new QVariantMap only to
0352      * add a new entry.
0353      *
0354      * @param key The new entry's key
0355      * @param value The value of the new entry
0356      */
0357     void addArgument(const QString &key, const QVariant &value);
0358 
0359     /**
0360      * @brief Gets information about the authorization status of an action
0361      *
0362      * This methods query the authorization backend to know if the user can try
0363      * to acquire the authorization for this action. If the result is Action::AuthRequired,
0364      * the user can try to acquire the authorization by authenticating.
0365      *
0366      * It should not be needed to call this method directly, because the execution methods
0367      * already take care of all the authorization stuff.
0368      *
0369      * @return @c Action::Denied if the user doesn't have the authorization to execute the action,
0370      *         @c Action::Authorized if the action can be executed,
0371      *         @c Action::AuthRequired if the user could acquire the authorization after authentication,
0372      *         @c Action::UserCancelled if the user cancels the authentication dialog. Not currently supported by the Polkit backend
0373      */
0374     AuthStatus status() const;
0375 
0376     /**
0377      * @brief Get the job object used to execute the action
0378      *
0379      * @return The KAuth::ExecuteJob object to be used to run the action.
0380      */
0381     ExecuteJob *execute(ExecutionMode mode = ExecuteMode);
0382 
0383     /**
0384      * @brief Sets a parent window for the authentication dialog
0385      *
0386      * This function is used for explicitly setting a parent window for an eventual authentication dialog required when
0387      * authorization is triggered. Some backends, in fact, (like polkit-1) need to have a parent explicitly set for displaying
0388      * the dialog correctly.
0389      *
0390      * @note If you are using KAuth through one of KDE's GUI components (KPushButton, KCModule...) you do not need and should not
0391      *       call this function, as it is already done by the component itself.
0392      *
0393      * @since 6.0
0394      *
0395      * @param parent A QWidget which will be used as the dialog's parent
0396      */
0397     void setParentWindow(QWindow *parent);
0398 
0399     /**
0400      * @brief Returns the parent widget for the authentication dialog for this action
0401      *
0402      * @since 6.0
0403      *
0404      * @returns A QWindow which will is being used as the dialog's parent
0405      */
0406     QWindow *parentWindow() const;
0407 
0408 private:
0409     QSharedDataPointer<ActionData> d;
0410 };
0411 
0412 } // namespace Auth
0413 
0414 Q_DECLARE_TYPEINFO(KAuth::Action, Q_RELOCATABLE_TYPE);
0415 
0416 #endif