From a4b056274963a6b4e56a72b50f00a58afa775925 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Mon, 16 Dec 2024 18:58:36 +0000 Subject: [PATCH] auth: add an interface for different authentication methods (#578) * auth: add an interface for different authentication methods * auth: pick inline feedback based on last active implementation * config: move auth options to auth: BREAKING: - general:pam_module -> auth:pam:module - general:enable_fingerprint -> auth:fingerprint:enabled - general:fingerprint_ready_message -> auth:fingerprint:ready_message - general:fingerprint_present_message -> auth:fingerprint:present_message * auth: don't clear password input for fingerprint auth check * fingerprint: checkAuthenticated when handling verfiy status * Revert conditionally clearing the password input buffer Makes sure the input field can show the fail text for fingerprint auth. * auth: virtual instead of override, remove braces * pam: join the thread * auth: remove isAuthenticated and switch to a control flow based unlock * auth: initialize authentication before aquiring the session lock --- src/auth/Auth.cpp | 116 ++++++++++++++++++++ src/auth/Auth.hpp | 61 ++++++++++ src/{core => auth}/Fingerprint.cpp | 56 ++++++---- src/{core => auth}/Fingerprint.hpp | 24 ++-- src/{core/Auth.cpp => auth/Pam.cpp} | 82 +++++++------- src/auth/Pam.hpp | 52 +++++++++ src/config/ConfigManager.cpp | 10 +- src/core/Auth.hpp | 54 --------- src/core/hyprlock.cpp | 44 ++------ src/core/hyprlock.hpp | 1 - src/renderer/widgets/IWidget.cpp | 21 ++-- src/renderer/widgets/PasswordInputField.cpp | 8 +- 12 files changed, 355 insertions(+), 174 deletions(-) create mode 100644 src/auth/Auth.cpp create mode 100644 src/auth/Auth.hpp rename src/{core => auth}/Fingerprint.cpp (89%) rename src/{core => auth}/Fingerprint.hpp (64%) rename src/{core/Auth.cpp => auth/Pam.cpp} (78%) create mode 100644 src/auth/Pam.hpp delete mode 100644 src/core/Auth.hpp diff --git a/src/auth/Auth.cpp b/src/auth/Auth.cpp new file mode 100644 index 0000000..d767084 --- /dev/null +++ b/src/auth/Auth.cpp @@ -0,0 +1,116 @@ +#include "Auth.hpp" +#include "Pam.hpp" +#include "Fingerprint.hpp" +#include "../config/ConfigManager.hpp" +#include "../core/hyprlock.hpp" +#include "src/helpers/Log.hpp" + +#include +#include + +CAuth::CAuth() { + static auto* const PENABLEPAM = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("auth:pam:enabled"); + if (**PENABLEPAM) + m_vImpls.push_back(std::make_shared()); + static auto* const PENABLEFINGERPRINT = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("auth:fingerprint:enabled"); + if (**PENABLEFINGERPRINT) + m_vImpls.push_back(std::make_shared()); + + RASSERT(!m_vImpls.empty(), "At least one authentication method must be enabled!"); +} + +void CAuth::start() { + for (const auto& i : m_vImpls) { + i->init(); + } +} + +void CAuth::submitInput(const std::string& input) { + for (const auto& i : m_vImpls) { + i->handleInput(input); + } +} + +bool CAuth::checkWaiting() { + for (const auto& i : m_vImpls) { + if (i->checkWaiting()) + return true; + } + + return false; +} + +std::string CAuth::getInlineFeedback() { + std::optional firstFeedback = std::nullopt; + for (const auto& i : m_vImpls) { + const auto FEEDBACK = (m_bDisplayFailText) ? i->getLastFailText() : i->getLastPrompt(); + if (!FEEDBACK.has_value()) + continue; + + if (!firstFeedback.has_value()) + firstFeedback = FEEDBACK; + + if (i->getImplType() == m_eLastActiveImpl) + return FEEDBACK.value(); + } + + return firstFeedback.value_or("Ups, no authentication feedack"); +} + +std::optional CAuth::getFailText(eAuthImplementations implType) { + for (const auto& i : m_vImpls) { + if (i->getImplType() == implType) + return i->getLastFailText(); + } + return std::nullopt; +} + +std::optional CAuth::getPrompt(eAuthImplementations implType) { + for (const auto& i : m_vImpls) { + if (i->getImplType() == implType) + return i->getLastPrompt(); + } + return std::nullopt; +} + +std::shared_ptr CAuth::getImpl(eAuthImplementations implType) { + for (const auto& i : m_vImpls) { + if (i->getImplType() == implType) + return i; + } + + return nullptr; +} + +void CAuth::terminate() { + for (const auto& i : m_vImpls) { + i->terminate(); + } +} + +static void passwordFailCallback(std::shared_ptr self, void* data) { + g_pHyprlock->clearPasswordBuffer(); + g_pAuth->m_iFailedAttempts++; + Debug::log(LOG, "Failed attempts: {}", g_pAuth->m_iFailedAttempts); + + g_pAuth->m_bDisplayFailText = true; + g_pHyprlock->enqueueForceUpdateTimers(); + + g_pHyprlock->renderAllOutputs(); +} + +static void passwordUnlockCallback(std::shared_ptr self, void* data) { + g_pHyprlock->unlock(); +} + +void CAuth::enqueueFail() { + g_pHyprlock->addTimer(std::chrono::milliseconds(0), passwordFailCallback, nullptr); +} + +void CAuth::enqueueUnlock() { + g_pHyprlock->addTimer(std::chrono::milliseconds(0), passwordUnlockCallback, nullptr); +} + +void CAuth::postActivity(eAuthImplementations implType) { + m_eLastActiveImpl = implType; +} diff --git a/src/auth/Auth.hpp b/src/auth/Auth.hpp new file mode 100644 index 0000000..49a618c --- /dev/null +++ b/src/auth/Auth.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include + +enum eAuthImplementations { + AUTH_IMPL_PAM = 0, + AUTH_IMPL_FINGERPRINT = 1, +}; + +class IAuthImplementation { + public: + virtual ~IAuthImplementation() = default; + + virtual eAuthImplementations getImplType() = 0; + virtual void init() = 0; + virtual void handleInput(const std::string& input) = 0; + virtual bool checkWaiting() = 0; + virtual std::optional getLastFailText() = 0; + virtual std::optional getLastPrompt() = 0; + virtual void terminate() = 0; + + friend class CAuth; +}; + +class CAuth { + public: + CAuth(); + + void start(); + + void submitInput(const std::string& input); + bool checkWaiting(); + + // Used by the PasswordInput field. We are constraint to a single line for the authentication feedback there. + // Based on m_bDisplayFailText, this will return either the fail text or the prompt. + // Based on m_eLastActiveImpl, it will select the implementation. + std::string getInlineFeedback(); + + std::optional getFailText(eAuthImplementations implType); + std::optional getPrompt(eAuthImplementations implType); + + std::shared_ptr getImpl(eAuthImplementations implType); + + void terminate(); + + // Should only be set via the main thread + bool m_bDisplayFailText = false; + size_t m_iFailedAttempts = 0; + + void enqueueUnlock(); + void enqueueFail(); + void postActivity(eAuthImplementations implType); + + private: + std::vector> m_vImpls; + std::optional m_eLastActiveImpl = std::nullopt; +}; + +inline std::unique_ptr g_pAuth; diff --git a/src/core/Fingerprint.cpp b/src/auth/Fingerprint.cpp similarity index 89% rename from src/core/Fingerprint.cpp rename to src/auth/Fingerprint.cpp index 16173a3..8a1528c 100644 --- a/src/core/Fingerprint.cpp +++ b/src/auth/Fingerprint.cpp @@ -1,13 +1,13 @@ #include "Fingerprint.hpp" +#include "../core/hyprlock.hpp" #include "../helpers/Log.hpp" #include "../config/ConfigManager.hpp" -#include +#include #include #include #include -#include static const auto FPRINT = sdbus::ServiceName{"net.reactivated.Fprint"}; static const auto DEVICE = sdbus::ServiceName{"net.reactivated.Fprint.Device"}; @@ -37,18 +37,17 @@ static std::map s_mapStringToTestType = {{"verify-no-m {"verify-unknown-error", MATCH_UNKNOWN_ERROR}}; CFingerprint::CFingerprint() { - static auto* const PFINGERPRINTREADY = (Hyprlang::STRING*)(g_pConfigManager->getValuePtr("general:fingerprint_ready_message")); + static auto* const PFINGERPRINTREADY = (Hyprlang::STRING*)(g_pConfigManager->getValuePtr("auth:fingerprint:ready_message")); m_sFingerprintReady = *PFINGERPRINTREADY; - static auto* const PFINGERPRINTPRESENT = (Hyprlang::STRING*)(g_pConfigManager->getValuePtr("general:fingerprint_present_message")); + static auto* const PFINGERPRINTPRESENT = (Hyprlang::STRING*)(g_pConfigManager->getValuePtr("auth:fingerprint:present_message")); m_sFingerprintPresent = *PFINGERPRINTPRESENT; - static auto* const PENABLEFINGERPRINT = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:enable_fingerprint"); - m_bEnabled = **PENABLEFINGERPRINT; } -std::shared_ptr CFingerprint::start() { - if (!m_bEnabled) - return {}; +CFingerprint::~CFingerprint() { + ; +} +void CFingerprint::init() { m_sDBUSState.connection = sdbus::createSystemBusConnection(); m_sDBUSState.login = sdbus::createProxy(*m_sDBUSState.connection, sdbus::ServiceName{"org.freedesktop.login1"}, sdbus::ObjectPath{"/org/freedesktop/login1"}); m_sDBUSState.login->getPropertyAsync("PreparingForSleep").onInterface(LOGIN_MANAGER).uponReplyInvoke([this](std::optional e, sdbus::Variant preparingForSleep) { @@ -75,22 +74,33 @@ std::shared_ptr CFingerprint::start() { startVerify(); } }); - return m_sDBUSState.connection; } -bool CFingerprint::isAuthenticated() { - return m_bAuthenticated; +void CFingerprint::handleInput(const std::string& input) { + ; } -std::optional CFingerprint::getLastMessage() { +std::optional CFingerprint::getLastFailText() { return m_sDBUSState.message.empty() ? std::nullopt : std::optional(m_sDBUSState.message); } +std::optional CFingerprint::getLastPrompt() { + return std::nullopt; +} + +bool CFingerprint::checkWaiting() { + return false; +} + void CFingerprint::terminate() { if (!m_sDBUSState.abort) releaseDevice(); } +std::shared_ptr CFingerprint::getConnection() { + return m_sDBUSState.connection; +} + void CFingerprint::inhibitSleep() { m_sDBUSState.login->callMethodAsync("Inhibit") .onInterface(LOGIN_MANAGER) @@ -139,8 +149,10 @@ bool CFingerprint::createDeviceProxy() { } void CFingerprint::handleVerifyStatus(const std::string& result, bool done) { + g_pAuth->postActivity(AUTH_IMPL_FINGERPRINT); Debug::log(LOG, "fprint: handling status {}", result); - auto matchResult = s_mapStringToTestType[result]; + auto matchResult = s_mapStringToTestType[result]; + bool authenticated = false; if (m_sDBUSState.sleeping && matchResult != MATCH_DISCONNECTED) return; switch (matchResult) { @@ -148,21 +160,22 @@ void CFingerprint::handleVerifyStatus(const std::string& result, bool done) { case MATCH_NO_MATCH: stopVerify(); if (m_sDBUSState.retries >= 3) { - m_sDBUSState.message = "Fingerprint auth disabled: too many failed attempts"; + m_sDBUSState.message = "Fingerprint auth disabled (too many failed attempts)"; } else { done = false; startVerify(true); + m_sDBUSState.message = "Fingerprint not matched"; } break; case MATCH_UNKNOWN_ERROR: stopVerify(); - m_sDBUSState.message = "Unknown fingerprint error, disabling fingerprint auth"; + m_sDBUSState.message = "Fingerprint auth disabled (unknown error)"; break; case MATCH_MATCHED: stopVerify(); - m_bAuthenticated = true; m_sDBUSState.message = ""; - g_pHyprlock->unlock(); + authenticated = true; + g_pAuth->enqueueUnlock(); break; case MATCH_RETRY: m_sDBUSState.message = "Please retry fingerprint scan"; break; case MATCH_SWIPE_TOO_SHORT: m_sDBUSState.message = "Swipe too short - try again"; break; @@ -173,7 +186,10 @@ void CFingerprint::handleVerifyStatus(const std::string& result, bool done) { m_sDBUSState.abort = true; break; } - g_pHyprlock->enqueueForceUpdateTimers(); + + if (!authenticated) + g_pAuth->enqueueFail(); + if (done || m_sDBUSState.abort) m_sDBUSState.done = true; } @@ -203,7 +219,7 @@ void CFingerprint::startVerify(bool isRetry) { if (e) { Debug::log(WARN, "fprint: could not start verifying, {}", e->what()); if (isRetry) - m_sDBUSState.message = "Fingerprint auth disabled: could not restart verification"; + m_sDBUSState.message = "Fingerprint auth disabled (failed to restart)"; } else { Debug::log(LOG, "fprint: started verifying"); if (isRetry) { diff --git a/src/core/Fingerprint.hpp b/src/auth/Fingerprint.hpp similarity index 64% rename from src/core/Fingerprint.hpp rename to src/auth/Fingerprint.hpp index 6e44102..f07e353 100644 --- a/src/core/Fingerprint.hpp +++ b/src/auth/Fingerprint.hpp @@ -1,20 +1,28 @@ #pragma once -#include "hyprlock.hpp" +#include "Auth.hpp" #include #include #include #include -class CFingerprint { +class CFingerprint : public IAuthImplementation { public: CFingerprint(); - std::shared_ptr start(); - bool isAuthenticated(); - std::optional getLastMessage(); - void terminate(); + virtual ~CFingerprint(); + virtual eAuthImplementations getImplType() { + return AUTH_IMPL_FINGERPRINT; + } + virtual void init(); + virtual void handleInput(const std::string& input); + virtual bool checkWaiting(); + virtual std::optional getLastFailText(); + virtual std::optional getLastPrompt(); + virtual void terminate(); + + std::shared_ptr getConnection(); private: struct SDBUSState { @@ -33,8 +41,6 @@ class CFingerprint { std::string m_sFingerprintReady; std::string m_sFingerprintPresent; - bool m_bAuthenticated = false; - bool m_bEnabled = false; void handleVerifyStatus(const std::string& result, const bool done); @@ -46,5 +52,3 @@ class CFingerprint { bool stopVerify(); bool releaseDevice(); }; - -inline std::unique_ptr g_pFingerprint; diff --git a/src/core/Auth.cpp b/src/auth/Pam.cpp similarity index 78% rename from src/core/Auth.cpp rename to src/auth/Pam.cpp index ed4a3fe..479de4e 100644 --- a/src/core/Auth.cpp +++ b/src/auth/Pam.cpp @@ -1,7 +1,7 @@ -#include "Auth.hpp" -#include "hyprlock.hpp" +#include "Pam.hpp" +#include "../core/hyprlock.hpp" #include "../helpers/Log.hpp" -#include "src/config/ConfigManager.hpp" +#include "../config/ConfigManager.hpp" #include #include @@ -15,7 +15,7 @@ #include int conv(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) { - const auto CONVERSATIONSTATE = (CAuth::SPamConversationState*)appdata_ptr; + const auto CONVERSATIONSTATE = (CPam::SPamConversationState*)appdata_ptr; struct pam_response* pamReply = (struct pam_response*)calloc(num_msg, sizeof(struct pam_response)); bool initialPrompt = true; @@ -34,7 +34,7 @@ int conv(int num_msg, const struct pam_message** msg, struct pam_response** resp // When the prompt is the same as the last one, I guess our answer can be the same. if (!initialPrompt && PROMPTCHANGED) { CONVERSATIONSTATE->prompt = PROMPT; - g_pAuth->waitForInput(); + CONVERSATIONSTATE->waitForInput(); } // Needed for unlocks via SIGUSR1 @@ -60,44 +60,52 @@ int conv(int num_msg, const struct pam_message** msg, struct pam_response** resp return PAM_SUCCESS; } -CAuth::CAuth() { - static auto* const PPAMMODULE = (Hyprlang::STRING*)(g_pConfigManager->getValuePtr("general:pam_module")); +CPam::CPam() { + static auto* const PPAMMODULE = (Hyprlang::STRING*)(g_pConfigManager->getValuePtr("auth:pam:module")); m_sPamModule = *PPAMMODULE; if (!std::filesystem::exists(std::filesystem::path("/etc/pam.d/") / m_sPamModule)) { Debug::log(ERR, "Pam module \"/etc/pam.d/{}\" does not exist! Falling back to \"/etc/pam.d/su\"", m_sPamModule); m_sPamModule = "su"; } + + m_sConversationState.waitForInput = [this]() { this->waitForInput(); }; } -static void passwordCheckTimerCallback(std::shared_ptr self, void* data) { - g_pHyprlock->onPasswordCheckTimer(); +CPam::~CPam() { + ; } -void CAuth::start() { - std::thread([this]() { - resetConversation(); +void CPam::init() { + m_thread = std::thread([this]() { + while (true) { + resetConversation(); - // Initial input - m_sConversationState.prompt = "Password: "; - waitForInput(); + // Initial input + m_sConversationState.prompt = "Password: "; + waitForInput(); - // For grace or SIGUSR1 unlocks - if (g_pHyprlock->isUnlocked()) - return; + // For grace or SIGUSR1 unlocks + if (g_pHyprlock->isUnlocked()) + return; - const auto AUTHENTICATED = auth(); - m_bAuthenticated = AUTHENTICATED; + const auto AUTHENTICATED = auth(); - // For SIGUSR1 unlocks - if (g_pHyprlock->isUnlocked()) - return; + // For SIGUSR1 unlocks + if (g_pHyprlock->isUnlocked()) + return; - g_pHyprlock->addTimer(std::chrono::milliseconds(1), passwordCheckTimerCallback, nullptr); - }).detach(); + if (!AUTHENTICATED) + g_pAuth->enqueueFail(); + else { + g_pAuth->enqueueUnlock(); + return; + } + } + }); } -bool CAuth::auth() { +bool CPam::auth() { const pam_conv localConv = {conv, (void*)&m_sConversationState}; pam_handle_t* handle = NULL; auto uidPassword = getpwuid(getuid()); @@ -115,6 +123,7 @@ bool CAuth::auth() { handle = nullptr; m_sConversationState.waitingForPamAuth = false; + g_pAuth->postActivity(AUTH_IMPL_PAM); if (ret != PAM_SUCCESS) { if (!m_sConversationState.failTextFromPam) @@ -129,16 +138,12 @@ bool CAuth::auth() { return true; } -bool CAuth::isAuthenticated() { - return m_bAuthenticated; -} - // clearing the input must be done from the main thread static void clearInputTimerCallback(std::shared_ptr self, void* data) { g_pHyprlock->clearPasswordBuffer(); } -void CAuth::waitForInput() { +void CPam::waitForInput() { g_pHyprlock->addTimer(std::chrono::milliseconds(1), clearInputTimerCallback, nullptr); std::unique_lock lk(m_sConversationState.inputMutex); @@ -149,7 +154,8 @@ void CAuth::waitForInput() { m_bBlockInput = true; } -void CAuth::submitInput(std::string input) { +void CPam::handleInput(const std::string& input) { + g_pAuth->postActivity(AUTH_IMPL_PAM); std::unique_lock lk(m_sConversationState.inputMutex); if (!m_sConversationState.inputRequested) @@ -161,23 +167,25 @@ void CAuth::submitInput(std::string input) { m_sConversationState.inputSubmittedCondition.notify_all(); } -std::optional CAuth::getLastFailText() { +std::optional CPam::getLastFailText() { return m_sConversationState.failText.empty() ? std::nullopt : std::optional(m_sConversationState.failText); } -std::optional CAuth::getLastPrompt() { +std::optional CPam::getLastPrompt() { return m_sConversationState.prompt.empty() ? std::nullopt : std::optional(m_sConversationState.prompt); } -bool CAuth::checkWaiting() { +bool CPam::checkWaiting() { return m_bBlockInput || m_sConversationState.waitingForPamAuth; } -void CAuth::terminate() { +void CPam::terminate() { m_sConversationState.inputSubmittedCondition.notify_all(); + if (m_thread.joinable()) + m_thread.join(); } -void CAuth::resetConversation() { +void CPam::resetConversation() { m_sConversationState.input = ""; m_sConversationState.waitingForPamAuth = false; m_sConversationState.inputRequested = false; diff --git a/src/auth/Pam.hpp b/src/auth/Pam.hpp new file mode 100644 index 0000000..7e45586 --- /dev/null +++ b/src/auth/Pam.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "Auth.hpp" + +#include +#include +#include +#include +#include + +class CPam : public IAuthImplementation { + public: + struct SPamConversationState { + std::string input = ""; + std::string prompt = ""; + std::string failText = ""; + + std::mutex inputMutex; + std::condition_variable inputSubmittedCondition; + + bool waitingForPamAuth = false; + bool inputRequested = false; + bool failTextFromPam = false; + std::function waitForInput = []() {}; + }; + + CPam(); + + void waitForInput(); + + virtual ~CPam(); + virtual eAuthImplementations getImplType() { + return AUTH_IMPL_PAM; + } + virtual void init(); + virtual void handleInput(const std::string& input); + virtual bool checkWaiting(); + virtual std::optional getLastFailText(); + virtual std::optional getLastPrompt(); + virtual void terminate(); + + private: + std::thread m_thread; + SPamConversationState m_sConversationState; + + bool m_bBlockInput = true; + + std::string m_sPamModule; + + bool auth(); + void resetConversation(); +}; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 2ce8a10..52f9526 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -171,11 +171,13 @@ void CConfigManager::init() { m_config.addConfigValue("general:no_fade_out", Hyprlang::INT{0}); m_config.addConfigValue("general:ignore_empty_input", Hyprlang::INT{0}); m_config.addConfigValue("general:immediate_render", Hyprlang::INT{0}); - m_config.addConfigValue("general:pam_module", Hyprlang::STRING{"hyprlock"}); m_config.addConfigValue("general:fractional_scaling", Hyprlang::INT{2}); - m_config.addConfigValue("general:enable_fingerprint", Hyprlang::INT{0}); - m_config.addConfigValue("general:fingerprint_ready_message", Hyprlang::STRING{"(Scan fingerprint to unlock)"}); - m_config.addConfigValue("general:fingerprint_present_message", Hyprlang::STRING{"Scanning fingerprint"}); + + m_config.addConfigValue("auth:pam:enabled", Hyprlang::INT{1}); + m_config.addConfigValue("auth:pam:module", Hyprlang::STRING{"hyprlock"}); + m_config.addConfigValue("auth:fingerprint:enabled", Hyprlang::INT{0}); + m_config.addConfigValue("auth:fingerprint:ready_message", Hyprlang::STRING{"(Scan fingerprint to unlock)"}); + m_config.addConfigValue("auth:fingerprint:present_message", Hyprlang::STRING{"Scanning fingerprint"}); m_config.addSpecialCategory("background", Hyprlang::SSpecialCategoryOptions{.key = nullptr, .anonymousKeyBased = true}); m_config.addSpecialConfigValue("background", "monitor", Hyprlang::STRING{""}); diff --git a/src/core/Auth.hpp b/src/core/Auth.hpp deleted file mode 100644 index a6f8289..0000000 --- a/src/core/Auth.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -class CAuth { - public: - struct SPamConversationState { - std::string input = ""; - std::string prompt = ""; - std::string failText = ""; - - std::mutex inputMutex; - std::condition_variable inputSubmittedCondition; - - bool waitingForPamAuth = false; - bool inputRequested = false; - bool failTextFromPam = false; - }; - - CAuth(); - - void start(); - bool auth(); - bool isAuthenticated(); - - void waitForInput(); - void submitInput(std::string input); - - std::optional getLastFailText(); - std::optional getLastPrompt(); - - bool checkWaiting(); - - void terminate(); - - // Should only be set via the main thread - bool m_bDisplayFailText = false; - - private: - SPamConversationState m_sConversationState; - - bool m_bBlockInput = true; - bool m_bAuthenticated = false; - - std::string m_sPamModule; - - void resetConversation(); -}; - -inline std::unique_ptr g_pAuth; diff --git a/src/core/hyprlock.cpp b/src/core/hyprlock.cpp index ffc9424..87161e7 100644 --- a/src/core/hyprlock.cpp +++ b/src/core/hyprlock.cpp @@ -2,9 +2,9 @@ #include "../helpers/Log.hpp" #include "../config/ConfigManager.hpp" #include "../renderer/Renderer.hpp" -#include "Auth.hpp" +#include "../auth/Auth.hpp" +#include "../auth/Fingerprint.hpp" #include "Egl.hpp" -#include "Fingerprint.hpp" #include "linux-dmabuf-unstable-v1-protocol.h" #include #include @@ -388,6 +388,8 @@ void CHyprlock::run() { wl_display_roundtrip(m_sWaylandState.display); g_pRenderer = std::make_unique(); + g_pAuth = std::make_unique(); + g_pAuth->start(); static auto* const PNOFADEOUT = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:no_fade_out"); const bool NOFADEOUT = **PNOFADEOUT; @@ -419,11 +421,8 @@ void CHyprlock::run() { exit(1); } - g_pAuth = std::make_unique(); - g_pAuth->start(); - - g_pFingerprint = std::make_unique(); - std::shared_ptr conn = g_pFingerprint->start(); + const auto fingerprintAuth = g_pAuth->getImpl(AUTH_IMPL_FINGERPRINT); + const auto dbusConn = (fingerprintAuth) ? ((CFingerprint*)fingerprintAuth.get())->getConnection() : nullptr; registerSignalAction(SIGUSR1, handleUnlockSignal, SA_RESTART); registerSignalAction(SIGUSR2, handleForceUpdateSignal); @@ -438,13 +437,13 @@ void CHyprlock::run() { .fd = wl_display_get_fd(m_sWaylandState.display), .events = POLLIN, }; - if (conn) { + if (dbusConn) { pollfds[1] = { - .fd = conn->getEventLoopPollData().fd, + .fd = dbusConn->getEventLoopPollData().fd, .events = POLLIN, }; } - size_t fdcount = conn ? 2 : 1; + size_t fdcount = dbusConn ? 2 : 1; std::thread pollThr([this, &pollfds, fdcount]() { while (!m_bTerminate) { @@ -524,7 +523,7 @@ void CHyprlock::run() { m_sLoopState.event = false; if (pollfds[1].revents & POLLIN /* dbus */) { - while (conn && conn->processPendingEvent()) { + while (dbusConn && dbusConn->processPendingEvent()) { ; } } @@ -592,7 +591,6 @@ void CHyprlock::run() { pthread_kill(pollThr.native_handle(), SIGRTMIN); g_pAuth->terminate(); - g_pFingerprint->terminate(); // wait for threads to exit cleanly to avoid a coredump pollThr.join(); @@ -811,24 +809,6 @@ static const ext_session_lock_v1_listener sessionLockListener = { // end session_lock -void CHyprlock::onPasswordCheckTimer() { - // check result - if (g_pAuth->isAuthenticated()) { - unlock(); - } else { - m_sPasswordState.passBuffer = ""; - m_sPasswordState.failedAttempts += 1; - Debug::log(LOG, "Failed attempts: {}", m_sPasswordState.failedAttempts); - - g_pAuth->m_bDisplayFailText = true; - forceUpdateTimers(); - - g_pAuth->start(); - - renderAllOutputs(); - } -} - void CHyprlock::clearPasswordBuffer() { if (m_sPasswordState.passBuffer.empty()) return; @@ -1087,10 +1067,6 @@ size_t CHyprlock::getPasswordBufferDisplayLen() { return std::count_if(m_sPasswordState.passBuffer.begin(), m_sPasswordState.passBuffer.end(), [](char c) { return (c & 0xc0) != 0x80; }); } -size_t CHyprlock::getPasswordFailedAttempts() { - return m_sPasswordState.failedAttempts; -} - std::shared_ptr CHyprlock::addTimer(const std::chrono::system_clock::duration& timeout, std::function self, void* data)> cb_, void* data, bool force) { std::lock_guard lg(m_sLoopState.timersMutex); diff --git a/src/core/hyprlock.hpp b/src/core/hyprlock.hpp index 82a159e..8b2cdf8 100644 --- a/src/core/hyprlock.hpp +++ b/src/core/hyprlock.hpp @@ -68,7 +68,6 @@ class CHyprlock { size_t getPasswordBufferLen(); size_t getPasswordBufferDisplayLen(); - size_t getPasswordFailedAttempts(); ext_session_lock_manager_v1* getSessionLockMgr(); ext_session_lock_v1* getSessionLock(); diff --git a/src/renderer/widgets/IWidget.cpp b/src/renderer/widgets/IWidget.cpp index f23cbc3..e145868 100644 --- a/src/renderer/widgets/IWidget.cpp +++ b/src/renderer/widgets/IWidget.cpp @@ -1,8 +1,8 @@ #include "IWidget.hpp" #include "../../helpers/Log.hpp" #include "../../core/hyprlock.hpp" -#include "../../core/Auth.hpp" -#include "../../core/Fingerprint.hpp" +#include "../../auth/Auth.hpp" +#include "../../auth/Fingerprint.hpp" #include #include #include @@ -58,7 +58,7 @@ Vector2D IWidget::posFromHVAlign(const Vector2D& viewport, const Vector2D& size, static void replaceAllAttempts(std::string& str) { - const size_t ATTEMPTS = g_pHyprlock->getPasswordFailedAttempts(); + const size_t ATTEMPTS = g_pAuth->m_iFailedAttempts; const std::string STR = std::to_string(ATTEMPTS); size_t pos = 0; @@ -138,7 +138,8 @@ static std::string getTime12h() { const auto HRS = hhmmss.hours().count(); const auto MINS = hhmmss.minutes().count(); - return (HRS == 12 || HRS == 0 ? "12" : (HRS % 12 < 10 ? "0" : "") + std::to_string(HRS % 12)) + ":" + (MINS < 10 ? "0" : "") + std::to_string(MINS) + (HRS < 12 ? " AM" : " PM"); + return (HRS == 12 || HRS == 0 ? "12" : (HRS % 12 < 10 ? "0" : "") + std::to_string(HRS % 12)) + ":" + (MINS < 10 ? "0" : "") + std::to_string(MINS) + + (HRS < 12 ? " AM" : " PM"); } IWidget::SFormatResult IWidget::formatString(std::string in) { @@ -169,14 +170,14 @@ IWidget::SFormatResult IWidget::formatString(std::string in) { } if (in.contains("$FAIL")) { - const auto FAIL = g_pAuth->getLastFailText(); - replaceInString(in, "$FAIL", FAIL.has_value() ? FAIL.value() : ""); + const auto FAIL = g_pAuth->getFailText(AUTH_IMPL_PAM); + replaceInString(in, "$FAIL", FAIL.value_or("")); result.allowForceUpdate = true; } if (in.contains("$PROMPT")) { - const auto PROMPT = g_pAuth->getLastPrompt(); - replaceInString(in, "$PROMPT", PROMPT.has_value() ? PROMPT.value() : ""); + const auto PROMPT = g_pAuth->getPrompt(AUTH_IMPL_PAM); + replaceInString(in, "$PROMPT", PROMPT.value_or("")); result.allowForceUpdate = true; } @@ -191,8 +192,8 @@ IWidget::SFormatResult IWidget::formatString(std::string in) { } if (in.contains("$FPRINTMESSAGE")) { - const auto FPRINTMESSAGE = g_pFingerprint->getLastMessage(); - replaceInString(in, "$FPRINTMESSAGE", FPRINTMESSAGE.has_value() ? FPRINTMESSAGE.value() : ""); + const auto FPRINTMESSAGE = g_pAuth->getFailText(AUTH_IMPL_FINGERPRINT); + replaceInString(in, "$FPRINTMESSAGE", FPRINTMESSAGE.value_or("")); result.allowForceUpdate = true; } diff --git a/src/renderer/widgets/PasswordInputField.cpp b/src/renderer/widgets/PasswordInputField.cpp index 9654a9f..f8b4be3 100644 --- a/src/renderer/widgets/PasswordInputField.cpp +++ b/src/renderer/widgets/PasswordInputField.cpp @@ -1,7 +1,7 @@ #include "PasswordInputField.hpp" #include "../Renderer.hpp" #include "../../core/hyprlock.hpp" -#include "../../core/Auth.hpp" +#include "../../auth/Auth.hpp" #include "../../config/ConfigDataValues.hpp" #include "../../helpers/Log.hpp" #include @@ -334,13 +334,13 @@ void CPasswordInputField::updatePlaceholder() { return; } - const auto AUTHFEEDBACK = g_pAuth->m_bDisplayFailText ? g_pAuth->getLastFailText().value_or("Ups, no fail text?") : g_pAuth->getLastPrompt().value_or("Ups, no prompt?"); + const auto AUTHFEEDBACK = g_pAuth->getInlineFeedback(); const auto ALLOWCOLORSWAP = outThick == 0 && colorConfig.swapFont; - if (!ALLOWCOLORSWAP && placeholder.lastAuthFeedback == AUTHFEEDBACK && g_pHyprlock->getPasswordFailedAttempts() == placeholder.failedAttempts) + if (!ALLOWCOLORSWAP && placeholder.lastAuthFeedback == AUTHFEEDBACK && g_pAuth->m_iFailedAttempts == placeholder.failedAttempts) return; - placeholder.failedAttempts = g_pHyprlock->getPasswordFailedAttempts(); + placeholder.failedAttempts = g_pAuth->m_iFailedAttempts; placeholder.lastAuthFeedback = AUTHFEEDBACK; placeholder.asset = nullptr;