mirror of
https://github.com/pi-hole/web.git
synced 2025-12-19 18:28:24 +00:00
Pi-hole Web v6.4 (#3670)
This commit is contained in:
8
.github/workflows/codeql.yml
vendored
8
.github/workflows/codeql.yml
vendored
@@ -26,21 +26,21 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 #v6.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@16140ae1a102900babc80a33c44059580f687047 #v4.30.9
|
||||
uses: github/codeql-action/init@e12f0178983d466f2f6028f5cc7a6d786fd97f4b #v4.31.4
|
||||
with:
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
languages: "javascript"
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@16140ae1a102900babc80a33c44059580f687047 #v4.30.9
|
||||
uses: github/codeql-action/autobuild@e12f0178983d466f2f6028f5cc7a6d786fd97f4b #v4.31.4
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@16140ae1a102900babc80a33c44059580f687047 #v4.30.9
|
||||
uses: github/codeql-action/analyze@e12f0178983d466f2f6028f5cc7a6d786fd97f4b #v4.31.4
|
||||
with:
|
||||
category: "/language:javascript"
|
||||
|
||||
4
.github/workflows/codespell.yml
vendored
4
.github/workflows/codespell.yml
vendored
@@ -13,12 +13,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 #v6.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Spell-Checking
|
||||
uses: codespell-project/actions-codespell@406322ec52dd7b488e48c1c4b82e2a8b3a1bf630 #v2.1
|
||||
uses: codespell-project/actions-codespell@8f01853be192eb0f849a5c7d721450e7a467c579 #v2.2
|
||||
with:
|
||||
ignore_words_file: .codespellignore
|
||||
skip: ./vendor,./package.json,./package-lock.json
|
||||
|
||||
4
.github/workflows/editorconfig-checker.yml
vendored
4
.github/workflows/editorconfig-checker.yml
vendored
@@ -10,8 +10,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 #v6.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: editorconfig-checker/action-editorconfig-checker@5ecdd656fe347c26f76b1b435b90e1d74fb5e787 # tag v2. is really out of date
|
||||
- uses: editorconfig-checker/action-editorconfig-checker@4b6cd6190d435e7e084fb35e36a096e98506f7b9 #v2.1.0
|
||||
- run: editorconfig-checker
|
||||
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -41,7 +41,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 #v6.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Remove 'stale' label
|
||||
|
||||
2
.github/workflows/sync-back-to-dev.yml
vendored
2
.github/workflows/sync-back-to-dev.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
name: Syncing branches
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 #v6.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Opening pull request
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #v5.0.0
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 #v6.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
|
||||
2
login.lp
2
login.lp
@@ -53,7 +53,7 @@ mg.include('scripts/lua/header.lp','r')
|
||||
</div>
|
||||
<div class="form-group hidden" id="totp_input">
|
||||
<div class="input-group">
|
||||
<input type="text" id="totp" size="6" maxlen="6" class="form-control totp_token" placeholder="123456" value="" spellcheck="false" autofocus autocomplete="off">
|
||||
<input type="text" id="totp" size="6" maxlen="6" class="form-control totp_token" placeholder="123456" value="" spellcheck="false" autofocus autocomplete="one-time-code">
|
||||
<div class="input-group-addon" data-toggle="tooltip" data-placement="auto" title="TOTP verification code">
|
||||
<i class="fa fa-clock-rotate-left"></i>
|
||||
</div>
|
||||
|
||||
956
package-lock.json
generated
956
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,7 @@
|
||||
"bootstrap-select": "1.13.18",
|
||||
"bootstrap-toggle": "2.2.2",
|
||||
"bstreeview": "1.2.0",
|
||||
"chart.js": "4.5.0",
|
||||
"chart.js": "4.5.1",
|
||||
"chartjs-adapter-moment": "1.0.1",
|
||||
"chartjs-plugin-deferred": "2.0.0",
|
||||
"chartjs-plugin-zoom": "2.2.0",
|
||||
@@ -52,10 +52,10 @@
|
||||
"select2": "4.0.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^9.38.0",
|
||||
"autoprefixer": "^10.4.22",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-plugin-compat": "^6.0.2",
|
||||
"globals": "^16.4.0",
|
||||
"globals": "^16.5.0",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-cli": "^11.0.1",
|
||||
"prettier": "^3.6.2",
|
||||
|
||||
@@ -64,6 +64,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
|
||||
</div>
|
||||
<input type="button" class="form-control pull-right" id="querytime" value="Click to select date and time range">
|
||||
</div>
|
||||
<small id="querytime-note" class="form-text text-muted" style="margin-top: 5px;"></small>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<div><input type="checkbox" id="disk"><label for="disk">Query on-disk data. This is <em>a lot</em> slower but necessary if you want to obtain queries older than 24 hours. This option disables live update.</label></div>
|
||||
|
||||
@@ -15,7 +15,7 @@ function eventsource() {
|
||||
const outputElement = document.getElementById("output");
|
||||
const gravityBtn = document.getElementById("gravityBtn");
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute("content");
|
||||
const url = `${document.body.dataset.apiurl}/action/gravity`;
|
||||
const url = `${document.body.dataset.apiurl}/action/gravity?color=true`;
|
||||
|
||||
if (outputElement.innerHTML.length > 0) {
|
||||
outputElement.innerHTML = "";
|
||||
|
||||
@@ -13,13 +13,7 @@ let table;
|
||||
const toasts = {};
|
||||
|
||||
$(() => {
|
||||
const ignoreNonfatal = localStorage
|
||||
? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true"
|
||||
: false;
|
||||
const url =
|
||||
document.body.dataset.apiurl +
|
||||
"/info/messages" +
|
||||
(ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : "");
|
||||
const url = document.body.dataset.apiurl + "/info/messages";
|
||||
table = $("#messagesTable").DataTable({
|
||||
ajax: {
|
||||
url,
|
||||
|
||||
@@ -9,10 +9,13 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const beginningOfTime = 1_262_304_000; // Jan 01 2010, 00:00 in seconds
|
||||
const endOfTime = 2_147_483_647; // Jan 19, 2038, 03:14 in seconds
|
||||
let from = beginningOfTime;
|
||||
let until = endOfTime;
|
||||
// These values are provided by the API (/info/database).
|
||||
// We initialize them as null and populate them during page init.
|
||||
let beginningOfTime = null; // seconds since epoch (set from API: info/database.earliest_timestamp)
|
||||
// endOfTime should be the end of today (local), in seconds since epoch
|
||||
const endOfTime = moment().endOf("day").unix();
|
||||
let from = null;
|
||||
let until = null;
|
||||
|
||||
const dateformat = "MMM Do YYYY, HH:mm";
|
||||
|
||||
@@ -34,10 +37,58 @@ let doDNSSEC = false;
|
||||
function getDnssecConfig() {
|
||||
$.getJSON(document.body.dataset.apiurl + "/config/dns/dnssec", data => {
|
||||
doDNSSEC = data.config.dns.dnssec;
|
||||
|
||||
// redraw the table to show the icons when the API call returns
|
||||
$("#all-queries").DataTable().draw();
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch database info (earliest timestamp, sizes, ...) from the API and
|
||||
// initialize related globals.
|
||||
function getDatabaseInfo() {
|
||||
$.getJSON(document.body.dataset.apiurl + "/info/database", data => {
|
||||
// earliest_timestamp is provided in seconds since epoch
|
||||
// We have two sources: earliest_timestamp_disk (on-disk) and earliest_timestamp (in-memory)
|
||||
// Use whichever is smallest and non-zero
|
||||
const diskTimestamp = Number(data.earliest_timestamp_disk);
|
||||
const memoryTimestamp = Number(data.earliest_timestamp);
|
||||
|
||||
// Filter out zero/invalid timestamps
|
||||
const validTimestamps = [diskTimestamp, memoryTimestamp].filter(ts => ts > 0);
|
||||
|
||||
// Use the smallest valid timestamp, or null if none exist
|
||||
beginningOfTime = validTimestamps.length > 0 ? Math.min(...validTimestamps) : null;
|
||||
|
||||
// Round down to nearest 5-minute segment (300 seconds) if valid
|
||||
if (beginningOfTime !== null) {
|
||||
beginningOfTime = Math.floor(beginningOfTime / 300) * 300;
|
||||
}
|
||||
|
||||
// If from/until were not provided via GET, default them
|
||||
// Only use defaults if beginningOfTime is valid
|
||||
if (beginningOfTime !== null) {
|
||||
from ??= beginningOfTime;
|
||||
until ??= endOfTime;
|
||||
}
|
||||
|
||||
initDateRangePicker();
|
||||
});
|
||||
}
|
||||
|
||||
function initDateRangePicker() {
|
||||
// If there's no valid data in the database, disable the datepicker
|
||||
if (beginningOfTime === null) {
|
||||
$("#querytime").prop("disabled", true);
|
||||
$("#querytime").addClass("disabled");
|
||||
$("#querytime-note").text("ℹ️ No data in the database");
|
||||
return;
|
||||
}
|
||||
|
||||
const minDateMoment = moment.unix(beginningOfTime);
|
||||
const maxDateMoment = moment.unix(endOfTime);
|
||||
const earliestDateStr = minDateMoment.format(dateformat);
|
||||
$("#querytime-note").text(`Earliest date: ${earliestDateStr}`);
|
||||
|
||||
$("#querytime").daterangepicker(
|
||||
{
|
||||
timePicker: true,
|
||||
@@ -49,21 +100,24 @@ function initDateRangePicker() {
|
||||
ranges: {
|
||||
"Last 10 Minutes": [moment().subtract(10, "minutes"), moment()],
|
||||
"Last Hour": [moment().subtract(1, "hours"), moment()],
|
||||
Today: [moment().startOf("day"), moment().endOf("day")],
|
||||
Today: [moment().startOf("day"), maxDateMoment],
|
||||
Yesterday: [
|
||||
moment().subtract(1, "days").startOf("day"),
|
||||
moment().subtract(1, "days").endOf("day"),
|
||||
],
|
||||
"Last 7 Days": [moment().subtract(6, "days"), moment().endOf("day")],
|
||||
"Last 30 Days": [moment().subtract(29, "days"), moment().endOf("day")],
|
||||
"This Month": [moment().startOf("month"), moment().endOf("month")],
|
||||
"Last 7 Days": [moment().subtract(6, "days").startOf("day"), maxDateMoment],
|
||||
"Last 30 Days": [moment().subtract(29, "days").startOf("day"), maxDateMoment],
|
||||
"This Month": [moment().startOf("month"), maxDateMoment],
|
||||
"Last Month": [
|
||||
moment().subtract(1, "month").startOf("month"),
|
||||
moment().subtract(1, "month").endOf("month"),
|
||||
],
|
||||
"This Year": [moment().startOf("year"), moment().endOf("year")],
|
||||
"All Time": [moment(beginningOfTime * 1000), moment(endOfTime * 1000)], // convert to milliseconds since epoch
|
||||
"This Year": [moment().startOf("year"), maxDateMoment],
|
||||
"All Time": [minDateMoment, maxDateMoment],
|
||||
},
|
||||
// Don't allow selecting dates outside the database range
|
||||
minDate: minDateMoment,
|
||||
maxDate: maxDateMoment,
|
||||
opens: "center",
|
||||
showDropdowns: true,
|
||||
autoUpdateInput: true,
|
||||
@@ -507,14 +561,15 @@ $(() => {
|
||||
const apiURL = getAPIURL(GETDict);
|
||||
|
||||
if ("from" in GETDict) {
|
||||
from = GETDict.from;
|
||||
from = Number(GETDict.from);
|
||||
}
|
||||
|
||||
if ("until" in GETDict) {
|
||||
until = GETDict.until;
|
||||
until = Number(GETDict.until);
|
||||
}
|
||||
|
||||
initDateRangePicker();
|
||||
// Fetch earliest timestamp from API and initialize date picker / table
|
||||
getDatabaseInfo();
|
||||
|
||||
table = $("#all-queries").DataTable({
|
||||
ajax: {
|
||||
|
||||
@@ -386,14 +386,8 @@ function colorBar(percentage, total, cssClass) {
|
||||
}
|
||||
|
||||
function checkMessages() {
|
||||
const ignoreNonfatal = localStorage
|
||||
? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true"
|
||||
: false;
|
||||
$.ajax({
|
||||
url:
|
||||
document.body.dataset.apiurl +
|
||||
"/info/messages/count" +
|
||||
(ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : ""),
|
||||
url: document.body.dataset.apiurl + "/info/messages/count",
|
||||
method: "GET",
|
||||
dataType: "json",
|
||||
})
|
||||
|
||||
@@ -26,14 +26,14 @@ mg.include('scripts/lua/header_authenticated.lp','r')
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="col-md-6">
|
||||
<div>
|
||||
<input type="checkbox" id="partialMatch" data-key="partialMatch">
|
||||
<label for="partialMatch"><strong>Use partial matching</strong></label>
|
||||
<label for="partialMatch"><strong>Use partial matching</strong> (may not find complex regex entries)</label>
|
||||
</div>
|
||||
</div>
|
||||
<br class="hidden-md hidden-lg">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-6">
|
||||
<div id="domain-limitbox-block" class="form-inline">
|
||||
<label for="number">Maximum number of results to be returned: </label>
|
||||
<input class="form-control input-sm" type="number" min="0" value="20" id="number">
|
||||
|
||||
4
vendor/chartjs/chart.umd.min.js
vendored
4
vendor/chartjs/chart.umd.min.js
vendored
File diff suppressed because one or more lines are too long
2
vendor/chartjs/chart.umd.min.js.map
vendored
2
vendor/chartjs/chart.umd.min.js.map
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user