1 /* libsecret - GLib wrapper for Secret Service
2  *
3  * Copyright 2012 Red Hat Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation; either version 2.1 of the licence or (at
8  * your option) any later version.
9  *
10  * See the included COPYING file for more information.
11  *
12  * Author: Stef Walter <stefw@gnome.org>
13  */
14 
15 #include "config.h"
16 
17 #include "secret-collection.h"
18 #include "secret-dbus-generated.h"
19 #include "secret-item.h"
20 #include "secret-paths.h"
21 #include "secret-private.h"
22 #include "secret-retrievable.h"
23 #include "secret-service.h"
24 #include "secret-types.h"
25 #include "secret-value.h"
26 
27 #include "libsecret/secret-enum-types.h"
28 
29 #include <glib/gi18n-lib.h>
30 
31 /**
32  * SECTION:secret-item
33  * @title: SecretItem
34  * @short_description: A secret item
35  *
36  * #SecretItem represents a secret item stored in the Secret Service.
37  *
38  * Each item has a value, represented by a #SecretValue, which can be
39  * retrieved by secret_item_get_secret() or set by secret_item_set_secret().
40  * The item is only available when the item is not locked.
41  *
42  * Items can be locked or unlocked using the secret_service_lock() or
43  * secret_service_unlock() functions. The Secret Service may not be able to
44  * unlock individual items, and may unlock an entire collection when a single
45  * item is unlocked.
46  *
47  * Each item has a set of attributes, which are used to locate the item later.
48  * These are not stored or transferred in a secure manner. Each attribute has
49  * a string name and a string value. Use secret_service_search() to search for
50  * items based on their attributes, and secret_item_set_attributes() to change
51  * the attributes associated with an item.
52  *
53  * Items can be created with secret_item_create() or secret_service_store().
54  *
55  * Stability: Stable
56  */
57 
58 /**
59  * SecretItem:
60  *
61  * A proxy object representing a secret item in the Secret Service.
62  */
63 
64 /**
65  * SecretItemClass:
66  * @parent_class: the parent class
67  *
68  * The class for #SecretItem.
69  */
70 
71 /**
72  * SecretItemFlags:
73  * @SECRET_ITEM_NONE: no flags
74  * @SECRET_ITEM_LOAD_SECRET: a secret has been (or should be) loaded for #SecretItem
75  *
76  * Flags which determine which parts of the #SecretItem proxy are initialized.
77  */
78 
79 /**
80  * SecretItemCreateFlags:
81  * @SECRET_ITEM_CREATE_NONE: no flags
82  * @SECRET_ITEM_CREATE_REPLACE: replace an item with the same attributes.
83  *
84  * Flags for secret_item_create().
85  */
86 
87 enum {
88 	PROP_0,
89 	PROP_SERVICE,
90 	PROP_FLAGS,
91 	PROP_ATTRIBUTES,
92 	PROP_LABEL,
93 	PROP_LOCKED,
94 	PROP_CREATED,
95 	PROP_MODIFIED
96 };
97 
98 struct _SecretItemPrivate {
99 	/* No changes between construct and finalize */
100 	SecretService *service;
101 	SecretItemFlags init_flags;
102 
103 	/* Locked by mutex */
104 	GMutex mutex;
105 	SecretValue *value;
106 	gint disposed;
107 };
108 
109 static SecretRetrievableInterface *secret_item_retrievable_parent_iface = NULL;
110 
111 static GInitableIface *secret_item_initable_parent_iface = NULL;
112 
113 static GAsyncInitableIface *secret_item_async_initable_parent_iface = NULL;
114 
115 static void   secret_item_retrievable_iface      (SecretRetrievableInterface *iface);
116 
117 static void   secret_item_initable_iface         (GInitableIface *iface);
118 
119 static void   secret_item_async_initable_iface   (GAsyncInitableIface *iface);
120 
121 G_DEFINE_TYPE_WITH_CODE (SecretItem, secret_item, G_TYPE_DBUS_PROXY,
122                          G_ADD_PRIVATE (SecretItem)
123 			 G_IMPLEMENT_INTERFACE (SECRET_TYPE_RETRIEVABLE, secret_item_retrievable_iface);
124                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, secret_item_initable_iface);
125                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, secret_item_async_initable_iface);
126 );
127 
128 static void
secret_item_init(SecretItem * self)129 secret_item_init (SecretItem *self)
130 {
131 	self->pv = secret_item_get_instance_private (self);
132 	g_mutex_init (&self->pv->mutex);
133 }
134 
135 static void
on_set_attributes(GObject * source,GAsyncResult * result,gpointer user_data)136 on_set_attributes (GObject *source,
137                    GAsyncResult *result,
138                    gpointer user_data)
139 {
140 	SecretItem *self = SECRET_ITEM (user_data);
141 	GError *error = NULL;
142 
143 	if (!g_atomic_int_get (&self->pv->disposed)) {
144 		secret_item_set_attributes_finish (self, result, &error);
145 		if (error != NULL) {
146 			g_warning ("couldn't set SecretItem Attributes: %s", error->message);
147 			g_error_free (error);
148 		}
149 	}
150 
151 	g_object_unref (self);
152 }
153 
154 static void
on_set_label(GObject * source,GAsyncResult * result,gpointer user_data)155 on_set_label (GObject *source,
156               GAsyncResult *result,
157               gpointer user_data)
158 {
159 	SecretItem *self = SECRET_ITEM (user_data);
160 	GError *error = NULL;
161 
162 	if (!g_atomic_int_get (&self->pv->disposed)) {
163 		secret_item_set_label_finish (self, result, &error);
164 		if (error != NULL) {
165 			g_warning ("couldn't set SecretItem Label: %s", error->message);
166 			g_error_free (error);
167 		}
168 	}
169 
170 	g_object_unref (self);
171 }
172 
173 
174 static void
item_take_service(SecretItem * self,SecretService * service)175 item_take_service (SecretItem *self,
176                    SecretService *service)
177 {
178 	if (service == NULL)
179 		return;
180 
181 	g_return_if_fail (self->pv->service == NULL);
182 
183 	self->pv->service = service;
184 	g_object_add_weak_pointer (G_OBJECT (self->pv->service),
185 	                           (gpointer *)&self->pv->service);
186 
187 	/* Yes, we expect that the service will stay around */
188 	g_object_unref (service);
189 }
190 
191 static void
secret_item_set_property(GObject * obj,guint prop_id,const GValue * value,GParamSpec * pspec)192 secret_item_set_property (GObject *obj,
193                           guint prop_id,
194                           const GValue *value,
195                           GParamSpec *pspec)
196 {
197 	SecretItem *self = SECRET_ITEM (obj);
198 
199 	switch (prop_id) {
200 	case PROP_SERVICE:
201 		item_take_service (self, g_value_dup_object (value));
202 		break;
203 	case PROP_FLAGS:
204 		self->pv->init_flags = g_value_get_flags (value);
205 		break;
206 	case PROP_ATTRIBUTES:
207 		secret_item_set_attributes (self, NULL, g_value_get_boxed (value),
208 		                            NULL, on_set_attributes,
209 		                            g_object_ref (self));
210 		break;
211 	case PROP_LABEL:
212 		secret_item_set_label (self, g_value_get_string (value),
213 		                       NULL, on_set_label,
214 		                       g_object_ref (self));
215 		break;
216 	default:
217 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
218 		break;
219 	}
220 }
221 
222 static void
secret_item_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)223 secret_item_get_property (GObject *obj,
224                           guint prop_id,
225                           GValue *value,
226                           GParamSpec *pspec)
227 {
228 	SecretItem *self = SECRET_ITEM (obj);
229 
230 	switch (prop_id) {
231 	case PROP_SERVICE:
232 		g_value_set_object (value, self->pv->service);
233 		break;
234 	case PROP_FLAGS:
235 		g_value_set_flags (value, secret_item_get_flags (self));
236 		break;
237 	case PROP_ATTRIBUTES:
238 		g_value_take_boxed (value, secret_item_get_attributes (self));
239 		break;
240 	case PROP_LABEL:
241 		g_value_take_string (value, secret_item_get_label (self));
242 		break;
243 	case PROP_LOCKED:
244 		g_value_set_boolean (value, secret_item_get_locked (self));
245 		break;
246 	case PROP_CREATED:
247 		g_value_set_uint64 (value, secret_item_get_created (self));
248 		break;
249 	case PROP_MODIFIED:
250 		g_value_set_uint64 (value, secret_item_get_modified (self));
251 		break;
252 	default:
253 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
254 		break;
255 	}
256 }
257 
258 static void
secret_item_dispose(GObject * obj)259 secret_item_dispose (GObject *obj)
260 {
261 	SecretItem *self = SECRET_ITEM (obj);
262 
263 	g_atomic_int_inc (&self->pv->disposed);
264 
265 	G_OBJECT_CLASS (secret_item_parent_class)->dispose (obj);
266 }
267 
268 static void
secret_item_finalize(GObject * obj)269 secret_item_finalize (GObject *obj)
270 {
271 	SecretItem *self = SECRET_ITEM (obj);
272 
273 	if (self->pv->service)
274 		g_object_remove_weak_pointer (G_OBJECT (self->pv->service),
275 		                              (gpointer *)&self->pv->service);
276 
277 	if (self->pv->value != NULL)
278 		secret_value_unref (self->pv->value);
279 
280 	g_mutex_clear (&self->pv->mutex);
281 
282 	G_OBJECT_CLASS (secret_item_parent_class)->finalize (obj);
283 }
284 
285 static void
handle_property_changed(GObject * object,const gchar * property_name)286 handle_property_changed (GObject *object,
287                          const gchar *property_name)
288 {
289 	if (g_str_equal (property_name, "Attributes"))
290 		g_object_notify (object, "attributes");
291 
292 	else if (g_str_equal (property_name, "Label"))
293 		g_object_notify (object, "label");
294 
295 	else if (g_str_equal (property_name, "Locked"))
296 		g_object_notify (object, "locked");
297 
298 	else if (g_str_equal (property_name, "Created"))
299 		g_object_notify (object, "created");
300 
301 	else if (g_str_equal (property_name, "Modified"))
302 		g_object_notify (object, "modified");
303 }
304 
305 static void
secret_item_properties_changed(GDBusProxy * proxy,GVariant * changed_properties,const gchar * const * invalidated_properties)306 secret_item_properties_changed (GDBusProxy *proxy,
307                                 GVariant *changed_properties,
308                                 const gchar* const *invalidated_properties)
309 {
310 	GObject *obj = G_OBJECT (proxy);
311 	gchar *property_name;
312 	GVariantIter iter;
313 	GVariant *value;
314 
315 	g_object_freeze_notify (obj);
316 
317 	g_variant_iter_init (&iter, changed_properties);
318 	while (g_variant_iter_loop (&iter, "{sv}", &property_name, &value))
319 		handle_property_changed (obj, property_name);
320 
321 	g_object_thaw_notify (obj);
322 }
323 
324 static void
secret_item_class_init(SecretItemClass * klass)325 secret_item_class_init (SecretItemClass *klass)
326 {
327 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
328 	GDBusProxyClass *proxy_class = G_DBUS_PROXY_CLASS (klass);
329 
330 	gobject_class->get_property = secret_item_get_property;
331 	gobject_class->set_property = secret_item_set_property;
332 	gobject_class->dispose = secret_item_dispose;
333 	gobject_class->finalize = secret_item_finalize;
334 
335 	proxy_class->g_properties_changed = secret_item_properties_changed;
336 
337 	/**
338 	 * SecretItem:service:
339 	 *
340 	 * The #SecretService object that this item is associated with and
341 	 * uses to interact with the actual D-Bus Secret Service.
342 	 */
343 	g_object_class_install_property (gobject_class, PROP_SERVICE,
344 	            g_param_spec_object ("service", "Service", "Secret Service",
345 	                                 SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
346 
347 	/**
348 	 * SecretItem:flags:
349 	 *
350 	 * A set of flags describing which parts of the secret item have
351 	 * been initialized.
352 	 */
353 	g_object_class_install_property (gobject_class, PROP_FLAGS,
354 	             g_param_spec_flags ("flags", "Flags", "Item flags",
355 	                                 secret_item_flags_get_type (), SECRET_ITEM_NONE,
356 	                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
357 
358 	/**
359 	 * SecretItem:attributes: (type GLib.HashTable(utf8,utf8)) (transfer full)
360 	 *
361 	 * The attributes set on this item. Attributes are used to locate an
362 	 * item. They are not guaranteed to be stored or transferred securely.
363 	 */
364 	g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
365 
366 	/**
367 	 * SecretItem:label:
368 	 *
369 	 * The human readable label for the item.
370 	 *
371 	 * Setting this property will result in the label of the item being
372 	 * set asynchronously. To properly track the changing of the label use the
373 	 * secret_item_set_label() function.
374 	 */
375 	g_object_class_override_property (gobject_class, PROP_LABEL, "label");
376 
377 	/**
378 	 * SecretItem:locked:
379 	 *
380 	 * Whether the item is locked or not. An item may not be independently
381 	 * lockable separate from other items in its collection.
382 	 *
383 	 * To lock or unlock a item use the secret_service_lock() or
384 	 * secret_service_unlock() functions.
385 	 */
386 	g_object_class_install_property (gobject_class, PROP_LOCKED,
387 	           g_param_spec_boolean ("locked", "Locked", "Item locked",
388 	                                 TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
389 
390 	/**
391 	 * SecretItem:created:
392 	 *
393 	 * The date and time (in seconds since the UNIX epoch) that this
394 	 * item was created.
395 	 */
396 	g_object_class_override_property (gobject_class, PROP_CREATED, "created");
397 
398 	/**
399 	 * SecretItem:modified:
400 	 *
401 	 * The date and time (in seconds since the UNIX epoch) that this
402 	 * item was last modified.
403 	 */
404 	g_object_class_override_property (gobject_class, PROP_MODIFIED, "modified");
405 }
406 
407 static gboolean
item_ensure_for_flags_sync(SecretItem * self,SecretItemFlags flags,GCancellable * cancellable,GError ** error)408 item_ensure_for_flags_sync (SecretItem *self,
409                             SecretItemFlags flags,
410                             GCancellable *cancellable,
411                             GError **error)
412 {
413 	if (flags & SECRET_ITEM_LOAD_SECRET && !secret_item_get_locked (self)) {
414 		if (!secret_item_load_secret_sync (self, cancellable, error))
415 			return FALSE;
416 	}
417 
418 	return TRUE;
419 }
420 
421 
422 static void
on_init_load_secret(GObject * source,GAsyncResult * result,gpointer user_data)423 on_init_load_secret (GObject *source,
424                      GAsyncResult *result,
425                      gpointer user_data)
426 {
427 	GTask *task = G_TASK (user_data);
428 	SecretItem *self = SECRET_ITEM (source);
429 	GError *error = NULL;
430 
431 	if (!secret_item_load_secret_finish (self, result, &error))
432 		g_task_return_error (task, g_steal_pointer (&error));
433 	else
434 		g_task_return_boolean (task, TRUE);
435 
436 	g_clear_object (&task);
437 }
438 
439 static void
item_ensure_for_flags_async(SecretItem * self,SecretItemFlags flags,GTask * task)440 item_ensure_for_flags_async (SecretItem *self,
441                              SecretItemFlags flags,
442                              GTask *task)
443 {
444 	GCancellable *cancellable = g_task_get_cancellable (task);
445 
446 	if (flags & SECRET_ITEM_LOAD_SECRET && !secret_item_get_locked (self))
447 		secret_item_load_secret (self, cancellable, on_init_load_secret,
448 		                         g_object_ref (task));
449 
450 	else
451 		g_task_return_boolean (task, TRUE);
452 }
453 
454 static gboolean
secret_item_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)455 secret_item_initable_init (GInitable *initable,
456                            GCancellable *cancellable,
457                            GError **error)
458 {
459 	SecretItem *self;
460 	SecretService *service;
461 	GDBusProxy *proxy;
462 
463 	if (!secret_item_initable_parent_iface->init (initable, cancellable, error))
464 		return FALSE;
465 
466 	proxy = G_DBUS_PROXY (initable);
467 
468 	if (!_secret_util_have_cached_properties (proxy)) {
469 		g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
470 		             "No such secret item at path: %s",
471 		             g_dbus_proxy_get_object_path (proxy));
472 		return FALSE;
473 	}
474 
475 	self = SECRET_ITEM (initable);
476 	if (!self->pv->service) {
477 		service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error);
478 		if (service == NULL)
479 			return FALSE;
480 		else
481 			item_take_service (self, service);
482 	}
483 
484 	return item_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error);
485 }
486 
487 static void
secret_item_initable_iface(GInitableIface * iface)488 secret_item_initable_iface (GInitableIface *iface)
489 {
490 	secret_item_initable_parent_iface = g_type_interface_peek_parent (iface);
491 
492 	iface->init = secret_item_initable_init;
493 }
494 
495 static void
on_init_service(GObject * source,GAsyncResult * result,gpointer user_data)496 on_init_service (GObject *source,
497                  GAsyncResult *result,
498                  gpointer user_data)
499 {
500 	GTask *task = G_TASK (user_data);
501 	SecretItem *self = SECRET_ITEM (g_task_get_source_object (task));
502 	SecretService *service;
503 	GError *error = NULL;
504 
505 	service = secret_service_get_finish (result, &error);
506 	if (error == NULL) {
507 		item_take_service (self, g_steal_pointer (&service));
508 		item_ensure_for_flags_async (self, self->pv->init_flags, task);
509 
510 	} else {
511 		g_task_return_error (task, g_steal_pointer (&error));
512 	}
513 
514 	g_clear_object (&task);
515 }
516 
517 static void
on_init_base(GObject * source,GAsyncResult * result,gpointer user_data)518 on_init_base (GObject *source,
519               GAsyncResult *result,
520               gpointer user_data)
521 {
522 	GTask *task = G_TASK (user_data);
523 	GCancellable *cancellable = g_task_get_cancellable (task);
524 	SecretItem *self = SECRET_ITEM (source);
525 	GDBusProxy *proxy = G_DBUS_PROXY (self);
526 	GError *error = NULL;
527 
528 	if (!secret_item_async_initable_parent_iface->init_finish (G_ASYNC_INITABLE (self),
529 	                                                           result, &error)) {
530 		g_task_return_error (task, g_steal_pointer (&error));
531 
532 	} else if (!_secret_util_have_cached_properties (proxy)) {
533 		g_task_return_new_error (task, G_DBUS_ERROR,
534 		                         G_DBUS_ERROR_UNKNOWN_METHOD,
535 		                         "No such secret item at path: %s",
536 		                         g_dbus_proxy_get_object_path (proxy));
537 
538 	} else if (self->pv->service == NULL) {
539 		secret_service_get (SECRET_SERVICE_NONE, cancellable,
540 		                    on_init_service, g_steal_pointer (&task));
541 
542 	} else {
543 		item_ensure_for_flags_async (self, self->pv->init_flags, task);
544 	}
545 
546 	g_clear_object (&task);
547 }
548 
549 static void
secret_item_async_initable_init_async(GAsyncInitable * initable,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)550 secret_item_async_initable_init_async (GAsyncInitable *initable,
551                                        int io_priority,
552                                        GCancellable *cancellable,
553                                        GAsyncReadyCallback callback,
554                                        gpointer user_data)
555 {
556 	GTask *task;
557 
558 	task = g_task_new (initable, cancellable, callback, user_data);
559 	g_task_set_source_tag (task, secret_item_async_initable_init_async);
560 
561 	secret_item_async_initable_parent_iface->init_async (initable, io_priority,
562 	                                                     cancellable,
563 	                                                     on_init_base,
564 	                                                     g_steal_pointer (&task));
565 
566 	g_clear_object (&task);
567 }
568 
569 static gboolean
secret_item_async_initable_init_finish(GAsyncInitable * initable,GAsyncResult * result,GError ** error)570 secret_item_async_initable_init_finish (GAsyncInitable *initable,
571                                         GAsyncResult *result,
572                                         GError **error)
573 {
574 	g_return_val_if_fail (g_task_is_valid (result, initable), FALSE);
575 
576 	if (!g_task_propagate_boolean (G_TASK (result), error)) {
577 		_secret_util_strip_remote_error (error);
578 		return FALSE;
579 	}
580 
581 	return TRUE;
582 }
583 
584 static void
secret_item_async_initable_iface(GAsyncInitableIface * iface)585 secret_item_async_initable_iface (GAsyncInitableIface *iface)
586 {
587 	secret_item_async_initable_parent_iface = g_type_interface_peek_parent (iface);
588 
589 	iface->init_async = secret_item_async_initable_init_async;
590 	iface->init_finish = secret_item_async_initable_init_finish;
591 }
592 
593 /**
594  * secret_item_refresh:
595  * @self: the collection
596  *
597  * Refresh the properties on this item. This fires off a request to
598  * refresh, and the properties will be updated later.
599  *
600  * Calling this method is not normally necessary, as the secret service
601  * will notify the client when properties change.
602  */
603 void
secret_item_refresh(SecretItem * self)604 secret_item_refresh (SecretItem *self)
605 {
606 	g_return_if_fail (SECRET_IS_ITEM (self));
607 
608 	_secret_util_get_properties (G_DBUS_PROXY (self),
609 	                             secret_item_refresh,
610 	                             NULL, NULL, NULL);
611 }
612 
613 void
_secret_item_set_cached_secret(SecretItem * self,SecretValue * value)614 _secret_item_set_cached_secret (SecretItem *self,
615                                 SecretValue *value)
616 {
617 	SecretValue *other = NULL;
618 	gboolean updated = FALSE;
619 
620 	g_return_if_fail (SECRET_IS_ITEM (self));
621 
622 	if (value != NULL)
623 		secret_value_ref (value);
624 
625 	g_mutex_lock (&self->pv->mutex);
626 
627 	if (value != self->pv->value) {
628 		other = self->pv->value;
629 		self->pv->value = value;
630 		updated = TRUE;
631 	} else {
632 		other = value;
633 	}
634 
635 	g_mutex_unlock (&self->pv->mutex);
636 
637 	if (other != NULL)
638 		secret_value_unref (other);
639 
640 	if (updated)
641 		g_object_notify (G_OBJECT (self), "flags");
642 }
643 
644 static void
on_create_item(GObject * source,GAsyncResult * result,gpointer user_data)645 on_create_item (GObject *source,
646                 GAsyncResult *result,
647                 gpointer user_data)
648 {
649 	GTask *task = G_TASK (user_data);
650 	SecretValue *value = g_task_get_task_data (task);
651 	SecretItem *item;
652 	GError *error = NULL;
653 
654 	item = secret_item_new_for_dbus_path_finish (result, &error);
655 	if (item) {
656 		/* As a convenience mark down the SecretValue on the item */
657 		_secret_item_set_cached_secret (item, value);
658 		g_task_return_pointer (task, item, g_object_unref);
659 	} else {
660 		g_task_return_error (task, g_steal_pointer (&error));
661 	}
662 
663 	g_clear_object (&task);
664 }
665 
666 static void
on_create_path(GObject * source,GAsyncResult * result,gpointer user_data)667 on_create_path (GObject *source,
668                 GAsyncResult *result,
669                 gpointer user_data)
670 {
671 	GTask *task = G_TASK (user_data);
672 	GCancellable *cancellable = g_task_get_cancellable (task);
673 	SecretService *service = SECRET_SERVICE (source);
674 	GError *error = NULL;
675 	gchar *path;
676 
677 	path = secret_service_create_item_dbus_path_finish (service, result, &error);
678 	if (error == NULL) {
679 		secret_item_new_for_dbus_path (service, path, SECRET_ITEM_NONE,
680 		                               cancellable, on_create_item,
681 		                               g_steal_pointer (&task));
682 	} else {
683 		g_task_return_error (task, g_steal_pointer (&error));
684 	}
685 	g_free (path);
686 
687 	g_clear_object (&task);
688 }
689 
690 static GHashTable *
item_properties_new(const gchar * label,const SecretSchema * schema,GHashTable * attributes)691 item_properties_new (const gchar *label,
692                      const SecretSchema *schema,
693                      GHashTable *attributes)
694 {
695 	const gchar *schema_name = NULL;
696 	GHashTable *properties;
697 	GVariant *value;
698 
699 	if (schema != NULL)
700 		schema_name = schema->name;
701 
702 	properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
703 	                                    (GDestroyNotify)g_variant_unref);
704 
705 	value = g_variant_new_string (label);
706 	g_hash_table_insert (properties,
707 	                     SECRET_ITEM_INTERFACE ".Label",
708 	                     g_variant_ref_sink (value));
709 
710 	value = _secret_attributes_to_variant (attributes, schema_name);
711 	g_hash_table_insert (properties,
712 	                     SECRET_ITEM_INTERFACE ".Attributes",
713 	                     g_variant_ref_sink (value));
714 
715 	return properties;
716 }
717 
718 /**
719  * secret_item_create:
720  * @collection: a secret collection to create this item in
721  * @schema: (allow-none): the schema for the attributes
722  * @attributes: (element-type utf8 utf8): attributes for the new item
723  * @label: label for the new item
724  * @value: secret value for the new item
725  * @flags: flags for the creation of the new item
726  * @cancellable: optional cancellation object
727  * @callback: called when the operation completes
728  * @user_data: data to pass to the callback
729  *
730  * Create a new item in the secret service.
731  *
732  * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret
733  * service will search for an item matching the @attributes, and update that item
734  * instead of creating a new one.
735  *
736  * This method may block indefinitely and should not be used in user interface
737  * threads. The secret service may prompt the user. secret_service_prompt()
738  * will be used to handle any prompts that are required.
739  */
740 void
secret_item_create(SecretCollection * collection,const SecretSchema * schema,GHashTable * attributes,const gchar * label,SecretValue * value,SecretItemCreateFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)741 secret_item_create (SecretCollection *collection,
742                     const SecretSchema *schema,
743                     GHashTable *attributes,
744                     const gchar *label,
745                     SecretValue *value,
746                     SecretItemCreateFlags flags,
747                     GCancellable *cancellable,
748                     GAsyncReadyCallback callback,
749                     gpointer user_data)
750 {
751 	SecretService *service = NULL;
752 	const gchar *collection_path;
753 	GTask *task;
754 	GHashTable *properties;
755 
756 	g_return_if_fail (SECRET_IS_COLLECTION (collection));
757 	g_return_if_fail (label != NULL);
758 	g_return_if_fail (attributes != NULL);
759 	g_return_if_fail (value != NULL);
760 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
761 
762 	/* Warnings raised already */
763 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
764 		return;
765 
766 	task = g_task_new (NULL, cancellable, callback, user_data);
767 	g_task_set_source_tag (task, secret_item_create);
768 	g_task_set_task_data (task, secret_value_ref (value), secret_value_unref);
769 
770 	properties = item_properties_new (label, schema, attributes);
771 	g_object_get (collection, "service", &service, NULL);
772 
773 	collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection));
774 
775 	secret_service_create_item_dbus_path (service, collection_path, properties,
776 	                                      value, flags, cancellable,
777 	                                      on_create_path,
778 	                                      g_steal_pointer (&task));
779 
780 	g_hash_table_unref (properties);
781 	g_object_unref (service);
782 	g_clear_object (&task);
783 }
784 
785 /**
786  * secret_item_create_finish:
787  * @result: the asynchronous result passed to the callback
788  * @error: location to place an error on failure
789  *
790  * Finish operation to create a new item in the secret service.
791  *
792  * Returns: (transfer full): the new item, which should be unreferenced
793  *          with g_object_unref()
794  */
795 SecretItem *
secret_item_create_finish(GAsyncResult * result,GError ** error)796 secret_item_create_finish (GAsyncResult *result,
797                            GError **error)
798 {
799 	SecretItem *retval;
800 
801 	g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
802 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
803 
804 	retval = g_task_propagate_pointer (G_TASK (result), error);
805 	if (!retval) {
806 		_secret_util_strip_remote_error (error);
807 		return NULL;
808 	}
809 
810 	return g_steal_pointer (&retval);
811 }
812 
813 /**
814  * secret_item_create_sync:
815  * @collection: a secret collection to create this item in
816  * @schema: (allow-none): the schema for the attributes
817  * @attributes: (element-type utf8 utf8): attributes for the new item
818  * @label: label for the new item
819  * @value: secret value for the new item
820  * @flags: flags for the creation of the new item
821  * @cancellable: optional cancellation object
822  * @error: location to place an error on failure
823  *
824  * Create a new item in the secret service.
825  *
826  * If the @flags contains %SECRET_ITEM_CREATE_REPLACE, then the secret
827  * service will search for an item matching the @attributes, and update that item
828  * instead of creating a new one.
829  *
830  * This method may block indefinitely and should not be used in user interface
831  * threads. The secret service may prompt the user. secret_service_prompt()
832  * will be used to handle any prompts that are required.
833  *
834  * Returns: (transfer full): the new item, which should be unreferenced
835  *          with g_object_unref()
836  */
837 SecretItem *
secret_item_create_sync(SecretCollection * collection,const SecretSchema * schema,GHashTable * attributes,const gchar * label,SecretValue * value,SecretItemCreateFlags flags,GCancellable * cancellable,GError ** error)838 secret_item_create_sync (SecretCollection *collection,
839                          const SecretSchema *schema,
840                          GHashTable *attributes,
841                          const gchar *label,
842                          SecretValue *value,
843                          SecretItemCreateFlags flags,
844                          GCancellable *cancellable,
845                          GError **error)
846 {
847 	SecretService *service = NULL;
848 	const gchar *collection_path;
849 	SecretItem *item = NULL;
850 	GHashTable *properties;
851 	gchar *path;
852 
853 	g_return_val_if_fail (SECRET_IS_COLLECTION (collection), NULL);
854 	g_return_val_if_fail (label != NULL, NULL);
855 	g_return_val_if_fail (attributes != NULL, NULL);
856 	g_return_val_if_fail (value != NULL, NULL);
857 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
858 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
859 
860 	/* Warnings raised already */
861 	if (schema != NULL && !_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
862 		return NULL;
863 
864 	properties = item_properties_new (label, schema, attributes);
865 	g_object_get (collection, "service", &service, NULL);
866 
867 	collection_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (collection));
868 
869 	path = secret_service_create_item_dbus_path_sync (service, collection_path, properties,
870 	                                                  value, flags, cancellable, error);
871 
872 	if (path != NULL) {
873 		item = secret_item_new_for_dbus_path_sync (service, path, SECRET_ITEM_NONE,
874 		                                           cancellable, error);
875 		g_free (path);
876 	}
877 
878 	g_hash_table_unref (properties);
879 	g_object_unref (service);
880 
881 	return item;
882 }
883 
884 static void
on_item_deleted(GObject * source,GAsyncResult * result,gpointer user_data)885 on_item_deleted (GObject *source,
886                  GAsyncResult *result,
887                  gpointer user_data)
888 {
889 	GTask *task = G_TASK (user_data);
890 	SecretService *service = SECRET_SERVICE (source);
891 	GError *error = NULL;
892 
893 	if (!_secret_service_delete_path_finish (service, result, &error))
894 		g_task_return_error (task, g_steal_pointer (&error));
895 	else
896 		g_task_return_boolean (task, TRUE);
897 
898 	g_clear_object (&task);
899 }
900 
901 /**
902  * secret_item_delete:
903  * @self: an item
904  * @cancellable: (nullable): optional cancellation object
905  * @callback: called when the operation completes
906  * @user_data: data to pass to the callback
907  *
908  * Delete this item.
909  *
910  * This method returns immediately and completes asynchronously. The secret
911  * service may prompt the user. secret_service_prompt() will be used to handle
912  * any prompts that show up.
913  */
914 void
secret_item_delete(SecretItem * self,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)915 secret_item_delete (SecretItem *self,
916                     GCancellable *cancellable,
917                     GAsyncReadyCallback callback,
918                     gpointer user_data)
919 {
920 	GTask *task;
921 	const gchar *object_path;
922 
923 	g_return_if_fail (SECRET_IS_ITEM (self));
924 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
925 
926 	object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self));
927 	task = g_task_new (self, cancellable, callback, user_data);
928 	g_task_set_source_tag (task, secret_item_delete);
929 
930 	_secret_service_delete_path (self->pv->service, object_path, TRUE,
931 	                             cancellable, on_item_deleted,
932 	                             g_steal_pointer (&task));
933 
934 	g_clear_object (&task);
935 }
936 
937 /**
938  * secret_item_delete_finish:
939  * @self: an item
940  * @result: asynchronous result passed to the callback
941  * @error: location to place an error on failure
942  *
943  * Complete asynchronous operation to delete the secret item.
944  *
945  * Returns: whether the item was successfully deleted or not
946  */
947 gboolean
secret_item_delete_finish(SecretItem * self,GAsyncResult * result,GError ** error)948 secret_item_delete_finish (SecretItem *self,
949                            GAsyncResult *result,
950                            GError **error)
951 {
952 	g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
953 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
954 	g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
955 
956 	if (!g_task_propagate_boolean (G_TASK (result), error)) {
957 		_secret_util_strip_remote_error (error);
958 		return FALSE;
959 	}
960 
961 	return TRUE;
962 }
963 
964 /**
965  * secret_item_delete_sync:
966  * @self: an item
967  * @cancellable: optional cancellation object
968  * @error: location to place an error on failure
969  *
970  * Delete this secret item.
971  *
972  * This method may block indefinitely and should not be used in user
973  * interface threads. The secret service may prompt the user.
974  * secret_service_prompt() will be used to handle any prompts that show up.
975  *
976  * Returns: whether the item was successfully deleted or not
977  */
978 gboolean
secret_item_delete_sync(SecretItem * self,GCancellable * cancellable,GError ** error)979 secret_item_delete_sync (SecretItem *self,
980                          GCancellable *cancellable,
981                          GError **error)
982 {
983 	SecretSync *sync;
984 	gboolean ret;
985 
986 	g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
987 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
988 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
989 
990 	sync = _secret_sync_new ();
991 	g_main_context_push_thread_default (sync->context);
992 
993 	secret_item_delete (self, cancellable, _secret_sync_on_result, sync);
994 
995 	g_main_loop_run (sync->loop);
996 
997 	ret = secret_item_delete_finish (self, sync->result, error);
998 
999 	g_main_context_pop_thread_default (sync->context);
1000 	_secret_sync_free (sync);
1001 
1002 	return ret;
1003 }
1004 
1005 /**
1006  * secret_item_get_flags:
1007  * @self: the secret item proxy
1008  *
1009  * Get the flags representing what features of the #SecretItem proxy
1010  * have been initialized.
1011  *
1012  * Use secret_item_load_secret() to initialize further features
1013  * and change the flags.
1014  *
1015  * Returns: the flags for features initialized
1016  */
1017 SecretItemFlags
secret_item_get_flags(SecretItem * self)1018 secret_item_get_flags (SecretItem *self)
1019 {
1020 	SecretServiceFlags flags = 0;
1021 
1022 	g_return_val_if_fail (SECRET_IS_ITEM (self), SECRET_ITEM_NONE);
1023 
1024 	g_mutex_lock (&self->pv->mutex);
1025 
1026 	if (self->pv->value)
1027 		flags |= SECRET_ITEM_LOAD_SECRET;
1028 
1029 	g_mutex_unlock (&self->pv->mutex);
1030 
1031 	return flags;
1032 
1033 }
1034 
1035 /**
1036  * secret_item_get_service:
1037  * @self: an item
1038  *
1039  * Get the Secret Service object that this item was created with.
1040  *
1041  * Returns: (transfer none): the Secret Service object
1042  */
1043 SecretService *
secret_item_get_service(SecretItem * self)1044 secret_item_get_service (SecretItem *self)
1045 {
1046 	g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1047 	return self->pv->service;
1048 }
1049 
1050 
1051 /**
1052  * secret_item_get_secret:
1053  * @self: an item
1054  *
1055  * Get the secret value of this item. If this item is locked or the secret
1056  * has not yet been loaded then this will return %NULL.
1057  *
1058  * To load the secret call the secret_item_load_secret() method.
1059  *
1060  * Returns: (transfer full) (allow-none): the secret value which should be
1061  *          released with secret_value_unref(), or %NULL
1062  */
1063 SecretValue *
secret_item_get_secret(SecretItem * self)1064 secret_item_get_secret (SecretItem *self)
1065 {
1066 	SecretValue *value = NULL;
1067 
1068 	g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1069 
1070 	g_mutex_lock (&self->pv->mutex);
1071 
1072 	if (self->pv->value)
1073 		value = secret_value_ref (self->pv->value);
1074 
1075 	g_mutex_unlock (&self->pv->mutex);
1076 
1077 	return value;
1078 }
1079 
1080 static void
on_item_load_secret(GObject * source,GAsyncResult * result,gpointer user_data)1081 on_item_load_secret (GObject *source,
1082                      GAsyncResult *result,
1083                      gpointer user_data)
1084 {
1085 	GTask *task = G_TASK (user_data);
1086 	SecretItem *self = SECRET_ITEM (g_task_get_source_object (task));
1087 	SecretSession *session;
1088 	GError *error = NULL;
1089 	SecretValue *value;
1090 	GVariant *retval;
1091 	GVariant *child;
1092 
1093 	retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
1094 	if (error == NULL) {
1095 		child = g_variant_get_child_value (retval, 0);
1096 		g_variant_unref (retval);
1097 
1098 		session = _secret_service_get_session (self->pv->service);
1099 		value = _secret_session_decode_secret (session, child);
1100 		g_variant_unref (child);
1101 
1102 		if (value == NULL) {
1103 			g_set_error (&error, SECRET_ERROR, SECRET_ERROR_PROTOCOL,
1104 			             _("Received invalid secret from the secret storage"));
1105 		} else {
1106 			_secret_item_set_cached_secret (self, value);
1107 			secret_value_unref (value);
1108 		}
1109 	}
1110 
1111 	if (error == NULL)
1112 		g_task_return_boolean (task, TRUE);
1113 	else
1114 		g_task_return_error (task, g_steal_pointer (&error));
1115 
1116 	g_clear_object (&task);
1117 }
1118 
1119 static void
on_load_ensure_session(GObject * source,GAsyncResult * result,gpointer user_data)1120 on_load_ensure_session (GObject *source,
1121                         GAsyncResult *result,
1122                         gpointer user_data)
1123 {
1124 	GTask *task = G_TASK (user_data);
1125 	SecretItem *self = SECRET_ITEM (g_task_get_source_object (task));
1126 	GCancellable *cancellable = g_task_get_cancellable (task);
1127 	const gchar *session_path;
1128 	GError *error = NULL;
1129 
1130 	secret_service_ensure_session_finish (self->pv->service, result, &error);
1131 	if (error != NULL) {
1132 		g_task_return_error (task, g_steal_pointer (&error));
1133 
1134 	} else {
1135 		session_path = secret_service_get_session_dbus_path (self->pv->service);
1136 		g_assert (session_path != NULL && session_path[0] != '\0');
1137 		g_dbus_proxy_call (G_DBUS_PROXY (self), "GetSecret",
1138 		                   g_variant_new ("(o)", session_path),
1139 		                   G_DBUS_CALL_FLAGS_NONE, -1, cancellable,
1140 		                   on_item_load_secret, g_steal_pointer (&task));
1141 	}
1142 
1143 	g_clear_object (&task);
1144 }
1145 
1146 /**
1147  * secret_item_load_secret:
1148  * @self: an item proxy
1149  * @cancellable: (nullable): optional cancellation object
1150  * @callback: called when the operation completes
1151  * @user_data: data to pass to the callback
1152  *
1153  * Load the secret value of this item.
1154  *
1155  * Each item has a single secret which might be a password or some
1156  * other secret binary value.
1157  *
1158  * This function will fail if the secret item is locked.
1159  *
1160  * This function returns immediately and completes asynchronously.
1161  */
1162 void
secret_item_load_secret(SecretItem * self,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1163 secret_item_load_secret (SecretItem *self,
1164                          GCancellable *cancellable,
1165                          GAsyncReadyCallback callback,
1166                          gpointer user_data)
1167 {
1168 	GTask *task;
1169 
1170 	g_return_if_fail (SECRET_IS_ITEM (self));
1171 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1172 
1173 	task = g_task_new (self, cancellable, callback, user_data);
1174 	g_task_set_source_tag (task, secret_item_load_secret);
1175 
1176 	secret_service_ensure_session (self->pv->service, cancellable,
1177 	                               on_load_ensure_session,
1178 	                               g_steal_pointer (&task));
1179 
1180 	g_clear_object (&task);
1181 }
1182 
1183 /**
1184  * secret_item_load_secret_finish:
1185  * @self: an item proxy
1186  * @result: asynchronous result passed to callback
1187  * @error: location to place error on failure
1188  *
1189  * Complete asynchronous operation to load the secret value of this item.
1190  *
1191  * The newly loaded secret value can be accessed by calling
1192  * secret_item_get_secret().
1193  *
1194  * Returns: whether the secret item successfully loaded or not
1195  */
1196 gboolean
secret_item_load_secret_finish(SecretItem * self,GAsyncResult * result,GError ** error)1197 secret_item_load_secret_finish (SecretItem *self,
1198                                 GAsyncResult *result,
1199                                 GError **error)
1200 {
1201 	g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
1202 
1203 	if (!g_task_propagate_boolean (G_TASK (result), error)) {
1204 		_secret_util_strip_remote_error (error);
1205 		return FALSE;
1206 	}
1207 
1208 	return TRUE;
1209 }
1210 
1211 /**
1212  * secret_item_load_secret_sync:
1213  * @self: an item
1214  * @cancellable: optional cancellation object
1215  * @error: location to place error on failure
1216  *
1217  * Load the secret value of this item.
1218  *
1219  * Each item has a single secret which might be a password or some
1220  * other secret binary value.
1221  *
1222  * This function may block indefinitely. Use the asynchronous version
1223  * in user interface threads.
1224  *
1225  * Returns: whether the secret item successfully loaded or not
1226  */
1227 gboolean
secret_item_load_secret_sync(SecretItem * self,GCancellable * cancellable,GError ** error)1228 secret_item_load_secret_sync (SecretItem *self,
1229                               GCancellable *cancellable,
1230                               GError **error)
1231 {
1232 	SecretSync *sync;
1233 	gboolean result;
1234 
1235 	g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1236 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1237 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1238 
1239 	sync = _secret_sync_new ();
1240 	g_main_context_push_thread_default (sync->context);
1241 
1242 	secret_item_load_secret (self, cancellable, _secret_sync_on_result, sync);
1243 
1244 	g_main_loop_run (sync->loop);
1245 
1246 	result = secret_item_load_secret_finish (self, sync->result, error);
1247 
1248 	g_main_context_pop_thread_default (sync->context);
1249 	_secret_sync_free (sync);
1250 
1251 	return result;
1252 }
1253 
1254 static void
on_retrieve_load(GObject * source_object,GAsyncResult * res,gpointer user_data)1255 on_retrieve_load (GObject *source_object,
1256 		  GAsyncResult *res,
1257 		  gpointer user_data)
1258 {
1259 	SecretItem *self = SECRET_ITEM (source_object);
1260 	GTask *task = G_TASK (user_data);
1261 	GError *error = NULL;
1262 
1263 	if (secret_item_load_secret_finish (self, res, &error)) {
1264 		g_task_return_pointer (task,
1265 				       secret_item_get_secret (self),
1266 				       secret_value_unref);
1267 		g_object_unref (task);
1268 	} else {
1269 		g_task_return_error (task, error);
1270 		g_object_unref (task);
1271 	}
1272 }
1273 
1274 static void
secret_item_retrieve_secret(SecretRetrievable * self,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1275 secret_item_retrieve_secret (SecretRetrievable *self,
1276 			     GCancellable *cancellable,
1277 			     GAsyncReadyCallback callback,
1278 			     gpointer user_data)
1279 {
1280 	GTask *task = g_task_new (self, cancellable, callback, user_data);
1281 
1282 	secret_item_load_secret (SECRET_ITEM (self), cancellable, on_retrieve_load, task);
1283 }
1284 
1285 static SecretValue *
secret_item_retrieve_secret_finish(SecretRetrievable * self,GAsyncResult * result,GError ** error)1286 secret_item_retrieve_secret_finish (SecretRetrievable *self,
1287 				    GAsyncResult *result,
1288 				    GError **error)
1289 {
1290 	g_return_val_if_fail (g_task_is_valid (result, self), NULL);
1291 
1292 	return g_task_propagate_pointer (G_TASK (result), error);
1293 }
1294 
1295 static void
secret_item_retrievable_iface(SecretRetrievableInterface * iface)1296 secret_item_retrievable_iface (SecretRetrievableInterface *iface)
1297 {
1298 	secret_item_retrievable_parent_iface = g_type_interface_peek_parent (iface);
1299 	iface->retrieve_secret = secret_item_retrieve_secret;
1300 	iface->retrieve_secret_finish = secret_item_retrieve_secret_finish;
1301 }
1302 
1303 typedef struct {
1304 	SecretService *service;
1305 	GVariant *in;
1306 	GHashTable *items;
1307 } LoadsClosure;
1308 
1309 static void
loads_closure_free(gpointer data)1310 loads_closure_free (gpointer data)
1311 {
1312 	LoadsClosure *loads = data;
1313 	if (loads->in)
1314 		g_variant_unref (loads->in);
1315 	if (loads->service)
1316 		g_object_unref (loads->service);
1317 	g_hash_table_destroy (loads->items);
1318 	g_slice_free (LoadsClosure, loads);
1319 }
1320 
1321 static void
on_get_secrets_complete(GObject * source,GAsyncResult * result,gpointer user_data)1322 on_get_secrets_complete (GObject *source,
1323                          GAsyncResult *result,
1324                          gpointer user_data)
1325 {
1326 	GTask *task = G_TASK (user_data);
1327 	LoadsClosure *loads = g_task_get_task_data (task);
1328 	GHashTable *with_paths;
1329 	GError *error = NULL;
1330 	GHashTableIter iter;
1331 	const gchar *path;
1332 	SecretValue *value;
1333 	SecretItem *item;
1334 	GVariant *retval;
1335 
1336 	retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
1337 	if (retval != NULL) {
1338 		with_paths = _secret_service_decode_get_secrets_all (loads->service, retval);
1339 		g_return_if_fail (with_paths != NULL);
1340 
1341 		g_hash_table_iter_init (&iter, with_paths);
1342 		while (g_hash_table_iter_next (&iter, (gpointer *)&path, (gpointer *)&value)) {
1343 			item = g_hash_table_lookup (loads->items, path);
1344 			if (item != NULL)
1345 				_secret_item_set_cached_secret (item, value);
1346 		}
1347 
1348 		g_hash_table_unref (with_paths);
1349 		g_variant_unref (retval);
1350 	}
1351 
1352 	if (error != NULL)
1353 		g_task_return_error (task, g_steal_pointer (&error));
1354 	else
1355 		g_task_return_boolean (task, TRUE);
1356 
1357 	g_clear_object (&task);
1358 }
1359 
1360 static void
on_loads_secrets_session(GObject * source,GAsyncResult * result,gpointer user_data)1361 on_loads_secrets_session (GObject *source,
1362                           GAsyncResult *result,
1363                           gpointer user_data)
1364 {
1365 	GTask *task = G_TASK (user_data);
1366 	LoadsClosure *loads = g_task_get_task_data (task);
1367 	GError *error = NULL;
1368 	const gchar *session;
1369 
1370 	secret_service_ensure_session_finish (SECRET_SERVICE (source), result, &error);
1371 	if (error != NULL) {
1372 		g_task_return_error (task, g_steal_pointer (&error));
1373 		g_clear_object (&task);
1374 		return;
1375 	}
1376 
1377 	session = secret_service_get_session_dbus_path (SECRET_SERVICE (source));
1378 	g_dbus_proxy_call (G_DBUS_PROXY (source), "GetSecrets",
1379 	                   g_variant_new ("(@aoo)", loads->in, session),
1380 	                   G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
1381 	                   g_task_get_cancellable (task),
1382 	                   on_get_secrets_complete,
1383 	                   g_object_ref (task));
1384 
1385 	g_clear_object (&task);
1386 }
1387 
1388 /**
1389  * secret_item_load_secrets:
1390  * @items: (element-type Secret.Item): the items to retrieve secrets for
1391  * @cancellable: optional cancellation object
1392  * @callback: called when the operation completes
1393  * @user_data: data to pass to the callback
1394  *
1395  * Load the secret values for a secret item stored in the service.
1396  *
1397  * The @items must all have the same SecretItem::service property.
1398  *
1399  * This function returns immediately and completes asynchronously.
1400  */
1401 void
secret_item_load_secrets(GList * items,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1402 secret_item_load_secrets (GList *items,
1403                           GCancellable *cancellable,
1404                           GAsyncReadyCallback callback,
1405                           gpointer user_data)
1406 {
1407 	GTask *task;
1408 	LoadsClosure *loads;
1409 	GPtrArray *paths;
1410 	const gchar *path;
1411 	GList *l;
1412 
1413 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1414 
1415 	for (l = items; l != NULL; l = g_list_next (l))
1416 		g_return_if_fail (SECRET_IS_ITEM (l->data));
1417 
1418 	task = g_task_new (NULL, cancellable, callback, user_data);
1419 	g_task_set_source_tag (task, secret_item_load_secrets);
1420 	loads = g_slice_new0 (LoadsClosure);
1421 	loads->items = g_hash_table_new_full (g_str_hash, g_str_equal,
1422 	                                      g_free, g_object_unref);
1423 
1424 	paths = g_ptr_array_new ();
1425 	for (l = items; l != NULL; l = g_list_next (l)) {
1426 		if (secret_item_get_locked (l->data))
1427 			continue;
1428 
1429 		if (loads->service == NULL) {
1430 			loads->service = secret_item_get_service (l->data);
1431 			if (loads->service)
1432 				g_object_ref (loads->service);
1433 		}
1434 
1435 		path = g_dbus_proxy_get_object_path (l->data);
1436 		g_hash_table_insert (loads->items, g_strdup (path), g_object_ref (l->data));
1437 		g_ptr_array_add (paths, (gpointer)path);
1438 	}
1439 
1440 	loads->in = g_variant_new_objv ((const gchar * const *)paths->pdata, paths->len);
1441 	g_variant_ref_sink (loads->in);
1442 
1443 	g_ptr_array_free (paths, TRUE);
1444 	g_task_set_task_data (task, loads, loads_closure_free);
1445 
1446 	if (loads->service) {
1447 		secret_service_ensure_session (loads->service, cancellable,
1448 		                               on_loads_secrets_session,
1449 		                               g_object_ref (task));
1450 	} else {
1451 		g_task_return_boolean (task, TRUE);
1452 	}
1453 
1454 	g_clear_object (&task);
1455 }
1456 
1457 /**
1458  * secret_item_load_secrets_finish:
1459  * @result: asynchronous result passed to callback
1460  * @error: location to place an error on failure
1461  *
1462  * Complete asynchronous operation to load the secret values for
1463  * secret items stored in the service.
1464  *
1465  * Items that are locked will not have their secrets loaded.
1466  *
1467  * Returns: whether the operation succeeded or not
1468  */
1469 gboolean
secret_item_load_secrets_finish(GAsyncResult * result,GError ** error)1470 secret_item_load_secrets_finish (GAsyncResult *result,
1471                                  GError **error)
1472 {
1473 	g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
1474 
1475 	if (!g_task_propagate_boolean (G_TASK (result), error)) {
1476 		_secret_util_strip_remote_error (error);
1477 		return FALSE;
1478 	}
1479 
1480 	return TRUE;
1481 }
1482 
1483 /**
1484  * secret_item_load_secrets_sync:
1485  * @items: (element-type Secret.Item): the items to retrieve secrets for
1486  * @cancellable: optional cancellation object
1487  * @error: location to place an error on failure
1488  *
1489  * Load the secret values for a secret item stored in the service.
1490  *
1491  * The @items must all have the same SecretItem::service property.
1492  *
1493  * This method may block indefinitely and should not be used in user interface
1494  * threads.
1495  *
1496  * Items that are locked will not have their secrets loaded.
1497  *
1498  * Returns: whether the operation succeeded or not
1499  */
1500 gboolean
secret_item_load_secrets_sync(GList * items,GCancellable * cancellable,GError ** error)1501 secret_item_load_secrets_sync (GList *items,
1502                                GCancellable *cancellable,
1503                                GError **error)
1504 {
1505 	SecretSync *sync;
1506 	gboolean ret;
1507 	GList *l;
1508 
1509 	for (l = items; l != NULL; l = g_list_next (l))
1510 		g_return_val_if_fail (SECRET_IS_ITEM (l->data), FALSE);
1511 
1512 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1513 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1514 
1515 	sync = _secret_sync_new ();
1516 	g_main_context_push_thread_default (sync->context);
1517 
1518 	secret_item_load_secrets (items, cancellable,
1519 	                          _secret_sync_on_result, sync);
1520 
1521 	g_main_loop_run (sync->loop);
1522 
1523 	ret = secret_item_load_secrets_finish (sync->result, error);
1524 
1525 	g_main_context_pop_thread_default (sync->context);
1526 	_secret_sync_free (sync);
1527 
1528 	return ret;
1529 }
1530 
1531 static void
on_item_set_secret(GObject * source,GAsyncResult * result,gpointer user_data)1532 on_item_set_secret (GObject *source,
1533                     GAsyncResult *result,
1534                     gpointer user_data)
1535 {
1536 	GTask *task = G_TASK (user_data);
1537 	SecretItem *self = SECRET_ITEM (g_task_get_source_object (task));
1538 	SecretValue *value = g_task_get_task_data (task);
1539 	GError *error = NULL;
1540 	GVariant *retval;
1541 
1542 	retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
1543 
1544 	if (error) {
1545 		g_task_return_error (task, g_steal_pointer (&error));
1546 		g_clear_object (&task);
1547 		return;
1548 	}
1549 
1550 	_secret_item_set_cached_secret (self, value);
1551 	g_clear_pointer (&retval, g_variant_unref);
1552 
1553 	g_task_return_boolean (task, TRUE);
1554 	g_clear_object (&task);
1555 }
1556 
1557 static void
on_set_ensure_session(GObject * source,GAsyncResult * result,gpointer user_data)1558 on_set_ensure_session (GObject *source,
1559                        GAsyncResult *result,
1560                        gpointer user_data)
1561 {
1562 	GTask *task = G_TASK (user_data);
1563 	SecretItem *self = SECRET_ITEM (g_task_get_source_object (task));
1564 	SecretValue *value = g_task_get_task_data (task);
1565 	SecretSession *session;
1566 	GVariant *encoded;
1567 	GError *error = NULL;
1568 
1569 	secret_service_ensure_session_finish (self->pv->service, result, &error);
1570 	if (error != NULL) {
1571 		g_task_return_error (task, g_steal_pointer (&error));
1572 		g_clear_object (&task);
1573 		return;
1574 	}
1575 
1576 	session = _secret_service_get_session (self->pv->service);
1577 	encoded = _secret_session_encode_secret (session, value);
1578 	g_dbus_proxy_call (G_DBUS_PROXY (self), "SetSecret",
1579 	                   g_variant_new ("(@(oayays))", encoded),
1580 	                   G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
1581 					   g_task_get_cancellable (task),
1582 	                   on_item_set_secret, g_object_ref (task));
1583 
1584 	g_clear_object (&task);
1585 }
1586 
1587 /**
1588  * secret_item_set_secret:
1589  * @self: an item
1590  * @value: a new secret value
1591  * @cancellable: optional cancellation object
1592  * @callback: called when the operation completes
1593  * @user_data: data to pass to the callback
1594  *
1595  * Set the secret value of this item.
1596  *
1597  * Each item has a single secret which might be a password or some
1598  * other secret binary value.
1599  *
1600  * This function returns immediately and completes asynchronously.
1601  */
1602 void
secret_item_set_secret(SecretItem * self,SecretValue * value,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1603 secret_item_set_secret (SecretItem *self,
1604                         SecretValue *value,
1605                         GCancellable *cancellable,
1606                         GAsyncReadyCallback callback,
1607                         gpointer user_data)
1608 {
1609 	GTask *task = NULL;
1610 
1611 	g_return_if_fail (SECRET_IS_ITEM (self));
1612 	g_return_if_fail (value != NULL);
1613 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1614 
1615 	task = g_task_new (self, cancellable, callback, user_data);
1616 	g_task_set_source_tag (task, secret_item_set_secret);
1617 	g_task_set_task_data (task, secret_value_ref (value), secret_value_unref);
1618 
1619 	secret_service_ensure_session (self->pv->service, cancellable,
1620 	                               on_set_ensure_session,
1621 	                               g_steal_pointer (&task));
1622 
1623 	g_clear_object (&task);
1624 }
1625 
1626 /**
1627  * secret_item_set_secret_finish:
1628  * @self: an item
1629  * @result: asynchronous result passed to callback
1630  * @error: location to place error on failure
1631  *
1632  * Complete asynchronous operation to set the secret value of this item.
1633  *
1634  * Returns: whether the change was successful or not
1635  */
1636 gboolean
secret_item_set_secret_finish(SecretItem * self,GAsyncResult * result,GError ** error)1637 secret_item_set_secret_finish (SecretItem *self,
1638                                GAsyncResult *result,
1639                                GError **error)
1640 {
1641 	g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
1642 
1643 	if (!g_task_propagate_boolean (G_TASK (result), error)) {
1644 		_secret_util_strip_remote_error (error);
1645 		return FALSE;
1646 	}
1647 
1648 	return TRUE;
1649 }
1650 
1651 /**
1652  * secret_item_set_secret_sync:
1653  * @self: an item
1654  * @value: a new secret value
1655  * @cancellable: optional cancellation object
1656  * @error: location to place error on failure
1657  *
1658  * Set the secret value of this item.
1659  *
1660  * Each item has a single secret which might be a password or some
1661  * other secret binary value.
1662  *
1663  * This function may block indefinitely. Use the asynchronous version
1664  * in user interface threads.
1665  *
1666  * Returns: whether the change was successful or not
1667  */
1668 gboolean
secret_item_set_secret_sync(SecretItem * self,SecretValue * value,GCancellable * cancellable,GError ** error)1669 secret_item_set_secret_sync (SecretItem *self,
1670                              SecretValue *value,
1671                              GCancellable *cancellable,
1672                              GError **error)
1673 {
1674 	SecretSync *sync;
1675 	gboolean ret;
1676 
1677 	g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1678 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1679 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1680 
1681 	sync = _secret_sync_new ();
1682 	g_main_context_push_thread_default (sync->context);
1683 
1684 	secret_item_set_secret (self, value, cancellable, _secret_sync_on_result, sync);
1685 
1686 	g_main_loop_run (sync->loop);
1687 
1688 	ret = secret_item_set_secret_finish (self, sync->result, error);
1689 
1690 	g_main_context_pop_thread_default (sync->context);
1691 	_secret_sync_free (sync);
1692 
1693 	return ret;
1694 }
1695 
1696 /**
1697  * secret_item_get_schema_name:
1698  * @self: an item
1699  *
1700  * Gets the name of the schema that this item was stored with. This is also
1701  * available at the <literal>xdg:schema</literal> attribute.
1702  *
1703  * Returns: (nullable) (transfer full): the schema name
1704  */
1705 gchar *
secret_item_get_schema_name(SecretItem * self)1706 secret_item_get_schema_name (SecretItem *self)
1707 {
1708 	gchar *schema_name = NULL;
1709 	GVariant *variant;
1710 
1711 	g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1712 
1713 	variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Attributes");
1714 	g_return_val_if_fail (variant != NULL, NULL);
1715 
1716 	g_variant_lookup (variant, "xdg:schema", "s", &schema_name);
1717 	g_variant_unref (variant);
1718 
1719 	return schema_name;
1720 }
1721 
1722 /**
1723  * secret_item_get_attributes:
1724  * @self: an item
1725  *
1726  * Set the attributes of this item.
1727  *
1728  * The @attributes are a mapping of string keys to string values.
1729  * Attributes are used to search for items. Attributes are not stored
1730  * or transferred securely by the secret service.
1731  *
1732  * Do not modify the attributes returned by this method. Use
1733  * secret_item_set_attributes() instead.
1734  *
1735  * Returns: (transfer full) (element-type utf8 utf8): a new reference
1736  *          to the attributes, which should not be modified, and
1737  *          released with g_hash_table_unref()
1738  */
1739 GHashTable *
secret_item_get_attributes(SecretItem * self)1740 secret_item_get_attributes (SecretItem *self)
1741 {
1742 	GHashTable *attributes;
1743 	GVariant *variant;
1744 
1745 	g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1746 
1747 	variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Attributes");
1748 	g_return_val_if_fail (variant != NULL, NULL);
1749 
1750 	attributes = _secret_attributes_for_variant (variant);
1751 	g_variant_unref (variant);
1752 
1753 	return attributes;
1754 }
1755 
1756 /**
1757  * secret_item_set_attributes:
1758  * @self: an item
1759  * @schema: (allow-none): the schema for the attributes
1760  * @attributes: (element-type utf8 utf8): a new set of attributes
1761  * @cancellable: optional cancellation object
1762  * @callback: called when the asynchronous operation completes
1763  * @user_data: data to pass to the callback
1764  *
1765  * Set the attributes of this item.
1766  *
1767  * The @attributes are a mapping of string keys to string values.
1768  * Attributes are used to search for items. Attributes are not stored
1769  * or transferred securely by the secret service.
1770  *
1771  * This function returns immediately and completes asynchronously.
1772  */
1773 void
secret_item_set_attributes(SecretItem * self,const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1774 secret_item_set_attributes (SecretItem *self,
1775                             const SecretSchema *schema,
1776                             GHashTable *attributes,
1777                             GCancellable *cancellable,
1778                             GAsyncReadyCallback callback,
1779                             gpointer user_data)
1780 {
1781 	const gchar *schema_name = NULL;
1782 
1783 	g_return_if_fail (SECRET_IS_ITEM (self));
1784 	g_return_if_fail (attributes != NULL);
1785 
1786 	if (schema != NULL) {
1787 		if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
1788 			return; /* Warnings raised already */
1789 		schema_name = schema->name;
1790 	}
1791 
1792 	_secret_util_set_property (G_DBUS_PROXY (self), "Attributes",
1793 	                           _secret_attributes_to_variant (attributes, schema_name),
1794 	                           secret_item_set_attributes, cancellable,
1795 	                           callback, user_data);
1796 }
1797 
1798 /**
1799  * secret_item_set_attributes_finish:
1800  * @self: an item
1801  * @result: asynchronous result passed to the callback
1802  * @error: location to place error on failure
1803  *
1804  * Complete operation to set the attributes of this item.
1805  *
1806  * Returns: whether the change was successful or not
1807  */
1808 gboolean
secret_item_set_attributes_finish(SecretItem * self,GAsyncResult * result,GError ** error)1809 secret_item_set_attributes_finish (SecretItem *self,
1810                                    GAsyncResult *result,
1811                                    GError **error)
1812 {
1813 	g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1814 
1815 	return _secret_util_set_property_finish (G_DBUS_PROXY (self),
1816 	                                         secret_item_set_attributes,
1817 	                                         result, error);
1818 }
1819 
1820 /**
1821  * secret_item_set_attributes_sync:
1822  * @self: an item
1823  * @schema: (allow-none): the schema for the attributes
1824  * @attributes: (element-type utf8 utf8): a new set of attributes
1825  * @cancellable: optional cancellation object
1826  * @error: location to place error on failure
1827  *
1828  * Set the attributes of this item.
1829  *
1830  * The @attributes are a mapping of string keys to string values.
1831  * Attributes are used to search for items. Attributes are not stored
1832  * or transferred securely by the secret service.
1833  *
1834  * This function may block indefinitely. Use the asynchronous version
1835  * in user interface threads.
1836  *
1837  * Returns: whether the change was successful or not
1838  */
1839 gboolean
secret_item_set_attributes_sync(SecretItem * self,const SecretSchema * schema,GHashTable * attributes,GCancellable * cancellable,GError ** error)1840 secret_item_set_attributes_sync (SecretItem *self,
1841                                  const SecretSchema *schema,
1842                                  GHashTable *attributes,
1843                                  GCancellable *cancellable,
1844                                  GError **error)
1845 {
1846 	const gchar *schema_name = NULL;
1847 
1848 	g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1849 	g_return_val_if_fail (attributes != NULL, FALSE);
1850 
1851 	if (schema != NULL) {
1852 		if (!_secret_attributes_validate (schema, attributes, G_STRFUNC, FALSE))
1853 			return FALSE; /* Warnings raised already */
1854 		schema_name = schema->name;
1855 	}
1856 
1857 	return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Attributes",
1858 	                                       _secret_attributes_to_variant (attributes, schema_name),
1859 	                                       cancellable, error);
1860 }
1861 
1862 /**
1863  * secret_item_get_label:
1864  * @self: an item
1865  *
1866  * Get the label of this item.
1867  *
1868  * Returns: (transfer full): the label, which should be freed with g_free()
1869  */
1870 gchar *
secret_item_get_label(SecretItem * self)1871 secret_item_get_label (SecretItem *self)
1872 {
1873 	GVariant *variant;
1874 	gchar *label;
1875 
1876 	g_return_val_if_fail (SECRET_IS_ITEM (self), NULL);
1877 
1878 	variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Label");
1879 	g_return_val_if_fail (variant != NULL, NULL);
1880 
1881 	label = g_variant_dup_string (variant, NULL);
1882 	g_variant_unref (variant);
1883 
1884 	return label;
1885 }
1886 
1887 /**
1888  * secret_item_set_label:
1889  * @self: an item
1890  * @label: a new label
1891  * @cancellable: optional cancellation object
1892  * @callback: called when the operation completes
1893  * @user_data: data to pass to the callback
1894  *
1895  * Set the label of this item.
1896  *
1897  * This function returns immediately and completes asynchronously.
1898  */
1899 void
secret_item_set_label(SecretItem * self,const gchar * label,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1900 secret_item_set_label (SecretItem *self,
1901                        const gchar *label,
1902                        GCancellable *cancellable,
1903                        GAsyncReadyCallback callback,
1904                        gpointer user_data)
1905 {
1906 	g_return_if_fail (SECRET_IS_ITEM (self));
1907 	g_return_if_fail (label != NULL);
1908 
1909 	_secret_util_set_property (G_DBUS_PROXY (self), "Label",
1910 	                           g_variant_new_string (label),
1911 	                           secret_item_set_label,
1912 	                           cancellable, callback, user_data);
1913 }
1914 
1915 /**
1916  * secret_item_set_label_finish:
1917  * @self: an item
1918  * @result: asynchronous result passed to callback
1919  * @error: location to place error on failure
1920  *
1921  * Complete asynchronous operation to set the label of this collection.
1922  *
1923  * Returns: whether the change was successful or not
1924  */
1925 gboolean
secret_item_set_label_finish(SecretItem * self,GAsyncResult * result,GError ** error)1926 secret_item_set_label_finish (SecretItem *self,
1927                               GAsyncResult *result,
1928                               GError **error)
1929 {
1930 	g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1931 
1932 	return _secret_util_set_property_finish (G_DBUS_PROXY (self),
1933 	                                         secret_item_set_label,
1934 	                                         result, error);
1935 }
1936 
1937 /**
1938  * secret_item_set_label_sync:
1939  * @self: an item
1940  * @label: a new label
1941  * @cancellable: optional cancellation object
1942  * @error: location to place error on failure
1943  *
1944  * Set the label of this item.
1945  *
1946  * This function may block indefinitely. Use the asynchronous version
1947  * in user interface threads.
1948  *
1949  * Returns: whether the change was successful or not
1950  */
1951 gboolean
secret_item_set_label_sync(SecretItem * self,const gchar * label,GCancellable * cancellable,GError ** error)1952 secret_item_set_label_sync (SecretItem *self,
1953                             const gchar *label,
1954                             GCancellable *cancellable,
1955                             GError **error)
1956 {
1957 	g_return_val_if_fail (SECRET_IS_ITEM (self), FALSE);
1958 	g_return_val_if_fail (label != NULL, FALSE);
1959 
1960 	return _secret_util_set_property_sync (G_DBUS_PROXY (self), "Label",
1961 	                                       g_variant_new_string (label),
1962 	                                       cancellable, error);
1963 }
1964 
1965 /**
1966  * secret_item_get_locked:
1967  * @self: an item
1968  *
1969  * Get whether the item is locked or not.
1970  *
1971  * Depending on the secret service an item may not be able to be locked
1972  * independently from the collection that it is in.
1973  *
1974  * Returns: whether the item is locked or not
1975  */
1976 gboolean
secret_item_get_locked(SecretItem * self)1977 secret_item_get_locked (SecretItem *self)
1978 {
1979 	GVariant *variant;
1980 	gboolean locked;
1981 
1982 	g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE);
1983 
1984 	variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Locked");
1985 	g_return_val_if_fail (variant != NULL, TRUE);
1986 
1987 	locked = g_variant_get_boolean (variant);
1988 	g_variant_unref (variant);
1989 
1990 	return locked;
1991 }
1992 
1993 /**
1994  * secret_item_get_created:
1995  * @self: an item
1996  *
1997  * Get the created date and time of the item. The return value is
1998  * the number of seconds since the unix epoch, January 1st 1970.
1999  *
2000  * Returns: the created date and time
2001  */
2002 guint64
secret_item_get_created(SecretItem * self)2003 secret_item_get_created (SecretItem *self)
2004 {
2005 	GVariant *variant;
2006 	guint64 created;
2007 
2008 	g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE);
2009 
2010 	variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Created");
2011 	g_return_val_if_fail (variant != NULL, 0);
2012 
2013 	created = g_variant_get_uint64 (variant);
2014 	g_variant_unref (variant);
2015 
2016 	return created;
2017 }
2018 
2019 /**
2020  * secret_item_get_modified:
2021  * @self: an item
2022  *
2023  * Get the modified date and time of the item. The return value is
2024  * the number of seconds since the unix epoch, January 1st 1970.
2025  *
2026  * Returns: the modified date and time
2027  */
2028 guint64
secret_item_get_modified(SecretItem * self)2029 secret_item_get_modified (SecretItem *self)
2030 {
2031 	GVariant *variant;
2032 	guint64 modified;
2033 
2034 	g_return_val_if_fail (SECRET_IS_ITEM (self), TRUE);
2035 
2036 	variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (self), "Modified");
2037 	g_return_val_if_fail (variant != NULL, 0);
2038 
2039 	modified = g_variant_get_uint64 (variant);
2040 	g_variant_unref (variant);
2041 
2042 	return modified;
2043 }
2044