Explorar el Código

Add graphical password strength indicator

Danilo Bargen hace 5 años
padre
commit
0291c78f39

+ 1 - 0
public/i18n/de.json

@@ -15,6 +15,7 @@
         "CHOOSE_PASSWORD": "Falls Sie die Sitzung speichern möchten,<br>legen Sie vor dem Scannen ein Passwort fest.",
         "UNLOCK_FAILED_TEXT": "Sie haben das falsche Passwort eingegeben. Die Verbindung kann nicht aufgebaut werden.",
         "ENTER_PASSWORD": "Um die letzte Sitzung wiederherzustellen, <br> geben Sie bitte das entsprechende Passwort ein.",
+        "PASSWORD_STRENGTH": "Passwortstärke",
         "UNLOCK_FAILED_TITLE": "Verbindung aufbauen fehlgeschlagen",
         "ALTERNATIVELY": "Alternativ:",
         "UNLOCK_FAILED_FORGOTTEN": "Haben Sie Ihr Passwort vergessen? W\u00e4hlen Sie \"gespeicherte Sitzung l\u00f6schen\" und setzen Sie ein neues Passwort.",

+ 1 - 0
public/i18n/en.json

@@ -15,6 +15,7 @@
         "CHOOSE_PASSWORD": "If you want to stay logged in, please enter<br>a session password before scanning.",
         "UNLOCK_FAILED_TEXT": "You entered the wrong password, the session cannot be restored.",
         "ENTER_PASSWORD": "To reconnect to your previous session,<br>please enter the password:",
+        "PASSWORD_STRENGTH": "Password strength",
         "UNLOCK_FAILED_TITLE": "Unlocking failed",
         "ALTERNATIVELY": "Alternatively,",
         "UNLOCK_FAILED_FORGOTTEN": "If you can't remember your password, simply choose \"forget this session\", and set a new password.",

+ 20 - 0
src/filters.ts

@@ -19,6 +19,7 @@ import Autolinker from 'autolinker';
 
 import {bufferToUrl, escapeRegExp, filter, hasValue} from './helpers';
 import {emojify} from './helpers/emoji';
+import {Strength} from './helpers/password_strength';
 import {markify} from './markup_parser';
 import {MimeService} from './services/mime';
 import {WebClientService} from './services/webclient';
@@ -418,4 +419,23 @@ angular.module('3ema.filters', [])
         };
 }])
 
+/**
+ * Convert a password strength to a color.
+ */
+.filter('strengthToColor', [function() {
+    return function(strength: Strength) {
+        switch (strength) {
+            case Strength.STRONG:
+                return '#05a63f';
+            case Strength.GOOD:
+                return '#cddc39';
+            case Strength.WEAK:
+                return '#ff9800';
+            case Strength.BAD:
+            default:
+                return '#f44336';
+        }
+    };
+}])
+
 ;

+ 10 - 0
src/partials/welcome.html

@@ -20,7 +20,17 @@
                                    ng-model="ctrl.password"
                                    aria-labelledby="aria-label-password-create"
                                    translate-attr="{'placeholder': 'welcome.PASSWORD', 'aria-label': 'welcome.PASSWORD'}"
+                                   title="{{ 'welcome.PASSWORD_STRENGTH' | translate }}: {{ ctrl.passwordStrength.score }} ({{ ctrl.passwordStrength.strength }})"
                                    autocomplete="new-password">
+                            <div class="password-strength-indicator" aria-hidden="true">
+                                <div class="reached" ng-style="{
+                                    'flex-grow': ctrl.passwordStrength.score,
+                                    'background-color': (ctrl.passwordStrength.strength | strengthToColor),
+                                }"></div>
+                                <div class="unreached" ng-style="{
+                                    'flex-grow': 80 - ctrl.passwordStrength.score,
+                                }"></div>
+                            </div>
                         </md-input-container>
                     </form>
                 </label>

+ 10 - 2
src/partials/welcome.ts

@@ -28,6 +28,7 @@ import {
 
 import {DialogController} from '../controllers/dialog';
 import {BrowserInfo} from '../helpers/browser_info';
+import {scorePassword, Strength} from '../helpers/password_strength';
 import {BrowserService} from '../services/browser';
 import {ControllerService} from '../services/controller';
 import {TrustedKeyStoreService} from '../services/keystore';
@@ -71,6 +72,7 @@ class WelcomeController {
     private mode: 'scan' | 'unlock';
     private qrCode;
     private password: string = '';
+    private passwordStrength: {score: number, strength: Strength} = {score: 0, strength: Strength.BAD};
     private formLocked: boolean = false;
     private pleaseUpdateAppMsg: string = null;
     private browser: BrowserInfo;
@@ -267,6 +269,7 @@ class WelcomeController {
         this.$scope.$watch(() => this.password, () => {
             const payload = this.webClientService.buildQrCodePayload(this.password.length > 0);
             this.qrCode = this.buildQrCode(payload);
+            this.passwordStrength = scorePassword(this.password);
         });
 
         // Start webclient
@@ -486,7 +489,7 @@ class WelcomeController {
         this.$mdDialog.show(confirm).then(() =>  {
             // Go back to scan mode
             this.mode = 'scan';
-            this.password = '';
+            this.clearPassword();
             this.formLocked = false;
 
             // Force-stop the webclient and initiate scan
@@ -541,6 +544,11 @@ class WelcomeController {
         };
     }
 
+    private clearPassword() {
+        this.password = '';
+        this.passwordStrength = {score: 0, strength: Strength.BAD};
+    }
+
     /**
      * Actually start the webclient.
      *
@@ -554,7 +562,7 @@ class WelcomeController {
                 this.webClientService.setPassword(this.password);
 
                 // Clear local password variable
-                this.password = '';
+                this.clearPassword();
                 this.formLocked = false;
 
                 // Redirect to home

+ 27 - 0
src/sass/sections/_welcome.scss

@@ -23,6 +23,10 @@
     md-input-container {
         margin-right: 32px;
         margin-left: 32px;
+
+        .md-errors-spacer {
+            display: none;
+        }
     }
 
     .scan {
@@ -57,6 +61,10 @@
         md-input-container {
             margin-top: 12px;
             margin-bottom: 0;
+
+            input {
+                border-bottom-width: 0;
+            }
         }
 
         qrcode {
@@ -164,4 +172,23 @@
             }
         }
     }
+
+    .password-strength-indicator {
+        display: flex;
+        align-content: stretch;
+        width: 100%;
+        height: 2px;
+
+        .reached {
+            background-color: #999999;
+        }
+
+        .unreached {
+            background-color: $background-grey;
+        }
+    }
+
+    md-input-container.md-input-focused .password-strength-indicator .unreached {
+        background-color: darken($background-grey, 7%);
+    }
 }