@@ -54,6 +54,7 @@ Showable {
54 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
54 property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
55 property int failedLoginsDelayAttempts: 7 // number of failed logins
55 property int failedLoginsDelayAttempts: 7 // number of failed logins
56 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
56 property real failedLoginsDelayMinutes: 5 // minutes of forced waiting
57+ property int failedFingerprintLoginsDisableAttempts: 3 // number of failed fingerprint logins
58 readonly property bool animating: loader.item ? loader.item.animating : false
59 readonly property bool animating: loader.item ? loader.item.animating : false
@@ -62,6 +63,9 @@ Showable {
62 signal emergencyCall()
63 signal emergencyCall()
64 function forceShow() {
65 function forceShow() {
67+ d.isLockscreen = true;
65 forcedUnlock = false;
69 forcedUnlock = false;
66 if (!required) {
70 if (!required) {
67 showNow(); // loader.onLoaded will select a user
71 showNow(); // loader.onLoaded will select a user
@@ -121,7 +125,11 @@ Showable {
121 readonly property bool multiUser: lightDM.users.count > 1
125 readonly property bool multiUser: lightDM.users.count > 1
122 property int currentIndex
126 property int currentIndex
123 property bool waiting
127 property bool waiting
124− property int fingerprintFailureCount
128+ property bool isLockscreen // true when we are locking an active session, rather than first user login
129+ readonly property bool allowFingerprint: isLockscreen &&
130+ AccountsService.failedFingerprintLogins <
131+ root.failedFingerprintLoginsDisableAttempts
132+ readonly property bool alphanumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
126 // We want 'launcherOffset' to animate down to zero. But not to animate
134 // We want 'launcherOffset' to animate down to zero. But not to animate
127 // while being dragged. So ideally we change this only when the user
135 // while being dragged. So ideally we change this only when the user
@@ -137,16 +145,8 @@ Showable {
137 UbuntuNumberAnimation {}
145 UbuntuNumberAnimation {}
140− onFingerprintFailureCountChanged: {
141− if (d.fingerprintFailureCount >= 3) {
142− d.startUnlock(false /* toTheRight */);
143− d.fingerprintFailureCount = 0;
147 function selectUser(uid, reset) {
148 function selectUser(uid, reset) {
148 d.waiting = true;
149 d.waiting = true;
149− d.fingerprintFailureCount = 0;
150 if (reset) {
150 if (reset) {
151 loader.item.reset();
151 loader.item.reset();
@@ -199,6 +199,13 @@ Showable {
199 onForcedUnlockChanged: d.checkForcedUnlock(false /* hideNow */)
199 onForcedUnlockChanged: d.checkForcedUnlock(false /* hideNow */)
200 Component.onCompleted: d.checkForcedUnlock(true /* hideNow */)
200 Component.onCompleted: d.checkForcedUnlock(true /* hideNow */)
204+ AccountsService.failedLogins = 0;
205+ AccountsService.failedFingerprintLogins = 0;
202 onRequiredChanged: {
209 onRequiredChanged: {
203 if (required) {
210 if (required) {
204 d.waiting = true;
211 d.waiting = true;
@@ -360,7 +367,7 @@ Showable {
360 Binding {
367 Binding {
361 target: loader.item
368 target: loader.item
362 property: "alphanumeric"
369 property: "alphanumeric"
363− value: AccountsService.passwordDisplayHint === AccountsService.Keyboard
370+ value: d.alphanumeric
366 Binding {
373 Binding {
@@ -419,7 +426,6 @@ Showable {
419 d.waiting = false;
426 d.waiting = false;
421 if (lightDM.greeter.authenticated) {
428 if (lightDM.greeter.authenticated) {
422− AccountsService.failedLogins = 0;
423 d.login();
429 d.login();
424 if (!lightDM.greeter.promptless) {
430 if (!lightDM.greeter.promptless) {
425 loader.item.hide();
431 loader.item.hide();
@@ -515,10 +521,16 @@ Showable {
516 function failOperation(reason) {
522 function failOperation(reason) {
517 console.log("Failed to identify user by fingerprint:", reason);
523 console.log("Failed to identify user by fingerprint:", reason);
518− d.fingerprintFailureCount++;
519 restartOperation();
524 restartOperation();
525+ if (!allowFingerprint) {
526+ d.startUnlock(false /* toTheRight */);
520− if (loader.item)
528+ if (loader.item) {
521− loader.item.showErrorMessage(i18n.tr("Try again"));
529+ var msg = d.allowFingerprint ? i18n.tr("Try again")
530+ d.alphanumeric ? i18n.tr("Use passphrase")
531+ : i18n.tr("Use passcode");
532+ loader.item.showErrorMessage(msg);
524 Component.onCompleted: restartOperation()
536 Component.onCompleted: restartOperation()
@@ -526,17 +538,28 @@ Showable {
526 onIdEnabledChanged: restartOperation()
538 onIdEnabledChanged: restartOperation()
528 onSucceeded: {
540 onSucceeded: {
541+ if (!d.allowFingerprint) {
542+ failOperation("too many failures");
529 if (result !== lightDM.users.data(d.currentIndex, lightDM.userRoles.UidRole)) {
545 if (result !== lightDM.users.data(d.currentIndex, lightDM.userRoles.UidRole)) {
546+ AccountsService.failedFingerprintLogins++;
530 failOperation("not the selected user");
547 failOperation("not the selected user");
533 console.log("Identified user by fingerprint:", result);
550 console.log("Identified user by fingerprint:", result);
534− d.fingerprintFailureCount = 0;
535 if (loader.item)
551 if (loader.item)
536 loader.item.notifyAuthenticationSucceeded(true /* showFakePassword */);
552 loader.item.notifyAuthenticationSucceeded(true /* showFakePassword */);
537 if (root.active)
553 if (root.active)
538 root.forcedUnlock = true;
554 root.forcedUnlock = true;
557+ if (!d.allowFingerprint) {
558+ failOperation("too many failures");
560+ AccountsService.failedFingerprintLogins++;
540− onFailed: failOperation(reason)
561+ failOperation(reason);