Harden auth, user detection, faillock, and LD_PRELOAD handling

- Replace os.getlogin() with pwd.getpwuid(os.getuid()) to prevent
  crashes in systemd/display-manager sessions without a controlling tty
- Cache libpam and libc at module level instead of calling find_library()
  on every auth attempt (spawned ldconfig subprocess each time)
- Disable password entry permanently after FAILLOCK_MAX_ATTEMPTS instead
  of just showing a warning while allowing unlimited retries
- Fix LD_PRELOAD logic to append gtk4-layer-shell instead of skipping
  when LD_PRELOAD is already set (caused silent session lock fallback)
- Ensure password entry keeps focus after errors and escape
This commit is contained in:
2026-03-26 13:35:26 +01:00
parent dd9937b020
commit e7ab4c2e73
5 changed files with 59 additions and 37 deletions
+10 -9
View File
@@ -11,9 +11,9 @@ from moonlock.users import get_current_user, get_avatar_path, get_default_avatar
class TestGetCurrentUser:
"""Tests for current user detection."""
@patch("moonlock.users.os.getlogin", return_value="testuser")
@patch("moonlock.users.pwd.getpwnam")
def test_returns_user_with_correct_username(self, mock_pwd, mock_login):
@patch("moonlock.users.os.getuid", return_value=1000)
@patch("moonlock.users.pwd.getpwuid")
def test_returns_user_with_correct_username(self, mock_pwd, mock_uid):
mock_pwd.return_value.pw_name = "testuser"
mock_pwd.return_value.pw_gecos = "Test User"
mock_pwd.return_value.pw_dir = "/home/testuser"
@@ -22,10 +22,11 @@ class TestGetCurrentUser:
assert user.username == "testuser"
assert user.display_name == "Test User"
assert user.home == Path("/home/testuser")
mock_pwd.assert_called_once_with(1000)
@patch("moonlock.users.os.getlogin", return_value="testuser")
@patch("moonlock.users.pwd.getpwnam")
def test_empty_gecos_falls_back_to_username(self, mock_pwd, mock_login):
@patch("moonlock.users.os.getuid", return_value=1000)
@patch("moonlock.users.pwd.getpwuid")
def test_empty_gecos_falls_back_to_username(self, mock_pwd, mock_uid):
mock_pwd.return_value.pw_name = "testuser"
mock_pwd.return_value.pw_gecos = ""
mock_pwd.return_value.pw_dir = "/home/testuser"
@@ -33,9 +34,9 @@ class TestGetCurrentUser:
user = get_current_user()
assert user.display_name == "testuser"
@patch("moonlock.users.os.getlogin", return_value="testuser")
@patch("moonlock.users.pwd.getpwnam")
def test_gecos_with_commas_uses_first_field(self, mock_pwd, mock_login):
@patch("moonlock.users.os.getuid", return_value=1000)
@patch("moonlock.users.pwd.getpwuid")
def test_gecos_with_commas_uses_first_field(self, mock_pwd, mock_uid):
mock_pwd.return_value.pw_name = "testuser"
mock_pwd.return_value.pw_gecos = "Test User,,,Room 42"
mock_pwd.return_value.pw_dir = "/home/testuser"