Files
web/scripts/js/login.js
2025-05-01 20:00:07 +03:00

201 lines
6.2 KiB
JavaScript

/* Pi-hole: A black hole for Internet advertisements
* (c) 2023 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global utils:false, NProgress:false */
"use strict";
globalThis._isLoginPage = true;
function redirect() {
// Login succeeded or not needed (empty password)
// Default: Send back to dashboard
let target = ".";
// If DNS failure: send to Pi-hole diagnosis messages page
if ($("#dns-failure-label").is(":visible")) {
target = "messages";
}
// Redirect to target
globalThis.location.replace(target);
}
function wrongPassword(isError = false, isSuccess = false, data = null) {
if (isError) {
let isErrorResponse = false;
let isInvalidTOTP = false;
// Reset hint and error message
$("#error-message").text("");
$("#error-hint").hide();
$("#error-hint").text("");
if (data !== null && "error" in data.responseJSON && "message" in data.responseJSON.error) {
// This is an error, highlight both the password and the TOTP field
isErrorResponse = true;
// Check if the error is caused by an invalid TOTP token
isInvalidTOTP = data.responseJSON.error.message === "Invalid 2FA token";
$("#error-message").text(data.responseJSON.error.message);
if ("hint" in data.responseJSON.error && data.responseJSON.error.hint !== null) {
$("#error-hint").text(data.responseJSON.error.hint);
$("#error-hint").show();
}
} else {
$("#error-message").text("Wrong password!");
}
$("#error-label").show();
// Always highlight the TOTP field on error
if (isErrorResponse) $("#totp_input").addClass("has-error");
// Only show the invalid 2FA box if the error is caused by an invalid TOTP
// token
if (isInvalidTOTP) $("#invalid2fa-box").removeClass("hidden");
// Only highlight the password field if the error is NOT caused by an
// invalid TOTP token
if (!isInvalidTOTP) $("#pw-field").addClass("has-error");
// Only show the forgot password box if the error is NOT caused by an
// invalid TOTP token and this is no error response (= password is wrong)
if (!isErrorResponse && !isInvalidTOTP) {
$("#forgot-pw-box")
.removeClass("box-info")
.removeClass("collapsed-box")
.addClass("box-danger");
$("#forgot-pw-box .box-body").show();
$("#forgot-pw-toggle-icon").removeClass("fa-plus").addClass("fa-minus");
}
return;
}
if (isSuccess) {
$("#pw-field").addClass("has-success");
$("#totp_input").addClass("has-success");
} else {
$("#pw-field").removeClass("has-error");
$("#totp_input").removeClass("has-error");
$("#error-label").hide();
}
$("#invalid2fa-box").addClass("hidden");
$("#forgot-pw-box").addClass("box-info").addClass("collapsed-box").removeClass("box-danger");
$("#forgot-pw-box .box-body").hide();
$("#forgot-pw-toggle-icon").removeClass("fa-minus").addClass("fa-plus");
}
function doLogin(password) {
wrongPassword(false, false, null);
NProgress.start();
utils.disableAll();
$.ajax({
url: document.body.dataset.apiurl + "/auth",
method: "POST",
dataType: "json",
processData: false,
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ password, totp: Number.parseInt($("#totp").val(), 10) }),
})
.done(data => {
wrongPassword(false, true, data);
NProgress.done();
redirect();
})
.fail(data => {
wrongPassword(true, false, data);
NProgress.done();
utils.enableAll();
});
}
$("#loginform").on("submit", event => {
// Cancel the native submit event (prevent the form from being
// submitted) because we want to do a two-step challenge-response login
event.preventDefault();
doLogin($("#current-password").val());
});
// Submit form when TOTP code is entered and password is already filled
$("#totp").on("input", function () {
const code = $(this).val();
const password = $("#current-password").val();
if (code.length === 6 && password.length > 0) {
$("#loginform").trigger("submit");
}
});
// Toggle password visibility button
$("#toggle-password").on("click", function () {
// Toggle font-awesome classes to change the svg icon on the button
$(".field-icon", this).toggleClass("fa-eye fa-eye-slash");
// Password field
const $pwd = $("#current-password");
if ($pwd.attr("type") === "password") {
$pwd.attr("type", "text");
$pwd.attr("title", "Hide password");
} else {
$pwd.attr("type", "password");
$pwd.attr(
"title",
"Show password as plain text. Warning: this will display your password on the screen"
);
}
// move the focus to password field after the click
$pwd.trigger("focus");
});
function showDNSfailure() {
$("#dns-failure-label").show();
$("#login-box").addClass("error-box");
}
$(() => {
// Check if we need to login at all
$.ajax({
url: document.body.dataset.apiurl + "/auth",
})
.done(data => {
// If we are already logged in, redirect to dashboard
if (data.session.valid === true) redirect();
})
.fail(xhr => {
const session = xhr.responseJSON.session;
// If TOPT is enabled, show the input field and add the required attribute
if (session.totp === true) {
$("#totp_input").removeClass("hidden");
$("#totp").attr("required", "required");
$("#totp-forgotten-title").removeClass("hidden");
$("#totp-forgotten-body").removeClass("hidden");
}
});
// Get information about HTTPS port and DNS status
$.ajax({
url: document.body.dataset.apiurl + "/info/login",
}).done(data => {
if (data.dns === false) showDNSfailure();
// Generate HTTPS redirection link (only used if not already HTTPS)
if (location.protocol !== "https:" && data.https_port !== 0) {
let url = "https://" + location.hostname;
if (data.https_port !== 443) url += ":" + data.https_port;
url += location.pathname + location.search + location.hash;
$("#https-link").attr("href", url);
$("#insecure-box").show();
}
});
// Clear TOTP field
$("#totp").val("");
});