mirror of
https://github.com/hyprwm/hyprlock.git
synced 2026-05-03 11:27:58 +02:00
core: move authentication to hyprauth
This commit is contained in:
parent
ef3017f5ef
commit
ff54f158bc
18 changed files with 299 additions and 809 deletions
|
|
@ -86,6 +86,7 @@ pkg_check_modules(
|
|||
pangocairo
|
||||
libdrm
|
||||
gbm
|
||||
hyprauth
|
||||
hyprutils>=0.11.0
|
||||
sdbus-c++>=2.0.0
|
||||
hyprgraphics>=0.1.6)
|
||||
|
|
|
|||
58
flake.lock
generated
58
flake.lock
generated
|
|
@ -1,5 +1,32 @@
|
|||
{
|
||||
"nodes": {
|
||||
"hyprauth": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
"hyprutils"
|
||||
],
|
||||
"hyprwire": "hyprwire",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1767727422,
|
||||
"narHash": "sha256-+b5Ma1CF+ueTXGVfWTL/CncLqkf/qpPfGkHlDx1jasc=",
|
||||
"owner": "PointerDilemma",
|
||||
"repo": "hyprauth",
|
||||
"rev": "070a5d34b0b0afcd088d031134880dc54fa24050",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "PointerDilemma",
|
||||
"repo": "hyprauth",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprgraphics": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
|
|
@ -98,6 +125,36 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprwire": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
"hyprauth",
|
||||
"hyprutils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"hyprauth",
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"hyprauth",
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1767633561,
|
||||
"narHash": "sha256-nCf0iTu9O+dihZ8Qdm1Vwn5+vfYG9KDAcajrAPX40QI=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprwire",
|
||||
"rev": "f3b4266618ef862684ca6b090b592df37e2d7588",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"ref": "fix-object-race",
|
||||
"repo": "hyprwire",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1766070988,
|
||||
|
|
@ -116,6 +173,7 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"hyprauth": "hyprauth",
|
||||
"hyprgraphics": "hyprgraphics",
|
||||
"hyprlang": "hyprlang",
|
||||
"hyprutils": "hyprutils",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,13 @@
|
|||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
|
||||
hyprauth = {
|
||||
url = "github:PointerDilemma/hyprauth";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
inputs.hyprutils.follows = "hyprutils";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
libGL,
|
||||
libxkbcommon,
|
||||
libgbm,
|
||||
hyprauth,
|
||||
hyprgraphics,
|
||||
hyprlang,
|
||||
hyprutils,
|
||||
|
|
@ -41,6 +42,7 @@ stdenv.mkDerivation {
|
|||
libGL
|
||||
libxkbcommon
|
||||
libgbm
|
||||
hyprauth
|
||||
hyprgraphics
|
||||
hyprlang
|
||||
hyprutils
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ in {
|
|||
inputs.hyprlang.overlays.default
|
||||
inputs.hyprutils.overlays.default
|
||||
inputs.hyprwayland-scanner.overlays.default
|
||||
inputs.hyprauth.overlays.default
|
||||
(final: prev: {
|
||||
hyprlock = prev.callPackage ./default.nix {
|
||||
stdenv = prev.gcc15Stdenv;
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
#include "Auth.hpp"
|
||||
#include "Pam.hpp"
|
||||
#include "Fingerprint.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
#include "../core/hyprlock.hpp"
|
||||
#include "src/helpers/Log.hpp"
|
||||
|
||||
#include <hyprlang.hpp>
|
||||
#include <memory>
|
||||
|
||||
CAuth::CAuth() {
|
||||
static const auto ENABLEPAM = g_pConfigManager->getValue<Hyprlang::INT>("auth:pam:enabled");
|
||||
if (*ENABLEPAM)
|
||||
m_vImpls.emplace_back(makeShared<CPam>());
|
||||
static const auto ENABLEFINGERPRINT = g_pConfigManager->getValue<Hyprlang::INT>("auth:fingerprint:enabled");
|
||||
if (*ENABLEFINGERPRINT)
|
||||
m_vImpls.emplace_back(makeShared<CFingerprint>());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
g_pHyprlock->clearPasswordBuffer();
|
||||
}
|
||||
|
||||
bool CAuth::checkWaiting() {
|
||||
return std::ranges::any_of(m_vImpls, [](const auto& i) { return i->checkWaiting(); });
|
||||
}
|
||||
|
||||
const std::string& CAuth::getCurrentFailText() {
|
||||
return m_sCurrentFail.failText;
|
||||
}
|
||||
|
||||
std::optional<std::string> CAuth::getFailText(eAuthImplementations implType) {
|
||||
for (const auto& i : m_vImpls) {
|
||||
if (i->getImplType() == implType)
|
||||
return i->getLastFailText();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> CAuth::getPrompt(eAuthImplementations implType) {
|
||||
for (const auto& i : m_vImpls) {
|
||||
if (i->getImplType() == implType)
|
||||
return i->getLastPrompt();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t CAuth::getFailedAttempts() {
|
||||
return m_sCurrentFail.failedAttempts;
|
||||
}
|
||||
|
||||
SP<IAuthImplementation> 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 unlockCallback(ASP<CTimer> self, void* data) {
|
||||
g_pHyprlock->unlock();
|
||||
}
|
||||
|
||||
void CAuth::enqueueUnlock() {
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(0), unlockCallback, nullptr);
|
||||
}
|
||||
|
||||
static void passwordFailCallback(ASP<CTimer> self, void* data) {
|
||||
g_pAuth->m_bDisplayFailText = true;
|
||||
|
||||
g_pHyprlock->enqueueForceUpdateTimers();
|
||||
|
||||
g_pHyprlock->renderAllOutputs();
|
||||
}
|
||||
|
||||
static void displayFailTimeoutCallback(ASP<CTimer> self, void* data) {
|
||||
if (g_pAuth->m_bDisplayFailText) {
|
||||
g_pAuth->m_bDisplayFailText = false;
|
||||
g_pHyprlock->renderAllOutputs();
|
||||
}
|
||||
}
|
||||
|
||||
void CAuth::enqueueFail(const std::string& failText, eAuthImplementations implType) {
|
||||
static const auto FAILTIMEOUT = g_pConfigManager->getValue<Hyprlang::INT>("general:fail_timeout");
|
||||
|
||||
m_sCurrentFail.failText = failText;
|
||||
m_sCurrentFail.failSource = implType;
|
||||
m_sCurrentFail.failedAttempts++;
|
||||
|
||||
Debug::log(LOG, "Failed attempts: {}", m_sCurrentFail.failedAttempts);
|
||||
|
||||
if (m_resetDisplayFailTimer) {
|
||||
m_resetDisplayFailTimer->cancel();
|
||||
m_resetDisplayFailTimer.reset();
|
||||
}
|
||||
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(0), passwordFailCallback, nullptr);
|
||||
m_resetDisplayFailTimer = g_pHyprlock->addTimer(std::chrono::milliseconds(*FAILTIMEOUT), displayFailTimeoutCallback, nullptr);
|
||||
}
|
||||
|
||||
void CAuth::resetDisplayFail() {
|
||||
g_pAuth->m_bDisplayFailText = false;
|
||||
m_resetDisplayFailTimer->cancel();
|
||||
m_resetDisplayFailTimer.reset();
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../core/Timer.hpp"
|
||||
|
||||
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<std::string> getLastFailText() = 0;
|
||||
virtual std::optional<std::string> getLastPrompt() = 0;
|
||||
virtual void terminate() = 0;
|
||||
|
||||
friend class CAuth;
|
||||
};
|
||||
|
||||
class CAuth {
|
||||
public:
|
||||
CAuth();
|
||||
|
||||
void start();
|
||||
|
||||
void submitInput(const std::string& input);
|
||||
bool checkWaiting();
|
||||
|
||||
const std::string& getCurrentFailText();
|
||||
|
||||
std::optional<std::string> getFailText(eAuthImplementations implType);
|
||||
std::optional<std::string> getPrompt(eAuthImplementations implType);
|
||||
size_t getFailedAttempts();
|
||||
|
||||
SP<IAuthImplementation> getImpl(eAuthImplementations implType);
|
||||
|
||||
void terminate();
|
||||
|
||||
void enqueueUnlock();
|
||||
void enqueueFail(const std::string& failText, eAuthImplementations implType);
|
||||
|
||||
void resetDisplayFail();
|
||||
|
||||
// Should only be set via the main thread
|
||||
bool m_bDisplayFailText = false;
|
||||
|
||||
private:
|
||||
struct {
|
||||
std::string failText = "";
|
||||
eAuthImplementations failSource = AUTH_IMPL_PAM;
|
||||
size_t failedAttempts = 0;
|
||||
} m_sCurrentFail;
|
||||
|
||||
std::vector<SP<IAuthImplementation>> m_vImpls;
|
||||
ASP<CTimer> m_resetDisplayFailTimer;
|
||||
};
|
||||
|
||||
inline UP<CAuth> g_pAuth;
|
||||
|
|
@ -1,270 +0,0 @@
|
|||
#include "Fingerprint.hpp"
|
||||
#include "../core/hyprlock.hpp"
|
||||
#include "../helpers/Log.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
static const auto FPRINT = sdbus::ServiceName{"net.reactivated.Fprint"};
|
||||
static const auto DEVICE = sdbus::ServiceName{"net.reactivated.Fprint.Device"};
|
||||
static const auto MANAGER = sdbus::ServiceName{"net.reactivated.Fprint.Manager"};
|
||||
static const auto LOGIN_MANAGER = sdbus::ServiceName{"org.freedesktop.login1.Manager"};
|
||||
|
||||
enum MatchResult {
|
||||
MATCH_INVALID = 0,
|
||||
MATCH_NO_MATCH,
|
||||
MATCH_MATCHED,
|
||||
MATCH_RETRY,
|
||||
MATCH_SWIPE_TOO_SHORT,
|
||||
MATCH_FINGER_NOT_CENTERED,
|
||||
MATCH_REMOVE_AND_RETRY,
|
||||
MATCH_DISCONNECTED,
|
||||
MATCH_UNKNOWN_ERROR,
|
||||
};
|
||||
|
||||
static std::map<std::string, MatchResult> s_mapStringToTestType = {{"verify-no-match", MATCH_NO_MATCH},
|
||||
{"verify-match", MATCH_MATCHED},
|
||||
{"verify-retry-scan", MATCH_RETRY},
|
||||
{"verify-swipe-too-short", MATCH_SWIPE_TOO_SHORT},
|
||||
{"verify-finger-not-centered", MATCH_FINGER_NOT_CENTERED},
|
||||
{"verify-remove-and-retry", MATCH_REMOVE_AND_RETRY},
|
||||
{"verify-disconnected", MATCH_DISCONNECTED},
|
||||
{"verify-unknown-error", MATCH_UNKNOWN_ERROR}};
|
||||
|
||||
CFingerprint::CFingerprint() {
|
||||
static const auto FINGERPRINTREADY = g_pConfigManager->getValue<Hyprlang::STRING>("auth:fingerprint:ready_message");
|
||||
m_sFingerprintReady = *FINGERPRINTREADY;
|
||||
static const auto FINGERPRINTPRESENT = g_pConfigManager->getValue<Hyprlang::STRING>("auth:fingerprint:present_message");
|
||||
m_sFingerprintPresent = *FINGERPRINTPRESENT;
|
||||
}
|
||||
|
||||
CFingerprint::~CFingerprint() {
|
||||
;
|
||||
}
|
||||
|
||||
void CFingerprint::init() {
|
||||
try {
|
||||
m_sDBUSState.connection = sdbus::createSystemBusConnection();
|
||||
m_sDBUSState.login = sdbus::createProxy(*m_sDBUSState.connection, sdbus::ServiceName{"org.freedesktop.login1"}, sdbus::ObjectPath{"/org/freedesktop/login1"});
|
||||
} catch (sdbus::Error& e) {
|
||||
Debug::log(ERR, "fprint: Failed to setup dbus ({})", e.what());
|
||||
m_sDBUSState.connection.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
m_sDBUSState.login->getPropertyAsync("PreparingForSleep").onInterface(LOGIN_MANAGER).uponReplyInvoke([this](std::optional<sdbus::Error> e, sdbus::Variant preparingForSleep) {
|
||||
if (e) {
|
||||
Debug::log(WARN, "fprint: Failed getting value for PreparingForSleep: {}", e->what());
|
||||
return;
|
||||
}
|
||||
m_sDBUSState.sleeping = preparingForSleep.get<bool>();
|
||||
// When entering sleep, the wake signal will trigger startVerify().
|
||||
if (m_sDBUSState.sleeping)
|
||||
return;
|
||||
startVerify();
|
||||
});
|
||||
m_sDBUSState.login->uponSignal("PrepareForSleep").onInterface(LOGIN_MANAGER).call([this](bool start) {
|
||||
Debug::log(LOG, "fprint: PrepareForSleep (start: {})", start);
|
||||
m_sDBUSState.sleeping = start;
|
||||
if (!m_sDBUSState.sleeping && !m_sDBUSState.verifying)
|
||||
startVerify();
|
||||
});
|
||||
}
|
||||
|
||||
void CFingerprint::handleInput(const std::string& input) {
|
||||
;
|
||||
}
|
||||
|
||||
std::optional<std::string> CFingerprint::getLastFailText() {
|
||||
if (!m_sFailureReason.empty())
|
||||
return std::optional(m_sFailureReason);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> CFingerprint::getLastPrompt() {
|
||||
if (!m_sPrompt.empty())
|
||||
return std::optional(m_sPrompt);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool CFingerprint::checkWaiting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void CFingerprint::terminate() {
|
||||
if (!m_sDBUSState.abort)
|
||||
releaseDevice();
|
||||
}
|
||||
|
||||
std::shared_ptr<sdbus::IConnection> CFingerprint::getConnection() {
|
||||
return m_sDBUSState.connection;
|
||||
}
|
||||
|
||||
bool CFingerprint::createDeviceProxy() {
|
||||
auto proxy = sdbus::createProxy(*m_sDBUSState.connection, FPRINT, sdbus::ObjectPath{"/net/reactivated/Fprint/Manager"});
|
||||
|
||||
sdbus::ObjectPath path;
|
||||
try {
|
||||
proxy->callMethod("GetDefaultDevice").onInterface(MANAGER).storeResultsTo(path);
|
||||
} catch (sdbus::Error& e) {
|
||||
Debug::log(WARN, "fprint: couldn't connect to Fprint service ({})", e.what());
|
||||
return false;
|
||||
}
|
||||
Debug::log(LOG, "fprint: using device path {}", path.c_str());
|
||||
m_sDBUSState.device = sdbus::createProxy(*m_sDBUSState.connection, FPRINT, path);
|
||||
|
||||
m_sDBUSState.device->uponSignal("VerifyFingerSelected").onInterface(DEVICE).call([](const std::string& finger) { Debug::log(LOG, "fprint: finger selected: {}", finger); });
|
||||
m_sDBUSState.device->uponSignal("VerifyStatus").onInterface(DEVICE).call([this](const std::string& result, const bool done) { handleVerifyStatus(result, done); });
|
||||
|
||||
m_sDBUSState.device->uponSignal("PropertiesChanged")
|
||||
.onInterface("org.freedesktop.DBus.Properties")
|
||||
.call([this](const std::string& interface, const std::map<std::string, sdbus::Variant>& properties) {
|
||||
if (interface != DEVICE || m_sDBUSState.done)
|
||||
return;
|
||||
|
||||
try {
|
||||
const auto presentVariant = properties.at("finger-present");
|
||||
bool isPresent = presentVariant.get<bool>();
|
||||
if (!isPresent)
|
||||
return;
|
||||
m_sPrompt = m_sFingerprintPresent;
|
||||
g_pHyprlock->enqueueForceUpdateTimers();
|
||||
} catch (std::out_of_range& e) {}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CFingerprint::handleVerifyStatus(const std::string& result, bool done) {
|
||||
Debug::log(LOG, "fprint: handling status {}", result);
|
||||
auto matchResult = s_mapStringToTestType[result];
|
||||
bool authenticated = false;
|
||||
bool retry = false;
|
||||
if (m_sDBUSState.sleeping) {
|
||||
stopVerify();
|
||||
Debug::log(LOG, "fprint: device suspended");
|
||||
return;
|
||||
}
|
||||
switch (matchResult) {
|
||||
case MATCH_INVALID: Debug::log(WARN, "fprint: unknown status: {}", result); break;
|
||||
case MATCH_NO_MATCH:
|
||||
stopVerify();
|
||||
if (m_sDBUSState.retries >= 3) {
|
||||
m_sFailureReason = "Fingerprint auth disabled (too many failed attempts)";
|
||||
} else {
|
||||
done = false;
|
||||
static const auto RETRYDELAY = g_pConfigManager->getValue<Hyprlang::INT>("auth:fingerprint:retry_delay");
|
||||
g_pHyprlock->addTimer(std::chrono::milliseconds(*RETRYDELAY), [](ASP<CTimer> self, void* data) { ((CFingerprint*)data)->startVerify(true); }, this);
|
||||
m_sFailureReason = "Fingerprint did not match";
|
||||
}
|
||||
break;
|
||||
case MATCH_UNKNOWN_ERROR:
|
||||
stopVerify();
|
||||
m_sFailureReason = "Fingerprint auth disabled (unknown error)";
|
||||
break;
|
||||
case MATCH_MATCHED:
|
||||
stopVerify();
|
||||
authenticated = true;
|
||||
g_pAuth->enqueueUnlock();
|
||||
break;
|
||||
case MATCH_RETRY:
|
||||
retry = true;
|
||||
m_sPrompt = "Please retry fingerprint scan";
|
||||
break;
|
||||
case MATCH_SWIPE_TOO_SHORT:
|
||||
retry = true;
|
||||
m_sPrompt = "Swipe too short - try again";
|
||||
break;
|
||||
case MATCH_FINGER_NOT_CENTERED:
|
||||
retry = true;
|
||||
m_sPrompt = "Finger not centered - try again";
|
||||
break;
|
||||
case MATCH_REMOVE_AND_RETRY:
|
||||
retry = true;
|
||||
m_sPrompt = "Remove your finger and try again";
|
||||
break;
|
||||
case MATCH_DISCONNECTED:
|
||||
m_sFailureReason = "Fingerprint device disconnected";
|
||||
m_sDBUSState.abort = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!authenticated && !retry)
|
||||
g_pAuth->enqueueFail(m_sFailureReason, AUTH_IMPL_FINGERPRINT);
|
||||
else if (retry)
|
||||
g_pHyprlock->enqueueForceUpdateTimers();
|
||||
|
||||
if (done || m_sDBUSState.abort)
|
||||
m_sDBUSState.done = true;
|
||||
}
|
||||
|
||||
void CFingerprint::claimDevice() {
|
||||
const auto currentUser = ""; // Empty string means use the caller's id.
|
||||
m_sDBUSState.device->callMethodAsync("Claim").onInterface(DEVICE).withArguments(currentUser).uponReplyInvoke([this](std::optional<sdbus::Error> e) {
|
||||
if (e)
|
||||
Debug::log(WARN, "fprint: could not claim device, {}", e->what());
|
||||
else {
|
||||
Debug::log(LOG, "fprint: claimed device");
|
||||
startVerify();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void CFingerprint::startVerify(bool isRetry) {
|
||||
m_sDBUSState.verifying = true;
|
||||
if (!m_sDBUSState.device) {
|
||||
if (!createDeviceProxy())
|
||||
return;
|
||||
|
||||
claimDevice();
|
||||
return;
|
||||
}
|
||||
auto finger = "any"; // Any finger.
|
||||
m_sDBUSState.device->callMethodAsync("VerifyStart").onInterface(DEVICE).withArguments(finger).uponReplyInvoke([this, isRetry](std::optional<sdbus::Error> e) {
|
||||
if (e) {
|
||||
Debug::log(WARN, "fprint: could not start verifying, {}", e->what());
|
||||
if (isRetry)
|
||||
m_sFailureReason = "Fingerprint auth disabled (failed to restart)";
|
||||
|
||||
} else {
|
||||
Debug::log(LOG, "fprint: started verifying");
|
||||
if (isRetry) {
|
||||
m_sDBUSState.retries++;
|
||||
m_sPrompt = "Could not match fingerprint. Try again.";
|
||||
} else
|
||||
m_sPrompt = m_sFingerprintReady;
|
||||
}
|
||||
g_pHyprlock->enqueueForceUpdateTimers();
|
||||
});
|
||||
}
|
||||
|
||||
bool CFingerprint::stopVerify() {
|
||||
m_sDBUSState.verifying = false;
|
||||
if (!m_sDBUSState.device)
|
||||
return false;
|
||||
try {
|
||||
m_sDBUSState.device->callMethod("VerifyStop").onInterface(DEVICE);
|
||||
} catch (sdbus::Error& e) {
|
||||
Debug::log(WARN, "fprint: could not stop verifying, {}", e.what());
|
||||
return false;
|
||||
}
|
||||
Debug::log(LOG, "fprint: stopped verification");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFingerprint::releaseDevice() {
|
||||
if (!m_sDBUSState.device)
|
||||
return false;
|
||||
try {
|
||||
m_sDBUSState.device->callMethod("Release").onInterface(DEVICE);
|
||||
} catch (sdbus::Error& e) {
|
||||
Debug::log(WARN, "fprint: could not release device, {}", e.what());
|
||||
return false;
|
||||
}
|
||||
Debug::log(LOG, "fprint: released device");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "Auth.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
|
||||
class CFingerprint : public IAuthImplementation {
|
||||
public:
|
||||
CFingerprint();
|
||||
|
||||
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<std::string> getLastFailText();
|
||||
virtual std::optional<std::string> getLastPrompt();
|
||||
virtual void terminate();
|
||||
|
||||
std::shared_ptr<sdbus::IConnection> getConnection();
|
||||
|
||||
private:
|
||||
struct SDBUSState {
|
||||
std::shared_ptr<sdbus::IConnection> connection;
|
||||
std::unique_ptr<sdbus::IProxy> login;
|
||||
std::unique_ptr<sdbus::IProxy> device;
|
||||
|
||||
bool abort = false;
|
||||
bool done = false;
|
||||
int retries = 0;
|
||||
bool sleeping = false;
|
||||
bool verifying = false;
|
||||
} m_sDBUSState;
|
||||
|
||||
std::string m_sFingerprintReady;
|
||||
std::string m_sFingerprintPresent;
|
||||
|
||||
std::string m_sPrompt{""};
|
||||
std::string m_sFailureReason{""};
|
||||
|
||||
void handleVerifyStatus(const std::string& result, const bool done);
|
||||
|
||||
bool createDeviceProxy();
|
||||
void claimDevice();
|
||||
void startVerify(bool isRetry = false);
|
||||
bool stopVerify();
|
||||
bool releaseDevice();
|
||||
};
|
||||
185
src/auth/Pam.cpp
185
src/auth/Pam.cpp
|
|
@ -1,185 +0,0 @@
|
|||
#include "Pam.hpp"
|
||||
#include "../core/hyprlock.hpp"
|
||||
#include "../helpers/Log.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <security/pam_appl.h>
|
||||
#if __has_include(<security/pam_misc.h>)
|
||||
#include <security/pam_misc.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
|
||||
int conv(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* 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;
|
||||
|
||||
for (int i = 0; i < num_msg; ++i) {
|
||||
switch (msg[i]->msg_style) {
|
||||
case PAM_PROMPT_ECHO_OFF:
|
||||
case PAM_PROMPT_ECHO_ON: {
|
||||
const auto PROMPT = std::string(msg[i]->msg);
|
||||
const auto PROMPTCHANGED = PROMPT != CONVERSATIONSTATE->prompt;
|
||||
Debug::log(LOG, "PAM_PROMPT: {}", PROMPT);
|
||||
|
||||
if (PROMPTCHANGED)
|
||||
g_pHyprlock->enqueueForceUpdateTimers();
|
||||
|
||||
// Some pam configurations ask for the password twice for whatever reason (Fedora su for example)
|
||||
// When the prompt is the same as the last one, I guess our answer can be the same.
|
||||
if (!initialPrompt && PROMPTCHANGED) {
|
||||
CONVERSATIONSTATE->prompt = PROMPT;
|
||||
CONVERSATIONSTATE->waitForInput();
|
||||
}
|
||||
|
||||
// Needed for unlocks via SIGUSR1
|
||||
if (g_pHyprlock->isUnlocked())
|
||||
return PAM_CONV_ERR;
|
||||
|
||||
pamReply[i].resp = strdup(CONVERSATIONSTATE->input.c_str());
|
||||
initialPrompt = false;
|
||||
} break;
|
||||
case PAM_ERROR_MSG: Debug::log(ERR, "PAM: {}", msg[i]->msg); break;
|
||||
case PAM_TEXT_INFO:
|
||||
Debug::log(LOG, "PAM: {}", msg[i]->msg);
|
||||
// Targets this log from pam_faillock: https://github.com/linux-pam/linux-pam/blob/fa3295e079dbbc241906f29bde5fb71bc4172771/modules/pam_faillock/pam_faillock.c#L417
|
||||
if (const auto MSG = std::string(msg[i]->msg); MSG.contains("left to unlock")) {
|
||||
CONVERSATIONSTATE->failText = MSG;
|
||||
CONVERSATIONSTATE->failTextFromPam = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*resp = pamReply;
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
CPam::CPam() {
|
||||
static const auto PAMMODULE = g_pConfigManager->getValue<Hyprlang::STRING>("auth:pam:module");
|
||||
m_sPamModule = *PAMMODULE;
|
||||
|
||||
if (!std::filesystem::exists(std::filesystem::path("/etc/pam.d/") / m_sPamModule)) {
|
||||
Debug::log(ERR, R"(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(); };
|
||||
}
|
||||
|
||||
CPam::~CPam() {
|
||||
;
|
||||
}
|
||||
|
||||
void CPam::init() {
|
||||
m_thread = std::thread([this]() {
|
||||
while (true) {
|
||||
resetConversation();
|
||||
|
||||
// Initial input
|
||||
m_sConversationState.prompt = "Password: ";
|
||||
waitForInput();
|
||||
|
||||
// For grace or SIGUSR1 unlocks
|
||||
if (g_pHyprlock->isUnlocked())
|
||||
return;
|
||||
|
||||
const auto AUTHENTICATED = auth();
|
||||
|
||||
// For SIGUSR1 unlocks
|
||||
if (g_pHyprlock->isUnlocked())
|
||||
return;
|
||||
|
||||
if (!AUTHENTICATED)
|
||||
g_pAuth->enqueueFail(m_sConversationState.failText, AUTH_IMPL_PAM);
|
||||
else {
|
||||
g_pAuth->enqueueUnlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool CPam::auth() {
|
||||
const pam_conv localConv = {.conv = conv, .appdata_ptr = (void*)&m_sConversationState};
|
||||
pam_handle_t* handle = nullptr;
|
||||
auto uidPassword = getpwuid(getuid());
|
||||
RASSERT(uidPassword && uidPassword->pw_name, "Failed to get username (getpwuid)");
|
||||
|
||||
int ret = pam_start(m_sPamModule.c_str(), uidPassword->pw_name, &localConv, &handle);
|
||||
|
||||
if (ret != PAM_SUCCESS) {
|
||||
m_sConversationState.failText = "pam_start failed";
|
||||
Debug::log(ERR, "auth: pam_start failed for {}", m_sPamModule);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = pam_authenticate(handle, 0);
|
||||
pam_end(handle, ret);
|
||||
handle = nullptr;
|
||||
|
||||
m_sConversationState.waitingForPamAuth = false;
|
||||
|
||||
if (ret != PAM_SUCCESS) {
|
||||
if (!m_sConversationState.failTextFromPam)
|
||||
m_sConversationState.failText = ret == PAM_AUTH_ERR ? "Authentication failed" : "pam_authenticate failed";
|
||||
Debug::log(ERR, "auth: {} for {}", m_sConversationState.failText, m_sPamModule);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sConversationState.failText = "Successfully authenticated";
|
||||
Debug::log(LOG, "auth: authenticated for {}", m_sPamModule);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPam::waitForInput() {
|
||||
std::unique_lock<std::mutex> lk(m_sConversationState.inputMutex);
|
||||
m_bBlockInput = false;
|
||||
m_sConversationState.waitingForPamAuth = false;
|
||||
m_sConversationState.inputRequested = true;
|
||||
m_sConversationState.inputSubmittedCondition.wait(lk, [this] { return !m_sConversationState.inputRequested || g_pHyprlock->m_bTerminate; });
|
||||
m_bBlockInput = true;
|
||||
}
|
||||
|
||||
void CPam::handleInput(const std::string& input) {
|
||||
std::unique_lock<std::mutex> lk(m_sConversationState.inputMutex);
|
||||
|
||||
if (!m_sConversationState.inputRequested)
|
||||
Debug::log(ERR, "SubmitInput called, but the auth thread is not waiting for input!");
|
||||
|
||||
m_sConversationState.input = input;
|
||||
m_sConversationState.inputRequested = false;
|
||||
m_sConversationState.waitingForPamAuth = true;
|
||||
m_sConversationState.inputSubmittedCondition.notify_all();
|
||||
}
|
||||
|
||||
std::optional<std::string> CPam::getLastFailText() {
|
||||
return m_sConversationState.failText.empty() ? std::nullopt : std::optional(m_sConversationState.failText);
|
||||
}
|
||||
|
||||
std::optional<std::string> CPam::getLastPrompt() {
|
||||
return m_sConversationState.prompt.empty() ? std::nullopt : std::optional(m_sConversationState.prompt);
|
||||
}
|
||||
|
||||
bool CPam::checkWaiting() {
|
||||
return m_bBlockInput || m_sConversationState.waitingForPamAuth;
|
||||
}
|
||||
|
||||
void CPam::terminate() {
|
||||
m_sConversationState.inputSubmittedCondition.notify_all();
|
||||
if (m_thread.joinable())
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
void CPam::resetConversation() {
|
||||
m_sConversationState.input = "";
|
||||
m_sConversationState.waitingForPamAuth = false;
|
||||
m_sConversationState.inputRequested = false;
|
||||
m_sConversationState.failTextFromPam = false;
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "Auth.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
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<void()> 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<std::string> getLastFailText();
|
||||
virtual std::optional<std::string> getLastPrompt();
|
||||
virtual void terminate();
|
||||
|
||||
private:
|
||||
std::thread m_thread;
|
||||
SPamConversationState m_sConversationState;
|
||||
|
||||
bool m_bBlockInput = true;
|
||||
|
||||
std::string m_sPamModule;
|
||||
|
||||
bool auth();
|
||||
void resetConversation();
|
||||
};
|
||||
|
|
@ -369,11 +369,10 @@ std::vector<CConfigManager::SWidgetConfig> CConfigManager::getWidgetConfigs() {
|
|||
|
||||
#define SHADOWABLE(name) \
|
||||
{"shadow_size", m_config.getSpecialConfigValue(name, "shadow_size", k.c_str())}, {"shadow_passes", m_config.getSpecialConfigValue(name, "shadow_passes", k.c_str())}, \
|
||||
{"shadow_color", m_config.getSpecialConfigValue(name, "shadow_color", k.c_str())}, { \
|
||||
"shadow_boost", m_config.getSpecialConfigValue(name, "shadow_boost", k.c_str()) \
|
||||
}
|
||||
{"shadow_color", m_config.getSpecialConfigValue(name, "shadow_color", k.c_str())}, {"shadow_boost", m_config.getSpecialConfigValue(name, "shadow_boost", k.c_str())}
|
||||
|
||||
#define CLICKABLE(name) {"onclick", m_config.getSpecialConfigValue(name, "onclick", k.c_str())}
|
||||
#define CLICKABLE(name) \
|
||||
{ "onclick", m_config.getSpecialConfigValue(name, "onclick", k.c_str()) }
|
||||
|
||||
//
|
||||
auto keys = m_config.listKeysForSpecialCategory("background");
|
||||
|
|
|
|||
106
src/core/Auth.cpp
Normal file
106
src/core/Auth.cpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include "Auth.hpp"
|
||||
#include "hyprlock.hpp"
|
||||
|
||||
#include "../config/ConfigManager.hpp"
|
||||
#include "../helpers/Log.hpp"
|
||||
|
||||
using namespace Hyprauth;
|
||||
|
||||
static void displayFailTimeoutCallback(ASP<CTimer> self, void* data) {
|
||||
if (g_auth->m_displayFail) {
|
||||
g_auth->m_displayFail = false;
|
||||
g_pHyprlock->renderAllOutputs();
|
||||
}
|
||||
}
|
||||
|
||||
CAuth::CAuth() {
|
||||
m_authenticator = IAuthenticator::create(SAuthenticatorCreationData{});
|
||||
|
||||
static const auto ENABLEPAM = g_pConfigManager->getValue<Hyprlang::INT>("auth:pam:enabled");
|
||||
static const auto ENABLEFINGERPRINT = g_pConfigManager->getValue<Hyprlang::INT>("auth:fingerprint:enabled");
|
||||
static const auto FAILTIMEOUT = g_pConfigManager->getValue<Hyprlang::INT>("general:fail_timeout");
|
||||
|
||||
RASSERT(*ENABLEPAM || *ENABLEFINGERPRINT, "At least one authentication method must be enabled!");
|
||||
|
||||
if (*ENABLEPAM) {
|
||||
SPamCreationData pamData;
|
||||
pamData.module = "hyprlock"; // hyprauth will fall back to su in case it doesn't exist
|
||||
pamData.extendUserCreds = true;
|
||||
m_pam = createPamProvider(pamData);
|
||||
if (m_pam)
|
||||
m_authenticator->addProvider(m_pam);
|
||||
}
|
||||
|
||||
if (*ENABLEFINGERPRINT) {
|
||||
m_fprint = createFprintProvider(SFprintCreationData{});
|
||||
if (m_fprint)
|
||||
m_authenticator->addProvider(m_fprint);
|
||||
}
|
||||
|
||||
m_textInfo[HYPRAUTH_PROVIDER_INVALID] = SProviderInfo{};
|
||||
|
||||
m_authenticator->m_events.prompt.listenStatic([this](IAuthenticator::SAuthPromptData data) {
|
||||
if (m_textInfo.contains(data.from))
|
||||
m_textInfo[data.from] = SProviderInfo{.prompt = data.promptText, .fail = ""};
|
||||
else
|
||||
m_textInfo[data.from].prompt = data.promptText;
|
||||
|
||||
Debug::log(INFO, "Prompt text: {}", data.promptText);
|
||||
g_pHyprlock->renderAllOutputs();
|
||||
});
|
||||
|
||||
m_authenticator->m_events.fail.listenStatic([this](IAuthenticator::SAuthFailData data) {
|
||||
if (m_textInfo.contains(data.from))
|
||||
m_textInfo[data.from] = SProviderInfo{.prompt = "", .fail = data.failText};
|
||||
else
|
||||
m_textInfo[data.from].fail = data.failText;
|
||||
|
||||
m_lastFailProvider = data.from;
|
||||
m_failedAttempts++;
|
||||
m_displayFail = true;
|
||||
|
||||
if (m_resetDisplayFailTimer) {
|
||||
m_resetDisplayFailTimer->cancel();
|
||||
m_resetDisplayFailTimer.reset();
|
||||
}
|
||||
|
||||
Debug::log(WARN, "Fail text: {}, attempts: {}", data.failText, m_failedAttempts);
|
||||
m_resetDisplayFailTimer = g_pHyprlock->addTimer(std::chrono::milliseconds(*FAILTIMEOUT), displayFailTimeoutCallback, nullptr);
|
||||
|
||||
g_pHyprlock->clearPasswordBuffer();
|
||||
});
|
||||
|
||||
m_authenticator->m_events.busy.listenStatic([this](IAuthenticator::SBusyData data) {
|
||||
if (data.from == HYPRAUTH_PROVIDER_PAM) {
|
||||
Debug::log(LOG, "Pam busy: {}", data.busy);
|
||||
m_pamBusy = data.busy;
|
||||
}
|
||||
});
|
||||
|
||||
m_authenticator->m_events.success.listenStatic([this](eAuthProvider tok) {
|
||||
Debug::log(INFO, "Success!");
|
||||
g_pHyprlock->unlock();
|
||||
});
|
||||
}
|
||||
|
||||
CAuth::~CAuth() {}
|
||||
|
||||
const std::string& CAuth::getCurrentFailText() {
|
||||
return m_textInfo[m_lastFailProvider].fail;
|
||||
}
|
||||
|
||||
const std::string& CAuth::getPromptText(eAuthProvider provider) {
|
||||
return m_textInfo[provider].prompt;
|
||||
}
|
||||
|
||||
const std::string& CAuth::getFailText(eAuthProvider provider) {
|
||||
return m_textInfo[provider].fail;
|
||||
}
|
||||
|
||||
size_t CAuth::getFailedAttempts() {
|
||||
return m_failedAttempts;
|
||||
}
|
||||
|
||||
void CAuth::resetDisplayFail() {
|
||||
displayFailTimeoutCallback(nullptr, nullptr);
|
||||
}
|
||||
41
src/core/Auth.hpp
Normal file
41
src/core/Auth.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <hyprauth/hyprauth.hpp>
|
||||
#include <array>
|
||||
#include "Timer.hpp"
|
||||
#include "../defines.hpp"
|
||||
|
||||
class CAuth {
|
||||
public:
|
||||
CAuth();
|
||||
~CAuth();
|
||||
|
||||
const std::string& getCurrentFailText();
|
||||
const std::string& getPromptText(Hyprauth::eAuthProvider provider);
|
||||
const std::string& getFailText(Hyprauth::eAuthProvider provider);
|
||||
|
||||
size_t getFailedAttempts();
|
||||
|
||||
void resetDisplayFail();
|
||||
|
||||
bool m_displayFail = false;
|
||||
bool m_pamBusy = false;
|
||||
ASP<CTimer> m_resetDisplayFailTimer;
|
||||
|
||||
SP<Hyprauth::IAuthenticator> m_authenticator;
|
||||
SP<Hyprauth::IAuthProvider> m_pam;
|
||||
SP<Hyprauth::IAuthProvider> m_fprint;
|
||||
|
||||
struct SProviderInfo {
|
||||
std::string prompt = "";
|
||||
std::string fail = "";
|
||||
};
|
||||
|
||||
private:
|
||||
size_t m_failedAttempts = 0;
|
||||
Hyprauth::eAuthProvider m_lastFailProvider = Hyprauth::HYPRAUTH_PROVIDER_INVALID;
|
||||
|
||||
std::unordered_map<Hyprauth::eAuthProvider, SProviderInfo> m_textInfo;
|
||||
};
|
||||
|
||||
inline UP<CAuth> g_auth;
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
#include "hyprlock.hpp"
|
||||
#include "Auth.hpp"
|
||||
#include "Egl.hpp"
|
||||
#include "Seat.hpp"
|
||||
#include "../helpers/Log.hpp"
|
||||
#include "../config/ConfigManager.hpp"
|
||||
#include "../renderer/Renderer.hpp"
|
||||
#include "../renderer/AsyncResourceManager.hpp"
|
||||
#include "../auth/Auth.hpp"
|
||||
#include "../auth/Fingerprint.hpp"
|
||||
#include "./Egl.hpp"
|
||||
#include "./Seat.hpp"
|
||||
#include <chrono>
|
||||
#include <hyprutils/memory/UniquePtr.hpp>
|
||||
#include <sys/wait.h>
|
||||
|
|
@ -72,7 +71,7 @@ static void registerSignalAction(int sig, void (*handler)(int), int sa_flags = 0
|
|||
static void handleUnlockSignal(int sig) {
|
||||
if (sig == SIGUSR1) {
|
||||
Debug::log(LOG, "Unlocking with a SIGUSR1");
|
||||
g_pAuth->enqueueUnlock();
|
||||
g_pHyprlock->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -320,8 +319,8 @@ void CHyprlock::run() {
|
|||
|
||||
g_pRenderer = makeUnique<CRenderer>();
|
||||
g_asyncResourceManager = makeUnique<CAsyncResourceManager>();
|
||||
g_pAuth = makeUnique<CAuth>();
|
||||
g_pAuth->start();
|
||||
g_auth = makeUnique<CAuth>();
|
||||
g_auth->m_authenticator->start();
|
||||
|
||||
Debug::log(LOG, "Running on {}", m_sCurrentDesktop);
|
||||
|
||||
|
|
@ -338,37 +337,44 @@ void CHyprlock::run() {
|
|||
if (!acquireSessionLock()) {
|
||||
m_sLoopState.timerEvent = true;
|
||||
m_sLoopState.timerCV.notify_all();
|
||||
g_pAuth->terminate();
|
||||
g_auth->m_authenticator->terminate();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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);
|
||||
registerSignalAction(SIGRTMIN, handlePollTerminate);
|
||||
|
||||
pollfd pollfds[2];
|
||||
pollfds[0] = {
|
||||
std::vector<pollfd> pollfds;
|
||||
int pamIdx = -1, fprintIdx = -1;
|
||||
pollfds.emplace_back(pollfd{
|
||||
.fd = wl_display_get_fd(m_sWaylandState.display),
|
||||
.events = POLLIN,
|
||||
};
|
||||
if (dbusConn) {
|
||||
pollfds[1] = {
|
||||
.fd = dbusConn->getEventLoopPollData().fd,
|
||||
.events = POLLIN,
|
||||
};
|
||||
}
|
||||
size_t fdcount = dbusConn ? 2 : 1;
|
||||
});
|
||||
|
||||
std::thread pollThr([this, &pollfds, fdcount]() {
|
||||
if (g_auth->m_pam) {
|
||||
pamIdx = pollfds.size();
|
||||
pollfds.emplace_back(pollfd{
|
||||
.fd = g_auth->m_pam->getLoopFd(),
|
||||
.events = POLLIN,
|
||||
});
|
||||
}
|
||||
|
||||
if (g_auth->m_fprint) {
|
||||
fprintIdx = pollfds.size();
|
||||
pollfds.emplace_back(pollfd{
|
||||
.fd = g_auth->m_fprint->getLoopFd(),
|
||||
.events = POLLIN,
|
||||
});
|
||||
}
|
||||
|
||||
std::thread pollThr([this, &pollfds]() {
|
||||
while (!m_bTerminate) {
|
||||
bool preparedToRead = wl_display_prepare_read(m_sWaylandState.display) == 0;
|
||||
|
||||
int events = 0;
|
||||
if (preparedToRead) {
|
||||
events = poll(pollfds, fdcount, 5000);
|
||||
events = poll(pollfds.data(), pollfds.size(), 5000);
|
||||
|
||||
if (events < 0) {
|
||||
RASSERT(errno == EINTR, "[core] Polling fds failed with {}", errno);
|
||||
|
|
@ -376,7 +382,7 @@ void CHyprlock::run() {
|
|||
continue;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < fdcount; ++i) {
|
||||
for (size_t i = 0; i < pollfds.size(); ++i) {
|
||||
RASSERT(!(pollfds[i].revents & POLLHUP), "[core] Disconnected from pollfd id {}", i);
|
||||
}
|
||||
|
||||
|
|
@ -441,11 +447,11 @@ void CHyprlock::run() {
|
|||
m_sLoopState.wlDispatched = true;
|
||||
m_sLoopState.wlDispatchCV.notify_all();
|
||||
|
||||
if (pollfds[1].revents & POLLIN /* dbus */) {
|
||||
while (dbusConn && dbusConn->processPendingEvent()) {
|
||||
;
|
||||
}
|
||||
}
|
||||
if (pamIdx > 0 && pollfds[pamIdx].revents & POLLIN)
|
||||
g_auth->m_pam->dispatchEvents();
|
||||
|
||||
if (fprintIdx > 0 && pollfds[fprintIdx].revents & POLLIN)
|
||||
g_auth->m_fprint->dispatchEvents();
|
||||
|
||||
processTimers();
|
||||
}
|
||||
|
|
@ -467,7 +473,7 @@ void CHyprlock::run() {
|
|||
|
||||
pthread_kill(pollThr.native_handle(), SIGRTMIN);
|
||||
|
||||
g_pAuth->terminate();
|
||||
g_auth->m_authenticator->terminate();
|
||||
|
||||
// wait for threads to exit cleanly to avoid a coredump
|
||||
pollThr.join();
|
||||
|
|
@ -578,13 +584,13 @@ void CHyprlock::onKey(uint32_t key, bool down) {
|
|||
}
|
||||
}
|
||||
|
||||
if (g_pAuth->checkWaiting()) {
|
||||
renderAllOutputs();
|
||||
return;
|
||||
}
|
||||
// if (g_pAuth->checkWaiting()) {
|
||||
// renderAllOutputs();
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (g_pAuth->m_bDisplayFailText)
|
||||
g_pAuth->resetDisplayFail();
|
||||
if (g_auth->m_displayFail)
|
||||
g_auth->resetDisplayFail();
|
||||
|
||||
if (down) {
|
||||
m_bCapsLock = xkb_state_mod_name_is_active(g_pSeatManager->m_pXKBState, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED);
|
||||
|
|
@ -627,7 +633,7 @@ void CHyprlock::handleKeySym(xkb_keysym_t sym, bool composed) {
|
|||
return;
|
||||
}
|
||||
|
||||
g_pAuth->submitInput(m_sPasswordState.passBuffer);
|
||||
g_auth->m_authenticator->submitInput(m_sPasswordState.passBuffer);
|
||||
} else if (SYM == XKB_KEY_BackSpace || SYM == XKB_KEY_Delete) {
|
||||
if (m_sPasswordState.passBuffer.length() > 0) {
|
||||
// handle utf-8
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "IWidget.hpp"
|
||||
#include "../../helpers/Log.hpp"
|
||||
#include "../../core/hyprlock.hpp"
|
||||
#include "../../auth/Auth.hpp"
|
||||
#include "../../core/Auth.hpp"
|
||||
#include <chrono>
|
||||
#include <hyprgraphics/resource/resources/TextResource.hpp>
|
||||
#include <unistd.h>
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
#include <hyprutils/string/String.hpp>
|
||||
#include <hyprutils/string/VarList.hpp>
|
||||
|
||||
using namespace Hyprauth;
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#if defined(_LIBCPP_VERSION)
|
||||
|
|
@ -89,7 +90,7 @@ Hyprgraphics::CTextResource::eTextAlignmentMode IWidget::parseTextAlignment(cons
|
|||
|
||||
static void replaceAllAttempts(std::string& str) {
|
||||
|
||||
const size_t ATTEMPTS = g_pAuth->getFailedAttempts();
|
||||
const size_t ATTEMPTS = g_auth->getFailedAttempts();
|
||||
const std::string STR = std::to_string(ATTEMPTS);
|
||||
size_t pos = 0;
|
||||
|
||||
|
|
@ -221,32 +222,32 @@ IWidget::SFormatResult IWidget::formatString(std::string in) {
|
|||
}
|
||||
|
||||
if (in.contains("$FAIL")) {
|
||||
const auto FAIL = g_pAuth->getCurrentFailText();
|
||||
const auto FAIL = g_auth->getCurrentFailText();
|
||||
replaceInString(in, "$FAIL", FAIL);
|
||||
result.allowForceUpdate = true;
|
||||
}
|
||||
|
||||
if (in.contains("$PAMFAIL")) {
|
||||
const auto FAIL = g_pAuth->getFailText(AUTH_IMPL_PAM);
|
||||
replaceInString(in, "$PAMFAIL", FAIL.value_or(""));
|
||||
const auto FAIL = g_auth->getFailText(HYPRAUTH_PROVIDER_PAM);
|
||||
replaceInString(in, "$PAMFAIL", FAIL);
|
||||
result.allowForceUpdate = true;
|
||||
}
|
||||
|
||||
if (in.contains("$PAMPROMPT")) {
|
||||
const auto PROMPT = g_pAuth->getPrompt(AUTH_IMPL_PAM);
|
||||
replaceInString(in, "$PAMPROMPT", PROMPT.value_or(""));
|
||||
const auto PROMPT = g_auth->getPromptText(HYPRAUTH_PROVIDER_PAM);
|
||||
replaceInString(in, "$PAMPROMPT", PROMPT);
|
||||
result.allowForceUpdate = true;
|
||||
}
|
||||
|
||||
if (in.contains("$FPRINTFAIL")) {
|
||||
const auto FPRINTFAIL = g_pAuth->getFailText(AUTH_IMPL_FINGERPRINT);
|
||||
replaceInString(in, "$FPRINTFAIL", FPRINTFAIL.value_or(""));
|
||||
const auto FPRINTFAIL = g_auth->getFailText(HYPRAUTH_PROVIDER_FPRINT);
|
||||
replaceInString(in, "$FPRINTFAIL", FPRINTFAIL);
|
||||
result.allowForceUpdate = true;
|
||||
}
|
||||
|
||||
if (in.contains("$FPRINTPROMPT")) {
|
||||
const auto FPRINTPROMPT = g_pAuth->getPrompt(AUTH_IMPL_FINGERPRINT);
|
||||
replaceInString(in, "$FPRINTPROMPT", FPRINTPROMPT.value_or(""));
|
||||
const auto FPRINTPROMPT = g_auth->getPromptText(HYPRAUTH_PROVIDER_FPRINT);
|
||||
replaceInString(in, "$FPRINTPROMPT", FPRINTPROMPT);
|
||||
result.allowForceUpdate = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "../AsyncResourceManager.hpp"
|
||||
#include "../Renderer.hpp"
|
||||
#include "../../core/hyprlock.hpp"
|
||||
#include "../../auth/Auth.hpp"
|
||||
#include "../../core/Auth.hpp"
|
||||
#include "../../config/ConfigDataValues.hpp"
|
||||
#include "../../config/ConfigManager.hpp"
|
||||
#include "../../helpers/Log.hpp"
|
||||
|
|
@ -182,8 +182,8 @@ bool CPasswordInputField::draw(const SRenderData& data) {
|
|||
bool forceReload = false;
|
||||
|
||||
passwordLength = g_pHyprlock->getPasswordBufferDisplayLen();
|
||||
checkWaiting = g_pAuth->checkWaiting();
|
||||
displayFail = g_pAuth->m_bDisplayFailText;
|
||||
checkWaiting = g_auth->m_pamBusy;
|
||||
displayFail = g_auth->m_displayFail;
|
||||
|
||||
updateFade();
|
||||
updateDots();
|
||||
|
|
@ -336,10 +336,10 @@ void CPasswordInputField::updatePlaceholder() {
|
|||
}
|
||||
|
||||
// already requested a placeholder for the current fail
|
||||
if (displayFail && placeholder.failedAttempts == g_pAuth->getFailedAttempts())
|
||||
if (displayFail && placeholder.failedAttempts == g_auth->getFailedAttempts())
|
||||
return;
|
||||
|
||||
placeholder.failedAttempts = g_pAuth->getFailedAttempts();
|
||||
placeholder.failedAttempts = g_auth->getFailedAttempts();
|
||||
|
||||
std::string newText = (displayFail) ? formatString(configFailText).formatted : formatString(configPlaceholderText).formatted;
|
||||
|
||||
|
|
|
|||
20
ydotool_loop.sh
Executable file
20
ydotool_loop.sh
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
LOG_FILE="/tmp/hyprlock_ydotool_loop.txt"
|
||||
|
||||
|
||||
EXIT=0
|
||||
while (( EXIT == 0 )); do
|
||||
hyprctl dispatch exec "HW_TRACE=1 HA_TRACE=1 script -q -c \"$1 --config $2\" /dev/null > \"$LOG_FILE\""
|
||||
|
||||
ydotool type "$3\n"
|
||||
sleep 3
|
||||
|
||||
grep -q "Authentication failed" "$LOG_FILE"
|
||||
if [ $? == 0 ]; then
|
||||
echo OK
|
||||
pkill -USR1 hyprlock
|
||||
|
||||
sleep 1
|
||||
else
|
||||
EXIT=1
|
||||
fi
|
||||
done
|
||||
Loading…
Add table
Reference in a new issue