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
25/*!
26 * \namespace KAuth
27 * \inmodule KAuth
28 */
29namespace KAuth
30{
31class ExecuteJob;
32
33class 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 */
83class KAUTHCORE_EXPORT Action
84{
85 Q_GADGET
86public:
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
433private:
434 QSharedDataPointer<ActionData> d;
435};
436
437} // namespace Auth
438
439Q_DECLARE_TYPEINFO(KAuth::Action, Q_RELOCATABLE_TYPE);
440
441#endif
442

source code of kauth/src/action.h