mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 09:36:05 -08:00
Compare commits
21 Commits
d3326b3362
...
next_relea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfd2cf9e20 | ||
|
|
61824abb9f | ||
|
|
33c5548fe1 | ||
|
|
fd41c395ae | ||
|
|
1a980844f0 | ||
|
|
82e018e284 | ||
|
|
e0e1233b1c | ||
|
|
74677f940e | ||
|
|
21a4d20579 | ||
|
|
9634e4e0f7 | ||
|
|
00a47ab5d3 | ||
|
|
59b417705e | ||
|
|
525d082f3d | ||
|
|
ba3481759b | ||
|
|
7125cea29b | ||
|
|
8586c5a307 | ||
|
|
0d81315809 | ||
|
|
8f193f1e2c | ||
|
|
b1eef8aa09 | ||
|
|
2da17f272c | ||
|
|
7bcb4586b2 |
12
.github/workflows/docker_prod.yml
vendored
12
.github/workflows/docker_prod.yml
vendored
@@ -32,6 +32,18 @@ jobs:
|
|||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
# --- Previous approach Get release version from tag
|
||||||
|
- name: Set up dynamic build ARGs
|
||||||
|
id: getargs
|
||||||
|
run: echo "version=$(cat ./stable/VERSION)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Get release version
|
||||||
|
id: get_version_prev
|
||||||
|
run: echo "::set-output name=version::${GITHUB_REF#refs/tags/}"
|
||||||
|
|
||||||
|
- name: Create .VERSION file
|
||||||
|
run: echo "${{ steps.get_version.outputs.version }}" >> .VERSION_PREV
|
||||||
|
|
||||||
# --- Get release version from tag
|
# --- Get release version from tag
|
||||||
- name: Get release version
|
- name: Get release version
|
||||||
id: get_version
|
id: get_version
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,6 +11,7 @@ nohup.out
|
|||||||
config/*
|
config/*
|
||||||
.ash_history
|
.ash_history
|
||||||
.VERSION
|
.VERSION
|
||||||
|
.VERSION_PREV
|
||||||
config/pialert.conf
|
config/pialert.conf
|
||||||
config/app.conf
|
config/app.conf
|
||||||
db/*
|
db/*
|
||||||
|
|||||||
13
Dockerfile
13
Dockerfile
@@ -138,6 +138,7 @@ RUN install -d -o ${NETALERTX_USER} -g ${NETALERTX_GROUP} -m 700 ${READ_WRITE_FO
|
|||||||
|
|
||||||
# Copy version information into the image
|
# Copy version information into the image
|
||||||
COPY --chown=${NETALERTX_USER}:${NETALERTX_GROUP} .[V]ERSION ${NETALERTX_APP}/.VERSION
|
COPY --chown=${NETALERTX_USER}:${NETALERTX_GROUP} .[V]ERSION ${NETALERTX_APP}/.VERSION
|
||||||
|
COPY --chown=${NETALERTX_USER}:${NETALERTX_GROUP} .[V]ERSION ${NETALERTX_APP}/.VERSION_PREV
|
||||||
|
|
||||||
# Copy the virtualenv from the builder stage
|
# Copy the virtualenv from the builder stage
|
||||||
COPY --from=builder --chown=20212:20212 ${VIRTUAL_ENV} ${VIRTUAL_ENV}
|
COPY --from=builder --chown=20212:20212 ${VIRTUAL_ENV} ${VIRTUAL_ENV}
|
||||||
@@ -147,12 +148,12 @@ COPY --from=builder --chown=20212:20212 ${VIRTUAL_ENV} ${VIRTUAL_ENV}
|
|||||||
# This is done after the copy of the venv to ensure the venv is in place
|
# This is done after the copy of the venv to ensure the venv is in place
|
||||||
# although it may be quicker to do it before the copy, it keeps the image
|
# although it may be quicker to do it before the copy, it keeps the image
|
||||||
# layers smaller to do it after.
|
# layers smaller to do it after.
|
||||||
RUN if [ -f '.VERSION' ]; then \
|
RUN for vfile in .VERSION .VERSION_PREV; do \
|
||||||
cp '.VERSION' "${NETALERTX_APP}/.VERSION"; \
|
if [ ! -f "${NETALERTX_APP}/${vfile}" ]; then \
|
||||||
else \
|
echo "DEVELOPMENT 00000000" > "${NETALERTX_APP}/${vfile}"; \
|
||||||
echo "DEVELOPMENT 00000000" > "${NETALERTX_APP}/.VERSION"; \
|
fi; \
|
||||||
fi && \
|
chown 20212:20212 "${NETALERTX_APP}/${vfile}"; \
|
||||||
chown 20212:20212 "${NETALERTX_APP}/.VERSION" && \
|
done && \
|
||||||
apk add --no-cache libcap && \
|
apk add --no-cache libcap && \
|
||||||
setcap cap_net_raw+ep /bin/busybox && \
|
setcap cap_net_raw+ep /bin/busybox && \
|
||||||
setcap cap_net_raw,cap_net_admin+eip /usr/bin/nmap && \
|
setcap cap_net_raw,cap_net_admin+eip /usr/bin/nmap && \
|
||||||
|
|||||||
@@ -34,9 +34,7 @@ Get visibility of what's going on on your WIFI/LAN network and enable presence d
|
|||||||
## 🚀 Quick Start
|
## 🚀 Quick Start
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed.
|
> ⚠️ **Important:** The docker-compose has recently changed. Carefully read the [Migration guide](https://jokob-sk.github.io/NetAlertX/MIGRATION/?h=migrat#12-migration-from-netalertx-v25524) for detailed instructions.
|
||||||
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
|
|
||||||
> These docs reflect the latest development version and may differ from the production image.
|
|
||||||
|
|
||||||
Start NetAlertX in seconds with Docker:
|
Start NetAlertX in seconds with Docker:
|
||||||
|
|
||||||
@@ -44,8 +42,7 @@ Start NetAlertX in seconds with Docker:
|
|||||||
docker run -d \
|
docker run -d \
|
||||||
--network=host \
|
--network=host \
|
||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
-v /local_data_dir/config:/data/config \
|
-v /local_data_dir:/data \
|
||||||
-v /local_data_dir/db:/data/db \
|
|
||||||
-v /etc/localtime:/etc/localtime:ro \
|
-v /etc/localtime:/etc/localtime:ro \
|
||||||
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
|
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
|
||||||
-e PORT=20211 \
|
-e PORT=20211 \
|
||||||
@@ -53,6 +50,8 @@ docker run -d \
|
|||||||
ghcr.io/jokob-sk/netalertx:latest
|
ghcr.io/jokob-sk/netalertx:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: Your `/local_data_dir` should contain a `config` and `db` folder.
|
||||||
|
|
||||||
To deploy a containerized instance directly from the source repository, execute the following BASH sequence:
|
To deploy a containerized instance directly from the source repository, execute the following BASH sequence:
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/jokob-sk/NetAlertX.git
|
git clone https://github.com/jokob-sk/NetAlertX.git
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ Start the container via the **terminal** with a command similar to this one:
|
|||||||
docker run \
|
docker run \
|
||||||
--network=host \
|
--network=host \
|
||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
-v /local_data_dir/config:/data/config \
|
-v /local_data_dir:/data \
|
||||||
-v /local_data_dir/db:/data/db \
|
|
||||||
-v /etc/localtime:/etc/localtime:ro \
|
-v /etc/localtime:/etc/localtime:ro \
|
||||||
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
|
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
|
||||||
-e PORT=20211 \
|
-e PORT=20211 \
|
||||||
@@ -26,6 +25,8 @@ docker run \
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: Your `/local_data_dir` should contain a `config` and `db` folder.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> ⚠ The most important part is NOT to use the `-d` parameter so you see the error when the container crashes. Use this error in your issue description.
|
> ⚠ The most important part is NOT to use the `-d` parameter so you see the error when the container crashes. Use this error in your issue description.
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# NetAlertX and Docker Compose
|
# NetAlertX and Docker Compose
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed.
|
> ⚠️ **Important:** The docker-compose has recently changed. Carefully read the [Migration guide](https://jokob-sk.github.io/NetAlertX/MIGRATION/?h=migrat#12-migration-from-netalertx-v25524) for detailed instructions.
|
||||||
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
|
|
||||||
> These docs reflect the latest development version and may differ from the production image.
|
|
||||||
|
|
||||||
Great care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system.Good care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system.
|
Great care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system.Good care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system.
|
||||||
|
|
||||||
@@ -125,9 +123,9 @@ docker compose up
|
|||||||
|
|
||||||
### Modification 1: Use a Local Folder (Bind Mount)
|
### Modification 1: Use a Local Folder (Bind Mount)
|
||||||
|
|
||||||
By default, the baseline compose file uses a single named volume (netalertx_data) mounted at /data. This single-volume layout is preferred because NetAlertX manages both configuration and the database under /data (for example, /data/config and /data/db) via its web UI. Using one named volume simplifies permissions and portability: Docker manages the storage and NetAlertX manages the files inside /data.
|
By default, the baseline compose file uses a single named volume (netalertx_data) mounted at `/data`. This single-volume layout is preferred because NetAlertX manages both configuration and the database under `/data` (for example, `/data/config` and `/data/db`) via its web UI. Using one named volume simplifies permissions and portability: Docker manages the storage and NetAlertX manages the files inside `/data`.
|
||||||
|
|
||||||
A two-volume layout that mounts /data/config and /data/db separately (for example, netalertx_config and netalertx_db) is supported for backward compatibility and some advanced workflows, but it is an abnormal/legacy layout and not recommended for new deployments.
|
A two-volume layout that mounts `/data/config` and `/data/db` separately (for example, `netalertx_config` and `netalertx_db`) is supported for backward compatibility and some advanced workflows, but it is an abnormal/legacy layout and not recommended for new deployments.
|
||||||
|
|
||||||
However, if you prefer to have direct, file-level access to your configuration for manual editing, a "bind mount" is a simple alternative. This tells Docker to use a specific folder from your computer (the "host") inside the container.
|
However, if you prefer to have direct, file-level access to your configuration for manual editing, a "bind mount" is a simple alternative. This tells Docker to use a specific folder from your computer (the "host") inside the container.
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ Head to [https://netalertx.com/](https://netalertx.com/) for more gifs and scree
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -d --rm --network=host \
|
docker run -d --rm --network=host \
|
||||||
-v /local_data_dir/config:/data/config \
|
-v /local_data_dir:/data \
|
||||||
-v /local_data_dir/db:/data/db \
|
|
||||||
-v /etc/localtime:/etc/localtime \
|
-v /etc/localtime:/etc/localtime \
|
||||||
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
|
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
|
||||||
-e PORT=20211 \
|
-e PORT=20211 \
|
||||||
@@ -62,8 +61,7 @@ See alternative [docked-compose examples](https://github.com/jokob-sk/NetAlertX/
|
|||||||
|
|
||||||
| Required | Path | Description |
|
| Required | Path | Description |
|
||||||
| :------------- | :------------- | :-------------|
|
| :------------- | :------------- | :-------------|
|
||||||
| ✅ | `:/data/config` | Folder which will contain the `app.conf` & `devices.csv` ([read about devices.csv](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md)) files |
|
| ✅ | `:/data` | Folder which will contain the `/db/app.db`, `/config/app.conf` & `/config/devices.csv` ([read about devices.csv](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md)) files |
|
||||||
| ✅ | `:/data/db` | Folder which will contain the `app.db` database file |
|
|
||||||
| ✅ | `/etc/localtime:/etc/localtime:ro` | Ensuring the timezone is teh same as on teh server. |
|
| ✅ | `/etc/localtime:/etc/localtime:ro` | Ensuring the timezone is teh same as on teh server. |
|
||||||
| | `:/tmp/log` | Logs folder useful for debugging if you have issues setting up the container |
|
| | `:/tmp/log` | Logs folder useful for debugging if you have issues setting up the container |
|
||||||
| | `:/tmp/api` | The [API endpoint](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md) containing static (but regularly updated) json and other files. Path configurable via `NETALERTX_API` environment variable. |
|
| | `:/tmp/api` | The [API endpoint](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md) containing static (but regularly updated) json and other files. Path configurable via `NETALERTX_API` environment variable. |
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
# The NetAlertX Container Operator's Guide
|
# The NetAlertX Container Operator's Guide
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed.
|
> ⚠️ **Important:** The docker-compose has recently changed. Carefully read the [Migration guide](https://jokob-sk.github.io/NetAlertX/MIGRATION/?h=migrat#12-migration-from-netalertx-v25524) for detailed instructions.
|
||||||
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
|
|
||||||
> These docs reflect the latest development version and may differ from the production image.
|
|
||||||
|
|
||||||
This guide assumes you are starting with the official `docker-compose.yml` file provided with the project. We strongly recommend you start with or migrate to this file as your baseline and modify it to suit your specific needs (e.g., changing file paths). While there are many ways to configure NetAlertX, the default file is designed to meet the mandatory security baseline with layer-2 networking capabilities while operating securely and without startup warnings.
|
This guide assumes you are starting with the official `docker-compose.yml` file provided with the project. We strongly recommend you start with or migrate to this file as your baseline and modify it to suit your specific needs (e.g., changing file paths). While there are many ways to configure NetAlertX, the default file is designed to meet the mandatory security baseline with layer-2 networking capabilities while operating securely and without startup warnings.
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ In the **Environment variables** section of Portainer, add the following:
|
|||||||
>
|
>
|
||||||
> `sudo chown -R 20211:20211 /local_data_dir`
|
> `sudo chown -R 20211:20211 /local_data_dir`
|
||||||
>
|
>
|
||||||
> `sudo chmod -R a+rwx /local_data_dir1`
|
> `sudo chmod -R a+rwx /local_data_dir`
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ NetAlertX requires certain paths to be writable at runtime. These paths should b
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -it --rm --name netalertx --user "0" \
|
docker run -it --rm --name netalertx --user "0" \
|
||||||
-v /local_data_dir/config:/data/config \
|
-v /local_data_dir:/data \
|
||||||
-v /local_data_dir/db:/data/db \
|
|
||||||
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
|
--tmpfs /tmp:uid=20211,gid=20211,mode=1700 \
|
||||||
ghcr.io/jokob-sk/netalertx:latest
|
ghcr.io/jokob-sk/netalertx:latest
|
||||||
```
|
```
|
||||||
@@ -63,7 +62,7 @@ docker run -it --rm --name netalertx --user "0" \
|
|||||||
>
|
>
|
||||||
> `sudo chown -R 20211:20211 /local_data_dir`
|
> `sudo chown -R 20211:20211 /local_data_dir`
|
||||||
>
|
>
|
||||||
> `sudo chmod -R a+rwx /local_data_dir1`
|
> `sudo chmod -R a+rwx /local_data_dir`
|
||||||
>
|
>
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -84,8 +83,7 @@ services:
|
|||||||
- NET_BIND_SERVICE # Required to bind to privileged ports (nbtscan)
|
- NET_BIND_SERVICE # Required to bind to privileged ports (nbtscan)
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- /local_data_dir/config:/data/config
|
- /local_data_dir:/data
|
||||||
- /local_data_dir/db:/data/db
|
|
||||||
- /etc/localtime:/etc/localtime
|
- /etc/localtime:/etc/localtime
|
||||||
environment:
|
environment:
|
||||||
- PORT=20211
|
- PORT=20211
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
# Migration
|
# Migration
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed.
|
|
||||||
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
|
|
||||||
> These docs reflect the latest development version and may differ from the production image.
|
|
||||||
|
|
||||||
|
|
||||||
When upgrading from older versions of NetAlertX (or PiAlert by jokob-sk), follow the migration steps below to ensure your data and configuration are properly transferred.
|
When upgrading from older versions of NetAlertX (or PiAlert by jokob-sk), follow the migration steps below to ensure your data and configuration are properly transferred.
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
@@ -259,12 +253,11 @@ docker run -it --rm --name netalertx --user "0" \
|
|||||||
ghcr.io/jokob-sk/netalertx:latest
|
ghcr.io/jokob-sk/netalertx:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
..or alternatively execute:
|
...or alternatively execute:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo chown -R 20211:20211 /local_data_dir/config
|
sudo chown -R 20211:20211 /local_data_dir
|
||||||
sudo chown -R 20211:20211 /local_data_dir/db
|
sudo chmod -R a+rwx /local_data_dir
|
||||||
sudo chmod -R a+rwx /local_data_dir/
|
|
||||||
```
|
```
|
||||||
|
|
||||||
7. Stop the container
|
7. Stop the container
|
||||||
@@ -284,8 +277,7 @@ services:
|
|||||||
- NET_BIND_SERVICE # 🆕 New line
|
- NET_BIND_SERVICE # 🆕 New line
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- /local_data_dir/config:/data/config # 🆕 This has changed from /app to /data
|
- /local_data_dir:/data # 🆕 This folder contains your /db and /config directories and the parent changed from /app to /data
|
||||||
- /local_data_dir/db:/data/db # 🆕 This has changed from /app to /data
|
|
||||||
# Ensuring the timezone is the same as on the server - make sure also the TIMEZONE setting is configured
|
# Ensuring the timezone is the same as on the server - make sure also the TIMEZONE setting is configured
|
||||||
- /etc/localtime:/etc/localtime:ro # 🆕 New line
|
- /etc/localtime:/etc/localtime:ro # 🆕 New line
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ There is also an in-app Help / FAQ section that should be answering frequently a
|
|||||||
|
|
||||||
#### ♻ Misc
|
#### ♻ Misc
|
||||||
|
|
||||||
- [Version history (legacy)](./VERSIONS_HISTORY.md)
|
|
||||||
- [Reverse proxy (Nginx, Apache, SWAG)](./REVERSE_PROXY.md)
|
- [Reverse proxy (Nginx, Apache, SWAG)](./REVERSE_PROXY.md)
|
||||||
- [Installing Updates](./UPDATES.md)
|
- [Installing Updates](./UPDATES.md)
|
||||||
- [Setting up Authelia](./AUTHELIA.md) (DRAFT)
|
- [Setting up Authelia](./AUTHELIA.md) (DRAFT)
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ services:
|
|||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
- NET_BIND_SERVICE
|
- NET_BIND_SERVICE
|
||||||
volumes:
|
volumes:
|
||||||
- /app_storage/netalertx/config:/data/config
|
- /app_storage/netalertx:/data
|
||||||
- /app_storage/netalertx/db:/data/db
|
|
||||||
# to sync with system time
|
# to sync with system time
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
tmpfs:
|
tmpfs:
|
||||||
@@ -66,10 +65,7 @@ services:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
volumes:
|
volumes:
|
||||||
- /volume1/app_storage/netalertx/config:/data/config
|
- /volume1/app_storage/netalertx:/data
|
||||||
- /volume1/app_storage/netalertx/db:/data/db
|
|
||||||
# (optional) useful for debugging if you have issues setting up the container
|
|
||||||
# - local/path/logs:/tmp/log <- commented out with # ⚠
|
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
@@ -88,5 +84,5 @@ services:
|
|||||||
>
|
>
|
||||||
> `sudo chown -R 20211:20211 /local_data_dir`
|
> `sudo chown -R 20211:20211 /local_data_dir`
|
||||||
>
|
>
|
||||||
> `sudo chmod -R a+rwx /local_data_dir1`
|
> `sudo chmod -R a+rwx /local_data_dir`
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ a[target="_blank"] {
|
|||||||
|
|
||||||
[data-is-valid="0"] {
|
[data-is-valid="0"] {
|
||||||
/* border: 1px solid red; */
|
/* border: 1px solid red; */
|
||||||
background-color: #ff4b4b;
|
background-color: #ff4b4b !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -136,7 +136,7 @@
|
|||||||
<!-- page script ----------------------------------------------------------- -->
|
<!-- page script ----------------------------------------------------------- -->
|
||||||
<script>
|
<script>
|
||||||
var deviceStatus = 'all';
|
var deviceStatus = 'all';
|
||||||
var tableRows = getCache ("nax_parTableRows") == "" ? parseInt(getSetting("UI_DEFAULT_PAGE_SIZE")) : getCache ("nax_parTableRows") ;
|
|
||||||
var tableOrder = getCache ("nax_parTableOrder") == "" ? [[3,'desc'], [0,'asc']] : JSON.parse(getCache ("nax_parTableOrder")) ;
|
var tableOrder = getCache ("nax_parTableOrder") == "" ? [[3,'desc'], [0,'asc']] : JSON.parse(getCache ("nax_parTableOrder")) ;
|
||||||
|
|
||||||
var tableColumnHide = [];
|
var tableColumnHide = [];
|
||||||
@@ -563,6 +563,9 @@ function initializeDatatable (status) {
|
|||||||
status = 'my_devices'
|
status = 'my_devices'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// retrieve page size
|
||||||
|
var tableRows = getCache ("nax_parTableRows") == "" ? parseInt(getSetting("UI_DEFAULT_PAGE_SIZE")) : getCache ("nax_parTableRows") ;
|
||||||
|
|
||||||
// Save status selected
|
// Save status selected
|
||||||
deviceStatus = status;
|
deviceStatus = status;
|
||||||
|
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ function localizeTimestamp(input) {
|
|||||||
let tz = getSetting("TIMEZONE") || 'Europe/Berlin';
|
let tz = getSetting("TIMEZONE") || 'Europe/Berlin';
|
||||||
input = String(input || '').trim();
|
input = String(input || '').trim();
|
||||||
|
|
||||||
// ✅ 1. Unix timestamps (10 or 13 digits)
|
// 1. Unix timestamps (10 or 13 digits)
|
||||||
if (/^\d+$/.test(input)) {
|
if (/^\d+$/.test(input)) {
|
||||||
const ms = input.length === 10 ? parseInt(input, 10) * 1000 : parseInt(input, 10);
|
const ms = input.length === 10 ? parseInt(input, 10) * 1000 : parseInt(input, 10);
|
||||||
return new Intl.DateTimeFormat('default', {
|
return new Intl.DateTimeFormat('default', {
|
||||||
@@ -389,39 +389,53 @@ function localizeTimestamp(input) {
|
|||||||
}).format(new Date(ms));
|
}).format(new Date(ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ 2. European DD/MM/YYYY
|
// 2. European DD/MM/YYYY
|
||||||
let match = input.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})(?:[ ,]+(\d{1,2}:\d{2}(?::\d{2})?))?(.*)$/);
|
let match = input.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})(?:[ ,]+(\d{1,2}:\d{2}(?::\d{2})?))?(.*)$/);
|
||||||
if (match) {
|
if (match) {
|
||||||
let [ , d, m, y, t = "00:00:00", tzPart = "" ] = match;
|
let [, d, m, y, t = "00:00:00", tzPart = ""] = match;
|
||||||
const iso = `${y}-${m.padStart(2,'0')}-${d.padStart(2,'0')}T${t.length===5?t+":00":t}${tzPart}`;
|
const iso = `${y}-${m.padStart(2,'0')}-${d.padStart(2,'0')}T${t.length===5?t+":00":t}${tzPart}`;
|
||||||
return formatSafe(iso, tz);
|
return formatSafe(iso, tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ 3. US MM/DD/YYYY
|
// 3. US MM/DD/YYYY
|
||||||
match = input.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})(?:[ ,]+(\d{1,2}:\d{2}(?::\d{2})?))?(.*)$/);
|
match = input.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})(?:[ ,]+(\d{1,2}:\d{2}(?::\d{2})?))?(.*)$/);
|
||||||
if (match) {
|
if (match) {
|
||||||
let [ , m, d, y, t = "00:00:00", tzPart = "" ] = match;
|
let [, m, d, y, t = "00:00:00", tzPart = ""] = match;
|
||||||
const iso = `${y}-${m.padStart(2,'0')}-${d.padStart(2,'0')}T${t.length===5?t+":00":t}${tzPart}`;
|
const iso = `${y}-${m.padStart(2,'0')}-${d.padStart(2,'0')}T${t.length===5?t+":00":t}${tzPart}`;
|
||||||
return formatSafe(iso, tz);
|
return formatSafe(iso, tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ 4. ISO-style (with T, Z, offsets)
|
// 4. ISO YYYY-MM-DD with optional Z/+offset
|
||||||
match = input.match(/^(\d{4}-\d{1,2}-\d{1,2})[ T](\d{1,2}:\d{2}(?::\d{2})?)(Z|[+-]\d{2}:?\d{2})?$/);
|
match = input.match(/^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])[ T](\d{1,2}:\d{2}(?::\d{2})?)(Z|[+-]\d{2}:?\d{2})?$/);
|
||||||
if (match) {
|
if (match) {
|
||||||
let [ , ymd, time, offset = "" ] = match;
|
let [, y, m, d, time, offset = ""] = match;
|
||||||
// normalize to YYYY-MM-DD
|
|
||||||
let [y, m, d] = ymd.split('-').map(x => x.padStart(2,'0'));
|
|
||||||
const iso = `${y}-${m}-${d}T${time.length===5?time+":00":time}${offset}`;
|
const iso = `${y}-${m}-${d}T${time.length===5?time+":00":time}${offset}`;
|
||||||
return formatSafe(iso, tz);
|
return formatSafe(iso, tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ 5. RFC2822 / "25 Aug 2025 13:45:22 +0200"
|
// 5. RFC2822 / "25 Aug 2025 13:45:22 +0200"
|
||||||
match = input.match(/^\d{1,2} [A-Za-z]{3,} \d{4}/);
|
match = input.match(/^\d{1,2} [A-Za-z]{3,} \d{4}/);
|
||||||
if (match) {
|
if (match) {
|
||||||
return formatSafe(input, tz);
|
return formatSafe(input, tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ 6. Fallback (whatever Date() can parse)
|
// 6. DD-MM-YYYY with optional time
|
||||||
|
match = input.match(/^(\d{1,2})-(\d{1,2})-(\d{4})(?:[ T](\d{1,2}:\d{2}(?::\d{2})?))?$/);
|
||||||
|
if (match) {
|
||||||
|
let [, d, m, y, time = "00:00:00"] = match;
|
||||||
|
const iso = `${y}-${m.padStart(2,'0')}-${d.padStart(2,'0')}T${time.length===5?time+":00":time}`;
|
||||||
|
return formatSafe(iso, tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Strict YYYY-DD-MM with optional time
|
||||||
|
match = input.match(/^(\d{4})-(0[1-9]|[12]\d|3[01])-(0[1-9]|1[0-2])(?:[ T](\d{1,2}:\d{2}(?::\d{2})?))?$/);
|
||||||
|
if (match) {
|
||||||
|
let [, y, d, m, time = "00:00:00"] = match;
|
||||||
|
const iso = `${y}-${m}-${d}T${time.length === 5 ? time + ":00" : time}`;
|
||||||
|
return formatSafe(iso, tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. Fallback
|
||||||
return formatSafe(input, tz);
|
return formatSafe(input, tz);
|
||||||
|
|
||||||
function formatSafe(str, tz) {
|
function formatSafe(str, tz) {
|
||||||
@@ -440,6 +454,7 @@ function localizeTimestamp(input) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* Replaces double quotes within single-quoted strings, then converts all single quotes to double quotes,
|
* Replaces double quotes within single-quoted strings, then converts all single quotes to double quotes,
|
||||||
@@ -1622,7 +1637,6 @@ async function executeOnce() {
|
|||||||
|
|
||||||
if (!isAppInitialized()) {
|
if (!isAppInitialized()) {
|
||||||
try {
|
try {
|
||||||
console.log("HERE");
|
|
||||||
|
|
||||||
await waitForGraphQLServer(); // Wait for the server to start
|
await waitForGraphQLServer(); // Wait for the server to start
|
||||||
|
|
||||||
@@ -1630,7 +1644,7 @@ async function executeOnce() {
|
|||||||
await cacheSettings();
|
await cacheSettings();
|
||||||
await cacheStrings();
|
await cacheStrings();
|
||||||
|
|
||||||
console.log("✅ All AJAX callbacks have completed");
|
console.log("All AJAX callbacks have completed");
|
||||||
onAllCallsComplete();
|
onAllCallsComplete();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
|
|||||||
@@ -521,12 +521,16 @@ function getChildren(node, list, path, visited = [])
|
|||||||
|
|
||||||
// Loop through all items to find children of the current node
|
// Loop through all items to find children of the current node
|
||||||
for (var i in list) {
|
for (var i in list) {
|
||||||
if (list[i].devParentMAC.toLowerCase() == node.devMac.toLowerCase() && !hiddenMacs.includes(list[i].devParentMAC)) {
|
const item = list[i];
|
||||||
|
const parentMac = item.devParentMAC || ""; // null-safe
|
||||||
|
const nodeMac = node.devMac || ""; // null-safe
|
||||||
|
|
||||||
|
if (parentMac != "" && parentMac.toLowerCase() == nodeMac.toLowerCase() && !hiddenMacs.includes(parentMac)) {
|
||||||
|
|
||||||
visibleNodesCount++;
|
visibleNodesCount++;
|
||||||
|
|
||||||
// Process children recursively, passing a copy of the visited list
|
// Process children recursively, passing a copy of the visited list
|
||||||
children.push(getChildren(list[i], list, path + ((path == "") ? "" : '|') + list[i].devParentMAC, visited));
|
children.push(getChildren(list[i], list, path + ((path == "") ? "" : '|') + parentMac, visited));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,14 +569,27 @@ function getChildren(node, list, path, visited = [])
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
function getHierarchy()
|
function getHierarchy()
|
||||||
{
|
{
|
||||||
|
let internetNode = null;
|
||||||
|
|
||||||
for(i in deviceListGlobal)
|
for(i in deviceListGlobal)
|
||||||
{
|
{
|
||||||
if(deviceListGlobal[i].devMac == 'Internet')
|
if(deviceListGlobal[i].devMac == 'Internet')
|
||||||
{
|
{
|
||||||
return (getChildren(deviceListGlobal[i], deviceListGlobal, ''))
|
internetNode = deviceListGlobal[i];
|
||||||
|
|
||||||
|
return (getChildren(internetNode, deviceListGlobal, ''))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!internetNode) {
|
||||||
|
showModalOk(
|
||||||
|
getString('Network_Configuration_Error'),
|
||||||
|
getString('Network_Root_Not_Configured')
|
||||||
|
);
|
||||||
|
console.error("getHierarchy(): Internet node not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@@ -671,8 +688,6 @@ function handleNodeClick(el)
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
var myTree;
|
var myTree;
|
||||||
|
|
||||||
|
|
||||||
var emSize;
|
var emSize;
|
||||||
var nodeHeight;
|
var nodeHeight;
|
||||||
// var sizeCoefficient = 1.4
|
// var sizeCoefficient = 1.4
|
||||||
@@ -689,10 +704,12 @@ function emToPx(em, element) {
|
|||||||
|
|
||||||
function initTree(myHierarchy)
|
function initTree(myHierarchy)
|
||||||
{
|
{
|
||||||
// calculate the drawing area based on teh tree width and available screen size
|
if(myHierarchy && myHierarchy.type !== "")
|
||||||
|
{
|
||||||
|
// calculate the drawing area based on the tree width and available screen size
|
||||||
let baseFontSize = parseFloat($('html').css('font-size'));
|
let baseFontSize = parseFloat($('html').css('font-size'));
|
||||||
let treeAreaHeight = ($(window).height() - 155); ;
|
let treeAreaHeight = ($(window).height() - 155); ;
|
||||||
|
|
||||||
// calculate the font size of the leaf nodes to fit everything into the tree area
|
// calculate the font size of the leaf nodes to fit everything into the tree area
|
||||||
leafNodesCount == 0 ? 1 : leafNodesCount;
|
leafNodesCount == 0 ? 1 : leafNodesCount;
|
||||||
|
|
||||||
@@ -703,13 +720,6 @@ function initTree(myHierarchy)
|
|||||||
// init the drawing area size
|
// init the drawing area size
|
||||||
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${emToPx(screenWidthEm)}px`)
|
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${emToPx(screenWidthEm)}px`)
|
||||||
|
|
||||||
if(myHierarchy.type == "")
|
|
||||||
{
|
|
||||||
showModalOk(getString('Network_Configuration_Error'), getString('Network_Root_Not_Configured'))
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle canvas and node size if only a few nodes
|
// handle canvas and node size if only a few nodes
|
||||||
emSize > 1 ? emSize = 1 : emSize = emSize;
|
emSize > 1 ? emSize = 1 : emSize = emSize;
|
||||||
|
|
||||||
@@ -823,6 +833,10 @@ function initTree(myHierarchy)
|
|||||||
|
|
||||||
// hide spinning icon
|
// hide spinning icon
|
||||||
hideSpinner()
|
hideSpinner()
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
console.error("getHierarchy() not returning expected result");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ function saveSettings()
|
|||||||
|
|
||||||
// save to the file
|
// save to the file
|
||||||
$new_name = $config_file.'_'.$timestamp.'.backup';
|
$new_name = $config_file.'_'.$timestamp.'.backup';
|
||||||
$new_location = $configFolderPath.$new_name;
|
$new_location = $configFolderPath.'/'.$new_name;
|
||||||
|
|
||||||
if(file_exists( $fullConfPath) != 1)
|
if(file_exists( $fullConfPath) != 1)
|
||||||
{
|
{
|
||||||
|
|||||||
2
front/php/templates/language/it_it.json
Executable file → Normal file
2
front/php/templates/language/it_it.json
Executable file → Normal file
@@ -311,7 +311,7 @@
|
|||||||
"Gen_Filter": "Filtro",
|
"Gen_Filter": "Filtro",
|
||||||
"Gen_Generate": "Genera",
|
"Gen_Generate": "Genera",
|
||||||
"Gen_InvalidMac": "Indirizzo Mac non valido.",
|
"Gen_InvalidMac": "Indirizzo Mac non valido.",
|
||||||
"Gen_Invalid_Value": "",
|
"Gen_Invalid_Value": "È stato inserito un valore non valido",
|
||||||
"Gen_LockedDB": "ERRORE: il DB potrebbe essere bloccato, controlla F12 Strumenti di sviluppo -> Console o riprova più tardi.",
|
"Gen_LockedDB": "ERRORE: il DB potrebbe essere bloccato, controlla F12 Strumenti di sviluppo -> Console o riprova più tardi.",
|
||||||
"Gen_NetworkMask": "Maschera di rete",
|
"Gen_NetworkMask": "Maschera di rete",
|
||||||
"Gen_Offline": "Offline",
|
"Gen_Offline": "Offline",
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import hashlib
|
|
||||||
import re
|
import re
|
||||||
import nmap
|
import nmap
|
||||||
|
|
||||||
@@ -17,6 +16,7 @@ from plugin_helper import Plugin_Objects # noqa: E402 [flake8 lint suppression]
|
|||||||
from logger import mylog, Logger # noqa: E402 [flake8 lint suppression]
|
from logger import mylog, Logger # noqa: E402 [flake8 lint suppression]
|
||||||
from helper import get_setting_value # noqa: E402 [flake8 lint suppression]
|
from helper import get_setting_value # noqa: E402 [flake8 lint suppression]
|
||||||
from const import logPath # noqa: E402 [flake8 lint suppression]
|
from const import logPath # noqa: E402 [flake8 lint suppression]
|
||||||
|
from utils.crypto_utils import string_to_mac_hash # noqa: E402 [flake8 lint suppression]
|
||||||
import conf # noqa: E402 [flake8 lint suppression]
|
import conf # noqa: E402 [flake8 lint suppression]
|
||||||
from pytz import timezone # noqa: E402 [flake8 lint suppression]
|
from pytz import timezone # noqa: E402 [flake8 lint suppression]
|
||||||
|
|
||||||
@@ -177,16 +177,6 @@ def parse_nmap_xml(xml_output, interface, fakeMac):
|
|||||||
return devices_list
|
return devices_list
|
||||||
|
|
||||||
|
|
||||||
def string_to_mac_hash(input_string):
|
|
||||||
# Calculate a hash using SHA-256
|
|
||||||
sha256_hash = hashlib.sha256(input_string.encode()).hexdigest()
|
|
||||||
|
|
||||||
# Take the first 12 characters of the hash and format as a MAC address
|
|
||||||
mac_hash = ':'.join(sha256_hash[i:i + 2] for i in range(0, 12, 2))
|
|
||||||
|
|
||||||
return mac_hash
|
|
||||||
|
|
||||||
|
|
||||||
# ===============================================================================
|
# ===============================================================================
|
||||||
# BEGIN
|
# BEGIN
|
||||||
# ===============================================================================
|
# ===============================================================================
|
||||||
|
|||||||
@@ -13,9 +13,6 @@ The plugin connects to your Pi-hole’s API and retrieves:
|
|||||||
|
|
||||||
NetAlertX then uses this information to match or create devices in your system.
|
NetAlertX then uses this information to match or create devices in your system.
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> Some tip.
|
|
||||||
|
|
||||||
### Quick setup guide
|
### Quick setup guide
|
||||||
|
|
||||||
* You are running **Pi-hole v6** or newer.
|
* You are running **Pi-hole v6** or newer.
|
||||||
@@ -35,16 +32,8 @@ No additional Pi-hole configuration is required.
|
|||||||
| **PIHOLEAPI_SSL_VERIFY** | Whether to verify HTTPS certificates. Disable only for self-signed certificates. |
|
| **PIHOLEAPI_SSL_VERIFY** | Whether to verify HTTPS certificates. Disable only for self-signed certificates. |
|
||||||
| **PIHOLEAPI_RUN_TIMEOUT** | Request timeout in seconds. |
|
| **PIHOLEAPI_RUN_TIMEOUT** | Request timeout in seconds. |
|
||||||
| **PIHOLEAPI_API_MAXCLIENTS** | Maximum number of devices to request from Pi-hole. Defaults are usually fine. |
|
| **PIHOLEAPI_API_MAXCLIENTS** | Maximum number of devices to request from Pi-hole. Defaults are usually fine. |
|
||||||
|
| **PIHOLEAPI_FAKE_MAC** | Generate FAKE MAC from IP. |
|
||||||
|
|
||||||
### Example Configuration
|
|
||||||
|
|
||||||
| Setting Key | Sample Value |
|
|
||||||
| ---------------------------- | -------------------------------------------------- |
|
|
||||||
| **PIHOLEAPI_URL** | `http://pi.hole/` |
|
|
||||||
| **PIHOLEAPI_PASSWORD** | `passw0rd` |
|
|
||||||
| **PIHOLEAPI_SSL_VERIFY** | `true` |
|
|
||||||
| **PIHOLEAPI_RUN_TIMEOUT** | `30` |
|
|
||||||
| **PIHOLEAPI_API_MAXCLIENTS** | `500` |
|
|
||||||
|
|
||||||
### ⚠️ Troubleshooting
|
### ⚠️ Troubleshooting
|
||||||
|
|
||||||
@@ -110,6 +99,32 @@ Then re-run the plugin.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### ❌ Some devices are missing
|
||||||
|
|
||||||
|
Check:
|
||||||
|
|
||||||
|
* Pi-hole shows devices under **Settings → Network**
|
||||||
|
* NetAlertX logs contain:
|
||||||
|
|
||||||
|
```
|
||||||
|
[PIHOLEAPI] Skipping invalid MAC (see PIHOLEAPI_FAKE_MAC setting) ...
|
||||||
|
```
|
||||||
|
|
||||||
|
If devices are missing:
|
||||||
|
|
||||||
|
* The app skipps devices with invalid MACs
|
||||||
|
* Enable PIHOLEAPI_FAKE_MAC if you want to import these devices with a fake mac and you are not concerned with data inconsistencies later on
|
||||||
|
|
||||||
|
Try enabling PIHOLEAPI_FAKE_MAC:
|
||||||
|
|
||||||
|
```
|
||||||
|
PIHOLEAPI_FAKE_MAC = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Then re-run the plugin.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
#### ❌ Wrong or missing hostnames
|
#### ❌ Wrong or missing hostnames
|
||||||
|
|
||||||
Pi-hole only reports names it knows from:
|
Pi-hole only reports names it knows from:
|
||||||
|
|||||||
@@ -279,6 +279,41 @@
|
|||||||
"string": "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted."
|
"string": "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"function": "FAKE_MAC",
|
||||||
|
"type": {
|
||||||
|
"dataType": "boolean",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"elementType": "input",
|
||||||
|
"elementOptions": [
|
||||||
|
{
|
||||||
|
"type": "checkbox"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"transformers": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default_value": false,
|
||||||
|
"options": [],
|
||||||
|
"localized": [
|
||||||
|
"name",
|
||||||
|
"description"
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Fake MAC if empty"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": [
|
||||||
|
{
|
||||||
|
"language_code": "en_us",
|
||||||
|
"string": "Some PiHole devices don't have a MAC assigned. Enabling the FAKE_MAC setting generates a fake MAC address from the IP address to track devices, but it may cause inconsistencies if IPs change or devices are re-discovered with a different MAC. Static IPs are recommended. Device type and icon might not be detected correctly and some plugins might fail if they depend on a valid MAC address. When unchecked, devices with empty MAC addresses are skipped."
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"database_column_definitions": [
|
"database_column_definitions": [
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from helper import get_setting_value # noqa: E402 [flake8 lint suppression]
|
|||||||
from const import logPath # noqa: E402 [flake8 lint suppression]
|
from const import logPath # noqa: E402 [flake8 lint suppression]
|
||||||
import conf # noqa: E402 [flake8 lint suppression]
|
import conf # noqa: E402 [flake8 lint suppression]
|
||||||
from pytz import timezone # noqa: E402 [flake8 lint suppression]
|
from pytz import timezone # noqa: E402 [flake8 lint suppression]
|
||||||
|
from utils.crypto_utils import string_to_mac_hash # noqa: E402 [flake8 lint suppression]
|
||||||
|
|
||||||
# Setup timezone & logger using standard NAX helpers
|
# Setup timezone & logger using standard NAX helpers
|
||||||
conf.tz = timezone(get_setting_value('TIMEZONE'))
|
conf.tz = timezone(get_setting_value('TIMEZONE'))
|
||||||
@@ -42,6 +43,7 @@ PIHOLEAPI_SES_CSRF = None
|
|||||||
PIHOLEAPI_API_MAXCLIENTS = None
|
PIHOLEAPI_API_MAXCLIENTS = None
|
||||||
PIHOLEAPI_VERIFY_SSL = True
|
PIHOLEAPI_VERIFY_SSL = True
|
||||||
PIHOLEAPI_RUN_TIMEOUT = 10
|
PIHOLEAPI_RUN_TIMEOUT = 10
|
||||||
|
PIHOLEAPI_FAKE_MAC = get_setting_value('PIHOLEAPI_FAKE_MAC')
|
||||||
VERSION_DATE = "NAX-PIHOLEAPI-1.0"
|
VERSION_DATE = "NAX-PIHOLEAPI-1.0"
|
||||||
|
|
||||||
|
|
||||||
@@ -222,8 +224,14 @@ def gather_device_entries():
|
|||||||
if ip in iplist:
|
if ip in iplist:
|
||||||
lastQuery = str(now_ts)
|
lastQuery = str(now_ts)
|
||||||
|
|
||||||
|
tmpMac = hwaddr.lower()
|
||||||
|
|
||||||
|
# ensure fake mac if enabled
|
||||||
|
if PIHOLEAPI_FAKE_MAC and is_mac(tmpMac) is False:
|
||||||
|
tmpMac = string_to_mac_hash(ip)
|
||||||
|
|
||||||
entries.append({
|
entries.append({
|
||||||
'mac': hwaddr.lower(),
|
'mac': tmpMac,
|
||||||
'ip': ip,
|
'ip': ip,
|
||||||
'name': name,
|
'name': name,
|
||||||
'macVendor': macVendor,
|
'macVendor': macVendor,
|
||||||
@@ -281,7 +289,7 @@ def main():
|
|||||||
foreignKey=str(entry['mac'])
|
foreignKey=str(entry['mac'])
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
mylog('verbose', [f"[{pluginName}] Skipping invalid MAC: {entry['name']}|{entry['mac']}|{entry['ip']}"])
|
mylog('verbose', [f"[{pluginName}] Skipping invalid MAC (see PIHOLEAPI_FAKE_MAC setting): {entry['name']}|{entry['mac']}|{entry['ip']}"])
|
||||||
|
|
||||||
# Write result file for NetAlertX to ingest
|
# Write result file for NetAlertX to ingest
|
||||||
plugin_objects.write_result_file()
|
plugin_objects.write_result_file()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ if ! awk '$2 == "/" && $4 ~ /ro/ {found=1} END {exit !found}' /proc/mounts; then
|
|||||||
══════════════════════════════════════════════════════════════════════════════
|
══════════════════════════════════════════════════════════════════════════════
|
||||||
⚠️ Warning: Container is running as read-write, not in read-only mode.
|
⚠️ Warning: Container is running as read-write, not in read-only mode.
|
||||||
|
|
||||||
Please mount the root filesystem as --read-only or use read-only: true
|
Please mount the root filesystem as --read-only or use read_only: true
|
||||||
https://github.com/jokob-sk/NetAlertX/blob/main/docs/docker-troubleshooting/read-only-filesystem.md
|
https://github.com/jokob-sk/NetAlertX/blob/main/docs/docker-troubleshooting/read-only-filesystem.md
|
||||||
══════════════════════════════════════════════════════════════════════════════
|
══════════════════════════════════════════════════════════════════════════════
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -70,3 +70,13 @@ def generate_deterministic_guid(plugin, primary_id, secondary_id):
|
|||||||
"""Generates a deterministic GUID based on plugin, primary ID, and secondary ID."""
|
"""Generates a deterministic GUID based on plugin, primary ID, and secondary ID."""
|
||||||
data = f"{plugin}-{primary_id}-{secondary_id}".encode("utf-8")
|
data = f"{plugin}-{primary_id}-{secondary_id}".encode("utf-8")
|
||||||
return str(uuid.UUID(hashlib.md5(data).hexdigest()))
|
return str(uuid.UUID(hashlib.md5(data).hexdigest()))
|
||||||
|
|
||||||
|
|
||||||
|
def string_to_mac_hash(input_string):
|
||||||
|
# Calculate a hash using SHA-256
|
||||||
|
sha256_hash = hashlib.sha256(input_string.encode()).hexdigest()
|
||||||
|
|
||||||
|
# Take the first 12 characters of the hash and format as a MAC address
|
||||||
|
mac_hash = ':'.join(sha256_hash[i:i + 2] for i in range(0, 12, 2))
|
||||||
|
|
||||||
|
return mac_hash
|
||||||
|
|||||||
Reference in New Issue
Block a user