on xenial help sign in
factor out password strength meter into its own component
da86a88Lukáš Tinkl
qml/Wizard/Pages/60-uaccount-signup.qml+13−3
@@ -99,13 +99,23 @@ LocalComponents.Page {
99 KeyNavigation.tab: pass2Input
99 KeyNavigation.tab: pass2Input
100 }
100 }
101
101
102+ // password meter
103+ LocalComponents.PasswordMeter {
104+ id: passMeter
105+ anchors.left: parent.left
106+ anchors.right: parent.right
107+ anchors.top: passInput.bottom
108+ anchors.topMargin: units.gu(1)
109+ password: passInput.text
110+ }
111+
102 // repeat password
112 // repeat password
103 Label {
113 Label {
104 id: pass2Label
114 id: pass2Label
105 anchors.left: parent.left
115 anchors.left: parent.left
106 anchors.right: parent.right
116 anchors.right: parent.right
107− anchors.top: passInput.bottom
117+ anchors.top: passMeter.bottom
108− anchors.topMargin: units.gu(3)
118+ anchors.topMargin: passInput.text !== "" ? units.gu(6) : units.gu(3)
109 wrapMode: Text.Wrap
119 wrapMode: Text.Wrap
110 text: i18n.tr("Repeat password:")
120 text: i18n.tr("Repeat password:")
111 color: "#525252"
121 color: "#525252"
@@ -167,7 +177,7 @@ LocalComponents.Page {
167 LocalComponents.StackButton {
177 LocalComponents.StackButton {
168 enabled: emailInput.acceptableInput &&
178 enabled: emailInput.acceptableInput &&
169 //termsCheck.checked && // FIXME re-enable when the checkboxes get visible again
179 //termsCheck.checked && // FIXME re-enable when the checkboxes get visible again
170− passInput.text !== "" && pass2Input.text !== "" && passInput.text === pass2Input.text
180+ pass2Input.text.length > 5 && passInput.text === pass2Input.text
171 text: i18n.tr("Sign Up")
181 text: i18n.tr("Sign Up")
172 onClicked: pageStack.next() // TODO sign up against U1
182 onClicked: pageStack.next() // TODO sign up against U1
173 }
183 }
qml/Wizard/Pages/password-set.qml+10−78
@@ -33,7 +33,6 @@ LocalComponents.Page {
33 backButtonText: i18n.tr("Cancel")
33 backButtonText: i18n.tr("Cancel")
34
34
35 property alias password: passwordField.text
35 property alias password: passwordField.text
36− readonly property int passwordScore: scorePassword(password)
37 property bool confirmPhase: false
36 property bool confirmPhase: false
38
37
39 // If we are entering this page, clear any saved password and get focus
38 // If we are entering this page, clear any saved password and get focus
@@ -71,39 +70,10 @@ LocalComponents.Page {
71 if (!!text) {
70 if (!!text) {
72 infoLabel.text = text
71 infoLabel.text = text
73 } else {
72 } else {
74− infoLabel.text = i18n.tr("Enter at least 4 characters")
73+ infoLabel.text = i18n.tr("Enter at least 6 characters")
75 }
74 }
76 }
75 }
77
76
78− function scorePassword(pass) {
79− var score = 0;
80− if (!pass)
81− return score;
82−
83− // award every unique letter until 5 repetitions
84− var letters = Object();
85− for (var i=0; i<pass.length; i++) {
86− letters[pass[i]] = (letters[pass[i]] || 0) + 1;
87− score += 5.0 / letters[pass[i]];
88− }
89−
90− // bonus points for mixing it up
91− var variations = {
92− digits: /\d/.test(pass),
93− lower: /[a-z]/.test(pass),
94− upper: /[A-Z]/.test(pass),
95− nonWords: /\W/.test(pass),
96− }
97−
98− var variationCount = 0;
99− for (var check in variations) {
100− variationCount += (variations[check] === true) ? 1 : 0;
101− }
102− score += (variationCount - 1) * 10;
103−
104− return parseInt(score);
105− }
106−
107 Item {
77 Item {
108 id: column
78 id: column
109 anchors.fill: content
79 anchors.fill: content
@@ -139,59 +109,21 @@ LocalComponents.Page {
139 }
109 }
140 }
110 }
141
111
142− Rectangle {
143− id: passwordStrengthMeter
144− anchors {
145− left: parent.left
146− right: parent.right
147− top: passwordField.bottom
148− topMargin: units.gu(1)
149− }
150− width: parent.width
151− height: units.gu(1)
152− color: {
153− if (passwordScore > 80)
154− return "green";
155− if (passwordScore > 60)
156− return "orange";
157− if (passwordScore >= 30)
158− return "red";
159−
160− return "red";
161− }
162− visible: password.length > 0
112+ // password meter
163− }
113+ LocalComponents.PasswordMeter {
164−
114+ id: passMeter
165− Label {
166− id: passwordStrengthInfo
167− anchors {
168− left: parent.left
115+ anchors.left: parent.left
169− right: parent.right
116+ anchors.right: parent.right
170− top: passwordStrengthMeter.bottom
117+ anchors.top: passwordField.bottom
171− topMargin: units.gu(1)
118+ anchors.topMargin: units.gu(1)
172− }
119+ password: passwordField.text
173− wrapMode: Text.Wrap
174− text: {
175− if (passwordScore > 80)
176− return i18n.tr("Strong password");
177− else if (passwordScore > 60)
178− return i18n.tr("Medium password")
179− if (passwordScore >= 30)
180− return i18n.tr("Weak password");
181−
182− return i18n.tr("Very weak password");
183− }
184− color: "#888888"
185− fontSize: "small"
186− font.weight: Font.Light
187− visible: password.length > 0
188 }
120 }
189 }
121 }
190
122
191 Component {
123 Component {
192 id: forwardButton
124 id: forwardButton
193 LocalComponents.StackButton {
125 LocalComponents.StackButton {
194− enabled: confirmPhase ? password === root.password : password.length >= 4 // TODO set more sensible restrictions for the length?
126+ enabled: confirmPhase ? password === root.password : password.length > 5 // TODO set more sensible restrictions for the length?
195 text: i18n.tr("OK")
127 text: i18n.tr("OK")
196 onClicked: {
128 onClicked: {
197 if (confirmPhase) {
129 if (confirmPhase) {
qml/Wizard/PasswordMeter.qmlnew file+83
@@ -0,0 +1,83 @@
1+import QtQuick 2.3
2+import Ubuntu.Components 1.2
3+
4+Item {
5+ property string password: ""
6+ readonly property int passwordScore: scorePassword(password)
7+
8+ function scorePassword(pass) {
9+ var score = 0;
10+ if (!pass)
11+ return score;
12+
13+ // award every unique letter until 5 repetitions
14+ var letters = Object();
15+ for (var i=0; i<pass.length; i++) {
16+ letters[pass[i]] = (letters[pass[i]] || 0) + 1;
17+ score += 5.0 / letters[pass[i]];
18+ }
19+
20+ // bonus points for mixing it up
21+ var variations = {
22+ digits: /\d/.test(pass),
23+ lower: /[a-z]/.test(pass),
24+ upper: /[A-Z]/.test(pass),
25+ nonWords: /\W/.test(pass),
26+ }
27+
28+ var variationCount = 0;
29+ for (var check in variations) {
30+ variationCount += (variations[check] === true) ? 1 : 0;
31+ }
32+ score += (variationCount - 1) * 10;
33+
34+ return parseInt(score);
35+ }
36+
37+ Rectangle {
38+ id: passwordStrengthMeter
39+ anchors {
40+ left: parent.left
41+ right: parent.right
42+ }
43+ width: parent.width
44+ height: units.gu(1)
45+ color: {
46+ if (passwordScore > 80)
47+ return "green";
48+ else if (passwordScore > 60)
49+ return "orange";
50+ else if (passwordScore >= 30)
51+ return "red";
52+
53+ return "red";
54+ }
55+ visible: password.length > 0
56+ }
57+
58+ Label {
59+ id: passwordStrengthInfo
60+ anchors {
61+ left: parent.left
62+ right: parent.right
63+ top: passwordStrengthMeter.bottom
64+ }
65+ wrapMode: Text.Wrap
66+ text: {
67+ if (password.length < 6)
68+ return i18n.tr("Password too short")
69+ else if (passwordScore > 80)
70+ return i18n.tr("Strong password");
71+ else if (passwordScore > 60)
72+ return i18n.tr("Fair password")
73+ if (passwordScore >= 30)
74+ return i18n.tr("Weak password");
75+
76+ return i18n.tr("Very weak password");
77+ }
78+ color: "#888888"
79+ fontSize: "small"
80+ font.weight: Font.Light
81+ visible: password.length > 0
82+ }
83+}