[gnome-boxes/remember-passwords] machine: Remember user credentials



commit 2f51e00d0faf818099b86c671fca733918f33da9
Author: Felipe Borges <felipeborges gnome org>
Date:   Wed Jan 17 13:56:14 2018 +0100

    machine: Remember user credentials
    
    It is quite inconvenient -- specially for remote machines -- having
    to enter username and/or password every time we connect to the
    display.
    
    We can store this data safely in the system keyring using libsecret,
    which is already a dependency added in commit 9d99c5a.
    
    Fixes #67

 src/machine.vala | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 76 insertions(+), 7 deletions(-)
---
diff --git a/src/machine.vala b/src/machine.vala
index 677101a7..dbb93d8d 100644
--- a/src/machine.vala
+++ b/src/machine.vala
@@ -20,6 +20,12 @@
     public bool can_delete { get; set; default = true; }
     public bool under_construction { get; protected set; default = false; }
 
+    private Cancellable auth_cancellable = new Cancellable ();
+    private Secret.Schema secret_auth_schema
+            = new Secret.Schema ("org.gnome.Boxes",
+                                 Secret.SchemaFlags.NONE,
+                                 "gnome-boxes-machine-uuid", Secret.SchemaAttributeType.STRING);
+
     public signal void got_error (string message);
 
     protected virtual bool should_autosave {
@@ -592,6 +598,9 @@ private void ui_state_changed () {
                 auth_notification.dismiss ();
             disconnect_display ();
 
+            auth_cancellable.cancel ();
+            auth_cancellable = new Cancellable ();
+
             break;
         }
     }
@@ -618,6 +627,34 @@ private async void try_connect_display (ConnectFlags flags = ConnectFlags.NONE)
         }
     }
 
+    private void store_auth_credentials () {
+        if (this.password == "" || this.password == null)
+            return;
+
+        var builder = new GLib.VariantBuilder (GLib.VariantType.VARDICT);
+
+        if (this.username != null)
+            builder.add ("{sv}", "username", new GLib.Variant ("s", this.username));
+
+        builder.add ("{sv}", "password", new GLib.Variant ("s", this.password));
+
+        var credentials_str = builder.end ().print (true);
+
+        var label = ("GNOME Boxes credentials for '%s'").printf (config.uuid);
+        Secret.password_store.begin (secret_auth_schema,
+                                     Secret.COLLECTION_DEFAULT,
+                                     label,
+                                     credentials_str,
+                                     null,
+                                     (obj, res) => {
+            try {
+                Secret.password_store.end (res);
+            } catch (GLib.Error error) {
+                warning ("Failed to store password for '%s' in the keyring: %s", config.uuid, error.message);
+            }
+        }, "gnome-boxes-machine-uuid", config.uuid);
+    }
+
     private Boxes.AuthNotification auth_notification;
 
     private void handle_auth () {
@@ -634,20 +671,52 @@ private void handle_auth () {
             if (password != "")
                 this.password = password;
 
-            auth_notification = null;
             try_connect_display.begin ();
+
+            /* Maybe this can be an optional preference with a toggle in the UI. */
+            store_auth_credentials ();
         };
+
         Notification.DismissFunc dismiss_func = () => {
             auth_notification = null;
             window.set_state (UIState.COLLECTION);
         };
 
-        // Translators: %s => name of launched box
-        var auth_string = _("ā€œ%sā€ requires authentication").printf (name);
-        auth_notification = window.notificationbar.display_for_auth (auth_string,
-                                                                         (owned) auth_func,
-                                                                         (owned) dismiss_func,
-                                                                         need_username);
+        Secret.password_lookup.begin (secret_auth_schema, auth_cancellable, (obj, res) => {
+            try {
+                var parsing_error = new Boxes.Error.INVALID ("couldn't unpack a string for the machine 
credentials");
+                var credentials_str = Secret.password_lookup.end (res);
+                if (credentials_str == null || credentials_str == "")
+                    throw parsing_error;
+
+                try {
+                    var credentials_variant = GLib.Variant.parse (null, credentials_str, null, null);
+
+                    string username_str;
+                    credentials_variant.lookup ("username", "s", out username_str);
+                    if (username_str != null && username_str != "")
+                        this.username = username_str;
+
+                    string password_str;
+                    credentials_variant.lookup ("password", "s", out password_str);
+                    if (password_str != null && password_str != "")
+                        this.password = password_str;
+
+                    try_connect_display.begin ();
+                } catch (GLib.Error error) {
+                    throw parsing_error;
+                }
+            } catch (GLib.Error error) {
+                debug ("No credentials found in keyring. Prompting user.");
+
+                // Translators: %s => name of launched box
+                var auth_string = _("ā€œ%sā€ requires authentication").printf (name);
+                auth_notification = window.notificationbar.display_for_auth (auth_string,
+                                                                             (owned) auth_func,
+                                                                             (owned) dismiss_func,
+                                                                             need_username);
+            }
+        }, "gnome-boxes-machine-uuid", config.uuid);
     }
 
     public override int compare (CollectionItem other) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]