]> git.ipfire.org Git - ipfire.org.git/commitdiff
people: Check password quality before submitting to server
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 23 Oct 2018 10:12:04 +0000 (11:12 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 23 Oct 2018 10:12:04 +0000 (11:12 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/templates/people/modules/password.html [new file with mode: 0644]
src/templates/people/modules/password.js [new file with mode: 0644]
src/templates/people/passwd.html
src/web/__init__.py
src/web/people.py

index 7a3ef5870e50f24cbfeed9fb7c735e8de10e15eb..d616ec5b5e9f05e6058ac76f5d6aed34de78e882 100644 (file)
@@ -181,6 +181,8 @@ templates_people_modules_DATA = \
        src/templates/people/modules/cdr.html \
        src/templates/people/modules/channels.html \
        src/templates/people/modules/mos.html \
+       src/templates/people/modules/password.html \
+       src/templates/people/modules/password.js \
        src/templates/people/modules/registrations.html \
        src/templates/people/modules/sip-status.html
 
@@ -305,7 +307,10 @@ static_js_DATA = \
        \
        src/static/js/jquery-3.3.1.min.js \
        src/static/js/popper.min.js \
-       src/static/js/prettify.js
+       src/static/js/prettify.js \
+       \
+       src/static/js/zxcvbn/dist/zxcvbn.js \
+       src/static/js/zxcvbn/dist/zxcvbn.js.map
 
 static_jsdir = $(staticdir)/js
 
diff --git a/src/templates/people/modules/password.html b/src/templates/people/modules/password.html
new file mode 100644 (file)
index 0000000..a70b405
--- /dev/null
@@ -0,0 +1,32 @@
+<fieldset>
+       <div class="form-group">
+               <label>{{ _("New Password") }}</label>
+
+               <input type="password" class="form-control" name="password1"
+                       id="password1" placeholder="{{ _("New Password") }}" required
+                       data-user-input="{{ " ".join((account.first_name, account.last_name)) }}">
+       </div>
+
+       <div class="form-group">
+               <input type="password" class="form-control" name="password2"
+                       id="password2" placeholder="{{ _("Repeat Password") }}" required>
+
+               <div id="password-mismatch" class="invalid-feedback">
+                       {{ _("Passwords do not match") }}
+               </div>
+       </div>
+
+       <div class="form-group">
+               <div class="progress">
+                       <div class="progress-bar" id="password-strength" role="progressbar"></div>
+               </div>
+       </div>
+
+       <div class="form-group text-muted">
+               <p class="mb-0" id="password-warning"></p>
+
+               <small class="form-text">
+                       <ul id="password-feedback"></ul>
+               </small>
+       </div>
+</fieldset>
diff --git a/src/templates/people/modules/password.js b/src/templates/people/modules/password.js
new file mode 100644 (file)
index 0000000..e20ed56
--- /dev/null
@@ -0,0 +1,79 @@
+$(function() {
+    var progress = $("#password-strength");
+    var warning  = $("#password-warning");
+    var feedback = $("#password-feedback");
+
+    $("#password1").keyup(function(event) {
+        var password1 = $(this).val();
+
+        // Fetch words that are common to the user
+        var user_inputs = $(this).data("user-input").split(" ");    
+
+        if (password1) {
+            // Estimate password quality
+            var quality = zxcvbn(password1, user_inputs);
+
+            // Convert score into percentage
+            var percentage = (quality.score + 1) * 20;
+
+            // Set progress bar width
+            progress.css("width", percentage + "%");
+
+            // Clear all previous backgrounds
+            progress.removeClass([
+                "bg-success", "bg-warning", "bg-danger"
+            ]);
+
+            // Make progress bar show in the right colour
+            switch (quality.score) {
+                case 0:
+                case 1:
+                case 2:
+                    progress.addClass("bg-danger");
+                    break;
+
+                case 3:
+                    progress.addClass("bg-warning");
+                    break;
+
+                case 4:
+                    progress.addClass("bg-success");
+                    break;
+            }
+
+            // Show any feedback
+            warning.empty();
+            feedback.empty();
+
+            if (quality.feedback) {
+                if (quality.feedback.warning) {
+                    warning.html(quality.feedback.warning);
+                }
+
+                $.each(quality.feedback.suggestions, function (i, suggestion) {
+                    feedback.append("<li>" + suggestion + "</li>");
+                });
+            }
+        } else {
+            progress.css("width", "0%");
+
+            // Clear all feedback
+            warning.empty();
+            feedback.empty();
+        }
+    });
+
+    $("input[type=submit]").click( function(event) {
+        var password1 = $("#password1");
+        var password2 = $("#password2");
+
+        // If the passwords match, we allow to submit the form
+        if (password1.val() === password2.val()) {
+            return true;
+
+        } else {
+            $("#password-mismatch").show();
+            return false;
+        }
+    });
+});
index abb3421f2da30fb9d9ca6a6ff7ef393a9104aac2..8285e71b49774cd2387797b4b32ab3bf495dfdc8 100644 (file)
                                                placeholder="{{ _("Current Password") }}">
                                </div>
 
-                               <fieldset>
-                                       <div class="form-group">
-                                               <label>{{ _("New Password") }}</label>
-
-                                               <input type="password" class="form-control" name="password1"
-                                                       placeholder="{{ _("New Password") }}">
-                                       </div>
-
-                                       <div class="form-group">
-                                               <input type="password" class="form-control" name="password2"
-                                                       placeholder="{{ _("Repeat Password") }}">
-                                       </div>
-                               </fieldset>
+                               {% module Password(account) %}
 
                                <input class="btn btn-primary btn-block" type="submit" value="{{ _("Change Password") }}">
                        </form>
index 84d0e501beacca63b096a760d95e35b3a763ae6c..96a97448dc6100091160275508896acafb3c6f82 100644 (file)
@@ -64,6 +64,7 @@ class Application(tornado.web.Application):
                                "CDR"                  : people.CDRModule,
                                "Channels"             : people.ChannelsModule,
                                "MOS"                  : people.MOSModule,
+                               "Password"             : people.PasswordModule,
                                "Registrations"        : people.RegistrationsModule,
                                "SIPStatus"            : people.SIPStatusModule,
 
index 7fbbe34d2ffd1d11036c7bf51bd6b3f242881acd..45955e6b49f0ae860ca658ed71b5e5a45c9e6551 100644 (file)
@@ -371,6 +371,17 @@ class MOSModule(ui_modules.UIModule):
                return self.render_string("people/modules/mos.html", call=call)
 
 
+class PasswordModule(ui_modules.UIModule):
+       def render(self, account):
+               return self.render_string("people/modules/password.html", account=account)
+
+       def javascript_files(self):
+               return "js/zxcvbn.js"
+
+       def embedded_javascript(self):
+               return self.render_string("people/modules/password.js")
+
+
 class RegistrationsModule(ui_modules.UIModule):
        def render(self, account):
                return self.render_string("people/modules/registrations.html", account=account)