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

source code of kauth/src/action.h