Branch data Line data Source code
1 : : /* libsecret - GLib wrapper for Secret Service
2 : : *
3 : : * Copyright 2011 Collabora Ltd.
4 : : * Copyright 2012 Red Hat Inc.
5 : : *
6 : : * This program is free software: you can redistribute it and/or modify
7 : : * it under the terms of the GNU Lesser General Public License as published
8 : : * by the Free Software Foundation; either version 2.1 of the licence or (at
9 : : * your option) any later version.
10 : : *
11 : : * See the included COPYING file for more information.
12 : : *
13 : : * Author: Stef Walter <stefw@gnome.org>
14 : : */
15 : :
16 : : #include "config.h"
17 : :
18 : : #include "secret-backend.h"
19 : : #include "secret-collection.h"
20 : : #include "secret-dbus-generated.h"
21 : : #include "secret-item.h"
22 : : #include "secret-paths.h"
23 : : #include "secret-private.h"
24 : : #include "secret-service.h"
25 : : #include "secret-types.h"
26 : : #include "secret-value.h"
27 : :
28 : : #include "libsecret/secret-enum-types.h"
29 : :
30 : : #include "egg/egg-secure-memory.h"
31 : :
32 : : /**
33 : : * SecretService:
34 : : *
35 : : * A proxy object representing the Secret Service.
36 : : *
37 : : * A #SecretService object represents the Secret Service implementation which
38 : : * runs as a D-Bus service.
39 : : *
40 : : * Normally a single #SecretService object can be shared between multiple
41 : : * callers. The [func@Service.get] method is used to access this #SecretService
42 : : * object. If a new independent #SecretService object is required, use
43 : : * [func@Service.open].
44 : : *
45 : : * In order to securely transfer secrets to the Sercret Service, a session
46 : : * is established. This session can be established while initializing a
47 : : * #SecretService object by passing the %SECRET_SERVICE_OPEN_SESSION flag
48 : : * to the [func@Service.get] or [func@Service.open] functions. In order to
49 : : * establish a session on an already existing #SecretService, use the
50 : : * [method@Service.ensure_session] function.
51 : : *
52 : : * To search for items, use the [method@Service.search] method.
53 : : *
54 : : * Multiple collections can exist in the Secret Service, each of which contains
55 : : * secret items. In order to instantiate [class@Collection] objects which
56 : : * represent those collections while initializing a #SecretService then pass
57 : : * the %SECRET_SERVICE_LOAD_COLLECTIONS flag to the [func@Service.get] or
58 : : * [func@Service.open] functions. In order to establish a session on an already
59 : : * existing #SecretService, use the [method@Service.load_collections] function.
60 : : * To access the list of collections use [method@Service.get_collections].
61 : : *
62 : : * Certain actions on the Secret Service require user prompting to complete,
63 : : * such as creating a collection, or unlocking a collection. When such a prompt
64 : : * is necessary, then a [class@Prompt] object is created by this library, and
65 : : * passed to the [method@Service.prompt] method. In this way it is handled
66 : : * automatically.
67 : : *
68 : : * In order to customize prompt handling, override the
69 : : * [vfunc@Service.prompt_async] and [vfunc@Service.prompt_finish] virtual
70 : : * methods of the #SecretService class.
71 : : *
72 : : * Stability: Stable
73 : : */
74 : :
75 : : /**
76 : : * SecretServiceClass:
77 : : * @parent_class: the parent class
78 : : * @collection_gtype: the [alias@GLib.Type] of the [class@Collection] objects instantiated
79 : : * by the #SecretService proxy
80 : : * @item_gtype: the [alias@GLib.Type] of the [class@Item] objects instantiated by the
81 : : * #SecretService proxy
82 : : * @prompt_async: called to perform asynchronous prompting when necessary
83 : : * @prompt_finish: called to complete an asynchronous prompt operation
84 : : * @prompt_sync: called to perform synchronous prompting when necessary
85 : : * @get_collection_gtype: called to get the GObject type for collections
86 : : * instantiated by the #SecretService proxy
87 : : * @get_item_gtype: called to get the GObject type for collections
88 : : * instantiated by the #SecretService proxy
89 : : *
90 : : * The class for #SecretService.
91 : : */
92 : :
93 : : /**
94 : : * SecretServiceFlags:
95 : : * @SECRET_SERVICE_NONE: no flags for initializing the #SecretService
96 : : * @SECRET_SERVICE_OPEN_SESSION: establish a session for transfer of secrets
97 : : * while initializing the #SecretService
98 : : * @SECRET_SERVICE_LOAD_COLLECTIONS: load collections while initializing the
99 : : * #SecretService
100 : : *
101 : : * Flags which determine which parts of the #SecretService proxy are initialized
102 : : * during a [func@Service.get] or [func@Service.open] operation.
103 : : */
104 : :
105 : 7614934 : EGG_SECURE_DEFINE_GLIB_GLOBALS ();
106 : :
107 : : GQuark _secret_error_quark = 0;
108 : :
109 : : enum {
110 : : PROP_0,
111 : : PROP_FLAGS,
112 : : PROP_COLLECTIONS
113 : : };
114 : :
115 : : struct _SecretServicePrivate {
116 : : /* No change between construct and finalize */
117 : : GCancellable *cancellable;
118 : : SecretServiceFlags init_flags;
119 : :
120 : : /* Locked by mutex */
121 : : GMutex mutex;
122 : : gpointer session;
123 : : GHashTable *collections;
124 : : };
125 : :
126 : : G_LOCK_DEFINE (service_instance);
127 : : static gpointer service_instance = NULL;
128 : : static guint service_watch = 0;
129 : :
130 : : static GInitableIface *secret_service_initable_parent_iface = NULL;
131 : :
132 : : static GAsyncInitableIface *secret_service_async_initable_parent_iface = NULL;
133 : :
134 : : static SecretBackendInterface *secret_service_backend_parent_iface = NULL;
135 : :
136 : : static void secret_service_initable_iface (GInitableIface *iface);
137 : :
138 : : static void secret_service_async_initable_iface (GAsyncInitableIface *iface);
139 : :
140 : : static void secret_service_backend_iface (SecretBackendInterface *iface);
141 : :
142 [ + + + - : 3015 : G_DEFINE_TYPE_WITH_CODE (SecretService, secret_service, G_TYPE_DBUS_PROXY,
+ + ]
143 : : G_ADD_PRIVATE (SecretService)
144 : : G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_service_initable_iface);
145 : : G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_service_async_initable_iface);
146 : : G_IMPLEMENT_INTERFACE (SECRET_TYPE_BACKEND, secret_service_backend_iface);
147 : : _secret_backend_ensure_extension_point ();
148 : : g_io_extension_point_implement (SECRET_BACKEND_EXTENSION_POINT_NAME,
149 : : g_define_type_id,
150 : : "service",
151 : : 0)
152 : : );
153 : :
154 : : static SecretService *
155 : 125 : service_get_instance (void)
156 : : {
157 : 125 : SecretService *instance = NULL;
158 : :
159 : 125 : G_LOCK (service_instance);
160 [ + + ]: 125 : if (service_instance != NULL)
161 : 4 : instance = g_object_ref (service_instance);
162 : 125 : G_UNLOCK (service_instance);
163 : :
164 : 125 : return instance;
165 : : }
166 : :
167 : : static gboolean
168 : 200 : service_uncache_instance (SecretService *which)
169 : : {
170 : 200 : SecretService *instance = NULL;
171 : 200 : guint watch = 0;
172 : 200 : gboolean matched = FALSE;
173 : :
174 : 200 : G_LOCK (service_instance);
175 [ - + - - ]: 200 : if (which == NULL || service_instance == which) {
176 : 200 : instance = service_instance;
177 : 200 : service_instance = NULL;
178 : 200 : watch = service_watch;
179 : 200 : service_watch = 0;
180 : 200 : matched = TRUE;
181 : : }
182 : 200 : G_UNLOCK (service_instance);
183 : :
184 [ + + ]: 200 : if (instance != NULL)
185 : 121 : g_object_unref (instance);
186 [ + + ]: 200 : if (watch != 0)
187 : 121 : g_bus_unwatch_name (watch);
188 : :
189 : 200 : _secret_backend_uncache_instance ();
190 : :
191 : 200 : return matched;
192 : : }
193 : :
194 : : static void
195 : 0 : on_service_instance_vanished (GDBusConnection *connection,
196 : : const gchar *name,
197 : : gpointer user_data)
198 : : {
199 [ # # ]: 0 : if (!service_uncache_instance (user_data)) {
200 : 0 : g_warning ("Global default SecretService instance out of sync "
201 : : "with the watch for its DBus name");
202 : : }
203 : 0 : }
204 : :
205 : : static void
206 : 121 : service_cache_instance (SecretService *instance)
207 : : {
208 : : GDBusProxy *proxy;
209 : : guint watch;
210 : :
211 : 121 : g_object_ref (instance);
212 : 121 : proxy = G_DBUS_PROXY (instance);
213 : 121 : watch = g_bus_watch_name_on_connection (g_dbus_proxy_get_connection (proxy),
214 : : g_dbus_proxy_get_name (proxy),
215 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
216 : : NULL, on_service_instance_vanished,
217 : : instance, NULL);
218 : :
219 : 121 : G_LOCK (service_instance);
220 [ + - ]: 121 : if (service_instance == NULL) {
221 : 121 : service_instance = instance;
222 : 121 : instance = NULL;
223 : 121 : service_watch = watch;
224 : 121 : watch = 0;
225 : : }
226 : 121 : G_UNLOCK (service_instance);
227 : :
228 [ - + ]: 121 : if (instance != NULL)
229 : 0 : g_object_unref (instance);
230 [ - + ]: 121 : if (watch != 0)
231 : 0 : g_bus_unwatch_name (watch);
232 : 121 : }
233 : :
234 : : static void
235 : 156 : secret_service_init (SecretService *self)
236 : : {
237 : 156 : self->pv = secret_service_get_instance_private (self);
238 : :
239 : 156 : g_mutex_init (&self->pv->mutex);
240 : 156 : self->pv->cancellable = g_cancellable_new ();
241 : 156 : }
242 : :
243 : : static void
244 : 2 : secret_service_get_property (GObject *obj,
245 : : guint prop_id,
246 : : GValue *value,
247 : : GParamSpec *pspec)
248 : : {
249 : 2 : SecretService *self = SECRET_SERVICE (obj);
250 : :
251 [ + - - ]: 2 : switch (prop_id) {
252 : 2 : case PROP_FLAGS:
253 : 2 : g_value_set_flags (value, secret_service_get_flags (self));
254 : 2 : break;
255 : 0 : case PROP_COLLECTIONS:
256 : 0 : g_value_take_boxed (value, secret_service_get_collections (self));
257 : 0 : break;
258 : 0 : default:
259 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
260 : 0 : break;
261 : : }
262 : 2 : }
263 : :
264 : : static void
265 : 156 : secret_service_set_property (GObject *obj,
266 : : guint prop_id,
267 : : const GValue *value,
268 : : GParamSpec *pspec)
269 : : {
270 : 156 : SecretService *self = SECRET_SERVICE (obj);
271 : :
272 [ + - ]: 156 : switch (prop_id) {
273 : 156 : case PROP_FLAGS:
274 : 156 : self->pv->init_flags = g_value_get_flags (value);
275 : 156 : break;
276 : 0 : default:
277 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
278 : 0 : break;
279 : : }
280 : 156 : }
281 : :
282 : : static void
283 : 144 : secret_service_dispose (GObject *obj)
284 : : {
285 : 144 : SecretService *self = SECRET_SERVICE (obj);
286 : :
287 : 144 : g_cancellable_cancel (self->pv->cancellable);
288 : :
289 : 144 : G_OBJECT_CLASS (secret_service_parent_class)->dispose (obj);
290 : 144 : }
291 : :
292 : : static void
293 : 144 : secret_service_finalize (GObject *obj)
294 : : {
295 : 144 : SecretService *self = SECRET_SERVICE (obj);
296 : :
297 : 144 : _secret_session_free (self->pv->session);
298 [ + + ]: 144 : if (self->pv->collections)
299 : 8 : g_hash_table_destroy (self->pv->collections);
300 [ + - ]: 144 : g_clear_object (&self->pv->cancellable);
301 : 144 : g_mutex_clear (&self->pv->mutex);
302 : :
303 : 144 : G_OBJECT_CLASS (secret_service_parent_class)->finalize (obj);
304 : 144 : }
305 : :
306 : : static GVariant *
307 : 1 : secret_service_real_prompt_sync (SecretService *self,
308 : : SecretPrompt *prompt,
309 : : GCancellable *cancellable,
310 : : const GVariantType *return_type,
311 : : GError **error)
312 : : {
313 : 1 : return secret_prompt_perform_sync (prompt, NULL, cancellable, return_type, error);
314 : : }
315 : :
316 : : static void
317 : 10 : on_real_prompt_completed (GObject *source,
318 : : GAsyncResult *result,
319 : : gpointer user_data)
320 : : {
321 : 10 : GTask *task = G_TASK (user_data);
322 : 10 : GError *error = NULL;
323 : : GVariant *retval;
324 : :
325 : 10 : retval = secret_prompt_perform_finish (SECRET_PROMPT (source),
326 : : result,
327 : : &error);
328 [ + + ]: 10 : if (retval != NULL)
329 : 9 : g_task_return_pointer (task,
330 : : g_steal_pointer (&retval),
331 : : (GDestroyNotify) g_variant_unref);
332 : : else
333 : 1 : g_task_return_error (task, g_steal_pointer (&error));
334 : :
335 : 10 : g_object_unref (task);
336 : 10 : }
337 : :
338 : : static void
339 : 10 : secret_service_real_prompt_async (SecretService *self,
340 : : SecretPrompt *prompt,
341 : : const GVariantType *return_type,
342 : : GCancellable *cancellable,
343 : : GAsyncReadyCallback callback,
344 : : gpointer user_data)
345 : : {
346 : : GTask *task;
347 : :
348 : 10 : task = g_task_new (self, cancellable, callback, user_data);
349 [ + - ]: 10 : g_task_set_source_tag (task, secret_service_real_prompt_async);
350 : :
351 : 10 : secret_prompt_perform (prompt, 0, return_type, cancellable,
352 : : on_real_prompt_completed,
353 : : g_object_ref (task));
354 : :
355 : 10 : g_object_unref (task);
356 : 10 : }
357 : :
358 : : static GVariant *
359 : 10 : secret_service_real_prompt_finish (SecretService *self,
360 : : GAsyncResult *result,
361 : : GError **error)
362 : : {
363 : : GVariant *retval;
364 : :
365 [ - + ]: 10 : g_return_val_if_fail (g_task_is_valid (result, self), NULL);
366 [ - + ]: 10 : g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
367 : : secret_service_real_prompt_async, NULL);
368 : :
369 : 10 : retval = g_task_propagate_pointer (G_TASK (result), error);
370 [ + + ]: 10 : if (!retval) {
371 : 1 : _secret_util_strip_remote_error (error);
372 : 1 : return NULL;
373 : : }
374 : :
375 : 9 : return retval;
376 : : }
377 : :
378 : : static void
379 : 156 : handle_property_changed (SecretService *self,
380 : : const gchar *property_name,
381 : : GVariant *value)
382 : : {
383 : : gboolean perform;
384 : :
385 : 156 : g_variant_ref_sink (value);
386 : :
387 [ + - ]: 156 : if (g_str_equal (property_name, "Collections")) {
388 : :
389 : 156 : g_mutex_lock (&self->pv->mutex);
390 : 156 : perform = self->pv->collections != NULL;
391 : 156 : g_mutex_unlock (&self->pv->mutex);
392 : :
393 [ - + ]: 156 : if (perform)
394 : 0 : secret_service_load_collections (self, self->pv->cancellable, NULL, NULL);
395 : : }
396 : :
397 : 156 : g_variant_unref (value);
398 : 156 : }
399 : :
400 : : static void
401 : 158 : secret_service_properties_changed (GDBusProxy *proxy,
402 : : GVariant *changed_properties,
403 : : const gchar* const *invalidated_properties)
404 : : {
405 : 158 : SecretService *self = SECRET_SERVICE (proxy);
406 : : gchar *property_name;
407 : : GVariantIter iter;
408 : : GVariant *value;
409 : :
410 : 158 : g_object_freeze_notify (G_OBJECT (self));
411 : :
412 : 158 : g_variant_iter_init (&iter, changed_properties);
413 [ + + ]: 314 : while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value))
414 : 156 : handle_property_changed (self, property_name, value);
415 : :
416 : 158 : g_object_thaw_notify (G_OBJECT (self));
417 : 158 : }
418 : :
419 : : static void
420 : 0 : secret_service_signal (GDBusProxy *proxy,
421 : : const gchar *sender_name,
422 : : const gchar *signal_name,
423 : : GVariant *parameters)
424 : : {
425 : 0 : SecretService *self = SECRET_SERVICE (proxy);
426 : : SecretCollection *collection;
427 : : const gchar *collection_path;
428 : : GVariantBuilder builder;
429 : 0 : gboolean found = FALSE;
430 : : GVariantIter iter;
431 : : GVariant *value;
432 : : GVariant *paths;
433 : : GVariant *path;
434 : :
435 : : /*
436 : : * Remember that these signals come from a time before PropertiesChanged.
437 : : * We support them because they're in the spec, and ksecretservice uses them.
438 : : */
439 : :
440 : 0 : paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
441 : :
442 : : /* A new collection was added, add it to the Collections property */
443 [ # # ]: 0 : if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CREATED)) {
444 : 0 : g_variant_get (parameters, "(@o)", &value);
445 : 0 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
446 : 0 : g_variant_iter_init (&iter, paths);
447 [ # # ]: 0 : while ((path = g_variant_iter_next_value (&iter)) != NULL) {
448 [ # # ]: 0 : if (g_variant_equal (path, value)) {
449 : 0 : found = TRUE;
450 : 0 : break;
451 : : }
452 : 0 : g_variant_builder_add_value (&builder, path);
453 : 0 : g_variant_unref (path);
454 : : }
455 [ # # ]: 0 : if (!found) {
456 : 0 : g_variant_builder_add_value (&builder, value);
457 : 0 : handle_property_changed (self, "Collections", g_variant_builder_end (&builder));
458 : : }
459 : 0 : g_variant_builder_clear (&builder);
460 : 0 : g_variant_unref (value);
461 : :
462 : : /* A collection was deleted, remove it from the Collections property */
463 [ # # ]: 0 : } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_DELETED)) {
464 : 0 : g_variant_get (parameters, "(@o)", &value);
465 : 0 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
466 : 0 : g_variant_iter_init (&iter, paths);
467 [ # # ]: 0 : while ((path = g_variant_iter_next_value (&iter)) != NULL) {
468 [ # # ]: 0 : if (g_variant_equal (path, value))
469 : 0 : found = TRUE;
470 : : else
471 : 0 : g_variant_builder_add_value (&builder, path);
472 : 0 : g_variant_unref (path);
473 : : }
474 [ # # ]: 0 : if (found)
475 : 0 : handle_property_changed (self, "Collections", g_variant_builder_end (&builder));
476 : 0 : g_variant_unref (value);
477 : :
478 : : /* The collection changed, update it */
479 [ # # ]: 0 : } else if (g_str_equal (signal_name, SECRET_SIGNAL_COLLECTION_CHANGED)) {
480 : 0 : g_variant_get (parameters, "(&o)", &collection_path);
481 : :
482 : 0 : g_mutex_lock (&self->pv->mutex);
483 : :
484 [ # # ]: 0 : if (self->pv->collections)
485 : 0 : collection = g_hash_table_lookup (self->pv->collections, collection_path);
486 : : else
487 : 0 : collection = NULL;
488 [ # # ]: 0 : if (collection)
489 : 0 : g_object_ref (collection);
490 : :
491 : 0 : g_mutex_unlock (&self->pv->mutex);
492 : :
493 [ # # ]: 0 : if (collection) {
494 : 0 : secret_collection_refresh (collection);
495 : 0 : g_object_unref (collection);
496 : : }
497 : : }
498 : :
499 : 0 : g_variant_unref (paths);
500 : 0 : }
501 : :
502 : : static GType
503 : 75 : secret_service_real_get_collection_gtype (SecretService *self)
504 : : {
505 : : SecretServiceClass *klass;
506 : :
507 : 75 : klass = SECRET_SERVICE_GET_CLASS (self);
508 : 75 : return klass->collection_gtype;
509 : : }
510 : :
511 : : static GType
512 : 144 : secret_service_real_get_item_gtype (SecretService *self)
513 : : {
514 : : SecretServiceClass *klass;
515 : :
516 : 144 : klass = SECRET_SERVICE_GET_CLASS (self);
517 : 144 : return klass->item_gtype;
518 : : }
519 : :
520 : : static const gchar *
521 : 156 : get_default_bus_name (void)
522 : : {
523 : : const gchar *bus_name;
524 : :
525 : 156 : bus_name = g_getenv ("SECRET_SERVICE_BUS_NAME");
526 [ - + ]: 156 : if (bus_name == NULL)
527 : 0 : bus_name = SECRET_SERVICE_BUS_NAME;
528 : :
529 : 156 : return bus_name;
530 : : }
531 : :
532 : : static GObject *
533 : 156 : secret_service_constructor (GType type,
534 : : guint n_construct_properties,
535 : : GObjectConstructParam *construct_properties)
536 : : {
537 : : GObject *object;
538 : :
539 : 156 : object = G_OBJECT_CLASS (secret_service_parent_class)->
540 : : constructor (type, n_construct_properties, construct_properties);
541 : 156 : g_object_set (object,
542 : : "g-flags", G_DBUS_PROXY_FLAGS_NONE,
543 : : "g-interface-info", _secret_gen_service_interface_info (),
544 : : "g-name", get_default_bus_name (),
545 : : "g-bus-type", G_BUS_TYPE_SESSION,
546 : : "g-object-path", SECRET_SERVICE_PATH,
547 : : "g-interface-name", SECRET_SERVICE_INTERFACE,
548 : : NULL);
549 : 156 : return object;
550 : : }
551 : :
552 : : static void
553 : 12 : secret_service_class_init (SecretServiceClass *klass)
554 : : {
555 : 12 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
556 : 12 : GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass);
557 : :
558 : 12 : object_class->get_property = secret_service_get_property;
559 : 12 : object_class->set_property = secret_service_set_property;
560 : 12 : object_class->dispose = secret_service_dispose;
561 : 12 : object_class->finalize = secret_service_finalize;
562 : 12 : object_class->constructor = secret_service_constructor;
563 : :
564 : 12 : proxy_class->g_properties_changed = secret_service_properties_changed;
565 : 12 : proxy_class->g_signal = secret_service_signal;
566 : :
567 : 12 : klass->prompt_sync = secret_service_real_prompt_sync;
568 : 12 : klass->prompt_async = secret_service_real_prompt_async;
569 : 12 : klass->prompt_finish = secret_service_real_prompt_finish;
570 : :
571 : 12 : klass->item_gtype = SECRET_TYPE_ITEM;
572 : 12 : klass->collection_gtype = SECRET_TYPE_COLLECTION;
573 : 12 : klass->get_item_gtype = secret_service_real_get_item_gtype;
574 : 12 : klass->get_collection_gtype = secret_service_real_get_collection_gtype;
575 : :
576 : : /**
577 : : * SecretService:flags:
578 : : *
579 : : * A set of flags describing which parts of the secret service have
580 : : * been initialized.
581 : : */
582 : 12 : g_object_class_override_property (object_class, PROP_FLAGS, "flags");
583 : :
584 : : /**
585 : : * SecretService:collections: (attributes org.gtk.Property.get=secret_service_get_collections)
586 : : *
587 : : * A list of [class@Collection] objects representing the collections in
588 : : * the Secret Service.
589 : : *
590 : : * This list may be %NULL if the collections have not been loaded.
591 : : *
592 : : * To load the collections, specify the %SECRET_SERVICE_LOAD_COLLECTIONS
593 : : * initialization flag when calling the [func@Service.get] or
594 : : * [func@Service.open] functions. Or call the [method@Service.load_collections]
595 : : * method.
596 : : */
597 : 12 : g_object_class_install_property (object_class, PROP_COLLECTIONS,
598 : : g_param_spec_boxed ("collections", "Collections", "Secret Service Collections",
599 : : _secret_list_get_type (), G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
600 : :
601 : : /* Initialize this error domain, registers dbus errors */
602 : 12 : _secret_error_quark = secret_error_get_quark ();
603 : 12 : }
604 : :
605 : : typedef struct {
606 : : SecretServiceFlags flags;
607 : : } InitClosure;
608 : :
609 : : static void
610 : 49 : init_closure_free (gpointer data)
611 : : {
612 : 49 : InitClosure *closure = data;
613 : 49 : g_free (closure);
614 : 49 : }
615 : :
616 : : static gboolean
617 : 125 : service_ensure_for_flags_sync (SecretService *self,
618 : : SecretServiceFlags flags,
619 : : GCancellable *cancellable,
620 : : GError **error)
621 : : {
622 [ + + ]: 125 : if (flags & SECRET_SERVICE_OPEN_SESSION)
623 [ - + ]: 2 : if (!secret_service_ensure_session_sync (self, cancellable, error))
624 : 0 : return FALSE;
625 : :
626 [ + + ]: 125 : if (flags & SECRET_SERVICE_LOAD_COLLECTIONS)
627 [ - + ]: 2 : if (!secret_service_load_collections_sync (self, cancellable, error))
628 : 0 : return FALSE;
629 : :
630 : 125 : return TRUE;
631 : : }
632 : :
633 : : static void
634 : 4 : on_load_collections (GObject *source,
635 : : GAsyncResult *result,
636 : : gpointer user_data)
637 : : {
638 : 4 : GTask *task = G_TASK (user_data);
639 : 4 : SecretService *self = SECRET_SERVICE (source);
640 : 4 : GError *error = NULL;
641 : :
642 [ - + ]: 4 : if (!secret_service_load_collections_finish (self, result, &error))
643 : 0 : g_task_return_error (task, g_steal_pointer (&error));
644 : : else
645 : 4 : g_task_return_boolean (task, TRUE);
646 : :
647 : 4 : g_object_unref (task);
648 : 4 : }
649 : :
650 : : static void
651 : 29 : on_ensure_session (GObject *source,
652 : : GAsyncResult *result,
653 : : gpointer user_data)
654 : : {
655 : 29 : GTask *task = G_TASK (user_data);
656 : 29 : InitClosure *closure = g_task_get_task_data (task);
657 : 29 : SecretService *self = SECRET_SERVICE (source);
658 : 29 : GError *error = NULL;
659 : :
660 [ - + ]: 29 : if (!secret_service_ensure_session_finish (self, result, &error)) {
661 : 0 : g_task_return_error (task, g_steal_pointer (&error));
662 : :
663 [ + + ]: 29 : } else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS) {
664 : 2 : secret_service_load_collections (self, g_task_get_cancellable (task),
665 : : on_load_collections,
666 : : g_object_ref (task));
667 : :
668 : : } else {
669 : 27 : g_task_return_boolean (task, TRUE);
670 : : }
671 : :
672 : 29 : g_object_unref (task);
673 : 29 : }
674 : :
675 : : static void
676 : 49 : service_ensure_for_flags_async (SecretService *self,
677 : : SecretServiceFlags flags,
678 : : GTask *task)
679 : : {
680 : 49 : InitClosure *closure = g_task_get_task_data (task);
681 : :
682 : 49 : closure->flags = flags;
683 : :
684 [ + + ]: 49 : if (closure->flags & SECRET_SERVICE_OPEN_SESSION)
685 : 29 : secret_service_ensure_session (self, g_task_get_cancellable (task),
686 : : on_ensure_session,
687 : : g_object_ref (task));
688 : :
689 [ + + ]: 20 : else if (closure->flags & SECRET_SERVICE_LOAD_COLLECTIONS)
690 : 2 : secret_service_load_collections (self, g_task_get_cancellable (task),
691 : : on_load_collections,
692 : : g_object_ref (task));
693 : :
694 : : else
695 : 18 : g_task_return_boolean (task, TRUE);
696 : 49 : }
697 : :
698 : : static gboolean
699 : 122 : secret_service_initable_init (GInitable *initable,
700 : : GCancellable *cancellable,
701 : : GError **error)
702 : : {
703 : : SecretService *self;
704 : :
705 [ - + ]: 122 : if (!secret_service_initable_parent_iface->init (initable, cancellable, error))
706 : 0 : return FALSE;
707 : :
708 : 122 : self = SECRET_SERVICE (initable);
709 : 122 : return service_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error);
710 : : }
711 : :
712 : : static void
713 : 12 : secret_service_initable_iface (GInitableIface *iface)
714 : : {
715 : 12 : secret_service_initable_parent_iface = g_type_interface_peek_parent (iface);
716 : :
717 : 12 : iface->init = secret_service_initable_init;
718 : 12 : }
719 : :
720 : : static void
721 : : secret_service_async_initable_init_async (GAsyncInitable *initable,
722 : : int io_priority,
723 : : GCancellable *cancellable,
724 : : GAsyncReadyCallback callback,
725 : : gpointer user_data);
726 : :
727 : : typedef struct {
728 : : GAsyncReadyCallback callback;
729 : : gpointer user_data;
730 : : } InitBaseClosure;
731 : :
732 : : static void
733 : 34 : on_init_base (GObject *source,
734 : : GAsyncResult *result,
735 : : gpointer user_data)
736 : : {
737 : 34 : GTask *base_task = G_TASK (user_data);
738 : 34 : InitBaseClosure *base = g_task_get_task_data (base_task);
739 : 34 : GCancellable *cancellable = g_task_get_cancellable (base_task);
740 : : GTask *task;
741 : : InitClosure *init;
742 : 34 : SecretService *self = SECRET_SERVICE (source);
743 : 34 : GError *error = NULL;
744 : :
745 : 34 : task = g_task_new (source, cancellable, base->callback, base->user_data);
746 [ + - ]: 34 : g_task_set_source_tag (task, secret_service_async_initable_init_async);
747 : 34 : init = g_new0 (InitClosure, 1);
748 : 34 : g_task_set_task_data (task, init, init_closure_free);
749 : :
750 [ + - ]: 34 : g_clear_object (&base_task);
751 : :
752 [ - + ]: 34 : if (!secret_service_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self),
753 : : result, &error)) {
754 : 0 : g_task_return_error (task, g_steal_pointer (&error));
755 : : } else {
756 : 34 : service_ensure_for_flags_async (self, self->pv->init_flags, task);
757 : : }
758 : :
759 : 34 : g_object_unref (task);
760 : 34 : }
761 : :
762 : : static void
763 : 34 : secret_service_async_initable_init_async (GAsyncInitable *initable,
764 : : int io_priority,
765 : : GCancellable *cancellable,
766 : : GAsyncReadyCallback callback,
767 : : gpointer user_data)
768 : : {
769 : : GTask *task;
770 : : InitBaseClosure *base;
771 : :
772 : 34 : task = g_task_new (initable, cancellable, NULL, NULL);
773 [ + - ]: 34 : g_task_set_source_tag (task, secret_service_async_initable_init_async);
774 : 34 : base = g_new0 (InitBaseClosure, 1);
775 : 34 : base->callback = callback;
776 : 34 : base->user_data = user_data;
777 : 34 : g_task_set_task_data (task, base, g_free);
778 : :
779 : 34 : secret_service_async_initable_parent_iface->init_async (initable,
780 : : io_priority,
781 : : cancellable,
782 : : on_init_base,
783 : : g_object_ref (task));
784 : :
785 : 34 : g_object_unref (task);
786 : 34 : }
787 : :
788 : : static gboolean
789 : 34 : secret_service_async_initable_init_finish (GAsyncInitable *initable,
790 : : GAsyncResult *result,
791 : : GError **error)
792 : : {
793 [ - + ]: 34 : g_return_val_if_fail (g_task_is_valid (result, initable), FALSE);
794 : :
795 [ - + ]: 34 : if (!g_task_propagate_boolean (G_TASK (result), error)) {
796 : 0 : _secret_util_strip_remote_error (error);
797 : 0 : return FALSE;
798 : : }
799 : :
800 : 34 : return TRUE;
801 : : }
802 : :
803 : : static void
804 : 12 : secret_service_async_initable_iface (GAsyncInitableIface *iface)
805 : : {
806 : 12 : secret_service_async_initable_parent_iface = g_type_interface_peek_parent (iface);
807 : :
808 : 12 : iface->init_async = secret_service_async_initable_init_async;
809 : 12 : iface->init_finish = secret_service_async_initable_init_finish;
810 : 12 : }
811 : :
812 : : static void
813 : 14 : secret_service_real_ensure_for_flags (SecretBackend *self,
814 : : SecretBackendFlags flags,
815 : : GCancellable *cancellable,
816 : : GAsyncReadyCallback callback,
817 : : gpointer user_data)
818 : : {
819 : : GTask *task;
820 : : InitClosure *closure;
821 : :
822 [ - + + - : 14 : g_return_if_fail (SECRET_IS_SERVICE (self));
+ - - + ]
823 : :
824 : 14 : task = g_task_new (self, cancellable, callback, user_data);
825 : 14 : closure = g_new0 (InitClosure, 1);
826 : 14 : g_task_set_task_data (task, closure, init_closure_free);
827 : 14 : service_ensure_for_flags_async (SECRET_SERVICE (self), flags, task);
828 : 14 : g_object_unref (task);
829 : : }
830 : :
831 : : static gboolean
832 : 14 : secret_service_real_ensure_for_flags_finish (SecretBackend *self,
833 : : GAsyncResult *result,
834 : : GError **error)
835 : : {
836 [ - + ]: 14 : g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
837 : :
838 [ - + ]: 14 : if (!g_task_propagate_boolean (G_TASK (result), error)) {
839 : 0 : _secret_util_strip_remote_error (error);
840 : 0 : return FALSE;
841 : : }
842 : :
843 : 14 : return TRUE;
844 : : }
845 : :
846 : : static void
847 : 7 : secret_service_real_store (SecretBackend *self,
848 : : const SecretSchema *schema,
849 : : GHashTable *attributes,
850 : : const gchar *collection,
851 : : const gchar *label,
852 : : SecretValue *value,
853 : : GCancellable *cancellable,
854 : : GAsyncReadyCallback callback,
855 : : gpointer user_data)
856 : : {
857 [ - + + - : 7 : g_return_if_fail (SECRET_IS_SERVICE (self));
+ - - + ]
858 : :
859 : 7 : secret_service_store (SECRET_SERVICE (self), schema, attributes,
860 : : collection, label, value,
861 : : cancellable, callback, user_data);
862 : : }
863 : :
864 : : static gboolean
865 : 7 : secret_service_real_store_finish (SecretBackend *self,
866 : : GAsyncResult *result,
867 : : GError **error)
868 : : {
869 [ - + + - : 7 : g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+ - - + ]
870 : :
871 : 7 : return secret_service_store_finish (SECRET_SERVICE (self),
872 : : result, error);
873 : : }
874 : :
875 : : static void
876 : 19 : secret_service_real_lookup (SecretBackend *self,
877 : : const SecretSchema *schema,
878 : : GHashTable *attributes,
879 : : GCancellable *cancellable,
880 : : GAsyncReadyCallback callback,
881 : : gpointer user_data)
882 : : {
883 [ - + + - : 19 : g_return_if_fail (SECRET_IS_SERVICE (self));
+ - - + ]
884 : :
885 : 19 : secret_service_lookup (SECRET_SERVICE (self), schema, attributes,
886 : : cancellable, callback, user_data);
887 : : }
888 : :
889 : : static SecretValue *
890 : 19 : secret_service_real_lookup_finish (SecretBackend *self,
891 : : GAsyncResult *result,
892 : : GError **error)
893 : : {
894 [ - + + - : 19 : g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+ - - + ]
895 : :
896 : 19 : return secret_service_lookup_finish (SECRET_SERVICE (self),
897 : : result, error);
898 : : }
899 : :
900 : : static void
901 : 8 : secret_service_real_clear (SecretBackend *self,
902 : : const SecretSchema *schema,
903 : : GHashTable *attributes,
904 : : GCancellable *cancellable,
905 : : GAsyncReadyCallback callback,
906 : : gpointer user_data)
907 : : {
908 [ - + + - : 8 : g_return_if_fail (SECRET_IS_SERVICE (self));
+ - - + ]
909 : :
910 : 8 : secret_service_clear (SECRET_SERVICE (self), schema, attributes,
911 : : cancellable, callback, user_data);
912 : : }
913 : :
914 : : static gboolean
915 : 8 : secret_service_real_clear_finish (SecretBackend *self,
916 : : GAsyncResult *result,
917 : : GError **error)
918 : : {
919 [ - + + - : 8 : g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+ - - + ]
920 : :
921 : 8 : return secret_service_clear_finish (SECRET_SERVICE (self),
922 : : result, error);
923 : : }
924 : :
925 : : static void
926 : 4 : secret_service_real_search (SecretBackend *self,
927 : : const SecretSchema *schema,
928 : : GHashTable *attributes,
929 : : SecretSearchFlags flags,
930 : : GCancellable *cancellable,
931 : : GAsyncReadyCallback callback,
932 : : gpointer user_data)
933 : : {
934 [ - + + - : 4 : g_return_if_fail (SECRET_IS_SERVICE (self));
+ - - + ]
935 : :
936 : 4 : secret_service_search (SECRET_SERVICE (self), schema, attributes, flags,
937 : : cancellable, callback, user_data);
938 : : }
939 : :
940 : : static GList *
941 : 4 : secret_service_real_search_finish (SecretBackend *self,
942 : : GAsyncResult *result,
943 : : GError **error)
944 : : {
945 [ - + + - : 4 : g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+ - - + ]
946 : :
947 : 4 : return secret_service_search_finish (SECRET_SERVICE (self),
948 : : result, error);
949 : : }
950 : :
951 : : static void
952 : 12 : secret_service_backend_iface (SecretBackendInterface *iface)
953 : : {
954 : 12 : secret_service_backend_parent_iface = g_type_interface_peek_parent (iface);
955 : :
956 : 12 : iface->ensure_for_flags = secret_service_real_ensure_for_flags;
957 : 12 : iface->ensure_for_flags_finish = secret_service_real_ensure_for_flags_finish;
958 : 12 : iface->store = secret_service_real_store;
959 : 12 : iface->store_finish = secret_service_real_store_finish;
960 : 12 : iface->lookup = secret_service_real_lookup;
961 : 12 : iface->lookup_finish = secret_service_real_lookup_finish;
962 : 12 : iface->clear = secret_service_real_clear;
963 : 12 : iface->clear_finish = secret_service_real_clear_finish;
964 : 12 : iface->search = secret_service_real_search;
965 : 12 : iface->search_finish = secret_service_real_search_finish;
966 : 12 : }
967 : :
968 : : /**
969 : : * secret_service_get:
970 : : * @flags: flags for which service functionality to ensure is initialized
971 : : * @cancellable: (nullable): optional cancellation object
972 : : * @callback: called when the operation completes
973 : : * @user_data: data to be passed to the callback
974 : : *
975 : : * Get a #SecretService proxy for the Secret Service.
976 : : *
977 : : * If such a proxy object already exists, then the same proxy is returned.
978 : : *
979 : : * If @flags contains any flags of which parts of the secret service to
980 : : * ensure are initialized, then those will be initialized before completing.
981 : : *
982 : : * This method will return immediately and complete asynchronously.
983 : : */
984 : : void
985 : 7 : secret_service_get (SecretServiceFlags flags,
986 : : GCancellable *cancellable,
987 : : GAsyncReadyCallback callback,
988 : : gpointer user_data)
989 : : {
990 : 7 : SecretService *service = NULL;
991 : : GTask *task;
992 : : InitClosure *closure;
993 : :
994 : 7 : service = service_get_instance ();
995 : :
996 : : /* Create a whole new service */
997 [ + + ]: 7 : if (service == NULL) {
998 : 6 : g_async_initable_new_async (SECRET_TYPE_SERVICE, G_PRIORITY_DEFAULT,
999 : : cancellable, callback, user_data,
1000 : : "flags", flags,
1001 : : NULL);
1002 : :
1003 : : /* Just have to ensure that the service matches flags */
1004 : : } else {
1005 : 1 : task = g_task_new (service, cancellable, callback, user_data);
1006 [ + - ]: 1 : g_task_set_source_tag (task, secret_service_get);
1007 : 1 : closure = g_new0 (InitClosure, 1);
1008 : 1 : closure->flags = flags;
1009 : 1 : g_task_set_task_data (task, closure, init_closure_free);
1010 : :
1011 : 1 : service_ensure_for_flags_async (service, flags, task);
1012 : :
1013 : 1 : g_object_unref (service);
1014 : 1 : g_object_unref (task);
1015 : : }
1016 : 7 : }
1017 : :
1018 : : /**
1019 : : * secret_service_get_finish:
1020 : : * @result: the asynchronous result passed to the callback
1021 : : * @error: location to place an error on failure
1022 : : *
1023 : : * Complete an asynchronous operation to get a #SecretService proxy for the
1024 : : * Secret Service.
1025 : : *
1026 : : * Returns: (transfer full): a new reference to a #SecretService proxy, which
1027 : : * should be released with [method@GObject.Object.unref].
1028 : : */
1029 : : SecretService *
1030 : 7 : secret_service_get_finish (GAsyncResult *result,
1031 : : GError **error)
1032 : : {
1033 : : GTask *task;
1034 : 7 : GObject *service = NULL;
1035 : : GObject *source_object;
1036 : :
1037 [ - + + - : 7 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
- + - + ]
1038 [ + - - + ]: 7 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1039 : :
1040 : 7 : task = G_TASK (result);
1041 : 7 : source_object = g_task_get_source_object (task);
1042 : :
1043 [ - + ]: 7 : g_return_val_if_fail (g_task_is_valid (result, source_object), NULL);
1044 : :
1045 : : /* Just ensuring that the service matches flags */
1046 [ + + ]: 7 : if (g_task_get_source_tag (task) == secret_service_get) {
1047 [ - + ]: 1 : if (g_task_had_error (task)) {
1048 : 0 : g_task_propagate_pointer (task, error);
1049 : 0 : _secret_util_strip_remote_error (error);
1050 : : } else {
1051 : 1 : service = g_object_ref (source_object);
1052 : : }
1053 : :
1054 : : /* Creating a whole new service */
1055 : : } else {
1056 : 6 : service = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
1057 [ + - ]: 6 : if (service)
1058 : 6 : service_cache_instance (SECRET_SERVICE (service));
1059 : : }
1060 : :
1061 [ - + ]: 7 : if (service == NULL)
1062 : 0 : return NULL;
1063 : :
1064 : 7 : return SECRET_SERVICE (service);
1065 : : }
1066 : :
1067 : : /**
1068 : : * secret_service_get_sync:
1069 : : * @flags: flags for which service functionality to ensure is initialized
1070 : : * @cancellable: (nullable): optional cancellation object
1071 : : * @error: location to place an error on failure
1072 : : *
1073 : : * Get a #SecretService proxy for the Secret Service.
1074 : : *
1075 : : * If such a proxy object already exists, then the same proxy is returned.
1076 : : *
1077 : : * If @flags contains any flags of which parts of the secret service to
1078 : : * ensure are initialized, then those will be initialized before returning.
1079 : : *
1080 : : * This method may block indefinitely and should not be used in user interface
1081 : : * threads.
1082 : : *
1083 : : * Returns: (transfer full): a new reference to a #SecretService proxy, which
1084 : : * should be released with [method@GObject.Object.unref].
1085 : : */
1086 : : SecretService *
1087 : 118 : secret_service_get_sync (SecretServiceFlags flags,
1088 : : GCancellable *cancellable,
1089 : : GError **error)
1090 : : {
1091 : 118 : SecretService *service = NULL;
1092 : :
1093 : 118 : service = service_get_instance ();
1094 : :
1095 [ + + ]: 118 : if (service == NULL) {
1096 : 115 : service = g_initable_new (SECRET_TYPE_SERVICE, cancellable, error,
1097 : : "flags", flags,
1098 : : NULL);
1099 : :
1100 [ + - ]: 115 : if (service != NULL)
1101 : 115 : service_cache_instance (service);
1102 : :
1103 : : } else {
1104 [ - + ]: 3 : if (!service_ensure_for_flags_sync (service, flags, cancellable, error)) {
1105 : 0 : g_object_unref (service);
1106 : 0 : return NULL;
1107 : : }
1108 : : }
1109 : :
1110 : 118 : return service;
1111 : : }
1112 : :
1113 : : /**
1114 : : * secret_service_disconnect:
1115 : : *
1116 : : * Disconnect the default #SecretService proxy returned by [func@Service.get]
1117 : : * and [func@Service.get_sync].
1118 : : *
1119 : : * It is not necessary to call this function, but you may choose to do so at
1120 : : * program exit. It is useful for testing that memory is not leaked.
1121 : : *
1122 : : * This function is safe to call at any time. But if other objects in this
1123 : : * library are still referenced, then this will not result in all memory
1124 : : * being freed.
1125 : : */
1126 : : void
1127 : 200 : secret_service_disconnect (void)
1128 : : {
1129 : 200 : service_uncache_instance (NULL);
1130 : 200 : }
1131 : :
1132 : : /**
1133 : : * secret_service_open:
1134 : : * @service_gtype: the GType of the new secret service
1135 : : * @service_bus_name: (nullable): the D-Bus service name of the secret service
1136 : : * @flags: flags for which service functionality to ensure is initialized
1137 : : * @cancellable: (nullable): optional cancellation object
1138 : : * @callback: called when the operation completes
1139 : : * @user_data: data to be passed to the callback
1140 : : *
1141 : : * Create a new #SecretService proxy for the Secret Service.
1142 : : *
1143 : : * This function is rarely used, see [func@Service.get] instead.
1144 : : *
1145 : : * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the type
1146 : : * of a derived class.
1147 : : *
1148 : : * If @flags contains any flags of which parts of the secret service to
1149 : : * ensure are initialized, then those will be initialized before returning.
1150 : : *
1151 : : * If @service_bus_name is %NULL then the default is used.
1152 : : *
1153 : : * This method will return immediately and complete asynchronously.
1154 : : */
1155 : : void
1156 : 4 : secret_service_open (GType service_gtype,
1157 : : const gchar *service_bus_name,
1158 : : SecretServiceFlags flags,
1159 : : GCancellable *cancellable,
1160 : : GAsyncReadyCallback callback,
1161 : : gpointer user_data)
1162 : : {
1163 [ - + - - : 4 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - -
- ]
1164 [ - + - - ]: 4 : g_return_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE));
1165 : :
1166 : 4 : g_async_initable_new_async (service_gtype, G_PRIORITY_DEFAULT,
1167 : : cancellable, callback, user_data,
1168 : : "flags", flags,
1169 : : NULL);
1170 : : }
1171 : :
1172 : : /**
1173 : : * secret_service_open_finish:
1174 : : * @result: the asynchronous result passed to the callback
1175 : : * @error: location to place an error on failure
1176 : : *
1177 : : * Complete an asynchronous operation to create a new #SecretService proxy for
1178 : : * the Secret Service.
1179 : : *
1180 : : * Returns: (transfer full): a new reference to a #SecretService proxy, which
1181 : : * should be released with [method@GObject.Object.unref].
1182 : : */
1183 : : SecretService *
1184 : 4 : secret_service_open_finish (GAsyncResult *result,
1185 : : GError **error)
1186 : : {
1187 : : GObject *source_object;
1188 : : GObject *object;
1189 : :
1190 [ - + + - : 4 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
- + - + ]
1191 [ + - - + ]: 4 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1192 : :
1193 : 4 : source_object = g_async_result_get_source_object (result);
1194 : 4 : object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
1195 : : result, error);
1196 : 4 : g_object_unref (source_object);
1197 : :
1198 [ - + ]: 4 : if (object == NULL)
1199 : 0 : return NULL;
1200 : :
1201 : 4 : return SECRET_SERVICE (object);
1202 : : }
1203 : :
1204 : : /**
1205 : : * secret_service_open_sync:
1206 : : * @service_gtype: the GType of the new secret service
1207 : : * @service_bus_name: (nullable): the D-Bus service name of the secret service
1208 : : * @flags: flags for which service functionality to ensure is initialized
1209 : : * @cancellable: (nullable): optional cancellation object
1210 : : * @error: location to place an error on failure
1211 : : *
1212 : : * Create a new #SecretService proxy for the Secret Service.
1213 : : *
1214 : : * This function is rarely used, see [func@Service.get_sync] instead.
1215 : : *
1216 : : * The @service_gtype argument should be set to %SECRET_TYPE_SERVICE or a the
1217 : : * type of a derived class.
1218 : : *
1219 : : * If @flags contains any flags of which parts of the secret service to
1220 : : * ensure are initialized, then those will be initialized before returning.
1221 : : *
1222 : : * If @service_bus_name is %NULL then the default is used.
1223 : : *
1224 : : * This method may block indefinitely and should not be used in user interface
1225 : : * threads.
1226 : : *
1227 : : * Returns: (transfer full): a new reference to a #SecretService proxy, which
1228 : : * should be released with [method@GObject.Object.unref].
1229 : : */
1230 : : SecretService *
1231 : 7 : secret_service_open_sync (GType service_gtype,
1232 : : const gchar *service_bus_name,
1233 : : SecretServiceFlags flags,
1234 : : GCancellable *cancellable,
1235 : : GError **error)
1236 : : {
1237 [ - + - - : 7 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- - - - -
- ]
1238 [ - + - - ]: 7 : g_return_val_if_fail (g_type_is_a (service_gtype, SECRET_TYPE_SERVICE), NULL);
1239 : :
1240 : 7 : return g_initable_new (service_gtype, cancellable, error,
1241 : : "flags", flags,
1242 : : NULL);
1243 : : }
1244 : :
1245 : : /**
1246 : : * secret_service_get_flags:
1247 : : * @self: the secret service proxy
1248 : : *
1249 : : * Get the flags representing what features of the #SecretService proxy
1250 : : * have been initialized.
1251 : : *
1252 : : * Use [method@Service.ensure_session] or [method@Service.load_collections]
1253 : : * to initialize further features and change the flags.
1254 : : *
1255 : : * Returns: the flags for features initialized
1256 : : */
1257 : : SecretServiceFlags
1258 : 16 : secret_service_get_flags (SecretService *self)
1259 : : {
1260 : 16 : SecretServiceFlags flags = 0;
1261 : :
1262 [ - + + - : 16 : g_return_val_if_fail (SECRET_IS_SERVICE (self), SECRET_SERVICE_NONE);
+ - - + ]
1263 : :
1264 : 16 : g_mutex_lock (&self->pv->mutex);
1265 : :
1266 [ + + ]: 16 : if (self->pv->session)
1267 : 6 : flags |= SECRET_SERVICE_OPEN_SESSION;
1268 [ + + ]: 16 : if (self->pv->collections)
1269 : 11 : flags |= SECRET_SERVICE_LOAD_COLLECTIONS;
1270 : :
1271 : 16 : g_mutex_unlock (&self->pv->mutex);
1272 : :
1273 : 16 : return flags;
1274 : : }
1275 : :
1276 : : /**
1277 : : * secret_service_get_collections: (attributes org.gtk.Method.get_property=collections)
1278 : : * @self: the secret service proxy
1279 : : *
1280 : : * Get a list of [class@Collection] objects representing all the collections
1281 : : * in the secret service.
1282 : : *
1283 : : * If the %SECRET_SERVICE_LOAD_COLLECTIONS flag was not specified when
1284 : : * initializing #SecretService proxy object, then this method will return
1285 : : * %NULL. Use [method@Service.load_collections] to load the collections.
1286 : : *
1287 : : * Returns: (transfer full) (element-type Secret.Collection) (nullable): a
1288 : : * list of the collections in the secret service
1289 : : */
1290 : : GList *
1291 : 8 : secret_service_get_collections (SecretService *self)
1292 : : {
1293 : : GList *l, *collections;
1294 : :
1295 [ - + + - : 8 : g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+ - - + ]
1296 : :
1297 : 8 : g_mutex_lock (&self->pv->mutex);
1298 : :
1299 [ + + ]: 8 : if (self->pv->collections == NULL) {
1300 : 2 : collections = NULL;
1301 : :
1302 : : } else {
1303 : 6 : collections = g_hash_table_get_values (self->pv->collections);
1304 [ + - + + ]: 36 : for (l = collections; l != NULL; l = g_list_next (l))
1305 : 30 : g_object_ref (l->data);
1306 : : }
1307 : :
1308 : 8 : g_mutex_unlock (&self->pv->mutex);
1309 : :
1310 : 8 : return collections;
1311 : : }
1312 : :
1313 : : SecretItem *
1314 : 17 : _secret_service_find_item_instance (SecretService *self,
1315 : : const gchar *item_path)
1316 : : {
1317 : 17 : SecretCollection *collection = NULL;
1318 : : gchar *collection_path;
1319 : : SecretItem *item;
1320 : :
1321 : 17 : collection_path = _secret_util_parent_path (item_path);
1322 : :
1323 : 17 : collection = _secret_service_find_collection_instance (self, collection_path);
1324 : :
1325 : 17 : g_free (collection_path);
1326 : :
1327 [ + - ]: 17 : if (collection == NULL)
1328 : 17 : return NULL;
1329 : :
1330 : 0 : item = _secret_collection_find_item_instance (collection, item_path);
1331 : 0 : g_object_unref (collection);
1332 : :
1333 : 0 : return item;
1334 : : }
1335 : :
1336 : : SecretCollection *
1337 : 21 : _secret_service_find_collection_instance (SecretService *self,
1338 : : const gchar *collection_path)
1339 : : {
1340 : 21 : SecretCollection *collection = NULL;
1341 : :
1342 : 21 : g_mutex_lock (&self->pv->mutex);
1343 [ - + ]: 21 : if (self->pv->collections) {
1344 : 0 : collection = g_hash_table_lookup (self->pv->collections, collection_path);
1345 [ # # ]: 0 : if (collection != NULL)
1346 : 0 : g_object_ref (collection);
1347 : : }
1348 : 21 : g_mutex_unlock (&self->pv->mutex);
1349 : :
1350 : 21 : return collection;
1351 : : }
1352 : :
1353 : : SecretSession *
1354 : 55 : _secret_service_get_session (SecretService *self)
1355 : : {
1356 : : SecretSession *session;
1357 : :
1358 [ - + + - : 55 : g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+ - - + ]
1359 : :
1360 : 55 : g_mutex_lock (&self->pv->mutex);
1361 : 55 : session = self->pv->session;
1362 : 55 : g_mutex_unlock (&self->pv->mutex);
1363 : :
1364 : 55 : return session;
1365 : : }
1366 : :
1367 : : void
1368 : 56 : _secret_service_take_session (SecretService *self,
1369 : : SecretSession *session)
1370 : : {
1371 [ - + + - : 56 : g_return_if_fail (SECRET_IS_SERVICE (self));
+ - - + ]
1372 [ - + ]: 56 : g_return_if_fail (session != NULL);
1373 : :
1374 : 56 : g_mutex_lock (&self->pv->mutex);
1375 [ + - ]: 56 : if (self->pv->session == NULL)
1376 : 56 : self->pv->session = session;
1377 : : else
1378 : 0 : _secret_session_free (session);
1379 : 56 : g_mutex_unlock (&self->pv->mutex);
1380 : : }
1381 : :
1382 : : /**
1383 : : * secret_service_get_session_algorithms:
1384 : : * @self: the secret service proxy
1385 : : *
1386 : : * Get the set of algorithms being used to transfer secrets between this
1387 : : * secret service proxy and the Secret Service itself.
1388 : : *
1389 : : * This will be %NULL if no session has been established. Use
1390 : : * [method@Service.ensure_session] to establish a session.
1391 : : *
1392 : : * Returns: (nullable): a string representing the algorithms for transferring
1393 : : * secrets
1394 : : */
1395 : : const gchar *
1396 : 11 : secret_service_get_session_algorithms (SecretService *self)
1397 : : {
1398 : : SecretSession *session;
1399 : : const gchar *algorithms;
1400 : :
1401 [ - + + - : 11 : g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+ - - + ]
1402 : :
1403 : 11 : g_mutex_lock (&self->pv->mutex);
1404 : 11 : session = self->pv->session;
1405 [ + + ]: 11 : algorithms = session ? _secret_session_get_algorithms (session) : NULL;
1406 : 11 : g_mutex_unlock (&self->pv->mutex);
1407 : :
1408 : : /* Session never changes once established, so can return const */
1409 : 11 : return algorithms;
1410 : : }
1411 : :
1412 : : /**
1413 : : * secret_service_get_session_dbus_path:
1414 : : * @self: the secret service proxy
1415 : : *
1416 : : * Get the D-Bus object path of the session object being used to transfer
1417 : : * secrets between this secret service proxy and the Secret Service itself.
1418 : : *
1419 : : * This will be %NULL if no session has been established. Use
1420 : : * [method@Service.ensure_session] to establish a session.
1421 : : *
1422 : : * Returns: (nullable): a string representing the D-Bus object path of the
1423 : : * session
1424 : : */
1425 : : const gchar *
1426 : 57 : secret_service_get_session_dbus_path (SecretService *self)
1427 : : {
1428 : : SecretSession *session;
1429 : : const gchar *path;
1430 : :
1431 [ - + + - : 57 : g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+ - - + ]
1432 : :
1433 : 57 : g_mutex_lock (&self->pv->mutex);
1434 : 57 : session = self->pv->session;
1435 [ + + ]: 57 : path = session ? _secret_session_get_path (session) : NULL;
1436 : 57 : g_mutex_unlock (&self->pv->mutex);
1437 : :
1438 : : /* Session never changes once established, so can return const */
1439 : 57 : return path;
1440 : : }
1441 : :
1442 : : /**
1443 : : * secret_service_ensure_session:
1444 : : * @self: the secret service
1445 : : * @cancellable: (nullable): optional cancellation object
1446 : : * @callback: called when the operation completes
1447 : : * @user_data: data to be passed to the callback
1448 : : *
1449 : : * Ensure that the #SecretService proxy has established a session with the
1450 : : * Secret Service.
1451 : : *
1452 : : * This session is used to transfer secrets.
1453 : : *
1454 : : * It is not normally necessary to call this method, as the session is
1455 : : * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION
1456 : : * to [func@Service.get] in order to ensure that a session has been established
1457 : : * by the time you get the #SecretService proxy.
1458 : : *
1459 : : * This method will return immediately and complete asynchronously.
1460 : : */
1461 : : void
1462 : 95 : secret_service_ensure_session (SecretService *self,
1463 : : GCancellable *cancellable,
1464 : : GAsyncReadyCallback callback,
1465 : : gpointer user_data)
1466 : : {
1467 : : GTask *task;
1468 : : SecretSession *session;
1469 : :
1470 [ - + + - : 95 : g_return_if_fail (SECRET_IS_SERVICE (self));
+ - - + ]
1471 [ - + - - : 95 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - -
- ]
1472 : :
1473 : 95 : g_mutex_lock (&self->pv->mutex);
1474 : 95 : session = self->pv->session;
1475 : 95 : g_mutex_unlock (&self->pv->mutex);
1476 : :
1477 [ + + ]: 95 : if (session == NULL) {
1478 : 56 : _secret_session_open (self, cancellable, callback, user_data);
1479 : :
1480 : : } else {
1481 : 39 : task = g_task_new (self, cancellable, callback, user_data);
1482 [ + - ]: 39 : g_task_set_source_tag (task, secret_service_ensure_session);
1483 : 39 : g_task_return_boolean (task, TRUE);
1484 : 39 : g_object_unref (task);
1485 : : }
1486 : : }
1487 : :
1488 : : /**
1489 : : * secret_service_ensure_session_finish:
1490 : : * @self: the secret service
1491 : : * @result: the asynchronous result passed to the callback
1492 : : * @error: location to place an error on failure
1493 : : *
1494 : : * Finish an asynchronous operation to ensure that the #SecretService proxy
1495 : : * has established a session with the Secret Service.
1496 : : *
1497 : : * Returns: whether a session is established or not
1498 : : */
1499 : : gboolean
1500 : 95 : secret_service_ensure_session_finish (SecretService *self,
1501 : : GAsyncResult *result,
1502 : : GError **error)
1503 : : {
1504 [ - + + - : 95 : g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+ - - + ]
1505 [ + - - + ]: 95 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1506 [ - + ]: 95 : g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
1507 : :
1508 [ - + ]: 95 : if (!g_task_propagate_boolean (G_TASK (result), error)) {
1509 : 0 : _secret_util_strip_remote_error (error);
1510 : 0 : return FALSE;
1511 : : }
1512 : :
1513 [ - + ]: 95 : g_return_val_if_fail (self->pv->session != NULL, FALSE);
1514 : 95 : return TRUE;
1515 : : }
1516 : :
1517 : : /**
1518 : : * secret_service_ensure_session_sync:
1519 : : * @self: the secret service
1520 : : * @cancellable: (nullable): optional cancellation object
1521 : : * @error: location to place an error on failure
1522 : : *
1523 : : * Ensure that the #SecretService proxy has established a session with the
1524 : : * Secret Service.
1525 : : *
1526 : : * This session is used to transfer secrets.
1527 : : *
1528 : : * It is not normally necessary to call this method, as the session is
1529 : : * established as necessary. You can also pass the %SECRET_SERVICE_OPEN_SESSION
1530 : : * to [func@Service.get_sync] in order to ensure that a session has been
1531 : : * established by the time you get the #SecretService proxy.
1532 : : *
1533 : : * This method may block indefinitely and should not be used in user interface
1534 : : * threads.
1535 : : *
1536 : : * Returns: whether a session is established or not
1537 : : */
1538 : : gboolean
1539 : 8 : secret_service_ensure_session_sync (SecretService *self,
1540 : : GCancellable *cancellable,
1541 : : GError **error)
1542 : : {
1543 : : SecretSync *sync;
1544 : : gboolean ret;
1545 : :
1546 [ - + + - : 8 : g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+ - - + ]
1547 [ - + - - : 8 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
- - - - -
- ]
1548 [ + - - + ]: 8 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1549 : :
1550 : 8 : sync = _secret_sync_new ();
1551 : 8 : g_main_context_push_thread_default (sync->context);
1552 : :
1553 : 8 : secret_service_ensure_session (self, cancellable,
1554 : : _secret_sync_on_result, sync);
1555 : :
1556 : 8 : g_main_loop_run (sync->loop);
1557 : :
1558 : 8 : ret = secret_service_ensure_session_finish (self, sync->result, error);
1559 : :
1560 : 8 : g_main_context_pop_thread_default (sync->context);
1561 : 8 : _secret_sync_free (sync);
1562 : :
1563 : 8 : return ret;
1564 : : }
1565 : :
1566 : : static SecretCollection *
1567 : 40 : service_lookup_collection (SecretService *self,
1568 : : const gchar *path)
1569 : : {
1570 : 40 : SecretCollection *collection = NULL;
1571 : :
1572 : 40 : g_mutex_lock (&self->pv->mutex);
1573 : :
1574 [ - + ]: 40 : if (self->pv->collections) {
1575 : 0 : collection = g_hash_table_lookup (self->pv->collections, path);
1576 [ # # ]: 0 : if (collection != NULL)
1577 : 0 : g_object_ref (collection);
1578 : : }
1579 : :
1580 : 40 : g_mutex_unlock (&self->pv->mutex);
1581 : :
1582 : 40 : return collection;
1583 : : }
1584 : :
1585 : : static void
1586 : 8 : service_update_collections (SecretService *self,
1587 : : GHashTable *collections)
1588 : : {
1589 : : GHashTable *previous;
1590 : :
1591 : 8 : g_hash_table_ref (collections);
1592 : :
1593 : 8 : g_mutex_lock (&self->pv->mutex);
1594 : :
1595 : 8 : previous = self->pv->collections;
1596 : 8 : self->pv->collections = collections;
1597 : :
1598 : 8 : g_mutex_unlock (&self->pv->mutex);
1599 : :
1600 [ - + ]: 8 : if (previous != NULL)
1601 : 0 : g_hash_table_unref (previous);
1602 : :
1603 : 8 : g_object_notify (G_OBJECT (self), "collections");
1604 : 8 : }
1605 : :
1606 : : typedef struct {
1607 : : GHashTable *collections;
1608 : : gint collections_loading;
1609 : : } EnsureClosure;
1610 : :
1611 : : static GHashTable *
1612 : 8 : collections_table_new (void)
1613 : : {
1614 : 8 : return g_hash_table_new_full (g_str_hash, g_str_equal,
1615 : : g_free, g_object_unref);
1616 : : }
1617 : :
1618 : : static void
1619 : 5 : ensure_closure_free (gpointer data)
1620 : : {
1621 : 5 : EnsureClosure *closure = data;
1622 : 5 : g_hash_table_unref (closure->collections);
1623 : 5 : g_free (closure);
1624 : 5 : }
1625 : :
1626 : : static void
1627 : 25 : on_ensure_collection (GObject *source,
1628 : : GAsyncResult *result,
1629 : : gpointer user_data)
1630 : : {
1631 : 25 : GTask *task = G_TASK (user_data);
1632 : 25 : SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
1633 : 25 : EnsureClosure *closure = g_task_get_task_data (task);
1634 : : SecretCollection *collection;
1635 : : const gchar *path;
1636 : 25 : GError *error = NULL;
1637 : :
1638 : 25 : closure->collections_loading--;
1639 : :
1640 : 25 : collection = secret_collection_new_for_dbus_path_finish (result, &error);
1641 : :
1642 [ - + ]: 25 : if (error != NULL) {
1643 : 0 : g_task_return_error (task, g_steal_pointer (&error));
1644 : :
1645 [ + - ]: 25 : } else if (collection != NULL) {
1646 : 25 : path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection));
1647 : 25 : g_hash_table_insert (closure->collections, g_strdup (path), collection);
1648 : :
1649 [ + + ]: 25 : if (closure->collections_loading == 0) {
1650 : 5 : service_update_collections (self, closure->collections);
1651 : 5 : g_task_return_boolean (task, TRUE);
1652 : : }
1653 : : }
1654 : :
1655 : 25 : g_object_unref (self);
1656 : 25 : g_object_unref (task);
1657 : 25 : }
1658 : :
1659 : : /**
1660 : : * secret_service_load_collections:
1661 : : * @self: the secret service
1662 : : * @cancellable: (nullable): optional cancellation object
1663 : : * @callback: called when the operation completes
1664 : : * @user_data: data to be passed to the callback
1665 : : *
1666 : : * Ensure that the #SecretService proxy has loaded all the collections present
1667 : : * in the Secret Service.
1668 : : *
1669 : : * This affects the result of [method@Service.get_collections].
1670 : : *
1671 : : * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to
1672 : : * [func@Service.get_sync] in order to ensure that the collections have been
1673 : : * loaded by the time you get the #SecretService proxy.
1674 : : *
1675 : : * This method will return immediately and complete asynchronously.
1676 : : */
1677 : : void
1678 : 5 : secret_service_load_collections (SecretService *self,
1679 : : GCancellable *cancellable,
1680 : : GAsyncReadyCallback callback,
1681 : : gpointer user_data)
1682 : : {
1683 : : EnsureClosure *closure;
1684 : : SecretCollection *collection;
1685 : : GTask *task;
1686 : : const gchar *path;
1687 : : GVariant *paths;
1688 : : GVariantIter iter;
1689 : :
1690 [ - + + - : 5 : g_return_if_fail (SECRET_IS_SERVICE (self));
+ - - + ]
1691 [ - + - - : 5 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - -
- ]
1692 : :
1693 : 5 : paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
1694 [ - + ]: 5 : g_return_if_fail (paths != NULL);
1695 : :
1696 : 5 : task = g_task_new (self, cancellable, callback, user_data);
1697 [ + - ]: 5 : g_task_set_source_tag (task, secret_service_load_collections);
1698 : 5 : closure = g_new0 (EnsureClosure, 1);
1699 : 5 : closure->collections = collections_table_new ();
1700 : 5 : g_task_set_task_data (task, closure, ensure_closure_free);
1701 : :
1702 : 5 : g_variant_iter_init (&iter, paths);
1703 [ + + ]: 30 : while (g_variant_iter_loop (&iter, "&o", &path)) {
1704 : 25 : collection = service_lookup_collection (self, path);
1705 : :
1706 : : /* No such collection yet create a new one */
1707 [ + - ]: 25 : if (collection == NULL) {
1708 : 25 : secret_collection_new_for_dbus_path (self, path,
1709 : : SECRET_COLLECTION_LOAD_ITEMS,
1710 : : cancellable,
1711 : : on_ensure_collection,
1712 : : g_object_ref (task));
1713 : 25 : closure->collections_loading++;
1714 : : } else {
1715 : 0 : g_hash_table_insert (closure->collections, g_strdup (path), collection);
1716 : : }
1717 : : }
1718 : :
1719 [ - + ]: 5 : if (closure->collections_loading == 0) {
1720 : 0 : service_update_collections (self, closure->collections);
1721 : 0 : g_task_return_boolean (task, TRUE);
1722 : : }
1723 : :
1724 : 5 : g_variant_unref (paths);
1725 : 5 : g_object_unref (task);
1726 : : }
1727 : :
1728 : : /**
1729 : : * secret_service_load_collections_finish:
1730 : : * @self: the secret service
1731 : : * @result: the asynchronous result passed to the callback
1732 : : * @error: location to place an error on failure
1733 : : *
1734 : : * Complete an asynchronous operation to ensure that the #SecretService proxy
1735 : : * has loaded all the collections present in the Secret Service.
1736 : : *
1737 : : * Returns: whether the load was successful or not
1738 : : */
1739 : : gboolean
1740 : 5 : secret_service_load_collections_finish (SecretService *self,
1741 : : GAsyncResult *result,
1742 : : GError **error)
1743 : : {
1744 [ - + + - : 5 : g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+ - - + ]
1745 [ + - - + ]: 5 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1746 [ - + ]: 5 : g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
1747 [ - + ]: 5 : g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
1748 : : secret_service_load_collections, FALSE);
1749 : :
1750 [ - + ]: 5 : if (!g_task_propagate_boolean (G_TASK (result), error)) {
1751 : 0 : _secret_util_strip_remote_error (error);
1752 : 0 : return FALSE;
1753 : : }
1754 : :
1755 : 5 : return TRUE;
1756 : : }
1757 : :
1758 : : /**
1759 : : * secret_service_load_collections_sync:
1760 : : * @self: the secret service
1761 : : * @cancellable: (nullable): optional cancellation object
1762 : : * @error: location to place an error on failure
1763 : : *
1764 : : * Ensure that the #SecretService proxy has loaded all the collections present
1765 : : * in the Secret Service.
1766 : : *
1767 : : * This affects the result of [method@Service.get_collections].
1768 : : *
1769 : : * You can also pass the %SECRET_SERVICE_LOAD_COLLECTIONS to
1770 : : * [func@Service.get_sync] in order to ensure that the collections have been
1771 : : * loaded by the time you get the #SecretService proxy.
1772 : : *
1773 : : * This method may block indefinitely and should not be used in user interface
1774 : : * threads.
1775 : : *
1776 : : * Returns: whether the load was successful or not
1777 : : */
1778 : : gboolean
1779 : 3 : secret_service_load_collections_sync (SecretService *self,
1780 : : GCancellable *cancellable,
1781 : : GError **error)
1782 : : {
1783 : : SecretCollection *collection;
1784 : : GHashTable *collections;
1785 : : GVariant *paths;
1786 : : GVariantIter iter;
1787 : : const gchar *path;
1788 : 3 : gboolean ret = TRUE;
1789 : :
1790 [ - + + - : 3 : g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+ - - + ]
1791 [ - + - - : 3 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
- - - - -
- ]
1792 [ + - - + ]: 3 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1793 : :
1794 : 3 : paths = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Collections");
1795 [ - + ]: 3 : g_return_val_if_fail (paths != NULL, FALSE);
1796 : :
1797 : 3 : collections = collections_table_new ();
1798 : :
1799 : 3 : g_variant_iter_init (&iter, paths);
1800 [ + + ]: 18 : while (g_variant_iter_next (&iter, "&o", &path)) {
1801 : 15 : collection = service_lookup_collection (self, path);
1802 : :
1803 : : /* No such collection yet create a new one */
1804 [ + - ]: 15 : if (collection == NULL) {
1805 : 15 : collection = secret_collection_new_for_dbus_path_sync (self, path,
1806 : : SECRET_COLLECTION_LOAD_ITEMS,
1807 : : cancellable, error);
1808 [ - + ]: 15 : if (collection == NULL) {
1809 : 0 : ret = FALSE;
1810 : 0 : break;
1811 : : }
1812 : : }
1813 : :
1814 : 30 : g_hash_table_insert (collections, g_strdup (path), collection);
1815 : : }
1816 : :
1817 [ + - ]: 3 : if (ret)
1818 : 3 : service_update_collections (self, collections);
1819 : :
1820 : 3 : g_hash_table_unref (collections);
1821 : 3 : g_variant_unref (paths);
1822 : 3 : return ret;
1823 : : }
1824 : :
1825 : : /**
1826 : : * secret_service_prompt_sync:
1827 : : * @self: the secret service
1828 : : * @prompt: the prompt
1829 : : * @cancellable: (nullable): optional cancellation object
1830 : : * @return_type: the variant type of the prompt result
1831 : : * @error: location to place an error on failure
1832 : : *
1833 : : * Perform prompting for a [class@Prompt].
1834 : : *
1835 : : * Runs a prompt and performs the prompting. Returns a variant result if the
1836 : : * prompt was completed and not dismissed. The type of result depends on the
1837 : : * action the prompt is completing, and is defined in the Secret Service DBus
1838 : : * API specification.
1839 : : *
1840 : : * This function is called by other parts of this library to handle prompts
1841 : : * for the various actions that can require prompting.
1842 : : *
1843 : : * Override the #SecretServiceClass [vfunc@Service.prompt_sync] virtual method
1844 : : * to change the behavior of the prompting. The default behavior is to simply
1845 : : * run [method@Prompt.perform_sync] on the prompt with a %NULL `window_id`.
1846 : : *
1847 : : * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred,
1848 : : * a variant result if the prompt was successful
1849 : : */
1850 : : GVariant *
1851 : 1 : secret_service_prompt_sync (SecretService *self,
1852 : : SecretPrompt *prompt,
1853 : : GCancellable *cancellable,
1854 : : const GVariantType *return_type,
1855 : : GError **error)
1856 : : {
1857 : : SecretServiceClass *klass;
1858 : :
1859 [ - + + - : 1 : g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+ - - + ]
1860 [ - + + - : 1 : g_return_val_if_fail (SECRET_IS_PROMPT (prompt), NULL);
+ - - + ]
1861 [ - + - - : 1 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- - - - -
- ]
1862 [ + - - + ]: 1 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1863 : :
1864 : 1 : klass = SECRET_SERVICE_GET_CLASS (self);
1865 [ - + ]: 1 : g_return_val_if_fail (klass->prompt_sync != NULL, NULL);
1866 : :
1867 : 1 : return (klass->prompt_sync) (self, prompt, cancellable, return_type, error);
1868 : : }
1869 : :
1870 : : /**
1871 : : * secret_service_prompt:
1872 : : * @self: the secret service
1873 : : * @prompt: the prompt
1874 : : * @return_type: (nullable): the variant type of the prompt result
1875 : : * @cancellable: (nullable): optional cancellation object
1876 : : * @callback: called when the operation completes
1877 : : * @user_data: data to be passed to the callback
1878 : : *
1879 : : * Perform prompting for a [class@Prompt].
1880 : : *
1881 : : * This function is called by other parts of this library to handle prompts
1882 : : * for the various actions that can require prompting.
1883 : : *
1884 : : * Override the #SecretServiceClass [vfunc@Service.prompt_async] virtual method
1885 : : * to change the behavior of the prompting. The default behavior is to simply
1886 : : * run [method@Prompt.perform] on the prompt.
1887 : : */
1888 : : void
1889 : 10 : secret_service_prompt (SecretService *self,
1890 : : SecretPrompt *prompt,
1891 : : const GVariantType *return_type,
1892 : : GCancellable *cancellable,
1893 : : GAsyncReadyCallback callback,
1894 : : gpointer user_data)
1895 : : {
1896 : : SecretServiceClass *klass;
1897 : :
1898 [ - + + - : 10 : g_return_if_fail (SECRET_IS_SERVICE (self));
+ - - + ]
1899 [ - + + - : 10 : g_return_if_fail (SECRET_IS_PROMPT (prompt));
+ - - + ]
1900 [ - + - - : 10 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - -
- ]
1901 : :
1902 : 10 : klass = SECRET_SERVICE_GET_CLASS (self);
1903 [ - + ]: 10 : g_return_if_fail (klass->prompt_async != NULL);
1904 : :
1905 : 10 : (klass->prompt_async) (self, prompt, return_type, cancellable, callback, user_data);
1906 : : }
1907 : :
1908 : : /**
1909 : : * secret_service_prompt_finish:
1910 : : * @self: the secret service
1911 : : * @result: the asynchronous result passed to the callback
1912 : : * @error: location to place an error on failure
1913 : : *
1914 : : * Complete asynchronous operation to perform prompting for a [class@Prompt].
1915 : : *
1916 : : * Returns a variant result if the prompt was completed and not dismissed. The
1917 : : * type of result depends on the action the prompt is completing, and is defined
1918 : : * in the Secret Service DBus API specification.
1919 : : *
1920 : : * Returns: (transfer full): %NULL if the prompt was dismissed or an error occurred,
1921 : : * a variant result if the prompt was successful
1922 : : */
1923 : : GVariant *
1924 : 10 : secret_service_prompt_finish (SecretService *self,
1925 : : GAsyncResult *result,
1926 : : GError **error)
1927 : : {
1928 : : SecretServiceClass *klass;
1929 : :
1930 [ - + + - : 10 : g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+ - - + ]
1931 [ - + + - : 10 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
- + - + ]
1932 [ + - - + ]: 10 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1933 : :
1934 : 10 : klass = SECRET_SERVICE_GET_CLASS (self);
1935 [ - + ]: 10 : g_return_val_if_fail (klass->prompt_finish != NULL, NULL);
1936 : :
1937 : 10 : return (klass->prompt_finish) (self, result, error);
1938 : : }
1939 : :
1940 : : /**
1941 : : * secret_service_get_collection_gtype:
1942 : : * @self: the secret service
1943 : : *
1944 : : * Get the GObject type for collections instantiated by this service.
1945 : : *
1946 : : * This will always be either [class@Collection] or derived from it.
1947 : : *
1948 : : * Returns: the gobject type for collections
1949 : : */
1950 : : GType
1951 : 75 : secret_service_get_collection_gtype (SecretService *self)
1952 : : {
1953 : : SecretServiceClass *klass;
1954 : : GType type;
1955 : :
1956 [ - + + - : 75 : g_return_val_if_fail (SECRET_IS_SERVICE (self), 0);
+ - - + ]
1957 : :
1958 : 75 : klass = SECRET_SERVICE_GET_CLASS (self);
1959 [ - + ]: 75 : g_return_val_if_fail (klass->get_collection_gtype != NULL,
1960 : : SECRET_TYPE_COLLECTION);
1961 : :
1962 : 75 : type = (klass->get_collection_gtype) (self);
1963 [ - + - - ]: 75 : g_return_val_if_fail (g_type_is_a (type, SECRET_TYPE_COLLECTION),
1964 : : SECRET_TYPE_COLLECTION);
1965 : :
1966 : 75 : return type;
1967 : : }
1968 : :
1969 : : /**
1970 : : * secret_service_get_item_gtype:
1971 : : * @self: the service
1972 : : *
1973 : : * Get the GObject type for items instantiated by this service.
1974 : : *
1975 : : * This will always be either [class@Item] or derived from it.
1976 : : *
1977 : : * Returns: the gobject type for items
1978 : : */
1979 : : GType
1980 : 144 : secret_service_get_item_gtype (SecretService *self)
1981 : : {
1982 : : SecretServiceClass *klass;
1983 : : GType type;
1984 : :
1985 [ - + + - : 144 : g_return_val_if_fail (SECRET_IS_SERVICE (self), 0);
+ - - + ]
1986 : :
1987 : 144 : klass = SECRET_SERVICE_GET_CLASS (self);
1988 [ - + ]: 144 : g_return_val_if_fail (klass->get_item_gtype != NULL,
1989 : : SECRET_TYPE_ITEM);
1990 : :
1991 : 144 : type = (klass->get_item_gtype) (self);
1992 [ - + - - ]: 144 : g_return_val_if_fail (g_type_is_a (type, SECRET_TYPE_ITEM),
1993 : : SECRET_TYPE_ITEM);
1994 : :
1995 : 144 : return type;
1996 : : }
|