File indexing completed on 2024-04-21 14:53:24

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