Pi-hole Web v6.1 (#3354)

This commit is contained in:
Adam Warner
2025-03-30 17:54:52 +01:00
committed by GitHub
120 changed files with 804 additions and 733 deletions
+2 -1
View File
@@ -1 +1,2 @@
* text=auto
# Enforce Unix newlines
* text=auto eol=lf
+3
View File
@@ -0,0 +1,3 @@
name: "CodeQL config"
paths-ignore:
- "**/vendor/**"
+18 -7
View File
@@ -7,29 +7,40 @@ on:
- development
- "!dependabot/**"
pull_request:
# The branches below must be a subset of the branches above
branches:
- master
- development
- "!dependabot/**"
schedule:
- cron: "0 0 * * 0"
workflow_dispatch:
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout repository
- name: Clone repository
uses: actions/checkout@v4.2.2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@v3.28.13
with:
config-file: ./.github/codeql/codeql-config.yml
languages: "javascript"
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v3.28.13
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v3.28.13
with:
category: "/language:javascript"
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
uses: actions/checkout@v4.2.2
- name: Set up Node.js
uses: actions/setup-node@v4.2.0
uses: actions/setup-node@v4.3.0
with:
node-version: "20.x"
cache: npm
+1 -1
View File
@@ -27,5 +27,5 @@ mg.include('scripts/lua/header_authenticated.lp','r')
<button type="button" id="gravityBtn" class="btn btn-lg btn-primary btn-block">Update</button>
<pre id="output" style="width: 100%; height: 100%;" hidden></pre>
<script src="<?=pihole.fileversion('scripts/js/gravity.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/gravity.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+5 -5
View File
@@ -95,10 +95,10 @@ mg.include('scripts/lua/header_authenticated.lp','r')
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/groups-common.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/groups-clients.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/groups-common.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/groups-clients.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+4 -4
View File
@@ -156,9 +156,9 @@ mg.include('scripts/lua/header_authenticated.lp','r')
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/groups-common.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/groups-domains.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/groups-common.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/groups-domains.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+5 -5
View File
@@ -46,7 +46,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
<strong>Hints:</strong>
<ol>
<li>Please run <code>pihole -g</code> or update your gravity list <a href="<?=webhome?>gravity">online</a> after modifying your lists.</li>
<li>Multiple lists can be added by separating each <i>unique</i> URL with a space or comma</li>
<li>Multiple lists can be added by separating each <em>unique</em> URL with a space or comma</li>
<li>Click on the icon in the first column to get additional information about your lists. The icons correspond to the health of the list.</li>
</ol>
<div class="btn-toolbar pull-right" role="toolbar" aria-label="Toolbar with buttons">
@@ -94,9 +94,9 @@ mg.include('scripts/lua/header_authenticated.lp','r')
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/groups-common.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/groups-lists.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/groups-common.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/groups-lists.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+4 -4
View File
@@ -79,9 +79,9 @@ mg.include('scripts/lua/header_authenticated.lp','r')
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/groups-common.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/groups.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/groups-common.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/groups.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="currentcolor" class="svg-inline--fa fa-fw menu-icon" viewBox="0 0 88.32 129.93">
<path d="M36.56 39.93C20.34 38.2 4 25.94 2.71 0c25.17 0 38.63 14.9 39.93 38.51 4.76-28.32 27.07-25 27.07-25 1.06 16.05-12.12 25.78-27.07 26.59-4.2-8.85-29.36-30.56-29.36-30.56a.07.07 0 0 0-.11.08s24.28 21.15 23.39 30.31m7.6 90c-1.57-.09-16.22-.65-17.11-17.11-.72-10 7.18-17.37 7.18-27.08C32.44 61.53 0 64.53 0 85.74a19.94 19.94 0 0 0 5.83 14.14L30 124.06a19.94 19.94 0 0 0 14.14 5.83"/>
<path d="M88.32 85.75c-.09 1.57-.65 16.22-17.11 17.11-10 .72-17.38-7.18-27.08-7.18-24.21 1.79-21.21 34.22 0 34.22a19.94 19.94 0 0 0 14.14-5.83L82.46 99.9a19.94 19.94 0 0 0 5.83-14.14"/>
<path d="M44.16 41.59c1.57.09 16.22.65 17.11 17.11.72 10-7.18 17.37-7.18 27.08 1.79 24.21 34.22 21.21 34.22 0a19.94 19.94 0 0 0-5.83-14.14L58.3 47.45a19.94 19.94 0 0 0-14.14-5.83"/>
<path d="M.08 85.75c.09-1.57.65-16.22 17.11-17.11 10-.72 17.38 7.18 27.08 7.18 24.21-1.82 21.21-34.22 0-34.22a19.94 19.94 0 0 0-14.14 5.83L5.94 71.61A19.94 19.94 0 0 0 .11 85.75"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

-12
View File
@@ -1,12 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<symbol id="drop">
<path d="M1 85.459c0-1.717 1.707-16.993 16.907-16.993 9.998-.717 17.766 7.169 27.464 7.169 24.208-1.814 20.952-34.293-.252-34.293-5.3-.014-10.179 2.22-13.929 5.954L6.738 71.747C2.68 75.792 1 80.972 1 85.459z"/>
</symbol>
<symbol id="pihole-svg-logo" viewBox="-20 0 130 130">
<path fill="currentColor" d="M37.4 40.145C21.18 38.415 4.84 26.155 3.55.215c25.17 0 38.63 14.9 39.93 38.51 4.76-28.32 27.07-25 27.07-25 1.06 16.05-12.12 25.78-27.07 26.59-4.2-8.85-29.36-30.56-29.36-30.56a.07.07 0 0 0-.11.08s24.28 21.15 23.39 30.31"/>
<use xlink:href="#drop" fill="currentColor" transform="rotate(180 45 85.3)"/>
<use xlink:href="#drop" fill="currentColor" transform="rotate(90 45 85.3)"/>
<use xlink:href="#drop" fill="currentColor" transform="rotate(-90 45 85.3)"/>
<use xlink:href="#drop" fill="currentColor"/>
</symbol>
</svg>

Before

Width:  |  Height:  |  Size: 949 B

+6 -6
View File
@@ -22,7 +22,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
<div class="icon">
<i class="fas fa-globe-americas"></i>
</div>
<a href="network.lp" class="small-box-footer" title="" id="total_clients">
<a href="network" class="small-box-footer" id="total_clients">
<span id="active_clients">-</span> active clients <i class="fa fa-arrow-circle-right"></i>
</a>
</div>
@@ -38,7 +38,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
<div class="icon">
<i class="fas fa-hand-paper"></i>
</div>
<a href="queries.lp?upstream=blocklist" class="small-box-footer" title="">
<a href="queries?upstream=blocklist" class="small-box-footer">
List blocked queries <i class="fa fa-arrow-circle-right"></i>
</a>
</div>
@@ -54,7 +54,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
<div class="icon">
<i class="fas fa-chart-pie"></i>
</div>
<a href="queries.lp" class="small-box-footer" title="">
<a href="queries" class="small-box-footer">
List all queries <i class="fa fa-arrow-circle-right"></i>
</a>
</div>
@@ -70,7 +70,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
<div class="icon">
<i class="fas fa-list-alt"></i>
</div>
<a href="groups-lists.lp" class="small-box-footer" title="">
<a href="groups-lists" class="small-box-footer">
Manage lists <i class="fa fa-arrow-circle-right"></i>
</a>
</div>
@@ -279,7 +279,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
</div>
<!-- /.row -->
<script src="<?=pihole.fileversion('scripts/js/charts.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/index.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/charts.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/index.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+1 -1
View File
@@ -32,5 +32,5 @@ mg.include('scripts/lua/header_authenticated.lp','r')
<pre id="output" style="width: 100%; height: 100%;" hidden></pre>
<script src="<?=pihole.fileversion('scripts/js/interfaces.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/interfaces.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+9 -9
View File
@@ -9,12 +9,12 @@
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">
<section style="padding: 15px;">
<div class="login-logo">
<div class="text-center">
<img src="<?=pihole.webhome()?>img/logo.svg" alt="Pi-hole logo" class="loginpage-logo">
<img src="<?=webhome?>img/logo.svg" alt="Pi-hole logo" class="loginpage-logo" width="140" height="202">
</div>
<div class="panel-title text-center"><span class="logo-lg" style="font-size: 25px;">Pi-<b>hole</b></span></div>
</div>
@@ -72,7 +72,7 @@ mg.include('scripts/lua/header.lp','r')
</div>
<div class="box-body">
<p>Your Pi-hole has two-factor authentication enabled. You have to
enter a valid <a href="https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm" target="_blank">TOTP</a>
enter a valid <a href="https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm" rel="noopener" target="_blank">TOTP</a>
token in addition to your password. You see this message because your
token was incorrect or has already expired.</p>
</div>
@@ -96,7 +96,7 @@ mg.include('scripts/lua/header.lp','r')
a new password (or explicitly disable the password by setting an empty password)
using the command
</p>
<pre>sudo pihole setpassword</pre>
<pre>pihole setpassword</pre>
</div>
</div>
</div>
@@ -104,9 +104,9 @@ mg.include('scripts/lua/header.lp','r')
</div>
<!-- /.login-card-body -->
<div class="login-footer" style="margin-top: 15px; display: flex; justify-content: space-between;">
<a class="btn btn-default btn-sm" role="button" href="https://docs.pi-hole.net/" target="_blank"><i class="fas fa-question-circle"></i> Documentation</a>
<a class="btn btn-default btn-sm" role="button" href="https://github.com/pi-hole/" target="_blank"><i class="fab fa-github"></i> GitHub</a>
<a class="btn btn-default btn-sm" role="button" href="https://discourse.pi-hole.net/" target="_blank"><i class="fab fa-discourse"></i> Pi-hole Discourse</a>
<a class="btn btn-default btn-sm" role="button" href="https://docs.pi-hole.net/" rel="noopener" target="_blank"><i class="fas fa-question-circle"></i> Documentation</a>
<a class="btn btn-default btn-sm" role="button" href="https://github.com/pi-hole/" rel="noopener" target="_blank"><i class="fab fa-github"></i> GitHub</a>
<a class="btn btn-default btn-sm" role="button" href="https://discourse.pi-hole.net/" rel="noopener" target="_blank"><i class="fab fa-discourse"></i> Pi-hole Discourse</a>
</div>
</div>
</section>
@@ -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.
</div>
</div>
<script src="<?=pihole.fileversion('scripts/js/login.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/footer.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/footer.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/login.js')?>"></script>
</body>
</html>
+1 -1
View File
@@ -41,6 +41,6 @@ mg.include('scripts/lua/header_authenticated.lp','r')
</div>
</div>
<script src="<?=pihole.fileversion('scripts/js/messages.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/messages.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+2 -2
View File
@@ -64,7 +64,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
</div>
<!-- /.row -->
<script src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/network.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/network.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+177 -141
View File
@@ -29,19 +29,19 @@
"icheck-bootstrap": "3.0.1",
"icheck-material": "1.0.1",
"jquery": "3.7.1",
"modernized-waitme": "1.0.0",
"moment": "2.30.1",
"myclabs.jquery.confirm": "2.7.0",
"nprogress": "0.2.0",
"qrious": "4.0.2",
"select2": "4.0.13",
"waitme": "1.19.0"
"select2": "4.0.13"
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"autoprefixer": "^10.4.21",
"eslint-plugin-compat": "^6.0.2",
"postcss": "^8.5.3",
"postcss-cli": "^11.0.0",
"prettier": "^3.5.2",
"postcss-cli": "^11.0.1",
"prettier": "^3.5.3",
"xo": "^0.60.0"
}
},
@@ -71,9 +71,9 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
"integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz",
"integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -113,9 +113,9 @@
}
},
"node_modules/@eslint/eslintrc": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz",
"integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
"integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -270,9 +270,9 @@
"license": "MIT"
},
"node_modules/@mdn/browser-compat-data": {
"version": "5.6.41",
"resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.6.41.tgz",
"integrity": "sha512-zsWm+JSL/0+Dbrvlp+IG/2hbB3/3+WeSbxaEVoFdIJNqKyJsyf1Dn95xYLKHGcs9q18bDTJo39Bv9T10YHzg6w==",
"version": "5.7.6",
"resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.7.6.tgz",
"integrity": "sha512-7xdrMX0Wk7grrTZQwAoy1GkvPMFoizStUoL+VmtUkAxegbCCec+3FKwOM6yc/uGU5+BEczQHXAlWiqvM8JeENg==",
"dev": true,
"license": "CC0-1.0"
},
@@ -315,9 +315,9 @@
}
},
"node_modules/@pkgr/core": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
"integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.0.tgz",
"integrity": "sha512-vsJDAkYR6qCPu+ioGScGiMYR7LvZYIXh/dlQeviqoTWNCVfKTLYD/LkNWH4Mxsv2a5vpIRc77FN5DnmK1eBggQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -378,9 +378,9 @@
}
},
"node_modules/@types/estree": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
"dev": true,
"license": "MIT"
},
@@ -405,9 +405,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "22.13.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz",
"integrity": "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==",
"version": "22.13.14",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz",
"integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -885,9 +885,9 @@
"peer": true
},
"node_modules/acorn": {
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"version": "8.14.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"dev": true,
"license": "MIT",
"bin": {
@@ -1157,18 +1157,19 @@
}
},
"node_modules/array.prototype.findlastindex": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
"integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
"integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"define-properties": "^1.2.1",
"es-abstract": "^1.23.2",
"es-abstract": "^1.23.9",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0",
"es-shim-unscopables": "^1.0.2"
"es-object-atoms": "^1.1.1",
"es-shim-unscopables": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -1313,9 +1314,9 @@
}
},
"node_modules/autoprefixer": {
"version": "10.4.20",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
"integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
"version": "10.4.21",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
"integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
"dev": true,
"funding": [
{
@@ -1333,11 +1334,11 @@
],
"license": "MIT",
"dependencies": {
"browserslist": "^4.23.3",
"caniuse-lite": "^1.0.30001646",
"browserslist": "^4.24.4",
"caniuse-lite": "^1.0.30001702",
"fraction.js": "^4.3.7",
"normalize-range": "^0.1.2",
"picocolors": "^1.0.1",
"picocolors": "^1.1.1",
"postcss-value-parser": "^4.2.0"
},
"bin": {
@@ -1808,13 +1809,13 @@
}
},
"node_modules/call-bound": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
"integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"get-intrinsic": "^1.2.6"
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
@@ -1834,9 +1835,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001700",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz",
"integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==",
"version": "1.0.30001707",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz",
"integrity": "sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==",
"dev": true,
"funding": [
{
@@ -1971,9 +1972,9 @@
}
},
"node_modules/ci-info": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.1.0.tgz",
"integrity": "sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz",
"integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==",
"dev": true,
"funding": [
{
@@ -2174,13 +2175,13 @@
"license": "MIT"
},
"node_modules/core-js-compat": {
"version": "3.40.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.40.0.tgz",
"integrity": "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==",
"version": "3.41.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz",
"integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==",
"dev": true,
"license": "MIT",
"dependencies": {
"browserslist": "^4.24.3"
"browserslist": "^4.24.4"
},
"funding": {
"type": "opencollective",
@@ -2556,13 +2557,13 @@
}
},
"node_modules/dependency-graph": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz",
"integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz",
"integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
"node": ">=4"
}
},
"node_modules/deps-sort": {
@@ -2707,9 +2708,9 @@
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.103",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.103.tgz",
"integrity": "sha512-P6+XzIkfndgsrjROJWfSvVEgNHtPgbhVyTkwLjUM2HU/h7pZRORgaTlHqfAikqxKmdJMLW8fftrdGWbd/Ds0FA==",
"version": "1.5.128",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.128.tgz",
"integrity": "sha512-bo1A4HH/NS522Ws0QNFIzyPcyUUNV/yyy70Ho1xqfGYzPUme2F/xr4tlEOuM6/A538U1vDA7a4XfCd1CKRegKQ==",
"dev": true,
"license": "ISC"
},
@@ -3469,13 +3470,13 @@
}
},
"node_modules/eslint-plugin-n": {
"version": "17.15.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.15.1.tgz",
"integrity": "sha512-KFw7x02hZZkBdbZEFQduRGH4VkIH4MW97ClsbAM4Y4E6KguBJWGfWG1P4HEIpZk2bkoWf0bojpnjNAhYQP8beA==",
"version": "17.17.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.17.0.tgz",
"integrity": "sha512-2VvPK7Mo73z1rDFb6pTvkH6kFibAmnTubFq5l83vePxu0WiY1s0LOtj2WHb6Sa40R3w4mnh8GFYbHBQyMlotKw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.1",
"@eslint-community/eslint-utils": "^4.5.0",
"enhanced-resolve": "^5.17.1",
"eslint-plugin-es-x": "^7.8.0",
"get-tsconfig": "^4.8.1",
@@ -3574,14 +3575,14 @@
}
},
"node_modules/eslint-plugin-prettier": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz",
"integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==",
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.5.tgz",
"integrity": "sha512-IKKP8R87pJyMl7WWamLgPkloB16dagPIdd2FjBDbyRYPKo93wS/NbCOPh6gH+ieNLC+XZrhJt/kWj0PS/DFdmg==",
"dev": true,
"license": "MIT",
"dependencies": {
"prettier-linter-helpers": "^1.0.0",
"synckit": "^0.9.1"
"synckit": "^0.10.2"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
@@ -3592,7 +3593,7 @@
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"eslint-config-prettier": "*",
"eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
@@ -4054,9 +4055,9 @@
"integrity": "sha512-cXyDBT4g0uWl/Xe75QspBDAgAWQ0lkPi/zgp6YFEUHj6WV6VIZl7R6TiDZhdOVU3W4ehp/8tG61Jev1jit+ztQ=="
},
"node_modules/fastq": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
"integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
"integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -4227,9 +4228,9 @@
}
},
"node_modules/find-cache-dir/node_modules/yocto-queue": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz",
"integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz",
"integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4264,9 +4265,9 @@
}
},
"node_modules/find-up-simple": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz",
"integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz",
"integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4457,17 +4458,17 @@
}
},
"node_modules/get-intrinsic": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.0",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
@@ -4849,9 +4850,9 @@
"license": "MIT"
},
"node_modules/human-signals": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
"integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==",
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz",
"integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -6252,6 +6253,12 @@
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"license": "MIT"
},
"node_modules/modernized-waitme": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/modernized-waitme/-/modernized-waitme-1.0.0.tgz",
"integrity": "sha512-4HQ0NepgLNYrjoNG8vKcicluu+8s2zeCaut1WPtfbzdSSj8oqJCuN0gHd/qBjnbOoRL0QN5TirKBJUfofLvsWQ==",
"license": "ISC"
},
"node_modules/module-deps": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz",
@@ -6317,9 +6324,9 @@
}
},
"node_modules/nanoid": {
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"dev": true,
"funding": [
{
@@ -6946,23 +6953,22 @@
}
},
"node_modules/postcss-cli": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.0.tgz",
"integrity": "sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==",
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.1.tgz",
"integrity": "sha512-0UnkNPSayHKRe/tc2YGW6XnSqqOA9eqpiRMgRlV1S6HdGi16vwJBx7lviARzbV1HpQHqLLRH3o8vTcB0cLc+5g==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^3.3.0",
"dependency-graph": "^0.11.0",
"dependency-graph": "^1.0.0",
"fs-extra": "^11.0.0",
"get-stdin": "^9.0.0",
"globby": "^14.0.0",
"picocolors": "^1.0.0",
"postcss-load-config": "^5.0.0",
"postcss-reporter": "^7.0.0",
"pretty-hrtime": "^1.0.3",
"read-cache": "^1.0.0",
"slash": "^5.0.0",
"tinyglobby": "^0.2.12",
"yargs": "^17.0.0"
},
"bin": {
@@ -7060,9 +7066,9 @@
}
},
"node_modules/prettier": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.2.tgz",
"integrity": "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==",
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
"license": "MIT",
"bin": {
@@ -7553,9 +7559,9 @@
}
},
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -8420,14 +8426,14 @@
}
},
"node_modules/synckit": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz",
"integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==",
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.10.3.tgz",
"integrity": "sha512-R1urvuyiTaWfeCggqEvpDJwAlDVdsT9NM+IP//Tk2x7qHCkSvBk/fwFgw/TLAHzZlrAnnazMcRw0ZD8HlYFTEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.1.0",
"tslib": "^2.6.2"
"@pkgr/core": "^0.2.0",
"tslib": "^2.8.1"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
@@ -8476,9 +8482,9 @@
}
},
"node_modules/terser-webpack-plugin": {
"version": "5.3.11",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz",
"integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==",
"version": "5.3.14",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz",
"integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -8552,6 +8558,51 @@
"node": ">=0.6.0"
}
},
"node_modules/tinyglobby": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz",
"integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.4.3",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/tinyglobby/node_modules/fdir": {
"version": "6.4.3",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
"integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/to-absolute-glob": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-3.0.0.tgz",
@@ -8729,9 +8780,9 @@
"license": "MIT"
},
"node_modules/typescript": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"version": "5.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -8828,9 +8879,9 @@
}
},
"node_modules/update-browserslist-db": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz",
"integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
"integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
"dev": true,
"funding": [
{
@@ -8943,22 +8994,6 @@
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
"license": "MIT"
},
"node_modules/waitme": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/waitme/-/waitme-1.19.0.tgz",
"integrity": "sha512-Y6PEtAD8Ycqfhl2SE6Njz/P9C2/1IkiFkevqprob86L0OEfGJ8sfgKARnBQ/xUC1eaJEaL+bmH7N7G6Kn0XgVw==",
"license": "MIT",
"dependencies": {
"jquery": "^1.0.0"
}
},
"node_modules/waitme/node_modules/jquery": {
"version": "1.12.4",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-1.12.4.tgz",
"integrity": "sha512-UEVp7PPK9xXYSk8xqXCJrkXnKZtlgWkd2GsAQbMRFK6S/ePU2JN5G2Zum8hIVjzR3CpdfSqdqAzId/xd4TJHeg==",
"deprecated": "This version is deprecated. Please upgrade to the latest version or find support at https://www.herodevs.com/support/jquery-nes.",
"license": "MIT"
},
"node_modules/watchpack": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
@@ -9176,15 +9211,16 @@
}
},
"node_modules/which-typed-array": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz",
"integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==",
"version": "1.1.19",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.3",
"for-each": "^0.3.3",
"call-bound": "^1.0.4",
"for-each": "^0.3.5",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2"
},
@@ -9326,9 +9362,9 @@
}
},
"node_modules/yaml": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",
"integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
"integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
"dev": true,
"license": "ISC",
"bin": {
+15 -10
View File
@@ -19,10 +19,10 @@
"prettier:check": "prettier -l \"style/*.css\" \"style/themes/*.css\" \"scripts/**/*.js\"",
"prettier:fix": "prettier --write \"style/*.css\" \"style/themes/*.css\" \"scripts/**/*.js\"",
"xo": "xo",
"xo:check": "npm run xo -- \"style/*.css\" \"style/themes/*.css\" \"scripts/**\"",
"xo:fix": "npm run xo -- --fix \"style/*.css\" \"style/themes/*.css\" \"scripts/**\"",
"xo:check": "npm run xo",
"xo:fix": "npm run xo -- --fix",
"test": "npm run prettier:check && npm run xo:check",
"testpr": "npm run prettier:fix && git diff --ws-error-highlight=all --color=always --exit-code && npm run xo:check"
"testpr": "npm run prefix && npm run prettier:fix && git diff --ws-error-highlight=all --color=always --exit-code && npm run xo:check"
},
"dependencies": {
"admin-lte": "2.4.18",
@@ -45,24 +45,27 @@
"icheck-bootstrap": "3.0.1",
"icheck-material": "1.0.1",
"jquery": "3.7.1",
"modernized-waitme": "1.0.0",
"moment": "2.30.1",
"myclabs.jquery.confirm": "2.7.0",
"nprogress": "0.2.0",
"qrious": "4.0.2",
"select2": "4.0.13",
"waitme": "1.19.0"
"select2": "4.0.13"
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"autoprefixer": "^10.4.21",
"eslint-plugin-compat": "^6.0.2",
"postcss": "^8.5.3",
"postcss-cli": "^11.0.0",
"prettier": "^3.5.2",
"postcss-cli": "^11.0.1",
"prettier": "^3.5.3",
"xo": "^0.60.0"
},
"browserslist": [
"defaults",
"not IE 11"
">= 0.5%",
"last 2 major versions",
"not dead",
"not op_mini all",
"Firefox ESR"
],
"prettier": {
"arrowParens": "avoid",
@@ -119,11 +122,13 @@
}
],
"unicorn/filename-case": "off",
"unicorn/no-anonymous-default-export": "off",
"unicorn/no-array-for-each": "off",
"unicorn/no-for-loop": "off",
"unicorn/no-document-cookie": "off",
"unicorn/numeric-separators-style": "off",
"unicorn/prefer-includes": "off",
"unicorn/prefer-module": "off",
"unicorn/prefer-node-append": "off",
"unicorn/prefer-number-properties": "off",
"unicorn/prefer-query-selector": "off",
+11
View File
@@ -0,0 +1,11 @@
/* eslint-env node */
"use strict";
module.exports = (/* ctx */) => ({
plugins: {
autoprefixer: {
cascade: false,
},
},
});
+5 -5
View File
@@ -154,7 +154,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
<h3 class="box-title">Recent Queries</h3>
<div class="pull-right align-click-options">
<span><input type="checkbox" id="live"><label for="live">Live update</label></span>
<a id="refresh" href="#" class="btn btn-sm btn-info btn-flat">Refresh</a>
<button type="button" id="refresh" class="btn btn-sm btn-info btn-flat">Refresh</button>
</div>
</div>
<!-- /.box-header -->
@@ -194,9 +194,9 @@ mg.include('scripts/lua/header_authenticated.lp','r')
</div>
<!-- /.row -->
<script src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/daterangepicker/daterangepicker.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/queries.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/daterangepicker/daterangepicker.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/queries.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+2 -2
View File
@@ -97,11 +97,11 @@ const htmlLegendPlugin = {
textLink.addEventListener("click", () => {
if (chart.canvas.id === "queryTypePieChart") {
globalThis.location.href = "queries.lp?type=" + item.text;
globalThis.location.href = "queries?type=" + item.text;
} else if (chart.canvas.id === "forwardDestinationPieChart") {
// Encode the forward destination as it may contain an "#" character
const upstream = encodeURIComponent(upstreams[item.text]);
globalThis.location.href = "queries.lp?upstream=" + upstream;
globalThis.location.href = "queries?upstream=" + upstream;
}
});
}
+32 -38
View File
@@ -7,8 +7,8 @@
/* global utils:false, moment:false */
//The following functions allow us to display time until pi-hole is enabled after disabling.
//Works between all pages
var _isLoginPage = false;
const apiUrl = document.body.dataset.apiurl;
const REFRESH_INTERVAL = {
logs: 500, // 0.5 sec (logs page)
@@ -115,7 +115,7 @@ function checkBlocking() {
}
$.ajax({
url: "/api/dns/blocking",
url: apiUrl + "/dns/blocking",
method: "GET",
})
.done(function (data) {
@@ -144,7 +144,7 @@ function piholeChange(action, duration) {
btnStatus.html("<i class='fa fa-spinner fa-spin'> </i>");
$.ajax({
url: "/api/dns/blocking",
url: apiUrl + "/dns/blocking",
method: "POST",
dataType: "json",
processData: false,
@@ -206,7 +206,7 @@ function initCheckboxRadioStyle() {
chkboxStyle = "primary";
}
var boxsheet = $('<link href="' + getCheckboxURL(chkboxStyle) + '" rel="stylesheet" />');
var boxsheet = $('<link href="' + getCheckboxURL(chkboxStyle) + '" rel="stylesheet">');
// Only add the stylesheet if it's not already present
if ($("link[href='" + boxsheet.attr("href") + "']").length === 0) boxsheet.appendTo("head");
@@ -220,7 +220,7 @@ function initCheckboxRadioStyle() {
iCheckStyle.on("change", function () {
var themename = $(this).val();
localStorage.setItem("theme_icheck", themename);
applyCheckboxRadioStyle(themename);
applyCheckboxRadioStyle();
});
}
}
@@ -267,7 +267,7 @@ function updateQueryFrequency(intl, frequency) {
var ftlinfoTimer = null;
function updateFtlInfo() {
$.ajax({
url: "/api/info/ftl",
url: apiUrl + "/info/ftl",
})
.done(function (data) {
var ftl = data.ftl;
@@ -324,7 +324,7 @@ function updateFtlInfo() {
function updateSystemInfo() {
$.ajax({
url: "/api/info/system",
url: apiUrl + "/info/system",
})
.done(function (data) {
var system = data.system;
@@ -372,39 +372,33 @@ function updateSystemInfo() {
$("#sysinfo-memory-swap").text("No swap space available");
}
color = system.cpu.load.percent[0] > 100 ? "text-red" : "text-green-light";
color = system.cpu.load.raw[0] > system.cpu.nprocs ? "text-red" : "text-green-light";
$("#cpu").html(
'<i class="fa fa-fw fa-microchip ' +
color +
'"></i>&nbsp;&nbsp;CPU:&nbsp;' +
system.cpu.load.percent[0].toFixed(1) +
"&thinsp;%"
'"></i>&nbsp;&nbsp;Load:&nbsp;' +
system.cpu.load.raw[0].toFixed(2) +
"&nbsp;/&nbsp;" +
system.cpu.load.raw[1].toFixed(2) +
"&nbsp;/&nbsp;" +
system.cpu.load.raw[2].toFixed(2)
);
$("#cpu").prop(
"title",
"Load: " +
system.cpu.load.raw[0].toFixed(2) +
" " +
system.cpu.load.raw[1].toFixed(2) +
" " +
system.cpu.load.raw[2].toFixed(2) +
" on " +
"Load averages for the past 1, 5, and 15 minutes\non a system with " +
system.cpu.nprocs +
" core" +
(system.cpu.nprocs > 1 ? "s" : "") +
" running " +
system.procs +
" processes"
" processes " +
(system.cpu.load.raw[0] > system.cpu.nprocs
? " (load is higher than the number of cores)"
: "")
);
$("#sysinfo-cpu").text(
system.cpu.load.percent[0].toFixed(1) +
"% (load: " +
system.cpu.load.raw[0].toFixed(2) +
" " +
system.cpu.load.raw[1].toFixed(2) +
" " +
system.cpu.load.raw[2].toFixed(2) +
") on " +
$("#sysinfo-cpu").html(
system.cpu["%cpu"].toFixed(1) +
"% on " +
system.cpu.nprocs +
" core" +
(system.cpu.nprocs > 1 ? "s" : "") +
@@ -490,7 +484,7 @@ function versionCompare(v1, v2) {
function updateVersionInfo() {
$.ajax({
url: "/api/info/version",
url: apiUrl + "/info/version",
}).done(function (data) {
var version = data.version;
var updateAvailable = false;
@@ -509,7 +503,7 @@ function updateVersionInfo() {
},
{
name: "Core",
local: version.core.local.version,
local: version.core.local.version || "N/A",
remote: version.core.remote.version,
branch: version.core.local.branch,
hash: version.core.local.hash,
@@ -518,7 +512,7 @@ function updateVersionInfo() {
},
{
name: "FTL",
local: version.ftl.local.version,
local: version.ftl.local.version || "N/A",
remote: version.ftl.remote.version,
branch: version.ftl.local.branch,
hash: version.ftl.local.hash,
@@ -527,7 +521,7 @@ function updateVersionInfo() {
},
{
name: "Web interface",
local: version.web.local.version,
local: version.web.local.version || "N/A",
remote: version.web.remote.version,
branch: version.web.local.branch,
hash: version.web.local.hash,
@@ -592,7 +586,7 @@ function updateVersionInfo() {
}
// Display update information of individual components only if we are not running in a Docker container
if ((!isDocker || (isDocker && v.name === "Docker Tag")) && updateComponentAvailable) {
if ((!isDocker || v.name === "Docker Tag") && updateComponentAvailable) {
$("#versions").append(
"<li><strong>" +
v.name +
@@ -625,7 +619,7 @@ function updateVersionInfo() {
}
$(function () {
if (globalThis.location.pathname !== "/admin/login") updateInfo();
if (!_isLoginPage) updateInfo();
var enaT = $("#enableTimer");
var target = new Date(parseInt(enaT.html(), 10));
var seconds = Math.round((target.getTime() - Date.now()) / 1000);
@@ -640,7 +634,7 @@ $(function () {
// Apply per-browser styling settings
initCheckboxRadioStyle();
if (globalThis.location.pathname !== "/admin/login") {
if (!_isLoginPage) {
// Run check immediately after page loading ...
utils.checkMessages();
// ... and then periodically
@@ -742,7 +736,7 @@ function applyExpertSettings() {
function addAdvancedInfo() {
const advancedInfoSource = $("#advanced-info-data");
const advancedInfoTarget = $("#advanced-info");
const isTLS = advancedInfoSource.data("tls");
const isTLS = location.protocol === "https:";
const clientIP = advancedInfoSource.data("client-ip");
const XForwardedFor = globalThis.atob(advancedInfoSource.data("xff") ?? "");
const starttime = parseFloat(advancedInfoSource.data("starttime"));
@@ -755,7 +749,7 @@ function addAdvancedInfo() {
// Add TLS and client IP info
advancedInfoTarget.append(
'Client: <i class="fa-solid fa-fw fa-lock' +
(isTLS ? "" : "-open") +
(isTLS ? " text-green" : "-open") +
'" title="Your connection is ' +
(isTLS ? "" : "NOT ") +
'end-to-end encrypted (TLS/SSL)"></i>&nbsp;<span id="client-id"></span><br>'
+3 -11
View File
@@ -4,27 +4,19 @@
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global apiUrl: false */
function eventsource() {
var alInfo = $("#alInfo");
var alSuccess = $("#alSuccess");
var ta = $("#output");
// https://caniuse.com/fetch - everything except IE
// This is fine, as we dropped support for IE a while ago
if (typeof fetch !== "function") {
ta.show();
ta.html("Updating lists of ad-serving domains is not supported with this browser!");
return;
}
ta.html("");
ta.show();
alInfo.show();
alSuccess.hide();
// eslint-disable-next-line compat/compat
fetch("/api/action/gravity", {
fetch(apiUrl + "/action/gravity", {
method: "POST",
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") },
})
@@ -76,7 +68,7 @@ $(function () {
});
// Do we want to start updating immediately?
// gravity.lp?go
// gravity?go
var searchString = globalThis.location.search.substring(1);
if (searchString.indexOf("go") !== -1) {
$("#gravityBtn").prop("disabled", true);
+5 -5
View File
@@ -5,14 +5,14 @@
* This file is copyright under the latest version of the EUPL.
* 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 */
var table;
function reloadClientSuggestions() {
$.ajax({
url: "/api/clients/_suggestions",
url: apiUrl + "/clients/_suggestions",
type: "GET",
dataType: "json",
success: function (data) {
@@ -96,7 +96,7 @@ function initTable() {
table = $("#clientsTable").DataTable({
processing: true,
ajax: {
url: "/api/clients",
url: apiUrl + "/clients",
dataSrc: "clients",
type: "GET",
},
@@ -402,7 +402,7 @@ function addClient() {
}
$.ajax({
url: "/api/clients",
url: apiUrl + "/clients",
method: "post",
dataType: "json",
processData: false,
@@ -459,7 +459,7 @@ function editClient() {
const clientDecoded = utils.hexDecode(client);
utils.showAlert("info", "", "Editing client...", clientDecoded);
$.ajax({
url: "/api/clients/" + encodeURIComponent(clientDecoded),
url: apiUrl + "/clients/" + encodeURIComponent(clientDecoded),
method: "put",
dataType: "json",
processData: false,
+3 -3
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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 = [];
@@ -39,7 +39,7 @@ function populateGroupSelect(selectEl) {
// eslint-disable-next-line no-unused-vars
function getGroups(groupSelector) {
$.ajax({
url: "/api/groups",
url: apiUrl + "/groups",
type: "GET",
dataType: "json",
success: function (data) {
@@ -79,7 +79,7 @@ function delGroupItems(type, ids, table, listType = undefined) {
// Check input validity
if (!Array.isArray(ids)) return;
const url = "/api/" + type + "s:batchDelete";
const url = apiUrl + "/" + type + "s:batchDelete";
// use utils.hexDecode() to decode all clients
let idstring = "";
+18 -24
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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 */
var table;
@@ -63,29 +63,23 @@ function showSuggestDomains(value) {
var newDomainEl = $("#new_domain");
var suggestDomainEl = $("#suggest_domains");
try {
// URL is not supported in all browsers, but we are in a try-block so we can ignore it
// eslint-disable-next-line compat/compat
var parts = new URL(value).hostname.split(".");
var table = $("<table>");
var parts = new URL(value).hostname.split(".");
var table = $("<table>");
for (var i = 0; i < parts.length - 1; ++i) {
var hostname = parts.slice(i).join(".");
for (var i = 0; i < parts.length - 1; ++i) {
var hostname = parts.slice(i).join(".");
table.append(
$("<tr>")
.append($('<td class="text-nowrap text-right">').text(i === 0 ? "Did you mean" : "or"))
.append($("<td>").append(createButton(hostname)))
);
}
suggestDomainEl.slideUp("fast", function () {
suggestDomainEl.html(table);
suggestDomainEl.slideDown("fast");
});
} catch {
hideSuggestDomains();
table.append(
$("<tr>")
.append($('<td class="text-nowrap text-right">').text(i === 0 ? "Did you mean" : "or"))
.append($("<td>").append(createButton(hostname)))
);
}
suggestDomainEl.slideUp("fast", function () {
suggestDomainEl.html(table);
suggestDomainEl.slideDown("fast");
});
}
function hideSuggestDomains() {
@@ -97,7 +91,7 @@ function initTable() {
table = $("#domainsTable").DataTable({
processing: true,
ajax: {
url: "/api/domains",
url: apiUrl + "/domains",
dataSrc: "domains",
type: "GET",
},
@@ -513,7 +507,7 @@ function addDomain() {
const type = action === "add_deny" ? "deny" : "allow";
$.ajax({
url: "/api/domains/" + type + "/" + kind,
url: apiUrl + "/domains/" + type + "/" + kind,
method: "post",
dataType: "json",
processData: false,
@@ -602,7 +596,7 @@ function editDomain() {
const domainDecoded = utils.hexDecode(domain.split("_")[0]);
utils.showAlert("info", "", "Editing domain...", domainDecoded);
$.ajax({
url: "/api/domains/" + newTypestr + "/" + encodeURIComponent(domainDecoded),
url: apiUrl + "/domains/" + newTypestr + "/" + encodeURIComponent(domainDecoded),
method: "put",
dataType: "json",
processData: false,
+4 -4
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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 */
var table;
@@ -170,7 +170,7 @@ function initTable() {
table = $("#listsTable").DataTable({
processing: true,
ajax: {
url: "/api/lists",
url: apiUrl + "/lists",
dataSrc: "lists",
type: "GET",
},
@@ -519,7 +519,7 @@ function addList(event) {
}
$.ajax({
url: "/api/lists",
url: apiUrl + "/lists",
method: "post",
dataType: "json",
processData: false,
@@ -588,7 +588,7 @@ function editList() {
utils.disableAll();
utils.showAlert("info", "", "Editing address...", address);
$.ajax({
url: "/api/lists/" + encodeURIComponent(address) + "?type=" + type,
url: apiUrl + "/lists/" + encodeURIComponent(address) + "?type=" + type,
method: "put",
dataType: "json",
processData: false,
+4 -4
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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;
@@ -26,7 +26,7 @@ $(function () {
table = $("#groupsTable").DataTable({
processing: true,
ajax: {
url: "/api/groups",
url: apiUrl + "/groups",
error: handleAjaxError,
dataSrc: "groups",
type: "GET",
@@ -261,7 +261,7 @@ function addGroup() {
}
$.ajax({
url: "/api/groups",
url: apiUrl + "/groups",
method: "post",
dataType: "json",
processData: false,
@@ -329,7 +329,7 @@ function editGroup() {
utils.disableAll();
utils.showAlert("info", "", "Editing group...", oldName);
$.ajax({
url: "/api/groups/" + oldName,
url: apiUrl + "/groups/" + oldName,
method: "put",
dataType: "json",
processData: false,
+21 -14
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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
var timeLineChart, clientsChart;
@@ -22,7 +22,7 @@ Chart.defaults.set("plugins.deferred", {
var failures = 0;
function updateQueriesOverTime() {
$.getJSON("/api/history", function (data) {
$.getJSON(apiUrl + "/history", function (data) {
// Remove graph if there are no results (e.g. new
// installation or privacy mode enabled)
if (jQuery.isEmptyObject(data.history)) {
@@ -92,7 +92,7 @@ function updateQueriesOverTime() {
}
function updateQueryTypesPie() {
$.getJSON("/api/stats/query_types", function (data) {
$.getJSON(apiUrl + "/stats/query_types", function (data) {
var v = [],
c = [],
k = [],
@@ -134,7 +134,7 @@ function updateQueryTypesPie() {
}
function updateClientsOverTime() {
$.getJSON("/api/history/clients", function (data) {
$.getJSON(apiUrl + "/history/clients", function (data) {
// Remove graph if there are no results (e.g. new
// installation or privacy mode enabled)
if (jQuery.isEmptyObject(data.history)) {
@@ -212,7 +212,7 @@ function updateClientsOverTime() {
var upstreams = {};
function updateForwardDestinationsPie() {
$.getJSON("/api/stats/upstreams", function (data) {
$.getJSON(apiUrl + "/stats/upstreams", function (data) {
var v = [],
c = [],
k = [],
@@ -273,13 +273,13 @@ function updateForwardDestinationsPie() {
function updateTopClientsTable(blocked) {
let api, style, tablecontent, overlay, clienttable;
if (blocked) {
api = "/api/stats/top_clients?blocked=true";
api = apiUrl + "/stats/top_clients?blocked=true";
style = "queries-blocked";
tablecontent = $("#client-frequency-blocked td").parent();
overlay = $("#client-frequency-blocked .overlay");
clienttable = $("#client-frequency-blocked").find("tbody:last");
} else {
api = "/api/stats/top_clients";
api = apiUrl + "/stats/top_clients";
style = "queries-permitted";
tablecontent = $("#client-frequency td").parent();
overlay = $("#client-frequency .overlay");
@@ -305,8 +305,9 @@ function updateTopClientsTable(blocked) {
let clientname = client.name;
if (clientname.length === 0) clientname = client.ip;
url =
'<a href="queries.lp?client_ip=' +
'<a href="queries?client_ip=' +
encodeURIComponent(client.ip) +
(blocked ? "&upstream=blocklist" : "") +
'">' +
utils.escapeHtml(clientname) +
"</a>";
@@ -332,13 +333,13 @@ function updateTopClientsTable(blocked) {
function updateTopDomainsTable(blocked) {
let api, style, tablecontent, overlay, domaintable;
if (blocked) {
api = "/api/stats/top_domains?blocked=true";
api = apiUrl + "/stats/top_domains?blocked=true";
style = "queries-blocked";
tablecontent = $("#ad-frequency td").parent();
overlay = $("#ad-frequency .overlay");
domaintable = $("#ad-frequency").find("tbody:last");
} else {
api = "/api/stats/top_domains";
api = apiUrl + "/stats/top_domains";
style = "queries-permitted";
tablecontent = $("#domain-frequency td").parent();
overlay = $("#domain-frequency .overlay");
@@ -364,7 +365,13 @@ function updateTopDomainsTable(blocked) {
domain = encodeURIComponent(item.domain);
// Substitute "." for empty domain lookups
urlText = domain === "" ? "." : domain;
url = '<a href="queries.lp?domain=' + domain + '">' + urlText + "</a>";
url =
'<a href="queries?domain=' +
domain +
(blocked ? "&upstream=blocklist" : "&upstream=permitted") +
'">' +
urlText +
"</a>";
percentage = (item.count / sum) * 100;
domaintable.append(
"<tr> " +
@@ -401,7 +408,7 @@ function updateTopLists() {
var previousCount = 0;
var firstSummaryUpdate = true;
function updateSummaryData(runOnce = false) {
$.getJSON("/api/stats/summary", function (data) {
$.getJSON(apiUrl + "/stats/summary", function (data) {
var intl = new Intl.NumberFormat();
const newCount = parseInt(data.queries.total, 10);
@@ -790,7 +797,7 @@ $(function () {
//get value by index
var from = label / 1000 - 300;
var until = label / 1000 + 300;
globalThis.location.href = "queries.lp?from=" + from + "&until=" + until;
globalThis.location.href = "queries?from=" + from + "&until=" + until;
}
return false;
@@ -813,7 +820,7 @@ $(function () {
//get value by index
var from = label / 1000 - 300;
var until = label / 1000 + 300;
globalThis.location.href = "queries.lp?from=" + from + "&until=" + until;
globalThis.location.href = "queries?from=" + from + "&until=" + until;
}
return false;
+83 -17
View File
@@ -5,11 +5,11 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global utils */
/* global utils: false, apiUrl: false */
$(function () {
$.ajax({
url: "/api/network/gateway",
url: apiUrl + "/network/gateway",
data: { detailed: true },
}).done(function (data) {
var intl = new Intl.NumberFormat();
@@ -28,29 +28,52 @@ $(function () {
gateways.add(inet6.gateway);
}
var json = [];
var interfaces = {};
var masterInterfaces = {};
// For each interface in data.interface, create a new object and push it to json
data.interfaces.forEach(function (interface) {
const status = interface.carrier
? '<span class="text-green">UP</span>'
: '<span class="text-red">DOWN</span>';
const carrierColor = interface.carrier ? "text-green" : "text-red";
let stateText = interface.state.toUpperCase();
if (stateText === "UNKNOWN" && interface.flags !== undefined && interface.flags.length > 0) {
if (interface.flags.includes("pointopoint")) {
// WireGuards, etc. -> the typo is intentional
stateText = "P2P";
} else if (interface.flags.includes("loopback")) {
// Loopback interfaces
stateText = "LOOPBACK";
}
}
const status = `<span class="${carrierColor}">${stateText}</span>`;
let master = null;
if (interface.master !== undefined) {
// Find interface.master in data.interfaces
master = data.interfaces.find(obj => obj.index === interface.master).name;
}
// Show an icon for indenting slave interfaces
const indentIcon =
master === null ? "" : "<span class='child-interface-icon'>&nbsp;&rdca;</span> ";
var obj = {
text: interface.name + " - " + status,
text: indentIcon + interface.name + " - " + status,
class: gateways.has(interface.name) ? "text-bold" : null,
icon: "fa fa-network-wired fa-fw",
icon: master === null ? "fa fa-network-wired fa-fw" : "",
nodes: [],
};
if (interface.master !== undefined) {
// Find interface.master in data.interfaces
const master = data.interfaces.find(obj => obj.index === interface.master);
if (master !== undefined) {
obj.nodes.push({
text: "Master interface: <code>" + utils.escapeHtml(master.name) + "</code>",
icon: "fa fa-network-wired fa-fw",
});
if (master !== null) {
obj.nodes.push({
text: "Master interface: <code>" + utils.escapeHtml(master) + "</code>",
icon: "fa fa-network-wired fa-fw",
});
if (master in masterInterfaces) {
masterInterfaces[master].push(interface.name);
} else {
masterInterfaces[master] = [interface.name];
}
}
@@ -306,6 +329,21 @@ $(function () {
nodes: [],
};
furtherDetails.nodes.push(
{
text:
"Carrier: " +
(interface.carrier
? "<span class='text-green'>Connected</span>"
: "<span class='text-red'>Disconnected</span>"),
icon: "fa fa-link fa-fw",
},
{
text: "State: " + utils.escapeHtml(interface.state.toUpperCase()),
icon: "fa fa-server fa-fw",
}
);
if (interface.parent_dev_name !== undefined) {
let extra = "";
if (interface.parent_dev_bus_name !== undefined) {
@@ -378,9 +416,37 @@ $(function () {
obj.nodes.push(furtherDetails);
}
json.push(obj);
interfaces[interface.name] = obj;
});
// Sort interfaces based on masterInterfaces. If an item is found in
// masterInterfaces, it should be placed after the master interface
const ifaces = Object.keys(interfaces);
const interfaceList = Object.keys(masterInterfaces);
// Add slave interfaces next to master interfaces
for (const master of interfaceList) {
if (master in masterInterfaces) {
for (const slave of masterInterfaces[master]) {
ifaces.splice(ifaces.indexOf(slave), 1);
interfaceList.splice(interfaceList.indexOf(master) + 1, 0, slave);
}
}
}
// Add interfaces that are not slaves at the top of the list (in reverse order)
for (const iface of ifaces.reverse()) {
if (!interfaceList.includes(iface)) {
interfaceList.unshift(iface);
}
}
// Build the tree view
const json = [];
for (const iface of interfaceList) {
json.push(interfaces[iface]);
}
$("#tree").bstreeview({
data: json,
expandIcon: "fa fa-angle-down fa-fw",
+8 -6
View File
@@ -5,7 +5,9 @@
* 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 */
/* global utils:false, apiUrl: false, NProgress:false */
var _isLoginPage = true;
function redirect() {
// Login succeeded or not needed (empty password)
@@ -14,7 +16,7 @@ function redirect() {
// If DNS failure: send to Pi-hole diagnosis messages page
if ($("#dns-failure-label").is(":visible")) {
target = "messages.lp";
target = "messages";
}
// Redirect to target
@@ -89,7 +91,7 @@ function doLogin(password) {
NProgress.start();
utils.disableAll();
$.ajax({
url: "/api/auth",
url: apiUrl + "/auth",
method: "POST",
dataType: "json",
processData: false,
@@ -134,7 +136,7 @@ $("#totp").on("input", function () {
// Toggle password visibility button
$("#toggle-password").on("click", function () {
// Toggle font-awesome classes to change the svg icon on the button
$("svg", this).toggleClass("fa-eye fa-eye-slash");
$(".field-icon", this).toggleClass("fa-eye fa-eye-slash");
// Password field
var $pwd = $("#current-password");
@@ -161,7 +163,7 @@ function showDNSfailure() {
$(function () {
// Check if we need to login at all
$.ajax({
url: "/api/auth",
url: apiUrl + "/auth",
})
.done(function (data) {
// If we are already logged in, redirect to dashboard
@@ -180,7 +182,7 @@ $(function () {
// Get information about HTTPS port and DNS status
$.ajax({
url: "/api/info/login",
url: apiUrl + "/info/login",
}).done(function (data) {
if (data.dns === false) showDNSfailure();
+5 -2
View File
@@ -9,7 +9,10 @@
document.addEventListener("DOMContentLoaded", () => {
const logoutButton = document.getElementById("logout-button");
logoutButton.addEventListener("click", () => {
utils.doLogout();
const logoutUrl = document.body.dataset.logoutUrl;
logoutButton.addEventListener("click", event => {
event.preventDefault();
utils.doLogout(logoutUrl);
});
});
+3 -3
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global utils:false */
/* global utils: false, apiUrl: false */
var table,
toasts = {};
@@ -13,7 +13,7 @@ $(function () {
var ignoreNonfatal = localStorage
? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true"
: false;
var url = "/api/info/messages" + (ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : "");
var url = apiUrl + "/info/messages" + (ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : "");
table = $("#messagesTable").DataTable({
ajax: {
url: url,
@@ -157,7 +157,7 @@ function delMsg(id) {
toasts[id] = utils.showAlert("info", "", "Deleting message...", "ID: " + id, null);
$.ajax({
url: "/api/info/messages/" + id,
url: apiUrl + "/info/messages/" + id,
method: "DELETE",
})
.done(function (response) {
+18 -5
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global utils:false, apiFailure:false */
/* global utils:false, apiUrl:false, apiFailure:false */
var tableApi;
@@ -64,7 +64,7 @@ function deleteNetworkEntry() {
utils.disableAll();
utils.showAlert("info", "", "Deleting network table entry...");
$.ajax({
url: "/api/network/devices/" + id,
url: apiUrl + "/network/devices/" + id,
method: "DELETE",
success: function () {
utils.enableAll();
@@ -138,6 +138,19 @@ $(function () {
var ips = [],
iptitles = [];
// Sort IPs, IPv4 before IPv6, then alphabetically
data.ips.sort(function (a, b) {
if (a.ip.includes(":") && !b.ip.includes(":")) {
return 1;
}
if (!a.ip.includes(":") && b.ip.includes(":")) {
return -1;
}
return a.ip.localeCompare(b.ip);
});
for (index = 0; index < data.ips.length; index++) {
var ip = data.ips[index],
iptext = ip.ip;
@@ -150,7 +163,7 @@ $(function () {
// Only add IPs to the table if we have not reached the maximum
if (index < MAXIPDISPLAY) {
ips.push('<a href="queries.lp?client_ip=' + ip.ip + '">' + iptext + "</a>");
ips.push('<a href="queries?client_ip=' + ip.ip + '">' + iptext + "</a>");
}
}
@@ -168,7 +181,7 @@ $(function () {
// MAC + Vendor field if available
if (data.macVendor && data.macVendor.length > 0) {
$("td:eq(1)", row).html(
utils.escapeHtml(data.hwaddr) + "<br/>" + utils.escapeHtml(data.macVendor)
utils.escapeHtml(data.hwaddr) + "<br>" + utils.escapeHtml(data.macVendor)
);
}
@@ -195,7 +208,7 @@ $(function () {
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
ajax: {
url: "/api/network/devices",
url: apiUrl + "/network/devices",
type: "GET",
dataType: "json",
data: {
+13 -9
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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 endOfTime = 2147483647; // Jan 19, 2038, 03:14 in seconds
@@ -149,6 +149,13 @@ function parseQueryStatus(data) {
buttontext = "";
blocked = true;
break;
case "QUERY_EXTERNAL_BLOCKED_EDE15":
colorClass = "text-red";
icon = "fa-solid fa-ban";
fieldtext = "Blocked (external, EDE15)";
buttontext = "";
blocked = true;
break;
case "GRAVITY_CNAME":
colorClass = "text-red";
icon = "fa-solid fa-ban";
@@ -424,7 +431,7 @@ function addSelectSuggestion(name, dict, data) {
function getSuggestions(dict) {
$.get(
"/api/queries/suggestions",
apiUrl + "/queries/suggestions",
function (data) {
for (var key in filters) {
if (Object.hasOwnProperty.call(filters, key)) {
@@ -455,7 +462,7 @@ function filterOn(param, dict) {
}
function getAPIURL(filters) {
var apiurl = "/api/queries?";
var apiurl = apiUrl + "/queries?";
for (var key in filters) {
if (Object.hasOwnProperty.call(filters, key)) {
var filter = filters[key];
@@ -568,8 +575,8 @@ $(function () {
{ data: null, width: "10%", sortable: false, searchable: false },
],
lengthMenu: [
[10, 25, 50, 100, -1],
[10, 25, 50, 100, "All"],
[10, 25, 50, 100, 500, 1000],
[10, 25, 50, 100, 500, 1000],
],
stateSave: true,
stateDuration: 0,
@@ -583,9 +590,6 @@ $(function () {
var querystatus = parseQueryStatus(data);
const dnssec = parseDNSSEC(data);
// Remove HTML from querystatus.fieldtext
var rawtext = $("<div/>").html(querystatus.fieldtext).text();
if (querystatus.icon !== false) {
$("td:eq(1)", row).html(
"<i class='fa fa-fw " +
@@ -593,7 +597,7 @@ $(function () {
" " +
querystatus.colorClass +
"' title='" +
rawtext +
utils.escapeHtml(querystatus.fieldtext) +
"'></i>"
);
} else if (querystatus.colorClass !== false) {
+4 -4
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global utils:false, apiFailure:false */
/* global utils:false, apiUrl:false, apiFailure:false */
var GETDict = {};
$(function () {
@@ -35,7 +35,7 @@ function doSearch() {
$.ajax({
method: "GET",
url: "/api/search/" + encodeURIComponent(q),
url: apiUrl + "/search/" + encodeURIComponent(q),
async: false,
data: {
partial: partial,
@@ -64,7 +64,7 @@ function doSearch() {
for (const domain of res.domains) {
const color = domain.type === "deny" ? "red" : "green";
result +=
" - <a href='groups-domains.lp?domainid=" +
" - <a href='groups-domains?domainid=" +
domain.id +
"' target='_blank'><strong>" +
utils.escapeHtml(domain.domain) +
@@ -118,7 +118,7 @@ function doSearch() {
const list = grouped[listId][0];
const color = list.type === "block" ? "red" : "green";
result +=
" - <a href='groups-lists.lp?listid=" +
" - <a href='groups-lists?listid=" +
list.id +
"' target='_blank'>" +
utils.escapeHtml(list.address) +
+3 -3
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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 */
function addAllowedValues(allowed) {
@@ -296,7 +296,7 @@ function generateRow(topic, key, value) {
function createDynamicConfigTabs() {
$.ajax({
url: "/api/config?detailed=true",
url: apiUrl + "/config?detailed=true",
})
.done(function (data) {
// Create the tabs for the advanced dynamic config topics
@@ -323,7 +323,7 @@ function createDynamicConfigTabs() {
// Dynamically fill the tabs with config topics
Object.keys(data.config).forEach(function (topic) {
var value = data.config[topic];
generateRow(topic, topic, value, data);
generateRow(topic, topic, value);
});
$("#advanced-overlay").hide();
+9 -9
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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 ownSessionID = null;
@@ -31,7 +31,7 @@ function renderBool(data, type) {
$(function () {
apiSessionsTable = $("#APISessionsTable").DataTable({
ajax: {
url: "/api/auth/sessions",
url: apiUrl + "/auth/sessions",
type: "GET",
dataSrc: "sessions",
},
@@ -247,7 +247,7 @@ function deleteOneSession(id, len, ownSessionDelete) {
// our own session is then triggered by the last successful deletion of
// another session (ownSessionDelete == true, len == global deleted)
$.ajax({
url: "/api/auth/session/" + id,
url: apiUrl + "/auth/session/" + id,
method: "DELETE",
})
.done(function () {
@@ -272,7 +272,7 @@ function deleteOneSession(id, len, ownSessionDelete) {
function processWebServerConfig() {
$.ajax({
url: "/api/config/webserver?detailed=true",
url: apiUrl + "/config/webserver?detailed=true",
})
.done(function (data) {
setConfigValues("webserver", "webserver", data.config.webserver);
@@ -291,7 +291,7 @@ function processWebServerConfig() {
$("#modal-totp").on("shown.bs.modal", function () {
$.ajax({
url: "/api/auth/totp",
url: apiUrl + "/auth/totp",
})
.done(function (data) {
TOTPdata = data.totp;
@@ -329,7 +329,7 @@ $("#modal-totp").on("shown.bs.modal", function () {
var apppwhash = null;
$("#modal-apppw").on("shown.bs.modal", function () {
$.ajax({
url: "/api/auth/app",
url: apiUrl + "/auth/app",
})
.done(function (data) {
apppwhash = data.app.hash;
@@ -373,7 +373,7 @@ $("#apppw_clear").on("click", function () {
function setAppPassword() {
$.ajax({
url: "/api/config",
url: apiUrl + "/config",
type: "PATCH",
dataType: "json",
processData: false,
@@ -426,7 +426,7 @@ $("#totp_code").on("keyup", function () {
function setTOTPSecret(secret) {
$.ajax({
url: "/api/config",
url: apiUrl + "/config",
type: "PATCH",
dataType: "json",
processData: false,
@@ -478,7 +478,7 @@ $(document).ready(function () {
processWebServerConfig();
// Check if TOTP is enabled
$.ajax({
url: "/api/auth",
url: apiUrl + "/auth",
}).done(function (data) {
if (data.session.totp === false) $("#button-enable-totp").removeClass("hidden");
else $("#button-disable-totp").removeClass("hidden");
+4 -4
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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,
toasts = {};
@@ -32,7 +32,7 @@ function renderHostnameCLID(data, type) {
$(function () {
dhcpLeaesTable = $("#DHCPLeasesTable").DataTable({
ajax: {
url: "/api/dhcp/leases",
url: apiUrl + "/dhcp/leases",
type: "GET",
dataSrc: "leases",
},
@@ -167,7 +167,7 @@ function delLease(ip) {
toasts[ip] = utils.showAlert("info", "", "Deleting lease...", ip, null);
$.ajax({
url: "/api/dhcp/leases/" + encodeURIComponent(ip),
url: apiUrl + "/dhcp/leases/" + encodeURIComponent(ip),
method: "DELETE",
})
.done(function (response) {
@@ -214,7 +214,7 @@ function fillDHCPhosts(data) {
function processDHCPConfig() {
$.ajax({
url: "/api/config/dhcp?detailed=true",
url: apiUrl + "/config/dhcp?detailed=true",
})
.done(function (data) {
fillDHCPhosts(data.config.dhcp.hosts);
+8 -6
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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) {
// Split record in format IP NAME1 [NAME2 [NAME3 [NAME...]]]
@@ -156,7 +156,7 @@ function deleteRecord() {
function delHosts(elem) {
utils.disableAll();
utils.showAlert("info", "", "Deleting DNS record...", elem);
const url = "/api/config/dns/hosts/" + encodeURIComponent(elem);
const url = apiUrl + "/config/dns/hosts/" + encodeURIComponent(elem);
$.ajax({
url: url,
@@ -183,7 +183,7 @@ function delHosts(elem) {
function delCNAME(elem) {
utils.disableAll();
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({
url: url,
@@ -216,7 +216,7 @@ $(document).ready(function () {
$("#btnAdd-host").on("click", function () {
utils.disableAll();
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);
$.ajax({
url: url,
@@ -242,7 +242,7 @@ $(document).ready(function () {
var elem = $("#Cdomain").val() + "," + $("#Ctarget").val();
var ttlVal = parseInt($("#Cttl").val(), 10);
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);
$.ajax({
url: url,
@@ -264,5 +264,7 @@ $(document).ready(function () {
});
// Add a small legend below the CNAME table
$("#cnameRecords-Table").after("<small>* <b>TTL</b> in seconds <i>(optional)</i></small>");
$("#cnameRecords-Table").after(
"<small>* <strong>TTL</strong> in seconds <em>(optional)</em></small>"
);
});
+2 -2
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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)
function removeFromArray(arr, what) {
@@ -114,7 +114,7 @@ function updateDNSserversTextfield(upstreams, customServers) {
function processDNSConfig() {
$.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) {
// Initialize the DNS upstreams
+2 -2
View File
@@ -5,11 +5,11 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global setConfigValues: false, apiFailure: false */
/* global setConfigValues: false, apiFailure: false, apiUrl: false */
function getConfig() {
$.ajax({
url: "/api/config/?detailed=true",
url: apiUrl + "/config/?detailed=true",
})
.done(function (data) {
setConfigValues("", "", data.config);
+9 -9
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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 cachePieChart = null;
@@ -83,7 +83,7 @@ function updateCachePie(data) {
function updateHostInfo() {
$.ajax({
url: "/api/info/host",
url: apiUrl + "/info/host",
})
.done(function (data) {
var host = data.host;
@@ -155,7 +155,7 @@ var metricsTimer = null;
function updateMetrics() {
$.ajax({
url: "/api/info/metrics",
url: apiUrl + "/info/metrics",
})
.done(function (data) {
var metrics = data.metrics;
@@ -196,7 +196,7 @@ function showQueryLoggingButton(state) {
function getLoggingButton() {
$.ajax({
url: "/api/config/dns/queryLogging",
url: apiUrl + "/config/dns/queryLogging",
})
.done(function (data) {
showQueryLoggingButton(data.config.dns.queryLogging);
@@ -214,7 +214,7 @@ $(".confirm-restartdns").confirm({
title: "Confirmation required",
confirm: function () {
$.ajax({
url: "/api/action/restartdns",
url: apiUrl + "/action/restartdns",
type: "POST",
}).fail(function (data) {
apiFailure(data);
@@ -238,7 +238,7 @@ $(".confirm-flushlogs").confirm({
title: "Confirmation required",
confirm: function () {
$.ajax({
url: "/api/action/flush/logs",
url: apiUrl + "/action/flush/logs",
type: "POST",
}).fail(function (data) {
apiFailure(data);
@@ -262,7 +262,7 @@ $(".confirm-flusharp").confirm({
title: "Confirmation required",
confirm: function () {
$.ajax({
url: "/api/action/flush/arp",
url: apiUrl + "/action/flush/arp",
type: "POST",
}).fail(function (data) {
apiFailure(data);
@@ -292,7 +292,7 @@ $("#loggingButton").confirm({
data.config.dns = {};
data.config.dns.queryLogging = $("#loggingButton").data("state") !== "enabled";
$.ajax({
url: "/api/config/dns/queryLogging",
url: apiUrl + "/config/dns/queryLogging",
type: "PATCH",
dataType: "json",
processData: false,
@@ -364,7 +364,7 @@ $(function () {
});
$.ajax({
url: "/api/network/gateway",
url: apiUrl + "/network/gateway",
})
.done(function (data) {
const gateway = data.gateway;
+12 -13
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global utils:false */
/* global utils:false, apiUrl: false */
// Add event listener to import button
document.getElementById("submit-import").addEventListener("click", function () {
@@ -20,13 +20,6 @@ function importZIP() {
return;
}
// https://caniuse.com/fetch - everything except IE
// This is fine, as we dropped support for IE a while ago
if (typeof fetch !== "function") {
alert("Importing Tricorder files is not supported with this browser!");
return;
}
// Get the selected import options
const imports = {},
gravity = {};
@@ -44,8 +37,7 @@ function importZIP() {
const formData = new FormData();
formData.append("import", JSON.stringify(imports));
formData.append("file", file);
// eslint-disable-next-line compat/compat
fetch("/api/teleporter", {
fetch(apiUrl + "/teleporter", {
method: "POST",
body: formData,
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") },
@@ -85,7 +77,7 @@ function importZIP() {
// Inspired by https://stackoverflow.com/a/59576416/2087442
$("#GETTeleporter").on("click", function () {
$.ajax({
url: "/api/teleporter",
url: apiUrl + "/teleporter",
headers: { "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content") },
method: "GET",
xhrFields: {
@@ -93,15 +85,22 @@ $("#GETTeleporter").on("click", function () {
},
success: function (data, status, xhr) {
var a = document.createElement("a");
// eslint-disable-next-line compat/compat
var url = globalThis.URL.createObjectURL(data);
a.href = url;
a.download = xhr.getResponseHeader("Content-Disposition").match(/filename="([^"]*)"/)[1];
document.body.append(a);
a.click();
a.remove();
// eslint-disable-next-line compat/compat
globalThis.URL.revokeObjectURL(url);
},
});
});
$(function () {
// Show warning if not accessed over HTTPS
if (location.protocol !== "https:") {
$("#encryption-warning").show();
}
});
+2 -2
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global utils:false, apiFailure:false*/
/* global utils:false, apiUrl:false, apiFailure:false*/
$(function () {
// Handle hiding of alerts
@@ -164,7 +164,7 @@ function saveSettings() {
// Apply changes
$.ajax({
url: "/api/config",
url: apiUrl + "/config",
method: "PATCH",
dataType: "json",
processData: false,
+4 -4
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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 lastPID = -1;
@@ -26,10 +26,10 @@ function formatDnsmasq(line) {
if (line.includes("denied") || line.includes("gravity blocked")) {
// Red bold text for blocked domains
txt = `<b class="log-red">${txt}</b>`;
txt = `<strong class="log-red">${txt}</strong>`;
} else if (line.includes("query[A") || line.includes("query[DHCP")) {
// Bold text for initial query lines
txt = `<b>${txt}</b>`;
txt = `<strong>${txt}</strong>`;
} else {
// Grey text for all other lines
txt = `<span class="text-muted">${txt}</span>`;
@@ -84,7 +84,7 @@ function getData() {
}
$.ajax({
url: "/api/logs/" + GETDict.file + "?nextID=" + nextID,
url: apiUrl + "/logs/" + GETDict.file + "?nextID=" + nextID,
timeout: 5000,
method: "GET",
})
+13 -19
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* 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, WaitMe:false */
$(function () {
// 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
alertModal.one("shown.bs.modal", function () {
$.ajax({
url: "/api/domains/" + list + "/exact",
url: apiUrl + "/domains/" + list + "/exact",
method: "post",
dataType: "json",
processData: false,
@@ -411,7 +411,7 @@ function checkMessages() {
? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true"
: false;
$.ajax({
url: "/api/info/messages/count" + (ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : ""),
url: apiUrl + "/info/messages/count" + (ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : ""),
method: "GET",
dataType: "json",
})
@@ -463,12 +463,12 @@ function changeBulkDeleteStates(table) {
}
}
function doLogout() {
function doLogout(url) {
$.ajax({
url: "/api/auth",
url: apiUrl + "/auth",
method: "DELETE",
}).always(function () {
location.reload();
globalThis.location = url;
});
}
@@ -530,16 +530,9 @@ function getCSSval(cssclass, cssproperty) {
return val;
}
function parseQueryString(queryString = globalThis.location.search) {
const GETDict = {};
queryString
.substr(1)
.split("&")
.forEach(function (item) {
GETDict[item.split("=")[0]] = decodeURIComponent(item.split("=")[1]);
});
return GETDict;
function parseQueryString() {
const params = new URLSearchParams(globalThis.location.search);
return Object.fromEntries(params.entries());
}
// https://stackoverflow.com/q/21647928
@@ -642,11 +635,12 @@ function listAlert(type, items, data) {
);
}
let waitMe = null;
// Callback function for the loading overlay timeout
function loadingOverlayTimeoutCallback(reloadAfterTimeout) {
// Try to ping FTL to see if it finished restarting
$.ajax({
url: "/api/info/login",
url: apiUrl + "/info/login",
method: "GET",
cache: false,
dataType: "json",
@@ -657,7 +651,7 @@ function loadingOverlayTimeoutCallback(reloadAfterTimeout) {
if (reloadAfterTimeout) {
location.reload();
} else {
$(".wrapper").waitMe("hide");
waitMe.hideAll();
}
})
.fail(function () {
@@ -668,7 +662,7 @@ function loadingOverlayTimeoutCallback(reloadAfterTimeout) {
function loadingOverlay(reloadAfterTimeout = false) {
NProgress.start();
$(".wrapper").waitMe({
waitMe = new WaitMe(".wrapper", {
effect: "bounce",
text: "Pi-hole is currently applying your changes...",
bg: "rgba(0,0,0,0.7)",
+2 -2
View File
@@ -66,8 +66,8 @@ end
</div>
<!-- ./wrapper -->
<script src="<?=pihole.fileversion('scripts/js/footer.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/footer.js')?>"></script>
<div id="advanced-info-data" style="display: none;" data-starttime="<?=starttime?>" data-endtime="<?=mg.time(true)?>" data-client-ip="<?=mg.request_info.remote_addr?>" data-tls="<?=tostring(is_secure)?>" data-xff="<?=x_forwarded_for?>"></div>
<div id="advanced-info-data" style="display: none;" data-starttime="<?=starttime?>" data-endtime="<?=mg.time(true)?>" data-client-ip="<?=mg.request_info.remote_addr?>" data-xff="<?=x_forwarded_for?>"></div>
</body>
</html>
+34 -36
View File
@@ -11,6 +11,7 @@
starttime = mg.time(true)
hostname = pihole.hostname()
webhome = pihole.webhome()
theme = pihole.webtheme()
-- Get name of script by matching whatever is after the last "/" in the URI
scriptname = mg.request_info.request_uri:match(webhome.."(.*)$")
@@ -39,9 +40,6 @@ function in_array (val, tab)
return false
end
-- Connection is considered secure if running natively on HTTPS
is_secure = mg.request_info.https
-- Variable to check if user is already authenticated
is_authenticated = mg.request_info.is_authenticated
@@ -49,51 +47,46 @@ is_authenticated = mg.request_info.is_authenticated
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Usually browsers proactively perform domain name resolution on links that the user may choose to follow. We disable DNS prefetching here -->
<meta http-equiv="x-dns-prefetch-control" content="off">
<meta http-equiv="cache-control" content="max-age=60,private">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pi-hole <?=hostname?></title>
<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="icon" href="<?=pihole.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="manifest" href="<?=pihole.webhome()?>img/favicons/manifest.json">
<? theme = pihole.webtheme() ?>
<link rel="mask-icon" href="<?=pihole.webhome()?>img/favicons/safari-pinned-tab.svg" color="<?=theme.color?>">
<link rel="shortcut icon" href="<?=pihole.webhome()?>img/favicons/favicon.ico">
<link rel="apple-touch-icon" href="<?=webhome?>img/favicons/apple-touch-icon.png" sizes="180x180">
<link rel="icon" href="<?=webhome?>img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
<link rel="icon" href="<?=webhome?>img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
<link rel="manifest" href="<?=webhome?>img/favicons/manifest.json">
<link rel="mask-icon" href="<?=webhome?>img/favicons/safari-pinned-tab.svg" color="<?=theme.color?>">
<link rel="shortcut icon" href="<?=webhome?>img/favicons/favicon.ico">
<meta name="msapplication-TileColor" content="<?=theme.color?>">
<meta name="msapplication-TileImage" content="<?=pihole.webhome()?>img/favicons/mstile-150x150.png">
<!-- Theme styles -->
<meta name="msapplication-TileImage" content="<?=webhome?>img/favicons/mstile-150x150.png">
<meta name="theme-color" content="<?=theme.color?>">
<? if theme.dark then ?>
<style>
html { background-color: #000; }
</style>
<? end ?>
<script src="<?=pihole.fileversion('vendor/nprogress/nprogress.min.js')?>"></script>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/nprogress/nprogress.min.css')?>">
<!-- Theme fonts -->
<? if theme.name == 'lcars' then ?>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/fonts/ubuntu-mono/ubuntu-mono.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/fonts/antonio/antonio.css')?>">
<? else ?>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/fonts/SourceSansPro/SourceSansPro.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/fonts/source-sans-pro/source-sans-pro.css')?>">
<? end ?>
<? if theme.dark then ?>
<style>
html { background-color: #000; }
</style>
<? end ?>
<!-- Common styles -->
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/bootstrap/css/bootstrap.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/animate/animate.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/bstreeview/bstreeview.min.css')?>">
<?
if startsWith(scriptname, 'groups') then
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/font-awesome/css/all.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/nprogress/nprogress.min.css')?>">
<? if startsWith(scriptname, 'groups') then
-- Group management styles
?>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/bootstrap-select/bootstrap-select.min.css')?>">
@@ -105,21 +98,26 @@ if startsWith(scriptname, 'groups') then
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/daterangepicker/daterangepicker.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.css')?>">
<? end ?>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/waitMe-js/waitMe.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/select2/select2.min.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/adminLTE/AdminLTE.min.css')?>">
<!-- Theme styles -->
<!-- Theme styles (<?= theme.name ?>) -->
<link rel="stylesheet" href="<?=pihole.fileversion('style/pi-hole.css')?>">
<link rel="stylesheet" href="<?=pihole.fileversion('style/themes/'..theme.name..'.css')?>">
<? if theme.name == "default-auto" then ?>
<link rel="stylesheet" href="<?=pihole.fileversion('style/themes/default-dark.css')?>" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="<?=pihole.fileversion('style/themes/default-light.css')?>" media="not (prefers-color-scheme: dark)">
<? else ?>
<link rel="stylesheet" href="<?=pihole.fileversion('style/themes/' ..theme.name.. '.css')?>">
<? end ?>
<noscript><link rel="stylesheet" href="<?=pihole.fileversion('vendor/js-warn/js-warn.css')?>"></noscript>
<!-- scripts -->
<script src="<?=pihole.fileversion('vendor/jquery/jquery.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/bootstrap/js/bootstrap.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/adminLTE/adminlte.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/bootstrap-notify/bootstrap-notify.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/font-awesome/all.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/utils.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/waitMe/waitMe.min.js')?>"></script>
<link rel="stylesheet" href="<?=pihole.fileversion('vendor/waitMe/waitMe.min.css')?>">
<script defer src="<?=pihole.fileversion('vendor/jquery/jquery.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap/js/bootstrap.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/adminLTE/adminlte.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-notify/bootstrap-notify.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/waitMe-js/modernized-waitme-min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/nprogress/nprogress.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/utils.js')?>"></script>
+18 -19
View File
@@ -9,20 +9,20 @@
]]--
mg.include('header.lp','r')
?>
<script src="<?=pihole.fileversion('scripts/js/logout.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/select2/select2.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/datatables/datatables.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/datatables-select/datatables.select.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/datatables-buttons/datatables.buttons.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/chartjs/chart.umd.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/chartjs-plugin-deferred/chartjs-plugin-deferred.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/moment/moment.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/chartjs-adapter-moment/chartjs-adapter-moment.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/hammer/hammer.min.js')?>"></script> <!-- Needed for chartjs-plugin-zoom --->
<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 defer src="<?=pihole.fileversion('vendor/select2/select2.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/datatables/datatables.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/datatables-select/datatables.select.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/datatables-buttons/datatables.buttons.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/chartjs/chart.umd.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/chartjs-plugin-deferred/chartjs-plugin-deferred.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/moment/moment.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/chartjs-adapter-moment/chartjs-adapter-moment.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/hammer/hammer.min.js')?>"></script> <!-- Needed for chartjs-plugin-zoom -->
<script defer src="<?=pihole.fileversion('vendor/chartjs-plugin-zoom/chartjs-plugin-zoom.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bstreeview/bstreeview.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/logout.js')?>"></script>
</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()?>" data-logout-url="<?=webhome .. 'login'?>">
<noscript>
<!-- JS Warning -->
<div>
@@ -39,7 +39,7 @@ mg.include('header.lp','r')
<div class="wrapper">
<header class="main-header">
<!-- Logo -->
<a href="<?=pihole.webhome()?>" class="logo">
<a href="<?=webhome?>" class="logo">
<!-- mini logo for sidebar mini 50x50 pixels -->
<span class="logo-mini">P<strong>h</strong></span>
<!-- logo for regular state and mobile devices -->
@@ -48,11 +48,10 @@ mg.include('header.lp','r')
<!-- Header Navbar: style can be found in header.less -->
<nav class="navbar navbar-static-top">
<!-- Sidebar toggle button-->
<a href="#" class="sidebar-toggle-svg" data-toggle="push-menu" role="button">
<button class="sidebar-toggle-svg" data-toggle="push-menu" aria-label="Toggle Navigation">
<i aria-hidden="true" class="fa fa-angle-double-left"></i>
<span class="sr-only">Toggle navigation</span>
<span class="warning-count hidden" id="top-warning-count"></span>
</a>
</button>
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
<li<? if string.len(hostname) == 0 then ?> class="hidden"<? end ?>>
@@ -68,7 +67,7 @@ mg.include('header.lp','r')
<ul class="dropdown-menu">
<!-- User image -->
<li class="user-header">
<img class="logo-img" src="<?=pihole.webhome()?>img/logo.svg" alt="Pi-hole Logo" style="border: 0" width="90" height="90">
<img class="logo-img" src="<?=webhome?>img/logo.svg" alt="Pi-hole Logo" width="50" height="50">
<p>
Open Source Ad Blocker
</p>
@@ -78,7 +77,7 @@ mg.include('header.lp','r')
<!-- Menu Footer -->
<li class="user-footer">
<a class="btn-link" href="https://pi-hole.net/" rel="noopener" target="_blank">
<svg class="svg-inline--fa fa-fw menu-icon" style="height: 1.25em"><use xlink:href="<?=pihole.webhome()?>img/pihole_icon.svg#pihole-svg-logo"/></svg>
<? mg.include('../../img/logo-bw.svg', 'r') ?>
Pi-hole Website
</a>
<hr>
+27 -19
View File
@@ -13,13 +13,13 @@
<!-- Sidebar user panel -->
<div class="user-panel">
<div class="pull-left image">
<img class="logo-img" src="<?=webhome?>img/logo.svg" alt="Pi-hole logo">
<img class="logo-img" src="<?=webhome?>img/logo.svg" alt="Pi-hole logo" width="52" height="75">
</div>
<div class="pull-left info">
<p>Status</p>
<span id="status"></span><br/>
<span id="query_frequency"></span><br/>
<span id="cpu"></span><br/>
<span id="status"></span><br>
<span id="query_frequency"></span><br>
<span id="cpu"></span><br>
<span id="memory"></span>
</div>
</div>
@@ -43,35 +43,43 @@
<!-- Group Management -->
<li class="menu-group<? if scriptname == 'groups' then ?> active<? end ?>">
<a href="<?=webhome?>groups">
<i class="fa fa-fw menu-icon fa-user-friends"></i> <span>Groups
<span class="pull-right-container">
<span class="label label-primary pull-right" id="num_groups" title="Number of enabled groups"></span>
<i class="fa fa-fw menu-icon fa-user-friends"></i>
<span>Groups
<span class="pull-right-container">
<span class="label label-primary pull-right" id="num_groups" title="Number of enabled groups"></span>
</span>
</span>
</a>
</li>
<li class="menu-group<? if scriptname == 'groups/clients' then ?> active<? end ?>">
<a href="<?=webhome?>groups/clients">
<i class="fa fa-fw menu-icon fa-laptop"></i> <span>Clients
<span class="pull-right-container">
<span class="label label-primary pull-right" id="num_clients" title="Number of defined clients"></span>
<i class="fa fa-fw menu-icon fa-laptop"></i>
<span>Clients
<span class="pull-right-container">
<span class="label label-primary pull-right" id="num_clients" title="Number of defined clients"></span>
</span>
</span>
</a>
</li>
<li class="menu-group<? if scriptname == 'groups/domains' then ?> active<? end ?>">
<a href="<?=webhome?>groups/domains">
<i class="fa fa-fw menu-icon fa-list"></i> <span>Domains
<span class="pull-right-container">
<span class="label bg-red pull-right" id="num_denied" title="Number of enabled deny rules (domains and regex)"></span>
<span class="label bg-green pull-right" id="num_allowed" title="Number of enabled allow rules (domains and regex)"></span>
<i class="fa fa-fw menu-icon fa-list"></i>
<span>Domains
<span class="pull-right-container">
<span class="label bg-red pull-right" id="num_denied" title="Number of enabled deny rules (domains and regex)"></span>
<span class="label bg-green pull-right" id="num_allowed" title="Number of enabled allow rules (domains and regex)"></span>
</span>
</span>
</a>
</li>
<li class="menu-group<? if scriptname == 'groups/lists' then ?> active<? end ?>">
<a href="<?=webhome?>groups/lists">
<i class="fa fa-fw menu-icon fa-shield-alt"></i> <span>Lists
<span class="pull-right-container">
<span class="label bg-blue pull-right" id="num_lists" title="Number of subscribed and enabled lists"></span>
<span class="label bg-yellow pull-right" id="num_gravity" title="Total number of domains subscribed by your Pi-hole"></span>
<i class="fa fa-fw menu-icon fa-shield-alt"></i>
<span>Lists
<span class="pull-right-container">
<span class="label bg-blue pull-right" id="num_lists" title="Number of subscribed and enabled lists"></span>
<span class="label bg-yellow pull-right" id="num_gravity" title="Total number of domains subscribed by your Pi-hole"></span>
</span>
</span>
</a>
</li>
@@ -251,7 +259,7 @@
<!-- Donate button -->
<li class="header text-uppercase">Donate</li>
<li class="menu-donate">
<a href="https://pi-hole.net/donate/" target="_blank">
<a href="https://pi-hole.net/donate/" rel="noopener" target="_blank">
<i class="fas fa-fw menu-icon fa-donate"></i> <span>Donate</span>
</a>
</li>
+1 -1
View File
@@ -48,5 +48,5 @@ mg.include('scripts/lua/header_authenticated.lp','r')
<pre id="output" style="width: 100%; height: 100%;" hidden></pre>
<script src="<?=pihole.fileversion('scripts/js/search.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/search.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+3 -3
View File
@@ -32,8 +32,8 @@ mg.include('scripts/lua/settings_header.lp','r')
<button type="button" class="btn btn-primary save-button"><i class="fa-solid fa-fw fa-floppy-disk"></i>&nbsp;Save & Apply</button>
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings-advanced.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings-advanced.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+6 -6
View File
@@ -194,7 +194,7 @@ mg.include('scripts/lua/settings_header.lp','r')
<div class="col-md-6 col-md-offset-3">
<div id="totp_div" class="has-feedback has-error">
<div class="pwd-field form-group">
<input type="text" size="6" maxlength="6" class="form-control totp_token" id="totp_code" placeholder=""/>
<input type="text" size="6" maxlength="6" class="form-control totp_token" id="totp_code" placeholder="">
</div>
<i class="fa-solid fa-clock-rotate-left pwd-field form-control-feedback"></i>
</div>
@@ -246,10 +246,10 @@ mg.include('scripts/lua/settings_header.lp','r')
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/jquery-confirm/jquery.confirm.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/qrious/qrious.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings-api.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/jquery-confirm/jquery.confirm.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/qrious/qrious.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings-api.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+5 -5
View File
@@ -202,7 +202,7 @@ mg.include('scripts/lua/settings_header.lp','r')
<ul>
<li> Addresses allocated like this are not constrained to be in the DHCP range specified above but they must be in the same subnet. For subnets which don't need a pool of dynamically allocated addresses, you can set a one-address range above and specify only static leases here.</li>
<li> It is allowed to use client identifiers (called client DUID in IPv6-land) rather than hardware addresses to identify hosts by prefixing with <code>id:</code>. Thus lines like <code>id:01:02:03:04,.....</code> refer to the host with client identifier <code>01:02:03:04</code>. It is also allowed to specify the client ID as text, like this: <code>id:clientidastext,.....</code></li>
<li> A single line may contain an IPv4 address or one or more IPv6 addresses, or both. IPv6 addresses must be bracketed by square brackets thus: <code>laptop,[1234::56]</code> IPv6 addresses may contain only the host-identifier part: <code>laptop,[::56]</code> in which case they act as wildcards in constructed DHCP ranges, with the appropriate network part inserted. For IPv6, an address may include a prefix length: <code>laptop,[1234:50/126]</code> which (in this case) specifies four addresses, <code>1234::50</code> to <code>1234::53</code>. This (an the ability to specify multiple addresses) is useful when a host presents either a consistent name or hardware-ID, but varying DUIDs, since it allows dnsmasq to honour the static address allocation but assign a different address for each DUID. This typically occurs when chain netbooting, as each stage of the chain gets in turn allocates an address.</li>
<li> A single line may contain an IPv4 address or one or more IPv6 addresses, or both. IPv6 addresses must be bracketed by square brackets thus: <code>laptop,[1234::56]</code> IPv6 addresses may contain only the host-identifier part: <code>laptop,[::56]</code> in which case they act as wildcards in constructed DHCP ranges, with the appropriate network part inserted. For IPv6, an address may include a prefix length: <code>laptop,[1234:50/126]</code> which (in this case) specifies four addresses, <code>1234::50</code> to <code>1234::53</code>. This (and the ability to specify multiple addresses) is useful when a host presents either a consistent name or hardware-ID, but varying DUIDs, since it allows dnsmasq to honour the static address allocation but assign a different address for each DUID. This typically occurs when chain netbooting, as each stage of the chain gets in turn allocates an address.</li>
<!--<li> Note that in IPv6 DHCP, the hardware address may not be available, though it normally is for direct-connected clients, or clients using DHCP relays which support RFC 6939.</li>-->
<li> For DHCPv4, the special option <code>id:*</code> means "ignore any client-id and use MAC addresses only." This is useful when a client presents a client-id sometimes but not others.</li>
<li> If a name appears in <code>/etc/hosts</code>, the associated address can be allocated to a DHCP lease, but only if a separate line specifying the name also exists. Only one hostname can be given per line, but aliases are possible by using CNAMEs. Note that <code>/etc/hosts</code> is NOT used when the DNS server side of dnsmasq is disabled by setting the DNS server port to zero.</li>
@@ -225,9 +225,9 @@ mg.include('scripts/lua/settings_header.lp','r')
<button type="button" class="btn btn-primary save-button"><i class="fa-solid fa-fw fa-floppy-disk"></i>&nbsp;Save & Apply</button>
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings-dhcp.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings-dhcp.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+6 -6
View File
@@ -99,7 +99,7 @@ mg.include('scripts/lua/settings_header.lp','r')
rate-limited clients are short-circuited at the same time.</p>
<p>Rate-limiting may be disabled altogether by setting both
values to zero. See
<a href="https://docs.pi-hole.net/ftldns/configfile/#rate_limit" target="_blank">our documentation</a>
<a href="https://docs.pi-hole.net/ftldns/configfile/#rate_limit" rel="noopener" target="_blank">our documentation</a>
for further details.</p>
</div>
</div>
@@ -144,7 +144,7 @@ mg.include('scripts/lua/settings_header.lp','r')
in your router!) they are safe to use.</p>
</div>
</div>
<p>See <a href="https://docs.pi-hole.net/ftldns/interfaces/" target="_blank">our documentation</a> for further technical details.</p>
<p>See <a href="https://docs.pi-hole.net/ftldns/interfaces/" rel="noopener" target="_blank">our documentation</a> for further technical details.</p>
</div>
</div>
</div>
@@ -175,7 +175,7 @@ mg.include('scripts/lua/settings_header.lp','r')
with "no such domain" rather than being forwarded upstream. The set
of prefixes affected is the list given in <a href="https://tools.ietf.org/html/rfc6303">RFC6303</a>.</p>
<p><strong>Important:</strong><br>Enabling these two options may increase your privacy,
but may also prevent you from being able to access to access local hostnames if the Pi-hole is not used as DHCP server.
but may also prevent you from being able to access local hostnames if the Pi-hole is not used as DHCP server.
Make sure you have set up conditional forwarding in this case.</p>
</div>
<br>
@@ -238,8 +238,8 @@ mg.include('scripts/lua/settings_header.lp','r')
<button type="button" class="btn btn-primary save-button"><i class="fa-solid fa-fw fa-floppy-disk"></i>&nbsp;Save & Apply</button>
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings-dns.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings-dns.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+6 -6
View File
@@ -100,17 +100,17 @@ mg.include('scripts/lua/settings_header.lp','r')
<strong>Note:</strong>
<p>The target of a <code>CNAME</code> must be a domain that the Pi-hole already has in its cache or is authoritative for. This is a universal limitation of <code>CNAME</code> records.</p>
<p>The reason for this is that Pi-hole will not send additional queries upstream when serving <code>CNAME</code> replies. As consequence, if you set a target that isn't already known, the reply to the client may be incomplete. Pi-hole just returns the information it knows at the time of the query. This results in certain limitations for <code>CNAME</code> targets,
for instance, only <i>active</i> DHCP leases work as targets - mere DHCP <i>leases</i> aren't sufficient as they aren't (yet) valid DNS records.</p>
for instance, only <em>active</em> DHCP leases work as targets - mere DHCP <i>leases</i> aren't sufficient as they aren't (yet) valid DNS records.</p>
<p>Additionally, you can't <code>CNAME</code> external domains (<code>bing.com</code> to <code>google.com</code>) successfully as this could result in invalid SSL certificate errors when the target server does not serve content for the requested domain.</p>
<p>Adding/removing local CNAME records will restart the DNS server.</p>
</div>
</div>
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/jquery-confirm/jquery.confirm.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings-dns-records.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/jquery-confirm/jquery.confirm.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings-dns-records.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/ip-address-sorting.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+3 -3
View File
@@ -104,8 +104,8 @@ mg.include('scripts/lua/settings_header.lp','r')
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings-privacy.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings-privacy.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+5 -5
View File
@@ -316,10 +316,10 @@ mg.include('scripts/lua/settings_header.lp','r')
</div>
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/jquery-confirm/jquery.confirm.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/charts.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings-system.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/jquery-confirm/jquery.confirm.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/charts.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings-system.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+5 -5
View File
@@ -21,7 +21,7 @@ mg.include('scripts/lua/settings_header.lp','r')
</div>
<div class="box-body">
<p><strong>Warning:</strong><br>This archive contains sensitive information about your Pi-hole installation, e.g. your 2FA-TOTP secret (if enabled). Please be careful with this file and do not share it with anyone even if they claim to help you.</p>
<? if not is_secure then ?><p class='text-danger'><strong>Warning:</strong><br>You are currently not using an end-to-end encryption. This means that secrets like your 2FA-TOTP secret will be transmitted in plain text. We recommend to use HTTPS when exporting your configuration.</p><? end ?>
<p class='text-danger' id="encryption-warning" style="display: none;"><strong>Warning:</strong><br>You are currently not using an end-to-end encryption. This means that secrets like your 2FA-TOTP secret will be transmitted in plain text. We recommend to use HTTPS when exporting your configuration.</p>
<div class="pull-right">
<a class="btn btn-app btn-success" id="GETTeleporter" target="_blank">
<i class="fa fa-save fa-xl"></i><br>Export
@@ -89,7 +89,7 @@ mg.include('scripts/lua/settings_header.lp','r')
<div id="modal-import-gravity" style="display:none">
<div class="alert alert-info alert-dismissible">
<h4><i class="icon fa fa-fw fa-info-circle"></i> Please run gravity</h4>
<p>Use <a href='/admin/gravity'>Tools &rarr; Gravity</a> or run <code>pihole -g</code> to update your lists.</p>
<p>Use <a href='/admin/gravity'>Tools &rarr; Update Gravity</a> or run <code>pihole -g</code> to update your lists.</p>
</div>
</div>
<div id="modal-import-info-message"></div>
@@ -101,8 +101,8 @@ mg.include('scripts/lua/settings_header.lp','r')
</div>
</div>
<script src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings-teleporter.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<script defer src="<?=pihole.fileversion('vendor/bootstrap-toggle/bootstrap-toggle.min.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings-teleporter.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/settings.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
+27 -28
View File
@@ -37,20 +37,6 @@
background: url("../img/boxed-bg.png") repeat fixed;
}
@-webkit-keyframes Pulse {
from {
opacity: 0;
}
50% {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes Pulse {
from {
opacity: 0;
@@ -97,7 +83,6 @@ td.lookatme {
inset: 0;
z-index: 1;
/* 20 steps / 2 seconds = 10fps */
-webkit-animation: 2s infinite Pulse steps(20);
animation: 2s infinite Pulse steps(20);
}
@@ -188,7 +173,6 @@ td.lookatme {
border-radius: 50%;
border: 4px solid #c0c0c0;
border-right-color: transparent;
-webkit-animation: fa-spin 1s infinite linear;
animation: fa-spin 1s infinite linear;
}
@@ -331,7 +315,6 @@ td.lookatme {
.no-user-select {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@@ -431,7 +414,8 @@ tfoot.add-new-item > tr > th {
position: relative;
color: #fff;
float: left;
background: none;
background-color: transparent;
border: none;
padding: 15px;
width: 50px;
text-align: center;
@@ -459,6 +443,12 @@ tfoot.add-new-item > tr > th {
padding: 5px;
}
.main-header .navbar .nav > li.user > a > .fa,
.main-header .navbar .nav > li.user > a > .glyphicon,
.main-header .navbar .nav > li.user > a > .ion {
margin-right: 0;
}
.box {
border-radius: 8px;
overflow: hidden;
@@ -502,7 +492,7 @@ tfoot.add-new-item > tr > th {
}
}
.small-box-footer svg {
.small-box-footer i {
margin: 0 5px;
font-size: 13px;
}
@@ -595,7 +585,6 @@ td.details-control {
}
.loginpage-logo {
width: 140px;
margin: 0 0 10px;
}
@@ -848,16 +837,16 @@ body:not([class*="lcars"])
}
/* reverse side menu collapse arrows when menu is closed */
.sidebar-collapse .sidebar-toggle-svg svg {
.sidebar-collapse .sidebar-toggle-svg i {
transform: scaleX(-1);
}
/* reverse side menu collapse arrows on mobile screens */
@media (max-width: 767px) {
.sidebar-toggle-svg svg {
.sidebar-toggle-svg i {
transform: scaleX(-1);
}
.sidebar-open .sidebar-toggle-svg svg {
.sidebar-open .sidebar-toggle-svg i {
transform: scaleX(1);
}
}
@@ -997,6 +986,11 @@ body:not([class*="lcars"])
margin-right: 0.5em;
}
.user-footer .menu-icon {
max-height: 1.75rem;
vertical-align: middle;
}
div.dt-buttons {
margin: 2px 0 5px;
}
@@ -1101,10 +1095,6 @@ table.dataTable tbody > tr > .selected {
padding: 5px;
}
.faint-border {
border-color: rgba(127, 127, 127, 0.1);
}
.pre-scrollable {
/* use dynamic unit to account for mobile browser interface height */
max-height: max(195px, 100dvh - 170px);
@@ -1141,6 +1131,10 @@ table.dataTable tbody > tr > .selected {
letter-spacing: 0.5em;
}
.totp_token::-moz-placeholder {
opacity: 0.1;
}
.totp_token::placeholder {
opacity: 0.1;
}
@@ -1151,6 +1145,7 @@ table.dataTable tbody > tr > .selected {
right: 0.6em;
z-index: 10;
background: var(--overlay-bgcolor);
width: -moz-fit-content;
width: fit-content;
border-radius: 0.5em;
padding: 0;
@@ -1565,7 +1560,7 @@ table.dataTable tbody > tr > .selected {
margin: 0 5px;
}
.box-icons svg {
.box-icons i {
margin: 0 4px;
}
@@ -1584,3 +1579,7 @@ textarea.field-sizing-content {
.bstreeview .list-group-item:hover {
background-color: rgba(127, 127, 127, 0.18);
}
.child-interface-icon {
line-height: 0.5em;
font-size: 1.7em;
}
-6
View File
@@ -1,6 +0,0 @@
/* Code courtesy of https://blog.jim-nielsen.com/2019/conditional-syntax-highlighting-in-dark-mode-with-css-imports/ */
/* Import light mode if color-scheme is different than dark (even not set) */
@import "default-light.css" screen and not (prefers-color-scheme: dark);
/* Import dark mode when applicable */
@import "default-dark.css" screen and (prefers-color-scheme: dark);
+1
View File
@@ -518,6 +518,7 @@ textarea:-webkit-autofill,
select:-webkit-autofill {
-webkit-text-fill-color: #bec5cb !important;
-webkit-box-shadow: 0 0 0px 1000px #353c42 inset;
-webkit-transition: background-color 1s ease-in-out 0s;
transition: background-color 1s ease-in-out 0s;
}
.form-control[disabled],
+13 -2
View File
@@ -54,6 +54,10 @@ table {
border-color: #545b5e;
background-color: transparent;
}
::-moz-placeholder {
color: #b2aba1;
opacity: 0.5 !important;
}
::placeholder {
color: #b2aba1;
opacity: 0.5 !important;
@@ -66,6 +70,7 @@ textarea:-webkit-autofill,
select:-webkit-autofill {
-webkit-text-fill-color: #b2aba1 !important;
-webkit-box-shadow: 0 0 0px 1000px #181a1b inset;
-webkit-transition: background-color 1s ease-in-out 0s;
transition: background-color 1s ease-in-out 0s;
}
::-webkit-scrollbar {
@@ -87,11 +92,11 @@ select:-webkit-autofill {
* {
scrollbar-color: #454a4d #202324;
}
::selection {
::-moz-selection {
background-color: #004daa !important;
color: #e8e6e3 !important;
}
::-moz-selection {
::selection {
background-color: #004daa !important;
color: #e8e6e3 !important;
}
@@ -552,6 +557,9 @@ output {
border-color: rgb(44, 103, 137);
box-shadow: none;
}
.form-control::-moz-placeholder {
color: rgb(168, 160, 149);
}
.form-control::placeholder {
color: rgb(168, 160, 149);
}
@@ -2477,6 +2485,9 @@ a:focus {
background-color: rgba(24, 26, 27, 0.9);
background-image: none;
}
.main-header #navbar-search-input.form-control::-moz-placeholder {
color: rgb(200, 195, 188);
}
.main-header #navbar-search-input.form-control::placeholder {
color: rgb(200, 195, 188);
}
+1
View File
@@ -294,6 +294,7 @@ textarea:-webkit-autofill,
select:-webkit-autofill {
-webkit-text-fill-color: #666 !important;
-webkit-box-shadow: 0 0 0px 1000px #fff inset;
-webkit-transition: background-color 1s ease-in-out 0s;
transition: background-color 1s ease-in-out 0s;
}
+6 -3
View File
@@ -621,7 +621,7 @@ kbd {
background: #181c20;
font-size: 14px;
}
#output b.log-red {
#output .log-red {
background: #b23;
color: #fff;
}
@@ -675,6 +675,7 @@ textarea:-webkit-autofill,
select:-webkit-autofill {
-webkit-text-fill-color: var(--main-text-color) !important;
-webkit-box-shadow: 0 0 0px 1000px #3c4652 inset;
-webkit-transition: background-color 1s ease-in-out 0s;
transition: background-color 1s ease-in-out 0s;
}
@@ -684,6 +685,7 @@ fieldset[disabled] .form-control {
background-color: #3c4652;
opacity: 1;
-moz-appearance: textfield;
-webkit-appearance: textfield;
appearance: textfield;
}
@@ -854,10 +856,11 @@ input[type="password"]::-webkit-caps-lock-indicator {
background-color: transparent;
}
.form-control::placeholder {
.form-control::-moz-placeholder {
color: #9ab;
}
.form-control::-webkit-input-placeholder {
.form-control::placeholder {
color: #9ab;
}
.form-control:focus::placeholder,
+5 -1
View File
@@ -202,6 +202,9 @@ a:hover {
.form-control {
color: #000;
}
.form-control::-moz-placeholder {
color: #6c747b;
}
.form-control::placeholder {
color: #6c747b;
}
@@ -291,7 +294,7 @@ a:hover {
#output {
font-size: 14px;
}
#output b.log-red {
#output .log-red {
background: #c00;
color: #fff;
}
@@ -331,6 +334,7 @@ textarea:-webkit-autofill,
select:-webkit-autofill {
-webkit-text-fill-color: #666 !important;
-webkit-box-shadow: 0 0 0px 1000px #fff inset;
-webkit-transition: background-color 1s ease-in-out 0s;
transition: background-color 1s ease-in-out 0s;
}
+24 -83
View File
@@ -306,6 +306,7 @@ textarea:-webkit-autofill,
select:-webkit-autofill {
-webkit-text-fill-color: #fff !important;
-webkit-box-shadow: 0 0 0 1000px #000 inset;
-webkit-transition: background-color 1s ease-in-out 0s;
transition: background-color 1s ease-in-out 0s;
}
@@ -346,13 +347,16 @@ p.login-box-msg,
z-index: 1;
}
.form-control::-moz-placeholder {
color: #456;
}
.form-control::placeholder {
color: #456;
}
.form-control:focus {
border-color: #48f;
-webkit-box-shadow: none;
box-shadow: none;
}
@@ -531,6 +535,11 @@ p.login-box-msg,
z-index: 1000;
}
.dropdown.bootstrap-select {
border: none;
background: none;
}
.bootstrap-select > .dropdown-toggle.bs-placeholder,
.bootstrap-select > .dropdown-toggle.bs-placeholder:active,
.bootstrap-select > .dropdown-toggle.bs-placeholder:focus {
@@ -589,8 +598,6 @@ p.login-box-msg,
}
.nav.navbar-nav {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
justify-content: space-between;
align-items: center;
@@ -608,14 +615,6 @@ p.login-box-msg,
flex: 1 1 auto;
}
#pihole-diagnosis {
min-width: 50px;
}
#pihole-diagnosis svg {
font-size: 28px;
}
.warning-count {
position: relative;
margin: 0;
@@ -931,7 +930,7 @@ p.login-box-msg,
margin-right: -9px;
}
.sidebar-menu li a > svg {
.sidebar-menu li a > i {
display: none;
}
@@ -939,7 +938,7 @@ p.login-box-msg,
margin-right: 0;
}
.treeview-menu li a svg {
.treeview-menu li a i {
display: inherit;
position: absolute;
right: 16px;
@@ -990,7 +989,7 @@ p.login-box-msg,
position: absolute !important;
}
.sidebar-collapse .treeview-menu li a svg {
.sidebar-collapse .treeview-menu li a i {
top: auto;
right: auto;
bottom: 6px;
@@ -1020,17 +1019,12 @@ p.login-box-msg,
margin-top: 20px;
}
.user-panel .fa-circle path {
stroke: rgba(0, 0, 0, 0.5);
stroke-width: 5%;
.user-panel > .info i {
text-shadow: 0 0 1px black;
}
.user-panel .svg-inline--fa {
margin-right: 2px;
}
.user-panel svg.text-orange,
.user-panel svg.text-red {
.user-panel > .info i.text-orange,
.user-panel > .info i.text-red {
animation: fire 1s ease-in-out 0s infinite;
}
@@ -1153,7 +1147,7 @@ footer a:focus {
box-shadow: none;
}
.sidebar-collapse .sidebar-menu svg {
.sidebar-collapse .sidebar-menu i {
display: block;
}
@@ -1569,38 +1563,6 @@ table.dataTable {
}
/*** Animation keyframes ***/
@-webkit-keyframes flash {
0% {
filter: opacity(0.35) contrast(2);
}
5% {
filter: opacity(0.7) contrast(2);
}
10% {
filter: opacity(0.35) contrast(2);
}
15% {
filter: opacity(0.7) contrast(2);
}
20% {
filter: opacity(0.35) contrast(2);
}
25% {
filter: opacity(0.7) contrast(2);
}
30% {
filter: opacity(0.35) contrast(2);
}
35% {
filter: opacity(0.7) contrast(1);
}
70% {
filter: opacity(1) contrast(1) brightness(1.2);
}
90% {
filter: none;
}
}
@keyframes flash {
0% {
@@ -1635,37 +1597,15 @@ table.dataTable {
}
}
@-webkit-keyframes fire {
0% {
filter: drop-shadow(0 0 2px #f90);
}
60% {
filter: none;
}
}
@keyframes fire {
0% {
filter: drop-shadow(0 0 2px #f90);
}
60% {
-webkit-filter: none;
filter: none;
}
}
@-webkit-keyframes warningPulse {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes warningPulse {
0% {
opacity: 0;
@@ -2131,11 +2071,6 @@ td.highlight {
font-family: sans-serif;
}
/*** size correction to fit in one line - Settings/DNS ***/
#dns .col-md-11 {
width: 84%;
}
/*** add style to the information/about dropdown ***/
.navbar-nav > .user-menu > .dropdown-menu > .user-header,
.navbar-nav > .user-menu > .dropdown-menu > .user-footer {
@@ -2188,3 +2123,9 @@ td.highlight {
padding-top: 0.2em;
padding-bottom: 0.55em;
}
/*** 🖖 ***/
.fas.fa-hand-paper {
--fa: "\f259" !important;
--fa--fa: "\f259\f259" !important;
}
+1 -1
View File
@@ -33,6 +33,6 @@ mg.include('scripts/lua/header_authenticated.lp','r')
</div>
</div>
<script src="<?=pihole.fileversion('scripts/js/taillog.js')?>"></script>
<script defer src="<?=pihole.fileversion('scripts/js/taillog.js')?>"></script>
<? mg.include('scripts/lua/footer.lp','r')?>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+11 -15
View File
@@ -1,32 +1,28 @@
/* antonio-100 - latin-ext_latin */
/* https://gwfh.mranftl.com/fonts/antonio?subsets=latin */
/* antonio-100 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Antonio';
font-style: normal;
font-weight: 100;
font-display: swap;
src: local('Antonio Light'),
url('antonio-v1-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
url('antonio-v1-latin-ext_latin-100.woff') format('woff') /* Modern Browsers */
src: url('antonio-v19-latin-100.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* antonio-regular - latin-ext_latin */
/* antonio-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Antonio';
font-style: normal;
font-weight: 400;
font-display: swap;
src: local('Antonio'),
url('antonio-v1-latin-ext_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('antonio-v1-latin-ext_latin-regular.woff') format('woff') /* Modern Browsers */
src: url('antonio-v19-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* antonio-700 - latin-ext_latin */
/* antonio-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: 'Antonio';
font-style: normal;
font-weight: 700;
font-display: swap;
src: local('Antonio Bold'),
url('antonio-v1-latin-ext_latin-700.woff2') format('woff2'), /* Super Modern Browsers */
url('antonio-v1-latin-ext_latin-700.woff') format('woff') /* Modern Browsers */
src: url('antonio-v19-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}

Some files were not shown because too many files have changed in this diff Show More