on xenial help sign in
implement the new password setup page
commit4af7183ec8136ffc10833bfee274a6b79fec30bd authorLukáš Tinkl <lukas.tinkl@canonical.com> dateThu 9 Jul 2015, 17:50 (11 years ago) parent387fb41
4 files changed+226−21
qml/Wizard/Pages/60-passwd-type.qml+10−3 qml/Wizard/Pages/passcode-confirm.qml+5−11 qml/Wizard/Pages/passcode-set.qml+6−7 qml/Wizard/Pages/password-set.qml+205
qml/Wizard/Pages/60-passwd-type.qml+10−3
@@ -206,14 +206,21 @@ LocalComponents.Page {
206206 LocalComponents.StackButton {
207207 text: i18n.tr("Next")
208208 onClicked: {
209− if (!requiredSwitch.checked) { // == swipe method
209+ var method = indexToMethod(selector.currentIndex)
210+
211+ if (!requiredSwitch.checked) {
210212 root.passwordMethod = UbuntuSecurityPrivacyPanel.Swipe
211213 } else {
212− root.passwordMethod = indexToMethod(selector.currentIndex)
214+ root.passwordMethod = method
213215 }
214216
215217 print("Current method: " + root.passwordMethod)
216− pageStack.load(Qt.resolvedUrl("passcode-set.qml"))
218+
219+ if (method === UbuntuSecurityPrivacyPanel.Passphrase) {
220+ pageStack.load(Qt.resolvedUrl("password-set.qml"))
221+ } else if (method === UbuntuSecurityPrivacyPanel.Passcode) {
222+ pageStack.load(Qt.resolvedUrl("passcode-set.qml"))
223+ }
217224 }
218225 }
219226 }
qml/Wizard/Pages/passcode-confirm.qml+5−11
@@ -26,14 +26,12 @@ import "../../Components" as UnityComponents
2626 */
2727
2828LocalComponents.Page {
29− id: passwdConfirmPage
30− objectName: "passwdConfirmPage"
29+ id: passcodeConfirmPage
30+ objectName: "passcodeConfirmPage"
3131 forwardButtonSourceComponent: forwardButton
3232 customTitle: true
3333 backButtonText: i18n.tr("Cancel")
3434
35− skip: root.passwordMethod === UbuntuSecurityPrivacyPanel.Swipe
36−
3735 // If we are entering this page, clear any saved password and get focus
3836 onEnabledChanged: if (enabled) lockscreen.clear(false)
3937
@@ -47,19 +45,15 @@ LocalComponents.Page {
4745 bottomMargin: buttonMargin
4846 }
4947
50− infoText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
51− i18n.tr("Confirm password") :
52− i18n.tr("Confirm passcode")
48+ infoText: i18n.tr("Confirm passcode")
5349
54− errorText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
55− i18n.tr("Incorrect password.") + "\n" + i18n.tr("Please re-enter.") :
56− i18n.tr("Incorrect passcode.") + "\n" + i18n.tr("Please re-enter.")
50+ errorText: i18n.tr("Incorrect passcode.") + "\n" + i18n.tr("Please re-enter.")
5751
5852 foregroundColor: "#525252"
5953
6054 showEmergencyCallButton: false
6155 showCancelButton: false
62− alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
56+ alphaNumeric: false
6357 minPinLength: 4
6458 maxPinLength: 4
6559
qml/Wizard/Pages/passcode-set.qml+6−7
@@ -26,8 +26,8 @@ import "../../Components" as UnityComponents
2626 */
2727
2828LocalComponents.Page {
29− id: passwdSetPage
30− objectName: "passwdSetPage"
29+ id: passcodeSetPage
30+ objectName: "passcodeSetPage"
3131 forwardButtonSourceComponent: forwardButton
3232 customTitle: true
3333 backButtonText: i18n.tr("Cancel")
@@ -56,7 +56,7 @@ LocalComponents.Page {
5656 bottomMargin: buttonMargin
5757 }
5858
59− infoText: alphaNumeric ? i18n.tr("Enter password") : i18n.tr("Choose passcode")
59+ infoText: i18n.tr("Choose passcode")
6060 foregroundColor: "#525252"
6161
6262 // Note that the number four comes from PAM settings,
@@ -68,13 +68,13 @@ LocalComponents.Page {
6868
6969 showEmergencyCallButton: false
7070 showCancelButton: false
71− alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
71+ alphaNumeric: false
7272 minPinLength: 4
7373 maxPinLength: 4
7474
7575 onEntered: {
7676 if (passphrase.length >= 4) {
77− passwdSetPage.confirm();
77+ passcodeSetPage.confirm();
7878 } else {
7979 lockscreen.clear(true)
8080 }
@@ -84,10 +84,9 @@ LocalComponents.Page {
8484 Component {
8585 id: forwardButton
8686 LocalComponents.StackButton {
87− visible: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
8887 enabled: lockscreen.passphrase.length >= 4
8988 text: i18n.tr("OK")
90− onClicked: passwdSetPage.confirm()
89+ onClicked: passcodeSetPage.confirm()
9190 }
9291 }
9392}
qml/Wizard/Pages/password-set.qmlnew file+205
@@ -0,0 +1,205 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+import Ubuntu.Components 1.2
19+import ".." as LocalComponents
20+import "../../Components" as UnityComponents
21+
22+/**
23+ * See the main passwd-type page for an explanation of why we don't actually
24+ * directly set the password here.
25+ */
26+
27+LocalComponents.Page {
28+ id: passwdSetPage
29+ objectName: "passwdSetPage"
30+ forwardButtonSourceComponent: forwardButton
31+ customTitle: true
32+ title: confirmPhase ? i18n.tr("Confirm password") : i18n.tr("Enter password")
33+ backButtonText: i18n.tr("Cancel")
34+
35+ property alias password: passwordField.text
36+ readonly property int passwordScore: scorePassword(password)
37+ property bool confirmPhase: false
38+
39+ // If we are entering this page, clear any saved password and get focus
40+ onEnabledChanged: if (enabled) password = ""
41+
42+ Component.onCompleted: {
43+ setInfo()
44+ passwordField.forceActiveFocus()
45+ }
46+
47+ function confirm() {
48+ root.password = password
49+ confirmTimer.start()
50+ }
51+
52+ Timer {
53+ id: confirmTimer
54+ interval: UbuntuAnimation.SnapDuration
55+ onTriggered: {
56+ confirmPhase = true
57+ password = ""
58+ passwordField.forceActiveFocus()
59+ }
60+ }
61+
62+ function setError(text) {
63+ if (!!text) {
64+ infoLabel.hasError = true
65+ infoLabel.text = text
66+ }
67+ }
68+
69+ function setInfo(text) {
70+ infoLabel.hasError = false
71+ if (!!text) {
72+ infoLabel.text = text
73+ } else {
74+ infoLabel.text = i18n.tr("Enter at least 4 characters")
75+ }
76+ }
77+
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 {
108+ id: column
109+ anchors.fill: content
110+
111+ Label {
112+ id: infoLabel
113+ property bool hasError: false
114+ anchors {
115+ left: parent.left
116+ right: parent.right
117+ }
118+ wrapMode: Text.Wrap
119+ color: hasError ? "#e14141": "#525252"
120+ }
121+
122+ TextField {
123+ id: passwordField
124+ anchors {
125+ left: parent.left
126+ right: parent.right
127+ top: infoLabel.bottom
128+ topMargin: units.gu(1)
129+ }
130+ echoMode: TextInput.Password
131+ onTextChanged: {
132+ if (confirmPhase) {
133+ if (password !== root.password) {
134+ setError(i18n.tr("Passwords do not match"))
135+ } else {
136+ setInfo(i18n.tr("Passwords match"))
137+ }
138+ }
139+ }
140+ }
141+
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
163+ }
164+
165+ Label {
166+ id: passwordStrengthInfo
167+ anchors {
168+ left: parent.left
169+ right: parent.right
170+ top: passwordStrengthMeter.bottom
171+ topMargin: units.gu(1)
172+ }
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: "x-small"
186+ font.weight: Font.Light
187+ visible: password.length > 0
188+ }
189+ }
190+
191+ Component {
192+ id: forwardButton
193+ LocalComponents.StackButton {
194+ enabled: confirmPhase ? password === root.password : password.length >= 4 // TODO set more sensible restrictions for the length?
195+ text: i18n.tr("OK")
196+ onClicked: {
197+ if (confirmPhase) {
198+ pageStack.next()
199+ } else {
200+ passwdSetPage.confirm()
201+ }
202+ }
203+ }
204+ }
205+}