on xenial help sign in
Make sure that our greeter lockout screen knows that time passes even when suspended
a67e41cMichael Terry
qml/Greeter/Greeter.qml+30−12
@@ -51,7 +51,7 @@ Showable {
51
51
52 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
52 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
53 property int failedLoginsDelayAttempts: 7 // number of failed logins
53 property int failedLoginsDelayAttempts: 7 // number of failed logins
54− property int failedLoginsDelayMinutes: 5 // minutes of forced waiting
54+ property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
55
55
56 signal tease()
56 signal tease()
57 signal sessionStarted()
57 signal sessionStarted()
@@ -110,7 +110,6 @@ Showable {
110
110
111 readonly property bool multiUser: LightDM.Users.count > 1
111 readonly property bool multiUser: LightDM.Users.count > 1
112 property int currentIndex
112 property int currentIndex
113− property int delayMinutes
114 property bool waiting
113 property bool waiting
115
114
116 // We want 'launcherOffset' to animate down to zero. But not to animate
115 // We want 'launcherOffset' to animate down to zero. But not to animate
@@ -185,13 +184,31 @@ Showable {
185
184
186 Timer {
185 Timer {
187 id: forcedDelayTimer
186 id: forcedDelayTimer
187+
188+ // We use a short interval and check against the system wall clock
189+ // because we have to consider the case that the system is suspended
190+ // for a few minutes. When we wake up, we want to quickly be correct.
188− interval: 1000 * 60
191+ interval: 500
192+
193+ property var delayTarget;
194+ property int delayMinutes;
195+
196+ onDelayMinutesChanged: console.log("MIKE delayMinutes", delayMinutes);
197+
198+ function forceDelay(delay /* in minutes */) {
199+ delayTarget = new Date();
200+ delayTarget.setTime(delayTarget.getTime() + delay * 60000);
201+ delayMinutes = Math.ceil(delay);
202+ start();
203+ }
204+
189 onTriggered: {
205 onTriggered: {
190− if (d.delayMinutes > 0) {
206+ var diff = delayTarget - new Date();
207+ if (diff > 0) {
191− d.delayMinutes -= 1;
208+ delayMinutes = Math.ceil(diff / 60000);
192− if (d.delayMinutes > 0) {
193− start(); // go again
209+ start(); // go again
194− }
210+ } else {
211+ delayMinutes = 0;
195 }
212 }
196 }
213 }
197 }
214 }
@@ -262,7 +279,7 @@ Showable {
262 Binding {
279 Binding {
263 target: loader.item
280 target: loader.item
264 property: "delayMinutes"
281 property: "delayMinutes"
265− value: d.delayMinutes
282+ value: forcedDelayTimer.delayMinutes
266 }
283 }
267
284
268 Binding {
285 Binding {
@@ -363,9 +380,10 @@ Showable {
363 }
380 }
364
381
365 // Check if we should initiate a forced login delay
382 // Check if we should initiate a forced login delay
383+ if (failedLoginsDelayAttempts > 0
384+ && AccountsService.failedLogins > 0
366− if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
385+ && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
367− d.delayMinutes = failedLoginsDelayMinutes;
386+ forcedDelayTimer.forceDelay(failedLoginsDelayMinutes);
368− forcedDelayTimer.start();
369 }
387 }
370
388
371 loader.item.notifyAuthenticationFailed();
389 loader.item.notifyAuthenticationFailed();
tests/qmltests/Greeter/tst_Greeter.qml+15
@@ -146,6 +146,8 @@ Item {
146 tryCompare(greeter, "waiting", false);
146 tryCompare(greeter, "waiting", false);
147 view = findChild(greeter, "testView");
147 view = findChild(greeter, "testView");
148 verifySelected(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
148 verifySelected(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
149+ greeter.failedLoginsDelayAttempts = 7;
150+ greeter.failedLoginsDelayMinutes = 5;
149 }
151 }
150
152
151 function cleanup() {
153 function cleanup() {
@@ -429,6 +431,19 @@ Item {
429 compare(LightDM.Infographic.username, "has-password");
431 compare(LightDM.Infographic.username, "has-password");
430 }
432 }
431
433
434+ function test_forcedDelay() {
435+ greeter.failedLoginsDelayAttempts = 1;
436+ greeter.failedLoginsDelayMinutes = 0.1; // 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+
432 function test_dbusRequestAuthenticationUser() {
447 function test_dbusRequestAuthenticationUser() {
433 selectUser("no-password");
448 selectUser("no-password");
434 LightDM.Greeter.requestAuthenticationUser("has-password");
449 LightDM.Greeter.requestAuthenticationUser("has-password");