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 | namespace KAuth |
26 | { |
27 | class ExecuteJob; |
28 | |
29 | class 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 | */ |
77 | class KAUTHCORE_EXPORT Action |
78 | { |
79 | Q_GADGET |
80 | public: |
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 | |
408 | private: |
409 | QSharedDataPointer<ActionData> d; |
410 | }; |
411 | |
412 | } // namespace Auth |
413 | |
414 | Q_DECLARE_TYPEINFO(KAuth::Action, Q_RELOCATABLE_TYPE); |
415 | |
416 | #endif |
417 | |