diff --git a/.gitattributes b/.gitattributes index 176a458f..205021e4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -* text=auto +# Enforce Unix newlines +* text=auto eol=lf diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 00000000..d2d76ddb --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,3 @@ +name: "CodeQL config" +paths-ignore: + - "**/vendor/**" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index cbed6a2e..6c9bc410 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -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" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0269d0f0..0923091b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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 diff --git a/gravity.lp b/gravity.lp index c2312acd..aaef944a 100644 --- a/gravity.lp +++ b/gravity.lp @@ -27,5 +27,5 @@ mg.include('scripts/lua/header_authenticated.lp','r') - + diff --git a/groups-clients.lp b/groups-clients.lp index 061bd0a4..5fd1e043 100644 --- a/groups-clients.lp +++ b/groups-clients.lp @@ -95,10 +95,10 @@ mg.include('scripts/lua/header_authenticated.lp','r') - - - - - + + + + + diff --git a/groups-domains.lp b/groups-domains.lp index c1aa01fa..58b64c08 100644 --- a/groups-domains.lp +++ b/groups-domains.lp @@ -156,9 +156,9 @@ mg.include('scripts/lua/header_authenticated.lp','r') - - - - + + + + diff --git a/groups-lists.lp b/groups-lists.lp index 59e5a402..3e94e83b 100644 --- a/groups-lists.lp +++ b/groups-lists.lp @@ -46,7 +46,7 @@ mg.include('scripts/lua/header_authenticated.lp','r') Hints:
  1. Please run pihole -g or update your gravity list online after modifying your lists.
  2. -
  3. Multiple lists can be added by separating each unique URL with a space or comma
  4. +
  5. Multiple lists can be added by separating each unique URL with a space or comma
  6. Click on the icon in the first column to get additional information about your lists. The icons correspond to the health of the list.
- - - - + + + + diff --git a/groups.lp b/groups.lp index 06db01da..dcf4691d 100644 --- a/groups.lp +++ b/groups.lp @@ -79,9 +79,9 @@ mg.include('scripts/lua/header_authenticated.lp','r') - - - - + + + + diff --git a/img/logo-bw.svg b/img/logo-bw.svg new file mode 100644 index 00000000..73600230 --- /dev/null +++ b/img/logo-bw.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/img/pihole_icon.svg b/img/pihole_icon.svg deleted file mode 100644 index 7abd50fa..00000000 --- a/img/pihole_icon.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - diff --git a/index.lp b/index.lp index 36998d83..4d85c23f 100644 --- a/index.lp +++ b/index.lp @@ -22,7 +22,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
- + - active clients @@ -38,7 +38,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
- + List blocked queries @@ -54,7 +54,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
- + List all queries @@ -70,7 +70,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')
- + Manage lists @@ -279,7 +279,7 @@ mg.include('scripts/lua/header_authenticated.lp','r') - - + + diff --git a/interfaces.lp b/interfaces.lp index d3f1a915..2d5f02ec 100644 --- a/interfaces.lp +++ b/interfaces.lp @@ -32,5 +32,5 @@ mg.include('scripts/lua/header_authenticated.lp','r') - + diff --git a/login.lp b/login.lp index f97b837f..450cae74 100644 --- a/login.lp +++ b/login.lp @@ -9,12 +9,12 @@ mg.include('scripts/lua/header.lp','r') ?> - +
@@ -72,7 +72,7 @@ mg.include('scripts/lua/header.lp','r')

Your Pi-hole has two-factor authentication enabled. You have to - enter a valid TOTP + enter a valid TOTP token in addition to your password. You see this message because your token was incorrect or has already expired.

@@ -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

-
sudo pihole setpassword
+
pihole setpassword
@@ -104,9 +104,9 @@ mg.include('scripts/lua/header.lp','r') @@ -117,7 +117,7 @@ mg.include('scripts/lua/header.lp','r') Donate if you found this useful. - - + + diff --git a/messages.lp b/messages.lp index 23968958..9bf440bf 100644 --- a/messages.lp +++ b/messages.lp @@ -41,6 +41,6 @@ mg.include('scripts/lua/header_authenticated.lp','r') - + diff --git a/network.lp b/network.lp index 75545221..c4566a36 100644 --- a/network.lp +++ b/network.lp @@ -64,7 +64,7 @@ mg.include('scripts/lua/header_authenticated.lp','r') - - + + diff --git a/package-lock.json b/package-lock.json index 52e9e4dd..3b80a8d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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": { diff --git a/package.json b/package.json index e779385d..d350770a 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..88658064 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,11 @@ +/* eslint-env node */ + +"use strict"; + +module.exports = (/* ctx */) => ({ + plugins: { + autoprefixer: { + cascade: false, + }, + }, +}); diff --git a/queries.lp b/queries.lp index baeaa1b4..929c20f1 100644 --- a/queries.lp +++ b/queries.lp @@ -154,7 +154,7 @@ mg.include('scripts/lua/header_authenticated.lp','r')

