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