[shotwell/wip/phako/libsecret: 15/15] wip: Store online service secrets with libsecret



commit c6e8b153d69b68ba65ae2db82fa35a1e679cd18f
Author: Jens Georg <mail jensge org>
Date:   Sat Jun 9 02:13:15 2018 +0200

    wip: Store online service secrets with libsecret

 flatpak/org.gnome.Shotwell.json                    |  3 +-
 meson.build                                        |  1 +
 .../shotwell/FlickrPublishingAuthenticator.vala    |  2 +-
 .../shotwell/GoogleAuthenticator.vala              | 34 +++++++--
 .../shotwell/OAuth1Authenticator.vala              | 83 ++++++++++++++++++----
 .../shotwell/TumblrAuthenticator.vala              |  2 +-
 plugins/authenticator/shotwell/meson.build         |  2 +-
 .../GalleryConnector.vala                          | 35 ++++++++-
 .../RajcePublishing.vala                           | 40 ++++++++++-
 .../YandexPublishing.vala                          | 28 ++++++--
 plugins/shotwell-publishing-extras/meson.build     |  2 +-
 plugins/shotwell-publishing/PiwigoPublishing.vala  | 56 ++++++++++++---
 plugins/shotwell-publishing/meson.build            |  2 +-
 13 files changed, 246 insertions(+), 44 deletions(-)
---
diff --git a/flatpak/org.gnome.Shotwell.json b/flatpak/org.gnome.Shotwell.json
index 29ec23be..b55c4fa0 100644
--- a/flatpak/org.gnome.Shotwell.json
+++ b/flatpak/org.gnome.Shotwell.json
@@ -27,7 +27,8 @@
         "--talk-name=org.gnome.SettingsDaemon",
         "--talk-name=org.gtk.vfs",
         "--talk-name=org.gtk.vfs.*",