Recent Queries

- Refresh +
@@ -194,9 +194,9 @@ mg.include('scripts/lua/header_authenticated.lp','r') - - - - + + + + diff --git a/scripts/js/charts.js b/scripts/js/charts.js index 83c99270..1fbc8fe7 100644 --- a/scripts/js/charts.js +++ b/scripts/js/charts.js @@ -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; } }); } diff --git a/scripts/js/footer.js b/scripts/js/footer.js index 22b7f2e9..5e6c8460 100644 --- a/scripts/js/footer.js +++ b/scripts/js/footer.js @@ -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(" "); $.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 = $(''); + var boxsheet = $(''); // 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( '  CPU: ' + - 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) ); $("#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( "
  • " + 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:  
    ' diff --git a/scripts/js/gravity.js b/scripts/js/gravity.js index 26573246..44077ff2 100644 --- a/scripts/js/gravity.js +++ b/scripts/js/gravity.js @@ -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); diff --git a/scripts/js/groups-clients.js b/scripts/js/groups-clients.js index 791de55f..adf1a96c 100644 --- a/scripts/js/groups-clients.js +++ b/scripts/js/groups-clients.js @@ -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, diff --git a/scripts/js/groups-common.js b/scripts/js/groups-common.js index e32ef189..73850d6d 100644 --- a/scripts/js/groups-common.js +++ b/scripts/js/groups-common.js @@ -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 = ""; diff --git a/scripts/js/groups-domains.js b/scripts/js/groups-domains.js index 8c8f86e5..2b030bc9 100644 --- a/scripts/js/groups-domains.js +++ b/scripts/js/groups-domains.js @@ -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 = $(""); + var parts = new URL(value).hostname.split("."); + var 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( - $("") - .append($('") + .append($(' " + @@ -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; diff --git a/scripts/js/interfaces.js b/scripts/js/interfaces.js index 7091a967..cd952257 100644 --- a/scripts/js/interfaces.js +++ b/scripts/js/interfaces.js @@ -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 - ? 'UP' - : 'DOWN'; + 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 = `${stateText}`; + + 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 ? "" : " ⤷ "; 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: " + utils.escapeHtml(master.name) + "", - icon: "fa fa-network-wired fa-fw", - }); + if (master !== null) { + obj.nodes.push({ + text: "Master interface: " + utils.escapeHtml(master) + "", + 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 + ? "Connected" + : "Disconnected"), + 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", diff --git a/scripts/js/login.js b/scripts/js/login.js index b30fd5d8..b8ce0aa3 100644 --- a/scripts/js/login.js +++ b/scripts/js/login.js @@ -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(); diff --git a/scripts/js/logout.js b/scripts/js/logout.js index 40f290ff..97658f8e 100644 --- a/scripts/js/logout.js +++ b/scripts/js/logout.js @@ -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); }); }); diff --git a/scripts/js/messages.js b/scripts/js/messages.js index e97f5cfd..56d50a31 100644 --- a/scripts/js/messages.js +++ b/scripts/js/messages.js @@ -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) { diff --git a/scripts/js/network.js b/scripts/js/network.js index a125a7b3..0c0d0dfc 100644 --- a/scripts/js/network.js +++ b/scripts/js/network.js @@ -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('' + iptext + ""); + ips.push('' + iptext + ""); } } @@ -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) + "
    " + utils.escapeHtml(data.macVendor) + utils.escapeHtml(data.hwaddr) + "
    " + 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: { diff --git a/scripts/js/queries.js b/scripts/js/queries.js index 416594d0..bf59e134 100644 --- a/scripts/js/queries.js +++ b/scripts/js/queries.js @@ -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 = $("
    ").html(querystatus.fieldtext).text(); - if (querystatus.icon !== false) { $("td:eq(1)", row).html( "" ); } else if (querystatus.colorClass !== false) { diff --git a/scripts/js/search.js b/scripts/js/search.js index f15c7934..ada949ae 100644 --- a/scripts/js/search.js +++ b/scripts/js/search.js @@ -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 += - " - " + utils.escapeHtml(domain.domain) + @@ -118,7 +118,7 @@ function doSearch() { const list = grouped[listId][0]; const color = list.type === "block" ? "red" : "green"; result += - " - " + utils.escapeHtml(list.address) + diff --git a/scripts/js/settings-advanced.js b/scripts/js/settings-advanced.js index 3d7e4332..e5eb0910 100644 --- a/scripts/js/settings-advanced.js +++ b/scripts/js/settings-advanced.js @@ -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(); diff --git a/scripts/js/settings-api.js b/scripts/js/settings-api.js index 124d135a..212e7963 100644 --- a/scripts/js/settings-api.js +++ b/scripts/js/settings-api.js @@ -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"); diff --git a/scripts/js/settings-dhcp.js b/scripts/js/settings-dhcp.js index 6e467668..a64ffd8a 100644 --- a/scripts/js/settings-dhcp.js +++ b/scripts/js/settings-dhcp.js @@ -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); diff --git a/scripts/js/settings-dns-records.js b/scripts/js/settings-dns-records.js index 93c7d475..c50b1f2f 100644 --- a/scripts/js/settings-dns-records.js +++ b/scripts/js/settings-dns-records.js @@ -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("* TTL in seconds (optional)"); + $("#cnameRecords-Table").after( + "* TTL in seconds (optional)" + ); }); diff --git a/scripts/js/settings-dns.js b/scripts/js/settings-dns.js index 6a2e4680..89cd968e 100644 --- a/scripts/js/settings-dns.js +++ b/scripts/js/settings-dns.js @@ -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 diff --git a/scripts/js/settings-privacy.js b/scripts/js/settings-privacy.js index 5c57e979..897d2399 100644 --- a/scripts/js/settings-privacy.js +++ b/scripts/js/settings-privacy.js @@ -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); diff --git a/scripts/js/settings-system.js b/scripts/js/settings-system.js index 79fafb09..653d12d1 100644 --- a/scripts/js/settings-system.js +++ b/scripts/js/settings-system.js @@ -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; diff --git a/scripts/js/settings-teleporter.js b/scripts/js/settings-teleporter.js index b337fa90..c92fd6a5 100644 --- a/scripts/js/settings-teleporter.js +++ b/scripts/js/settings-teleporter.js @@ -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(); + } +}); diff --git a/scripts/js/settings.js b/scripts/js/settings.js index 444af212..43b55ca6 100644 --- a/scripts/js/settings.js +++ b/scripts/js/settings.js @@ -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, diff --git a/scripts/js/taillog.js b/scripts/js/taillog.js index 01c1e48e..778c50c0 100644 --- a/scripts/js/taillog.js +++ b/scripts/js/taillog.js @@ -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 = `${txt}`; + txt = `${txt}`; } else if (line.includes("query[A") || line.includes("query[DHCP")) { // Bold text for initial query lines - txt = `${txt}`; + txt = `${txt}`; } else { // Grey text for all other lines txt = `${txt}`; @@ -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", }) diff --git a/scripts/js/utils.js b/scripts/js/utils.js index d83cdf2c..146941ab 100644 --- a/scripts/js/utils.js +++ b/scripts/js/utils.js @@ -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)", diff --git a/scripts/lua/footer.lp b/scripts/lua/footer.lp index 6dcb5640..eb14d072 100644 --- a/scripts/lua/footer.lp +++ b/scripts/lua/footer.lp @@ -66,8 +66,8 @@ end
    - + - + diff --git a/scripts/lua/header.lp b/scripts/lua/header.lp index 3b5379c8..6397b9a3 100644 --- a/scripts/lua/header.lp +++ b/scripts/lua/header.lp @@ -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 - - Pi-hole <?=hostname?> - - - - - - - + + + + + + - - - + - - - - - - - + + + + + -"> + + + @@ -105,21 +98,26 @@ if startsWith(scriptname, 'groups') then + - + - + + + + + + - - - - - - - - + + + + + + + diff --git a/scripts/lua/header_authenticated.lp b/scripts/lua/header_authenticated.lp index e14377b0..a6bd53e9 100644 --- a/scripts/lua/header_authenticated.lp +++ b/scripts/lua/header_authenticated.lp @@ -9,20 +9,20 @@ ]]-- mg.include('header.lp','r') ?> - - - - - - - - - - - - + + + + + + + + + + + + - +
    ').text(i === 0 ? "Did you mean" : "or")) - .append($("").append(createButton(hostname))) - ); - } - - suggestDomainEl.slideUp("fast", function () { - suggestDomainEl.html(table); - suggestDomainEl.slideDown("fast"); - }); - } catch { - hideSuggestDomains(); + table.append( + $("
    ').text(i === 0 ? "Did you mean" : "or")) + .append($("").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, diff --git a/scripts/js/groups-lists.js b/scripts/js/groups-lists.js index f66145c6..b5646c06 100644 --- a/scripts/js/groups-lists.js +++ b/scripts/js/groups-lists.js @@ -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, diff --git a/scripts/js/groups.js b/scripts/js/groups.js index d886aee2..dc69c3e6 100644 --- a/scripts/js/groups.js +++ b/scripts/js/groups.js @@ -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, diff --git a/scripts/js/index.js b/scripts/js/index.js index 749bdb31..114984fd 100644 --- a/scripts/js/index.js +++ b/scripts/js/index.js @@ -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 = - '' + utils.escapeHtml(clientname) + ""; @@ -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 = '' + urlText + ""; + url = + '' + + urlText + + ""; percentage = (item.count / sum) * 100; domaintable.append( "