Allow path prefix multiplexing the dashboard and API (#3269)

This commit is contained in:
Dominik
2025-03-22 20:46:37 +01:00
committed by GitHub
28 changed files with 119 additions and 117 deletions

View File

@@ -9,12 +9,12 @@
mg.include('scripts/lua/header.lp','r') mg.include('scripts/lua/header.lp','r')
?> ?>
<body class="hold-transition layout-boxed login-page"> <body class="hold-transition layout-boxed login-page" data-apiurl="<?=pihole.api_url()?>">
<div class="box login-box" id="login-box"> <div class="box login-box" id="login-box">
<section style="padding: 15px;"> <section style="padding: 15px;">
<div class="login-logo"> <div class="login-logo">
<div class="text-center"> <div class="text-center">
<img src="<?=pihole.webhome()?>img/logo.svg" alt="Pi-hole logo" class="loginpage-logo" width="140" height="202"> <img src="<?=webhome?>img/logo.svg" alt="Pi-hole logo" class="loginpage-logo" width="140" height="202">
</div> </div>
<div class="panel-title text-center"><span class="logo-lg" style="font-size: 25px;">Pi-<b>hole</b></span></div> <div class="panel-title text-center"><span class="logo-lg" style="font-size: 25px;">Pi-<b>hole</b></span></div>
</div> </div>
@@ -117,7 +117,7 @@ mg.include('scripts/lua/header.lp','r')
<strong><a href="https://pi-hole.net/donate/" rel="noopener" target="_blank"><i class="fa fa-heart text-red"></i> Donate</a></strong> if you found this useful. <strong><a href="https://pi-hole.net/donate/" rel="noopener" target="_blank"><i class="fa fa-heart text-red"></i> Donate</a></strong> if you found this useful.
</div> </div>
</div> </div>
<script src="<?=pihole.fileversion('scripts/js/login.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/footer.js')?>"></script> <script src="<?=pihole.fileversion('scripts/js/footer.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/login.js')?>"></script>
</body> </body>
</html> </html>

View File

@@ -7,8 +7,8 @@
/* global utils:false, moment:false */ /* global utils:false, moment:false */
//The following functions allow us to display time until pi-hole is enabled after disabling. var _isLoginPage = false;
//Works between all pages const apiUrl = document.body.dataset.apiurl;
const REFRESH_INTERVAL = { const REFRESH_INTERVAL = {
logs: 500, // 0.5 sec (logs page) logs: 500, // 0.5 sec (logs page)
@@ -115,7 +115,7 @@ function checkBlocking() {
} }
$.ajax({ $.ajax({
url: "/api/dns/blocking", url: apiUrl + "/dns/blocking",
method: "GET", method: "GET",
}) })
.done(function (data) { .done(function (data) {
@@ -144,7 +144,7 @@ function piholeChange(action, duration) {
btnStatus.html("<i class='fa fa-spinner fa-spin'> </i>"); btnStatus.html("<i class='fa fa-spinner fa-spin'> </i>");
$.ajax({ $.ajax({
url: "/api/dns/blocking", url: apiUrl + "/dns/blocking",
method: "POST", method: "POST",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -267,7 +267,7 @@ function updateQueryFrequency(intl, frequency) {
var ftlinfoTimer = null; var ftlinfoTimer = null;
function updateFtlInfo() { function updateFtlInfo() {
$.ajax({ $.ajax({
url: "/api/info/ftl", url: apiUrl + "/info/ftl",
}) })
.done(function (data) { .done(function (data) {
var ftl = data.ftl; var ftl = data.ftl;
@@ -324,7 +324,7 @@ function updateFtlInfo() {
function updateSystemInfo() { function updateSystemInfo() {
$.ajax({ $.ajax({
url: "/api/info/system", url: apiUrl + "/info/system",
}) })
.done(function (data) { .done(function (data) {
var system = data.system; var system = data.system;
@@ -484,7 +484,7 @@ function versionCompare(v1, v2) {
function updateVersionInfo() { function updateVersionInfo() {
$.ajax({ $.ajax({
url: "/api/info/version", url: apiUrl + "/info/version",
}).done(function (data) { }).done(function (data) {
var version = data.version; var version = data.version;
var updateAvailable = false; var updateAvailable = false;
@@ -619,7 +619,7 @@ function updateVersionInfo() {
} }
$(function () { $(function () {
if (globalThis.location.pathname !== "/admin/login") updateInfo(); if (!_isLoginPage) updateInfo();
var enaT = $("#enableTimer"); var enaT = $("#enableTimer");
var target = new Date(parseInt(enaT.html(), 10)); var target = new Date(parseInt(enaT.html(), 10));
var seconds = Math.round((target.getTime() - Date.now()) / 1000); var seconds = Math.round((target.getTime() - Date.now()) / 1000);
@@ -634,7 +634,7 @@ $(function () {
// Apply per-browser styling settings // Apply per-browser styling settings
initCheckboxRadioStyle(); initCheckboxRadioStyle();
if (globalThis.location.pathname !== "/admin/login") { if (!_isLoginPage) {
// Run check immediately after page loading ... // Run check immediately after page loading ...
utils.checkMessages(); utils.checkMessages();
// ... and then periodically // ... and then periodically

View File

@@ -4,6 +4,7 @@
* *
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global apiUrl: false */
function eventsource() { function eventsource() {
var alInfo = $("#alInfo"); var alInfo = $("#alInfo");
@@ -15,7 +16,7 @@ function eventsource() {
alInfo.show(); alInfo.show();
alSuccess.hide(); alSuccess.hide();
fetch("/api/action/gravity", { fetch(apiUrl + "/action/gravity", {
method: "POST", method: "POST",
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") }, headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") },
}) })

View File

@@ -5,14 +5,14 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, groups:false,, apiFailure:false, updateFtlInfo:false, getGroups:false, processGroupResult:false, delGroupItems:false */ /* global utils:false, apiUrl:false, groups:false,, apiFailure:false, updateFtlInfo:false, getGroups:false, processGroupResult:false, delGroupItems:false */
/* exported initTable */ /* exported initTable */
var table; var table;
function reloadClientSuggestions() { function reloadClientSuggestions() {
$.ajax({ $.ajax({
url: "/api/clients/_suggestions", url: apiUrl + "/clients/_suggestions",
type: "GET", type: "GET",
dataType: "json", dataType: "json",
success: function (data) { success: function (data) {
@@ -96,7 +96,7 @@ function initTable() {
table = $("#clientsTable").DataTable({ table = $("#clientsTable").DataTable({
processing: true, processing: true,
ajax: { ajax: {
url: "/api/clients", url: apiUrl + "/clients",
dataSrc: "clients", dataSrc: "clients",
type: "GET", type: "GET",
}, },
@@ -402,7 +402,7 @@ function addClient() {
} }
$.ajax({ $.ajax({
url: "/api/clients", url: apiUrl + "/clients",
method: "post", method: "post",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -459,7 +459,7 @@ function editClient() {
const clientDecoded = utils.hexDecode(client); const clientDecoded = utils.hexDecode(client);
utils.showAlert("info", "", "Editing client...", clientDecoded); utils.showAlert("info", "", "Editing client...", clientDecoded);
$.ajax({ $.ajax({
url: "/api/clients/" + encodeURIComponent(clientDecoded), url: apiUrl + "/clients/" + encodeURIComponent(clientDecoded),
method: "put", method: "put",
dataType: "json", dataType: "json",
processData: false, processData: false,

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global apiFailure:false, utils:false, initTable:false, updateFtlInfo:false */ /* global apiFailure:false, utils:false, apiUrl:false, initTable:false, updateFtlInfo:false */
var groups = []; var groups = [];
@@ -39,7 +39,7 @@ function populateGroupSelect(selectEl) {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
function getGroups(groupSelector) { function getGroups(groupSelector) {
$.ajax({ $.ajax({
url: "/api/groups", url: apiUrl + "/groups",
type: "GET", type: "GET",
dataType: "json", dataType: "json",
success: function (data) { success: function (data) {
@@ -79,7 +79,7 @@ function delGroupItems(type, ids, table, listType = undefined) {
// Check input validity // Check input validity
if (!Array.isArray(ids)) return; if (!Array.isArray(ids)) return;
const url = "/api/" + type + "s:batchDelete"; const url = apiUrl + "/" + type + "s:batchDelete";
// use utils.hexDecode() to decode all clients // use utils.hexDecode() to decode all clients
let idstring = ""; let idstring = "";

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, groups:false,, getGroups:false, updateFtlInfo:false, apiFailure:false, processGroupResult:false, delGroupItems:false */ /* global utils:false, apiUrl:false, groups:false,, getGroups:false, updateFtlInfo:false, apiFailure:false, processGroupResult:false, delGroupItems:false */
/* exported initTable */ /* exported initTable */
var table; var table;
@@ -91,7 +91,7 @@ function initTable() {
table = $("#domainsTable").DataTable({ table = $("#domainsTable").DataTable({
processing: true, processing: true,
ajax: { ajax: {
url: "/api/domains", url: apiUrl + "/domains",
dataSrc: "domains", dataSrc: "domains",
type: "GET", type: "GET",
}, },
@@ -507,7 +507,7 @@ function addDomain() {
const type = action === "add_deny" ? "deny" : "allow"; const type = action === "add_deny" ? "deny" : "allow";
$.ajax({ $.ajax({
url: "/api/domains/" + type + "/" + kind, url: apiUrl + "/domains/" + type + "/" + kind,
method: "post", method: "post",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -596,7 +596,7 @@ function editDomain() {
const domainDecoded = utils.hexDecode(domain.split("_")[0]); const domainDecoded = utils.hexDecode(domain.split("_")[0]);
utils.showAlert("info", "", "Editing domain...", domainDecoded); utils.showAlert("info", "", "Editing domain...", domainDecoded);
$.ajax({ $.ajax({
url: "/api/domains/" + newTypestr + "/" + encodeURIComponent(domainDecoded), url: apiUrl + "/domains/" + newTypestr + "/" + encodeURIComponent(domainDecoded),
method: "put", method: "put",
dataType: "json", dataType: "json",
processData: false, processData: false,

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, groups:false, apiFailure:false, updateFtlInfo:false, getGroups:false, processGroupResult:false, delGroupItems:false */ /* global utils:false, apiUrl:false, groups:false, apiFailure:false, updateFtlInfo:false, getGroups:false, processGroupResult:false, delGroupItems:false */
/* exported initTable */ /* exported initTable */
var table; var table;
@@ -170,7 +170,7 @@ function initTable() {
table = $("#listsTable").DataTable({ table = $("#listsTable").DataTable({
processing: true, processing: true,
ajax: { ajax: {
url: "/api/lists", url: apiUrl + "/lists",
dataSrc: "lists", dataSrc: "lists",
type: "GET", type: "GET",
}, },
@@ -519,7 +519,7 @@ function addList(event) {
} }
$.ajax({ $.ajax({
url: "/api/lists", url: apiUrl + "/lists",
method: "post", method: "post",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -588,7 +588,7 @@ function editList() {
utils.disableAll(); utils.disableAll();
utils.showAlert("info", "", "Editing address...", address); utils.showAlert("info", "", "Editing address...", address);
$.ajax({ $.ajax({
url: "/api/lists/" + encodeURIComponent(address) + "?type=" + type, url: apiUrl + "/lists/" + encodeURIComponent(address) + "?type=" + type,
method: "put", method: "put",
dataType: "json", dataType: "json",
processData: false, processData: false,

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, apiFailure:false, updateFtlInfo:false, processGroupResult:false, delGroupItems:false */ /* global utils:false, apiUrl:false, apiFailure:false, updateFtlInfo:false, processGroupResult:false, delGroupItems:false */
var table; var table;
@@ -26,7 +26,7 @@ $(function () {
table = $("#groupsTable").DataTable({ table = $("#groupsTable").DataTable({
processing: true, processing: true,
ajax: { ajax: {
url: "/api/groups", url: apiUrl + "/groups",
error: handleAjaxError, error: handleAjaxError,
dataSrc: "groups", dataSrc: "groups",
type: "GET", type: "GET",
@@ -261,7 +261,7 @@ function addGroup() {
} }
$.ajax({ $.ajax({
url: "/api/groups", url: apiUrl + "/groups",
method: "post", method: "post",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -329,7 +329,7 @@ function editGroup() {
utils.disableAll(); utils.disableAll();
utils.showAlert("info", "", "Editing group...", oldName); utils.showAlert("info", "", "Editing group...", oldName);
$.ajax({ $.ajax({
url: "/api/groups/" + oldName, url: apiUrl + "/groups/" + oldName,
method: "put", method: "put",
dataType: "json", dataType: "json",
processData: false, processData: false,

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, Chart:false, apiFailure:false, THEME_COLORS:false, customTooltips:false, htmlLegendPlugin:false,doughnutTooltip:false, ChartDeferred:false, REFRESH_INTERVAL: false, updateQueryFrequency: false */ /* global utils:false, apiUrl:false, Chart:false, apiFailure:false, THEME_COLORS:false, customTooltips:false, htmlLegendPlugin:false,doughnutTooltip:false, ChartDeferred:false, REFRESH_INTERVAL: false, updateQueryFrequency: false */
// Define global variables // Define global variables
var timeLineChart, clientsChart; var timeLineChart, clientsChart;
@@ -22,7 +22,7 @@ Chart.defaults.set("plugins.deferred", {
var failures = 0; var failures = 0;
function updateQueriesOverTime() { function updateQueriesOverTime() {
$.getJSON("/api/history", function (data) { $.getJSON(apiUrl + "/history", function (data) {
// Remove graph if there are no results (e.g. new // Remove graph if there are no results (e.g. new
// installation or privacy mode enabled) // installation or privacy mode enabled)
if (jQuery.isEmptyObject(data.history)) { if (jQuery.isEmptyObject(data.history)) {
@@ -92,7 +92,7 @@ function updateQueriesOverTime() {
} }
function updateQueryTypesPie() { function updateQueryTypesPie() {
$.getJSON("/api/stats/query_types", function (data) { $.getJSON(apiUrl + "/stats/query_types", function (data) {
var v = [], var v = [],
c = [], c = [],
k = [], k = [],
@@ -134,7 +134,7 @@ function updateQueryTypesPie() {
} }
function updateClientsOverTime() { function updateClientsOverTime() {
$.getJSON("/api/history/clients", function (data) { $.getJSON(apiUrl + "/history/clients", function (data) {
// Remove graph if there are no results (e.g. new // Remove graph if there are no results (e.g. new
// installation or privacy mode enabled) // installation or privacy mode enabled)
if (jQuery.isEmptyObject(data.history)) { if (jQuery.isEmptyObject(data.history)) {
@@ -212,7 +212,7 @@ function updateClientsOverTime() {
var upstreams = {}; var upstreams = {};
function updateForwardDestinationsPie() { function updateForwardDestinationsPie() {
$.getJSON("/api/stats/upstreams", function (data) { $.getJSON(apiUrl + "/stats/upstreams", function (data) {
var v = [], var v = [],
c = [], c = [],
k = [], k = [],
@@ -273,13 +273,13 @@ function updateForwardDestinationsPie() {
function updateTopClientsTable(blocked) { function updateTopClientsTable(blocked) {
let api, style, tablecontent, overlay, clienttable; let api, style, tablecontent, overlay, clienttable;
if (blocked) { if (blocked) {
api = "/api/stats/top_clients?blocked=true"; api = apiUrl + "/stats/top_clients?blocked=true";
style = "queries-blocked"; style = "queries-blocked";
tablecontent = $("#client-frequency-blocked td").parent(); tablecontent = $("#client-frequency-blocked td").parent();
overlay = $("#client-frequency-blocked .overlay"); overlay = $("#client-frequency-blocked .overlay");
clienttable = $("#client-frequency-blocked").find("tbody:last"); clienttable = $("#client-frequency-blocked").find("tbody:last");
} else { } else {
api = "/api/stats/top_clients"; api = apiUrl + "/stats/top_clients";
style = "queries-permitted"; style = "queries-permitted";
tablecontent = $("#client-frequency td").parent(); tablecontent = $("#client-frequency td").parent();
overlay = $("#client-frequency .overlay"); overlay = $("#client-frequency .overlay");
@@ -333,13 +333,13 @@ function updateTopClientsTable(blocked) {
function updateTopDomainsTable(blocked) { function updateTopDomainsTable(blocked) {
let api, style, tablecontent, overlay, domaintable; let api, style, tablecontent, overlay, domaintable;
if (blocked) { if (blocked) {
api = "/api/stats/top_domains?blocked=true"; api = apiUrl + "/stats/top_domains?blocked=true";
style = "queries-blocked"; style = "queries-blocked";
tablecontent = $("#ad-frequency td").parent(); tablecontent = $("#ad-frequency td").parent();
overlay = $("#ad-frequency .overlay"); overlay = $("#ad-frequency .overlay");
domaintable = $("#ad-frequency").find("tbody:last"); domaintable = $("#ad-frequency").find("tbody:last");
} else { } else {
api = "/api/stats/top_domains"; api = apiUrl + "/stats/top_domains";
style = "queries-permitted"; style = "queries-permitted";
tablecontent = $("#domain-frequency td").parent(); tablecontent = $("#domain-frequency td").parent();
overlay = $("#domain-frequency .overlay"); overlay = $("#domain-frequency .overlay");
@@ -408,7 +408,7 @@ function updateTopLists() {
var previousCount = 0; var previousCount = 0;
var firstSummaryUpdate = true; var firstSummaryUpdate = true;
function updateSummaryData(runOnce = false) { function updateSummaryData(runOnce = false) {
$.getJSON("/api/stats/summary", function (data) { $.getJSON(apiUrl + "/stats/summary", function (data) {
var intl = new Intl.NumberFormat(); var intl = new Intl.NumberFormat();
const newCount = parseInt(data.queries.total, 10); const newCount = parseInt(data.queries.total, 10);

View File

@@ -5,11 +5,11 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils */ /* global utils: false, apiUrl: false */
$(function () { $(function () {
$.ajax({ $.ajax({
url: "/api/network/gateway", url: apiUrl + "/network/gateway",
data: { detailed: true }, data: { detailed: true },
}).done(function (data) { }).done(function (data) {
var intl = new Intl.NumberFormat(); var intl = new Intl.NumberFormat();

View File

@@ -5,7 +5,9 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, NProgress:false */ /* global utils:false, apiUrl: false, NProgress:false */
var _isLoginPage = true;
function redirect() { function redirect() {
// Login succeeded or not needed (empty password) // Login succeeded or not needed (empty password)
@@ -89,7 +91,7 @@ function doLogin(password) {
NProgress.start(); NProgress.start();
utils.disableAll(); utils.disableAll();
$.ajax({ $.ajax({
url: "/api/auth", url: apiUrl + "/auth",
method: "POST", method: "POST",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -161,7 +163,7 @@ function showDNSfailure() {
$(function () { $(function () {
// Check if we need to login at all // Check if we need to login at all
$.ajax({ $.ajax({
url: "/api/auth", url: apiUrl + "/auth",
}) })
.done(function (data) { .done(function (data) {
// If we are already logged in, redirect to dashboard // If we are already logged in, redirect to dashboard
@@ -180,7 +182,7 @@ $(function () {
// Get information about HTTPS port and DNS status // Get information about HTTPS port and DNS status
$.ajax({ $.ajax({
url: "/api/info/login", url: apiUrl + "/info/login",
}).done(function (data) { }).done(function (data) {
if (data.dns === false) showDNSfailure(); if (data.dns === false) showDNSfailure();

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false */ /* global utils: false, apiUrl: false */
var table, var table,
toasts = {}; toasts = {};
@@ -13,7 +13,7 @@ $(function () {
var ignoreNonfatal = localStorage var ignoreNonfatal = localStorage
? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true" ? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true"
: false; : false;
var url = "/api/info/messages" + (ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : ""); var url = apiUrl + "/info/messages" + (ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : "");
table = $("#messagesTable").DataTable({ table = $("#messagesTable").DataTable({
ajax: { ajax: {
url: url, url: url,
@@ -157,7 +157,7 @@ function delMsg(id) {
toasts[id] = utils.showAlert("info", "", "Deleting message...", "ID: " + id, null); toasts[id] = utils.showAlert("info", "", "Deleting message...", "ID: " + id, null);
$.ajax({ $.ajax({
url: "/api/info/messages/" + id, url: apiUrl + "/info/messages/" + id,
method: "DELETE", method: "DELETE",
}) })
.done(function (response) { .done(function (response) {

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, apiFailure:false */ /* global utils:false, apiUrl:false, apiFailure:false */
var tableApi; var tableApi;
@@ -64,7 +64,7 @@ function deleteNetworkEntry() {
utils.disableAll(); utils.disableAll();
utils.showAlert("info", "", "Deleting network table entry..."); utils.showAlert("info", "", "Deleting network table entry...");
$.ajax({ $.ajax({
url: "/api/network/devices/" + id, url: apiUrl + "/network/devices/" + id,
method: "DELETE", method: "DELETE",
success: function () { success: function () {
utils.enableAll(); utils.enableAll();
@@ -208,7 +208,7 @@ $(function () {
"<'row'<'col-sm-12'<'table-responsive'tr>>>" + "<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>", "<'row'<'col-sm-5'i><'col-sm-7'p>>",
ajax: { ajax: {
url: "/api/network/devices", url: apiUrl + "/network/devices",
type: "GET", type: "GET",
dataType: "json", dataType: "json",
data: { data: {

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global moment:false, utils:false, REFRESH_INTERVAL:false */ /* global moment:false, utils:false, apiUrl:false, REFRESH_INTERVAL:false */
const beginningOfTime = 1262304000; // Jan 01 2010, 00:00 in seconds const beginningOfTime = 1262304000; // Jan 01 2010, 00:00 in seconds
const endOfTime = 2147483647; // Jan 19, 2038, 03:14 in seconds const endOfTime = 2147483647; // Jan 19, 2038, 03:14 in seconds
@@ -424,7 +424,7 @@ function addSelectSuggestion(name, dict, data) {
function getSuggestions(dict) { function getSuggestions(dict) {
$.get( $.get(
"/api/queries/suggestions", apiUrl + "/queries/suggestions",
function (data) { function (data) {
for (var key in filters) { for (var key in filters) {
if (Object.hasOwnProperty.call(filters, key)) { if (Object.hasOwnProperty.call(filters, key)) {
@@ -455,7 +455,7 @@ function filterOn(param, dict) {
} }
function getAPIURL(filters) { function getAPIURL(filters) {
var apiurl = "/api/queries?"; var apiurl = apiUrl + "/queries?";
for (var key in filters) { for (var key in filters) {
if (Object.hasOwnProperty.call(filters, key)) { if (Object.hasOwnProperty.call(filters, key)) {
var filter = filters[key]; var filter = filters[key];

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, apiFailure:false */ /* global utils:false, apiUrl:false, apiFailure:false */
var GETDict = {}; var GETDict = {};
$(function () { $(function () {
@@ -35,7 +35,7 @@ function doSearch() {
$.ajax({ $.ajax({
method: "GET", method: "GET",
url: "/api/search/" + encodeURIComponent(q), url: apiUrl + "/search/" + encodeURIComponent(q),
async: false, async: false,
data: { data: {
partial: partial, partial: partial,

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, apiFailure: false, applyCheckboxRadioStyle: false, saveSettings:false */ /* global utils:false, apiUrl:false, apiFailure: false, applyCheckboxRadioStyle: false, saveSettings:false */
/* exported createDynamicConfigTabs */ /* exported createDynamicConfigTabs */
function addAllowedValues(allowed) { function addAllowedValues(allowed) {
@@ -296,7 +296,7 @@ function generateRow(topic, key, value) {
function createDynamicConfigTabs() { function createDynamicConfigTabs() {
$.ajax({ $.ajax({
url: "/api/config?detailed=true", url: apiUrl + "/config?detailed=true",
}) })
.done(function (data) { .done(function (data) {
// Create the tabs for the advanced dynamic config topics // Create the tabs for the advanced dynamic config topics

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, setConfigValues: false, apiFailure: false, QRious: false */ /* global utils:false, apiUrl:false, setConfigValues: false, apiFailure: false, QRious: false */
var apiSessionsTable = null; var apiSessionsTable = null;
var ownSessionID = null; var ownSessionID = null;
@@ -31,7 +31,7 @@ function renderBool(data, type) {
$(function () { $(function () {
apiSessionsTable = $("#APISessionsTable").DataTable({ apiSessionsTable = $("#APISessionsTable").DataTable({
ajax: { ajax: {
url: "/api/auth/sessions", url: apiUrl + "/auth/sessions",
type: "GET", type: "GET",
dataSrc: "sessions", dataSrc: "sessions",
}, },
@@ -247,7 +247,7 @@ function deleteOneSession(id, len, ownSessionDelete) {
// our own session is then triggered by the last successful deletion of // our own session is then triggered by the last successful deletion of
// another session (ownSessionDelete == true, len == global deleted) // another session (ownSessionDelete == true, len == global deleted)
$.ajax({ $.ajax({
url: "/api/auth/session/" + id, url: apiUrl + "/auth/session/" + id,
method: "DELETE", method: "DELETE",
}) })
.done(function () { .done(function () {
@@ -272,7 +272,7 @@ function deleteOneSession(id, len, ownSessionDelete) {
function processWebServerConfig() { function processWebServerConfig() {
$.ajax({ $.ajax({
url: "/api/config/webserver?detailed=true", url: apiUrl + "/config/webserver?detailed=true",
}) })
.done(function (data) { .done(function (data) {
setConfigValues("webserver", "webserver", data.config.webserver); setConfigValues("webserver", "webserver", data.config.webserver);
@@ -291,7 +291,7 @@ function processWebServerConfig() {
$("#modal-totp").on("shown.bs.modal", function () { $("#modal-totp").on("shown.bs.modal", function () {
$.ajax({ $.ajax({
url: "/api/auth/totp", url: apiUrl + "/auth/totp",
}) })
.done(function (data) { .done(function (data) {
TOTPdata = data.totp; TOTPdata = data.totp;
@@ -329,7 +329,7 @@ $("#modal-totp").on("shown.bs.modal", function () {
var apppwhash = null; var apppwhash = null;
$("#modal-apppw").on("shown.bs.modal", function () { $("#modal-apppw").on("shown.bs.modal", function () {
$.ajax({ $.ajax({
url: "/api/auth/app", url: apiUrl + "/auth/app",
}) })
.done(function (data) { .done(function (data) {
apppwhash = data.app.hash; apppwhash = data.app.hash;
@@ -373,7 +373,7 @@ $("#apppw_clear").on("click", function () {
function setAppPassword() { function setAppPassword() {
$.ajax({ $.ajax({
url: "/api/config", url: apiUrl + "/config",
type: "PATCH", type: "PATCH",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -426,7 +426,7 @@ $("#totp_code").on("keyup", function () {
function setTOTPSecret(secret) { function setTOTPSecret(secret) {
$.ajax({ $.ajax({
url: "/api/config", url: apiUrl + "/config",
type: "PATCH", type: "PATCH",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -478,7 +478,7 @@ $(document).ready(function () {
processWebServerConfig(); processWebServerConfig();
// Check if TOTP is enabled // Check if TOTP is enabled
$.ajax({ $.ajax({
url: "/api/auth", url: apiUrl + "/auth",
}).done(function (data) { }).done(function (data) {
if (data.session.totp === false) $("#button-enable-totp").removeClass("hidden"); if (data.session.totp === false) $("#button-enable-totp").removeClass("hidden");
else $("#button-disable-totp").removeClass("hidden"); else $("#button-disable-totp").removeClass("hidden");

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, setConfigValues: false, apiFailure: false */ /* global utils:false, apiUrl:false, setConfigValues: false, apiFailure: false */
var dhcpLeaesTable = null, var dhcpLeaesTable = null,
toasts = {}; toasts = {};
@@ -32,7 +32,7 @@ function renderHostnameCLID(data, type) {
$(function () { $(function () {
dhcpLeaesTable = $("#DHCPLeasesTable").DataTable({ dhcpLeaesTable = $("#DHCPLeasesTable").DataTable({
ajax: { ajax: {
url: "/api/dhcp/leases", url: apiUrl + "/dhcp/leases",
type: "GET", type: "GET",
dataSrc: "leases", dataSrc: "leases",
}, },
@@ -167,7 +167,7 @@ function delLease(ip) {
toasts[ip] = utils.showAlert("info", "", "Deleting lease...", ip, null); toasts[ip] = utils.showAlert("info", "", "Deleting lease...", ip, null);
$.ajax({ $.ajax({
url: "/api/dhcp/leases/" + encodeURIComponent(ip), url: apiUrl + "/dhcp/leases/" + encodeURIComponent(ip),
method: "DELETE", method: "DELETE",
}) })
.done(function (response) { .done(function (response) {
@@ -214,7 +214,7 @@ function fillDHCPhosts(data) {
function processDHCPConfig() { function processDHCPConfig() {
$.ajax({ $.ajax({
url: "/api/config/dhcp?detailed=true", url: apiUrl + "/config/dhcp?detailed=true",
}) })
.done(function (data) { .done(function (data) {
fillDHCPhosts(data.config.dhcp.hosts); fillDHCPhosts(data.config.dhcp.hosts);

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Precord see LICENSE file for your rights under this license. */ * Precord see LICENSE file for your rights under this license. */
/* global utils: false, apiFailure:false, setConfigValues: false */ /* global utils: false, apiUrl: false, apiFailure:false, setConfigValues: false */
function hostsDomain(data) { function hostsDomain(data) {
// Split record in format IP NAME1 [NAME2 [NAME3 [NAME...]]] // Split record in format IP NAME1 [NAME2 [NAME3 [NAME...]]]
@@ -156,7 +156,7 @@ function deleteRecord() {
function delHosts(elem) { function delHosts(elem) {
utils.disableAll(); utils.disableAll();
utils.showAlert("info", "", "Deleting DNS record...", elem); utils.showAlert("info", "", "Deleting DNS record...", elem);
const url = "/api/config/dns/hosts/" + encodeURIComponent(elem); const url = apiUrl + "/config/dns/hosts/" + encodeURIComponent(elem);
$.ajax({ $.ajax({
url: url, url: url,
@@ -183,7 +183,7 @@ function delHosts(elem) {
function delCNAME(elem) { function delCNAME(elem) {
utils.disableAll(); utils.disableAll();
utils.showAlert("info", "", "Deleting local CNAME record...", elem); utils.showAlert("info", "", "Deleting local CNAME record...", elem);
const url = "/api/config/dns/cnameRecords/" + encodeURIComponent(elem); const url = apiUrl + "/config/dns/cnameRecords/" + encodeURIComponent(elem);
$.ajax({ $.ajax({
url: url, url: url,
@@ -216,7 +216,7 @@ $(document).ready(function () {
$("#btnAdd-host").on("click", function () { $("#btnAdd-host").on("click", function () {
utils.disableAll(); utils.disableAll();
const elem = $("#Hip").val() + " " + $("#Hdomain").val(); const elem = $("#Hip").val() + " " + $("#Hdomain").val();
const url = "/api/config/dns/hosts/" + encodeURIComponent(elem); const url = apiUrl + "/config/dns/hosts/" + encodeURIComponent(elem);
utils.showAlert("info", "", "Adding DNS record...", elem); utils.showAlert("info", "", "Adding DNS record...", elem);
$.ajax({ $.ajax({
url: url, url: url,
@@ -242,7 +242,7 @@ $(document).ready(function () {
var elem = $("#Cdomain").val() + "," + $("#Ctarget").val(); var elem = $("#Cdomain").val() + "," + $("#Ctarget").val();
var ttlVal = parseInt($("#Cttl").val(), 10); var ttlVal = parseInt($("#Cttl").val(), 10);
if (isFinite(ttlVal) && ttlVal >= 0) elem += "," + ttlVal; if (isFinite(ttlVal) && ttlVal >= 0) elem += "," + ttlVal;
const url = "/api/config/dns/cnameRecords/" + encodeURIComponent(elem); const url = apiUrl + "/config/dns/cnameRecords/" + encodeURIComponent(elem);
utils.showAlert("info", "", "Adding DNS record...", elem); utils.showAlert("info", "", "Adding DNS record...", elem);
$.ajax({ $.ajax({
url: url, url: url,

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global applyCheckboxRadioStyle:false, setConfigValues: false, apiFailure: false */ /* global applyCheckboxRadioStyle:false, setConfigValues: false, apiFailure: false, apiUrl: false */
// Remove an element from an array (inline) // Remove an element from an array (inline)
function removeFromArray(arr, what) { function removeFromArray(arr, what) {
@@ -114,7 +114,7 @@ function updateDNSserversTextfield(upstreams, customServers) {
function processDNSConfig() { function processDNSConfig() {
$.ajax({ $.ajax({
url: "/api/config/dns?detailed=true", // We need the detailed output to get the DNS server list url: apiUrl + "/config/dns?detailed=true", // We need the detailed output to get the DNS server list
}) })
.done(function (data) { .done(function (data) {
// Initialize the DNS upstreams // Initialize the DNS upstreams

View File

@@ -5,11 +5,11 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global setConfigValues: false, apiFailure: false */ /* global setConfigValues: false, apiFailure: false, apiUrl: false */
function getConfig() { function getConfig() {
$.ajax({ $.ajax({
url: "/api/config/?detailed=true", url: apiUrl + "/config/?detailed=true",
}) })
.done(function (data) { .done(function (data) {
setConfigValues("", "", data.config); setConfigValues("", "", data.config);

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global apiFailure:false, Chart:false, THEME_COLORS:false, customTooltips:false, htmlLegendPlugin:false,doughnutTooltip:false, ChartDeferred:false, REFRESH_INTERVAL: false, utils: false */ /* global apiFailure:false, apiUrl: false, Chart:false, THEME_COLORS:false, customTooltips:false, htmlLegendPlugin:false,doughnutTooltip:false, ChartDeferred:false, REFRESH_INTERVAL: false, utils: false */
var hostinfoTimer = null; var hostinfoTimer = null;
var cachePieChart = null; var cachePieChart = null;
@@ -83,7 +83,7 @@ function updateCachePie(data) {
function updateHostInfo() { function updateHostInfo() {
$.ajax({ $.ajax({
url: "/api/info/host", url: apiUrl + "/info/host",
}) })
.done(function (data) { .done(function (data) {
var host = data.host; var host = data.host;
@@ -155,7 +155,7 @@ var metricsTimer = null;
function updateMetrics() { function updateMetrics() {
$.ajax({ $.ajax({
url: "/api/info/metrics", url: apiUrl + "/info/metrics",
}) })
.done(function (data) { .done(function (data) {
var metrics = data.metrics; var metrics = data.metrics;
@@ -196,7 +196,7 @@ function showQueryLoggingButton(state) {
function getLoggingButton() { function getLoggingButton() {
$.ajax({ $.ajax({
url: "/api/config/dns/queryLogging", url: apiUrl + "/config/dns/queryLogging",
}) })
.done(function (data) { .done(function (data) {
showQueryLoggingButton(data.config.dns.queryLogging); showQueryLoggingButton(data.config.dns.queryLogging);
@@ -214,7 +214,7 @@ $(".confirm-restartdns").confirm({
title: "Confirmation required", title: "Confirmation required",
confirm: function () { confirm: function () {
$.ajax({ $.ajax({
url: "/api/action/restartdns", url: apiUrl + "/action/restartdns",
type: "POST", type: "POST",
}).fail(function (data) { }).fail(function (data) {
apiFailure(data); apiFailure(data);
@@ -238,7 +238,7 @@ $(".confirm-flushlogs").confirm({
title: "Confirmation required", title: "Confirmation required",
confirm: function () { confirm: function () {
$.ajax({ $.ajax({
url: "/api/action/flush/logs", url: apiUrl + "/action/flush/logs",
type: "POST", type: "POST",
}).fail(function (data) { }).fail(function (data) {
apiFailure(data); apiFailure(data);
@@ -262,7 +262,7 @@ $(".confirm-flusharp").confirm({
title: "Confirmation required", title: "Confirmation required",
confirm: function () { confirm: function () {
$.ajax({ $.ajax({
url: "/api/action/flush/arp", url: apiUrl + "/action/flush/arp",
type: "POST", type: "POST",
}).fail(function (data) { }).fail(function (data) {
apiFailure(data); apiFailure(data);
@@ -292,7 +292,7 @@ $("#loggingButton").confirm({
data.config.dns = {}; data.config.dns = {};
data.config.dns.queryLogging = $("#loggingButton").data("state") !== "enabled"; data.config.dns.queryLogging = $("#loggingButton").data("state") !== "enabled";
$.ajax({ $.ajax({
url: "/api/config/dns/queryLogging", url: apiUrl + "/config/dns/queryLogging",
type: "PATCH", type: "PATCH",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -364,7 +364,7 @@ $(function () {
}); });
$.ajax({ $.ajax({
url: "/api/network/gateway", url: apiUrl + "/network/gateway",
}) })
.done(function (data) { .done(function (data) {
const gateway = data.gateway; const gateway = data.gateway;

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false */ /* global utils:false, apiUrl: false */
// Add event listener to import button // Add event listener to import button
document.getElementById("submit-import").addEventListener("click", function () { document.getElementById("submit-import").addEventListener("click", function () {
@@ -37,8 +37,7 @@ function importZIP() {
const formData = new FormData(); const formData = new FormData();
formData.append("import", JSON.stringify(imports)); formData.append("import", JSON.stringify(imports));
formData.append("file", file); formData.append("file", file);
fetch(apiUrl + "/teleporter", {
fetch("/api/teleporter", {
method: "POST", method: "POST",
body: formData, body: formData,
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") }, headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") },
@@ -78,7 +77,7 @@ function importZIP() {
// Inspired by https://stackoverflow.com/a/59576416/2087442 // Inspired by https://stackoverflow.com/a/59576416/2087442
$("#GETTeleporter").on("click", function () { $("#GETTeleporter").on("click", function () {
$.ajax({ $.ajax({
url: "/api/teleporter", url: apiUrl + "/teleporter",
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") }, headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") },
method: "GET", method: "GET",
xhrFields: { xhrFields: {

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global utils:false, apiFailure:false*/ /* global utils:false, apiUrl:false, apiFailure:false*/
$(function () { $(function () {
// Handle hiding of alerts // Handle hiding of alerts
@@ -164,7 +164,7 @@ function saveSettings() {
// Apply changes // Apply changes
$.ajax({ $.ajax({
url: "/api/config", url: apiUrl + "/config",
method: "PATCH", method: "PATCH",
dataType: "json", dataType: "json",
processData: false, processData: false,

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global moment: false, apiFailure: false, utils: false, REFRESH_INTERVAL: false */ /* global moment: false, apiFailure: false, utils: false, REFRESH_INTERVAL: false, apiUrl: false */
var nextID = 0; var nextID = 0;
var lastPID = -1; var lastPID = -1;
@@ -84,7 +84,7 @@ function getData() {
} }
$.ajax({ $.ajax({
url: "/api/logs/" + GETDict.file + "?nextID=" + nextID, url: apiUrl + "/logs/" + GETDict.file + "?nextID=" + nextID,
timeout: 5000, timeout: 5000,
method: "GET", method: "GET",
}) })

View File

@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL. * This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */ * Please see LICENSE file for your rights under this license. */
/* global moment:false, apiFailure: false, updateFtlInfo: false, NProgress:false */ /* global moment:false, apiUrl: false, apiFailure: false, updateFtlInfo: false, NProgress:false */
$(function () { $(function () {
// CSRF protection for AJAX requests, this has to be configured globally // CSRF protection for AJAX requests, this has to be configured globally
@@ -331,7 +331,7 @@ function addFromQueryLog(domain, list) {
// add Domain to List after Modal has faded in // add Domain to List after Modal has faded in
alertModal.one("shown.bs.modal", function () { alertModal.one("shown.bs.modal", function () {
$.ajax({ $.ajax({
url: "/api/domains/" + list + "/exact", url: apiUrl + "/domains/" + list + "/exact",
method: "post", method: "post",
dataType: "json", dataType: "json",
processData: false, processData: false,
@@ -411,7 +411,7 @@ function checkMessages() {
? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true" ? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true"
: false; : false;
$.ajax({ $.ajax({
url: "/api/info/messages/count" + (ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : ""), url: apiUrl + "/info/messages/count" + (ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : ""),
method: "GET", method: "GET",
dataType: "json", dataType: "json",
}) })
@@ -465,7 +465,7 @@ function changeBulkDeleteStates(table) {
function doLogout() { function doLogout() {
$.ajax({ $.ajax({
url: "/api/auth", url: apiUrl + "/auth",
method: "DELETE", method: "DELETE",
}).always(function () { }).always(function () {
location.reload(); location.reload();
@@ -646,7 +646,7 @@ function listAlert(type, items, data) {
function loadingOverlayTimeoutCallback(reloadAfterTimeout) { function loadingOverlayTimeoutCallback(reloadAfterTimeout) {
// Try to ping FTL to see if it finished restarting // Try to ping FTL to see if it finished restarting
$.ajax({ $.ajax({
url: "/api/info/login", url: apiUrl + "/info/login",
method: "GET", method: "GET",
cache: false, cache: false,
dataType: "json", dataType: "json",

View File

@@ -11,6 +11,7 @@
starttime = mg.time(true) starttime = mg.time(true)
hostname = pihole.hostname() hostname = pihole.hostname()
webhome = pihole.webhome() webhome = pihole.webhome()
theme = pihole.webtheme()
-- Get name of script by matching whatever is after the last "/" in the URI -- Get name of script by matching whatever is after the last "/" in the URI
scriptname = mg.request_info.request_uri:match(webhome.."(.*)$") scriptname = mg.request_info.request_uri:match(webhome.."(.*)$")
@@ -55,15 +56,14 @@ is_authenticated = mg.request_info.is_authenticated
<meta name="csrf-token" content="<?=mg.request_info.csrf_token?>"> <meta name="csrf-token" content="<?=mg.request_info.csrf_token?>">
<link rel="apple-touch-icon" href="<?=pihole.webhome()?>img/favicons/apple-touch-icon.png" sizes="180x180"> <link rel="apple-touch-icon" href="<?=webhome?>img/favicons/apple-touch-icon.png" sizes="180x180">
<link rel="icon" href="<?=pihole.webhome()?>img/favicons/favicon-32x32.png" sizes="32x32" type="image/png"> <link rel="icon" href="<?=webhome?>img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
<link rel="icon" href="<?=pihole.webhome()?>img/favicons/favicon-16x16.png" sizes="16x16" type="image/png"> <link rel="icon" href="<?=webhome?>img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
<link rel="manifest" href="<?=pihole.webhome()?>img/favicons/manifest.json"> <link rel="manifest" href="<?=webhome?>img/favicons/manifest.json">
<? theme = pihole.webtheme() ?> <link rel="mask-icon" href="<?=webhome?>img/favicons/safari-pinned-tab.svg" color="<?=theme.color?>">
<link rel="mask-icon" href="<?=pihole.webhome()?>img/favicons/safari-pinned-tab.svg" color="<?=theme.color?>"> <link rel="shortcut icon" href="<?=webhome?>img/favicons/favicon.ico">
<link rel="shortcut icon" href="<?=pihole.webhome()?>img/favicons/favicon.ico">
<meta name="msapplication-TileColor" content="<?=theme.color?>"> <meta name="msapplication-TileColor" content="<?=theme.color?>">
<meta name="msapplication-TileImage" content="<?=pihole.webhome()?>img/favicons/mstile-150x150.png"> <meta name="msapplication-TileImage" content="<?=webhome?>img/favicons/mstile-150x150.png">
<!-- Theme styles --> <!-- Theme styles -->
<meta name="theme-color" content="<?=theme.color?>"> <meta name="theme-color" content="<?=theme.color?>">

View File

@@ -22,7 +22,7 @@ mg.include('header.lp','r')
<script src="<?=pihole.fileversion('vendor/chartjs-plugin-zoom/chartjs-plugin-zoom.min.js')?>"></script> <script src="<?=pihole.fileversion('vendor/chartjs-plugin-zoom/chartjs-plugin-zoom.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/bstreeview/bstreeview.min.js')?>"></script> <script src="<?=pihole.fileversion('vendor/bstreeview/bstreeview.min.js')?>"></script>
</head> </head>
<body class="<?=theme.name?> hold-transition sidebar-mini <? if pihole.boxedlayout() then ?>layout-boxed<? end ?> logged-in"> <body class="<?=theme.name?> hold-transition sidebar-mini <? if pihole.boxedlayout() then ?>layout-boxed<? end ?> logged-in" data-apiurl="<?=pihole.api_url()?>">
<noscript> <noscript>
<!-- JS Warning --> <!-- JS Warning -->
<div> <div>
@@ -39,7 +39,7 @@ mg.include('header.lp','r')
<div class="wrapper"> <div class="wrapper">
<header class="main-header"> <header class="main-header">
<!-- Logo --> <!-- Logo -->
<a href="<?=pihole.webhome()?>" class="logo"> <a href="<?=webhome?>" class="logo">
<!-- mini logo for sidebar mini 50x50 pixels --> <!-- mini logo for sidebar mini 50x50 pixels -->
<span class="logo-mini">P<strong>h</strong></span> <span class="logo-mini">P<strong>h</strong></span>
<!-- logo for regular state and mobile devices --> <!-- logo for regular state and mobile devices -->
@@ -68,7 +68,7 @@ mg.include('header.lp','r')
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<!-- User image --> <!-- User image -->
<li class="user-header"> <li class="user-header">
<img class="logo-img" src="<?=pihole.webhome()?>img/logo.svg" alt="Pi-hole Logo" width="50" height="50"> <img class="logo-img" src="<?=webhome?>img/logo.svg" alt="Pi-hole Logo" width="50" height="50">
<p> <p>
Open Source Ad Blocker Open Source Ad Blocker
</p> </p>