on xenial help sign in
implement the new password setup page
4af7183Lukáš Tinkl
qml/Wizard/Pages/60-passwd-type.qml+10−3
@@ -206,14 +206,21 @@ LocalComponents.Page {
206 LocalComponents.StackButton {
206 LocalComponents.StackButton {
207 text: i18n.tr("Next")
207 text: i18n.tr("Next")
208 onClicked: {
208 onClicked: {
209+ var method = indexToMethod(selector.currentIndex)
210+
209− if (!requiredSwitch.checked) { // == swipe method
211+ if (!requiredSwitch.checked) {
210 root.passwordMethod = UbuntuSecurityPrivacyPanel.Swipe
212 root.passwordMethod = UbuntuSecurityPrivacyPanel.Swipe
211 } else {
213 } else {
212− root.passwordMethod = indexToMethod(selector.currentIndex)
214+ root.passwordMethod = method
213 }
215 }
214
216
215 print("Current method: " + root.passwordMethod)
217 print("Current method: " + root.passwordMethod)
218+
219+ if (method === UbuntuSecurityPrivacyPanel.Passphrase) {
220+ pageStack.load(Qt.resolvedUrl("password-set.qml"))
221+ } else if (method === UbuntuSecurityPrivacyPanel.Passcode) {
216− pageStack.load(Qt.resolvedUrl("passcode-set.qml"))
222+ pageStack.load(Qt.resolvedUrl("passcode-set.qml"))
223+ }
217 }
224 }
218 }
225 }
219 }
226 }
qml/Wizard/Pages/passcode-confirm.qml+5−11
@@ -26,14 +26,12 @@ import "../../Components" as UnityComponents
26 */
26 */
27
27
28LocalComponents.Page {
28LocalComponents.Page {
29− id: passwdConfirmPage
29+ id: passcodeConfirmPage
30− objectName: "passwdConfirmPage"
30+ objectName: "passcodeConfirmPage"
31 forwardButtonSourceComponent: forwardButton
31 forwardButtonSourceComponent: forwardButton
32 customTitle: true
32 customTitle: true
33 backButtonText: i18n.tr("Cancel")
33 backButtonText: i18n.tr("Cancel")
34
34
35− skip: root.passwordMethod === UbuntuSecurityPrivacyPanel.Swipe
36−
37 // If we are entering this page, clear any saved password and get focus
35 // If we are entering this page, clear any saved password and get focus
38 onEnabledChanged: if (enabled) lockscreen.clear(false)
36 onEnabledChanged: if (enabled) lockscreen.clear(false)
39
37
@@ -47,19 +45,15 @@ LocalComponents.Page {
47 bottomMargin: buttonMargin
45 bottomMargin: buttonMargin
48 }
46 }
49
47
50− infoText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
51− i18n.tr("Confirm password") :
52− i18n.tr("Confirm passcode")
48+ infoText: i18n.tr("Confirm passcode")
53
49
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.")
57
51
58 foregroundColor: "#525252"
52 foregroundColor: "#525252"
59
53
60 showEmergencyCallButton: false
54 showEmergencyCallButton: false
61 showCancelButton: false
55 showCancelButton: false
62− alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
56+ alphaNumeric: false
63 minPinLength: 4
57 minPinLength: 4
64 maxPinLength: 4
58 maxPinLength: 4
65
59
qml/Wizard/Pages/passcode-set.qml+6−7
@@ -26,8 +26,8 @@ import "../../Components" as UnityComponents
26 */
26 */
27
27
28LocalComponents.Page {
28LocalComponents.Page {
29− id: passwdSetPage
29+ id: passcodeSetPage
30− objectName: "passwdSetPage"
30+ objectName: "passcodeSetPage"
31 forwardButtonSourceComponent: forwardButton
31 forwardButtonSourceComponent: forwardButton
32 customTitle: true
32 customTitle: true
33 backButtonText: i18n.tr("Cancel")
33 backButtonText: i18n.tr("Cancel")
@@ -56,7 +56,7 @@ LocalComponents.Page {
56 bottomMargin: buttonMargin
56 bottomMargin: buttonMargin
57 }
57 }
58
58
59− infoText: alphaNumeric ? i18n.tr("Enter password") : i18n.tr("Choose passcode")
59+ infoText: i18n.tr("Choose passcode")
60 foregroundColor: "#525252"
60 foregroundColor: "#525252"
61
61
62 // Note that the number four comes from PAM settings,
62 // Note that the number four comes from PAM settings,
@@ -68,13 +68,13 @@ LocalComponents.Page {
68
68
69 showEmergencyCallButton: false
69 showEmergencyCallButton: false
70 showCancelButton: false
70 showCancelButton: false
71− alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
71+ alphaNumeric: false
72 minPinLength: 4
72 minPinLength: 4
73 maxPinLength: 4
73 maxPinLength: 4
74
74
75 onEntered: {
75 onEntered: {
76 if (passphrase.length >= 4) {
76 if (passphrase.length >= 4) {
77− passwdSetPage.confirm();
77+ passcodeSetPage.confirm();
78 } else {
78 } else {
79 lockscreen.clear(true)
79 lockscreen.clear(true)
80 }
80 }
@@ -84,10 +84,9 @@ LocalComponents.Page {
84 Component {
84 Component {
85 id: forwardButton
85 id: forwardButton
86 LocalComponents.StackButton {
86 LocalComponents.StackButton {
87− visible: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
88 enabled: lockscreen.passphrase.length >= 4
87 enabled: lockscreen.passphrase.length >= 4
89 text: i18n.tr("OK")
88 text: i18n.tr("OK")
90− onClicked: passwdSetPage.confirm()
89+ onClicked: passcodeSetPage.confirm()
91 }
90 }
92 }
91 }
93}
92}
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+}