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 | |