Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auth: fixup prompt and fail substitution #641

Merged
merged 1 commit into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 15 additions & 23 deletions src/auth/Auth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,8 @@ bool CAuth::checkWaiting() {
return false;
}

std::string CAuth::getInlineFeedback() {
std::optional<std::string> 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");
const std::string& CAuth::getCurrentFailText() {
return m_sCurrentFail.failText;
}

std::optional<std::string> CAuth::getFailText(eAuthImplementations implType) {
Expand All @@ -73,6 +60,10 @@ std::optional<std::string> CAuth::getPrompt(eAuthImplementations implType) {
return std::nullopt;
}

size_t CAuth::getFailedAttempts() {
return m_sCurrentFail.failedAttempts;
}

std::shared_ptr<IAuthImplementation> CAuth::getImpl(eAuthImplementations implType) {
for (const auto& i : m_vImpls) {
if (i->getImplType() == implType)
Expand All @@ -89,11 +80,10 @@ void CAuth::terminate() {
}

static void passwordFailCallback(std::shared_ptr<CTimer> self, void* data) {
g_pAuth->m_bDisplayFailText = true;

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();
Expand All @@ -103,14 +93,16 @@ static void passwordUnlockCallback(std::shared_ptr<CTimer> self, void* data) {
g_pHyprlock->unlock();
}

void CAuth::enqueueFail() {
void CAuth::enqueueFail(const std::string& failText, eAuthImplementations implType) {
m_sCurrentFail.failText = failText;
m_sCurrentFail.failSource = implType;
m_sCurrentFail.failedAttempts++;

Debug::log(LOG, "Failed attempts: {}", m_sCurrentFail.failedAttempts);

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;
}
29 changes: 15 additions & 14 deletions src/auth/Auth.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,35 @@ class CAuth {
public:
CAuth();

void start();
void start();

void submitInput(const std::string& input);
bool checkWaiting();
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();
const std::string& getCurrentFailText();

std::optional<std::string> getFailText(eAuthImplementations implType);
std::optional<std::string> getPrompt(eAuthImplementations implType);
size_t getFailedAttempts();

std::shared_ptr<IAuthImplementation> 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(const std::string& failText, eAuthImplementations implType);

void enqueueUnlock();
void enqueueFail();
void postActivity(eAuthImplementations implType);
// 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<std::shared_ptr<IAuthImplementation>> m_vImpls;
std::optional<eAuthImplementations> m_eLastActiveImpl = std::nullopt;
};

inline std::unique_ptr<CAuth> g_pAuth;
57 changes: 19 additions & 38 deletions src/auth/Fingerprint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ bool CFingerprint::createDeviceProxy() {
bool isPresent = presentVariant.get<bool>();
if (!isPresent)
return;
m_sPrompt = m_sFingerprintPresent;
m_sFailureReason = "";
m_sPrompt = m_sFingerprintPresent;
g_pHyprlock->enqueueForceUpdateTimers();
} catch (std::out_of_range& e) {}
});
Expand All @@ -153,7 +152,6 @@ 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];
bool authenticated = false;
Expand All @@ -165,60 +163,47 @@ void CFingerprint::handleVerifyStatus(const std::string& result, bool done) {
case MATCH_NO_MATCH:
stopVerify();
if (m_sDBUSState.retries >= 3) {
m_sPrompt = "";
m_sFailureReason = "Fingerprint auth disabled (too many failed attempts)";
} else {
done = false;
done = false;
static const auto RETRYDELAY = **(Hyprlang::INT* const*)(g_pConfigManager->getValuePtr("auth:fingerprint:retry_delay"));
g_pHyprlock->addTimer(
std::chrono::milliseconds(RETRYDELAY),
[](std::shared_ptr<CTimer> self, void* data) {
((CFingerprint*)data)->startVerify(true);
},
this);
g_pHyprlock->addTimer(std::chrono::milliseconds(RETRYDELAY), [](std::shared_ptr<CTimer> self, void* data) { ((CFingerprint*)data)->startVerify(true); }, this);
m_sFailureReason = "Fingerprint did not match";
}
break;
case MATCH_UNKNOWN_ERROR:
stopVerify();
m_sPrompt = "";
m_sFailureReason = "Fingerprint auth disabled (unknown error)";
break;
case MATCH_MATCHED:
stopVerify();
m_sPrompt = "";
m_sFailureReason = "";
authenticated = true;
authenticated = true;
g_pAuth->enqueueUnlock();
break;
case MATCH_RETRY:
retry = true;
m_sPrompt = "Please retry fingerprint scan";
m_sFailureReason = "";
retry = true;
m_sPrompt = "Please retry fingerprint scan";
break;
case MATCH_SWIPE_TOO_SHORT:
retry = true;
m_sPrompt = "Swipe too short - try again";
m_sFailureReason = "";
retry = true;
m_sPrompt = "Swipe too short - try again";
break;
case MATCH_FINGER_NOT_CENTERED:
retry = true;
m_sPrompt = "Finger not centered - try again";
m_sFailureReason = "";
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";
m_sFailureReason = "";
retry = true;
m_sPrompt = "Remove your finger and try again";
break;
case MATCH_DISCONNECTED:
m_sPrompt = "";
m_sFailureReason = "Fingerprint device disconnected";
m_sDBUSState.abort = true;
break;
}

if (!authenticated && !retry)
g_pAuth->enqueueFail();
g_pAuth->enqueueFail(m_sFailureReason, AUTH_IMPL_FINGERPRINT);

if (done || m_sDBUSState.abort)
m_sDBUSState.done = true;
Expand Down Expand Up @@ -248,20 +233,16 @@ void CFingerprint::startVerify(bool isRetry) {
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_sPrompt = "";
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.";
m_sFailureReason = "";
} else {
m_sPrompt = m_sFingerprintReady;
m_sFailureReason = "";
}
m_sPrompt = "Could not match fingerprint. Try again.";
} else
m_sPrompt = m_sFingerprintReady;
}
g_pHyprlock->enqueueForceUpdateTimers();
});
Expand Down
4 changes: 1 addition & 3 deletions src/auth/Pam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ void CPam::init() {
return;

if (!AUTHENTICATED)
g_pAuth->enqueueFail();
g_pAuth->enqueueFail(m_sConversationState.failText, AUTH_IMPL_PAM);
else {
g_pAuth->enqueueUnlock();
return;
Expand Down Expand Up @@ -124,7 +124,6 @@ bool CPam::auth() {
handle = nullptr;

m_sConversationState.waitingForPamAuth = false;
g_pAuth->postActivity(AUTH_IMPL_PAM);

if (ret != PAM_SUCCESS) {
if (!m_sConversationState.failTextFromPam)
Expand Down Expand Up @@ -156,7 +155,6 @@ void CPam::waitForInput() {
}

void CPam::handleInput(const std::string& input) {
g_pAuth->postActivity(AUTH_IMPL_PAM);
std::unique_lock<std::mutex> lk(m_sConversationState.inputMutex);

if (!m_sConversationState.inputRequested)
Expand Down
48 changes: 26 additions & 22 deletions src/renderer/widgets/IWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ int IWidget::roundingForBorderBox(const CBox& borderBox, int roundingConfig, int

static void replaceAllAttempts(std::string& str) {

const size_t ATTEMPTS = g_pAuth->m_iFailedAttempts;
const size_t ATTEMPTS = g_pAuth->getFailedAttempts();
const std::string STR = std::to_string(ATTEMPTS);
size_t pos = 0;

Expand Down Expand Up @@ -118,16 +118,14 @@ static void replaceAllLayout(std::string& str) {
}
}

static bool logMissingTzOnce = true;
static bool logMissingTzOnce = true;
static std::chrono::hh_mm_ss<std::chrono::system_clock::duration> getTime() {
const std::chrono::time_zone* pCurrentTz = nullptr;
try {
auto name = std::getenv("TZ");
if (name)
pCurrentTz = std::chrono::locate_zone(name);
} catch (std::runtime_error&) {
Debug::log(WARN, "Invalid TZ value. Falling back to current timezone!");
}
} catch (std::runtime_error&) { Debug::log(WARN, "Invalid TZ value. Falling back to current timezone!"); }

if (!pCurrentTz)
pCurrentTz = std::chrono::current_zone();
Expand All @@ -150,15 +148,15 @@ static std::chrono::hh_mm_ss<std::chrono::system_clock::duration> getTime() {

static std::string getTime24h() {
const auto HHMMSS = getTime();
const auto HRS = HHMMSS.hours().count();
const auto MINS = HHMMSS.minutes().count();
const auto HRS = HHMMSS.hours().count();
const auto MINS = HHMMSS.minutes().count();
return (HRS < 10 ? "0" : "") + std::to_string(HRS) + ":" + (MINS < 10 ? "0" : "") + std::to_string(MINS);
}

static std::string getTime12h() {
const auto HHMMSS = getTime();
const auto HRS = HHMMSS.hours().count();
const auto MINS = HHMMSS.minutes().count();
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");
}
Expand Down Expand Up @@ -190,31 +188,37 @@ IWidget::SFormatResult IWidget::formatString(std::string in) {
result.updateEveryMs = result.updateEveryMs != 0 && result.updateEveryMs < 1000 ? result.updateEveryMs : 1000;
}

if (in.contains("$FAIL")) {
const auto FAIL = g_pAuth->getFailText(AUTH_IMPL_PAM);
replaceInString(in, "$FAIL", FAIL.value_or(""));
if (in.contains("$ATTEMPTS")) {
replaceAllAttempts(in);
result.allowForceUpdate = true;
}

if (in.contains("$PROMPT")) {
const auto PROMPT = g_pAuth->getPrompt(AUTH_IMPL_PAM);
replaceInString(in, "$PROMPT", PROMPT.value_or(""));
if (in.contains("$LAYOUT")) {
replaceAllLayout(in);
result.allowForceUpdate = true;
}

if (in.contains("$ATTEMPTS")) {
replaceAllAttempts(in);
if (in.contains("$FAIL")) {
const auto FAIL = g_pAuth->getCurrentFailText();
replaceInString(in, "$FAIL", FAIL);
result.allowForceUpdate = true;
}

if (in.contains("$LAYOUT")) {
replaceAllLayout(in);
if (in.contains("$PAMFAIL")) {
const auto FAIL = g_pAuth->getFailText(AUTH_IMPL_PAM);
replaceInString(in, "$PAMFAIL", FAIL.value_or(""));
result.allowForceUpdate = true;
}

if (in.contains("$PAMPROMPT")) {
const auto PROMPT = g_pAuth->getPrompt(AUTH_IMPL_PAM);
replaceInString(in, "$PAMPROMPT", PROMPT.value_or(""));
result.allowForceUpdate = true;
}

if (in.contains("$FPRINTMESSAGE")) {
const auto FPRINTMESSAGE = g_pAuth->getFailText(AUTH_IMPL_FINGERPRINT);
replaceInString(in, "$FPRINTMESSAGE", FPRINTMESSAGE.value_or(""));
if (in.contains("$FPRINTFAIL")) {
const auto FPRINTFAIL = g_pAuth->getFailText(AUTH_IMPL_FINGERPRINT);
replaceInString(in, "$FPRINTFAIL", FPRINTFAIL.value_or(""));
result.allowForceUpdate = true;
}

Expand Down
Loading
Loading