on xenial help sign in
When we are locking the user out from too many login failures, notice when time passes even if the device is suspended. (LP: #1396817) Fixes: #1396817

Approved by: Albert Astals Cid

commite4df71e0584b3bf47ed0b9960dde03148b206667 authorMichael Terry <michael.terry@canonical.com> dateWed 18 Mar 2015, 10:17 (12 years ago) parent95cd8a034baeb4
2 files changed+43−12
qml/Greeter/Greeter.qml+28−12 tests/qmltests/Greeter/tst_Greeter.qml+15
qml/Greeter/Greeter.qml+28−12
@@ -50,7 +50,7 @@ Showable {
5050
5151 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
5252 property int failedLoginsDelayAttempts: 7 // number of failed logins
53− property int failedLoginsDelayMinutes: 5 // minutes of forced waiting
53+ property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
5454
5555 signal tease()
5656 signal sessionStarted()
@@ -109,7 +109,6 @@ Showable {
109109
110110 readonly property bool multiUser: LightDM.Users.count > 1
111111 property int currentIndex
112− property int delayMinutes
113112 property bool waiting
114113
115114 // We want 'launcherOffset' to animate down to zero. But not to animate
@@ -180,13 +179,29 @@ Showable {
180179
181180 Timer {
182181 id: forcedDelayTimer
183− interval: 1000 * 60
182+
183+ // We use a short interval and check against the system wall clock
184+ // because we have to consider the case that the system is suspended
185+ // for a few minutes. When we wake up, we want to quickly be correct.
186+ interval: 500
187+
188+ property var delayTarget;
189+ property int delayMinutes;
190+
191+ function forceDelay(delay /* in minutes */) {
192+ delayTarget = new Date();
193+ delayTarget.setTime(delayTarget.getTime() + delay * 60000);
194+ delayMinutes = Math.ceil(delay);
195+ start();
196+ }
197+
184198 onTriggered: {
185− if (d.delayMinutes > 0) {
186− d.delayMinutes -= 1;
187− if (d.delayMinutes > 0) {
188− start(); // go again
189− }
199+ var diff = delayTarget - new Date();
200+ if (diff > 0) {
201+ delayMinutes = Math.ceil(diff / 60000);
202+ start(); // go again
203+ } else {
204+ delayMinutes = 0;
190205 }
191206 }
192207 }
@@ -257,7 +272,7 @@ Showable {
257272 Binding {
258273 target: loader.item
259274 property: "delayMinutes"
260− value: d.delayMinutes
275+ value: forcedDelayTimer.delayMinutes
261276 }
262277
263278 Binding {
@@ -358,9 +373,10 @@ Showable {
358373 }
359374
360375 // Check if we should initiate a forced login delay
361− if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
362− d.delayMinutes = failedLoginsDelayMinutes;
363− forcedDelayTimer.start();
376+ if (failedLoginsDelayAttempts > 0
377+ && AccountsService.failedLogins > 0
378+ && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
379+ forcedDelayTimer.forceDelay(failedLoginsDelayMinutes);
364380 }
365381
366382 loader.item.notifyAuthenticationFailed();
tests/qmltests/Greeter/tst_Greeter.qml+15
@@ -146,6 +146,8 @@ Item {
146146 tryCompare(greeter, "waiting", false);
147147 view = findChild(greeter, "testView");
148148 verifySelected(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
149+ greeter.failedLoginsDelayAttempts = 7;
150+ greeter.failedLoginsDelayMinutes = 5;
149151 }
150152
151153 function cleanup() {
@@ -429,6 +431,19 @@ Item {
429431 compare(LightDM.Infographic.username, "has-password");
430432 }
431433
434+ function test_forcedDelay() {
435+ greeter.failedLoginsDelayAttempts = 1;
436+ greeter.failedLoginsDelayMinutes = 0.001; // make delay very short
437+
438+ selectUser("has-password");
439+ tryCompare(viewShowPromptSpy, "count", 1);
440+
441+ compare(view.delayMinutes, 0);
442+ view.responded("wr0ng p4ssw0rd");
443+ tryCompare(view, "delayMinutes", 1);
444+ tryCompare(view, "delayMinutes", 0);
445+ }
446+
432447 function test_dbusRequestAuthenticationUser() {
433448 selectUser("no-password");
434449 LightDM.Greeter.requestAuthenticationUser("has-password");