-        "--env=GSETTINGS_BACKEND=dconf"
+        "--env=GSETTINGS_BACKEND=dconf",
+        "--talk-name=org.freedesktop.secrets"
     ],
     "cleanup" : [
         "/include",
diff --git a/meson.build b/meson.build
index 6a06b349..143e9190 100644
--- a/meson.build
+++ b/meson.build
@@ -64,6 +64,7 @@ gexiv2 = dependency('gexiv2', version: '>= 0.11.0')
 libraw = dependency('libraw', version : '>= 0.13.2')
 libexif = dependency('libexif', version : '>= 0.6.16')
 unity = dependency('unity', required : false)
+secret = dependency('libsecret-1', required: true)
 champlain = dependency('champlain-0.12', version: '>= 0.12.16')
 champlain_gtk = dependency('champlain-gtk-0.12')
 clutter = dependency('clutter-1.0')
diff --git a/plugins/authenticator/shotwell/FlickrPublishingAuthenticator.vala 
b/plugins/authenticator/shotwell/FlickrPublishingAuthenticator.vala
index 82448e26..49eacf73 100644
--- a/plugins/authenticator/shotwell/FlickrPublishingAuthenticator.vala
+++ b/plugins/authenticator/shotwell/FlickrPublishingAuthenticator.vala
@@ -90,7 +90,7 @@ namespace Publishing.Authenticator.Shotwell.Flickr {
         private WebAuthenticationPane pane;
 
         public Flickr(Spit.Publishing.PluginHost host) {
-            base(API_KEY, API_SECRET, host);
+            base("Flickr", API_KEY, API_SECRET, host);
         }
 
         public override void authenticate() {
diff --git a/plugins/authenticator/shotwell/GoogleAuthenticator.vala 
b/plugins/authenticator/shotwell/GoogleAuthenticator.vala
index 5b38ee66..815df2fa 100644
--- a/plugins/authenticator/shotwell/GoogleAuthenticator.vala
+++ b/plugins/authenticator/shotwell/GoogleAuthenticator.vala
@@ -112,12 +112,15 @@ namespace Publishing.Authenticator.Shotwell.Google {
     }
 
     internal class Google : Spit.Publishing.Authenticator, Object {
+        private const string PASSWORD_SCHEME = "org.gnome.Shotwell.Google";
+
         private string scope = null;
         private Spit.Publishing.PluginHost host = null;
         private GLib.HashTable<string, Variant> params = null;
         private WebAuthenticationPane web_auth_pane = null;
         private Session session = null;
         private string welcome_message = null;
+        private Secret.Schema? schema = null;
 
         public Google(string scope,
                       string welcome_message,
@@ -127,10 +130,17 @@ namespace Publishing.Authenticator.Shotwell.Google {
             this.scope = scope;
             this.session = new Session();
             this.welcome_message = welcome_message;
+            this.schema = new Secret.Schema (PASSWORD_SCHEME, Secret.SchemaFlags.NONE,
+                                             "scope", Secret.SchemaAttributeType.STRING);
         }
 
         public void authenticate() {
-            var refresh_token = host.get_config_string("refresh_token", null);
+            string? refresh_token = null;
+            try {
+                refresh_token = Secret.password_lookup_sync(this.schema, null, "scope", this.scope);
+            } catch (Error err) {
+                critical("Failed to lookup refresh_token from password store: %s", err.message);
+            }
             if (refresh_token != null && refresh_token != "") {
                 on_refresh_token_available(refresh_token);
                 do_exchange_refresh_token_for_access_token();
@@ -157,7 +167,11 @@ namespace Publishing.Authenticator.Shotwell.Google {
 
         public void logout() {
             session.deauthenticate();
-            host.set_config_string("refresh_token", "");
+            try {
+                Secret.password_clear_sync(this.schema, null, "scope", this.scope);
+            } catch (Error err) {
+                critical("Failed to remove password for scope %s: %s", this.scope, err.message);
+            }
         }
 
         public void refresh() {
@@ -368,12 +382,17 @@ namespace Publishing.Authenticator.Shotwell.Google {
             // by the time we get a username, the session should be authenticated, or else something
             // really tragic has happened
             assert(session.is_authenticated());
-            host.set_config_string("refresh_token", session.refresh_token);
+            try {
+                Secret.password_store_sync(this.schema, Secret.COLLECTION_DEFAULT,
+                    "Shotwell publishing (Google account scope %s)".printf(this.scope),
+                    session.refresh_token, null, "scope", this.scope);
+            } catch (Error err) {
+                critical("Failed to look up password for scope %s: %s", this.scope, err.message);
+            }
 
             this.authenticated();
         }
 
-
         private void do_exchange_refresh_token_for_access_token() {
             debug("ACTION: exchanging OAuth refresh token for OAuth access token.");
 
@@ -416,7 +435,12 @@ namespace Publishing.Authenticator.Shotwell.Google {
             if (txn.get_status_code() == Soup.Status.BAD_REQUEST ||
                 txn.get_status_code() == Soup.Status.UNAUTHORIZED) {
                 // Refresh token invalid, starting over
-                host.set_config_string("refresh_token", "");
+                try {
+                    Secret.password_clear_sync(this.schema, null, "scope", this.scope);
+                } catch (Error err) {
+                    critical("Failed to remove password for scope %s: %s", this.scope, err.message);
+                }
+
                 Idle.add (() => { this.authenticate(); return false; });
             }
 
diff --git a/plugins/authenticator/shotwell/OAuth1Authenticator.vala 
b/plugins/authenticator/shotwell/OAuth1Authenticator.vala
index 39752ece..ca19dc17 100644
--- a/plugins/authenticator/shotwell/OAuth1Authenticator.vala
+++ b/plugins/authenticator/shotwell/OAuth1Authenticator.vala
@@ -11,10 +11,18 @@ namespace Publishing.Authenticator.Shotwell.OAuth1 {
         protected GLib.HashTable<string, Variant> params;
         protected Publishing.RESTSupport.OAuth1.Session session;
         protected Spit.Publishing.PluginHost host;
+        private Secret.Schema? schema = null;
+        private const string SECRET_TYPE_USERNAME = "username";
+        private const string SECRET_TYPE_AUTH_TOKEN = "auth-token";
+        private const string SECRET_TYPE_AUTH_TOKEN_SECRET = "auth-token-secret";
+        private string service = null;
 
-        protected Authenticator(string api_key, string api_secret, Spit.Publishing.PluginHost host) {
+        protected Authenticator(string service, string api_key, string api_secret, 
Spit.Publishing.PluginHost host) {
             base();
             this.host = host;
+            this.service = service;
+            this.schema = new Secret.Schema ("org.gnome.Shotwell." + service, Secret.SchemaFlags.NONE,
+                                             "type", Secret.SchemaAttributeType.STRING);
 
             params = new GLib.HashTable<string, Variant>(str_hash, str_equal);
             params.insert("ConsumerKey", api_key);
@@ -43,9 +51,9 @@ namespace Publishing.Authenticator.Shotwell.OAuth1 {
         public abstract void refresh();
 
         public void invalidate_persistent_session() {
-            set_persistent_access_phase_token("");
-            set_persistent_access_phase_token_secret("");
-            set_persistent_access_phase_username("");
+            set_persistent_access_phase_token(null);
+            set_persistent_access_phase_token_secret(null);
+            set_persistent_access_phase_username(null);
         }
         protected bool is_persistent_session_valid() {
             return (get_persistent_access_phase_username() != null &&
@@ -54,27 +62,76 @@ namespace Publishing.Authenticator.Shotwell.OAuth1 {
         }
 
         protected string? get_persistent_access_phase_username() {
-            return host.get_config_string("access_phase_username", null);
+            try {
+                return Secret.password_lookup_sync(this.schema, null, "type", SECRET_TYPE_USERNAME);
+            } catch (Error err) {
+                critical("Failed to lookup username from password store: %s", err.message);
+                return null;
+            }
         }
 
-        protected void set_persistent_access_phase_username(string username) {
-            host.set_config_string("access_phase_username", username);
+        protected void set_persistent_access_phase_username(string? username) {
+            try {
+                if (username == null || username == "") {
+                    Secret.password_clear_sync(this.schema, null,
+                                               "type", SECRET_TYPE_USERNAME);
+                } else {
+                    Secret.password_store_sync(this.schema, Secret.COLLECTION_DEFAULT,
+                                               "Shotwell publishing (%s)".printf(this.service),
+                                               username, null, "type", SECRET_TYPE_USERNAME);
+                }
+            } catch (Error err) {
+                critical("Failed to store username in store: %s", err.message);
+            }
         }
 
         protected string? get_persistent_access_phase_token() {
-            return host.get_config_string("access_phase_token", null);
+            try {
+                return Secret.password_lookup_sync(this.schema, null,
+                                                   "type", SECRET_TYPE_AUTH_TOKEN);
+            } catch (Error err) {
+                critical("Failed to lookup auth-token from password store: %s", err.message);
+                return null;
+            }
         }
 
-        protected void set_persistent_access_phase_token(string token) {
-            host.set_config_string("access_phase_token", token);
+        protected void set_persistent_access_phase_token(string? token) {
+            try {
+                if (token == null || token == "") {
+                    Secret.password_clear_sync(this.schema, null,
+                                               "type", SECRET_TYPE_AUTH_TOKEN);
+                } else {
+                    Secret.password_store_sync(this.schema, Secret.COLLECTION_DEFAULT,
+                                               "Shotwell publishing (%s)".printf(this.service),
+                                               token, null, "type", SECRET_TYPE_AUTH_TOKEN);
+                }
+            } catch (Error err) {
+                critical("Failed to store auth-token store: %s", err.message);
+            }
         }
 
         protected string? get_persistent_access_phase_token_secret() {
-            return host.get_config_string("access_phase_token_secret", null);
+            try {
+                return Secret.password_lookup_sync(this.schema, null, "type", SECRET_TYPE_AUTH_TOKEN_SECRET);
+            } catch (Error err) {
+                critical("Failed to lookup auth-token-secret from password store: %s", err.message);
+                return null;
+            }
         }
 
-        protected void set_persistent_access_phase_token_secret(string secret) {
-            host.set_config_string("access_phase_token_secret", secret);
+        protected void set_persistent_access_phase_token_secret(string? secret) {
+            try {
+                if (secret == null || secret == "") {
+                    Secret.password_clear_sync(this.schema, null,
+                                               "type", SECRET_TYPE_AUTH_TOKEN_SECRET);
+                } else {
+                    Secret.password_store_sync(this.schema, Secret.COLLECTION_DEFAULT,
+                                               "Shotwell publishing (%s)".printf(this.service),
+                                               secret, null, "type", SECRET_TYPE_AUTH_TOKEN_SECRET);
+                }
+            } catch (Error err) {
+                critical("Failed to store auth-token-secret store: %s", err.message);
+            }
         }
 
 
diff --git a/plugins/authenticator/shotwell/TumblrAuthenticator.vala 
b/plugins/authenticator/shotwell/TumblrAuthenticator.vala
index 35fdce98..72904d52 100644
--- a/plugins/authenticator/shotwell/TumblrAuthenticator.vala
+++ b/plugins/authenticator/shotwell/TumblrAuthenticator.vala
@@ -127,7 +127,7 @@ namespace Publishing.Authenticator.Shotwell.Tumblr {
 
     internal class Tumblr : Publishing.Authenticator.Shotwell.OAuth1.Authenticator {
         public Tumblr(Spit.Publishing.PluginHost host) {
-            base(API_KEY, API_SECRET, host);
+            base("Tumblr", API_KEY, API_SECRET, host);
         }
 
         public override void authenticate() {
diff --git a/plugins/authenticator/shotwell/meson.build b/plugins/authenticator/shotwell/meson.build
index b1a6fd2b..b43b889e 100644
--- a/plugins/authenticator/shotwell/meson.build
+++ b/plugins/authenticator/shotwell/meson.build
@@ -11,7 +11,7 @@ authenticator_shotwell_resources = gnome.compile_resources('authenticator-resour
         source_dir : meson.source_root())
 
 authenticator_shotwell_deps = [gee, gtk, gio, soup, json_glib, sw_plugin,
-                               sw_plugin_common_dep, json_glib, xml, webkit]
+                               sw_plugin_common_dep, json_glib, xml, webkit, secret]
 
 authenticator = library('shotwell-authenticator',
                         authenticator_shotwell_sources + authenticator_shotwell_resources,
diff --git a/plugins/shotwell-publishing-extras/GalleryConnector.vala 
b/plugins/shotwell-publishing-extras/GalleryConnector.vala
index 9932862a..2af20871 100644
--- a/plugins/shotwell-publishing-extras/GalleryConnector.vala
+++ b/plugins/shotwell-publishing-extras/GalleryConnector.vala
@@ -65,6 +65,7 @@ public class Gallery3Service : Object, Spit.Pluggable,
         if (icon_pixbuf_set == null)
             icon_pixbuf_set = Resources.load_from_resource
                 (Resources.RESOURCE_PATH + "/" + ICON_FILENAME);
+
     }
 
     public int get_pluggable_interface(int min_host_interface,
@@ -798,6 +799,7 @@ private class GalleryUploadTransaction :
 
 
 public class GalleryPublisher : Spit.Publishing.Publisher, GLib.Object {
+    private const string PASSWORD_SCHEME = "org.gnome.Shotwell.Gallery3";
     private const string BAD_FILE_MSG = _("\n\nThe file ā€œ%sā€ may not be supported by or may be too large for 
this instance of Gallery3.");
     private const string BAD_MOVIE_MSG = _("\nNote that Gallery3 only supports the video types that 
Flowplayer does.");
 
@@ -808,6 +810,7 @@ public class GalleryPublisher : Spit.Publishing.Publisher, GLib.Object {
     private bool running = false;
     private Album[] albums = null;
     private string key = null;
+    private Secret.Schema? schema = null;
 
     private PublishingOptionsPane publishing_options_pane = null;
 
@@ -816,6 +819,9 @@ public class GalleryPublisher : Spit.Publishing.Publisher, GLib.Object {
         this.service = service;
         this.host = host;
         this.session = new Session();
+        this.schema = new Secret.Schema (PASSWORD_SCHEME, Secret.SchemaFlags.NONE,
+                                        "url", Secret.SchemaAttributeType.STRING,
+                                        "user", Secret.SchemaAttributeType.STRING);
     }
 
     public bool is_running() {
@@ -872,11 +878,34 @@ public class GalleryPublisher : Spit.Publishing.Publisher, GLib.Object {
     // Config getters/setters
     // API key
     internal string? get_api_key() {
-        return host.get_config_string("api-key", null);
+        var user = get_gallery_username();
+        var url = get_gallery_url();
+
+        try {
+            return Secret.password_lookup_sync(this.schema, null, "url", url, "user", user);
+        } catch (Error err) {
+            critical ("Failed to get api key for %s@%s: %s", user, url, err.message);
+        }
+
+        return null;
     }
 
-    internal void set_api_key(string key) {
-        host.set_config_string("api-key", key);
+    internal void set_api_key(string? key) {
+        var user = get_gallery_username();
+        var url = get_gallery_url();
+        try {
+            if (key == null | key == "") {
+                Secret.password_clear_sync(this.schema, null, "url", url, "user", user);
+            } else {
+                Secret.password_store_sync(this.schema, Secret.COLLECTION_DEFAULT,
+                                           "Shotwell publishing (Gallery3 account %s@%s)".printf(user, url),
+                                           key,
+                                           null,
+                                           "url", url, "user", user);
+            }
+        } catch (Error err) {
+            critical("Failed to store api key for %s@%s: %s", user, url, err.message);
+        }
     }
 
     // URL
diff --git a/plugins/shotwell-publishing-extras/RajcePublishing.vala 
b/plugins/shotwell-publishing-extras/RajcePublishing.vala
index a0882747..ab27863d 100644
--- a/plugins/shotwell-publishing-extras/RajcePublishing.vala
+++ b/plugins/shotwell-publishing-extras/RajcePublishing.vala
@@ -65,6 +65,7 @@ namespace Publishing.Rajce
 
 public class RajcePublisher : Spit.Publishing.Publisher, GLib.Object
 {
+    private const string PASSWORD_SCHEME = "org.gnome.Shotwell.Rajce";
     private Spit.Publishing.PluginHost host = null;
     private Spit.Publishing.ProgressCallback progress_reporter = null;
     private Spit.Publishing.Service service = null;
@@ -80,6 +81,7 @@ public class RajcePublisher : Spit.Publishing.Publisher, GLib.Object
     private Album[] albums = null;
     private PublishingParameters parameters = null;
     private Spit.Publishing.Publisher.MediaType media_type = Spit.Publishing.Publisher.MediaType.NONE;
+    private Secret.Schema schema = null;
 
     public RajcePublisher(Spit.Publishing.Service service, Spit.Publishing.PluginHost host)
        {
@@ -90,6 +92,9 @@ public class RajcePublisher : Spit.Publishing.Publisher, GLib.Object
         
         foreach(Spit.Publishing.Publishable p in host.get_publishables())
             media_type |= p.get_media_type();
+
+        this.schema = new Secret.Schema(PASSWORD_SCHEME, Secret.SchemaFlags.NONE,
+                                        "user", Secret.SchemaAttributeType.STRING);
     }
     
     private string get_rajce_url()
@@ -140,8 +145,39 @@ public class RajcePublisher : Spit.Publishing.Publisher, GLib.Object
     public string? get_url() { return get_rajce_url(); }
     public string? get_username() { return host.get_config_string("username", null); }
     private void set_username(string username) { host.set_config_string("username", username); }
-    public string? get_token() { return host.get_config_string("token", null); }
-    private void set_token(string? token) { host.set_config_string("token", token); }
+    public string? get_token() {
+        var user = get_username();
+        if (user == null)
+            return null;
+
+        try {
+            return Secret.password_lookup_sync(this.schema, null, "user", user);
+        } catch (Error err) {
+            critical("Failed to get token for user %s: %s", user, err.message);
+        }
+
+        return null;
+    }
+
+    private void set_token(string? token) {
+        var user = get_username();
+        if (user == null)
+            return;
+
+        try {
+            if (token == null || token == "") {
+                Secret.password_clear_sync(this.schema, null, "user", user);
+            } else {
+                Secret.password_store_sync(this.schema, Secret.COLLECTION_DEFAULT,
+                                           "Shotwell publishing (Rajce user %s)".printf(user),
+                                           token,
+                                           null,
+                                           "user", user);
+            }
+        } catch (Error err) {
+            critical("Failed to store token for user %s: %s", user, err.message);
+        }
+    }
 //    public int get_last_photo_size() { return host.get_config_int("last-photo-size", -1); }
 //    private void set_last_photo_size(int last_photo_size) { host.set_config_int("last-photo-size", 
last_photo_size); }
     public bool get_remember() { return host.get_config_bool("remember", false); }
diff --git a/plugins/shotwell-publishing-extras/YandexPublishing.vala 
b/plugins/shotwell-publishing-extras/YandexPublishing.vala
index 2680df07..51bf2940 100644
--- a/plugins/shotwell-publishing-extras/YandexPublishing.vala
+++ b/plugins/shotwell-publishing-extras/YandexPublishing.vala
@@ -296,6 +296,7 @@ private class UploadTransaction: Transaction {
 }
 
 public class YandexPublisher : Spit.Publishing.Publisher, GLib.Object {
+    private const string PASSWORD_SCHEME = "org.gnome.Shotwell.Yandex";
     private weak Spit.Publishing.PluginHost host = null;
     private Spit.Publishing.ProgressCallback progress_reporter = null;
     private weak Spit.Publishing.Service service = null;
@@ -310,6 +311,7 @@ public class YandexPublisher : Spit.Publishing.Publisher, GLib.Object {
     private WebAuthPane web_auth_pane = null;
 
     private Session session;
+    private Secret.Schema? schema = null;
 
     public YandexPublisher(Spit.Publishing.Service service, Spit.Publishing.PluginHost host) {
         this.service = service;
@@ -317,18 +319,36 @@ public class YandexPublisher : Spit.Publishing.Publisher, GLib.Object {
         this.session = new Session();
         this.album_list = new Gee.HashMap<string, string>();
         this.options = new PublishOptions();
+        this.schema = new Secret.Schema (PASSWORD_SCHEME, Secret.SchemaFlags.NONE);
     }
 
     internal string? get_persistent_auth_token() {
-        return host.get_config_string("auth_token", null);
+        try {
+            return Secret.password_lookup_sync(this.schema, null);
+        } catch (Error err) {
+            critical ("Failed to get api key for yandex: %s", err.message);
+        }
+
+        return null;
     }
     
-    internal void set_persistent_auth_token(string auth_token) {
-        host.set_config_string("auth_token", auth_token);
+    internal void set_persistent_auth_token(string? auth_token) {
+        try {
+            if (auth_token == null | auth_token == "") {
+                Secret.password_clear_sync(this.schema, null);
+            } else {
+                Secret.password_store_sync(this.schema, Secret.COLLECTION_DEFAULT,
+                                           "Shotwell publishing (Yandex)",
+                                           auth_token,
+                                           null);
+            }
+        } catch (Error err) {
+            critical("Failed to store api key: %s", err.message);
+        }
     }
 
     internal void invalidate_persistent_session() {
-        host.unset_config_key("auth_token");
+        set_persistent_auth_token(null);
     }
     
     internal bool is_persistent_session_available() {
diff --git a/plugins/shotwell-publishing-extras/meson.build b/plugins/shotwell-publishing-extras/meson.build
index 34f3e125..3f7845a6 100644
--- a/plugins/shotwell-publishing-extras/meson.build
+++ b/plugins/shotwell-publishing-extras/meson.build
@@ -11,7 +11,7 @@ shotwell_publishing_extra_resources = gnome.compile_resources('publishing-extra-
 shared_module('shotwell-publishing-extras',
               shotwell_publishing_extra_sources + shotwell_publishing_extra_resources,
               dependencies : [gee, gtk, xml, soup, gdk_pixbuf, sw_plugin,
-                              sw_plugin_common_dep, json_glib, webkit],
+                              sw_plugin_common_dep, json_glib, webkit, secret],
               vala_args : [
                   '--gresources', 'org.gnome.Shotwell.Publishing.Extras.gresource.xml'
                   ],
diff --git a/plugins/shotwell-publishing/PiwigoPublishing.vala 
b/plugins/shotwell-publishing/PiwigoPublishing.vala
index 58d638e7..ce91e529 100644
--- a/plugins/shotwell-publishing/PiwigoPublishing.vala
+++ b/plugins/shotwell-publishing/PiwigoPublishing.vala
@@ -124,6 +124,8 @@ internal class PublishingParameters {
 }
 
 public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object {
+    private const string PASSWORD_SCHEME = "org.gnome.Shotwell.Piwigo";
+
     private Spit.Publishing.Service service;
     private Spit.Publishing.PluginHost host;
     private bool running = false;
@@ -132,6 +134,7 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object {
     private Category[] categories = null;
     private PublishingParameters parameters = null;
     private Spit.Publishing.ProgressCallback progress_reporter = null;
+    private Secret.Schema? schema = null;
 
     public PiwigoPublisher(Spit.Publishing.Service service,
         Spit.Publishing.PluginHost host) {
@@ -139,6 +142,9 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object {
         this.service = service;
         this.host = host;
         session = new Session();
+        this.schema = new Secret.Schema (PASSWORD_SCHEME, Secret.SchemaFlags.NONE,
+                                         "url", Secret.SchemaAttributeType.STRING,
+                                         "user", Secret.SchemaAttributeType.STRING);
     }
 
     // Publisher interface implementation
@@ -170,7 +176,9 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object {
             debug("PiwigoPublisher: session is not authenticated.");
             string? persistent_url = get_persistent_url();
             string? persistent_username = get_persistent_username();
-            string? persistent_password = get_persistent_password();
+            string? persistent_password = get_persistent_password(persistent_url, persistent_username);
+
+            // This will only be null if either of the other two was null or the password did not exist
             if (persistent_url != null && persistent_username != null && persistent_password != null)
                 do_network_login(persistent_url, persistent_username,
                     persistent_password, get_remember_password());
@@ -201,12 +209,37 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object {
         host.set_config_string("username", username);
     }
     
-    public string? get_persistent_password() {
-        return host.get_config_string("password", null);
+    public string? get_persistent_password(string? url, string? user) {
+        if (url != null && user != null) {
+            try {
+                var pw = Secret.password_lookup_sync(this.schema, null, "url", url, "user", user);
+
+                return pw;
+            } catch (Error err) {
+                critical("Failed to lookup the password for url %s and user %s: %s", url, user, err.message);
+
+                return null;
+            }
+        }
+
+        return null;
     }
     
-    private void set_persistent_password(string? password) {
-        host.set_config_string("password", password);
+    private void set_persistent_password(string? url, string? user, string? password) {
+        try {
+            if (password == null) {
+                // remove
+                Secret.password_clear_sync(this.schema, null, "url", url, "user", user);
+            } else {
+                Secret.password_store_sync(this.schema, Secret.COLLECTION_DEFAULT,
+                        "Shotwell publishing (Piwigo account %s@%s)".printf(user, url),
+                        password,
+                        null,
+                        "url", url, "user", user);
+            }
+        } catch (Error err) {
+            critical("Failed to store password for %s@%s: %s", user, url, err.message);
+        }
     }
     
     public bool get_remember_password() {
@@ -309,7 +342,7 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object {
 
             string? persistent_url = get_persistent_url();
             string? persistent_username = get_persistent_username();
-            string? persistent_password = get_persistent_password();
+            string? persistent_password = get_persistent_password(persistent_url, persistent_username);
             if (persistent_url != null && persistent_username != null && persistent_password != null)
                 do_network_login(persistent_url, persistent_username,
                     persistent_password, get_remember_password());
@@ -359,10 +392,11 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object {
         host.install_login_wait_pane();
         
         set_remember_password(remember_password);
-        if (remember_password)
-            set_persistent_password(password);
-        else
-            set_persistent_password(null);
+        if (remember_password) {
+            set_persistent_password(url, username, password);
+        } else {
+            set_persistent_password(url, username, null);
+        }
 
         SessionLoginTransaction login_trans = new SessionLoginTransaction(
             session, normalise_url(url), username, password);
@@ -1147,7 +1181,7 @@ internal class AuthenticationPane : Shotwell.Plugins.Common.BuilderPane {
             username_entry.set_text(persistent_username);
         }
         password_entry = builder.get_object ("password_entry") as Gtk.Entry;
-        string? persistent_password = publisher.get_persistent_password();
+        string? persistent_password = publisher.get_persistent_password(persistent_url, persistent_username);
         if (persistent_password != null) {
             password_entry.set_text(persistent_password);
         }
diff --git a/plugins/shotwell-publishing/meson.build b/plugins/shotwell-publishing/meson.build
index a5f9ed8f..18c101aa 100644
--- a/plugins/shotwell-publishing/meson.build
+++ b/plugins/shotwell-publishing/meson.build
@@ -18,7 +18,7 @@ shared_module('shotwell-publishing',
               shotwell_publishing_sources + shotwell_publishing_resources,
               dependencies : [gtk, soup, gexiv2, gee, sw_plugin, json_glib,
                               webkit, sw_plugin_common_dep, xml, gdata, gcr,
-                              gcr_ui, authenticator_dep],
+                              gcr_ui, authenticator_dep, secret],
               c_args : ['-DPLUGIN_RESOURCE_PATH="/org/gnome/Shotwell/Publishing"',
                         '-DGCR_API_SUBJECT_TO_CHANGE'],
               install: true,


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