diff --git a/shell/plugins/lock/Service.qml b/shell/plugins/lock/Service.qml index 9ecb1cc09be..6886c6dae00 100644 --- a/shell/plugins/lock/Service.qml +++ b/shell/plugins/lock/Service.qml @@ -512,6 +512,12 @@ Item { function lock(): string { if (!root.passwordPamConfigured) return "missing-pam" + if (root.lockRequested && !sessionLock.locked && !sessionLock.secure) { + root.lockRequested = false + root.pendingSessionLock = false + sessionLockStabilizeTimer.stop() + pendingSessionLockTimer.stop() + } if (!root.locked && !root.beginLock()) return "failed" return "ok" } diff --git a/test/shell.d/lock-requested-latch-test.sh b/test/shell.d/lock-requested-latch-test.sh new file mode 100755 index 00000000000..f19c5ea8f5b --- /dev/null +++ b/test/shell.d/lock-requested-latch-test.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +run_node_test <<'JS' +const fs = require('fs') +const serviceQml = fs.readFileSync(path.join(root, 'shell/plugins/lock/Service.qml'), 'utf8') + +// When lock() is called and lockRequested is latched but the session is not +// actually locked or secure, clear the latch so the request can retry. +// Fixes #10299: a stalled lock must not prevent later lock attempts. +assert( + /function lock\(\): string \{[\s\S]*if \(root\.lockRequested && !sessionLock\.locked && !sessionLock\.secure\) \{[\s\S]*root\.lockRequested = false/.test(serviceQml), + 'lock() clears a stalled lockRequested latch before retrying' +) + +assert( + /if \(root\.lockRequested && !sessionLock\.locked && !sessionLock\.secure\) \{[\s\S]*root\.pendingSessionLock = false/.test(serviceQml), + 'lock() clears pendingSessionLock when resetting a stalled request' +) + +assert( + /if \(root\.lockRequested && !sessionLock\.locked && !sessionLock\.secure\) \{[\s\S]*sessionLockStabilizeTimer\.stop\(\)/.test(serviceQml), + 'lock() stops the stabilize timer when resetting a stalled request' +) + +assert( + /if \(root\.lockRequested && !sessionLock\.locked && !sessionLock\.secure\) \{[\s\S]*pendingSessionLockTimer\.stop\(\)/.test(serviceQml), + 'lock() stops the pending timer when resetting a stalled request' +) + +// The latch reset must happen before the locked check, so beginLock() gets called. +assert( + /function lock\(\): string \{[\s\S]*if \(root\.lockRequested && !sessionLock\.locked && !sessionLock\.secure\) \{[\s\S]*\}\s*if \(!root\.locked && !root\.beginLock\(\)\)/.test(serviceQml), + 'lock() resets the latch before checking root.locked' +) +JS