From b0b439e4dfdb64fb36c043b8aea4ef0efe8fa908 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 11 May 2026 12:20:46 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=A1=D0=9F=D0=A0=D0=90=D0=92=D0=9B?= =?UTF-8?q?=D0=95=D0=9D=D0=98=D0=95=20-=20NODEDC=20AUTH:=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20login=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=B0=D0=BA=D0=BA=D0=B0=D1=83=D0=BD=D1=82=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../custom-templates/base/header_js.html | 104 +++++++++++++++--- 1 file changed, 91 insertions(+), 13 deletions(-) diff --git a/infra/authentik/custom-templates/base/header_js.html b/infra/authentik/custom-templates/base/header_js.html index 612a137..bef08fd 100644 --- a/infra/authentik/custom-templates/base/header_js.html +++ b/infra/authentik/custom-templates/base/header_js.html @@ -60,12 +60,15 @@ `; + const genericLoginError = "Не удалось выполнить вход. Проверьте email и пароль или запросите доступ."; + const revokedLoginError = "Аккаунт больше не активен. Запросите доступ, если хотите подключиться снова."; + const accountStatusCache = new Map(); const authTranslations = new Map([ - ["Failed to authenticate.", "Не удалось выполнить вход."], - ["Invalid credentials.", "Неверная почта или пароль."], - ["Invalid password.", "Неверный пароль."], - ["Incorrect password.", "Неверный пароль."], - ["Authentication failed.", "Не удалось выполнить вход."], + ["Failed to authenticate.", genericLoginError], + ["Invalid credentials.", genericLoginError], + ["Invalid password.", genericLoginError], + ["Incorrect password.", genericLoginError], + ["Authentication failed.", genericLoginError], ["This field is required.", "Заполните это поле."], ["Please enter your password", "Введите пароль"], ["Please enter your password.", "Введите пароль."], @@ -385,6 +388,87 @@ form.appendChild(link); } + function normalizeEmail(value) { + return typeof value === "string" ? value.trim().toLowerCase() : ""; + } + + function getLoginEmail(root) { + return normalizeEmail(root.querySelector("#ak-identifier-input")?.value); + } + + function getLoginErrorMessages() { + return [ + "Failed to authenticate.", + "Invalid credentials.", + "Invalid password.", + "Incorrect password.", + "Authentication failed.", + "Не удалось выполнить вход.", + "Неверная почта или пароль.", + "Неверный пароль.", + genericLoginError, + revokedLoginError, + ]; + } + + function replaceLoginErrorText(root, message) { + const errorMessages = getLoginErrorMessages(); + const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, { + acceptNode(node) { + const text = node.nodeValue?.trim() || ""; + return errorMessages.some((errorMessage) => text.includes(errorMessage)) + ? NodeFilter.FILTER_ACCEPT + : NodeFilter.FILTER_REJECT; + }, + }); + const textNodes = []; + + while (walker.nextNode()) { + textNodes.push(walker.currentNode); + } + + textNodes.forEach((node) => { + const currentValue = node.nodeValue || ""; + const trimmed = currentValue.trim(); + if (!trimmed) return; + node.nodeValue = currentValue.replace(trimmed, message); + }); + } + + function syncLoginErrorReason(root) { + if (!hasAuthError(root)) return; + + replaceLoginErrorText(root, genericLoginError); + const email = getLoginEmail(root); + if (!email) return; + + const cachedStatus = accountStatusCache.get(email); + if (cachedStatus === "revoked") { + replaceLoginErrorText(root, revokedLoginError); + return; + } + + if (cachedStatus === "unknown" || cachedStatus === "loading") return; + + accountStatusCache.set(email, "loading"); + const statusUrl = new URL("/api/public/login-account-status", getLauncherBaseUrl()); + statusUrl.searchParams.set("email", email); + + fetch(statusUrl.toString(), { cache: "no-store" }) + .then((response) => (response.ok ? response.json() : null)) + .then((payload) => { + const status = payload?.status === "revoked" ? "revoked" : "unknown"; + accountStatusCache.set(email, status); + if (status !== "revoked") return; + visitRoots(document, (candidateRoot) => { + replaceLoginErrorText(candidateRoot, revokedLoginError); + }); + }) + .catch(() => { + accountStatusCache.set(email, "unknown"); + }); + } + function hasAuthError(root) { const hasErrorElement = root.querySelector( ".pf-c-alert, .pf-m-error, .pf-c-helper-text__item.pf-m-error, [aria-invalid='true']" @@ -392,14 +476,7 @@ if (hasErrorElement) return true; const text = root.textContent || ""; - return [ - "Failed to authenticate.", - "Не удалось выполнить вход.", - "Invalid credentials.", - "Неверная почта или пароль.", - "Invalid password.", - "Неверный пароль.", - ].some((message) => text.includes(message)); + return getLoginErrorMessages().some((message) => text.includes(message)); } function restoreCardOnErrors(root) { @@ -480,6 +557,7 @@ enhanceSubmitHandoff(root); ensureAccessRequestLink(root); translateAuthText(root); + syncLoginErrorReason(root); applyPermissionDeniedLayout(root); hidePermissionDeniedReason(root); restoreCardOnErrors(root);