[seahorse/wip/nielsdg/pwquality] gkr: Add strength indicator for new passwords



commit fd3ba723b24c794c296b9c84549e778f4c104c3f
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Sat Feb 16 15:25:06 2019 +0100

    gkr: Add strength indicator for new passwords
    
    We add [libpwquality] as a dependency for this (it's already part of
    GNOME's core-deps group).
    
    [libpwquality]: https://github.com/libpwquality/libpwquality

 build-aux/org.gnome.Seahorse.json |  10 ++++
 gkr/gkr-item-add.vala             |  29 +++++++---
 gkr/meson.build                   |   3 +
 gkr/pwquality.vapi                | 116 ++++++++++++++++++++++++++++++++++++++
 gkr/seahorse-gkr-add-item.ui      |  32 +++++++++--
 libseahorse/seahorse.css          |  17 ++++++
 meson.build                       |   1 +
 7 files changed, 195 insertions(+), 13 deletions(-)
---
diff --git a/build-aux/org.gnome.Seahorse.json b/build-aux/org.gnome.Seahorse.json
index a37163a3..ae8700d3 100644
--- a/build-aux/org.gnome.Seahorse.json
+++ b/build-aux/org.gnome.Seahorse.json
@@ -49,6 +49,16 @@
                 }
             ]
         },
