on xenial help sign in
Support locking user out for five seconds after five failed entries
551a661Michael Terry
qml/Components/Lockscreen.qml+32−1
@@ -57,26 +57,37 @@ Showable {
57
57
58 onRequiredChanged: {
58 onRequiredChanged: {
59 if (required && pinPadLoader.item) {
59 if (required && pinPadLoader.item) {
60− pinPadLoader.item.clear(false);
60+ clear(false)
61 }
61 }
62 }
62 }
63
63
64+ function forceDelay(delay) {
65+ forcedDelayTimer.interval = delay
66+ forcedDelayTimer.start()
67+ }
68+
64 function reset() {
69 function reset() {
65 // This causes the loader below to destry and recreate the source
70 // This causes the loader below to destry and recreate the source
66 pinPadLoader.resetting = true;
71 pinPadLoader.resetting = true;
67 pinPadLoader.resetting = false;
72 pinPadLoader.resetting = false;
73+ pinPadLoader.waiting = false
68 }
74 }
69
75
70 function clear(showAnimation) {
76 function clear(showAnimation) {
71 if (pinPadLoader.item) {
77 if (pinPadLoader.item) {
72 pinPadLoader.item.clear(showAnimation);
78 pinPadLoader.item.clear(showAnimation);
73 }
79 }
80+ pinPadLoader.waiting = false
74 }
81 }
75
82
76 function showInfoPopup(title, text) {
83 function showInfoPopup(title, text) {
77 PopupUtils.open(infoPopupComponent, root, {title: title, text: text})
84 PopupUtils.open(infoPopupComponent, root, {title: title, text: text})
78 }
85 }
79
86
87+ Timer {
88+ id: forcedDelayTimer
89+ }
90+
80 Rectangle {
91 Rectangle {
81 // In case background fails to load or is undefined
92 // In case background fails to load or is undefined
82 id: backgroundBackup
93 id: backgroundBackup
@@ -106,6 +117,19 @@ Showable {
106 bottom: pinPadLoader.top
117 bottom: pinPadLoader.top
107 bottomMargin: units.gu(2)
118 bottomMargin: units.gu(2)
108 }
119 }
120+ Label {
121+ id: delayTextLabel
122+ objectName: "delayTextLabel"
123+ anchors {
124+ left: parent.left
125+ right: parent.right
126+ }
127+ text: i18n.tr("Too many incorrect attempts, please wait")
128+ horizontalAlignment: Text.AlignHCenter
129+ color: "#f3f3e7"
130+ opacity: 0.6
131+ visible: forcedDelayTimer.running
132+ }
109 Label {
133 Label {
110 objectName: "retryCountLabel"
134 objectName: "retryCountLabel"
111 anchors {
135 anchors {
@@ -145,6 +169,7 @@ Showable {
145 verticalCenterOffset: root.alphaNumeric ? -units.gu(10) : -units.gu(4)
169 verticalCenterOffset: root.alphaNumeric ? -units.gu(10) : -units.gu(4)
146 }
170 }
147 property bool resetting: false
171 property bool resetting: false
172+ property bool waiting: false
148
173
149 source: (!resetting && root.required) ? (root.alphaNumeric ? "PassphraseLockscreen.qml" : "PinLockscreen.qml") : ""
174 source: (!resetting && root.required) ? (root.alphaNumeric ? "PassphraseLockscreen.qml" : "PinLockscreen.qml") : ""
150
175
@@ -152,6 +177,7 @@ Showable {
152 target: pinPadLoader.item
177 target: pinPadLoader.item
153
178
154 onEntered: {
179 onEntered: {
180+ pinPadLoader.waiting = true
155 root.entered(passphrase);
181 root.entered(passphrase);
156 }
182 }
157
183
@@ -185,6 +211,11 @@ Showable {
185 property: "username"
211 property: "username"
186 value: root.username
212 value: root.username
187 }
213 }
214+ Binding {
215+ target: pinPadLoader.item
216+ property: "entryEnabled"
217+ value: !pinPadLoader.waiting && !forcedDelayTimer.running
218+ }
188 }
219 }
189
220
190 Column {
221 Column {
qml/Components/PassphraseLockscreen.qml+2−2
@@ -25,13 +25,13 @@ Item {
25 property string placeholderText
25 property string placeholderText
26 property string wrongPlaceholderText
26 property string wrongPlaceholderText
27 property string username: ""
27 property string username: ""
28+ property bool entryEnabled: true
28
29
29 signal entered(string passphrase)
30 signal entered(string passphrase)
30 signal cancel()
31 signal cancel()
31
32
32 function clear(playAnimation) {
33 function clear(playAnimation) {
33 pinentryField.text = "";
34 pinentryField.text = "";
34− pinentryField.enabled = true
35 if (playAnimation) {
35 if (playAnimation) {
36 wrongPasswordAnimation.start();
36 wrongPasswordAnimation.start();
37 pinentryField.forceActiveFocus();
37 pinentryField.forceActiveFocus();
@@ -76,11 +76,11 @@ Item {
76 echoMode: TextInput.Password
76 echoMode: TextInput.Password
77 opacity: 0.9
77 opacity: 0.9
78 hasClearButton: false
78 hasClearButton: false
79+ enabled: entryEnabled
79 placeholderText: wrongPasswordAnimation.running ? root.wrongPlaceholderText : root.placeholderText
80 placeholderText: wrongPasswordAnimation.running ? root.wrongPlaceholderText : root.placeholderText
80
81
81 onAccepted: {
82 onAccepted: {
82 if (pinentryField.text) {
83 if (pinentryField.text) {
83− pinentryField.enabled = false;
84 root.entered(pinentryField.text);
84 root.entered(pinentryField.text);
85 }
85 }
86 }
86 }
qml/Components/PinLockscreen.qml+1−1
@@ -223,7 +223,7 @@ Column {
223 root.entered(pinentryField.text);
223 root.entered(pinentryField.text);
224 }
224 }
225 }
225 }
226− enabled: priv.autoConfirm ? entryEnabled : pinentryField.text.length >= root.minPinLength
226+ enabled: entryEnabled
227 }
227 }
228 }
228 }
229 }
229 }
qml/Notifications/NotificationMenuItemFactory.qml−1
@@ -114,7 +114,6 @@ Loader {
114
114
115 onEntered: {
115 onEntered: {
116 menuModel.changeState(menuIndex, passphrase);
116 menuModel.changeState(menuIndex, passphrase);
117− entryEnabled = false;
118 }
117 }
119
118
120 onCancel: {
119 onCancel: {
qml/Shell.qml+5
@@ -55,6 +55,8 @@ Item {
55 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
55 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
56
56
57 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
57 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
58+ property int failedLoginsDelayAttempts: 5 // number of failed logins
59+ property int failedLoginsDelaySeconds: 5 // seconds of forced waiting
58
60
59 function activateApplication(appId) {
61 function activateApplication(appId) {
60 if (ApplicationManager.findApplication(appId)) {
62 if (ApplicationManager.findApplication(appId)) {
@@ -433,6 +435,9 @@ Item {
433 SystemImage.factoryReset() // Ouch!
435 SystemImage.factoryReset() // Ouch!
434 }
436 }
435 }
437 }
438+ if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
439+ lockscreen.forceDelay(failedLoginsDelaySeconds * 1000)
440+ }
436
441
437 lockscreen.clear(true);
442 lockscreen.clear(true);
438 if (greeter.narrowMode) {
443 if (greeter.narrowMode) {