+        {
+            "name": "libpwquality",
+            "sources": [
+                {
+                    "type": "archive",
+                    "url": 
"https://github.com/libpwquality/libpwquality/releases/download/libpwquality-1.4.0/libpwquality-1.4.0.tar.bz2";,
+                    "sha256": "a51a0d585ace4ddfb512ff29d80e55db3cb52705113ea9a846a63b9b15ddc9a7"
+                }
+            ]
+        },
         {
             "name": "seahorse",
             "buildsystem": "meson",
diff --git a/gkr/gkr-item-add.vala b/gkr/gkr-item-add.vala
index f27146d4..9e2532b0 100644
--- a/gkr/gkr-item-add.vala
+++ b/gkr/gkr-item-add.vala
@@ -27,7 +27,11 @@ public class Seahorse.Gkr.ItemAdd : Gtk.Dialog {
     [GtkChild]
     private Gtk.Entry item_entry;
     [GtkChild]
-    private Gtk.CheckButton show_password_checkbutton;
+    private Gtk.LevelBar password_strength_bar;
+    [GtkChild]
+    private Gtk.Image password_strength_icon;
+
+    private PasswordQuality.Settings pwquality = new PasswordQuality.Settings();
 
     construct {
         // Load up a list of all the keyrings, and select the default
@@ -49,15 +53,11 @@ public class Seahorse.Gkr.ItemAdd : Gtk.Dialog {
 
         set_response_sensitive(Gtk.ResponseType.ACCEPT, false);
 
-        var buffer = new Gcr.SecureEntryBuffer();
-        this.password_entry = new Gtk.Entry.with_buffer(buffer);
+        this.password_entry = new PasswordEntry();
         this.password_entry.visibility = false;
+        this.password_entry.changed.connect(on_password_entry_changed);
         this.password_area.add(this.password_entry);
         this.password_entry.show();
-
-        this.show_password_checkbutton.toggled.connect(() => {
-            this.password_entry.visibility = this.show_password_checkbutton.active;
-        });
     }
 
     public ItemAdd(Gtk.Window? parent) {
@@ -72,6 +72,21 @@ public class Seahorse.Gkr.ItemAdd : Gtk.Dialog {
         set_response_sensitive(Gtk.ResponseType.ACCEPT, this.item_entry.text != "");
     }
 
+    private void on_password_entry_changed (Gtk.Editable entry) {
+        void* auxerr;
+        int score = this.pwquality.check(entry.get_chars(), null, null, out auxerr);
+
+        if (score < 0) {
+            PasswordQuality.Error err = ((PasswordQuality.Error) score);
+            this.password_strength_icon.tooltip_text = dgettext("libpwquality", err.to_string(auxerr));
+            this.password_strength_icon.show();
+        } else {
+            this.password_strength_icon.hide();
+        }
+
+        this.password_strength_bar.value = ((score / 25) + 1).clamp(1, 5);
+    }
+
     public override void response(int resp) {
         if (resp != Gtk.ResponseType.ACCEPT)
             return;
diff --git a/gkr/meson.build b/gkr/meson.build
index 5cf37db6..e0e671fc 100644
--- a/gkr/meson.build
+++ b/gkr/meson.build
@@ -17,11 +17,14 @@ gkr_dependencies = [
   gcr,
   gcr_ui,
   libsecret,
+  libpwquality,
   common_dep,
 ]
 
 gkr_vala_args = [
   '--gresources', resources_xml,
+  '--vapidir', meson.current_source_dir(),
+  '--pkg=pwquality',
 ]
 
 gkr_lib = static_library('seahorse-gkr',
diff --git a/gkr/pwquality.vapi b/gkr/pwquality.vapi
new file mode 100644
index 00000000..b56557ab
--- /dev/null
+++ b/gkr/pwquality.vapi
@@ -0,0 +1,116 @@
+/* libpwquality Vala Bindings
+ * Copyright 2013 Evan Nemerson <evan coeus-group com>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+[CCode (lower_case_cprefix = "pwquality_", cheader_filename = "pwquality.h")]
+namespace PasswordQuality {
+    [CCode (cname = "int", cprefix = "PWQ_SETTING_", has_type_id = false)]
+    public enum Setting {
+        DIFF_OK,
+        MIN_LENGTH,
+        DIG_CREDIT,
+        UP_CREDIT,
+        LOW_CREDIT,
+        OTH_CREDIT,
+        MIN_CLASS,
+        MAX_REPEAT,
+        DICT_PATH,
+        MAX_CLASS_REPEAT,
+        GECOS_CHECK,
+        BAD_WORDS,
+        MAX_SEQUENCE
+    }
+
+    [CCode (cname = "int", cprefix = "PWQ_ERROR_", has_type_id = false)]
+    public enum Error {
+        SUCCESS,
+        FATAL_FAILURE,
+        INTEGER,
+        CFGFILE_OPEN,
+        CFGFILE_MALFORMED,
+        UNKNOWN_SETTING,
+        NON_INT_SETTING,
+        NON_STR_SETTING,
+        MEM_ALLOC,
+        TOO_SIMILAR,
+        MIN_DIGITS,
+        MIN_UPPERS,
+        MIN_LOWERS,
+        MIN_OTHERS,
+        MIN_LENGTH,
+        PALINDROME,
+        CASE_CHANGES_ONLY,
+        ROTATED,
+        MIN_CLASSES,
+        MAX_CONSECUTIVE,
+        EMPTY_PASSWORD,
+        SAME_PASSWORD,
+        CRACKLIB_CHECK,
+        RNG,
+        GENERATION_FAILED,
+        USER_CHECK,
+        GECOS_CHECK,
+        MAX_CLASS_REPEAT,
+        BAD_WORDS,
+        MAX_SEQUENCE;
+
+        [CCode (cname = "pwquality_strerror", instance_pos = 2.5)]
+        private void* strerror (void* buf, size_t len, void* auxerror);
+
+        public string to_string (void* auxerror = null) {
+            string ret = null;
+            string** retp = &ret;
+            *retp = GLib.malloc (PasswordQuality.MAX_ERROR_MESSAGE_LEN);
+            void* res = this.strerror (*retp, PasswordQuality.MAX_ERROR_MESSAGE_LEN, auxerror);
+
+            if ( res != *retp ) {
+                GLib.Memory.copy (*retp, res, ((string) res).length + 1);
+            }
+
+            return ret;
+        }
+    }
+
+    [CCode (cname = "PWQ_MAX_ENTROPY_BITS")]
+    public const int MAX_ENTROPY_BITS;
+    [CCode (cname = "PWQ_MIN_ENTROPY_BITS")]
+    public const int MIN_ENTROPY_BITS;
+    [CCode (cname = "PWQ_MAX_ERROR_MESSAGE_LEN")]
+    public const int MAX_ERROR_MESSAGE_LEN;
+
+    [Compact, CCode (cname = "pwquality_settings_t", lower_case_cprefix = "pwquality_", free_function = 
"pwquality_free_settings")]
+    public class Settings {
+        [CCode (cname = "pwquality_default_settings")]
+        public Settings ();
+
+        public PasswordQuality.Error read_config (string cfgfile, out void* auxerror);
+        public PasswordQuality.Error set_option (string option);
+        public PasswordQuality.Error set_int_value (PasswordQuality.Setting setting, int value);
+        public PasswordQuality.Error set_str_value (PasswordQuality.Setting setting, string value);
+        public PasswordQuality.Error get_int_value (PasswordQuality.Setting setting, out int value);
+        public PasswordQuality.Error get_str_value (PasswordQuality.Setting setting, out unowned string 
value);
+
+        public PasswordQuality.Error generate (int entropy_bits, out string password);
+        public int check (string password, string? oldpassword = null, string? user = null, out void* 
auxerror = null);
+    }
+}
diff --git a/gkr/seahorse-gkr-add-item.ui b/gkr/seahorse-gkr-add-item.ui
index 714729e1..8564f5f9 100644
--- a/gkr/seahorse-gkr-add-item.ui
+++ b/gkr/seahorse-gkr-add-item.ui
@@ -89,13 +89,33 @@
               </packing>
             </child>
             <child>
-              <object class="GtkCheckButton" id="show_password_checkbutton">
-                <property name="label" translatable="yes">_Show Password</property>
+              <object class="GtkImage" id="password_strength_icon">
                 <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_underline">True</property>
-                <property name="draw_indicator">True</property>
+                <property name="halign">end</property>
+                <property name="icon-name">dialog-warning-symbolic</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+              </object>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="left_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLevelBar" id="password_strength_bar">
+                <property name="visible">True</property>
+                <property name="valign">start</property>
+                <property name="min_value">0</property>
+                <property name="max_value">5</property>
+                <property name="mode">discrete</property>
+                <offsets>
+                  <offset name="strength-weak" value="1"/>
+                  <offset name="strength-low" value="2"/>
+                  <offset name="strength-medium" value="3"/>
+                  <offset name="strength-good" value="4"/>
+                  <offset name="strength-high" value="5"/>
+                </offsets>
               </object>
               <packing>
                 <property name="top_attach">3</property>
diff --git a/libseahorse/seahorse.css b/libseahorse/seahorse.css
index b44b7f83..448eb001 100644
--- a/libseahorse/seahorse.css
+++ b/libseahorse/seahorse.css
@@ -14,3 +14,20 @@
     border-style: solid;
     border-color: shade (@theme_bg_color, 0.66);
 }
+
+levelbar .strength-weak {
+  background-color: #cc0000;
+  border-color: #cc0000;
+}
+
+levelbar .strength-low {
+  background-color: #f5ce00;
+  border-color: #f5ce00;
+}
+
+levelbar .strength-medium,
+levelbar .strength-good,
+levelbar .strength-high {
+  background-color: #73d216;
+  border-color: #73d216;
+}
diff --git a/meson.build b/meson.build
index 02eb7365..e29cc1ff 100644
--- a/meson.build
+++ b/meson.build
@@ -47,6 +47,7 @@ gtk = dependency('gtk+-3.0', version: '>= 3.22.0')
 gcr = dependency('gcr-3',       version: '>=' + min_gcr_version)
 gcr_ui = dependency('gcr-ui-3', version: '>=' + min_gcr_version)
 libsecret = dependency('libsecret-1', version: '>= 0.16')
+libpwquality = dependency('pwquality')
 posix = valac.find_library('posix')
 ssh_bin = find_program('ssh')
 ssh_keygen = find_program('ssh-keygen')


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