mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 09:36:05 -08:00
Compare commits
160 Commits
dbecbfc85f
...
v24.10.12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d36486ef6d | ||
|
|
1767776dd9 | ||
|
|
507e0469d6 | ||
|
|
ae14229ca7 | ||
|
|
dcfeb51aa1 | ||
|
|
ab6e7d910b | ||
|
|
d6164a005b | ||
|
|
ca1d55b3c2 | ||
|
|
c4e0abf913 | ||
|
|
f9e6871ab2 | ||
|
|
30b8ecb743 | ||
|
|
506b8a17fc | ||
|
|
43c60586f4 | ||
|
|
a11d7d9c97 | ||
|
|
222a439212 | ||
|
|
48effdbbad | ||
|
|
62a0149435 | ||
|
|
8702ae032e | ||
|
|
82d2fa4125 | ||
|
|
189a4ece84 | ||
|
|
29de6654a8 | ||
|
|
06008058ab | ||
|
|
efc9a974b1 | ||
|
|
d91141f9ac | ||
|
|
e8d2e52ee2 | ||
|
|
d64b92c273 | ||
|
|
32bebe3ad4 | ||
|
|
2d119f39c0 | ||
|
|
f9b28b647b | ||
|
|
41a72f0292 | ||
|
|
129cd39ef8 | ||
|
|
68febd1350 | ||
|
|
669ce20a84 | ||
|
|
9427ff6453 | ||
|
|
7b2186073f | ||
|
|
30de0f9f93 | ||
|
|
d146b485c4 | ||
|
|
37290528fc | ||
|
|
b4d1505e42 | ||
|
|
afe5a2ae48 | ||
|
|
ef5dc885d9 | ||
|
|
a758548fea | ||
|
|
c6cfa398ef | ||
|
|
677e293138 | ||
|
|
ac259b1fab | ||
|
|
14996d6582 | ||
|
|
d44744657e | ||
|
|
615e5e4084 | ||
|
|
dd948b5e63 | ||
|
|
97a5cb6737 | ||
|
|
c6fe09d366 | ||
|
|
040f2792e4 | ||
|
|
d1d6d7f1ec | ||
|
|
33c16c4d00 | ||
|
|
cc8b57e790 | ||
|
|
57d8e97b60 | ||
|
|
91ad39e991 | ||
|
|
15ed621748 | ||
|
|
50304fd63b | ||
|
|
90689e5c69 | ||
|
|
5f4b2f114c | ||
|
|
e72a87ab43 | ||
|
|
044de61ab5 | ||
|
|
e5d835cfa9 | ||
|
|
e2d84a1885 | ||
|
|
e648acde5c | ||
|
|
a17e066f34 | ||
|
|
0bdc4c4ed1 | ||
|
|
9144fd0c3a | ||
|
|
02077d4654 | ||
|
|
e3b2039257 | ||
|
|
1fa38472e1 | ||
|
|
1e197ae749 | ||
|
|
7731a01f3c | ||
|
|
3ce08ba97d | ||
|
|
c58bbf21b1 | ||
|
|
3780e47117 | ||
|
|
e8f353024f | ||
|
|
7308797314 | ||
|
|
6e36f7d7aa | ||
|
|
8d3a4500e2 | ||
|
|
40d6bdc2b2 | ||
|
|
b7b2e0bc65 | ||
|
|
081d0f3400 | ||
|
|
a7f4565954 | ||
|
|
15a7779d6e | ||
|
|
2784f2ebeb | ||
|
|
d46046beea | ||
|
|
6233f4d646 | ||
|
|
31411e0a14 | ||
|
|
8d824af3bd | ||
|
|
f05f0d625a | ||
|
|
2fec3b6607 | ||
|
|
f285a28887 | ||
|
|
11cb47fada | ||
|
|
d8b413b5e7 | ||
|
|
656bba7ff7 | ||
|
|
a2cf8c1167 | ||
|
|
737cb07403 | ||
|
|
3febbc21cb | ||
|
|
7e14fae29c | ||
|
|
a16fe4561b | ||
|
|
f2afe9d681 | ||
|
|
f8c0a5a1ef | ||
|
|
631e992411 | ||
|
|
feafaff218 | ||
|
|
f6a06842cc | ||
|
|
0cc3ede86c | ||
|
|
aa277136c6 | ||
|
|
82ccb0c0b6 | ||
|
|
30750a9449 | ||
|
|
5278af48c5 | ||
|
|
77f19c3575 | ||
|
|
10df7363d6 | ||
|
|
06e49f7adb | ||
|
|
9fcbd9d64e | ||
|
|
c6888a79fd | ||
|
|
ef458903b7 | ||
|
|
b544734209 | ||
|
|
815810dc7a | ||
|
|
552d79eee8 | ||
|
|
2f70e2e8d8 | ||
|
|
4a20b66c92 | ||
|
|
36cec0ab38 | ||
|
|
6bde0f9084 | ||
|
|
f64ef5b881 | ||
|
|
1895f68233 | ||
|
|
d2fe53bc81 | ||
|
|
e9e45c34ae | ||
|
|
064a51acee | ||
|
|
7340ce6da2 | ||
|
|
703885308a | ||
|
|
71856b49a4 | ||
|
|
86c7d26107 | ||
|
|
d858f4f9d0 | ||
|
|
aefe470d31 | ||
|
|
99fb60c1b5 | ||
|
|
ec37e4d71b | ||
|
|
e240821d6c | ||
|
|
632e441dda | ||
|
|
24f7935891 | ||
|
|
dcc43d1f3c | ||
|
|
8f35bf36ff | ||
|
|
1548168eba | ||
|
|
2e35bac6ec | ||
|
|
ba348fc4c2 | ||
|
|
d3337e75a9 | ||
|
|
9e0bc043b0 | ||
|
|
29fdd0b115 | ||
|
|
48e92a186e | ||
|
|
1dcb66e972 | ||
|
|
fa0d6d312d | ||
|
|
a19fe342e7 | ||
|
|
c4fc68cac8 | ||
|
|
3a050c31a7 | ||
|
|
2cd406a390 | ||
|
|
b086417686 | ||
|
|
615fd08f5b | ||
|
|
4839211fe1 | ||
|
|
ae1673c1c3 |
28
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
28
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -9,20 +9,6 @@ body:
|
||||
options:
|
||||
- label: I have searched the existing open and closed issues
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Am I willing to test this? 🧪
|
||||
description: I rely on the community to test unreleased features. If you are requesting a feature, please be willing to test it within 48h of test request. Otherwise, the feature might be pulled from the code base.
|
||||
options:
|
||||
- label: I will do my best to test this feature on the `netlertx-dev` image when requested within 48h and report bugs to help deliver a great user experience for everyone and not to break existing installations.
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Can I help implement this? 👩💻👨💻
|
||||
description: The maintainer will provide guidance and help. The implementer will read the PR guidelines https://github.com/jokob-sk/NetAlertX/tree/main/docs#-pull-requests-prs
|
||||
options:
|
||||
- label: "Yes"
|
||||
- label: "No"
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe
|
||||
@@ -50,3 +36,17 @@ body:
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Am I willing to test this? 🧪
|
||||
description: I rely on the community to test unreleased features. If you are requesting a feature, please be willing to test it within 48h of test request. Otherwise, the feature might be pulled from the code base.
|
||||
options:
|
||||
- label: I will do my best to test this feature on the `netlertx-dev` image when requested within 48h and report bugs to help deliver a great user experience for everyone and not to break existing installations.
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Can I help implement this? 👩💻👨💻
|
||||
description: The maintainer will provide guidance and help. The implementer will read the PR guidelines https://github.com/jokob-sk/NetAlertX/tree/main/docs#-pull-requests-prs
|
||||
options:
|
||||
- label: "Yes"
|
||||
- label: "No"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
FROM alpine:3.20 as builder
|
||||
FROM alpine:3.20 AS builder
|
||||
|
||||
ARG INSTALL_DIR=/app
|
||||
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
# Install build dependencies
|
||||
RUN apk add --no-cache bash python3 python3-dev gcc musl-dev libffi-dev openssl-dev \
|
||||
@@ -21,7 +21,7 @@ RUN pip install netifaces tplink-omada-client pycryptodome requests paho-mqtt sc
|
||||
&& bash -c "find ${INSTALL_DIR} -type f \( -name '*.sh' -o -name '*.py' -o -name 'speedtest-cli' \) -exec chmod 750 {} \;"
|
||||
|
||||
# second stage
|
||||
FROM alpine:3.20 as runner
|
||||
FROM alpine:3.20 AS runner
|
||||
|
||||
ARG INSTALL_DIR=/app
|
||||
|
||||
@@ -40,7 +40,7 @@ ENV S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0
|
||||
|
||||
RUN apk update --no-cache \
|
||||
&& apk add --no-cache bash zip lsblk gettext-envsubst sudo mtr tzdata s6-overlay \
|
||||
&& apk add --no-cache curl arp-scan iproute2 iproute2-ss nmap nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake ca-certificates \
|
||||
&& apk add --no-cache curl arp-scan iproute2 iproute2-ss nmap nmap-scripts traceroute nbtscan avahi avahi-tools openrc dbus net-tools net-snmp-tools bind-tools awake ca-certificates \
|
||||
&& apk add --no-cache sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session \
|
||||
&& apk add --no-cache python3 nginx \
|
||||
&& apk add --no-cache dcron \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
# default UID and GID
|
||||
ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211
|
||||
ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211
|
||||
#TZ=Europe/London
|
||||
|
||||
# Todo, figure out why using a workdir instead of full paths don't work
|
||||
@@ -33,7 +33,7 @@ COPY --chmod=775 --chown=${USER_ID}:${USER_GID} . ${INSTALL_DIR}/
|
||||
RUN apt-get install -y \
|
||||
tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo \
|
||||
nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools php-openssl \
|
||||
python3 python3-dev iproute2 nmap python3-pip zip systemctl usbutils traceroute nbtscan
|
||||
python3 python3-dev iproute2 nmap python3-pip zip systemctl usbutils traceroute nbtscan avahi avahi-tools openrc dbus
|
||||
|
||||
# Alternate dependencies
|
||||
RUN apt-get install nginx nginx-core mtr php-fpm php8.2-fpm php-cli php8.2 php8.2-sqlite3 -y
|
||||
@@ -43,7 +43,7 @@ RUN phpenmod -v 8.2 sqlite3
|
||||
RUN apt-get install -y python3-venv
|
||||
RUN python3 -m venv myenv
|
||||
|
||||
RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install tplink-omada-client pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython cryptography librouteros "
|
||||
RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install tplink-omada-client pycryptodome requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet python-nmap dnspython librouteros "
|
||||
|
||||
# Create a buildtimestamp.txt to later check if a new version was released
|
||||
RUN date +%s > ${INSTALL_DIR}/front/buildtimestamp.txt
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[](https://github.com/jokob-sk/NetAlertX)
|
||||
[](https://github.com/jokob-sk/NetAlertX)
|
||||
[](https://hub.docker.com/r/jokobsk/netalertx)
|
||||
[](https://hub.docker.com/r/jokobsk/netalertx)
|
||||
[](https://github.com/jokob-sk/NetAlertX/releases)
|
||||
@@ -62,6 +62,8 @@ Head to [https://netalertx.com/](https://netalertx.com/) for more gifs and scree
|
||||
## Installation & Documentation
|
||||
<!--- --------------------------------------------------------------------- --->
|
||||
|
||||
Supported browsers: Chrome, Firefox
|
||||
|
||||
| Docs | Link |
|
||||
|-------------|-------------|
|
||||
| 📥🐳 | [Docker instructions](https://github.com/jokob-sk/NetAlertX/blob/main/dockerfiles/README.md)
|
||||
@@ -93,6 +95,7 @@ Thank you to all the wonderful people who are sponsoring this project.
|
||||
<!-- SPONSORS-LIST DO NOT MODIFY BELOW -->
|
||||
| All Sponsors |
|
||||
|---|
|
||||
| [joel72265](https://github.com/joel72265) |
|
||||
|
||||
<!-- SPONSORS-LIST DO NOT MODIFY ABOVE -->
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
SCAN_SUBNETS=['192.168.1.0/24 --interface=eth0']
|
||||
TIMEZONE='Europe/Berlin'
|
||||
LOADED_PLUGINS = ['ARPSCAN','CSVBCKP','DBCLNP', 'INTRNT','MAINT','NEWDEV','NSLOOKUP','NTFPRCS', 'PHOLUS','SETPWD','SMTP', 'SYNC', 'VNDRPDT', 'WORKFLOWS']
|
||||
LOADED_PLUGINS = ['ARPSCAN','CSVBCKP','DBCLNP', 'INTRNT','MAINT','NEWDEV','NSLOOKUP','NTFPRCS', 'AVAHISCAN', 'SETPWD','SMTP', 'SYNC', 'VNDRPDT', 'WORKFLOWS']
|
||||
|
||||
DAYS_TO_KEEP_EVENTS=90
|
||||
# Used for generating links in emails. Make sure not to add a trailing slash!
|
||||
@@ -28,7 +28,6 @@ REPORT_DASHBOARD_URL='http://netalertx'
|
||||
# Make sure at least these scanners are enabled for new installs, other defaults are taken from the config.json
|
||||
INTRNT_RUN='schedule'
|
||||
ARPSCAN_RUN='schedule'
|
||||
PHOLUS_RUN='on_new_device'
|
||||
NSLOOKUP_RUN='before_name_updates'
|
||||
|
||||
# Email
|
||||
|
||||
@@ -64,7 +64,9 @@ services:
|
||||
# DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes
|
||||
# ---------------------------------------------------------------------------
|
||||
environment:
|
||||
# - APP_CONF_OVERRIDE={"SCAN_SUBNETS":"['192.168.1.0/24 --interface=eth1']","UI_dark_mode":"True"}
|
||||
- TZ=${TZ}
|
||||
- PORT=${PORT}
|
||||
- PORT=${PORT}
|
||||
# ❗ DANGER ZONE BELOW - Setting ALWAYS_FRESH_INSTALL=true will delete the content of the /db & /config folders
|
||||
- ALWAYS_FRESH_INSTALL=${ALWAYS_FRESH_INSTALL}
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ docker run -d --rm --network=host \
|
||||
| `PORT` |Port of the web interface | `20211` |
|
||||
| `LISTEN_ADDR` |Set the specific IP Address for the listener address for the nginx webserver (web interface). This could be useful when using multiple subnets to hide the web interface from all untrusted networks. | `0.0.0.0` |
|
||||
|`TZ` |Time zone to display stats correctly. Find your time zone [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `Europe/Berlin` |
|
||||
|`ALWAYS_FRESH_INSTALL` | Setting to `true` will delete the content of the `/db` & `/config` folders. For testing purposes. Can be coupled with [watchtower](https://github.com/containrrr/watchtower) to have an always freshly installed `netalertx`/`-dev` image. | `N/A` |
|
||||
|`APP_CONF_OVERRIDE` | JSON override for settings, e.g. `{"SCAN_SUBNETS":"['192.168.1.0/24 --interface=eth1']","UI_dark_mode":"True"}` (Experimental 🧪) | `N/A` |
|
||||
|`ALWAYS_FRESH_INSTALL` | If `true` will delete the content of the `/db` & `/config` folders. For testing purposes. Can be coupled with [watchtower](https://github.com/containrrr/watchtower) to have an always freshly installed `netalertx`/`netalertx-dev` image. | `N/A` |
|
||||
|
||||
### Docker paths
|
||||
|
||||
|
||||
@@ -41,6 +41,16 @@ if [ "$ALWAYS_FRESH_INSTALL" = true ]; then
|
||||
rm -rf "$INSTALL_DIR_OLD/db/"*
|
||||
fi
|
||||
|
||||
# OVERRIDE settings: Handling APP_CONF_OVERRIDE
|
||||
# Check if APP_CONF_OVERRIDE is set
|
||||
if [ -z "$APP_CONF_OVERRIDE" ]; then
|
||||
echo "APP_CONF_OVERRIDE is not set. Skipping config file creation."
|
||||
else
|
||||
# Save the APP_CONF_OVERRIDE env variable as a JSON file
|
||||
echo "$APP_CONF_OVERRIDE" > "${INSTALL_DIR}/config/app_conf_override.json"
|
||||
echo "Config file saved to ${INSTALL_DIR}/config/app_conf_override.json"
|
||||
fi
|
||||
|
||||
# 🔻 FOR BACKWARD COMPATIBILITY - REMOVE AFTER 12/12/2024
|
||||
|
||||
# Check if pialert.db exists, then create a symbolic link to app.db
|
||||
|
||||
275
docs/AUTHELIA.md
Executable file
275
docs/AUTHELIA.md
Executable file
@@ -0,0 +1,275 @@
|
||||
(DRAFT) Authelia support
|
||||
|
||||
|
||||
|
||||
```yaml
|
||||
theme: dark
|
||||
|
||||
default_2fa_method: "totp"
|
||||
|
||||
server:
|
||||
address: 0.0.0.0:9091
|
||||
endpoints:
|
||||
enable_expvars: false
|
||||
enable_pprof: false
|
||||
authz:
|
||||
forward-auth:
|
||||
implementation: 'ForwardAuth'
|
||||
authn_strategies:
|
||||
- name: 'HeaderAuthorization'
|
||||
schemes:
|
||||
- 'Basic'
|
||||
- name: 'CookieSession'
|
||||
ext-authz:
|
||||
implementation: 'ExtAuthz'
|
||||
authn_strategies:
|
||||
- name: 'HeaderAuthorization'
|
||||
schemes:
|
||||
- 'Basic'
|
||||
- name: 'CookieSession'
|
||||
auth-request:
|
||||
implementation: 'AuthRequest'
|
||||
authn_strategies:
|
||||
- name: 'HeaderAuthRequestProxyAuthorization'
|
||||
schemes:
|
||||
- 'Basic'
|
||||
- name: 'CookieSession'
|
||||
legacy:
|
||||
implementation: 'Legacy'
|
||||
authn_strategies:
|
||||
- name: 'HeaderLegacy'
|
||||
- name: 'CookieSession'
|
||||
disable_healthcheck: false
|
||||
tls:
|
||||
key: ""
|
||||
certificate: ""
|
||||
client_certificates: []
|
||||
headers:
|
||||
csp_template: ""
|
||||
|
||||
log:
|
||||
## Level of verbosity for logs: info, debug, trace.
|
||||
level: info
|
||||
|
||||
###############################################################
|
||||
# The most important section
|
||||
###############################################################
|
||||
access_control:
|
||||
## Default policy can either be 'bypass', 'one_factor', 'two_factor' or 'deny'.
|
||||
default_policy: deny
|
||||
networks:
|
||||
- name: internal
|
||||
networks:
|
||||
- '192.168.0.0/18'
|
||||
- '10.10.10.0/8' # Zerotier
|
||||
- name: private
|
||||
networks:
|
||||
- '172.16.0.0/12'
|
||||
rules:
|
||||
- networks:
|
||||
- private
|
||||
domain:
|
||||
- '*'
|
||||
policy: bypass
|
||||
- networks:
|
||||
- internal
|
||||
domain:
|
||||
- '*'
|
||||
policy: bypass
|
||||
- domain:
|
||||
# exclude itself from auth, should not happen as we use Traefik middleware on a case-by-case screnario
|
||||
- 'auth.MYDOMAIN1.TLD'
|
||||
- 'authelia.MYDOMAIN1.TLD'
|
||||
- 'auth.MYDOMAIN2.TLD'
|
||||
- 'authelia.MYDOMAIN2.TLD'
|
||||
policy: bypass
|
||||
- domain:
|
||||
#All subdomains match
|
||||
- 'MYDOMAIN1.TLD'
|
||||
- '*.MYDOMAIN1.TLD'
|
||||
policy: two_factor
|
||||
- domain:
|
||||
# This will not work yet as Authelio does not support multi-domain authentication
|
||||
- 'MYDOMAIN2.TLD'
|
||||
- '*.MYDOMAIN2.TLD'
|
||||
policy: two_factor
|
||||
|
||||
|
||||
############################################################
|
||||
identity_validation:
|
||||
reset_password:
|
||||
jwt_secret: "[REDACTED]"
|
||||
|
||||
identity_providers:
|
||||
oidc:
|
||||
enable_client_debug_messages: true
|
||||
enforce_pkce: public_clients_only
|
||||
hmac_secret: [REDACTED]
|
||||
lifespans:
|
||||
authorize_code: 1m
|
||||
id_token: 1h
|
||||
refresh_token: 90m
|
||||
access_token: 1h
|
||||
cors:
|
||||
endpoints:
|
||||
- authorization
|
||||
- token
|
||||
- revocation
|
||||
- introspection
|
||||
- userinfo
|
||||
allowed_origins:
|
||||
- "*"
|
||||
allowed_origins_from_client_redirect_uris: false
|
||||
jwks:
|
||||
- key: [REDACTED]
|
||||
certificate_chain:
|
||||
clients:
|
||||
- client_id: portainer
|
||||
client_name: Portainer
|
||||
# generate secret with "authelia crypto hash generate pbkdf2 --random --random.length 32 --random.charset alphanumeric"
|
||||
# Random Password: [REDACTED]
|
||||
# Digest: [REDACTED]
|
||||
client_secret: [REDACTED]
|
||||
token_endpoint_auth_method: 'client_secret_post'
|
||||
public: false
|
||||
authorization_policy: two_factor
|
||||
consent_mode: pre-configured #explicit
|
||||
pre_configured_consent_duration: '6M' #Must be re-authorised every 6 Months
|
||||
scopes:
|
||||
- openid
|
||||
#- groups #Currently not supported in Authelia V
|
||||
- email
|
||||
- profile
|
||||
redirect_uris:
|
||||
- https://portainer.MYDOMAIN1.LTD
|
||||
userinfo_signed_response_alg: none
|
||||
|
||||
- client_id: openproject
|
||||
client_name: OpenProject
|
||||
# generate secret with "authelia crypto hash generate pbkdf2 --random --random.length 32 --random.charset alphanumeric"
|
||||
# Random Password: [REDACTED]
|
||||
# Digest: [REDACTED]
|
||||
client_secret: [REDACTED]
|
||||
token_endpoint_auth_method: 'client_secret_basic'
|
||||
public: false
|
||||
authorization_policy: two_factor
|
||||
consent_mode: pre-configured #explicit
|
||||
pre_configured_consent_duration: '6M' #Must be re-authorised every 6 Months
|
||||
scopes:
|
||||
- openid
|
||||
#- groups #Currently not supported in Authelia V
|
||||
- email
|
||||
- profile
|
||||
redirect_uris:
|
||||
- https://op.MYDOMAIN.TLD
|
||||
#grant_types:
|
||||
# - refresh_token
|
||||
# - authorization_code
|
||||
#response_types:
|
||||
# - code
|
||||
#response_modes:
|
||||
# - form_post
|
||||
# - query
|
||||
# - fragment
|
||||
userinfo_signed_response_alg: none
|
||||
##################################################################
|
||||
|
||||
|
||||
telemetry:
|
||||
metrics:
|
||||
enabled: false
|
||||
address: tcp://0.0.0.0:9959
|
||||
|
||||
totp:
|
||||
disable: false
|
||||
issuer: authelia.com
|
||||
algorithm: sha1
|
||||
digits: 6
|
||||
period: 30 ## The period in seconds a one-time password is valid for.
|
||||
skew: 1
|
||||
secret_size: 32
|
||||
|
||||
webauthn:
|
||||
disable: false
|
||||
timeout: 60s ## Adjust the interaction timeout for Webauthn dialogues.
|
||||
display_name: Authelia
|
||||
attestation_conveyance_preference: indirect
|
||||
user_verification: preferred
|
||||
|
||||
ntp:
|
||||
address: "pool.ntp.org"
|
||||
version: 4
|
||||
max_desync: 5s
|
||||
disable_startup_check: false
|
||||
disable_failure: false
|
||||
|
||||
authentication_backend:
|
||||
password_reset:
|
||||
disable: false
|
||||
custom_url: ""
|
||||
refresh_interval: 5m
|
||||
file:
|
||||
path: /config/users_database.yml
|
||||
watch: true
|
||||
password:
|
||||
algorithm: argon2
|
||||
argon2:
|
||||
variant: argon2id
|
||||
iterations: 3
|
||||
memory: 65536
|
||||
parallelism: 4
|
||||
key_length: 32
|
||||
salt_length: 16
|
||||
|
||||
password_policy:
|
||||
standard:
|
||||
enabled: false
|
||||
min_length: 8
|
||||
max_length: 0
|
||||
require_uppercase: true
|
||||
require_lowercase: true
|
||||
require_number: true
|
||||
require_special: true
|
||||
## zxcvbn is a well known and used password strength algorithm. It does not have tunable settings.
|
||||
zxcvbn:
|
||||
enabled: false
|
||||
min_score: 3
|
||||
|
||||
regulation:
|
||||
max_retries: 3
|
||||
find_time: 2m
|
||||
ban_time: 5m
|
||||
|
||||
session:
|
||||
name: authelia_session
|
||||
secret: [REDACTED]
|
||||
expiration: 60m
|
||||
inactivity: 15m
|
||||
cookies:
|
||||
- domain: 'MYDOMAIN1.LTD'
|
||||
authelia_url: 'https://auth.MYDOMAIN1.LTD'
|
||||
name: 'authelia_session'
|
||||
default_redirection_url: 'https://MYDOMAIN1.LTD'
|
||||
- domain: 'MYDOMAIN2.LTD'
|
||||
authelia_url: 'https://auth.MYDOMAIN2.LTD'
|
||||
name: 'authelia_session_other'
|
||||
default_redirection_url: 'https://MYDOMAIN2.LTD'
|
||||
|
||||
storage:
|
||||
encryption_key: [REDACTED]
|
||||
local:
|
||||
path: /config/db.sqlite3
|
||||
|
||||
notifier:
|
||||
disable_startup_check: true
|
||||
smtp:
|
||||
address: MYOTHERDOMAIN.LTD:465
|
||||
timeout: 5s
|
||||
username: "USER@DOMAIN"
|
||||
password: "[REDACTED]"
|
||||
sender: "Authelia <postmaster@MYOTHERDOMAIN.LTD>"
|
||||
identifier: NAME@MYOTHERDOMAIN.LTD
|
||||
subject: "[Authelia] {title}"
|
||||
startup_check_address: postmaster@MYOTHERDOMAIN.LTD
|
||||
|
||||
```
|
||||
@@ -8,7 +8,7 @@ There are 3 artifacts that can be used to backup the application:
|
||||
| File | Description | Limitations |
|
||||
|-----------------------|-------------------------------|-------------------------------|
|
||||
| `/db/app.db` | Database file(s) | The database file might be in an uncommitted state or corrupted |
|
||||
| `/config/app.conf` | Configuration file | Doesn't contain settings from the Maintenance section |
|
||||
| `/config/app.conf` | Configuration file | Can be overridden with the [`APP_CONF_OVERRIDE` env variable](https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles#docker-environment-variables). |
|
||||
| `/config/devices.csv` | CSV file containing device information | Doesn't contain historical data |
|
||||
|
||||
## Data and backup storage
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
| Pholus_Scan | Scan results of the Pholus python network penetration script. | ![Screen8][screen8] |
|
||||
| Plugins_Events | For capturing events exposed by a plugin via the `last_result.log` file. If unique then saved into the `Plugins_Objects` table. Entries are deleted once processed and stored in the `Plugins_History` and/or `Plugins_Objects` tables. | ![Screen10][screen10] |
|
||||
| Plugins_History | History of all entries from the `Plugins_Events` table | ![Screen11][screen11] |
|
||||
| Plugins_Language_Strings | Language strings colelcted from the plugin `config.json` files used for string resolution in the frontend. | ![Screen12][screen12] |
|
||||
| Plugins_Language_Strings | Language strings collected from the plugin `config.json` files used for string resolution in the frontend. | ![Screen12][screen12] |
|
||||
| Plugins_Objects | Unique objects detected by individual plugins. | ![Screen13][screen13] |
|
||||
| Sessions | Used to display sessions in the charts | ![Screen15][screen15] |
|
||||
| Settings | Database representation of the sum of all settings from `app.conf` and plugins coming from `config.json` files. | ![Screen16][screen16] |
|
||||
|
||||
@@ -81,3 +81,7 @@ sudo dpkg -i libseccomp2_2.5.3-2_armhf.deb
|
||||
```
|
||||
|
||||
The link above will probably break in time too. Go to https://packages.debian.org/sid/armhf/libseccomp2/download to find the new version number and put that in the url.
|
||||
|
||||
### Only Router and own device show up
|
||||
|
||||
Make sure that the subnet and interface in SCAN_SUBNETS are the correct ones. If your device/NAS has multiple ethernet ports, you probably need to change eth0 to something else!
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Development environemnt set up
|
||||
## Development environment set up
|
||||
|
||||
>[!NOTE]
|
||||
> Replace `/development` with the path where your code files will be stored. The default container name is `netalertx` so there might be a conflict with your running containers.
|
||||
@@ -52,13 +52,19 @@ A command to stop, remove the container and the image (replace `netalertx` and `
|
||||
|
||||
- `sudo docker container stop netalertx ; sudo docker container rm netalertx ; sudo docker image rm netalertx-netalertx`
|
||||
|
||||
### Restart hanging python script
|
||||
### Restart the server backend
|
||||
|
||||
SSH into the container and kill & restart the main script loop
|
||||
Most code changes can be tetsed without rebuilding the container. When working on the python server backend, you only need to restart the server.
|
||||
|
||||
1. You can usually restart the backend via Maintenance > Logs > Restart server
|
||||
|
||||

|
||||
|
||||
2. If above doesn't work, SSH into the container and kill & restart the main script loop
|
||||
|
||||
- `sudo docker exec -it netalertx /bin/bash`
|
||||
- `pkill -f "python /app/server" && python /app/server & `
|
||||
|
||||
|
||||
3. If none of the above work, restart the docker image. This is usually the last resort as sometimes the Docker engine becomes unresponsive and the whole engine needs to be restarted.
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ NetAlertX comes with MQTT support, allowing you to show all detected devices as
|
||||
|
||||
- Please note that discovery takes about ~10s per device.
|
||||
- Deleting of devices is not handled automatically. Please use [MQTT Explorer](https://mqtt-explorer.com/) to delete devices in the broker (Home Assistant), if needed.
|
||||
- For optimization reasons, the devices are not always fully synchronized. You can delete Plugin objects as described in the [MQTT plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/_publisher_mqtt#forcing-an-update) docs to force a full synchronization.
|
||||
|
||||
|
||||
## 🧭 Guide
|
||||
|
||||
24
docs/PERFORMANCE.md
Executable file
24
docs/PERFORMANCE.md
Executable file
@@ -0,0 +1,24 @@
|
||||
# Performance tips
|
||||
|
||||
The application runs regular maintenance and DB cleanup tasks. If these tasks fail, you might encounter performance issues.
|
||||
|
||||
Most performance issues are caused by a big database or large log files. Enabling unnecessary plugins will also lead to performance degradation.
|
||||
|
||||
You can always check the size of your database and database tables under the Maintenance page.
|
||||
|
||||

|
||||
|
||||
> [!NOTE]
|
||||
> For around 100 devices the database should be approximately `50MB` and none of the entries (rows) should exceed the value of `10 000` on a healthy system. These numbers will depend on your network activity and settings.
|
||||
|
||||
## Maintenance plugins
|
||||
|
||||
There are 2 plugins responsible for maintaining the overal health of the application. One is responsible for the database cleanup and one for other tasks, such as log cleanup.
|
||||
|
||||
### DB Cleanup (DBCLNP)
|
||||
|
||||
The database cleanup plugin. Check details and related setting in the [DB Cleanup plugin docs](/front/plugins/db_cleanup/README.md). Make sure the plugin is not failing by checking the logs. Try changing the schedule `DBCLNP_RUN_SCHD` and the timeout `DBCLNP_RUN_TIMEOUT` (increase) if the plugin is failing to execute.
|
||||
|
||||
### Maintenance (MAINT)
|
||||
|
||||
The maintenance plugin. Check details and related setting in the [Maintenance plugin docs](/front/plugins/maintenance/README.md). Make sure the plugin is not failing by checking the logs. Try changing the schedule `MAINT_RUN_SCHD` and the timeout `MAINT_RUN_TIMEOUT` (increase) if the plugin is failing to execute.
|
||||
@@ -83,7 +83,7 @@ The `config.json` file is the manifest of the plugin. It contains mainly setting
|
||||
|
||||
## Execution order
|
||||
|
||||
The execution order is used to specify wwhen a plugin is executed. This is useful if a plugin has access and surfaces more information than others. If a device is detected by 2 plugins and inserted into the `CurrentScan` table, the plugin with the higher priority (e.g.: `Level_0` is a higher priority than `Level_1`) will insert it's values first. These values (devices) will be then prioritized over any values inserted later.
|
||||
The execution order is used to specify when a plugin is executed. This is useful if a plugin has access and surfaces more information than others. If a device is detected by 2 plugins and inserted into the `CurrentScan` table, the plugin with the higher priority (e.g.: `Level_0` is a higher priority than `Level_1`) will insert it's values first. These values (devices) will be then prioritized over any values inserted later.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -361,7 +361,7 @@ Plugin results are always inserted into the standard `Plugin_Objects` database t
|
||||
>3. That's it. The app takes care of the rest. It loops thru the objects discovered by the plugin, takes the results line-by-line, and inserts them into the database table specified in `"mapped_to_table"`. The columns are translated from the generic plugin columns to the target table columns via the `"mapped_to_column"` property in the column definitions.
|
||||
|
||||
> [!NOTE]
|
||||
> You can create a column mapping with a default value via the `mapped_to_column_data` property. This means that the value of the given column will always be this value. That also menas that the `"column": "NameDoesntMatter"` is not important as there is no database source column.
|
||||
> You can create a column mapping with a default value via the `mapped_to_column_data` property. This means that the value of the given column will always be this value. That also means that the `"column": "NameDoesntMatter"` is not important as there is no database source column.
|
||||
|
||||
|
||||
>🔍 Example:
|
||||
@@ -518,6 +518,60 @@ Required attributes are:
|
||||
| (optional) `"override_value"` | Used to determine a user-defined override for the setting. Useful for template-based plugins, where you can choose to leave the current value or override it with the value defined in the setting. (Work in progress) |
|
||||
| (optional) `"events"` | Used to trigger the plugin. Usually used on the `RUN` setting. Not fully tested in all scenarios. Will show a play button next to the setting. After clicking, an event is generated for the backend in the `Parameters` database table to process the front-end event on the next run. |
|
||||
|
||||
### UI Component Types Documentation
|
||||
|
||||
This section outlines the structure and types of UI components, primarily used to build HTML forms or interactive elements dynamically. Each UI component has a `"type"` which defines its structure, behavior, and rendering options.
|
||||
|
||||
#### UI Component JSON Structure
|
||||
The UI component is defined as a JSON object containing a list of `elements`. Each element specifies how it should behave, with properties like `elementType`, `elementOptions`, and any associated `transformers` to modify the data. The example below demonstrates how a component with two elements (`span` and `select`) is structured:
|
||||
|
||||
```json
|
||||
{
|
||||
"function": "dev_Icon",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "span",
|
||||
"elementOptions": [
|
||||
{ "cssClasses": "input-group-addon iconPreview" },
|
||||
{ "getStringKey": "Gen_SelectToPreview" },
|
||||
{ "customId": "NEWDEV_dev_Icon_preview" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "select",
|
||||
"elementHasInputValue": 1,
|
||||
"elementOptions": [
|
||||
{ "cssClasses": "col-xs-12" },
|
||||
{
|
||||
"onChange": "updateIconPreview(this)"
|
||||
},
|
||||
{ "customParams": "NEWDEV_dev_Icon,NEWDEV_dev_Icon_preview" }
|
||||
],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Rendering Logic
|
||||
|
||||
The code snippet provided demonstrates how the elements are iterated over to generate their corresponding HTML. Depending on the `elementType`, different HTML tags (like `<select>`, `<input>`, `<textarea>`, `<button>`, etc.) are created with the respective attributes such as `onChange`, `my-data-type`, and `class` based on the provided `elementOptions`. Events can also be attached to elements like buttons or select inputs.
|
||||
|
||||
### Key Element Types
|
||||
|
||||
- **`select`**: Renders a dropdown list. Additional options like `isMultiSelect` and event handlers (e.g., `onChange`) can be attached.
|
||||
- **`input`**: Handles various types of input fields, including checkboxes, text, and others, with customizable attributes like `readOnly`, `placeholder`, etc.
|
||||
- **`button`**: Generates clickable buttons with custom event handlers (`onClick`), icons, or labels.
|
||||
- **`textarea`**: Creates a multi-line input box for text input.
|
||||
- **`span`**: Used for inline text or content with customizable classes and data attributes.
|
||||
|
||||
Each element may also have associated events (e.g., running a scan or triggering a notification) defined under `Events`.
|
||||
|
||||
|
||||
##### Supported settings `function` values
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ There is also an in-app Help / FAQ section that should be answering frequently a
|
||||
- [Invalid JSON errors debug help](/docs/DEBUG_INVALID_JSON.md)
|
||||
- [Troubleshooting Plugins](/docs/DEBUG_PLUGINS.md)
|
||||
- [File Permissions](/docs/FILE_PERMISSIONS.md)
|
||||
- [Performance tips](/docs/PERFORMANCE.md)
|
||||
|
||||
#### 🔝 Popular/Suggested
|
||||
|
||||
@@ -63,6 +64,7 @@ There is also an in-app Help / FAQ section that should be answering frequently a
|
||||
|
||||
- [Version history (legacy)](/docs/VERSIONS_HISTORY.md)
|
||||
- [Reverse proxy (Nginx, Apache, SWAG)](/docs/REVERSE_PROXY.md)
|
||||
- [Setting up Authelia](/docs/AUTHELIA.md) (DRAFT)
|
||||
|
||||
#### 👩💻For Developers👨💻
|
||||
|
||||
|
||||
@@ -27,6 +27,29 @@ If you are running a DNS server, such as **AdGuard**, set up **Private reverse D
|
||||
5. Click **Apply** to save your settings.
|
||||
|
||||
|
||||
### Specifying the DNS in the container
|
||||
|
||||
You can specify the DNS server in the docker-compose to improve name resolution on your network.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
netalertx:
|
||||
container_name: netalertx
|
||||
image: "jokobsk/netalertx:latest"
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /home/netalertx/config:/app/config
|
||||
- /home/netalertx/db:/app/db
|
||||
- /home/netalertx/log:/app/front/log
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
- PORT=20211
|
||||
network_mode: host
|
||||
dns: # specifying the DNS servers used for the container
|
||||
- 10.8.0.1
|
||||
- 10.8.0.17
|
||||
```
|
||||
|
||||
### Using a custom resolv.conf file
|
||||
|
||||
You can configure a custom **/etc/resolv.conf** file in **docker-compose.yml** and set the nameserver to your LAN DNS server (e.g.: Pi-Hole). See the relevant [resolv.conf man](https://www.man7.org/linux/man-pages/man5/resolv.conf.5.html) entry for details.
|
||||
|
||||
149
docs/SUBNETS.md
149
docs/SUBNETS.md
@@ -1,107 +1,112 @@
|
||||
# Subnets configuration
|
||||
# Subnets Configuration
|
||||
|
||||
You need to specify the network interface and the network mask. You can also configure multiple subnets and specify VLANS (see exceptions below).
|
||||
You need to specify the network interface and the network mask. You can also configure multiple subnets and specify VLANs (see VLAN exceptions below).
|
||||
|
||||
> [!TIP]
|
||||
> You may need to increase the time between scans `ARPSCAN_RUN_SCHD` and the timeout `ARPSCAN_RUN_TIMEOUT` (and similar setting on related plugins) when adding more subnets. If the timeout setting is exceeded, the scan is cancelled to prevent application hanging from rogue plugins. Check [debugging plugins](/docs/DEBUG_PLUGINS.md) for more tips.
|
||||
`ARPSCAN` can scan multiple networks if the network allows it. To scan networks directly, the subnets must be accessible from the network where NetAlertX is running. This means NetAlertX needs to have access to the interface attached to that subnet. You can verify this by running the following command in the container:
|
||||
|
||||
## Examples
|
||||
`sudo arp-scan --interface=eth0 192.168.1.0/24`
|
||||
|
||||
In this example, `--interface=eth0 192.168.1.0/24` represents a neighboring subnet. If this command returns no results, the network is not accessible due to your network or firewall restrictions.
|
||||
|
||||
If direct scans are not possible, you can use [supplementing plugins](https://github.com/jokob-sk/NetAlertX/blob/main/front/plugins/README.md) that use alternate methods. Protocols used by the `SNMPDSC` or `DHCPLSS` plugins have good support and usually can be used as a workaround.
|
||||
|
||||
Alternatively, you can set up separate NetAlertX instances running on the subnets and synchronize the results into one instance with the [`SYNC` plugin](https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/sync).
|
||||
|
||||
> [!TIP]
|
||||
> You may need to increase the time between scans `ARPSCAN_RUN_SCHD` and the timeout `ARPSCAN_RUN_TIMEOUT` (and similar settings for related plugins) when adding more subnets. If the timeout setting is exceeded, the scan is canceled to prevent the application from hanging due to rogue plugins.
|
||||
> Check [debugging plugins](/docs/DEBUG_PLUGINS.md) for more tips.
|
||||
|
||||
## Example Values
|
||||
|
||||
> [!NOTE]
|
||||
> Please use the UI to configure settings as that ensures that the config file is in the correct format. Edit `app.conf` directly only when really necessary.
|
||||
> 
|
||||
> Please use the UI to configure settings as it ensures the config file is in the correct format. Edit `app.conf` directly only when really necessary.
|
||||
> 
|
||||
|
||||
* Examples for one and two subnets (❗ Note the `['...','...']` format):
|
||||
* One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']`
|
||||
* Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0','192.168.1.0/24 --interface=eth1 -vlan=107']`
|
||||
* **Examples for one and two subnets:**
|
||||
* One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']`
|
||||
* Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0','192.168.1.0/24 --interface=eth1 -vlan=107']`
|
||||
|
||||
If you get timeout messages, decrease the network mask (e.g.: from `/16` to `/24`) or increase the `TIMEOUT` setting (e.g.: `ARPSCAN_RUN_TIMEOUT` to `300` (5-minute timeout)) for the plugin and the interval between scans (e.g.: `ARPSCAN_RUN_SCHD` to `*/10 * * * *` (scans every 10 minutes)).
|
||||
|
||||
---
|
||||
|
||||
## Explanation
|
||||
|
||||
### Network mask
|
||||
### Network Mask
|
||||
|
||||
**Example value: `192.168.1.0/24`**
|
||||
**Example value:** `192.168.1.0/24`
|
||||
|
||||
The arp-scan time itself depends on the number of IP addresses to check.
|
||||
The `arp-scan` time itself depends on the number of IP addresses to check.
|
||||
|
||||
> The number of IPs to check depends on the [network mask](https://www.calculator.net/ip-subnet-calculator.html) you set on the `SCAN_SUBNETS` setting.
|
||||
> For example, a `/24` mask results in 256 IPs to check, whereas a `/16` mask checks around 65,536. Every IP takes a couple of seconds. This means that with an incorrect configuration, the arp-scan will take hours to complete instead of seconds.
|
||||
> The number of IPs to check depends on the [network mask](https://www.calculator.net/ip-subnet-calculator.html) you set in the `SCAN_SUBNETS` setting.
|
||||
> For example, a `/24` mask results in 256 IPs to check, whereas a `/16` mask checks around 65,536 IPs. Each IP takes a couple of seconds, so an incorrect configuration could make `arp-scan` take hours instead of seconds.
|
||||
|
||||
Specify the network filter (which **significantly** speeds up the scan process). For example, the filter `192.168.1.0/24` covers IP ranges `192.168.1.0` to `192.168.1.255`.
|
||||
Specify the network filter, which **significantly** speeds up the scan process. For example, the filter `192.168.1.0/24` covers IP ranges from `192.168.1.0` to `192.168.1.255`.
|
||||
|
||||
### Network interface (adapter)
|
||||
### Network Interface (Adapter)
|
||||
|
||||
**Example value: `--interface=eth0`**
|
||||
**Example value:** `--interface=eth0`
|
||||
|
||||
The adapter will probably be `eth0` or `eth1`. (Check `System info` > `Network Hardware` or run `iwconfig` in the container to find your interface name(s))
|
||||
The adapter will probably be `eth0` or `eth1`. (Check `System Info` > `Network Hardware` or run `iwconfig` in the container to find your interface name(s)).
|
||||
|
||||

|
||||
|
||||
> [!TIP]
|
||||
> Alterantive to `iwconfig` run `ip -o link show | awk -F': ' '!/lo|vir|docker/ {print $2}'` in your container to find your interface name(s) (e.g.: `eth0`, `eth1`).
|
||||
> [!TIP]
|
||||
> As an alternative to `iwconfig`, run `ip -o link show | awk -F': ' '!/lo|vir|docker/ {print $2}'` in your container to find your interface name(s) (e.g.: `eth0`, `eth1`).
|
||||
|
||||
### VLANs
|
||||
|
||||
**Example value: `-vlan=107`**
|
||||
**Example value:** `-vlan=107`
|
||||
|
||||
- Append e.g.: ` -vlan=107` to the interface field (e.g.: `eth0 -vlan=107`) for multiple vlans. More details in this [comment in this issue](https://github.com/jokob-sk/NetAlertX/issues/170#issuecomment-1419902988)
|
||||
- Append `-vlan=107` to the interface field (e.g.: `eth0 -vlan=107`) for multiple VLANs. More details are available in this [comment](https://github.com/jokob-sk/NetAlertX/issues/170#issuecomment-1419902988).
|
||||
|
||||
#### VLANs on a Hyper-V Setup
|
||||
|
||||
> Community-sourced content by [mscreations](https://github.com/mscreations) from this [discussion](https://github.com/jokob-sk/NetAlertX/discussions/404).
|
||||
|
||||
**Tested Setup:** Bare Metal → Hyper-V on Win Server 2019 → Ubuntu 22.04 VM → Docker → NetAlertX.
|
||||
|
||||
**Approach 1 (may cause issues):**
|
||||
Configure multiple network adapters in Hyper-V with distinct VLANs connected to each one using Hyper-V's network setup. However, this action can potentially lead to the Docker host's inability to handle network traffic correctly. This might interfere with other applications such as Authentik.
|
||||
|
||||
**Approach 2 (working example):**
|
||||
|
||||
Network connections to switches are configured as trunk and allow all VLANs access to the server.
|
||||
|
||||
By default, Hyper-V only allows untagged packets through to the VM interface, blocking VLAN-tagged packets. To fix this, follow these steps:
|
||||
|
||||
1. Run the following command in PowerShell on the Hyper-V machine:
|
||||
|
||||
```powershell
|
||||
Set-VMNetworkAdapterVlan -VMName <Docker VM Name> -Trunk -NativeVlanId 0 -AllowedVlanIdList "<comma separated list of vlans>"
|
||||
```
|
||||
|
||||
|
||||
#### VLANs on a Hyper-V setup
|
||||
2. Within the VM, set up sub-interfaces for each VLAN to enable scanning. On Ubuntu 22.04, Netplan can be used. In /etc/netplan/00-installer-config.yaml, add VLAN definitions:
|
||||
|
||||
> Community sourced content by [mscreations](https://github.com/mscreations) from this [discussion](https://github.com/jokob-sk/NetAlertX/discussions/404).
|
||||
```yaml
|
||||
|
||||
> [!NOTE]
|
||||
> The setup this was tested on: Bare Metal -> Hyper-V on Win Server 2019 -> Ubuntu 22.04 VM -> Docker -> NetAlertX.
|
||||
network:
|
||||
ethernets:
|
||||
eth0:
|
||||
dhcp4: yes
|
||||
vlans:
|
||||
eth0.2:
|
||||
id: 2
|
||||
link: eth0
|
||||
addresses: [ "192.168.2.2/24" ]
|
||||
routes:
|
||||
- to: 192.168.2.0/24
|
||||
via: 192.168.1.1
|
||||
```
|
||||
|
||||
**Approach 1 (may cause issues):**
|
||||
3. Run `sudo netplan apply` to activate the interfaces for scanning in NetAlertX.
|
||||
|
||||
Configure multiple network adapters in Hyper-V with distinct VLANs connected to each one using Hyper-V's network setup. However, this action can potentially lead to the Docker host's inability to handle network traffic correctly. The issue may stem from the creation of routes for network time servers or domain controllers on every interface, thereby preventing proper synchronization of the underlying Ubuntu VM. This interference can affect the performance of other applications such as Authentik.
|
||||
In this case, use `192.168.2.0/24 --interface=eth0.2` in NetAlertX.
|
||||
|
||||
**Approach 2 (working example)**
|
||||
#### VLAN Support & Exceptions
|
||||
|
||||
Network connections to switches are configured as trunk and allow all VLANs access to the server.
|
||||
|
||||
By default Hyper-V only allows untagged packets through to the VM interface and no VLAN tagged packets get through. In order to fix this follow these steps:
|
||||
|
||||
1) Run the following command in Powershell on the Hyper-V machine:
|
||||
|
||||
```shell
|
||||
Set-VMNetworkAdapterVlan -VMName <Docker VM Name> -Trunk -NativeVlanId 0 -AllowedVlanIdList "<comma separated list of vlans>"
|
||||
```
|
||||
|
||||
(There might be other ways how adjust this.)
|
||||
|
||||
2) Within the VM, set up sub-interfaces for each of the VLANs so they can be scanned. On Ubuntu 22.04 Netplan can be used.
|
||||
|
||||
In /etc/netplan/00-installer-config.yaml, add vlan definitions:
|
||||
|
||||
```
|
||||
network:
|
||||
ethernets:
|
||||
eth0:
|
||||
dhcp4: yes
|
||||
vlans:
|
||||
eth0.2:
|
||||
id: 2
|
||||
link: eth0
|
||||
addresses: [ "192.168.2.2/24" ]
|
||||
routes:
|
||||
- to: 192.168.2.0/24
|
||||
via: 192.168.1.1
|
||||
```
|
||||
|
||||
3) Run `sudo netplan apply` and the interfaces are then available to scan in NetAlertX.
|
||||
4) In this case, use `192.168.2.0/24 --interface=eth0.2` in NetAlertX
|
||||
|
||||
#### VLAN 🔍Example:
|
||||
|
||||

|
||||
|
||||
#### Support for VLANS (& exceptions)
|
||||
|
||||
Please note the accessibility of the macvlans when they are configured on the same computer. My understanding this is a general networking behavior, but feel free to clarify via a PR/issue.
|
||||
Please note the accessibility of macvlans when configured on the same computer. This is a general networking behavior, but feel free to clarify via a PR/issue.
|
||||
|
||||
- NetAlertX does not detect the macvlan container when it is running on the same computer.
|
||||
- NetAlertX recognizes the macvlan container when it is running on a different computer.
|
||||
|
||||
|
||||
BIN
docs/img/DEV_ENV_SETUP/Maintenance_Logs_Restart_server.png
Executable file
BIN
docs/img/DEV_ENV_SETUP/Maintenance_Logs_Restart_server.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
BIN
docs/img/PERFORMANCE/db_size_check.png
Executable file
BIN
docs/img/PERFORMANCE/db_size_check.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
@@ -17,7 +17,7 @@ showSpinner()
|
||||
$(document).ready(function() {
|
||||
|
||||
// Load JSON data from the provided URL
|
||||
$.getJSON('/api/table_appevents.json', function(data) {
|
||||
$.getJSON('api/table_appevents.json', function(data) {
|
||||
// Process the JSON data and generate UI dynamically
|
||||
processData(data)
|
||||
|
||||
|
||||
@@ -124,6 +124,21 @@
|
||||
border: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
||||
.hideOnBigScreen{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) { /* on mobile */
|
||||
|
||||
.hideOnMobile{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Main Sections
|
||||
----------------------------------------------------------------------------- */
|
||||
@@ -261,7 +276,7 @@
|
||||
.main-sidebar {
|
||||
padding-top: 50px;
|
||||
}
|
||||
.content-header {
|
||||
.content-header #pageTitle{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -781,20 +796,20 @@ height: 50px;
|
||||
/* settings */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
@media (max-width: 767px) {
|
||||
@media (max-width: 767px) { /* on mobile */
|
||||
/* hide on mobile */
|
||||
.setting_description {
|
||||
/* color: red; */
|
||||
display: none;
|
||||
}
|
||||
.setting_input{
|
||||
/* .setting_input{
|
||||
width:70%;
|
||||
/* background-color: red; */
|
||||
|
||||
}
|
||||
.setting_name
|
||||
{
|
||||
width:30%;
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
@@ -802,14 +817,14 @@ height: 50px;
|
||||
/* color: green; */
|
||||
display: block;
|
||||
}
|
||||
.setting_input{
|
||||
/* .setting_input{
|
||||
width:40%;
|
||||
/* background-color: green; */
|
||||
|
||||
}
|
||||
.setting_name
|
||||
{
|
||||
width:19%;
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
.settingswrap
|
||||
@@ -874,10 +889,10 @@ height: 50px;
|
||||
}
|
||||
|
||||
|
||||
.table_row {
|
||||
#settingsPage .table_row {
|
||||
padding: 3px;
|
||||
width:100%;
|
||||
display: flex;
|
||||
/* width:100%; */
|
||||
/* display: flex; */
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
border-color: #606060;
|
||||
@@ -897,10 +912,6 @@ height: 50px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.setting_description
|
||||
{
|
||||
width:40%;
|
||||
}
|
||||
|
||||
.myhidden
|
||||
{
|
||||
@@ -1097,6 +1108,11 @@ input[readonly] {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#settingsPage .form-control
|
||||
{
|
||||
min-height: 42px;
|
||||
}
|
||||
|
||||
#settingsPage .select2-selection
|
||||
{
|
||||
background-color: rgb(96, 96, 96);
|
||||
@@ -1112,11 +1128,41 @@ input[readonly] {
|
||||
display: inline-grid;
|
||||
}
|
||||
|
||||
|
||||
/* Basic style for the div elements */
|
||||
#settingsPage .setting_overriden_by_env {
|
||||
position: relative;
|
||||
/* width: 300px;
|
||||
height: 200px; */
|
||||
background-color: #f3f3f3;
|
||||
border: 1px solid #ccc;
|
||||
margin: 20px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/* Style for the overlay */
|
||||
#settingsPage .setting_overriden_by_env::after {
|
||||
content: "Overridden with ENV variable";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.6); /* semi-transparent black overlay */
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
z-index: 11;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/* Devices page */
|
||||
/* ----------------------------------------------------------------- */
|
||||
|
||||
#txtIconFA {
|
||||
.iconPreview {
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<div class="col-lg-12 col-sm-12 col-xs-12">
|
||||
<!-- <div class="box-transparent"> -->
|
||||
<div id="navDevice" class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs" style="fon t-size:16px;">
|
||||
<ul class="nav nav-tabs" style="font-size:16px;">
|
||||
<li> <a id="tabDetails" href="#panDetails" data-toggle="tab"> <?= lang('DevDetail_Tab_Details');?> </a></li>
|
||||
<li> <a id="tabTools" href="#panTools" data-toggle="tab"> <?= lang('DevDetail_Tab_Tools');?> </a></li>
|
||||
<li> <a id="tabSessions" href="#panSessions" data-toggle="tab"> <?= lang('DevDetail_Tab_Sessions');?> </a></li>
|
||||
@@ -197,8 +197,8 @@
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon" id="txtIconFA"></span>
|
||||
<input class="form-control" id="txtIcon" type="text" value="--" readonly>
|
||||
<span class="input-group-addon iconPreview" id="txtIconPreview" my-customid="txtIconPreview"></span>
|
||||
<input class="form-control" id="txtIcon" my-customid="txtIcon" my-customparams="txtIcon,txtIconPreview" type="text" value="--" readonly>
|
||||
<span class="input-group-addon" title='<?= lang('DevDetail_button_AddIcon_Tooltip');?>'><i class="fa fa-square-plus pointer" onclick="askAddIcon();"></i></span>
|
||||
<span class="input-group-addon" title='<?= lang('DevDetail_button_OverwriteIcons_Tooltip');?>'><i class="fa fa-copy pointer" onclick="askOverwriteIconType();"></i></span>
|
||||
<div class="input-group-btn">
|
||||
@@ -693,7 +693,6 @@ if ($ENABLED_DARKMODE === True) {
|
||||
|
||||
var pos = -1;
|
||||
var parPeriod = 'Front_Details_Period';
|
||||
var parTab = 'Front_Details_Tab';
|
||||
var parSessionsRows = 'Front_Details_Sessions_Rows';
|
||||
var parEventsRows = 'Front_Details_Events_Rows';
|
||||
var parEventsHide = 'Front_Details_Events_Hide';
|
||||
@@ -736,7 +735,7 @@ function main () {
|
||||
$('#chkHideConnectionEvents')[0].checked = eval(eventsHide == 'true');
|
||||
|
||||
// Initialize components with parameters
|
||||
initializeTabs();
|
||||
initializeTabsNew();
|
||||
initializeiCheck();
|
||||
initializeCombos();
|
||||
initializeDatatables();
|
||||
@@ -756,24 +755,13 @@ function main () {
|
||||
|
||||
// Show device icon as it changes
|
||||
$('#txtIcon').on('change input', function() {
|
||||
updateIconPreview('#txtIcon')
|
||||
updateIconPreview(this)
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function initializeTabs () {
|
||||
// Activate panel
|
||||
$('.nav-tabs a[id='+ tab +']').tab('show');
|
||||
|
||||
// When changed save new current tab
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
setParameter (parTab, $(e.target).attr('id'));
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function initializeiCheck () {
|
||||
// Blue
|
||||
@@ -802,7 +790,6 @@ function initializeiCheck () {
|
||||
// Hide / Show Events
|
||||
if (event.currentTarget.id == 'chkHideConnectionEvents') {
|
||||
getDeviceEvents();
|
||||
setParameter (parEventsHide, event.currentTarget.checked);
|
||||
} else {
|
||||
// Activate save & restore
|
||||
// activateSaveRestoreData();
|
||||
@@ -1026,25 +1013,6 @@ function initializeDatatables () {
|
||||
"info": "<?= lang('Events_Table_info');?>",
|
||||
}
|
||||
});
|
||||
|
||||
// Save Parameters rows & order when changed
|
||||
$('#tableSessions').on( 'length.dt', function ( e, settings, len ) {
|
||||
setParameter (parSessionsRows, len);
|
||||
|
||||
// Sync Rows in both datatables
|
||||
// if ( $('#tableEvents').DataTable().page.len() != len) {
|
||||
// $('#tableEvents').DataTable().page.len( len ).draw();
|
||||
// }
|
||||
} );
|
||||
|
||||
$('#tableEvents').on( 'length.dt', function ( e, settings, len ) {
|
||||
setParameter (parEventsRows, len);
|
||||
|
||||
// Sync Rows in both datatables
|
||||
// if ( $('#tableSessions').DataTable().page.len() != len) {
|
||||
// $('#tableSessions').DataTable().page.len( len ).draw();
|
||||
// }
|
||||
} );
|
||||
};
|
||||
|
||||
|
||||
@@ -1148,7 +1116,7 @@ function initializeCalendar () {
|
||||
showSpinner()
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
updateIconPreview('#txtIcon')
|
||||
updateIconPreview($('#txtIcon'))
|
||||
}, 500);
|
||||
|
||||
hideSpinner()
|
||||
@@ -1161,10 +1129,6 @@ function initializeCalendar () {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function periodChanged () {
|
||||
// Save Parameter Period
|
||||
period = $('#period').val();
|
||||
setParameter (parPeriod, period);
|
||||
|
||||
// Requery Device data
|
||||
getDeviceData(true);
|
||||
getSessionsPresenceEvents();
|
||||
@@ -1324,7 +1288,7 @@ function getDeviceData (readAllData=false) {
|
||||
if (deviceData['dev_Favorite'] == 1) {$('#chkFavorite').iCheck('check');} else {$('#chkFavorite').iCheck('uncheck');}
|
||||
$('#txtGroup').val (deviceData['dev_Group']);
|
||||
$('#txtLocation').val (deviceData['dev_Location']);
|
||||
$('#txtComments').val (deviceData['dev_Comments']);
|
||||
$('#txtComments').val (decodeSpecialChars(deviceData['dev_Comments']));
|
||||
$('#txtNetworkNodeMac').val ( networkParentMacName) ;
|
||||
$('#txtNetworkNodeMac').attr ('data-mynodemac', deviceData['dev_Network_Node_MAC_ADDR']);
|
||||
$('#txtNetworkPort').val (deviceData['dev_Network_Node_port']);
|
||||
@@ -1457,15 +1421,15 @@ function setDeviceData (direction='', refreshCallback='') {
|
||||
|
||||
// update data to server
|
||||
$.get('php/server/devices.php?action=setDeviceData&mac='+ mac
|
||||
+ '&name=' + encodeURIComponent($('#txtName').val())
|
||||
+ '&owner=' + encodeURIComponent($('#txtOwner').val())
|
||||
+ '&name=' + encodeURIComponent($('#txtName').val().replace(/'/g, ""))
|
||||
+ '&owner=' + encodeURIComponent($('#txtOwner').val().replace(/'/g, ""))
|
||||
+ '&type=' + $('#txtDeviceType').val()
|
||||
+ '&vendor=' + encodeURIComponent($('#txtVendor').val())
|
||||
+ '&vendor=' + encodeURIComponent($('#txtVendor').val().replace(/'/g, ""))
|
||||
+ '&icon=' + encodeURIComponent($('#txtIcon').val())
|
||||
+ '&favorite=' + ($('#chkFavorite')[0].checked * 1)
|
||||
+ '&group=' + encodeURIComponent($('#txtGroup').val())
|
||||
+ '&location=' + encodeURIComponent($('#txtLocation').val())
|
||||
+ '&comments=' + encodeURIComponent($('#txtComments').val())
|
||||
+ '&comments=' + encodeURIComponent(encodeSpecialChars($('#txtComments').val()))
|
||||
+ '&networknode=' + $('#txtNetworkNodeMac').attr('data-mynodemac')
|
||||
+ '&networknodeport=' + $('#txtNetworkPort').val()
|
||||
+ '&ssid=' + $('#txtSSID').val()
|
||||
@@ -1494,7 +1458,7 @@ function setDeviceData (direction='', refreshCallback='') {
|
||||
somethingChanged = false;
|
||||
|
||||
// refresh API
|
||||
updateApi()
|
||||
updateApi("devices,appevents")
|
||||
|
||||
hideSpinner()
|
||||
|
||||
@@ -1679,7 +1643,7 @@ function addAsBase64 () {
|
||||
|
||||
$('#txtIcon').val(iconHtmlBase64);
|
||||
|
||||
updateIconPreview('#txtIcon')
|
||||
updateIconPreview($('#txtIcon'))
|
||||
|
||||
}
|
||||
|
||||
@@ -1714,7 +1678,7 @@ function deleteDevice () {
|
||||
$('#panDetails :input').attr('disabled', true);
|
||||
|
||||
// refresh API
|
||||
updateApi()
|
||||
updateApi("devices,appevents")
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1843,12 +1807,6 @@ function initTable(tableId, mac){
|
||||
|
||||
$("#"+tableId).attr("data-mac", mac)
|
||||
|
||||
// Save Parameters rows & order when changed
|
||||
$('#'+tableId).on( 'length.dt', function ( e, settings, len ) {
|
||||
setParameter (parSessionsRows, len);
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
<?php
|
||||
|
||||
require 'php/templates/header.php';
|
||||
require 'php/templates/graph.php';
|
||||
|
||||
|
||||
// check permissions
|
||||
$dbPath = "../db/app.db";
|
||||
@@ -66,19 +64,37 @@
|
||||
</div>
|
||||
<script src="js/graph_online_history.js"></script>
|
||||
<script>
|
||||
var pia_js_online_history_time = [<?php pia_graph_devices_data($Pia_Graph_Device_Time); ?>];
|
||||
var pia_js_online_history_ondev = [<?php pia_graph_devices_data($Pia_Graph_Device_Online); ?>];
|
||||
var pia_js_online_history_dodev = [<?php pia_graph_devices_data($Pia_Graph_Device_Down); ?>];
|
||||
var pia_js_online_history_ardev = [<?php pia_graph_devices_data($Pia_Graph_Device_Arch); ?>];
|
||||
|
||||
setTimeout(() => {
|
||||
pia_draw_graph_online_history(
|
||||
pia_js_online_history_time,
|
||||
pia_js_online_history_ondev,
|
||||
pia_js_online_history_dodev,
|
||||
pia_js_online_history_ardev);
|
||||
}, 500);
|
||||
$.get('api/table_online_history.json?nocache=' + Date.now(), function(res) {
|
||||
// Extracting data from the JSON response
|
||||
var timeStamps = [];
|
||||
var onlineCounts = [];
|
||||
var downCounts = [];
|
||||
var offlineCounts = [];
|
||||
var archivedCounts = [];
|
||||
|
||||
res.data.forEach(function(entry) {
|
||||
var dateObj = new Date(entry.Scan_Date);
|
||||
var formattedTime = dateObj.toLocaleTimeString([], {hour: '2-digit', minute: '2-digit', hour12: false});
|
||||
|
||||
timeStamps.push(formattedTime);
|
||||
onlineCounts.push(entry.Online_Devices);
|
||||
downCounts.push(entry.Down_Devices);
|
||||
offlineCounts.push(entry.Offline_Devices);
|
||||
archivedCounts.push(entry.Archived_Devices);
|
||||
});
|
||||
|
||||
// Call your presenceOverTime function after data is ready
|
||||
presenceOverTime(
|
||||
timeStamps,
|
||||
onlineCounts,
|
||||
offlineCounts,
|
||||
archivedCounts,
|
||||
downCounts
|
||||
);
|
||||
}).fail(function() {
|
||||
// Handle any errors in fetching the data
|
||||
console.error('Error fetching online history data.');
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- datatable ------------------------------------------------------------- -->
|
||||
@@ -137,10 +153,8 @@
|
||||
<!-- page script ----------------------------------------------------------- -->
|
||||
<script>
|
||||
var deviceStatus = 'all';
|
||||
var parTableRows = 'Front_Devices_Rows';
|
||||
var parTableOrder = 'Front_Devices_Order';
|
||||
var tableRows = getCookie ("nax_parTableRows") == "" ? 10 : getCookie ("nax_parTableRows") ;
|
||||
var tableOrder = getCookie ("nax_parTableOrder") == "" ? [[3,'desc'], [0,'asc']] : JSON.parse(getCookie ("nax_parTableOrder")) ;
|
||||
var tableOrder = getCookie ("nax_parTableOrder") == "" ? [[3,'desc'], [0,'asc']] : JSON.parse(getCookie ("nax_parTableOrder")) ;
|
||||
|
||||
var tableColumnHide = [];
|
||||
var tableColumnOrder = [];
|
||||
@@ -403,6 +417,11 @@ function initializeDatatable (status) {
|
||||
}
|
||||
|
||||
$.get('api/table_devices.json?nocache=' + Date.now(), function(result) {
|
||||
|
||||
// refresh devices cache
|
||||
devicesListAll_JSON = result["data"]
|
||||
devicesListAll_JSON_str = JSON.stringify(devicesListAll_JSON)
|
||||
setCache('devicesListAll_JSON', devicesListAll_JSON_str)
|
||||
|
||||
// query data
|
||||
getDevicesTotals(result.data);
|
||||
@@ -451,10 +470,6 @@ function initializeDatatable (status) {
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
// TODO displayed columns
|
||||
|
||||
|
||||
// Check if the DataTable already exists
|
||||
if ($.fn.dataTable.isDataTable('#tableDevices')) {
|
||||
// The DataTable exists, so destroy it
|
||||
@@ -462,12 +477,12 @@ function initializeDatatable (status) {
|
||||
table.clear().destroy();
|
||||
}
|
||||
|
||||
var table=
|
||||
var table =
|
||||
$('#tableDevices').DataTable({
|
||||
'data' : dataArray["data"],
|
||||
'paging' : true,
|
||||
'lengthChange' : true,
|
||||
'lengthMenu' : [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
|
||||
'lengthMenu' : [[10, 25, 50, 100, 500, 100000], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
|
||||
'searching' : true,
|
||||
|
||||
'ordering' : true,
|
||||
@@ -615,11 +630,11 @@ function initializeDatatable (status) {
|
||||
|
||||
// Save cookie Rows displayed, and Parameters rows & order
|
||||
$('#tableDevices').on( 'length.dt', function ( e, settings, len ) {
|
||||
setCookie ("nax_parTableRows", len);
|
||||
setCookie ("nax_parTableRows", len, 129600); // save for 90 days
|
||||
} );
|
||||
|
||||
$('#tableDevices').on( 'order.dt', function () {
|
||||
setCookie ("nax_parTableOrder", JSON.stringify (table.order()) );
|
||||
setCookie ("nax_parTableOrder", JSON.stringify (table.order()), 129600); // save for 90 days
|
||||
setCache ('devicesList', getDevicesFromTable(table) );
|
||||
} );
|
||||
|
||||
@@ -639,8 +654,6 @@ function initializeDatatable (status) {
|
||||
// Check if any row is selected
|
||||
var anyRowSelected = $('#tableDevices tr.selected').length > 0;
|
||||
|
||||
console.log(anyRowSelected);
|
||||
|
||||
// Toggle visibility of element with ID 'multiEdit'
|
||||
$('#multiEdit').toggle(anyRowSelected);
|
||||
}, 200);
|
||||
|
||||
@@ -183,43 +183,31 @@
|
||||
|
||||
<!-- page script ----------------------------------------------------------- -->
|
||||
<script>
|
||||
var parPeriod = 'Front_Events_Period';
|
||||
var parTableRows = 'Front_Events_Rows';
|
||||
var parPeriod = 'nax_parPeriod';
|
||||
var parTableRows = 'nax_parTableRows';
|
||||
|
||||
var eventsType = 'all';
|
||||
var period = '';
|
||||
var tableRows = 10;
|
||||
var period = '1 day';
|
||||
var tableRows = 25;
|
||||
|
||||
// Read parameters & Initialize components
|
||||
main();
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function main () {
|
||||
// get parameter value
|
||||
$.get('php/server/parameters.php?action=get&defaultValue=1 day¶meter='+ parPeriod, function(data) {
|
||||
var result = JSON.parse(data);
|
||||
if (result) {
|
||||
period = result;
|
||||
$('#period').val(period);
|
||||
}
|
||||
function main() {
|
||||
// Get parameter value from cookies instead of server
|
||||
period = getCookie(parPeriod) === "" ? "1 day" : getCookie(parPeriod);
|
||||
$('#period').val(period);
|
||||
|
||||
// get parameter value
|
||||
$.get('php/server/parameters.php?action=get&defaultValue=50¶meter='+ parTableRows, function(data) {
|
||||
var result = JSON.parse(data);
|
||||
result = parseInt(result, 10)
|
||||
if (Number.isInteger (result) ) {
|
||||
tableRows = result;
|
||||
}
|
||||
tableRows = getCookie(parTableRows) === "" ? 50 : parseInt(getCookie(parTableRows), 10);
|
||||
|
||||
// Initialize components
|
||||
initializeDatatable();
|
||||
// Initialize components
|
||||
initializeDatatable();
|
||||
|
||||
// query data
|
||||
getEventsTotals();
|
||||
getEvents (eventsType);
|
||||
});
|
||||
});
|
||||
// Query data
|
||||
getEventsTotals();
|
||||
getEvents(eventsType);
|
||||
}
|
||||
|
||||
|
||||
@@ -281,7 +269,7 @@ function initializeDatatable () {
|
||||
|
||||
// Save Parameter rows when changed
|
||||
$('#tableEvents').on( 'length.dt', function ( e, settings, len ) {
|
||||
setParameter (parTableRows, len);
|
||||
setCookie(parTableRows, len)
|
||||
} );
|
||||
};
|
||||
|
||||
@@ -290,7 +278,8 @@ function initializeDatatable () {
|
||||
function periodChanged () {
|
||||
// Save Parameter Period
|
||||
period = $('#period').val();
|
||||
setParameter (parPeriod, period);
|
||||
|
||||
setCookie(parTableRows, period)
|
||||
|
||||
// Requery totals and events
|
||||
getEventsTotals();
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
|
||||
<?php
|
||||
require dirname(__FILE__).'/php/server/init.php';
|
||||
require 'php/templates/security.php';
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
$CookieSaveLoginName = 'NetAlertX_SaveLogin';
|
||||
|
||||
if ($Pia_WebProtection != 'true')
|
||||
if ($nax_WebProtection != 'true')
|
||||
{
|
||||
header('Location: devices.php');
|
||||
$_SESSION["login"] = 1;
|
||||
@@ -24,7 +26,7 @@ if (isset ($_GET["action"]) && $_GET["action"] == 'logout')
|
||||
}
|
||||
|
||||
// Password without Cookie check -> pass and set initial cookie
|
||||
if (isset ($_POST["loginpassword"]) && $Pia_Password == hash('sha256',$_POST["loginpassword"]))
|
||||
if (isset ($_POST["loginpassword"]) && $nax_Password == hash('sha256',$_POST["loginpassword"]))
|
||||
{
|
||||
header('Location: devices.php');
|
||||
$_SESSION["login"] = 1;
|
||||
@@ -32,7 +34,7 @@ if (isset ($_POST["loginpassword"]) && $Pia_Password == hash('sha256',$_POST["lo
|
||||
}
|
||||
|
||||
// active Session or valid cookie (cookie not extends)
|
||||
if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOKIE[$CookieSaveLoginName]) && $Pia_Password == $_COOKIE[$CookieSaveLoginName]))
|
||||
if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOKIE[$CookieSaveLoginName]) && $nax_Password == $_COOKIE[$CookieSaveLoginName]))
|
||||
{
|
||||
header('Location: devices.php');
|
||||
$_SESSION["login"] = 1;
|
||||
@@ -40,7 +42,7 @@ if (( isset ($_SESSION["login"]) && ($_SESSION["login"] == 1)) || (isset ($_COOK
|
||||
}
|
||||
|
||||
$login_headline = lang('Login_Toggle_Info_headline');
|
||||
$login_info = "";
|
||||
$login_info = lang('Login_Info');
|
||||
$login_mode = 'danger';
|
||||
$login_display_mode = 'display: block;';
|
||||
$login_icon = 'fa-info';
|
||||
@@ -48,7 +50,7 @@ $login_icon = 'fa-info';
|
||||
// no active session, cookie not checked
|
||||
if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1)
|
||||
{
|
||||
if ($Pia_Password == '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92')
|
||||
if ($nax_Password == '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92')
|
||||
{
|
||||
$login_info = lang('Login_Default_PWD');
|
||||
$login_mode = 'danger';
|
||||
@@ -78,7 +80,7 @@ if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1)
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Net Alert X | Log in</title>
|
||||
<title>NetAlert X | Log in</title>
|
||||
<!-- Tell the browser to be responsive to screen width -->
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<!-- Bootstrap 3.3.7 -->
|
||||
@@ -91,6 +93,13 @@ if (isset ($_SESSION["login"]) == FALSE || $_SESSION["login"] != 1)
|
||||
<link rel="stylesheet" href="lib/AdminLTE/dist/css/AdminLTE.min.css">
|
||||
<!-- iCheck -->
|
||||
<link rel="stylesheet" href="lib/AdminLTE/plugins/iCheck/square/blue.css">
|
||||
<!-- Font Awesome -->
|
||||
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/fontawesome.min.css">
|
||||
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/solid.css">
|
||||
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/brands.css">
|
||||
<link rel="stylesheet" href="lib/AdminLTE/bower_components/font-awesome/css/v5-font-face.css">
|
||||
<!-- Favicon -->
|
||||
<link id="favicon" rel="icon" type="image/x-icon" href="img/NetAlertX_logo.png">
|
||||
|
||||
<!-- Dark-Mode Patch -->
|
||||
<?php
|
||||
@@ -104,7 +113,7 @@ if ($ENABLED_DARKMODE === True) {
|
||||
<body class="hold-transition login-page">
|
||||
<div class="login-box login-custom">
|
||||
<div class="login-logo">
|
||||
<a href="/index2.php">Net <b>Alert</b><sup>x</sup></a>
|
||||
<a href="/index2.php">Net<b>Alert</b><sup>x</sup></a>
|
||||
</div>
|
||||
<!-- /.login-logo -->
|
||||
<div class="login-box-body">
|
||||
@@ -140,11 +149,9 @@ if ($ENABLED_DARKMODE === True) {
|
||||
</div>
|
||||
<!-- /.login-box-body -->
|
||||
|
||||
|
||||
|
||||
<div id="myDIV" class="box-body" style="margin-top: 50px; <?php echo $login_display_mode;?>">
|
||||
<div class="alert alert-<?php echo $login_mode;?> alert-dismissible">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true"><EFBFBD></button>
|
||||
<button type="button" class="close" onclick="Passwordhinfo()" aria-hidden="true">X</button>
|
||||
<h4><i class="icon fa <?php echo $login_icon;?>"></i><?php echo $login_headline;?></h4>
|
||||
<p><?php echo $login_info;?></p>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ var timerRefreshData = ''
|
||||
|
||||
var emptyArr = ['undefined', "", undefined, null, 'null'];
|
||||
var UI_LANG = "English";
|
||||
const allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "it_it", "ru_ru", "nb_no", "pl_pl", "pt_br", "tr_tr", "zh_cn", "cs_cz"]; // needs to be same as in lang.php
|
||||
const allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "it_it", "ru_ru", "nb_no", "pl_pl", "pt_br", "tr_tr", "zh_cn", "cs_cz", "ar_ar"]; // needs to be same as in lang.php
|
||||
var settingsJSON = {}
|
||||
|
||||
|
||||
@@ -212,7 +212,8 @@ function cacheStrings() {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
// Create a promise for each language
|
||||
const languagePromises = allLanguages.map((language_code) => {
|
||||
languagesToLoad = ['en_us', getLangCode()]
|
||||
const languagePromises = languagesToLoad.map((language_code) => {
|
||||
return new Promise((resolveLang, rejectLang) => {
|
||||
// Fetch core strings and translations
|
||||
|
||||
@@ -267,6 +268,30 @@ function cacheStrings() {
|
||||
function getString(key) {
|
||||
|
||||
function fetchString(key) {
|
||||
|
||||
lang_code = getLangCode();
|
||||
|
||||
let result = getCache(`pia_lang_${key}_${lang_code}`, true);
|
||||
|
||||
if (isEmpty(result)) {
|
||||
result = getCache(`pia_lang_${key}_en_us`, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (isAppInitialized()) {
|
||||
return fetchString(key);
|
||||
} else {
|
||||
callAfterAppInitialized(() => fetchString(key));
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Get current language ISO code
|
||||
// below has to match exactly teh values in /front/php/templates/language/lang.php & /front/js/common.js
|
||||
function getLangCode() {
|
||||
|
||||
UI_LANG = getSetting("UI_LANG");
|
||||
|
||||
let lang_code = 'en_us';
|
||||
@@ -308,22 +333,12 @@ function getString(key) {
|
||||
case 'Czech (cs_cz)':
|
||||
lang_code = 'cs_cz';
|
||||
break;
|
||||
case 'Arabic (ar_ar)':
|
||||
lang_code = 'ar_ar';
|
||||
break;
|
||||
}
|
||||
|
||||
let result = getCache(`pia_lang_${key}_${lang_code}`, true);
|
||||
|
||||
if (isEmpty(result)) {
|
||||
result = getCache(`pia_lang_${key}_en_us`, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (isAppInitialized()) {
|
||||
return fetchString(key);
|
||||
} else {
|
||||
callAfterAppInitialized(() => fetchString(key));
|
||||
}
|
||||
return lang_code;
|
||||
}
|
||||
|
||||
|
||||
@@ -331,6 +346,8 @@ function getString(key) {
|
||||
// -----------------------------------------------------------------------------
|
||||
// String utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------
|
||||
function jsonSyntaxHighlight(json) {
|
||||
if (typeof json != 'string') {
|
||||
json = JSON.stringify(json, undefined, 2);
|
||||
@@ -353,6 +370,7 @@ function jsonSyntaxHighlight(json) {
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
function isValidBase64(str) {
|
||||
// Base64 characters set
|
||||
var base64CharacterSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
||||
@@ -362,7 +380,7 @@ function isValidBase64(str) {
|
||||
return invalidCharacters === '';
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
function isValidJSON(jsonString) {
|
||||
try {
|
||||
JSON.parse(jsonString);
|
||||
@@ -372,6 +390,37 @@ function isValidJSON(jsonString) {
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// method to sanitize input so that HTML and other things don't break
|
||||
function encodeSpecialChars(str) {
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
// ----------------------------------------------------
|
||||
function decodeSpecialChars(str) {
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, '\'');
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// base64 conversion of UTF8 chars
|
||||
function utf8ToBase64(str) {
|
||||
// Convert the string to a Uint8Array using TextEncoder
|
||||
const utf8Bytes = new TextEncoder().encode(str);
|
||||
|
||||
// Convert the Uint8Array to a base64-encoded string
|
||||
return btoa(String.fromCharCode(...utf8Bytes));
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// General utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -412,29 +461,6 @@ function numberArrayFromString(data)
|
||||
return data.replace(/\[|\]/g, '').split(',').map(Number);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function setParameter (parameter, value) {
|
||||
// Retry
|
||||
$.get('php/server/parameters.php?action=set¶meter=' + parameter +
|
||||
'&value='+ value,
|
||||
function(data) {
|
||||
if (data != "OK") {
|
||||
// Retry
|
||||
sleep (200);
|
||||
$.get('php/server/parameters.php?action=set¶meter=' + parameter +
|
||||
'&value='+ value,
|
||||
function(data) {
|
||||
if (data != "OK") {
|
||||
// alert (data);
|
||||
} else {
|
||||
// alert ("OK. Second attempt");
|
||||
};
|
||||
} );
|
||||
};
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function saveData(functionName, id, value) {
|
||||
$.ajax({
|
||||
@@ -619,17 +645,11 @@ function debugTimer () {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function secondsSincePageLoad() {
|
||||
// Get the current time
|
||||
var currentTime = Date.now();
|
||||
|
||||
// Get the time when the page was loaded
|
||||
var pageLoadTime = performance.timeOrigin;
|
||||
|
||||
// Calculate the difference in milliseconds
|
||||
var timeDifference = currentTime - pageLoadTime;
|
||||
// Get the current time since the page was loaded
|
||||
var timeSincePageLoad = performance.now();
|
||||
|
||||
// Convert milliseconds to seconds
|
||||
var secondsAgo = Math.floor(timeDifference / 1000);
|
||||
var secondsAgo = Math.floor(timeSincePageLoad / 1000);
|
||||
|
||||
return secondsAgo;
|
||||
}
|
||||
@@ -990,11 +1010,11 @@ function hideSpinner()
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Calls a backend function to add a front-end event to an execution queue
|
||||
function updateApi()
|
||||
function updateApi(apiEndpoints)
|
||||
{
|
||||
|
||||
// value has to be in format event|param. e.g. run|ARPSCAN
|
||||
action = `${getGuid()}|update_api|devices,appevents`
|
||||
action = `${getGuid()}|update_api|${apiEndpoints}`
|
||||
|
||||
|
||||
$.ajax({
|
||||
@@ -1193,7 +1213,7 @@ const sessionStorageKey = "myScriptExecuted_common_js";
|
||||
var completedCalls = []
|
||||
var completedCalls_final = ['cacheSettings', 'cacheStrings', 'cacheDevices'];
|
||||
var completedCallsCount = 0;
|
||||
var completedCallsCount_final = allLanguages.length + 2; // number of language files + cacheDevices + cacheSettings
|
||||
var completedCallsCount_final;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Clearing all the caches
|
||||
@@ -1249,6 +1269,10 @@ function callAfterAppInitialized(callback) {
|
||||
// Check if the code has been executed before by checking sessionStorage
|
||||
function isAppInitialized() {
|
||||
// return arraysContainSameValues(getCache("completedCalls").split(',').filter(Boolean), completedCalls_final);
|
||||
|
||||
// loading settings + 1 (or 2 language files if not english) + device cache.
|
||||
completedCallsCount_final = getLangCode() == 'en_us' ? 3 : 4 ;
|
||||
|
||||
return (parseInt(getCache("completedCallsCount")) >= completedCallsCount_final);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
function pia_draw_graph_online_history(pia_js_graph_online_history_time, pia_js_graph_online_history_ondev, pia_js_graph_online_history_dodev, pia_js_graph_online_history_ardev) {
|
||||
var xValues = pia_js_graph_online_history_time;
|
||||
|
||||
// alert("dev presence")
|
||||
function presenceOverTime(
|
||||
timeStamp,
|
||||
onlineCount,
|
||||
offlineCount,
|
||||
archivedCount,
|
||||
downCount
|
||||
) {
|
||||
var xValues = timeStamp;
|
||||
|
||||
// Data object for online status
|
||||
onlineData = {
|
||||
label: 'Online',
|
||||
data: pia_js_graph_online_history_ondev,
|
||||
borderColor: "rgba(0, 166, 89)",
|
||||
data: onlineCount,
|
||||
borderColor: "#00000",
|
||||
fill: true,
|
||||
backgroundColor: "rgba(0, 166, 89, .6)",
|
||||
pointStyle: 'circle',
|
||||
@@ -15,20 +19,29 @@ function pia_draw_graph_online_history(pia_js_graph_online_history_time, pia_js_
|
||||
pointHoverRadius: 3
|
||||
};
|
||||
|
||||
// Data object for down status
|
||||
downData = {
|
||||
label: 'Down',
|
||||
data: downCount,
|
||||
borderColor: "#00000",
|
||||
fill: true,
|
||||
backgroundColor: "#dd4b39",
|
||||
};
|
||||
|
||||
// Data object for offline status
|
||||
offlineData = {
|
||||
label: 'Offline/Down',
|
||||
data: pia_js_graph_online_history_dodev,
|
||||
borderColor: "rgba(222, 74, 56)",
|
||||
label: 'Offline',
|
||||
data: offlineCount,
|
||||
borderColor: "#00000",
|
||||
fill: true,
|
||||
backgroundColor: "rgba(222, 74, 56, .6)",
|
||||
backgroundColor: "#b2b6be",
|
||||
};
|
||||
|
||||
// Data object for archived status
|
||||
archivedData = {
|
||||
label: 'Archived',
|
||||
data: pia_js_graph_online_history_ardev,
|
||||
borderColor: "rgba(220,220,220)",
|
||||
data: archivedCount,
|
||||
borderColor: "#00000",
|
||||
fill: true,
|
||||
backgroundColor: "rgba(220,220,220, .6)",
|
||||
};
|
||||
@@ -42,23 +55,27 @@ function pia_draw_graph_online_history(pia_js_graph_online_history_time, pia_js_
|
||||
// Check if 'online' status should be displayed
|
||||
if(showStats.includes("online"))
|
||||
{
|
||||
datasets.push(onlineData); // Add onlineData to datasets array
|
||||
datasets.push(onlineData);
|
||||
}
|
||||
|
||||
// Check if 'down' status should be displayed
|
||||
if(showStats.includes("down"))
|
||||
{
|
||||
datasets.push(downData);
|
||||
}
|
||||
|
||||
// Check if 'offline' status should be displayed
|
||||
if(showStats.includes("offline"))
|
||||
{
|
||||
datasets.push(offlineData); // Add offlineData to datasets array
|
||||
datasets.push(offlineData);
|
||||
}
|
||||
|
||||
// Check if 'archived' status should be displayed
|
||||
if(showStats.includes("archived"))
|
||||
{
|
||||
datasets.push(archivedData); // Add archivedData to datasets array
|
||||
datasets.push(archivedData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
new Chart("OnlineChart", {
|
||||
type: "bar",
|
||||
scaleIntegersOnly: true,
|
||||
|
||||
@@ -295,6 +295,7 @@ function checkNotification() {
|
||||
console.log(response);
|
||||
// After marking the notification as read, check for the next one
|
||||
checkNotification();
|
||||
hideSpinner();
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("Error marking notification as read:", status, error);
|
||||
|
||||
@@ -502,33 +502,6 @@ setTimeout(() => {
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// handling events on the backend initiated by the front end END
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// UNUSED?
|
||||
function getParam(targetId, key, skipCache = false) {
|
||||
skipCacheQuery = "";
|
||||
|
||||
if (skipCache) {
|
||||
skipCacheQuery = "&skipcache";
|
||||
}
|
||||
|
||||
// get parameter value
|
||||
$.get(
|
||||
"php/server/parameters.php?action=get&defaultValue=0¶meter=" +
|
||||
key +
|
||||
skipCacheQuery,
|
||||
function (data) {
|
||||
var result = data;
|
||||
|
||||
result = result.replaceAll('"', "");
|
||||
|
||||
document.getElementById(targetId).innerHTML = result.replaceAll('"', "");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Show/hide the metadata settings
|
||||
@@ -539,6 +512,17 @@ function toggleMetadata(element) {
|
||||
$(`#${id}`).toggle();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Show setting description in a modal on smaller screens
|
||||
// -----------------------------------------------------------------------------
|
||||
function showDescription(element) {
|
||||
const id = $(element).attr("my-to-show");
|
||||
|
||||
description = $(`${id}`)[0].innerHTML
|
||||
console.log(description);
|
||||
showModalOK(getString("Gen_Description"), description);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Helper methods
|
||||
// ---------------------------------------------------------
|
||||
@@ -667,7 +651,11 @@ const handleElementOptions = (codeName, elementOptions, transformers, val) => {
|
||||
let valRes = val;
|
||||
let sourceIds = [];
|
||||
let getStringKey = "";
|
||||
let onClick = "alert('Not implemented');";
|
||||
let onClick = "console.log('onClick - Not implemented');";
|
||||
let onChange = "console.log('onChange - Not implemented');";
|
||||
let customParams = "";
|
||||
let customId = "";
|
||||
|
||||
|
||||
elementOptions.forEach((option) => {
|
||||
if (option.prefillValue) {
|
||||
@@ -711,6 +699,15 @@ const handleElementOptions = (codeName, elementOptions, transformers, val) => {
|
||||
if (option.onClick) {
|
||||
onClick = option.onClick;
|
||||
}
|
||||
if (option.onChange) {
|
||||
onChange = option.onChange;
|
||||
}
|
||||
if (option.customParams) {
|
||||
customParams = option.customParams;
|
||||
}
|
||||
if (option.customId) {
|
||||
customId = option.customId;
|
||||
}
|
||||
});
|
||||
|
||||
if (transformers.includes("sha256")) {
|
||||
@@ -731,6 +728,9 @@ const handleElementOptions = (codeName, elementOptions, transformers, val) => {
|
||||
valRes,
|
||||
getStringKey,
|
||||
onClick,
|
||||
onChange,
|
||||
customParams,
|
||||
customId
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -68,23 +68,66 @@ function initDeviceSelectors(devicesListAll_JSON) {
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ----------------------------------------------
|
||||
// Updates the icon preview
|
||||
function updateIconPreview (inputId) {
|
||||
// update icon
|
||||
iconInput = $(inputId)
|
||||
function updateIconPreview(elem) {
|
||||
// Retrieve and parse custom parameters from the element
|
||||
let params = $(elem).attr("my-customparams")?.split(',').map(param => param.trim());
|
||||
|
||||
value = iconInput.val()
|
||||
// console.log(params);
|
||||
|
||||
iconInput.on('change input', function() {
|
||||
$('#txtIconFA').html(atob(value))
|
||||
});
|
||||
if (params && params.length >= 2) {
|
||||
var inputElementID = params[0];
|
||||
var targetElementID = params[1];
|
||||
} else {
|
||||
console.error("Invalid parameters passed to updateIconPreview function");
|
||||
return;
|
||||
}
|
||||
|
||||
$('#txtIconFA').html(atob(value))
|
||||
|
||||
// Get the input element using the inputElementID
|
||||
let iconInput = $("#" + inputElementID);
|
||||
|
||||
if (iconInput.length === 0) {
|
||||
console.error("Icon input element not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the initial value and update the target element
|
||||
let value = iconInput.val();
|
||||
if (!value) {
|
||||
console.error("Input value is empty or not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!targetElementID) {
|
||||
targetElementID = "txtIcon";
|
||||
}
|
||||
|
||||
// Check if the target element exists, if not find an element with matching custom attribute
|
||||
let targetElement = $('#' + targetElementID);
|
||||
if (targetElement.length === 0) {
|
||||
// Look for an element with my-custom-id attribute equal to targetElementID
|
||||
targetElement = $('[my-customid="' + targetElementID + '"]');
|
||||
if (targetElement.length === 0) {
|
||||
console.error("Neither target element with ID nor element with custom attribute found");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the target element with decoded base64 value
|
||||
targetElement.html(atob(value));
|
||||
|
||||
// Add event listener to update the icon on input change
|
||||
iconInput.on('change input', function () {
|
||||
let newValue = $(this).val();
|
||||
$('#' + targetElementID).html(atob(newValue));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Generic function to copy text to clipboard
|
||||
function copyToClipboard(buttonElement) {
|
||||
|
||||
@@ -1034,7 +1034,7 @@ var mouse = $.widget("ui.mouse", {
|
||||
return this.mouseDelayMet;
|
||||
},
|
||||
|
||||
// These are placeholder methods, to be overriden by extending plugin
|
||||
// These are placeholder methods, to be overridden by extending plugin
|
||||
_mouseStart: function(/* event */) {},
|
||||
_mouseDrag: function(/* event */) {},
|
||||
_mouseStop: function(/* event */) {},
|
||||
|
||||
@@ -39,46 +39,17 @@
|
||||
|
||||
// Size and last mod of DB ------------------------------------------------------
|
||||
|
||||
$pia_db = str_replace('front', 'db', getcwd()).'/app.db';
|
||||
$pia_db_size = number_format((filesize($pia_db) / 1000000),2,",",".") . ' MB';
|
||||
$pia_db_mod = date ("F d Y H:i:s", filemtime($pia_db));
|
||||
$nax_db = str_replace('front', 'db', getcwd()).'/app.db';
|
||||
$nax_db_size = number_format((filesize($nax_db) / 1000000),2,",",".") . ' MB';
|
||||
$nax_db_mod = date ("F d Y H:i:s", filemtime($nax_db));
|
||||
|
||||
|
||||
// Count and Calc Backups -------------------------------------------------------
|
||||
|
||||
$Pia_Archive_Path = str_replace('front', 'db', getcwd()).'/';
|
||||
$Pia_Archive_count = 0;
|
||||
$Pia_Archive_diskusage = 0;
|
||||
$files = glob($Pia_Archive_Path."appdb_*.zip");
|
||||
if ($files){
|
||||
$Pia_Archive_count = count($files);
|
||||
}
|
||||
foreach ($files as $result) {
|
||||
$Pia_Archive_diskusage = $Pia_Archive_diskusage + filesize($result);
|
||||
}
|
||||
$Pia_Archive_diskusage = number_format(($Pia_Archive_diskusage / 1000000),2,",",".") . ' MB';
|
||||
|
||||
// Find latest Backup for restore -----------------------------------------------
|
||||
|
||||
$latestfiles = glob($Pia_Archive_Path."appdb_*.zip");
|
||||
natsort($latestfiles);
|
||||
$latestfiles = array_reverse($latestfiles,False);
|
||||
|
||||
$latestbackup = 'none';
|
||||
$latestbackup_date = 'no backup';
|
||||
|
||||
if (count($latestfiles) > 0)
|
||||
{
|
||||
$latestbackup = $latestfiles[0];
|
||||
$latestbackup_date = date ("Y-m-d H:i:s", filemtime($latestbackup));
|
||||
}
|
||||
|
||||
// Table sizes -----------------------------------------------------------------
|
||||
|
||||
$tableSizesHTML = "";
|
||||
|
||||
// Open a connection to the SQLite database
|
||||
$db = new SQLite3($pia_db);
|
||||
$db = new SQLite3($nax_db);
|
||||
|
||||
// Retrieve the table names from sqlite_master
|
||||
$query = "SELECT name FROM sqlite_master WHERE type='table'";
|
||||
@@ -133,13 +104,13 @@ $db->close();
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell" style="min-width: 140px"><?= lang('Maintenance_database_path');?></div>
|
||||
<div class="db_info_table_cell">
|
||||
<?php echo $pia_db;?>
|
||||
<?php echo $nax_db;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell"><?= lang('Maintenance_database_size');?></div>
|
||||
<div class="db_info_table_cell">
|
||||
<?php echo $pia_db_size;?>
|
||||
<?php echo $nax_db_size;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
@@ -151,15 +122,9 @@ $db->close();
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell"><?= lang('Maintenance_database_lastmod');?></div>
|
||||
<div class="db_info_table_cell">
|
||||
<?php echo $pia_db_mod;?>
|
||||
<?php echo $nax_db_mod;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell"><?= lang('Maintenance_database_backup');?></div>
|
||||
<div class="db_info_table_cell">
|
||||
<?php echo $Pia_Archive_count.' '.lang('Maintenance_database_backup_found').' / '.lang('Maintenance_database_backup_total').': '.$Pia_Archive_diskusage;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
@@ -254,25 +219,7 @@ $db->close();
|
||||
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnImportPastedCSV" onclick="askImportPastedCSV()"><?= lang('Maintenance_Tool_ImportPastedCSV');?></button>
|
||||
</div>
|
||||
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_ImportPastedCSV_text');?></div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_tools_table_cell_a" >
|
||||
<button type="button" class="btn btn-default pa-btn bg-green dbtools-button" id="btnPiaBackupDBtoArchive" onclick="askPiaBackupDBtoArchive()"><?= lang('Maintenance_Tool_backup');?></button>
|
||||
</div>
|
||||
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_backup_text');?></div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_tools_table_cell_a" >
|
||||
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnPiaRestoreDBfromArchive" onclick="askPiaRestoreDBfromArchive()"><?= lang('Maintenance_Tool_restore');?><br><?php echo $latestbackup_date;?></button>
|
||||
</div>
|
||||
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_restore_text');?></div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_tools_table_cell_a" >
|
||||
<button type="button" class="btn btn-default pa-btn pa-btn-delete bg-red dbtools-button" id="btnPiaPurgeDBBackups" onclick="askPiaPurgeDBBackups()"><?= lang('Maintenance_Tool_purgebackup');?></button>
|
||||
</div>
|
||||
<div class="db_tools_table_cell_b"><?= lang('Maintenance_Tool_purgebackup_text');?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ---------------------------Logging-------------------------------------------- -->
|
||||
@@ -458,51 +405,6 @@ function deleteActHistory()
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Backup DB to Archive
|
||||
function askPiaBackupDBtoArchive () {
|
||||
// Ask
|
||||
showModalWarning('<?= lang('Maintenance_Tool_backup_noti');?>', '<?= lang('Maintenance_Tool_backup_noti_text');?>',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Backup');?>', 'PiaBackupDBtoArchive');
|
||||
}
|
||||
function PiaBackupDBtoArchive()
|
||||
{
|
||||
// Execute
|
||||
$.get('php/server/devices.php?action=PiaBackupDBtoArchive', function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Restore DB from Archive
|
||||
function askPiaRestoreDBfromArchive () {
|
||||
// Ask
|
||||
showModalWarning('<?= lang('Maintenance_Tool_restore_noti');?>', '<?= lang('Maintenance_Tool_restore_noti_text');?>',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Restore');?>', 'PiaRestoreDBfromArchive');
|
||||
}
|
||||
function PiaRestoreDBfromArchive()
|
||||
{
|
||||
// Execute
|
||||
$.get('php/server/devices.php?action=PiaRestoreDBfromArchive', function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Purge Backups
|
||||
function askPiaPurgeDBBackups() {
|
||||
// Ask
|
||||
showModalWarning('<?= lang('Maintenance_Tool_purgebackup_noti');?>', '<?= lang('Maintenance_Tool_purgebackup_noti_text');?>',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Purge');?>', 'PiaPurgeDBBackups');
|
||||
}
|
||||
function PiaPurgeDBBackups()
|
||||
{
|
||||
// Execute
|
||||
$.get('php/server/devices.php?action=PiaPurgeDBBackups', function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Restart Backend Python Server
|
||||
|
||||
@@ -571,12 +473,15 @@ function askImportPastedCSV() {
|
||||
function ImportPastedCSV()
|
||||
{
|
||||
var csv = $('#modal-input-textarea').val();
|
||||
csvBase64 = btoa(csv)
|
||||
// Execute
|
||||
|
||||
csvBase64 = utf8ToBase64(csv);
|
||||
|
||||
$.post('php/server/devices.php?action=ImportCSV', { content: csvBase64 }, function(msg) {
|
||||
showMessage(msg);
|
||||
write_notification(`[Maintenance] Devices imported from pasted content`, 'info');
|
||||
showMessage(msg);
|
||||
write_notification(`[Maintenance] Devices imported from pasted content`, 'info');
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -101,19 +101,20 @@
|
||||
for (let j = i * elementsPerColumn; j < Math.min((i + 1) * elementsPerColumn, columns.length); j++) {
|
||||
|
||||
const setTypeObject = JSON.parse(columns[j].Type.replace(/'/g, '"'));
|
||||
// console.log(setTypeObject); 🔽
|
||||
// const lastElementObj = setTypeObject.elements[setTypeObject.elements.length - 1]
|
||||
|
||||
// get the element with the input value(s)
|
||||
let elementsWithInputValue = setTypeObject.elements.filter(element => element.elementHasInputValue === 1);
|
||||
let elements = setTypeObject.elements.filter(element => element.elementHasInputValue === 1);
|
||||
|
||||
// if none found, take last
|
||||
if(elementsWithInputValue.length == 0)
|
||||
if(elements.length == 0)
|
||||
{
|
||||
elementsWithInputValue = setTypeObject.elements[setTypeObject.elements.length - 1]
|
||||
elementWithInputValue = setTypeObject.elements[setTypeObject.elements.length - 1]
|
||||
} else
|
||||
{
|
||||
elementWithInputValue = elements[0]
|
||||
}
|
||||
|
||||
const { elementType, elementOptions = [], transformers = [] } = elementsWithInputValue;
|
||||
const { elementType, elementOptions = [], transformers = [] } = elementWithInputValue;
|
||||
const {
|
||||
inputType,
|
||||
readOnly,
|
||||
@@ -127,26 +128,28 @@
|
||||
editable,
|
||||
valRes,
|
||||
getStringKey,
|
||||
onClick
|
||||
onClick,
|
||||
onChange,
|
||||
customParams,
|
||||
customId
|
||||
} = handleElementOptions('none', elementOptions, transformers, val = "");
|
||||
|
||||
// console.log(setTypeObject);
|
||||
// console.log(inputType);
|
||||
|
||||
// render based on element type
|
||||
if (elementsWithInputValue.elementType === 'select') {
|
||||
if (elementType === 'select') {
|
||||
|
||||
targetLocation = columns[j].Code_Name + "_generateSetOptions"
|
||||
|
||||
generateOptionsOrSetOptions(columns[j].Code_Name, [], targetLocation, generateOptions)
|
||||
|
||||
// Handle Icons as tehy need a preview
|
||||
console.log(columns[j].Code_Name)
|
||||
// Handle Icons as they need a preview
|
||||
if(columns[j].Code_Name == 'NEWDEV_dev_Icon')
|
||||
{
|
||||
input = `
|
||||
<span class="input-group-addon" id="txtIconFA"></span>
|
||||
<span class="input-group-addon iconPreview" my-customid="NEWDEV_dev_Icon_preview"></span>
|
||||
<select class="form-control"
|
||||
onChange="updateIconPreview('#NEWDEV_dev_Icon')"
|
||||
onChange="updateIconPreview(this)"
|
||||
my-customparams="NEWDEV_dev_Icon,NEWDEV_dev_Icon_preview"
|
||||
id="${columns[j].Code_Name}"
|
||||
data-my-column="${columns[j].Code_Name}"
|
||||
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}" >
|
||||
@@ -164,7 +167,7 @@
|
||||
}
|
||||
|
||||
|
||||
} else if (elementsWithInputValue.elementType === 'input'){
|
||||
} else if (elementType === 'input'){
|
||||
|
||||
// Add classes specifically for checkboxes
|
||||
inputType === 'checkbox' ? inputClass = 'checkbox' : inputClass = 'form-control';
|
||||
@@ -172,6 +175,7 @@
|
||||
|
||||
input = `<input class="${inputClass}"
|
||||
id="${columns[j].Code_Name}"
|
||||
my-customid="${columns[j].Code_Name}"
|
||||
data-my-column="${columns[j].Code_Name}"
|
||||
data-my-targetColumns="${columns[j].Code_Name.replace('NEWDEV_','')}"
|
||||
type="${inputType}">`
|
||||
@@ -301,7 +305,7 @@ function executeAction(action, whereColumnName, key, targetColumns, newTargetCol
|
||||
window.onbeforeunload = null;
|
||||
|
||||
// update API endpoints to refresh the UI
|
||||
updateApi()
|
||||
updateApi("devices,appevents")
|
||||
|
||||
write_notification(`[Multi edit] Executed "${action}" on Columns "${targetColumns}" matching "${key}"`, 'info')
|
||||
|
||||
|
||||
@@ -783,7 +783,7 @@
|
||||
setCache(key, target.replaceAll(":","_")+'_id') // _id is added so it doesn't conflict with AdminLTE tab behavior
|
||||
}
|
||||
|
||||
// get the tab id from the cookie (already overriden by the target)
|
||||
// get the tab id from the cookie (already overridden by the target)
|
||||
if(!emptyArr.includes(getCache(key)))
|
||||
{
|
||||
selectedTab = getCache(key);
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
require '../server/init.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
// Function to render the log area component
|
||||
function renderLogArea($params) {
|
||||
$fileName = isset($params['fileName']) ? $params['fileName'] : '';
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
<?php
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
function renderInfobox($params) {
|
||||
$onclickEvent = isset($params['onclickEvent']) ? $params['onclickEvent'] : '';
|
||||
$color = isset($params['color']) ? $params['color'] : '';
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
// Cache the contents to a cache file
|
||||
$cached = fopen($cachefile, 'w');
|
||||
fwrite($cached, ob_get_contents());
|
||||
fclose($cached);
|
||||
ob_end_flush(); // Send the output to the browser
|
||||
?>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
$url = $_SERVER["SCRIPT_NAME"];
|
||||
$break = Explode('/', $url);
|
||||
$file = $break[count($break) - 1];
|
||||
$cachefile = 'cached-'.substr_replace($file ,"",-4).'.html';
|
||||
$cachetime = 18000;
|
||||
|
||||
// Serve from the cache if it is younger than $cachetime
|
||||
if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) {
|
||||
echo "<!-- Cached copy, generated ".date('H:i', filemtime($cachefile))." -->\n";
|
||||
readfile($cachefile);
|
||||
exit;
|
||||
}
|
||||
ob_start(); // Start the output buffer
|
||||
?>
|
||||
@@ -13,6 +13,10 @@
|
||||
$DBFILE = dirname(__FILE__).'/../../../db/app.db';
|
||||
$DBFILE_LOCKED_FILE = dirname(__FILE__).'/../../../front/log/db_is_locked.log';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
$db_locked = false;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -3,16 +3,18 @@
|
||||
// NetAlertX
|
||||
// Open Source Network Guard / WIFI & LAN intrusion detector
|
||||
//
|
||||
// parameters.php - Front module. Server side. Manage Parameters
|
||||
//------------------------------------------------------------------------------
|
||||
# Puche 2022+ jokob jokob@duck.com GNU GPLv3
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// External files
|
||||
require dirname(__FILE__).'/init.php';
|
||||
|
||||
// External files
|
||||
require dirname(__FILE__).'/init.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Action selector
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
// External files
|
||||
require dirname(__FILE__).'/init.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Action selector
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -424,41 +428,39 @@ function ExportCSV() {
|
||||
$func_result = $db->query("SELECT * FROM Devices");
|
||||
|
||||
// prepare CSV header row
|
||||
// header array with column names
|
||||
$columns = getDevicesColumns();
|
||||
|
||||
// wrap the headers with " (quotes)
|
||||
$resultCSV = '"'.implode('","', $columns).'"';
|
||||
|
||||
//and append a new line
|
||||
$resultCSV = $resultCSV."\n";
|
||||
$resultCSV = '"'.implode('","', $columns).'"'."\n";
|
||||
|
||||
// retrieve the devices from the DB
|
||||
while ($row = $func_result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
while ($row = $func_result->fetchArray(SQLITE3_ASSOC)) {
|
||||
|
||||
// loop through columns and add values to the string
|
||||
$index = 0;
|
||||
foreach ($columns as $columnName) {
|
||||
// Escape special chars (e.g.quotes) inside fields by replacing them with html definitions
|
||||
$fieldValue = encodeSpecialChars($row[$columnName]);
|
||||
|
||||
// add quotes around the value to prevent issues with commas in fields
|
||||
$resultCSV = $resultCSV.'"'.$row[$columnName].'"';
|
||||
$resultCSV .= '"'.$fieldValue.'"';
|
||||
|
||||
// detect last loop - skip as no comma needed
|
||||
if ($index != count($columns) - 1 )
|
||||
{
|
||||
$resultCSV = $resultCSV.',';
|
||||
if ($index != count($columns) - 1) {
|
||||
$resultCSV .= ',';
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
|
||||
//$resultCSV = $resultCSV.implode(",", [$row["dev_MAC"], $row["dev_Name"]]);
|
||||
$resultCSV = $resultCSV."\n";
|
||||
// add a new line for the next row
|
||||
$resultCSV .= "\n";
|
||||
}
|
||||
|
||||
//write the built CSV string
|
||||
echo $resultCSV;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Import CSV of devices
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -474,7 +476,11 @@ function ImportCSV() {
|
||||
if(isset ($_POST['content']) && !empty ($_POST['content']))
|
||||
{
|
||||
// Decode the Base64 string
|
||||
$data = base64_decode($_POST['content']);
|
||||
// $data = base64_decode($_POST['content']);
|
||||
$data = base64_decode($_POST['content'], true); // The second parameter ensures safe decoding
|
||||
|
||||
// // Ensure the decoded data is treated as UTF-8 text
|
||||
// $data = mb_convert_encoding($data, 'UTF-8', 'UTF-8');
|
||||
|
||||
} else if (file_exists($file)) { // try to get the data form the file
|
||||
|
||||
@@ -486,6 +492,12 @@ function ImportCSV() {
|
||||
|
||||
if($data != "")
|
||||
{
|
||||
// data cleanup - new lines breaking the CSV
|
||||
$data = preg_replace_callback('/"([^"]*)"/', function($matches) {
|
||||
// Replace all \n within the quotes with a space
|
||||
return str_replace("\n", " ", $matches[0]); // Replace with a space
|
||||
}, $data);
|
||||
|
||||
$lines = explode("\n", $data);
|
||||
|
||||
// Get the column headers from the first line of the CSV
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
// External files
|
||||
require dirname(__FILE__).'/init.php';
|
||||
// External files
|
||||
require dirname(__FILE__).'/init.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Action selector
|
||||
@@ -72,7 +75,7 @@ function getEventsTotals() {
|
||||
$resultJSON = getCache("getEventsTotals".$days);
|
||||
} else
|
||||
{
|
||||
// one query to get all numbers, whcih is quicker than multiple queries
|
||||
// one query to get all numbers, which is quicker than multiple queries
|
||||
$sql = "select
|
||||
(SELECT Count(*) FROM Events WHERE eve_DateTime >= date('now', '".$periodDateSQL."')) as all_events,
|
||||
(SELECT Count(*) FROM Sessions as sessions WHERE ( ses_DateTimeConnection >= date('now', '".$periodDateSQL."') OR ses_DateTimeDisconnection >= date('now', '".$periodDateSQL."') OR ses_StillConnected = 1 )) as sessions,
|
||||
@@ -334,24 +337,40 @@ function getEventsCalendar() {
|
||||
$endDate = '"'. $_REQUEST ['end'] .'"';
|
||||
|
||||
// SQL
|
||||
$SQL = 'SELECT ses_MAC, ses_EventTypeConnection, ses_DateTimeConnection,
|
||||
ses_EventTypeDisconnection, ses_DateTimeDisconnection, ses_IP, ses_AdditionalInfo, ses_StillConnected,
|
||||
|
||||
CASE
|
||||
WHEN ses_EventTypeConnection = "<missing event>" THEN
|
||||
IFNULL ((SELECT MAX(ses_DateTimeDisconnection) FROM Sessions AS SES2 WHERE SES2.ses_MAC = SES1.ses_MAC AND SES2.ses_DateTimeDisconnection < SES1.ses_DateTimeDisconnection), DATETIME(ses_DateTimeDisconnection, "-1 hour"))
|
||||
ELSE ses_DateTimeConnection
|
||||
END AS ses_DateTimeConnectionCorrected,
|
||||
$SQL = 'SELECT SES1.ses_MAC, SES1.ses_EventTypeConnection, SES1.ses_DateTimeConnection,
|
||||
SES1.ses_EventTypeDisconnection, SES1.ses_DateTimeDisconnection, SES1.ses_IP,
|
||||
SES1.ses_AdditionalInfo, SES1.ses_StillConnected,
|
||||
|
||||
CASE
|
||||
WHEN SES1.ses_EventTypeConnection = "<missing event>" THEN
|
||||
IFNULL (
|
||||
(SELECT MAX(SES2.ses_DateTimeDisconnection)
|
||||
FROM Sessions AS SES2
|
||||
WHERE SES2.ses_MAC = SES1.ses_MAC
|
||||
AND SES2.ses_DateTimeDisconnection < SES1.ses_DateTimeDisconnection
|
||||
AND SES2.ses_DateTimeDisconnection BETWEEN Date('. $startDate .') AND Date('. $endDate .')
|
||||
),
|
||||
DATETIME(SES1.ses_DateTimeDisconnection, "-1 hour")
|
||||
)
|
||||
ELSE SES1.ses_DateTimeConnection
|
||||
END AS ses_DateTimeConnectionCorrected,
|
||||
|
||||
CASE
|
||||
WHEN ses_EventTypeDisconnection = "<missing event>" THEN
|
||||
(SELECT MIN(ses_DateTimeConnection) FROM Sessions AS SES2 WHERE SES2.ses_MAC = SES1.ses_MAC AND SES2.ses_DateTimeConnection > SES1.ses_DateTimeConnection)
|
||||
ELSE ses_DateTimeDisconnection
|
||||
END AS ses_DateTimeDisconnectionCorrected
|
||||
CASE
|
||||
WHEN SES1.ses_EventTypeDisconnection = "<missing event>" THEN
|
||||
(SELECT MIN(SES2.ses_DateTimeConnection)
|
||||
FROM Sessions AS SES2
|
||||
WHERE SES2.ses_MAC = SES1.ses_MAC
|
||||
AND SES2.ses_DateTimeConnection > SES1.ses_DateTimeConnection
|
||||
AND SES2.ses_DateTimeConnection BETWEEN Date('. $startDate .') AND Date('. $endDate .')
|
||||
)
|
||||
ELSE SES1.ses_DateTimeDisconnection
|
||||
END AS ses_DateTimeDisconnectionCorrected
|
||||
|
||||
FROM Sessions AS SES1
|
||||
WHERE (SES1.ses_DateTimeConnection BETWEEN Date('. $startDate .') AND Date('. $endDate .'))
|
||||
OR (SES1.ses_DateTimeDisconnection BETWEEN Date('. $startDate .') AND Date('. $endDate .'))
|
||||
OR SES1.ses_StillConnected = 1';
|
||||
|
||||
FROM Sessions AS SES1
|
||||
WHERE ( ses_DateTimeConnectionCorrected <= Date('. $endDate .')
|
||||
AND (ses_DateTimeDisconnectionCorrected >= Date('. $startDate .') OR ses_StillConnected = 1 )) ';
|
||||
$result = $db->query($SQL);
|
||||
|
||||
// arrays of rows
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
// Get init.php
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
// Perform a test with the PING command
|
||||
$output = shell_exec("curl ipinfo.io");
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
require 'util.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
$PIA_HOST_IP = $_REQUEST['scan'];
|
||||
$PIA_SCAN_MODE = $_REQUEST['mode'];
|
||||
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
// Get init.php
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
// Get IP
|
||||
$ip = $_GET['ip'];
|
||||
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
<?php
|
||||
//------------------------------------------------------------------------------
|
||||
// NetAlertX
|
||||
// Open Source Network Guard / WIFI & LAN intrusion detector
|
||||
//
|
||||
// parameters.php - Front module. Server side. Manage Parameters
|
||||
//------------------------------------------------------------------------------
|
||||
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// External files
|
||||
require dirname(__FILE__).'/init.php';
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Action selector
|
||||
//------------------------------------------------------------------------------
|
||||
// Set maximum execution time to 15 seconds
|
||||
ini_set ('max_execution_time','15');
|
||||
|
||||
$skipCache = FALSE;
|
||||
$expireMinutes = 5;
|
||||
$defaultValue = '';
|
||||
|
||||
|
||||
if (isset ($_REQUEST['skipcache'])) {
|
||||
$skipCache = TRUE;
|
||||
}
|
||||
|
||||
if (isset ($_REQUEST['defaultValue'])) {
|
||||
$defaultValue = $_REQUEST['defaultValue'];
|
||||
}
|
||||
|
||||
if (isset ($_REQUEST['expireMinutes'])) {
|
||||
$expireMinutes = $_REQUEST['expireMinutes'];
|
||||
}
|
||||
|
||||
// Action functions
|
||||
if (isset ($_REQUEST['action']) && !empty ($_REQUEST['action'])) {
|
||||
$action = $_REQUEST['action'];
|
||||
switch ($action) {
|
||||
case 'get': getParameter($skipCache, $defaultValue, $expireMinutes); break;
|
||||
case 'set': setParameter($expireMinutes); break;
|
||||
default: logServerConsole ('Action: '. $action); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Get Parameter Value
|
||||
//------------------------------------------------------------------------------
|
||||
function getParameter($skipCache, $defaultValue, $expireMinutes) {
|
||||
|
||||
$parameter = $_REQUEST['parameter'];
|
||||
$value = "";
|
||||
|
||||
// get the value from the cache if available
|
||||
$cachedValue = getCache($parameter);
|
||||
if($cachedValue != "")
|
||||
{
|
||||
$value = $cachedValue;
|
||||
}
|
||||
|
||||
// query the database if no cache entry found or requesting live data (skipping cache)
|
||||
if($skipCache || $value == "" )
|
||||
{
|
||||
global $db;
|
||||
|
||||
$sql = 'SELECT par_Value FROM Parameters
|
||||
WHERE par_ID="'. quotes($parameter) .'"';
|
||||
|
||||
$result = $db->query($sql);
|
||||
$row = $result -> fetchArray (SQLITE3_NUM);
|
||||
|
||||
if($row != NULL && count($row) == 1)
|
||||
{
|
||||
$value = $row[0];
|
||||
} else{
|
||||
$value = $defaultValue;
|
||||
|
||||
// Nothing found in the DB, Insert new value
|
||||
insertNew($parameter, $value);
|
||||
}
|
||||
|
||||
// update cache
|
||||
setCache($parameter, $value, $expireMinutes);
|
||||
}
|
||||
// return value
|
||||
echo (json_encode ($value));
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Set Parameter Value
|
||||
//------------------------------------------------------------------------------
|
||||
function setParameter($expireMinutes) {
|
||||
|
||||
$parameter = $_REQUEST['parameter'];
|
||||
$value = $_REQUEST['value'];
|
||||
|
||||
global $db;
|
||||
|
||||
// Update value
|
||||
$sql = 'UPDATE Parameters SET par_Value="'. quotes ($value) .'"
|
||||
WHERE par_ID="'. quotes($parameter) .'"';
|
||||
$result = $db->query($sql);
|
||||
|
||||
if (! $result == TRUE) {
|
||||
echo "Error updating parameter\n\n$sql \n\n". $db->lastErrorMsg();
|
||||
return;
|
||||
}
|
||||
|
||||
$changes = $db->changes();
|
||||
if ($changes == 0) {
|
||||
// Insert new value
|
||||
insertNew($parameter, $value);
|
||||
}
|
||||
|
||||
// update cache
|
||||
setCache($parameter, $value, $expireMinutes);
|
||||
|
||||
echo 'OK';
|
||||
}
|
||||
|
||||
function insertNew($parameter, $value)
|
||||
{
|
||||
global $db;
|
||||
|
||||
// Insert new value
|
||||
$sql = 'INSERT INTO Parameters (par_ID, par_Value)
|
||||
VALUES ("'. quotes($parameter) .'",
|
||||
"'. quotes($value) .'")';
|
||||
$result = $db->query($sql);
|
||||
|
||||
if (! $result == TRUE) {
|
||||
echo "Error creating parameter\n\n$sql \n\n". $db->lastErrorMsg();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,5 +1,10 @@
|
||||
<?php
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
exec('../../../back/speedtest-cli --secure --simple', $output);
|
||||
|
||||
echo '<h4>'. lang('Speedtest_Results') .'</h4>';
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
// Get init.php
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
// Get IP
|
||||
$ip = $_GET['ip'];
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
require dirname(__FILE__).'/../templates/timezone.php';
|
||||
require dirname(__FILE__).'/../templates/skinUI.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
$FUNCTION = [];
|
||||
$SETTINGS = [];
|
||||
$ACTION = "";
|
||||
@@ -484,7 +488,7 @@ function getDateFromPeriod () {
|
||||
$days = "3650"; //10 years
|
||||
break;
|
||||
default:
|
||||
$days = "1";
|
||||
$days = "1";
|
||||
}
|
||||
|
||||
$periodDateSQL = "-".$days." day";
|
||||
@@ -520,6 +524,25 @@ function handleNull ($text, $default = "") {
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Encode special chars
|
||||
function encodeSpecialChars($str) {
|
||||
return str_replace(
|
||||
['&', '<', '>', '"', "'"],
|
||||
['&', '<', '>', '"', '''],
|
||||
$str
|
||||
);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Decode special chars
|
||||
function decodeSpecialChars($str) {
|
||||
return str_replace(
|
||||
['&', '<', '>', '"', '''],
|
||||
['&', '<', '>', '"', "'"],
|
||||
$str
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<!-- utils needing a DB connection -->
|
||||
|
||||
<?php
|
||||
|
||||
require dirname(__FILE__).'/init.php';
|
||||
|
||||
// Action functions
|
||||
if (isset ($_REQUEST['key']))
|
||||
{
|
||||
echo lang($_REQUEST['key']);
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
|
||||
require dirname(__FILE__).'/../templates/timezone.php';
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// Check if the action parameter is set in the GET request
|
||||
if (isset($_GET['action'])) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (session_status() == PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
$isAuthenticated = false;
|
||||
|
||||
@@ -17,9 +19,9 @@ $config_file = "../../../config/app.conf"; // depends on where this file is call
|
||||
$config_file_lines = file($config_file);
|
||||
$config_file_lines = array_values(preg_grep('/^SETPWD_password.*=/', $config_file_lines));
|
||||
$password_line = explode("'", $config_file_lines[0]);
|
||||
$Pia_Password = $password_line[1];
|
||||
$nax_Password = $password_line[1];
|
||||
|
||||
if (isset($_COOKIE[$CookieSaveLoginName]) && $Pia_Password == $_COOKIE[$CookieSaveLoginName]) {
|
||||
if (isset($_COOKIE[$CookieSaveLoginName]) && $nax_Password == $_COOKIE[$CookieSaveLoginName]) {
|
||||
$isAuthenticated = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
#---------------------------------------------------------------------------------#
|
||||
-->
|
||||
|
||||
<?php
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
?>
|
||||
|
||||
<!-- Main Footer -->
|
||||
<footer class="main-footer">
|
||||
<!-- Default to the left -->
|
||||
@@ -53,8 +59,8 @@
|
||||
<link rel="stylesheet" href="lib/AdminLTE/bower_components/select2/dist/css/select2.min.css">
|
||||
|
||||
<!-- NetAlertX -->
|
||||
<script src="js/handle_version.js"></script>
|
||||
<script defer src="js/ui_components.js?v=<?php include 'php/templates/version.php'; ?>"></script>
|
||||
<script defer src="js/handle_version.js"></script>
|
||||
<script src="js/ui_components.js?v=<?php include 'php/templates/version.php'; ?>"></script>
|
||||
|
||||
|
||||
<!-- Select2 JavaScript -->
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
global $db;
|
||||
|
||||
$Pia_Graph_Device_Time = array();
|
||||
$Pia_Graph_Device_All = array();
|
||||
$Pia_Graph_Device_Online = array();
|
||||
$Pia_Graph_Device_Down = array();
|
||||
$Pia_Graph_Device_Arch = array();
|
||||
|
||||
$statusesToShow = "'online', 'offline', 'archived'";
|
||||
|
||||
$statQuery = $db->query("SELECT * FROM Settings WHERE Code_Name = 'UI_PRESENCE'");
|
||||
|
||||
while($r = $statQuery->fetchArray(SQLITE3_ASSOC))
|
||||
{
|
||||
$statusesToShow = $r['Value'];
|
||||
}
|
||||
|
||||
$results = $db->query('SELECT * FROM Online_History ORDER BY Scan_Date DESC LIMIT 144');
|
||||
|
||||
while ($row = $results->fetchArray())
|
||||
{
|
||||
$time_raw = explode(' ', $row['Scan_Date']);
|
||||
$time = explode(':', $time_raw[1]);
|
||||
array_push($Pia_Graph_Device_Time, $time[0].':'.$time[1]);
|
||||
|
||||
// Offline
|
||||
if(strpos($statusesToShow, 'offline') !== false)
|
||||
{
|
||||
array_push($Pia_Graph_Device_Down, $row['Down_Devices']);
|
||||
}
|
||||
|
||||
// All
|
||||
array_push($Pia_Graph_Device_All, $row['All_Devices']);
|
||||
|
||||
// Online
|
||||
if(strpos($statusesToShow, 'online') !== false)
|
||||
{
|
||||
array_push($Pia_Graph_Device_Online, $row['Online_Devices']);
|
||||
}
|
||||
|
||||
// Archived
|
||||
if(strpos($statusesToShow, 'archived') !== false)
|
||||
{
|
||||
array_push($Pia_Graph_Device_Arch, $row['Archived_Devices']);
|
||||
}
|
||||
}
|
||||
function pia_graph_devices_data($Pia_Graph_Array) {
|
||||
$Pia_Graph_Array_rev = array_reverse($Pia_Graph_Array);
|
||||
foreach ($Pia_Graph_Array_rev as $result) {
|
||||
echo "'".$result."'";
|
||||
echo ",";
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,10 @@
|
||||
#--------------------------------------------------------------------------- -->
|
||||
|
||||
<?php
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
require dirname(__FILE__).'/security.php';
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
|
||||
?>
|
||||
|
||||
|
||||
704
front/php/templates/language/ar_ar.json
Executable file
704
front/php/templates/language/ar_ar.json
Executable file
@@ -0,0 +1,704 @@
|
||||
{
|
||||
"API_CUSTOM_SQL_description": "",
|
||||
"API_CUSTOM_SQL_name": "",
|
||||
"API_display_name": "",
|
||||
"API_icon": "",
|
||||
"About_Design": "",
|
||||
"About_Exit": "",
|
||||
"About_Title": "",
|
||||
"AppEvents_DateTimeCreated": "",
|
||||
"AppEvents_Extra": "",
|
||||
"AppEvents_GUID": "",
|
||||
"AppEvents_Helper1": "",
|
||||
"AppEvents_Helper2": "",
|
||||
"AppEvents_Helper3": "",
|
||||
"AppEvents_ObjectForeignKey": "",
|
||||
"AppEvents_ObjectIndex": "",
|
||||
"AppEvents_ObjectIsArchived": "",
|
||||
"AppEvents_ObjectIsNew": "",
|
||||
"AppEvents_ObjectPlugin": "",
|
||||
"AppEvents_ObjectPrimaryID": "",
|
||||
"AppEvents_ObjectSecondaryID": "",
|
||||
"AppEvents_ObjectStatus": "",
|
||||
"AppEvents_ObjectStatusColumn": "",
|
||||
"AppEvents_ObjectType": "",
|
||||
"AppEvents_Plugin": "",
|
||||
"AppEvents_Type": "",
|
||||
"BackDevDetail_Actions_Ask_Run": "",
|
||||
"BackDevDetail_Actions_Not_Registered": "",
|
||||
"BackDevDetail_Actions_Title_Run": "",
|
||||
"BackDevDetail_Copy_Ask": "",
|
||||
"BackDevDetail_Copy_Title": "",
|
||||
"BackDevDetail_Tools_WOL_error": "",
|
||||
"BackDevDetail_Tools_WOL_okay": "",
|
||||
"BackDevices_Arpscan_disabled": "",
|
||||
"BackDevices_Arpscan_enabled": "",
|
||||
"BackDevices_Backup_CopError": "",
|
||||
"BackDevices_Backup_Failed": "",
|
||||
"BackDevices_Backup_okay": "",
|
||||
"BackDevices_DBTools_DelDevError_a": "",
|
||||
"BackDevices_DBTools_DelDevError_b": "",
|
||||
"BackDevices_DBTools_DelDev_a": "",
|
||||
"BackDevices_DBTools_DelDev_b": "",
|
||||
"BackDevices_DBTools_DelEvents": "",
|
||||
"BackDevices_DBTools_DelEventsError": "",
|
||||
"BackDevices_DBTools_ImportCSV": "",
|
||||
"BackDevices_DBTools_ImportCSVError": "",
|
||||
"BackDevices_DBTools_ImportCSVMissing": "",
|
||||
"BackDevices_DBTools_Purge": "",
|
||||
"BackDevices_DBTools_UpdDev": "",
|
||||
"BackDevices_DBTools_UpdDevError": "",
|
||||
"BackDevices_DBTools_Upgrade": "",
|
||||
"BackDevices_DBTools_UpgradeError": "",
|
||||
"BackDevices_Device_UpdDevError": "",
|
||||
"BackDevices_Restore_CopError": "",
|
||||
"BackDevices_Restore_Failed": "",
|
||||
"BackDevices_Restore_okay": "",
|
||||
"BackDevices_darkmode_disabled": "",
|
||||
"BackDevices_darkmode_enabled": "",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "",
|
||||
"DevDetail_Copy_Device_Tooltip": "",
|
||||
"DevDetail_EveandAl_AlertAllEvents": "",
|
||||
"DevDetail_EveandAl_AlertDown": "",
|
||||
"DevDetail_EveandAl_Archived": "",
|
||||
"DevDetail_EveandAl_NewDevice": "",
|
||||
"DevDetail_EveandAl_NewDevice_Tooltip": "",
|
||||
"DevDetail_EveandAl_RandomMAC": "",
|
||||
"DevDetail_EveandAl_ScanCycle": "",
|
||||
"DevDetail_EveandAl_ScanCycle_a": "",
|
||||
"DevDetail_EveandAl_ScanCycle_z": "",
|
||||
"DevDetail_EveandAl_Skip": "",
|
||||
"DevDetail_EveandAl_Title": "",
|
||||
"DevDetail_Events_CheckBox": "",
|
||||
"DevDetail_GoToNetworkNode": "",
|
||||
"DevDetail_Icon": "",
|
||||
"DevDetail_Icon_Descr": "",
|
||||
"DevDetail_Loading": "",
|
||||
"DevDetail_MainInfo_Comments": "",
|
||||
"DevDetail_MainInfo_Favorite": "",
|
||||
"DevDetail_MainInfo_Group": "",
|
||||
"DevDetail_MainInfo_Location": "",
|
||||
"DevDetail_MainInfo_Name": "",
|
||||
"DevDetail_MainInfo_Network": "",
|
||||
"DevDetail_MainInfo_Network_Port": "",
|
||||
"DevDetail_MainInfo_Network_Site": "",
|
||||
"DevDetail_MainInfo_Network_Title": "",
|
||||
"DevDetail_MainInfo_Owner": "",
|
||||
"DevDetail_MainInfo_SSID": "",
|
||||
"DevDetail_MainInfo_Title": "",
|
||||
"DevDetail_MainInfo_Type": "",
|
||||
"DevDetail_MainInfo_Vendor": "",
|
||||
"DevDetail_MainInfo_mac": "",
|
||||
"DevDetail_Network_Node_hover": "",
|
||||
"DevDetail_Network_Port_hover": "",
|
||||
"DevDetail_Nmap_Scans": "",
|
||||
"DevDetail_Nmap_Scans_desc": "",
|
||||
"DevDetail_Nmap_buttonDefault": "",
|
||||
"DevDetail_Nmap_buttonDefault_text": "",
|
||||
"DevDetail_Nmap_buttonDetail": "",
|
||||
"DevDetail_Nmap_buttonDetail_text": "",
|
||||
"DevDetail_Nmap_buttonFast": "",
|
||||
"DevDetail_Nmap_buttonFast_text": "",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery": "",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery_text": "",
|
||||
"DevDetail_Nmap_resultsLink": "",
|
||||
"DevDetail_Owner_hover": "",
|
||||
"DevDetail_Periodselect_All": "",
|
||||
"DevDetail_Periodselect_LastMonth": "",
|
||||
"DevDetail_Periodselect_LastWeek": "",
|
||||
"DevDetail_Periodselect_LastYear": "",
|
||||
"DevDetail_Periodselect_today": "",
|
||||
"DevDetail_Run_Actions_Title": "",
|
||||
"DevDetail_Run_Actions_Tooltip": "",
|
||||
"DevDetail_SessionInfo_FirstSession": "",
|
||||
"DevDetail_SessionInfo_LastIP": "",
|
||||
"DevDetail_SessionInfo_LastSession": "",
|
||||
"DevDetail_SessionInfo_StaticIP": "",
|
||||
"DevDetail_SessionInfo_Status": "",
|
||||
"DevDetail_SessionInfo_Title": "",
|
||||
"DevDetail_SessionTable_Additionalinfo": "",
|
||||
"DevDetail_SessionTable_Connection": "",
|
||||
"DevDetail_SessionTable_Disconnection": "",
|
||||
"DevDetail_SessionTable_Duration": "",
|
||||
"DevDetail_SessionTable_IP": "",
|
||||
"DevDetail_SessionTable_Order": "",
|
||||
"DevDetail_Shortcut_CurrentStatus": "",
|
||||
"DevDetail_Shortcut_DownAlerts": "",
|
||||
"DevDetail_Shortcut_Presence": "",
|
||||
"DevDetail_Shortcut_Sessions": "",
|
||||
"DevDetail_Tab_Details": "",
|
||||
"DevDetail_Tab_Events": "",
|
||||
"DevDetail_Tab_EventsTableDate": "",
|
||||
"DevDetail_Tab_EventsTableEvent": "",
|
||||
"DevDetail_Tab_EventsTableIP": "",
|
||||
"DevDetail_Tab_EventsTableInfo": "",
|
||||
"DevDetail_Tab_Nmap": "",
|
||||
"DevDetail_Tab_NmapEmpty": "",
|
||||
"DevDetail_Tab_NmapTableExtra": "",
|
||||
"DevDetail_Tab_NmapTableHeader": "",
|
||||
"DevDetail_Tab_NmapTableIndex": "",
|
||||
"DevDetail_Tab_NmapTablePort": "",
|
||||
"DevDetail_Tab_NmapTableService": "",
|
||||
"DevDetail_Tab_NmapTableState": "",
|
||||
"DevDetail_Tab_NmapTableText": "",
|
||||
"DevDetail_Tab_NmapTableTime": "",
|
||||
"DevDetail_Tab_Plugins": "",
|
||||
"DevDetail_Tab_Presence": "",
|
||||
"DevDetail_Tab_Sessions": "",
|
||||
"DevDetail_Tab_Tools": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Description": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Error": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Start": "",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Title": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Description": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Error": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Start": "",
|
||||
"DevDetail_Tab_Tools_Nslookup_Title": "",
|
||||
"DevDetail_Tab_Tools_Speedtest_Description": "",
|
||||
"DevDetail_Tab_Tools_Speedtest_Start": "",
|
||||
"DevDetail_Tab_Tools_Speedtest_Title": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Description": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Error": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Start": "",
|
||||
"DevDetail_Tab_Tools_Traceroute_Title": "",
|
||||
"DevDetail_Tools_WOL": "",
|
||||
"DevDetail_Tools_WOL_noti": "",
|
||||
"DevDetail_Tools_WOL_noti_text": "",
|
||||
"DevDetail_Type_hover": "",
|
||||
"DevDetail_Vendor_hover": "",
|
||||
"DevDetail_WOL_Title": "",
|
||||
"DevDetail_button_AddIcon": "",
|
||||
"DevDetail_button_AddIcon_Help": "",
|
||||
"DevDetail_button_AddIcon_Tooltip": "",
|
||||
"DevDetail_button_Delete": "",
|
||||
"DevDetail_button_DeleteEvents": "",
|
||||
"DevDetail_button_DeleteEvents_Warning": "",
|
||||
"DevDetail_button_OverwriteIcons": "",
|
||||
"DevDetail_button_OverwriteIcons_Tooltip": "",
|
||||
"DevDetail_button_OverwriteIcons_Warning": "",
|
||||
"DevDetail_button_Reset": "",
|
||||
"DevDetail_button_Save": "",
|
||||
"Device_MultiEdit": "",
|
||||
"Device_MultiEdit_Backup": "",
|
||||
"Device_MultiEdit_Fields": "",
|
||||
"Device_MultiEdit_MassActions": "",
|
||||
"Device_MultiEdit_Tooltip": "",
|
||||
"Device_Searchbox": "",
|
||||
"Device_Shortcut_AllDevices": "",
|
||||
"Device_Shortcut_Archived": "",
|
||||
"Device_Shortcut_Connected": "",
|
||||
"Device_Shortcut_Devices": "",
|
||||
"Device_Shortcut_DownAlerts": "",
|
||||
"Device_Shortcut_DownOnly": "",
|
||||
"Device_Shortcut_Favorites": "",
|
||||
"Device_Shortcut_NewDevices": "",
|
||||
"Device_Shortcut_OnlineChart": "",
|
||||
"Device_TableHead_Connected_Devices": "",
|
||||
"Device_TableHead_Favorite": "",
|
||||
"Device_TableHead_FirstSession": "",
|
||||
"Device_TableHead_GUID": "",
|
||||
"Device_TableHead_Group": "",
|
||||
"Device_TableHead_Icon": "",
|
||||
"Device_TableHead_LastIP": "",
|
||||
"Device_TableHead_LastIPOrder": "",
|
||||
"Device_TableHead_LastSession": "",
|
||||
"Device_TableHead_Location": "",
|
||||
"Device_TableHead_MAC": "",
|
||||
"Device_TableHead_MAC_full": "",
|
||||
"Device_TableHead_Name": "",
|
||||
"Device_TableHead_NetworkSite": "",
|
||||
"Device_TableHead_Owner": "",
|
||||
"Device_TableHead_Parent_MAC": "",
|
||||
"Device_TableHead_Port": "",
|
||||
"Device_TableHead_RowID": "",
|
||||
"Device_TableHead_Rowid": "",
|
||||
"Device_TableHead_SSID": "",
|
||||
"Device_TableHead_Status": "",
|
||||
"Device_TableHead_SyncHubNodeName": "",
|
||||
"Device_TableHead_Type": "",
|
||||
"Device_TableHead_Vendor": "",
|
||||
"Device_Table_Not_Network_Device": "",
|
||||
"Device_Table_info": "",
|
||||
"Device_Table_nav_next": "",
|
||||
"Device_Table_nav_prev": "",
|
||||
"Device_Tablelenght": "",
|
||||
"Device_Tablelenght_all": "",
|
||||
"Device_Title": "",
|
||||
"Donations_Others": "",
|
||||
"Donations_Platforms": "",
|
||||
"Donations_Text": "",
|
||||
"Donations_Title": "",
|
||||
"ENABLE_PLUGINS_description": "",
|
||||
"ENABLE_PLUGINS_name": "",
|
||||
"Email_display_name": "",
|
||||
"Email_icon": "",
|
||||
"Events_Loading": "",
|
||||
"Events_Periodselect_All": "",
|
||||
"Events_Periodselect_LastMonth": "",
|
||||
"Events_Periodselect_LastWeek": "",
|
||||
"Events_Periodselect_LastYear": "",
|
||||
"Events_Periodselect_today": "",
|
||||
"Events_Searchbox": "",
|
||||
"Events_Shortcut_AllEvents": "",
|
||||
"Events_Shortcut_DownAlerts": "",
|
||||
"Events_Shortcut_Events": "",
|
||||
"Events_Shortcut_MissSessions": "",
|
||||
"Events_Shortcut_NewDevices": "",
|
||||
"Events_Shortcut_Sessions": "",
|
||||
"Events_Shortcut_VoidSessions": "",
|
||||
"Events_TableHead_AdditionalInfo": "",
|
||||
"Events_TableHead_Connection": "",
|
||||
"Events_TableHead_Date": "",
|
||||
"Events_TableHead_Device": "",
|
||||
"Events_TableHead_Disconnection": "",
|
||||
"Events_TableHead_Duration": "",
|
||||
"Events_TableHead_DurationOrder": "",
|
||||
"Events_TableHead_EventType": "",
|
||||
"Events_TableHead_IP": "",
|
||||
"Events_TableHead_IPOrder": "",
|
||||
"Events_TableHead_Order": "",
|
||||
"Events_TableHead_Owner": "",
|
||||
"Events_TableHead_PendingAlert": "",
|
||||
"Events_Table_info": "",
|
||||
"Events_Table_nav_next": "",
|
||||
"Events_Table_nav_prev": "",
|
||||
"Events_Tablelenght": "",
|
||||
"Events_Tablelenght_all": "",
|
||||
"Events_Title": "",
|
||||
"Gen_Action": "",
|
||||
"Gen_Add": "",
|
||||
"Gen_Add_All": "",
|
||||
"Gen_All_Devices": "",
|
||||
"Gen_AreYouSure": "",
|
||||
"Gen_Backup": "",
|
||||
"Gen_Cancel": "",
|
||||
"Gen_Change": "",
|
||||
"Gen_Copy": "",
|
||||
"Gen_DataUpdatedUITakesTime": "",
|
||||
"Gen_Delete": "",
|
||||
"Gen_DeleteAll": "",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "",
|
||||
"Gen_Filter": "",
|
||||
"Gen_LockedDB": "",
|
||||
"Gen_Offline": "",
|
||||
"Gen_Okay": "",
|
||||
"Gen_Purge": "",
|
||||
"Gen_ReadDocs": "",
|
||||
"Gen_Remove_All": "",
|
||||
"Gen_Remove_Last": "",
|
||||
"Gen_Restore": "",
|
||||
"Gen_Run": "",
|
||||
"Gen_Save": "",
|
||||
"Gen_Saved": "",
|
||||
"Gen_Search": "",
|
||||
"Gen_SelectToPreview": "",
|
||||
"Gen_Selected_Devices": "",
|
||||
"Gen_Switch": "",
|
||||
"Gen_Upd": "",
|
||||
"Gen_Upd_Fail": "",
|
||||
"Gen_Update": "",
|
||||
"Gen_Update_Value": "",
|
||||
"Gen_Warning": "",
|
||||
"Gen_Work_In_Progress": "",
|
||||
"General_display_name": "",
|
||||
"General_icon": "",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "",
|
||||
"HelpFAQ_Cat_Detail": "",
|
||||
"HelpFAQ_Cat_Detail_300_head": "",
|
||||
"HelpFAQ_Cat_Detail_300_text_a": "",
|
||||
"HelpFAQ_Cat_Detail_300_text_b": "",
|
||||
"HelpFAQ_Cat_Detail_301_head_a": "",
|
||||
"HelpFAQ_Cat_Detail_301_head_b": "",
|
||||
"HelpFAQ_Cat_Detail_301_text": "",
|
||||
"HelpFAQ_Cat_Detail_302_head_a": "",
|
||||
"HelpFAQ_Cat_Detail_302_head_b": "",
|
||||
"HelpFAQ_Cat_Detail_302_text": "",
|
||||
"HelpFAQ_Cat_Detail_303_head": "",
|
||||
"HelpFAQ_Cat_Detail_303_text": "",
|
||||
"HelpFAQ_Cat_Device_200_head": "",
|
||||
"HelpFAQ_Cat_Device_200_text": "",
|
||||
"HelpFAQ_Cat_General": "",
|
||||
"HelpFAQ_Cat_General_100_head": "",
|
||||
"HelpFAQ_Cat_General_100_text_a": "",
|
||||
"HelpFAQ_Cat_General_100_text_b": "",
|
||||
"HelpFAQ_Cat_General_100_text_c": "",
|
||||
"HelpFAQ_Cat_General_101_head": "",
|
||||
"HelpFAQ_Cat_General_101_text": "",
|
||||
"HelpFAQ_Cat_General_102_head": "",
|
||||
"HelpFAQ_Cat_General_102_text": "",
|
||||
"HelpFAQ_Cat_General_102docker_head": "",
|
||||
"HelpFAQ_Cat_General_102docker_text": "",
|
||||
"HelpFAQ_Cat_General_103_head": "",
|
||||
"HelpFAQ_Cat_General_103_text": "",
|
||||
"HelpFAQ_Cat_Network_600_head": "",
|
||||
"HelpFAQ_Cat_Network_600_text": "",
|
||||
"HelpFAQ_Cat_Network_601_head": "",
|
||||
"HelpFAQ_Cat_Network_601_text": "",
|
||||
"HelpFAQ_Cat_Presence_400_head": "",
|
||||
"HelpFAQ_Cat_Presence_400_text": "",
|
||||
"HelpFAQ_Cat_Presence_401_head": "",
|
||||
"HelpFAQ_Cat_Presence_401_text": "",
|
||||
"HelpFAQ_Title": "",
|
||||
"LOADED_PLUGINS_description": "",
|
||||
"LOADED_PLUGINS_name": "",
|
||||
"LOG_LEVEL_description": "",
|
||||
"LOG_LEVEL_name": "",
|
||||
"Loading": "",
|
||||
"Login_Box": "",
|
||||
"Login_Default_PWD": "",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "",
|
||||
"Login_Psw_alert": "",
|
||||
"Login_Psw_folder": "",
|
||||
"Login_Psw_new": "",
|
||||
"Login_Psw_run": "",
|
||||
"Login_Remember": "",
|
||||
"Login_Remember_small": "",
|
||||
"Login_Submit": "",
|
||||
"Login_Toggle_Alert_headline": "",
|
||||
"Login_Toggle_Info": "",
|
||||
"Login_Toggle_Info_headline": "",
|
||||
"Maint_PurgeLog": "",
|
||||
"Maint_RestartServer": "",
|
||||
"Maint_Restart_Server_noti_text": "",
|
||||
"Maintenance_Running_Version": "",
|
||||
"Maintenance_Status": "",
|
||||
"Maintenance_Title": "",
|
||||
"Maintenance_Tool_ExportCSV": "",
|
||||
"Maintenance_Tool_ExportCSV_noti": "",
|
||||
"Maintenance_Tool_ExportCSV_noti_text": "",
|
||||
"Maintenance_Tool_ExportCSV_text": "",
|
||||
"Maintenance_Tool_ImportCSV": "",
|
||||
"Maintenance_Tool_ImportCSV_noti": "",
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "",
|
||||
"Maintenance_Tool_ImportCSV_text": "",
|
||||
"Maintenance_Tool_ImportPastedCSV": "",
|
||||
"Maintenance_Tool_ImportPastedCSV_noti_text": "",
|
||||
"Maintenance_Tool_ImportPastedCSV_text": "",
|
||||
"Maintenance_Tool_arpscansw": "",
|
||||
"Maintenance_Tool_arpscansw_noti": "",
|
||||
"Maintenance_Tool_arpscansw_noti_text": "",
|
||||
"Maintenance_Tool_arpscansw_text": "",
|
||||
"Maintenance_Tool_backup": "",
|
||||
"Maintenance_Tool_backup_noti": "",
|
||||
"Maintenance_Tool_backup_noti_text": "",
|
||||
"Maintenance_Tool_backup_text": "",
|
||||
"Maintenance_Tool_check_visible": "",
|
||||
"Maintenance_Tool_darkmode": "",
|
||||
"Maintenance_Tool_darkmode_noti": "",
|
||||
"Maintenance_Tool_darkmode_noti_text": "",
|
||||
"Maintenance_Tool_darkmode_text": "",
|
||||
"Maintenance_Tool_del_ActHistory": "",
|
||||
"Maintenance_Tool_del_ActHistory_noti": "",
|
||||
"Maintenance_Tool_del_ActHistory_noti_text": "",
|
||||
"Maintenance_Tool_del_ActHistory_text": "",
|
||||
"Maintenance_Tool_del_alldev": "",
|
||||
"Maintenance_Tool_del_alldev_noti": "",
|
||||
"Maintenance_Tool_del_alldev_noti_text": "",
|
||||
"Maintenance_Tool_del_alldev_text": "",
|
||||
"Maintenance_Tool_del_allevents": "",
|
||||
"Maintenance_Tool_del_allevents30": "",
|
||||
"Maintenance_Tool_del_allevents30_noti": "",
|
||||
"Maintenance_Tool_del_allevents30_noti_text": "",
|
||||
"Maintenance_Tool_del_allevents30_text": "",
|
||||
"Maintenance_Tool_del_allevents_noti": "",
|
||||
"Maintenance_Tool_del_allevents_noti_text": "",
|
||||
"Maintenance_Tool_del_allevents_text": "",
|
||||
"Maintenance_Tool_del_empty_macs": "",
|
||||
"Maintenance_Tool_del_empty_macs_noti": "",
|
||||
"Maintenance_Tool_del_empty_macs_noti_text": "",
|
||||
"Maintenance_Tool_del_empty_macs_text": "",
|
||||
"Maintenance_Tool_del_selecteddev": "",
|
||||
"Maintenance_Tool_del_selecteddev_text": "",
|
||||
"Maintenance_Tool_del_unknowndev": "",
|
||||
"Maintenance_Tool_del_unknowndev_noti": "",
|
||||
"Maintenance_Tool_del_unknowndev_noti_text": "",
|
||||
"Maintenance_Tool_del_unknowndev_text": "",
|
||||
"Maintenance_Tool_displayed_columns_text": "",
|
||||
"Maintenance_Tool_drag_me": "",
|
||||
"Maintenance_Tool_order_columns_text": "",
|
||||
"Maintenance_Tool_purgebackup": "",
|
||||
"Maintenance_Tool_purgebackup_noti": "",
|
||||
"Maintenance_Tool_purgebackup_noti_text": "",
|
||||
"Maintenance_Tool_purgebackup_text": "",
|
||||
"Maintenance_Tool_restore": "",
|
||||
"Maintenance_Tool_restore_noti": "",
|
||||
"Maintenance_Tool_restore_noti_text": "",
|
||||
"Maintenance_Tool_restore_text": "",
|
||||
"Maintenance_Tool_upgrade_database_noti": "",
|
||||
"Maintenance_Tool_upgrade_database_noti_text": "",
|
||||
"Maintenance_Tool_upgrade_database_text": "",
|
||||
"Maintenance_Tools_Tab_BackupRestore": "",
|
||||
"Maintenance_Tools_Tab_Logging": "",
|
||||
"Maintenance_Tools_Tab_Settings": "",
|
||||
"Maintenance_Tools_Tab_Tools": "",
|
||||
"Maintenance_Tools_Tab_UISettings": "",
|
||||
"Maintenance_arp_status": "",
|
||||
"Maintenance_arp_status_off": "",
|
||||
"Maintenance_arp_status_on": "",
|
||||
"Maintenance_built_on": "",
|
||||
"Maintenance_current_version": "",
|
||||
"Maintenance_database_backup": "",
|
||||
"Maintenance_database_backup_found": "",
|
||||
"Maintenance_database_backup_total": "",
|
||||
"Maintenance_database_lastmod": "",
|
||||
"Maintenance_database_path": "",
|
||||
"Maintenance_database_rows": "",
|
||||
"Maintenance_database_size": "",
|
||||
"Maintenance_lang_selector_apply": "",
|
||||
"Maintenance_lang_selector_empty": "",
|
||||
"Maintenance_lang_selector_lable": "",
|
||||
"Maintenance_lang_selector_text": "",
|
||||
"Maintenance_new_version": "",
|
||||
"Maintenance_themeselector_apply": "",
|
||||
"Maintenance_themeselector_empty": "",
|
||||
"Maintenance_themeselector_lable": "",
|
||||
"Maintenance_themeselector_text": "",
|
||||
"Maintenance_version": "",
|
||||
"NETWORK_DEVICE_TYPES_description": "",
|
||||
"NETWORK_DEVICE_TYPES_name": "",
|
||||
"Navigation_About": "",
|
||||
"Navigation_Devices": "",
|
||||
"Navigation_Donations": "",
|
||||
"Navigation_Events": "",
|
||||
"Navigation_HelpFAQ": "",
|
||||
"Navigation_Integrations": "",
|
||||
"Navigation_Maintenance": "",
|
||||
"Navigation_Monitoring": "",
|
||||
"Navigation_Network": "",
|
||||
"Navigation_Notifications": "",
|
||||
"Navigation_Plugins": "",
|
||||
"Navigation_Presence": "",
|
||||
"Navigation_Report": "",
|
||||
"Navigation_Settings": "",
|
||||
"Navigation_SystemInfo": "",
|
||||
"Navigation_Workflows": "",
|
||||
"Network_Assign": "",
|
||||
"Network_Cant_Assign": "",
|
||||
"Network_Configuration_Error": "",
|
||||
"Network_Connected": "",
|
||||
"Network_ManageAdd": "",
|
||||
"Network_ManageAdd_Name": "",
|
||||
"Network_ManageAdd_Name_text": "",
|
||||
"Network_ManageAdd_Port": "",
|
||||
"Network_ManageAdd_Port_text": "",
|
||||
"Network_ManageAdd_Submit": "",
|
||||
"Network_ManageAdd_Type": "",
|
||||
"Network_ManageAdd_Type_text": "",
|
||||
"Network_ManageAssign": "",
|
||||
"Network_ManageDel": "",
|
||||
"Network_ManageDel_Name": "",
|
||||
"Network_ManageDel_Name_text": "",
|
||||
"Network_ManageDel_Submit": "",
|
||||
"Network_ManageDevices": "",
|
||||
"Network_ManageEdit": "",
|
||||
"Network_ManageEdit_ID": "",
|
||||
"Network_ManageEdit_ID_text": "",
|
||||
"Network_ManageEdit_Name": "",
|
||||
"Network_ManageEdit_Name_text": "",
|
||||
"Network_ManageEdit_Port": "",
|
||||
"Network_ManageEdit_Port_text": "",
|
||||
"Network_ManageEdit_Submit": "",
|
||||
"Network_ManageEdit_Type": "",
|
||||
"Network_ManageEdit_Type_text": "",
|
||||
"Network_ManageLeaf": "",
|
||||
"Network_ManageUnassign": "",
|
||||
"Network_NoAssignedDevices": "",
|
||||
"Network_NoDevices": "",
|
||||
"Network_Node": "",
|
||||
"Network_Node_Name": "",
|
||||
"Network_Parent": "",
|
||||
"Network_Root": "",
|
||||
"Network_Root_Not_Configured": "",
|
||||
"Network_Root_Unconfigurable": "",
|
||||
"Network_Table_Hostname": "",
|
||||
"Network_Table_IP": "",
|
||||
"Network_Table_State": "",
|
||||
"Network_Title": "",
|
||||
"Network_UnassignedDevices": "",
|
||||
"Notifications_All": "",
|
||||
"Notifications_Mark_All_Read": "",
|
||||
"PIALERT_WEB_PASSWORD_description": "",
|
||||
"PIALERT_WEB_PASSWORD_name": "",
|
||||
"PIALERT_WEB_PROTECTION_description": "",
|
||||
"PIALERT_WEB_PROTECTION_name": "",
|
||||
"PLUGINS_KEEP_HIST_description": "",
|
||||
"PLUGINS_KEEP_HIST_name": "",
|
||||
"Plugins_DeleteAll": "",
|
||||
"Plugins_Filters_Mac": "",
|
||||
"Plugins_History": "",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "",
|
||||
"Plugins_Out_of": "",
|
||||
"Plugins_Unprocessed_Events": "",
|
||||
"Plugins_no_control": "",
|
||||
"Presence_CalHead_day": "",
|
||||
"Presence_CalHead_lang": "",
|
||||
"Presence_CalHead_month": "",
|
||||
"Presence_CalHead_quarter": "",
|
||||
"Presence_CalHead_week": "",
|
||||
"Presence_CalHead_year": "",
|
||||
"Presence_CallHead_Devices": "",
|
||||
"Presence_Loading": "",
|
||||
"Presence_Shortcut_AllDevices": "",
|
||||
"Presence_Shortcut_Archived": "",
|
||||
"Presence_Shortcut_Connected": "",
|
||||
"Presence_Shortcut_Devices": "",
|
||||
"Presence_Shortcut_DownAlerts": "",
|
||||
"Presence_Shortcut_Favorites": "",
|
||||
"Presence_Shortcut_NewDevices": "",
|
||||
"Presence_Title": "",
|
||||
"REPORT_DASHBOARD_URL_description": "",
|
||||
"REPORT_DASHBOARD_URL_name": "",
|
||||
"REPORT_ERROR": "",
|
||||
"REPORT_MAIL_description": "",
|
||||
"REPORT_MAIL_name": "",
|
||||
"REPORT_TITLE": "",
|
||||
"RandomMAC_hover": "",
|
||||
"Reports_Sent_Log": "",
|
||||
"SCAN_SUBNETS_description": "",
|
||||
"SCAN_SUBNETS_name": "",
|
||||
"SYSTEM_TITLE": "",
|
||||
"Setting_Override": "",
|
||||
"Setting_Override_Description": "",
|
||||
"Settings_Metadata_Toggle": "",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "",
|
||||
"Settings_device_Scanners_desync_popup": "",
|
||||
"Speedtest_Results": "",
|
||||
"Systeminfo_CPU": "",
|
||||
"Systeminfo_CPU_Cores": "",
|
||||
"Systeminfo_CPU_Name": "",
|
||||
"Systeminfo_CPU_Speed": "",
|
||||
"Systeminfo_CPU_Temp": "",
|
||||
"Systeminfo_CPU_Vendor": "",
|
||||
"Systeminfo_Client_Resolution": "",
|
||||
"Systeminfo_Client_User_Agent": "",
|
||||
"Systeminfo_General": "",
|
||||
"Systeminfo_General_Date": "",
|
||||
"Systeminfo_General_Date2": "",
|
||||
"Systeminfo_General_Full_Date": "",
|
||||
"Systeminfo_General_TimeZone": "",
|
||||
"Systeminfo_Memory": "",
|
||||
"Systeminfo_Memory_Total_Memory": "",
|
||||
"Systeminfo_Memory_Usage": "",
|
||||
"Systeminfo_Memory_Usage_Percent": "",
|
||||
"Systeminfo_Motherboard": "",
|
||||
"Systeminfo_Motherboard_BIOS": "",
|
||||
"Systeminfo_Motherboard_BIOS_Date": "",
|
||||
"Systeminfo_Motherboard_BIOS_Vendor": "",
|
||||
"Systeminfo_Motherboard_Manufactured": "",
|
||||
"Systeminfo_Motherboard_Name": "",
|
||||
"Systeminfo_Motherboard_Revision": "",
|
||||
"Systeminfo_Network": "",
|
||||
"Systeminfo_Network_Accept_Encoding": "",
|
||||
"Systeminfo_Network_Accept_Language": "",
|
||||
"Systeminfo_Network_Connection_Port": "",
|
||||
"Systeminfo_Network_HTTP_Host": "",
|
||||
"Systeminfo_Network_HTTP_Referer": "",
|
||||
"Systeminfo_Network_HTTP_Referer_String": "",
|
||||
"Systeminfo_Network_Hardware": "",
|
||||
"Systeminfo_Network_Hardware_Interface_Mask": "",
|
||||
"Systeminfo_Network_Hardware_Interface_Name": "",
|
||||
"Systeminfo_Network_Hardware_Interface_RX": "",
|
||||
"Systeminfo_Network_Hardware_Interface_TX": "",
|
||||
"Systeminfo_Network_IP": "",
|
||||
"Systeminfo_Network_IP_Connection": "",
|
||||
"Systeminfo_Network_IP_Server": "",
|
||||
"Systeminfo_Network_MIME": "",
|
||||
"Systeminfo_Network_Request_Method": "",
|
||||
"Systeminfo_Network_Request_Time": "",
|
||||
"Systeminfo_Network_Request_URI": "",
|
||||
"Systeminfo_Network_Secure_Connection": "",
|
||||
"Systeminfo_Network_Secure_Connection_String": "",
|
||||
"Systeminfo_Network_Server_Name": "",
|
||||
"Systeminfo_Network_Server_Name_String": "",
|
||||
"Systeminfo_Network_Server_Query": "",
|
||||
"Systeminfo_Network_Server_Query_String": "",
|
||||
"Systeminfo_Network_Server_Version": "",
|
||||
"Systeminfo_Services": "",
|
||||
"Systeminfo_Services_Description": "",
|
||||
"Systeminfo_Services_Name": "",
|
||||
"Systeminfo_Storage": "",
|
||||
"Systeminfo_Storage_Device": "",
|
||||
"Systeminfo_Storage_Mount": "",
|
||||
"Systeminfo_Storage_Size": "",
|
||||
"Systeminfo_Storage_Type": "",
|
||||
"Systeminfo_Storage_Usage": "",
|
||||
"Systeminfo_Storage_Usage_Free": "",
|
||||
"Systeminfo_Storage_Usage_Mount": "",
|
||||
"Systeminfo_Storage_Usage_Total": "",
|
||||
"Systeminfo_Storage_Usage_Used": "",
|
||||
"Systeminfo_System": "",
|
||||
"Systeminfo_System_AVG": "",
|
||||
"Systeminfo_System_Architecture": "",
|
||||
"Systeminfo_System_Kernel": "",
|
||||
"Systeminfo_System_OSVersion": "",
|
||||
"Systeminfo_System_Running_Processes": "",
|
||||
"Systeminfo_System_System": "",
|
||||
"Systeminfo_System_Uname": "",
|
||||
"Systeminfo_System_Uptime": "",
|
||||
"Systeminfo_This_Client": "",
|
||||
"Systeminfo_USB_Devices": "",
|
||||
"TICKER_MIGRATE_TO_NETALERTX": "",
|
||||
"TIMEZONE_description": "",
|
||||
"TIMEZONE_name": "",
|
||||
"UI_DEV_SECTIONS_description": "",
|
||||
"UI_DEV_SECTIONS_name": "",
|
||||
"UI_ICONS_description": "",
|
||||
"UI_ICONS_name": "",
|
||||
"UI_LANG_description": "",
|
||||
"UI_LANG_name": "",
|
||||
"UI_MY_DEVICES_description": "",
|
||||
"UI_MY_DEVICES_name": "",
|
||||
"UI_NOT_RANDOM_MAC_description": "",
|
||||
"UI_NOT_RANDOM_MAC_name": "",
|
||||
"UI_PRESENCE_description": "",
|
||||
"UI_PRESENCE_name": "",
|
||||
"UI_REFRESH_description": "",
|
||||
"UI_REFRESH_name": "",
|
||||
"VERSION_description": "",
|
||||
"VERSION_name": "",
|
||||
"devices_old": "",
|
||||
"general_event_description": "",
|
||||
"general_event_title": "",
|
||||
"report_guid": "",
|
||||
"report_guid_missing": "",
|
||||
"report_select_format": "",
|
||||
"report_time": "",
|
||||
"run_event_icon": "",
|
||||
"run_event_tooltip": "",
|
||||
"settings_core_icon": "",
|
||||
"settings_core_label": "",
|
||||
"settings_device_scanners": "",
|
||||
"settings_device_scanners_icon": "",
|
||||
"settings_device_scanners_info": "",
|
||||
"settings_device_scanners_label": "",
|
||||
"settings_enabled": "",
|
||||
"settings_enabled_icon": "",
|
||||
"settings_expand_all": "",
|
||||
"settings_imported": "",
|
||||
"settings_imported_label": "",
|
||||
"settings_missing": "",
|
||||
"settings_missing_block": "",
|
||||
"settings_old": "",
|
||||
"settings_other_scanners": "",
|
||||
"settings_other_scanners_icon": "",
|
||||
"settings_other_scanners_label": "",
|
||||
"settings_publishers": "",
|
||||
"settings_publishers_icon": "",
|
||||
"settings_publishers_info": "",
|
||||
"settings_publishers_label": "",
|
||||
"settings_saved": "",
|
||||
"settings_system_icon": "",
|
||||
"settings_system_label": "",
|
||||
"settings_update_item_warning": "",
|
||||
"test_event_icon": "",
|
||||
"test_event_tooltip": ""
|
||||
}
|
||||
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "",
|
||||
"BackDevices_darkmode_disabled": "",
|
||||
"BackDevices_darkmode_enabled": "",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "",
|
||||
@@ -279,6 +281,7 @@
|
||||
"Gen_DataUpdatedUITakesTime": "",
|
||||
"Gen_Delete": "",
|
||||
"Gen_DeleteAll": "",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "",
|
||||
"Gen_Filter": "",
|
||||
"Gen_LockedDB": "",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "",
|
||||
"Gen_Saved": "",
|
||||
"Gen_Search": "",
|
||||
"Gen_SelectToPreview": "",
|
||||
"Gen_Selected_Devices": "",
|
||||
"Gen_Switch": "",
|
||||
"Gen_Upd": "",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "",
|
||||
"Login_Box": "",
|
||||
"Login_Default_PWD": "",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "",
|
||||
"Login_Psw_alert": "",
|
||||
"Login_Psw_folder": "",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "",
|
||||
"Plugins_Filters_Mac": "",
|
||||
"Plugins_History": "",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "",
|
||||
"Plugins_Out_of": "",
|
||||
"Plugins_Unprocessed_Events": "",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "",
|
||||
"Reports_Sent_Log": "",
|
||||
"SCAN_SUBNETS_description": "",
|
||||
"SCAN_SUBNETS_name": "",
|
||||
"SYSTEM_TITLE": "",
|
||||
"Setting_Override": "",
|
||||
"Setting_Override_Description": "",
|
||||
"Settings_Metadata_Toggle": "",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "",
|
||||
"Settings_device_Scanners_desync_popup": "",
|
||||
"Speedtest_Results": "",
|
||||
|
||||
@@ -50,24 +50,26 @@
|
||||
"BackDevices_DBTools_DelActHistoryError": "Fehler beim Zurücksetzen der Netzwerkaktivitätsanzeige.",
|
||||
"BackDevices_DBTools_DelDevError_a": "Fehler beim Löschen des Gerätes.",
|
||||
"BackDevices_DBTools_DelDevError_b": "Fehler beim Löschen der Geräte.",
|
||||
"BackDevices_DBTools_DelDev_a": "Gerät gelöscht.",
|
||||
"BackDevices_DBTools_DelDev_b": "Geräte gelöscht.",
|
||||
"BackDevices_DBTools_DelEvents": "Events gelöscht.",
|
||||
"BackDevices_DBTools_DelEventsError": "Fehler beim Löschen der Ereignisse.",
|
||||
"BackDevices_DBTools_DelDev_a": "Gerät wurde gelöscht",
|
||||
"BackDevices_DBTools_DelDev_b": "Geräte wurden gelöscht",
|
||||
"BackDevices_DBTools_DelEvents": "Events wurden gelöscht",
|
||||
"BackDevices_DBTools_DelEventsError": "Fehler beim Löschen der Ereignisse",
|
||||
"BackDevices_DBTools_ImportCSV": "Die Geräte aus der CSV-Datei wurden erfolgreich importiert.",
|
||||
"BackDevices_DBTools_ImportCSVError": "Die CSV-Datei konnte nicht importiert werden. Stellen Sie sicher, dass das Format korrekt ist.",
|
||||
"BackDevices_DBTools_ImportCSVMissing": "Die CSV-Datei konnte nicht in <b>/config/devices.csv</b> gefunden werden.",
|
||||
"BackDevices_DBTools_Purge": "Die ältesten Backups wurden gelöscht.",
|
||||
"BackDevices_DBTools_UpdDev": "Gerät erfolgreich aktualisiert.",
|
||||
"BackDevices_DBTools_UpdDevError": "Fehler beim Aktualisieren des Gerätes.",
|
||||
"BackDevices_DBTools_Upgrade": "Datenbank erfolgreich aktualisiert.",
|
||||
"BackDevices_DBTools_UpgradeError": "Fehler beim Aktualisieren der Datenbank.",
|
||||
"BackDevices_DBTools_Purge": "Die ältesten Backups wurden gelöscht",
|
||||
"BackDevices_DBTools_UpdDev": "Gerät wurde erfolgreich aktualisiert",
|
||||
"BackDevices_DBTools_UpdDevError": "Fehler beim Aktualisieren des Gerätes",
|
||||
"BackDevices_DBTools_Upgrade": "Datenbank wurde erfolgreich aktualisiert",
|
||||
"BackDevices_DBTools_UpgradeError": "Fehler beim Aktualisieren der Datenbank",
|
||||
"BackDevices_Device_UpdDevError": "Konnte Geräte nicht aktualisieren, versuchen Sie es später erneut. Die Datenbank ist wahrscheinlich wegen einer laufenden Aufgabe gesperrt.",
|
||||
"BackDevices_Restore_CopError": "Die originale Datenbank konnte nicht kopiert werden.",
|
||||
"BackDevices_Restore_Failed": "Die Wiederherstellung ist fehlgeschlagen. Stellen Sie das Backup manuell her.",
|
||||
"BackDevices_Restore_okay": "Die Wiederherstellung wurde erfolgreich ausgeführt.",
|
||||
"BackDevices_darkmode_disabled": "Heller Modus aktiviert.",
|
||||
"BackDevices_darkmode_enabled": "Dunkler Modus aktiviert.",
|
||||
"BackDevices_darkmode_disabled": "Heller Modus aktiviert",
|
||||
"BackDevices_darkmode_enabled": "Dunkler Modus aktiviert",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Dies ist eine Wartungseinstellung. Spezifiziert wie viele Tage Events gespeichert bleiben. Alle älteren Events werden periodisch gelöscht. Wird auch auf die Plugins History angewendet.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Lösche Events älter als",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Details von Gerät kopieren",
|
||||
@@ -106,7 +108,7 @@
|
||||
"DevDetail_Network_Node_hover": "Wählen Sie das Elternnetzgerät aus, an das das aktuelle Gerät angeschlossen ist, um den Netzwerkbaum zu erstellen.",
|
||||
"DevDetail_Network_Port_hover": "The port this device is connected to on the parent network device. If left empty a wifi icon is displayed in the Network tree.",
|
||||
"DevDetail_Nmap_Scans": "Nmap Scans",
|
||||
"DevDetail_Nmap_Scans_desc": "Hier kannst du manuelle NMAP Scans starten. Reguläre automatische NMAP Scans können mit dem Services & Ports (NMAP) Plugin geplant werden. Gehe zu den <a href='/settings.php' target='_blank'>Einstellungen</a> um mehr herauszufinden.",
|
||||
"DevDetail_Nmap_Scans_desc": "Hier kannst du manuelle NMAP Scans starten. Reguläre automatische NMAP Scans können mit dem Services & Ports (NMAP) Plugin geplant werden. Gehe zu den <a href='/settings.php' target='_blank'>Einstellungen</a> um erfahren",
|
||||
"DevDetail_Nmap_buttonDefault": "Standard Scan",
|
||||
"DevDetail_Nmap_buttonDefault_text": "Standard Scan: Nmap scannt die ersten 1.000 Ports für jedes angeforderte Scan-Protokoll. Damit werden etwa 93 % der TCP-Ports und 49 % der UDP-Ports erfasst. (ca. 5-10 Sekunden)",
|
||||
"DevDetail_Nmap_buttonDetail": "Detailierter Scan",
|
||||
@@ -114,7 +116,7 @@
|
||||
"DevDetail_Nmap_buttonFast": "Schneller Scan",
|
||||
"DevDetail_Nmap_buttonFast_text": "Schneller Scan: Überprüft nur die wichtigsten 100 Ports (wenige Sekunden)",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery": "Ohne Erreichbarkeitsprüfung",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery_text": "Ohne Erreichbarkeitsprüfung (-Pn Parameter): Standard Scan bei dem nmap annimmt, dass der Host erreichbar ist.",
|
||||
"DevDetail_Nmap_buttonSkipDiscovery_text": "Ohne Erreichbarkeitsprüfung (-Pn Parameter): Standard Scan, bei dem nmap annimmt, dass der Host erreichbar ist",
|
||||
"DevDetail_Nmap_resultsLink": "Nachdem ein Scan gestartet wurde, kann diese Seite verlassen werden. Resultate sind auch in der Datei <code>app_front.log</code> verfügbar.",
|
||||
"DevDetail_Owner_hover": "Der Eigentümer des Gerätes. Freies Textfeld.",
|
||||
"DevDetail_Periodselect_All": "Alle Infos",
|
||||
@@ -164,7 +166,7 @@
|
||||
"DevDetail_Tab_Tools_Internet_Info_Error": "Es ist ein Fehler aufgetreten",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Start": "Internet-Info starten",
|
||||
"DevDetail_Tab_Tools_Internet_Info_Title": "Internetinformationen",
|
||||
"DevDetail_Tab_Tools_Nslookup_Description": "Nslookup ist ein Befehlszeilentool zur Abfrage des Domain Name System (DNS). DNS ist ein System, das Domainnamen wie www.google.com in IP-Adressen wie 172.217.0.142 übersetzt. ",
|
||||
"DevDetail_Tab_Tools_Nslookup_Description": "Nslookup ist ein Befehlszeilentool zur Abfrage des Domain Name System (DNS). DNS ist ein System, das Domainnamen wie www.google.com in IP-Adressen wie 172.217.0.142 übersetzt.",
|
||||
"DevDetail_Tab_Tools_Nslookup_Error": "Fehler: IP-Adresse ist ungültig",
|
||||
"DevDetail_Tab_Tools_Nslookup_Start": "Nslookup starten",
|
||||
"DevDetail_Tab_Tools_Nslookup_Title": "Nslookup",
|
||||
@@ -288,16 +290,17 @@
|
||||
"Gen_Cancel": "Abbrechen",
|
||||
"Gen_Change": "",
|
||||
"Gen_Copy": "Run",
|
||||
"Gen_DataUpdatedUITakesTime": "OK - It may take a while for the UI to update if a scan is runnig",
|
||||
"Gen_DataUpdatedUITakesTime": "OK – Es kann einen Moment dauern, bis die Benutzeroberfläche aktualisiert wird, während ein Scan ausgeführt wird.",
|
||||
"Gen_Delete": "Löschen",
|
||||
"Gen_DeleteAll": "Delete all",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "Fehler",
|
||||
"Gen_Filter": "Filter",
|
||||
"Gen_LockedDB": "ERROR - DB eventuell gesperrt - Nutze die Konsole in den Entwickler Werkzeugen (F12) zur Überprüfung oder probiere es später erneut.",
|
||||
"Gen_Offline": "Offline",
|
||||
"Gen_Okay": "Ok",
|
||||
"Gen_Purge": "Aufräumen",
|
||||
"Gen_ReadDocs": "Mehr in der Dokumentation",
|
||||
"Gen_ReadDocs": "Mehr in der Dokumentation.",
|
||||
"Gen_Remove_All": "Alle entfernen",
|
||||
"Gen_Remove_Last": "Letzte entfernen",
|
||||
"Gen_Restore": "Wiederherstellen",
|
||||
@@ -305,6 +308,7 @@
|
||||
"Gen_Save": "Speichern",
|
||||
"Gen_Saved": "Gespeichert",
|
||||
"Gen_Search": "Suchen",
|
||||
"Gen_SelectToPreview": "",
|
||||
"Gen_Selected_Devices": "Ausgewählte Geräte:",
|
||||
"Gen_Switch": "Umschalten",
|
||||
"Gen_Upd": "Aktualisierung erfolgreich",
|
||||
@@ -360,6 +364,7 @@
|
||||
"Loading": "Laden...",
|
||||
"Login_Box": "Passwort eingeben",
|
||||
"Login_Default_PWD": "Standardpasswort \"123456\" noch immer aktiv.",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "Passwort",
|
||||
"Login_Psw_alert": "Sicherheitshinweis!",
|
||||
"Login_Psw_folder": "im Ordner /app/config",
|
||||
@@ -569,6 +574,7 @@
|
||||
"Plugins_DeleteAll": "Delete all (filters are ignored)",
|
||||
"Plugins_Filters_Mac": "Mac Filter",
|
||||
"Plugins_History": "Events History",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "Plugin Objects",
|
||||
"Plugins_Out_of": "von",
|
||||
"Plugins_Unprocessed_Events": "Unprocessed Events",
|
||||
@@ -612,6 +618,7 @@
|
||||
"RandomMAC_hover": "Autodetected - indicates if the device randomizes it's MAC address.",
|
||||
"Reports_Sent_Log": "Protokoll gesendeter Berichte",
|
||||
"SCAN_SUBNETS_description": "",
|
||||
"SCAN_SUBNETS_name": "",
|
||||
"SMTP_FORCE_SSL_description": "Force SSL when connecting to your SMTP server.",
|
||||
"SMTP_FORCE_SSL_name": "Force SSL",
|
||||
"SMTP_PASS_description": "The SMTP server password. ",
|
||||
@@ -630,6 +637,7 @@
|
||||
"Setting_Override": "Override value",
|
||||
"Setting_Override_Description": "Enabling this option will override an App supplied default value with the value specified above.",
|
||||
"Settings_Metadata_Toggle": "Show/hide metadata for the given setting.",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "⚠ Die Zeitpläne des Gerätescanners sind nicht synchronisiert.",
|
||||
"Settings_device_Scanners_desync_popup": "",
|
||||
"Speedtest_Results": "Ergebnisse des Geschwindigkeitstests",
|
||||
@@ -756,7 +764,7 @@
|
||||
"settings_enabled": "Aktive Einstellungen",
|
||||
"settings_enabled_icon": "",
|
||||
"settings_expand_all": "Expand all",
|
||||
"settings_imported": "Last time settings were imported from the app.conf file:",
|
||||
"settings_imported": "Die letzten Einstellungen wurden aus der Datei app.conf importiert",
|
||||
"settings_imported_label": "Einstellungen importiert",
|
||||
"settings_missing": "",
|
||||
"settings_missing_block": "",
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "Restore executed successfully.",
|
||||
"BackDevices_darkmode_disabled": "Darkmode Disabled",
|
||||
"BackDevices_darkmode_enabled": "Darkmode Enabled",
|
||||
"CLEAR_NEW_FLAG_description": "If enabled (<code>0</code> is disabled), devices flagged as <b>New Device</b> will be unflagged if the time limit (specified in hours) exceeds their <b>First Session</b> time.",
|
||||
"CLEAR_NEW_FLAG_name": "Clear new flag",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "This is a maintenance setting. This specifies the number of days worth of event entries that will be kept. All older events will be deleted periodically. Also applies on Plugin Events History.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Delete events older than",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copy details from device",
|
||||
@@ -279,6 +281,7 @@
|
||||
"Gen_DataUpdatedUITakesTime": "OK - It may take a while for the UI to update if a scan is running.",
|
||||
"Gen_Delete": "Delete",
|
||||
"Gen_DeleteAll": "Delete all",
|
||||
"Gen_Description": "Description",
|
||||
"Gen_Error": "Error",
|
||||
"Gen_Filter": "Filter",
|
||||
"Gen_LockedDB": "ERROR - DB might be locked - Check F12 Dev tools -> Console or try later.",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "Save",
|
||||
"Gen_Saved": "Saved",
|
||||
"Gen_Search": "Search",
|
||||
"Gen_SelectToPreview": "Select to preview",
|
||||
"Gen_Selected_Devices": "Selected Devices:",
|
||||
"Gen_Switch": "Switch",
|
||||
"Gen_Upd": "Updated successfully",
|
||||
@@ -303,8 +307,8 @@
|
||||
"Gen_Work_In_Progress": "Work in progress, good time to feedback on https://github.com/jokob-sk/NetAlertX/issues",
|
||||
"General_display_name": "General",
|
||||
"General_icon": "<i class=\"fa fa-gears\"></i>",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "This is a maintenance setting. If enabled (<code>0</code> is disabled), devices marked as <b>New Device</b> will be deleted if their <b>First Session</b> time was older than the specified hours in this setting. Use this setting if you want to auto-delete <b>New Devices</b> after <code>X</code> hours.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Keep new devices for",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "This is a maintenance setting <b>DELETING devices</b>. If enabled (<code>0</code> is disabled), devices marked as <b>New Device</b> will be deleted if their <b>First Session</b> time was older than the specified hours in this setting. Use this setting if you want to auto-delete <b>New Devices</b> after <code>X</code> hours.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Delete new devices after",
|
||||
"HelpFAQ_Cat_Detail": "Details",
|
||||
"HelpFAQ_Cat_Detail_300_head": "What means ",
|
||||
"HelpFAQ_Cat_Detail_300_text_a": "means a network device (a device of the type AP, Gateway, Firewall, Hypervisor, Powerline, Switch, WLAN, PLC, Router,USB LAN Adapter, USB WIFI Adapter, or Internet). Custom types can be added via the <code>NETWORK_DEVICE_TYPES</code> setting.",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "Loading...",
|
||||
"Login_Box": "Enter your password",
|
||||
"Login_Default_PWD": "Default password \"123456\" is still active.",
|
||||
"Login_Info": "Passwords are set via the Set Password plugin. Check the <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/set_password\">SETPWD docs</a> if you have issues logging in.",
|
||||
"Login_Psw-box": "Password",
|
||||
"Login_Psw_alert": "Password Alert!",
|
||||
"Login_Psw_folder": "in the config folder.",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "Delete all (filters are ignored)",
|
||||
"Plugins_Filters_Mac": "Mac Filter",
|
||||
"Plugins_History": "Events History",
|
||||
"Plugins_Obj_DeleteListed": "Delete Listed Objects",
|
||||
"Plugins_Objects": "Plugin Objects",
|
||||
"Plugins_Out_of": "out of",
|
||||
"Plugins_Unprocessed_Events": "Unprocessed Events",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "Autodetected - indicates if the device randomizes it's MAC address.",
|
||||
"Reports_Sent_Log": "Sent Reports Log",
|
||||
"SCAN_SUBNETS_description": "Most on-network scanners (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) rely on scanning specific network interfaces and subnets. Check the <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">subnets documentation</a> for help on this setting, especially VLANs, what VLANs are supported, or how to figure out the network mask and your interface. <br/> <br/> An alternative to on-network scanners is to enable some other Device scanners/importers that don't rely on NetAlert<sup>X</sup> having access to the network (UNIFI, dhcp.leases, PiHole, etc.). <br/> <br/> Note: The scan time itself depends on the number of IP addresses to check, so set this up carefully with the appropriate network mask and interface.",
|
||||
"SCAN_SUBNETS_name": "Networks to scan",
|
||||
"SYSTEM_TITLE": "System Information",
|
||||
"Setting_Override": "Override value",
|
||||
"Setting_Override_Description": "Enabling this option will override an App supplied default value with the value specified above.",
|
||||
"Settings_Metadata_Toggle": "Show/hide metadata for the given setting.",
|
||||
"Settings_Show_Description": "Show setting description.",
|
||||
"Settings_device_Scanners_desync": "⚠ Device scanner schedules are out-of-sync.",
|
||||
"Settings_device_Scanners_desync_popup": "Schedules of devices scanners (<code>*_RUN_SCHD</code>) are not the same. This will result into inconsistent device online/offline notifications. Unless this is intended, please use the same schedule for all enabled <b>🔍Device scanners</b>.",
|
||||
"Speedtest_Results": "Speedtest Results",
|
||||
@@ -647,11 +655,11 @@
|
||||
"UI_ICONS_name": "Pre-defined icons",
|
||||
"UI_LANG_description": "Select the preferred UI language. Help translating or suggest languages in the online portal of <a href=\"https://hosted.weblate.org/projects/pialert/core/\" target=\"_blank\">Weblate</a>.",
|
||||
"UI_LANG_name": "UI Language",
|
||||
"UI_MY_DEVICES_description": "Devices of which statuses should be shown in the default <b>My Devices</b> view. (<code>CTRL + Click</code> to select/deselect)",
|
||||
"UI_MY_DEVICES_description": "Devices of which statuses should be shown in the default <b>My Devices</b> view.",
|
||||
"UI_MY_DEVICES_name": "Show in My Devices view",
|
||||
"UI_NOT_RANDOM_MAC_description": "Mac prefixes which shouldn't be marked as Random devices. Enter for example <code>52</code> to exclude devices starting with <code>52:xx:xx:xx:xx:xx</code> from being marked as devices with a random MAC address.",
|
||||
"UI_NOT_RANDOM_MAC_name": "Don't mark as Random",
|
||||
"UI_PRESENCE_description": "Select what statuses should be shown in the <b>Device presence</b> chart in the <a href=\"/devices.php\" target=\"_blank\">Devices</a> page. (<code>CTRL + Click</code> to select/deselect)",
|
||||
"UI_PRESENCE_description": "Select what statuses should be shown in the <b>Device presence</b> chart in the <a href=\"/devices.php\" target=\"_blank\">Devices</a> page.",
|
||||
"UI_PRESENCE_name": "Show in presence chart",
|
||||
"UI_REFRESH_description": "Enter number of seconds after which the UI reloads. Set to <code>0</code> to disable.",
|
||||
"UI_REFRESH_name": "Auto-refresh UI",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"BackDevices_Restore_okay": "Restauración ejecutado con éxito.",
|
||||
"BackDevices_darkmode_disabled": "Darkmode Desactivado",
|
||||
"BackDevices_darkmode_enabled": "Darkmode Activado",
|
||||
"CLEAR_NEW_FLAG_description": "Si está habilitado (<code>0</code> está desactivado), los dispositivos marcados como <b>Nuevo dispositivo</b> se desmarcarán si el límite de tiempo (especificado en horas) excede su tiempo de <b>primera sesión</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Eliminar la nueva bandera",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Esta es una configuración de mantenimiento. Esto especifica el número de días de entradas de eventos que se guardarán. Todos los eventos anteriores se eliminarán periódicamente.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Eliminar eventos anteriores a",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copiar detalles del dispositivo",
|
||||
@@ -284,11 +286,12 @@
|
||||
"Gen_AreYouSure": "¿Estás seguro?",
|
||||
"Gen_Backup": "Ejecutar copia de seguridad",
|
||||
"Gen_Cancel": "Cancelar",
|
||||
"Gen_Change": "",
|
||||
"Gen_Change": "Cambiar",
|
||||
"Gen_Copy": "Ejecutar",
|
||||
"Gen_DataUpdatedUITakesTime": "Correcto - La interfaz puede tardar en actualizarse si se está ejecutando un escaneo.",
|
||||
"Gen_Delete": "Eliminar",
|
||||
"Gen_DeleteAll": "Eliminar todo",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "Error",
|
||||
"Gen_Filter": "Filtro",
|
||||
"Gen_LockedDB": "Fallo - La base de datos puede estar bloqueada - Pulsa F1 -> Ajustes de desarrolladores -> Consola o prueba más tarde.",
|
||||
@@ -303,6 +306,7 @@
|
||||
"Gen_Save": "Guardar",
|
||||
"Gen_Saved": "Guardado",
|
||||
"Gen_Search": "Buscar",
|
||||
"Gen_SelectToPreview": "Seleccionar para previsualizar",
|
||||
"Gen_Selected_Devices": "Dispositivos seleccionados:",
|
||||
"Gen_Switch": "Cambiar",
|
||||
"Gen_Upd": "Actualizado correctamente",
|
||||
@@ -313,8 +317,8 @@
|
||||
"Gen_Work_In_Progress": "Trabajo en curso, un buen momento para hacer comentarios en https://github.com/jokob-sk/NetAlertX/issues",
|
||||
"General_display_name": "General",
|
||||
"General_icon": "<i class=\"fa fa-gears\"></i>",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "Esta es una configuración de mantenimiento. Si está habilitado (<code>0</code> está deshabilitado), los dispositivos marcados como <b>Nuevo dispositivo</b> se eliminarán si su <b>Primera sesión</b> el tiempo era anterior a las horas especificadas en esta configuración. Utilice esta configuración si desea eliminar automáticamente <b>Nuevos dispositivos</b> después de <code>X</code> horas.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Guardar nuevos dispositivos para",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "Se trata de una configuración de mantenimiento <b>BORRAR dispositivos</b>. Si está activado (<code>0</code> está desactivado), los dispositivos marcados como <b>Nuevo dispositivo</b> se eliminarán si su fecha de <b>primera sesión</b> es anterior a las horas especificadas en este ajuste. Use este ajuste si desea eliminar automáticamente <b>Nuevos dispositivos</b> después de <code>X</code> horas.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Eliminar nuevos dispositivos después",
|
||||
"HelpFAQ_Cat_Detail": "Detalles",
|
||||
"HelpFAQ_Cat_Detail_300_head": "¿Qué significa? ",
|
||||
"HelpFAQ_Cat_Detail_300_text_a": "significa un dispositivo de red (un dispositivo del tipo AP, Gateway, Firewall, Hypervisor, Powerline, Switch, WLAN, PLC, Router,Adaptador LAN USB, Adaptador WIFI USB o Internet). Los tipos personalizados pueden añadirse mediante el ajuste <code>NETWORK_DEVICE_TYPES</code>.",
|
||||
@@ -358,6 +362,7 @@
|
||||
"Loading": "Cargando...",
|
||||
"Login_Box": "Ingrese su contraseña",
|
||||
"Login_Default_PWD": "La contraseña por defecto \"123456\" sigue activa.",
|
||||
"Login_Info": "Las contraseñas se establecen a través del plugin Establecer contraseña. Compruebe la <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/set_password\">documentación SETPWD</a> si tiene problemas para iniciar sesión.",
|
||||
"Login_Psw-box": "Contraseña",
|
||||
"Login_Psw_alert": "¡Alerta de Contraseña!",
|
||||
"Login_Psw_folder": "en la carpeta config.",
|
||||
@@ -567,6 +572,7 @@
|
||||
"Plugins_DeleteAll": "Eliminar todo (se ignoran los filtros)",
|
||||
"Plugins_Filters_Mac": "Filtro MAC",
|
||||
"Plugins_History": "Historial de eventos",
|
||||
"Plugins_Obj_DeleteListed": "Eliminar objetos enumerados",
|
||||
"Plugins_Objects": "Objetos del Plugin",
|
||||
"Plugins_Out_of": "de",
|
||||
"Plugins_Unprocessed_Events": "Eventos sin procesar",
|
||||
@@ -629,6 +635,7 @@
|
||||
"Setting_Override": "Sobreescribir el valor",
|
||||
"Setting_Override_Description": "Habilitar esta opción anulará un valor predeterminado proporcionado por la aplicación con el valor especificado anteriormente.",
|
||||
"Settings_Metadata_Toggle": "Mostrar/ocultar los metadatos de la configuración.",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_Title": "<i class=\"fa fa-cog\"> Configuración</i>",
|
||||
"Settings_device_Scanners_desync": "⚠ Los horarios del escáner de los dispositivos no están sincronizados.",
|
||||
"Settings_device_Scanners_desync_popup": "Los horarios de escáneres de dispositivos (<code> *_RUN_SCHD</code> ) no son lo mismo. Esto resultará en notificaciones inconsistentes del dispositivo en línea/fuera de línea. A menos que sea así, utilice el mismo horario para todos los habilitados.<b> 🔍Escáneres de dispositivos</b> .",
|
||||
@@ -724,8 +731,8 @@
|
||||
"UI_PRESENCE_name": "Mostrar en el gráfico de presencia",
|
||||
"UI_REFRESH_description": "Ingrese el número de segundos después de los cuales se recarga la interfaz de usuario. Ajustado a <code> 0 </code> para desactivar.",
|
||||
"UI_REFRESH_name": "Actualización automática de la interfaz de usuario",
|
||||
"VERSION_description": "",
|
||||
"VERSION_name": "",
|
||||
"VERSION_description": "Valor de ayuda de versión o marca de tiempo para comprobar si la aplicación se ha actualizado.",
|
||||
"VERSION_name": "Versión o marca de tiempo",
|
||||
"WEBHOOK_PAYLOAD_description": "El formato de datos de carga de Webhook para el atributo <code>body</code> > <code>attachments</code> > <code>text</code> en el json de carga. Vea un ejemplo de la carga <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/front/report_templates/webhook_json_sample.json\">aquí</a>. (por ejemplo: para discord use <code>text</code>)",
|
||||
"WEBHOOK_PAYLOAD_name": "Tipo de carga",
|
||||
"WEBHOOK_REQUEST_METHOD_description": "El método de solicitud HTTP que se utilizará para la llamada de webhook.",
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "Restauration exécutée avec succès.",
|
||||
"BackDevices_darkmode_disabled": "Mode sombre désactivé",
|
||||
"BackDevices_darkmode_enabled": "Mode sombre activé",
|
||||
"CLEAR_NEW_FLAG_description": "Si activé (<code>0</code> est activé), les appareils marqués comme <b>Nouvel appareil</b> seront démarqués si la durée limite (spécifiée en heures) dépasse la durée de la <b>Première Session</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Supprime le nouveau drapeau",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Il s'agit d'un paramètre de maintenance. Il indique le nombre de jours pendant lesquels les entrées d'événements seront conservées. Tous les événements plus anciens seront supprimés périodiquement. S'applique également à l'historique des événements du plugin.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Supprimer les événements plus anciens que",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copier les détails de l'appareil",
|
||||
@@ -72,7 +74,7 @@
|
||||
"DevDetail_EveandAl_Skip": "Passer les notifications répétées durant",
|
||||
"DevDetail_EveandAl_Title": "<i class=\"fa fa-bolt\"></i> Configuration des événements & Alertes",
|
||||
"DevDetail_Events_CheckBox": "Masquer les événements de connexion",
|
||||
"DevDetail_GoToNetworkNode": "Naviguer à la page Réseau pour le noeud sélectionné",
|
||||
"DevDetail_GoToNetworkNode": "Naviguer à la page Réseau pour le nœud sélectionné.",
|
||||
"DevDetail_Icon": "Icône",
|
||||
"DevDetail_Icon_Descr": "Renseigner le nom d'une icône Font Awesome sans le préfixe fa- ou la classe complète ; par ex. fa fa-brands fa-apple.",
|
||||
"DevDetail_Loading": "Chargement…",
|
||||
@@ -96,7 +98,7 @@
|
||||
"DevDetail_Nmap_Scans": "Scans NMAP manuels",
|
||||
"DevDetail_Nmap_Scans_desc": "Vous pouvez lancer des scans NMAP manuels. Vous pouvez aussi programmer des sans réguliers via le plugin Services & Ports (NMAP). Aller dans les <a href='/settings.php' target='_blank'>Paramètres</a> pour plus de details",
|
||||
"DevDetail_Nmap_buttonDefault": "Scan par défaut",
|
||||
"DevDetail_Nmap_buttonDefault_text": "Scan par défaut : NMAP scanne les 1 000 premiers ports pour chaque demande de scan de protocole. Cela couvre environ 93% des ports TCP et 49% des ports UDP (environ 5 secondes).",
|
||||
"DevDetail_Nmap_buttonDefault_text": "Scan par défaut : NMAP scanne les 1 000 premiers ports pour chaque demande de scan de protocole. Cela couvre environ 93% des ports TCP et 49% des ports UDP (environ 5 secondes)",
|
||||
"DevDetail_Nmap_buttonDetail": "Scan détaillé",
|
||||
"DevDetail_Nmap_buttonDetail_text": "Scan détaillé : scan par défaut avec la détection de système d'exploitation, la détection de version, l'analyse de script et le traceroute (jusqu'à 30 secondes ou plus)",
|
||||
"DevDetail_Nmap_buttonFast": "Scan rapide",
|
||||
@@ -228,7 +230,7 @@
|
||||
"Device_Title": "Appareils",
|
||||
"Donations_Others": "Autres",
|
||||
"Donations_Platforms": "Plateformes de sponsoring",
|
||||
"Donations_Text": "Coucou 👋! </br> Merci d'avoir cliqué ici 😅 </br> </br> J'essaie de récolter des donations pour vous faire un meilleur produit. En plus, ça m'aide à éviter le burn-out pour développer cette application plus longtemps. Toute subvention (régulière ou non) me donne envie de poursuivre le développement de cette application.</br> J'aimerais réduire mon activité principale pour me concentrer plus longuement à NetAlertX. Vous auriez plus de fonctionnalités, une application mieux finie et avec moins de bugs.</br> </br> Merci de votre lecture - je vous suis reconnaissant pour votre soutien ❤🙏 </br> </br> Version courte : en me soutenant, vous aurez : </br> </br> <ul><li>Des mises à jour régulières pour protéger vos données personnelles et familiales 🔄</li><li>Moins de bugs 🐛🔫</li><li>Des fonctionnalités plus riches et plus nombreuses ➕</li><li>Je ne me retrouve pas en burn-out 🔥🤯</li><li>Des versions moins à la va-vite 💨</li><li>une meilleure documentation <20></li><li>Un support meilleur et plus réactif en cas de problème 🆘</li></ul> </br> 📧Envoyez-moi un courriel à <a href='mailto:jokob@duck.com?subject=NetAlertX'>jokob@duck.com</a> si vous voulez mebcontacter ou du je peux ajouter une autre plateforme de soutien. </br>",
|
||||
"Donations_Text": "Coucou 👋 ! </br> Merci d'avoir cliqué ici 😅 </br> </br> J'essaie de récolter des donations pour vous faire un meilleur produit. En plus, ça m'aide à éviter le burn-out pour développer cette application plus longtemps. Toute subvention (régulière ou non) me donne envie de poursuivre le développement de cette application.</br> J'aimerais réduire mon activité principale pour me concentrer plus longuement à NetAlertX. Vous auriez plus de fonctionnalités, une application mieux finie et avec moins de bugs.</br> </br> Merci de votre lecture - je vous suis reconnaissant pour votre soutien ❤🙏 </br> </br> Version courte : en me soutenant, vous aurez : </br> </br> <ul><li>Des mises à jour régulières pour protéger vos données personnelles et familiales 🔄</li><li>Moins de bugs 🐛🔫</li><li>Des fonctionnalités plus riches et plus nombreuses ➕</li><li>Je ne me retrouve pas en burn-out 🔥🤯</li><li>Des versions moins à la va-vite 💨</li><li>une meilleure documentation <20></li><li>Un support meilleur et plus réactif en cas de problème 🆘</li></ul> </br> 📧Envoyez-moi un courriel à <a href='mailto :jokob@duck.com ?subject=NetAlertX'>jokob@duck.com</a> si vous voulez me contacter ou du je peux ajouter une autre plateforme de soutien. </br>",
|
||||
"Donations_Title": "Dons",
|
||||
"ENABLE_PLUGINS_description": "Active les fonctionnalités des <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins\">Plugins</a>. Charger des plugins nécessite plus de ressources, il est recommandé de les désactiver sur des systèmes de faible puissance.",
|
||||
"ENABLE_PLUGINS_name": "Activer les Plugins",
|
||||
@@ -274,11 +276,12 @@
|
||||
"Gen_AreYouSure": "Êtes-vous sûr ?",
|
||||
"Gen_Backup": "Lancer la sauvegarde",
|
||||
"Gen_Cancel": "Annuler",
|
||||
"Gen_Change": "",
|
||||
"Gen_Change": "Changement",
|
||||
"Gen_Copy": "Lancer",
|
||||
"Gen_DataUpdatedUITakesTime": "OK - cela peut prendre du temps à l'interface pour se mettre à jour si un scan est en cours.",
|
||||
"Gen_Delete": "Supprimer",
|
||||
"Gen_DeleteAll": "Supprimer tous",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "Erreur",
|
||||
"Gen_Filter": "Filtrer",
|
||||
"Gen_LockedDB": "Erreur - La base de données est peut-être verrouillée - Vérifier avec les outils de dév via F12 -> Console ou essayer plus tard.",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "Enregistrer",
|
||||
"Gen_Saved": "Enregistré",
|
||||
"Gen_Search": "Recherche",
|
||||
"Gen_SelectToPreview": "Sélectionnez pour prévisualiser",
|
||||
"Gen_Selected_Devices": "Appareils sélectionnés :",
|
||||
"Gen_Switch": "Basculer",
|
||||
"Gen_Upd": "Mise à jour réussie",
|
||||
@@ -304,7 +308,7 @@
|
||||
"General_display_name": "Général",
|
||||
"General_icon": "<i class=\"fa fa-gears\"></i>",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "Paramétrage de maintenance. S'il est activé (<code>0</code> s'il est désactivé), les appareils marqués comme <b>Nouvel appareil</b> seront supprimés si leur durée depuis la <b>première session</b> est plus ancienne que le nombre d'heures paramétré. Utilisez ce paramétrage si vous voulez supprimer automatiquement les <b>Nouveaux appareils</b> après <code>X</code> heures.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Garder les appareils en Nouveau pendant",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Supprimer les nouveaux appareils après",
|
||||
"HelpFAQ_Cat_Detail": "Détails",
|
||||
"HelpFAQ_Cat_Detail_300_head": "Que signifie ",
|
||||
"HelpFAQ_Cat_Detail_300_text_a": "signifie que cela représente un équipement réseau (Access Point, Gateway, Firewall, Hyperviseur, Powerline, Switch, WLAN, CPL, adaptateur Ethernet USB, adaptateur Wifi USB, Internet). Les types d'appareils personnalisés peuvent être ajoutés via le paramètre <code>NETWORK_DEVICE_TYPES</code>.",
|
||||
@@ -329,7 +333,7 @@
|
||||
"HelpFAQ_Cat_General_102_head": "Un message m'indique que la base de données est en lecture seule.",
|
||||
"HelpFAQ_Cat_General_102_text": "Vérifiez dans le répertoire de NetAlertX si la base de données (db) possède les bonnes permissions :<br> <span class=\"text-danger help_faq_code\">drwxrwx--- 2 (votre nom d'utilisateur) www-data</span><br> Si la permission n'est pas correcte, vous pouvez la modifier en passant les commandes suivantes dans le terminal :<br> <span class=\"text-danger help_faq_code\">sudo chgrp -R www-data /app/db<br>chmod -R 770 /app/db</span><br>Si la base de données est encore en lecture seule, tentez de la réinstaller ou de restaurer une sauvegarde de la base à partir de la page de maintenance.",
|
||||
"HelpFAQ_Cat_General_102docker_head": "Erreur de base de données (erreurs AJAX, lecture seule, non trouvé)",
|
||||
"HelpFAQ_Cat_General_102docker_text": "Vérifiez avec attention que vous avez suivi les instructions dans le <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles\">lisez-moi (readme) Docker (contient les infos les plus récentes)</a>. <br/> <br/> <ul data-sourcepos=\"49:4-52:146\" dir=\"auto\"><li data-sourcepos=\"49:4-49:106\"> Télécharger la <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/db/app.db\">base de données originelle depuis GitHub</a>.</li><li data-sourcepos=\"50:4-50:195\">Relier le fichier <code>app.db</code> (<g-emoji class=\"g-emoji\" alias=\"warning\" fallback-src=\"https://github.githubassets.com/images/icons/emoji/unicode/26a0.png\">⚠</g-emoji> pas le dossier) au-dessus avec <code>/app/db/app.db</code> (plus de détails dans les <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles#-examples\">Exemples</a>).</li><li data-sourcepos=\"51:4-51:161\">. Si vous rencontrez des erreurs (erreurs Ajax, impossible d'écrire dans la base, etc.), vérifiez que les permissions sont correctement définies, éventuellement regarder dans les blogs présents dans <code>/app/front/log</code>.</li><li data-sourcepos=\"52:4-52:146\">. Pour résoudre les problèmes de permission, vous pouvez aussi essayer de créer une sauvegarde de la base de données et lancer une restauration via la section <strong>Maintenance > Sauvegarde/Restauration</strong>.</li><li data-sourcepos=\"53:4-53:228\">Si la base de données est en lecture seule, vous pouvez résoudre cela en définissant le propriétaire et le groupe en lançant la commande suivante depuis le système hôte : <code>docker exec netalertx chown -R www-data:www-data /app/db/app.db</code>.</li></ul>",
|
||||
"HelpFAQ_Cat_General_102docker_text": "Vérifiez avec attention que vous avez suivi les instructions dans le <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles\">lisez-moi (readme) Docker (contient les infos les plus récentes)</a>. <br/> <br/> <ul data-sourcepos=\"49:4-52:146\" dir=\"auto\"><li data-sourcepos=\"49:4-49:106\"> Télécharger la <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/blob/main/db/app.db\">base de données originelle depuis GitHub</a>.</li><li data-sourcepos=\"50:4-50:195\">Relier le fichier <code>app.db</code> (<g-emoji class=\"g-emoji\" alias=\"warning\" fallback-src=\"https://github.githubassets.com/images/icons/emoji/unicode/26a0.png\">⚠</g-emoji> pas le dossier) au-dessus avec <code>/app/db/app.db</code> (plus de détails dans les <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/dockerfiles#-examples\">Exemples</a>).</li><li data-sourcepos=\"51:4-51:161\">. Si vous rencontrez des erreurs (erreurs Ajax, impossible d'écrire dans la base, etc.), vérifiez que les permissions sont correctement définies, éventuellement regarder dans les blogs présents dans <code>/app/front/log</code>.</li><li data-sourcepos=\"52:4-52:146\">. Pour résoudre les problèmes de permission, vous pouvez aussi essayer de créer une sauvegarde de la base de données et lancer une restauration via la section <strong>Maintenance > Sauvegarde/Restauration</strong>.</li><li data-sourcepos=\"53:4-53:228\">Si la base de données est en lecture seule, vous pouvez résoudre cela en définissant le propriétaire et le groupe en lançant la commande suivante depuis le système hôte : <code>docker exec netalertx chown -R www-data:www-data /app/db/app.db</code>.</li></ul>",
|
||||
"HelpFAQ_Cat_General_103_head": "La page d'authentification n'apparaît pas, même après avoir changé le mot de passe.",
|
||||
"HelpFAQ_Cat_General_103_text": "En plus du mot de passe, le fichier de configuration doit contenir <span class=\"text-danger help_faq_code\">/app/config/app.conf</span>. De plus, le paramètre <span class=\"text-danger help_faq_code\">PIALERT_WEB_PROTECTION</span> doit être à la valeur<span class=\"text-danger help_faq_code\">True</span>.",
|
||||
"HelpFAQ_Cat_Network_600_head": "A quoi sert cette page ?",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "Chargement...",
|
||||
"Login_Box": "Saisir votre mot de passe",
|
||||
"Login_Default_PWD": "Le mot de passe par défaut \"123456\" est encore actif.",
|
||||
"Login_Info": "Les mots de passe sont définis via le plugin Set Password. Vérifiez la <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/set_password\">documentation de SETPWD</a> si vous rencontrez des difficultés à vous identifier.",
|
||||
"Login_Psw-box": "Mot de passe",
|
||||
"Login_Psw_alert": "Alerte de mot de passe !",
|
||||
"Login_Psw_folder": "dans le dossier de configuration.",
|
||||
@@ -371,7 +376,7 @@
|
||||
"Maintenance_Tool_ExportCSV_text": "Génère un fichier CSV (valeurs séparées par des virgules), contenant la liste des appareils, dont les liens entre nœuds Réseaux et les appareils connectés. Vous pouvez aussi lancer cet export depuis l'URL <code>votre URL de NetAlertX/php/server/devices.php?action=ExportCSV</code> ou en activant le plugin <a href=\"settings.php#CSVBCKP_header\">CSV Backup</a>.",
|
||||
"Maintenance_Tool_ImportCSV": "Import CSV",
|
||||
"Maintenance_Tool_ImportCSV_noti": "Import CSV",
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "Êtes-vous sûr de vouloir importer le fichier CSV ? Cela écrasera complètement les appareils de votre base de données.",
|
||||
"Maintenance_Tool_ImportCSV_noti_text": "Êtes-vous sûr de vouloir importer le fichier CSV ? Cela <b>écrasera</b> complètement les appareils de votre base de données.",
|
||||
"Maintenance_Tool_ImportCSV_text": "Avant d'utiliser cette fonctionnalité, il est recommandé de faire une sauvegarde. La fonctionnalité importe un fichier CSV (valeurs séparées par des virgules) contenant la liste des appareils, dont les liens réseau entre les nœuds du réseau et ces appareils. Pour cela, placer un fichier CSV nommé <b>devices.csv</b> dans votre répertoire <b>/config</b>.",
|
||||
"Maintenance_Tool_ImportPastedCSV": "Import CSV (coller)",
|
||||
"Maintenance_Tool_ImportPastedCSV_noti_text": "Êtes-vous sûr de vouloir importer les CSV copié ? Cela va complètement <b>remplacer</b> les appareils de votre base de données.",
|
||||
@@ -510,7 +515,7 @@
|
||||
"Network_Node_Name": "Nom du nœud",
|
||||
"Network_Parent": "Appareil du réseau principal",
|
||||
"Network_Root": "Noeud racine",
|
||||
"Network_Root_Not_Configured": "Pour commencer la configuration de cet écran, sélectionner un type d'appareil réseau, par exemple une <b>Gateway</b>, dans le champ <b>Type</b> de <a href=\"deviceDetails.php?mac=Internet\">l'appareil racine pour Internet</a> <br/><br/> Plus d'informations dans le guide <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md\" target=\"_blank\">Comment configurer votre page Réseau</a>",
|
||||
"Network_Root_Not_Configured": "Pour commencer la configuration de cet écran, sélectionner un type d'appareil réseau, par exemple une <b>Gateway</b>, dans le champ <b>Type</b> de <a href=\"deviceDetails.php?mac=Internet\">l'appareil racine pour Internet</a> <br/><br/> Plus d'informations dans le guide <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/NETWORK_TREE.md\" target=\"_blank\">Comment configurer votre page Réseau</a>",
|
||||
"Network_Root_Unconfigurable": "Racine non configurable",
|
||||
"Network_Table_Hostname": "Nom de hôte",
|
||||
"Network_Table_IP": "IP",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "Tout supprimer (ne prend pas en compte les filtres)",
|
||||
"Plugins_Filters_Mac": "Filtrer par MAC",
|
||||
"Plugins_History": "Historique des événements",
|
||||
"Plugins_Obj_DeleteListed": "Effacer les objets listés",
|
||||
"Plugins_Objects": "Objets des plugins",
|
||||
"Plugins_Out_of": "sur",
|
||||
"Plugins_Unprocessed_Events": "Événements non traités",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "Détecté automatiquement - indique si l'appareil dispose d'une adresse MAC générée aléatoirement.",
|
||||
"Reports_Sent_Log": "Rapports de log transmis",
|
||||
"SCAN_SUBNETS_description": "La plupart des scanners sur le réseau (scan ARP, NMAP, Nslookup, DIG, Pholud) se base sur le scan d'une partie spécifique des interfaces réseau ou de sous-réseau. Consulter la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">documentation des sous-réseaux</a> pour plus d'aide sur ce paramètre, notamment pour des VLAN, lesquels sont supportés ou sur comment identifier le masque réseau et votre interface réseau. <br/> <br/> Une alternative à ces scanner sur le réseau et d'activer d'autres scanners d'appareils ou des importe, qui ne dépendent pas du fait de laisser NetAlert<sup>X</sup> accéder au réseau (Unifié, baux DHCP, Pi-hole, etc.).<br/><br/> Remarque : la durée du scan en lui-même dépend du nombre d'adresses IP à scanner, renseignez donc soigneusement avec le bon masque réseau et la bonne interface réseau.",
|
||||
"SCAN_SUBNETS_name": "Réseaux à scanner",
|
||||
"SYSTEM_TITLE": "Informations système",
|
||||
"Setting_Override": "Remplacer la valeur",
|
||||
"Setting_Override_Description": "Activer cette option va remplacer la valeur fournie par défaut par une application par la valeur renseignée au-dessus.",
|
||||
"Settings_Metadata_Toggle": "Afficher/masquer les méta données pour le paramètre sélectionné.",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "⚠ La planification des différents scanners d'appareils est désynchronisée.",
|
||||
"Settings_device_Scanners_desync_popup": "La planification des scanners (<code>*_RUN_SCHD</code>) n'est pas identique entre scanners. Cela va entraîner des notifications en ligne/hors-ligne non cohérentes. À moins que cela soit attendu, utilisez la même planification pour tous les <b>🔍scanners d'appareils</b> activés.",
|
||||
"Speedtest_Results": "Résultats du test de débit",
|
||||
@@ -655,8 +663,8 @@
|
||||
"UI_PRESENCE_name": "Afficher dans le graphique de présence",
|
||||
"UI_REFRESH_description": "Renseignez le nombre de secondes après lequel rafraîchir l'interface graphique. Renseignez <code>0</code> pour désactiver.",
|
||||
"UI_REFRESH_name": "Rafraîchir automatiquement l'interface graphique",
|
||||
"VERSION_description": "",
|
||||
"VERSION_name": "",
|
||||
"VERSION_description": "Valeur de la version ou du timestamp d'aide à vérifier si l'application a été mise à jour.",
|
||||
"VERSION_name": "Version ou Timestamp",
|
||||
"devices_old": "Rafraichissement...",
|
||||
"general_event_description": "L'événement que vous avez lancé peut prendre du temps avant que les tâches de fond ne soit terminées. La durée d'exécution finira une fois que la file d'exécution ci-dessous sera vide (consulter les <a href='/maintenance.php#tab_Logging'>journaux d'erreur</a> si vous rencontrez des erreurs). <br/> <br/> File d'exécution :",
|
||||
"general_event_title": "Lancement d'un événement sur mesure",
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "Ripristino eseguito correttamente.",
|
||||
"BackDevices_darkmode_disabled": "Modalità scura disabilitata",
|
||||
"BackDevices_darkmode_enabled": "Modalità scura abilitata",
|
||||
"CLEAR_NEW_FLAG_description": "Se abilitato (<code>0</code> è disabilitato), i dispositivi contrassegnati come <b>Nuovo dispositivo</b> verranno deselezionati se il limite di tempo (specificato in ore) supera il tempo della <b>Prima sessione</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Cancella nuova bandiera",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Questa è un'impostazione di manutenzione. Specifica il numero di giorni delle voci degli eventi che verranno conservati. Tutti gli eventi più vecchi verranno eliminati periodicamente. Si applica anche alla cronologia degli eventi del plugin (Plugin Events History).",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Elimina eventi più vecchi di",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copia dettagli dal dispositivo",
|
||||
@@ -279,6 +281,7 @@
|
||||
"Gen_DataUpdatedUITakesTime": "OK: l'aggiornamento dell'interfaccia utente potrebbe richiedere del tempo se è in esecuzione una scansione.",
|
||||
"Gen_Delete": "Elimina",
|
||||
"Gen_DeleteAll": "Elimina tutti",
|
||||
"Gen_Description": "Descrizione",
|
||||
"Gen_Error": "Errore",
|
||||
"Gen_Filter": "Filtro",
|
||||
"Gen_LockedDB": "ERRORE: il DB potrebbe essere bloccato, controlla F12 Strumenti di sviluppo -> Console o riprova più tardi.",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "Salva",
|
||||
"Gen_Saved": "Salvato",
|
||||
"Gen_Search": "Cerca",
|
||||
"Gen_SelectToPreview": "Seleziona per anteprima",
|
||||
"Gen_Selected_Devices": "Dispositivi selezionati:",
|
||||
"Gen_Switch": "Cambia",
|
||||
"Gen_Upd": "Aggiornato correttamente",
|
||||
@@ -303,8 +307,8 @@
|
||||
"Gen_Work_In_Progress": "Lavori in corso, è quindi un buon momento per un feedback su https://github.com/jokob-sk/NetAlertX/issues",
|
||||
"General_display_name": "Generale",
|
||||
"General_icon": "<i class=\"fa fa-gears\"></i>",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "Questa è un'opzione di manutenzione. Se abilitata (<code>0</code> è disabilitata), tutti i dispositivi marcati con <b>Nuovo dispositivo</b> verranno eliminati se l'orario della <b>Prima sessione</b> è precedente all'orario di questa impostazione. Usa questa impostazione se vuoi eliminare automaticamente i <b>Nuovi dispositivi</b> dopo <code>X</code> ore.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Mantieni nuovi dispositivi per",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "Questa è un'impostazione di manutenzione <b>ELIMINAZIONE dispositivi</b>. Se abilitata (<code>0</code> è disabilitata), tutti i dispositivi marcati con <b>Nuovo dispositivo</b> verranno eliminati se l'orario della <b>Prima sessione</b> è precedente all'orario di questa impostazione. Usa questa impostazione se vuoi eliminare automaticamente i <b>Nuovi dispositivi</b> dopo <code>X</code> ore.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Elimina nuovi dispositivi dopo",
|
||||
"HelpFAQ_Cat_Detail": "Dettagli",
|
||||
"HelpFAQ_Cat_Detail_300_head": "Cosa significa ",
|
||||
"HelpFAQ_Cat_Detail_300_text_a": "indica un dispositivo di rete (un dispositivo di tipo AP, Gateway, Firewall, Hypervisor, Powerline, Switch, WLAN, PLC, Router, USB LAN Adapter, USB WIFI Adapter, o Internet). Tipi personalizzati possono essere aggiunti attraverso l'impostazione <code>NETWORK_DEVICE_TYPES</code>.",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "Caricamento...",
|
||||
"Login_Box": "Inserisci la tua password",
|
||||
"Login_Default_PWD": "La password predefinita \"123456\" è ancora attiva.",
|
||||
"Login_Info": "Le password vengono impostate tramite il plugin Set Password. Controlla la <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/set_password\">documentazione SETPWD</a> se riscontri problemi di accesso.",
|
||||
"Login_Psw-box": "Password",
|
||||
"Login_Psw_alert": "Avviso password!",
|
||||
"Login_Psw_folder": "nella cartella di configurazione.",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "Elimina tutti (i filtri vengono ignorati)",
|
||||
"Plugins_Filters_Mac": "Filtro MAC",
|
||||
"Plugins_History": "Storico eventi",
|
||||
"Plugins_Obj_DeleteListed": "Elimina oggetti elencati",
|
||||
"Plugins_Objects": "Oggetti plugin",
|
||||
"Plugins_Out_of": "fuori da",
|
||||
"Plugins_Unprocessed_Events": "Eventi non processati",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "Rilevato automaticamente: indica se il dispositivo genera il suo indirizzo MAC casualmente.",
|
||||
"Reports_Sent_Log": "Log rapporti inviati",
|
||||
"SCAN_SUBNETS_description": "La maggior parte degli scanner di rete (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) si basano sulla scansione di interfacce di rete e sottoreti specifiche. Consulta la <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">documentazione sulle sottoreti</a> per assistenza su questa impostazione, in particolare VLAN, quali VLAN sono supportate o come individuare la maschera di rete e l'interfaccia. <br/> <br/> Un'alternativa agli scanner in rete è abilitare altri scanner/importatori di dispositivi che non si affidano a NetAlert<sup>X</sup> che hanno accesso alla rete (UNIFI, dhcp.leases , PiHole, ecc.). <br/> <br/> Nota: il tempo di scansione stesso dipende dal numero di indirizzi IP da controllare, quindi impostalo attentamente con la maschera di rete e l'interfaccia appropriate.",
|
||||
"SCAN_SUBNETS_name": "Reti da scansionare",
|
||||
"SYSTEM_TITLE": "Informazioni sistema",
|
||||
"Setting_Override": "Sovrascrivi valore",
|
||||
"Setting_Override_Description": "L'abilitazione di questa opzione sovrascriverà il valore predefinito fornito dall'app con il valore specificato sopra.",
|
||||
"Settings_Metadata_Toggle": "Mostra/nascondi i metadati per l'impostazione specificata.",
|
||||
"Settings_Show_Description": "Mostra descrizione dell'impostazione.",
|
||||
"Settings_device_Scanners_desync": "⚠ Le pianificazioni dello scanner del dispositivo non sono sincronizzate.",
|
||||
"Settings_device_Scanners_desync_popup": "Gli orari degli scanner dei dispositivi (<code>*_RUN_SCHD</code>) non sono gli stessi. Questo comporterà notifiche online/offline incoerenti del dispositivo. A meno che ciò non sia previsto, utilizza la stessa pianificazione per tutti gli <b>🔍Scanner dispositivi</b> abilitati.",
|
||||
"Speedtest_Results": "Risultati test di velocità",
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
// ###################################
|
||||
|
||||
$defaultLang = "en_us";
|
||||
$allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "it_it", "ru_ru", "nb_no", "pl_pl", "pt_br", "tr_tr", "zh_cn", "cs_cz"];
|
||||
$allLanguages = ["en_us", "es_es", "de_de", "fr_fr", "it_it", "ru_ru", "nb_no", "pl_pl", "pt_br", "tr_tr", "zh_cn", "cs_cz", "ar_ar"];
|
||||
|
||||
|
||||
global $db;
|
||||
|
||||
$result = $db->querySingle("SELECT Value FROM Settings WHERE Code_Name = 'UI_LANG'");
|
||||
|
||||
// below has to match exactly teh values in /front/php/templates/language/lang.php & /front/js/common.js
|
||||
switch($result){
|
||||
case 'Spanish': $pia_lang_selected = 'es_es'; break;
|
||||
case 'German': $pia_lang_selected = 'de_de'; break;
|
||||
@@ -23,13 +25,12 @@ switch($result){
|
||||
case 'French': $pia_lang_selected = 'fr_fr'; break;
|
||||
case 'Chinese (zh_cn)': $pia_lang_selected = 'zh_cn'; break;
|
||||
case 'Czech (cs_cz)': $pia_lang_selected = 'cs_cz'; break;
|
||||
case 'Arabic (ar_ar)': $pia_lang_selected = 'ar_ar'; break;
|
||||
default: $pia_lang_selected = 'en_us'; break;
|
||||
}
|
||||
|
||||
if (isset($pia_lang_selected) == FALSE or (strlen($pia_lang_selected) == 0)) {$pia_lang_selected = $defaultLang;}
|
||||
|
||||
require dirname(__FILE__).'/../skinUI.php';
|
||||
|
||||
$result = $db->query("SELECT * FROM Plugins_Language_Strings");
|
||||
$strings = array();
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
|
||||
@@ -33,6 +33,6 @@ def merge_translations(main_file, other_files):
|
||||
if __name__ == "__main__":
|
||||
current_path = os.path.dirname(os.path.abspath(__file__))
|
||||
# language codes can be found here: http://www.lingoes.net/en/translator/langcode.htm
|
||||
json_files = ["en_us.json", "de_de.json", "es_es.json", "fr_fr.json", "nb_no.json", "ru_ru.json", "it_it.json", "pt_br.json", "pl_pl.json", "zh_cn.json", "tr_tr.json", "cs_cz.json"]
|
||||
json_files = ["en_us.json", "de_de.json", "es_es.json", "fr_fr.json", "nb_no.json", "ru_ru.json", "it_it.json", "pt_br.json", "pl_pl.json", "zh_cn.json", "tr_tr.json", "cs_cz.json", "ar_ar.json"]
|
||||
file_paths = [os.path.join(current_path, file) for file in json_files]
|
||||
merge_translations(file_paths[0], file_paths[1:])
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "Gjenoppretting utført.",
|
||||
"BackDevices_darkmode_disabled": "Mørk modus Deaktivert",
|
||||
"BackDevices_darkmode_enabled": "Mørk modus Aktivert",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Dette er en vedlikeholdsinnstilling. Dette spesifiserer antall dager verdt med hendelsesoppføringer som vil beholdes. Alle eldre hendelser vil bli slettet med jevne mellomrom. Gjelder også for plugin-hendelseshistorikk.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Slett hendelser eldre enn",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Kopier detaljer fra enhet",
|
||||
@@ -279,6 +281,7 @@
|
||||
"Gen_DataUpdatedUITakesTime": "OK - Det kan ta litt tid før brukergrensesnittet oppdateres hvis en skanning kjøres.",
|
||||
"Gen_Delete": "Slett",
|
||||
"Gen_DeleteAll": "Slett alle",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "Feil",
|
||||
"Gen_Filter": "Filter",
|
||||
"Gen_LockedDB": "FEIL - DB kan være låst - Sjekk F12 Dev tools -> Konsoll eller prøv senere.",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "Lagre",
|
||||
"Gen_Saved": "Lagret",
|
||||
"Gen_Search": "Søk",
|
||||
"Gen_SelectToPreview": "",
|
||||
"Gen_Selected_Devices": "Valgte Enheter:",
|
||||
"Gen_Switch": "Bytt",
|
||||
"Gen_Upd": "Oppdatering vellykket",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "Laster...",
|
||||
"Login_Box": "Skriv inn passordet ditt",
|
||||
"Login_Default_PWD": "Standard passordet \"123456\" er fortsatt aktivt.",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "Passord",
|
||||
"Login_Psw_alert": "Passord varsling!",
|
||||
"Login_Psw_folder": "i config-mappen.",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "Slett alle (filtre blir ignorert)",
|
||||
"Plugins_Filters_Mac": "Mac filter",
|
||||
"Plugins_History": "Hendelses historikk",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "Plugin-objekter",
|
||||
"Plugins_Out_of": "ut av",
|
||||
"Plugins_Unprocessed_Events": "Uprosesserte hendelser",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "Autodetektert - indikerer om enheten randomiserer MAC-adressen sin.",
|
||||
"Reports_Sent_Log": "Sendte rapport logger",
|
||||
"SCAN_SUBNETS_description": "De fleste skannere på nettet (ARP-Scan, NMAP, NSlookup, Dig, Pholus) er avhengige av å skanne spesifikke nettverksgrensesnitt og undernett. Sjekk <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">subnett dokumentasjonen</a> for hjelp på denne innstillingen, spesielt VLAN-er, hvilke VLAN-er som støttes, eller hvordan du kan finne ut nettverksmasken og grensesnittet ditt. <br/> <br/> Et alternativ til skannere på nettet er å aktivere noen andre enhetsskannere/importører som ikke er avhengige av Netalert<sup>X</sup> med tilgang til nettverket (UniFi, DHCP-Leaser, Pihole, osv.). <br/> <br/> Merk: Selve skanningstiden avhenger av antall IP -adresser som skal sjekkes, så sett dette opp nøye med riktig nettverksmaske og grensesnitt.",
|
||||
"SCAN_SUBNETS_name": "",
|
||||
"SYSTEM_TITLE": "Systeminformasjon",
|
||||
"Setting_Override": "Overstyr verdi",
|
||||
"Setting_Override_Description": "Aktivering av dette alternativet vil overstyre en App som leveres standard-verdi med verdien som er spesifisert ovenfor.",
|
||||
"Settings_Metadata_Toggle": "Vis/skjul metadata for den gitte innstillingen.",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "⚠ Enhetsskanning tidsplan er ikke synkronisert lenger.",
|
||||
"Settings_device_Scanners_desync_popup": "Tidsplanene for enhetsskanning (<code>*_RUN_SCHD</code>) er ikke de samme. Dette vil føre til inkonsekvent enhet på online/offline varsler. Med mindre dette er ment, kan du bruke den samme tidsplanen for alle aktiverte <b> 🔍Enhets-skannere</b>.",
|
||||
"Speedtest_Results": "Speedtest resultater",
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "Przywracanie wykonane z sukcesem.",
|
||||
"BackDevices_darkmode_disabled": "Tryb ciemny Wyłączony",
|
||||
"BackDevices_darkmode_enabled": "Tryb ciemny Włączony",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "To jest ustawienie konserwacji. Określa ile dni mają być utrzymywane wpisy wydarzeń. Wszystkie starsze wpisy wydarzeń zostaną usunięte okresowo. Dotyczy także Historii Wydarzeń Pluginów.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Usuń wydarzenia starsze niż",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i>Kopiuj opis z urządzenia",
|
||||
@@ -279,6 +281,7 @@
|
||||
"Gen_DataUpdatedUITakesTime": "OK - Aktualizacja UI może chwile potrwać jeżeli wykonywany jest skan.",
|
||||
"Gen_Delete": "Usuń",
|
||||
"Gen_DeleteAll": "Usuń wszystko",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "Błąd",
|
||||
"Gen_Filter": "Filtr",
|
||||
"Gen_LockedDB": "BŁĄD - BAZA DANYCH może być zablokowana - Sprawdź F12 narzędzia dewelopera -> Konsola lub spróbuj ponownie później.",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "Zapisz",
|
||||
"Gen_Saved": "Zapisano",
|
||||
"Gen_Search": "Szukaj",
|
||||
"Gen_SelectToPreview": "",
|
||||
"Gen_Selected_Devices": "Wybierz Urządzenia:",
|
||||
"Gen_Switch": "Switch",
|
||||
"Gen_Upd": "Zaktualizowane poprawnie",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "Wczytywanie...",
|
||||
"Login_Box": "Wprowadź hasło",
|
||||
"Login_Default_PWD": "Podstawowe hasło \"123456\" jest aktywne.",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "Hasło",
|
||||
"Login_Psw_alert": "Alert HASŁA!",
|
||||
"Login_Psw_folder": "w folderze konfiguracji.",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "Usuń wszystkie (filtry są ignorowane)",
|
||||
"Plugins_Filters_Mac": "Filtr MAC",
|
||||
"Plugins_History": "Historia Wydarzeń",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "Obiekty Wtyczek",
|
||||
"Plugins_Out_of": "brakujące",
|
||||
"Plugins_Unprocessed_Events": "Nieprzeprocesowane Wydarzenia",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "Auto wykrywanie - oznacza czy urządzenie randomizuje swój adres MAC.",
|
||||
"Reports_Sent_Log": "Wyślij zgłoszenie logów",
|
||||
"SCAN_SUBNETS_description": "Większość skanerów sieciowych (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) opiera się na konkretnych interfejsach sieciowych oraz podsieci. Sprawdź <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\"> dokumentacji podsieci</a> jeżeli potrzebujesz pomocy w ustawieniach, a szczególnie z VLAN'ami, jakie VLAN'y są wspierane oraz jak rozgryźć maskę podsieci twojego interfejsu.<br/><br/> Alternatywą do skanerów sieciowych jest uruchomienie innego Skanera Urządzeń/Importera który nie polega by NetAlert<sup>X</sup> miał dostęp do sieci (UNIFI, dhcp.leases, PiHole, itp.).<br/><br/> Notatka: Czas skanu zależy od liczby adresów IP do sprawdzenia, więc ustaw go tak by skanował odpowiedni interfejs i maskę sieciową.",
|
||||
"SCAN_SUBNETS_name": "",
|
||||
"SYSTEM_TITLE": "Informacje o Systemie",
|
||||
"Setting_Override": "Nadpisz wartość",
|
||||
"Setting_Override_Description": "Włączanie tej opcji nadpisze podstawową wartość na wartość podaną powyżej.",
|
||||
"Settings_Metadata_Toggle": "Pokaż/Ukryj metadane dla podanego ustawienia.",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "⚠ Harmonogramy skanowania urządzeń są niesynchronizowane.",
|
||||
"Settings_device_Scanners_desync_popup": "Harmonogramy skanowania urządzeń (<code>*_RUN_SCHD</code>) nie są takie same. Powodować to będzie nierównomierne powiadomienia o urządzeniach włączynych/wyłączonych. Jeżeli nie jest to zamierzone to proszę włączyć ten sam harmonogram dla wszyskich <b>🔍Skanerów Urządzeń</b>.",
|
||||
"Speedtest_Results": "Wyniki Testu Prędkości",
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "Restauração executada com sucesso.",
|
||||
"BackDevices_darkmode_disabled": "Modo Noturno Desabilitado",
|
||||
"BackDevices_darkmode_enabled": "Modo Noturno Habilitado",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Esta é uma definição de manutenção. Especifica o número de dias de entradas de eventos que serão mantidas. Todos os eventos mais antigos serão eliminados periodicamente. Também se aplica ao Histórico de eventos do plug-in.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Excluir eventos mais antigos que",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Copiar detalhes do dispositivo",
|
||||
@@ -279,6 +281,7 @@
|
||||
"Gen_DataUpdatedUITakesTime": "OK - Pode levar um tempo para a interface do usuário ser atualizada se uma verificação estiver em execução.",
|
||||
"Gen_Delete": "Excluir",
|
||||
"Gen_DeleteAll": "Excluir todos",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "Erro",
|
||||
"Gen_Filter": "Filtro",
|
||||
"Gen_LockedDB": "ERRO - O banco de dados pode estar bloqueado - Verifique F12 Ferramentas de desenvolvimento -> Console ou tente mais tarde.",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "Salvar",
|
||||
"Gen_Saved": "Salvo",
|
||||
"Gen_Search": "Procurar",
|
||||
"Gen_SelectToPreview": "",
|
||||
"Gen_Selected_Devices": "Dispositivos selecionados:",
|
||||
"Gen_Switch": "Trocar",
|
||||
"Gen_Upd": "Atualizado com sucesso",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "",
|
||||
"Login_Box": "",
|
||||
"Login_Default_PWD": "",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "",
|
||||
"Login_Psw_alert": "",
|
||||
"Login_Psw_folder": "",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "",
|
||||
"Plugins_Filters_Mac": "",
|
||||
"Plugins_History": "",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "",
|
||||
"Plugins_Out_of": "",
|
||||
"Plugins_Unprocessed_Events": "",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "",
|
||||
"Reports_Sent_Log": "",
|
||||
"SCAN_SUBNETS_description": "",
|
||||
"SCAN_SUBNETS_name": "",
|
||||
"SYSTEM_TITLE": "",
|
||||
"Setting_Override": "",
|
||||
"Setting_Override_Description": "",
|
||||
"Settings_Metadata_Toggle": "",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "",
|
||||
"Settings_device_Scanners_desync_popup": "",
|
||||
"Speedtest_Results": "",
|
||||
|
||||
14
front/php/templates/language/ru_ru.json
Normal file → Executable file
14
front/php/templates/language/ru_ru.json
Normal file → Executable file
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "Восстановление выполнено успешно.",
|
||||
"BackDevices_darkmode_disabled": "Темный режим отключен",
|
||||
"BackDevices_darkmode_enabled": "Темный режим включен",
|
||||
"CLEAR_NEW_FLAG_description": "Если этот параметр включен (<code>0</code> отключен), устройства, помеченные как <b>Новое устройство</b>, станут неотмеченными, если лимит времени, указанный в часах, превышает время их <b>первой сессии</b>.",
|
||||
"CLEAR_NEW_FLAG_name": "Удалить новый флаг",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "Это настройка обслуживания. Здесь указывается количество дней, в течение которых будут храниться записи о событиях. Все старые события будут периодически удаляться. Также применимо к истории событий плагина.",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "Удалить события старше",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> Скопировать данные с устройства",
|
||||
@@ -279,6 +281,7 @@
|
||||
"Gen_DataUpdatedUITakesTime": "ОК - Обновление UI может занять некоторое время, если сканирование выполняется.",
|
||||
"Gen_Delete": "Удалить",
|
||||
"Gen_DeleteAll": "Удалить все",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "Ошибка",
|
||||
"Gen_Filter": "Фильтр",
|
||||
"Gen_LockedDB": "ОШИБКА - Возможно, база данных заблокирована. Проверьте инструменты разработчика F12 -> Консоль или повторите попытку позже.",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "Сохранить",
|
||||
"Gen_Saved": "Сохранено",
|
||||
"Gen_Search": "Поиск",
|
||||
"Gen_SelectToPreview": "Выберите для предварительного просмотра",
|
||||
"Gen_Selected_Devices": "Выбранные устройства:",
|
||||
"Gen_Switch": "Переключить",
|
||||
"Gen_Upd": "Успешное обновление",
|
||||
@@ -303,8 +307,8 @@
|
||||
"Gen_Work_In_Progress": "Работа продолжается, самое время оставить отзыв на https://github.com/jokob-sk/NetAlertX/issues",
|
||||
"General_display_name": "Главное",
|
||||
"General_icon": "<i class=\"fa fa-gears\"></i>",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "Это настройка обслуживания. Если этот параметр включен (<code>0</code> отключен), устройства, помеченные как <b>Новое устройство</b>, будут удалены, если время их <b>Первого сеанса</b> было старше указанных в этой настройке часов. Используйте этот параметр, если вы хотите автоматически удалять <b>Новые устройства</b> через <code>X</code> часов.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Хранить новые устройства в течение",
|
||||
"HRS_TO_KEEP_NEWDEV_description": "Это настройка обслуживания <b>УДАЛЕНИЕ устройств</b>. Если этот параметр включен (<code>0</code> отключен), устройства, помеченные как <b>Новое устройство</b>, будут удалены, если время их <b>Первого сеанса</b> было старше указанных в этой настройке часов. Используйте этот параметр, если вы хотите автоматически удалять <b>Новые устройства</b> через <code>X</code> часов.",
|
||||
"HRS_TO_KEEP_NEWDEV_name": "Удалить новые устройства после",
|
||||
"HelpFAQ_Cat_Detail": "Подробности",
|
||||
"HelpFAQ_Cat_Detail_300_head": "Что значит ",
|
||||
"HelpFAQ_Cat_Detail_300_text_a": "означает сетевое устройство (типа AP, шлюз, межсетевой экран, гипервизор, Powerline, коммутатор, WLAN, PLC, маршрутизатор, USB-адаптер локальной сети, USB-адаптер Wi-Fi или Интернет). Пользовательские типы можно добавить с помощью параметра <code>NETWORK_DEVICE_TYPES</code>.",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "Загрузка...",
|
||||
"Login_Box": "Введите пароль",
|
||||
"Login_Default_PWD": "Пароль по умолчанию «123456» все еще активен.",
|
||||
"Login_Info": "Пароли устанавливаются через плагин Set Password. Если у вас возникли проблемы со входом в систему, проверьте <a target=\"_blank\" href=\"https://github.com/jokob-sk/NetAlertX/tree/main/front/plugins/set_password\">SEPWD документацию</a>.",
|
||||
"Login_Psw-box": "Пароль",
|
||||
"Login_Psw_alert": "Предупреждение о пароле!",
|
||||
"Login_Psw_folder": "в папке конфигурации.",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "Удалить все (фильтры игнорируются)",
|
||||
"Plugins_Filters_Mac": "Фильтр MAC-адреса",
|
||||
"Plugins_History": "История событий",
|
||||
"Plugins_Obj_DeleteListed": "Удалить перечисленные объекты",
|
||||
"Plugins_Objects": "Объекты плагина",
|
||||
"Plugins_Out_of": "из",
|
||||
"Plugins_Unprocessed_Events": "Необработанные события",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "Автоматически обнаружено — указывает, рандомизирует ли устройство свой MAC-адрес.",
|
||||
"Reports_Sent_Log": "Отправить журнал логов",
|
||||
"SCAN_SUBNETS_description": "Большинство сетевых сканеров (ARP-SCAN, NMAP, NSLOOKUP, DIG, PHOLUS) полагаются на сканирование определенных сетевых интерфейсов и подсетей. Дополнительную информацию по этому параметру можно найти в <a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">документации по подсетям</a>, особенно VLAN, какие VLAN поддерживаются или как разобраться в маске сети и своем интерфейсе. <br/> <br/> Альтернативой сетевым сканерам является включение некоторых других сканеров/импортеров устройств, которые не полагаются на NetAlert<sup>X</sup>, имеющий доступ к сети (UNIFI, dhcp.leases , PiHole и др.). <br/> <br/> Примечание. Само время сканирования зависит от количества проверяемых IP-адресов, поэтому тщательно настройте его, указав соответствующую маску сети и интерфейс.",
|
||||
"SCAN_SUBNETS_name": "Сети для сканирования",
|
||||
"SYSTEM_TITLE": "Системная информация",
|
||||
"Setting_Override": "Переопределить значение",
|
||||
"Setting_Override_Description": "Включение этой опции приведет к переопределению значения по умолчанию, предоставленного приложением, на значение, указанное выше.",
|
||||
"Settings_Metadata_Toggle": "Показать/скрыть метаданные для данного параметра.",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "⚠ Расписания сканера устройств не синхронизированы.",
|
||||
"Settings_device_Scanners_desync_popup": "Расписания сканеров устройств (<code>*_RUN_SCHD</code>) не совпадают. Это приведет к несогласованным онлайн/оффлайн уведомлениям устройства. Если это не предусмотрено, используйте одно и то же расписание для всех включенных <b>🔍Сканеров устройств</b>.",
|
||||
"Speedtest_Results": "Результаты теста скорости",
|
||||
@@ -693,4 +701,4 @@
|
||||
"settings_update_item_warning": "Обновить значение ниже. Будьте осторожны, следуя предыдущему формату. <b>Проверка не выполняется.</b>",
|
||||
"test_event_icon": "fa-vial-circle-check",
|
||||
"test_event_tooltip": "Сначала сохраните изменения, прежде чем проверять настройки."
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "",
|
||||
"BackDevices_darkmode_disabled": "",
|
||||
"BackDevices_darkmode_enabled": "",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "",
|
||||
"DevDetail_Copy_Device_Title": "",
|
||||
@@ -279,6 +281,7 @@
|
||||
"Gen_DataUpdatedUITakesTime": "TAMAM - Eğer bir tarama çalışıyorsa arayüzün güncellenmesi biraz zaman alabilir",
|
||||
"Gen_Delete": "Sil",
|
||||
"Gen_DeleteAll": "Tümünü sil",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "Hata",
|
||||
"Gen_Filter": "Filtre",
|
||||
"Gen_LockedDB": "",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "Kaydet",
|
||||
"Gen_Saved": "Kaydedildi",
|
||||
"Gen_Search": "",
|
||||
"Gen_SelectToPreview": "",
|
||||
"Gen_Selected_Devices": "Seçilmiş Cihazlar:",
|
||||
"Gen_Switch": "",
|
||||
"Gen_Upd": "Başarılı bir şekilde güncellendi",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "Yükleniyor...",
|
||||
"Login_Box": "Şifrenizi giriniz",
|
||||
"Login_Default_PWD": "Varsayılan şifre \"123456\" hâlâ aktif.",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "Şİfre",
|
||||
"Login_Psw_alert": "",
|
||||
"Login_Psw_folder": "",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "",
|
||||
"Plugins_Filters_Mac": "",
|
||||
"Plugins_History": "",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "",
|
||||
"Plugins_Out_of": "",
|
||||
"Plugins_Unprocessed_Events": "",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "",
|
||||
"Reports_Sent_Log": "",
|
||||
"SCAN_SUBNETS_description": "",
|
||||
"SCAN_SUBNETS_name": "",
|
||||
"SYSTEM_TITLE": "",
|
||||
"Setting_Override": "",
|
||||
"Setting_Override_Description": "",
|
||||
"Settings_Metadata_Toggle": "",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "",
|
||||
"Settings_device_Scanners_desync_popup": "",
|
||||
"Speedtest_Results": "",
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
"BackDevices_Restore_okay": "已成功恢复。",
|
||||
"BackDevices_darkmode_disabled": "暗黑模式已禁用",
|
||||
"BackDevices_darkmode_enabled": "已启用暗黑模式",
|
||||
"CLEAR_NEW_FLAG_description": "",
|
||||
"CLEAR_NEW_FLAG_name": "",
|
||||
"DAYS_TO_KEEP_EVENTS_description": "这是维护设置。它指定将保留的事件条目的天数。所有较旧的事件将被定期删除。也适用于插件事件历史记录。",
|
||||
"DAYS_TO_KEEP_EVENTS_name": "删除早于",
|
||||
"DevDetail_Copy_Device_Title": "<i class=\"fa fa-copy\"></i> 从设备复制详细信息",
|
||||
@@ -279,6 +281,7 @@
|
||||
"Gen_DataUpdatedUITakesTime": "好的 - 如果扫描正在运行,UI 可能需要一段时间才能更新。",
|
||||
"Gen_Delete": "删除",
|
||||
"Gen_DeleteAll": "全部删除",
|
||||
"Gen_Description": "",
|
||||
"Gen_Error": "错误",
|
||||
"Gen_Filter": "筛选",
|
||||
"Gen_LockedDB": "错误 - DB 可能被锁定 - 检查 F12 开发工具 -> 控制台或稍后重试。",
|
||||
@@ -293,6 +296,7 @@
|
||||
"Gen_Save": "保存",
|
||||
"Gen_Saved": "已保存",
|
||||
"Gen_Search": "搜索",
|
||||
"Gen_SelectToPreview": "",
|
||||
"Gen_Selected_Devices": "选定的设备:",
|
||||
"Gen_Switch": "交换",
|
||||
"Gen_Upd": "已成功更新",
|
||||
@@ -348,6 +352,7 @@
|
||||
"Loading": "加载中...",
|
||||
"Login_Box": "输入密码",
|
||||
"Login_Default_PWD": "默认密码“123456”仍然有效。",
|
||||
"Login_Info": "",
|
||||
"Login_Psw-box": "密码",
|
||||
"Login_Psw_alert": "密码警报!",
|
||||
"Login_Psw_folder": "在配置文件夹中。",
|
||||
@@ -528,6 +533,7 @@
|
||||
"Plugins_DeleteAll": "全部删除(忽略过滤器)",
|
||||
"Plugins_Filters_Mac": "Mac 过滤器",
|
||||
"Plugins_History": "事件历史",
|
||||
"Plugins_Obj_DeleteListed": "",
|
||||
"Plugins_Objects": "插件对象",
|
||||
"Plugins_Out_of": "",
|
||||
"Plugins_Unprocessed_Events": "未处理的事件",
|
||||
@@ -557,10 +563,12 @@
|
||||
"RandomMAC_hover": "自动检测 - 表示设备是否随机化其 MAC 地址。",
|
||||
"Reports_Sent_Log": "已发送报告日志",
|
||||
"SCAN_SUBNETS_description": "大多数网络扫描器(ARP-SCAN、NMAP、NSLOOKUP、DIG、PHOLUS)依赖于扫描特定的网络接口和子网。查看<a href=\"https://github.com/jokob-sk/NetAlertX/blob/main/docs/SUBNETS.md\" target=\"_blank\">子网文档</a>以获取有关此设置的帮助,尤其是 VLAN、支持哪些 VLAN,或者如何确定网络掩码和接口。<br/> <br/> 网络扫描器的替代方法是启用一些其他不依赖于 NetAlert<sup>X</sup> 访问网络的设备扫描器/导入器(UNIFI、dhcp.leases、PiHole 等)。<br/> <br/> 注意:扫描时间本身取决于要检查的 IP 地址数量,因此请使用适当的网络掩码和接口仔细设置。",
|
||||
"SCAN_SUBNETS_name": "",
|
||||
"SYSTEM_TITLE": "系统信息",
|
||||
"Setting_Override": "覆盖值",
|
||||
"Setting_Override_Description": "启用此选项将用上面指定的值覆盖应用程序提供的默认值。",
|
||||
"Settings_Metadata_Toggle": "显示/隐藏给定设置的元数据。",
|
||||
"Settings_Show_Description": "",
|
||||
"Settings_device_Scanners_desync": "⚠ 设备扫描计划不同步。",
|
||||
"Settings_device_Scanners_desync_popup": "设备扫描 (<code>*_RUN_SCHD</code>) 的时间表并不相同。这将导致设备在线/离线通知不一致。除非有意为之,否则请对所有启用的 <b>🔍设备扫描</b> 使用相同的时间表。",
|
||||
"Speedtest_Results": "Speedtest 结果",
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php require 'php/templates/notification.php'; ?>
|
||||
<?php
|
||||
|
||||
require 'php/templates/notification.php';
|
||||
//------------------------------------------------------------------------------
|
||||
// check if authenticated
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
||||
?>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
@@ -1,67 +1,83 @@
|
||||
<?php
|
||||
|
||||
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
|
||||
$isLogonPage = FALSE;
|
||||
// Constants
|
||||
define('CONFIG_PATH', $_SERVER['DOCUMENT_ROOT'] . "/../config/app.conf");
|
||||
define('COOKIE_SAVE_LOGIN_NAME', "NetAlertX_SaveLogin");
|
||||
|
||||
$CookieSaveLoginName = "NetAlertX_SaveLogin";
|
||||
// Utility Functions
|
||||
function getConfigLine($pattern, $config_lines) {
|
||||
$matches = preg_grep($pattern, $config_lines);
|
||||
return !empty($matches) ? explode("=", array_values($matches)[0]) : null;
|
||||
}
|
||||
|
||||
function getConfigValue($pattern, $config_lines, $delimiter = "'") {
|
||||
$line = preg_grep($pattern, $config_lines);
|
||||
return !empty($line) ? explode($delimiter, array_values($line)[0])[1] : '';
|
||||
}
|
||||
|
||||
if (strpos($url,'index.php') !== false) {
|
||||
$isLogonPage = TRUE;
|
||||
}
|
||||
function redirect($url) {
|
||||
header("Location: $url");
|
||||
exit();
|
||||
}
|
||||
|
||||
session_start();
|
||||
// Initialization
|
||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://';
|
||||
$url = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
|
||||
|
||||
if(array_search('action', $_REQUEST) != FALSE)
|
||||
{
|
||||
if ($_REQUEST['action'] == 'logout') {
|
||||
// Parse the URL and extract the path component
|
||||
// error_log("-------------");
|
||||
$parsedUrl = parse_url($url, PHP_URL_PATH);
|
||||
|
||||
// Normalize the path: treat '/' (root) and '/index.php' as equivalent
|
||||
$isLogonPage = ($parsedUrl === '/' || $parsedUrl === '/index.php');
|
||||
|
||||
$authHeader = apache_request_headers()['Authorization'] ?? '';
|
||||
$sessionLogin = isset($_SESSION['login']) ? $_SESSION['login'] : 0;
|
||||
|
||||
// Start session if not already started
|
||||
if (session_status() == PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// Handle logout
|
||||
if (!empty($_REQUEST['action']) && $_REQUEST['action'] == 'logout') {
|
||||
session_destroy();
|
||||
setcookie($CookieSaveLoginName, "", time() - 3600);
|
||||
header('Location: index.php');
|
||||
}
|
||||
setcookie(COOKIE_SAVE_LOGIN_NAME, "", time() - 3600);
|
||||
redirect('index.php');
|
||||
}
|
||||
|
||||
// ##################################################
|
||||
// ## Login Processing start
|
||||
// ##################################################
|
||||
$config_file = "../config/app.conf";
|
||||
$config_file_lines = file($config_file);
|
||||
$CookieSaveLoginName = "NetAlertX_SaveLogin";
|
||||
// Load configuration
|
||||
if (!file_exists(CONFIG_PATH)) {
|
||||
die("Configuration file not found.");
|
||||
}
|
||||
$configLines = file(CONFIG_PATH);
|
||||
|
||||
// ###################################
|
||||
// ## SETPWD_enable_password FALSE
|
||||
// ###################################
|
||||
// Handle web protection and password
|
||||
$nax_WebProtection = strtolower(trim(getConfigLine('/^SETPWD_enable_password.*=/', $configLines)[1] ?? 'false'));
|
||||
$nax_Password = getConfigValue('/^SETPWD_password.*=/', $configLines);
|
||||
$api_token = getConfigValue('/^SYNC_api_token.*=/', $configLines, "'");
|
||||
|
||||
$config_file_lines_bypass = array_values(preg_grep('/^SETPWD_enable_password.*=/', $config_file_lines));
|
||||
$protection_line = explode("=", $config_file_lines_bypass[0]);
|
||||
$Pia_WebProtection = strtolower(trim($protection_line[1]));
|
||||
$expectedToken = 'Bearer ' . $api_token;
|
||||
|
||||
// ###################################
|
||||
// ## SETPWD_enable_password TRUE
|
||||
// ###################################
|
||||
// Authentication Handling
|
||||
if ($nax_WebProtection == 'true') {
|
||||
if ($authHeader === $expectedToken) {
|
||||
$_SESSION['login'] = 1; // User authenticated with bearer token
|
||||
} elseif (!empty($authHeader)) {
|
||||
echo "[Security] Incorrect Bearer Token";
|
||||
}
|
||||
|
||||
$config_file_lines = array_values(preg_grep('/^SETPWD_password.*=/', $config_file_lines));
|
||||
$password_line = explode("'", $config_file_lines[0]);
|
||||
$Pia_Password = $password_line[1];
|
||||
|
||||
// active Session or valid cookie (cookie not extends)
|
||||
if($Pia_WebProtection == 'true')
|
||||
{
|
||||
if(isset ($_SESSION["login"]) == FALSE )
|
||||
{
|
||||
$_SESSION["login"] = 0;
|
||||
}
|
||||
|
||||
if ( ($_SESSION["login"] == 1) || $isLogonPage || (( isset($_COOKIE[$CookieSaveLoginName]) && $Pia_Password == $_COOKIE[$CookieSaveLoginName ])))
|
||||
{
|
||||
//Logged in or stay on this page if we are on the index.php already
|
||||
|
||||
} else
|
||||
{
|
||||
// we need to redirect
|
||||
header('Location: index.php');
|
||||
}
|
||||
// Safely check if the session login exists before checking its value
|
||||
$isLoggedIn = isset($_SESSION['login']) && $_SESSION['login'] == 1;
|
||||
|
||||
// Determine if the user should be redirected
|
||||
if ($isLoggedIn || $isLogonPage || (isset($_COOKIE[COOKIE_SAVE_LOGIN_NAME]) && $nax_Password == $_COOKIE[COOKIE_SAVE_LOGIN_NAME])) {
|
||||
// Logged in or stay on this page if we are on the index.php already
|
||||
} else {
|
||||
// We need to redirect
|
||||
redirect('/index.php');
|
||||
exit; // exit is needed to prevent authentication bypass
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -12,10 +12,7 @@ if( isset($_COOKIE['UI_dark_mode']))
|
||||
$ENABLED_DARKMODE = False;
|
||||
}
|
||||
|
||||
foreach (glob("/app/db/setting_skin*") as $filename) {
|
||||
$pia_skin_selected = str_replace('setting_','',basename($filename));
|
||||
}
|
||||
if (isset($pia_skin_selected) == FALSE or (strlen($pia_skin_selected) == 0)) {$pia_skin_selected = 'skin-blue';}
|
||||
$pia_skin_selected = 'skin-blue';
|
||||
|
||||
// ###################################
|
||||
// ## GUI settings processing end
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#---------------------------------------------------------------------------------#
|
||||
|
||||
$filename = "/app/.VERSION";
|
||||
|
||||
if(file_exists($filename)) {
|
||||
$fileContents = file_get_contents($filename);
|
||||
if(trim($fileContents) === 'Dev') {
|
||||
@@ -22,5 +23,6 @@ if(file_exists($filename)) {
|
||||
}
|
||||
else {
|
||||
echo date('H:i:s') . " - N/A";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -8,7 +8,7 @@ NetAlertX supports additional plugins to extend its functionality, each with its
|
||||
## ⚡ Quick start
|
||||
|
||||
> [!TIP]
|
||||
> You can load additional Plugins via the General -> `LOADED_PLUGINS` setting. Use `Ctrl + Click` to select/deselect.
|
||||
> You can load additional Plugins via the General -> `LOADED_PLUGINS` setting.
|
||||
|
||||
1. Pick your `🔍 dev scanner` plugin (e.g. `ARPSCAN` or `NMAPDEV`), or import devices into the application with an `📥 importer` plugin. (See **✅Enabling plugins** below)
|
||||
2. Pick a `▶️ publisher` plugin, if you want to send notifications. If you don't see a publisher you'd like to use, look at the [📚_publisher_apprise](/front/plugins/_publisher_apprise/) plugin which is a proxy for over 80 notification services.
|
||||
@@ -28,6 +28,7 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T
|
||||
|---------------|---------|--------------------------------------------|----------|----------|--------------------|---------------------------------------------------------------|
|
||||
| `APPRISE` | ▶️ | Apprise notification proxy | | | Script | [_publisher_apprise](/front/plugins/_publisher_apprise/) |
|
||||
| `ARPSCAN` | 🔍 | ARP-scan on current network | | | Script | [arp_scan](/front/plugins/arp_scan/) |
|
||||
| `AVAHISCAN` | ♻ | Avahi (mDNS-based) name resolution | | | Script | [avahi_scan](/front/plugins/avahi_scan/) |
|
||||
| `CSVBCKP` | ⚙ | CSV devices backup | | | Script | [csv_backup](/front/plugins/csv_backup/) |
|
||||
| `DBCLNP` | ⚙ | Database cleanup | | Yes* | Script | [db_cleanup](/front/plugins/db_cleanup/) |
|
||||
| `DDNS` | ⚙ | DDNS update | | | Script | [ddns_update](/front/plugins/ddns_update/) |
|
||||
@@ -70,13 +71,13 @@ Device-detecting plugins insert values into the `CurrentScan` database table. T
|
||||
## Plugin types
|
||||
|
||||
|
||||
| Plugin type | Icon | Description | When to run | Required | Data source [?](/docs/PLUGINS_DEV.md) |
|
||||
|---------------|------|---------------------------------------------------------------|--------------------------|----|---------|
|
||||
| publisher | ▶️ | Sending notifications to services. | `on_notification` | ✖ | Script |
|
||||
| dev scanner | 🔍 | Create devices in the app, usually scanning the current network. | `schedule` | ✖ | Script / SQLite DB |
|
||||
| importer | 📥 | Importing devices from another service. | `schedule` | ✖ | Script / SQLite DB |
|
||||
| system | ⚙ | Providing core system functionality. | `schedule` / always on | ✖/✔ | Script / Template |
|
||||
| other | ♻ | Other scanners, e.g. for name resolution | misc | ✖ | Script / Template |
|
||||
| Plugin type | Icon | Description | When to run | Required | Data source [?](/docs/PLUGINS_DEV.md) |
|
||||
|---------------|------|----------------------------------------------------------------|--------------------------|----|---------|
|
||||
| publisher | ▶️ | Sending notifications to services. | `on_notification` | ✖ | Script |
|
||||
| dev scanner | 🔍 | Create devices in the app, manages online/offline device status. | `schedule` | ✖ | Script / SQLite DB |
|
||||
| importer | 📥 | Importing devices from another service. | `schedule` | ✖ | Script / SQLite DB |
|
||||
| system | ⚙ | Providing core system functionality. | `schedule` / always on | ✖/✔ | Script / Template |
|
||||
| other | ♻ | Other scanners, e.g. for name resolution | misc | ✖ | Script / Template |
|
||||
|
||||
## Features
|
||||
|
||||
|
||||
@@ -259,9 +259,13 @@
|
||||
"function": "CMD",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"element": "input",
|
||||
"elementOptions": ["readonly"],
|
||||
"transformers": []
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [{ "readonly": "true" }],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": "python3 /app/front/plugins/<plugin folder>/rename_me.py",
|
||||
"options": [],
|
||||
|
||||
BIN
front/plugins/_publisher_mqtt/Deleting_MQTT_Plugin_Objects.png
Executable file
BIN
front/plugins/_publisher_mqtt/Deleting_MQTT_Plugin_Objects.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
@@ -7,9 +7,31 @@
|
||||
- Go to settings and fill in relevant details. There are 2 types of "devices" generated and sent to the broker. A generic overview device that contains online/down/archived device stats and then the actual devices detected by the application.
|
||||
|
||||
|
||||
## Forcing an update
|
||||
|
||||
In order to speed up the processing, device configs are only pushed to the broker if a change occurs. The plugin compares the previous data with the current device state, and the following fields are checked:
|
||||
|
||||
- icon
|
||||
- device name
|
||||
- mac
|
||||
|
||||
You can force an update of all devices by deleting plugin objects of the MQTT plugin. For example, navigate to:
|
||||
|
||||
`Device -> Plugins -> MQTT -> Delete all`
|
||||
|
||||
Filters will be ignored, and this will delete all objects associated with the plugin. The next time the MQTT plugin is processed, all data is re-sent to the broker.
|
||||
|
||||

|
||||
|
||||
Please note the online/offline state of the device is always updated based on the scan result and if it changed from the previous value.
|
||||
|
||||
|
||||
# Sample Payloads
|
||||
|
||||
|
||||
>[!WARNING]
|
||||
> Please check your Home Assistant MQTT broker debug info for the most up-to-date data and format as the below might be outdated.
|
||||
|
||||
## Overview device
|
||||
|
||||
The below payloads apply to the device showing overall online/down/archived stats. You can toggle them on/off with the `SEND_STATS` setting.
|
||||
@@ -179,8 +201,6 @@ Payload:
|
||||
}
|
||||
```
|
||||
|
||||
>[!WARNING]
|
||||
> Please check your Home Assistant MQTT broker debug info for the most up-to-date data nad format as the above might be outdated.
|
||||
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
"data_filters": [
|
||||
{
|
||||
"compare_column": "Watched_Value4",
|
||||
"compare_operator": "==",
|
||||
"compare_field_id": "txtMacFilter",
|
||||
"compare_js_template": "'{value}'.toString()",
|
||||
"compare_use_quotes": true
|
||||
}
|
||||
],
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name": [
|
||||
{
|
||||
@@ -647,7 +656,7 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "The root path of the stats overview sensor. Inserted into the <code>system-sensors/sensor/{DEVICE_ID}/state</code> topic."
|
||||
"string": "The root path of the stats overview sensor. Inserted into the <code>{MQTT_topic_root}/sensor/{MQTT_DEVICE_ID}/state</code> topic."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -703,6 +712,30 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "topic_root",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{ "elementType": "input", "elementOptions": [], "transformers": [] }
|
||||
]
|
||||
},
|
||||
"default_value": "system-sensors",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "MQTT topic root"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "The topic root of the devices sensors. Inserted into the <code>{MQTT_topic_root}/sensor/{MQTT_DEVICE_ID}/state</code> topic."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "DEVICES_SQL",
|
||||
"type": {
|
||||
|
||||
@@ -9,6 +9,7 @@ import sys
|
||||
from datetime import datetime
|
||||
import time
|
||||
import re
|
||||
import unicodedata
|
||||
import paho.mqtt.client as mqtt
|
||||
# from paho.mqtt import client as mqtt_client
|
||||
# from paho.mqtt import CallbackAPIVersion as mqtt_CallbackAPIVersion
|
||||
@@ -26,7 +27,7 @@ from const import apiPath, confFileName
|
||||
from plugin_utils import getPluginObject
|
||||
from plugin_helper import Plugin_Objects
|
||||
from logger import mylog, append_line_to_file
|
||||
from helper import timeNowTZ, get_setting_value, bytes_to_string, sanitize_string
|
||||
from helper import timeNowTZ, get_setting_value, bytes_to_string, sanitize_string, normalize_string
|
||||
from notification import Notification_obj
|
||||
from database import DB, get_device_stats
|
||||
from pytz import timezone
|
||||
@@ -37,7 +38,6 @@ conf.tz = timezone(get_setting_value('TIMEZONE'))
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
# Create an MD5 hash object
|
||||
@@ -46,10 +46,10 @@ md5_hash = hashlib.md5()
|
||||
pluginName = 'MQTT'
|
||||
|
||||
# globals
|
||||
|
||||
mqtt_sensors = []
|
||||
mqtt_connected_to_broker = False
|
||||
mqtt_client = None # mqtt client
|
||||
topic_root = get_setting_value('MQTT_topic_root')
|
||||
|
||||
def main():
|
||||
|
||||
@@ -86,111 +86,144 @@ def check_config():
|
||||
# Sensor configs are tracking which sensors in NetAlertX exist and if a config has changed
|
||||
class sensor_config:
|
||||
def __init__(self, deviceId, deviceName, sensorType, sensorName, icon, mac):
|
||||
"""
|
||||
Initialize the sensor_config object with provided parameters. Sets up sensor configuration
|
||||
and generates necessary MQTT topics and messages based on the sensor type.
|
||||
"""
|
||||
# Assign initial attributes
|
||||
self.deviceId = deviceId
|
||||
self.deviceName = deviceName
|
||||
self.sensorType = sensorType
|
||||
self.sensorName = sensorName
|
||||
self.icon = icon
|
||||
self.mac = mac
|
||||
self.mac = mac
|
||||
self.model = deviceName
|
||||
self.hash = ''
|
||||
self.state_topic = ''
|
||||
self.json_attr_topic = ''
|
||||
self.topic = ''
|
||||
self.message = ''
|
||||
self.message = {} # Initialize message as an empty dictionary
|
||||
self.unique_id = ''
|
||||
|
||||
# binary sensor only sensor
|
||||
if self.sensorType == 'binary_sensor' or self.sensorType == 'sensor':
|
||||
# Call helper functions to initialize the message, generate a hash, and handle plugin object
|
||||
self.initialize_message()
|
||||
self.generate_hash()
|
||||
self.handle_plugin_object()
|
||||
|
||||
def initialize_message(self):
|
||||
"""
|
||||
Initialize the MQTT message payload based on the sensor type. This method handles sensors of types:
|
||||
- 'timestamp'
|
||||
- 'binary_sensor'
|
||||
- 'sensor'
|
||||
- 'device_tracker'
|
||||
"""
|
||||
# Ensure self.message is initialized as a dictionary if not already done
|
||||
if not isinstance(self.message, dict):
|
||||
self.message = {}
|
||||
|
||||
# Handle sensors with a 'timestamp' device class
|
||||
if self.sensorName in ['last_connection', 'first_connection']:
|
||||
self.message.update({
|
||||
"device_class": "timestamp"
|
||||
})
|
||||
|
||||
# Handle 'binary_sensor' or 'sensor' types
|
||||
if self.sensorType in ['binary_sensor', 'sensor']:
|
||||
self.topic = f'homeassistant/{self.sensorType}/{self.deviceId}/{self.sensorName}/config'
|
||||
self.state_topic = f'system-sensors/{self.sensorType}/{self.deviceId}/state'
|
||||
self.unique_id = self.deviceId+'_sensor_'+self.sensorName
|
||||
self.state_topic = f'{topic_root}/{self.sensorType}/{self.deviceId}/state'
|
||||
self.unique_id = f'{self.deviceId}_sensor_{self.sensorName}'
|
||||
|
||||
self.message = {
|
||||
"name" : self.sensorName,
|
||||
"state_topic" : self.state_topic,
|
||||
"value_template" : "{{value_json."+self.sensorName+"}}",
|
||||
"unique_id" : self.unique_id,
|
||||
"device":
|
||||
{
|
||||
"identifiers" : [self.deviceId+"_sensor"],
|
||||
"manufacturer" : "NetAlertX",
|
||||
"name" : self.deviceName
|
||||
},
|
||||
"icon": f'mdi:{self.icon}'
|
||||
}
|
||||
|
||||
# Update the message dictionary, expanding it without overwriting
|
||||
self.message.update({
|
||||
"name": self.sensorName,
|
||||
"state_topic": self.state_topic,
|
||||
"value_template": f"{{{{value_json.{self.sensorName}}}}}",
|
||||
"unique_id": self.unique_id,
|
||||
"device": {
|
||||
"identifiers": [f"{self.deviceId}_sensor"],
|
||||
"manufacturer": "NetAlertX",
|
||||
"name": self.deviceName
|
||||
},
|
||||
"icon": f'mdi:{self.icon}'
|
||||
})
|
||||
|
||||
|
||||
# Handle 'device_tracker' sensor type
|
||||
elif self.sensorType == 'device_tracker':
|
||||
|
||||
self.topic = f'homeassistant/device_tracker/{self.deviceId}/config'
|
||||
self.state_topic = f'system-sensors/device_tracker/{self.deviceId}/state'
|
||||
self.json_attr_topic = f'system-sensors/device_tracker/{self.deviceId}/attributes'
|
||||
self.state_topic = f'{topic_root}/device_tracker/{self.deviceId}/state'
|
||||
self.json_attr_topic = f'{topic_root}/device_tracker/{self.deviceId}/attributes'
|
||||
self.unique_id = f'{self.deviceId}_{self.sensorType}_{self.sensorName}'
|
||||
|
||||
payload_home = 'home'
|
||||
payload_away = 'away'
|
||||
# Construct the message dictionary for device_tracker
|
||||
self.message = {
|
||||
"state_topic": self.state_topic,
|
||||
"json_attributes_topic": self.json_attr_topic,
|
||||
"name": self.sensorName,
|
||||
"payload_home": 'home',
|
||||
"payload_not_home": 'away',
|
||||
"unique_id": self.unique_id,
|
||||
"icon": f'mdi:{self.icon}',
|
||||
"device": {
|
||||
"identifiers": [f"{self.deviceId}_sensor", self.unique_id],
|
||||
"manufacturer": "NetAlertX",
|
||||
"model": self.model or "Unknown", # Use model if available, else set to 'Unknown'
|
||||
"name": self.deviceName
|
||||
}
|
||||
}
|
||||
|
||||
self.message = {
|
||||
"state_topic": self.state_topic,
|
||||
"json_attributes_topic": self.json_attr_topic,
|
||||
"name": self.sensorName,
|
||||
"payload_home": payload_home,
|
||||
"payload_not_home": payload_away,
|
||||
"unique_id" : self.unique_id,
|
||||
"icon": f'mdi:{self.icon}',
|
||||
"device":
|
||||
{
|
||||
"identifiers" : [self.deviceId+"_sensor", self.unique_id],
|
||||
"manufacturer" : "NetAlertX",
|
||||
"name" : self.deviceName
|
||||
},
|
||||
}
|
||||
def generate_hash(self):
|
||||
"""
|
||||
Generate an MD5 hash based on the combined string of deviceId, deviceName, sensorType, sensorName, and icon.
|
||||
This hash will uniquely identify the sensor configuration.
|
||||
"""
|
||||
# Concatenate all relevant attributes into a single string
|
||||
input_string = f"{self.deviceId}{self.deviceName}{self.sensorType}{self.sensorName}{self.icon}"
|
||||
md5_hash = hashlib.md5() # Initialize the MD5 hash object
|
||||
md5_hash.update(input_string.encode('utf-8')) # Update hash with input string
|
||||
self.hash = md5_hash.hexdigest() # Store the hex representation of the hash
|
||||
|
||||
# Define your input string
|
||||
input_string = str(self.deviceId) + str(self.deviceName) + str(self.sensorType) + str(self.sensorName) + str(self.icon)
|
||||
def handle_plugin_object(self):
|
||||
"""
|
||||
Fetch the plugin object from the system based on the generated hash. If the object exists, it logs that the sensor is
|
||||
already known. If not, it marks the sensor as new and logs relevant information.
|
||||
"""
|
||||
# Retrieve the plugin object based on the sensor's hash
|
||||
plugObj = getPluginObject({"Plugin": "MQTT", "Watched_Value3": self.hash})
|
||||
|
||||
# Hash the input string and convert the hash to a string
|
||||
# Update the hash object with the bytes of the input string
|
||||
md5_hash.update(input_string.encode('utf-8'))
|
||||
|
||||
# Get the hexadecimal representation of the MD5 hash
|
||||
md5_hash_hex = md5_hash.hexdigest()
|
||||
hash_value = str(md5_hash_hex)
|
||||
|
||||
self.hash = hash_value
|
||||
|
||||
plugObj = getPluginObject({"Plugin":"MQTT", "Watched_Value3":hash_value})
|
||||
|
||||
# mylog('verbose', [f"[{pluginName}] Previous plugin object entry: {json.dumps(plugObj)}"])
|
||||
|
||||
if plugObj == {}:
|
||||
# Check if the plugin object is new
|
||||
if not plugObj:
|
||||
self.isNew = True
|
||||
mylog('verbose', [f"[{pluginName}] New sensor entry name : {self.deviceName}"])
|
||||
mylog('verbose', [f"[{pluginName}] New sensor entry mac : {self.mac}"])
|
||||
mylog('verbose', [f"[{pluginName}] New sensor entry hash_value : {hash_value}"])
|
||||
mylog('verbose', [f"[{pluginName}] New sensor entry (name|mac|hash) : ({self.deviceName}|{self.mac}|{self.hash}"])
|
||||
else:
|
||||
device_name = plugObj.get("Watched_Value1", "Unknown")
|
||||
mylog('verbose', [f"[{pluginName}] Existing, skip Device Name : {device_name}"])
|
||||
mylog('verbose', [f"[{pluginName}] Existing, skip Device Name: {device_name}"])
|
||||
self.isNew = False
|
||||
|
||||
# Store the sensor configuration in global plugin_objects
|
||||
self.store_plugin_object()
|
||||
|
||||
# Log sensor
|
||||
def store_plugin_object(self):
|
||||
"""
|
||||
Store the sensor configuration in the global plugin_objects, which tracks sensors based on a unique combination
|
||||
of attributes including deviceId, sensorName, hash, and MAC.
|
||||
"""
|
||||
global plugin_objects
|
||||
|
||||
if mac == '':
|
||||
mac = "N/A"
|
||||
|
||||
# Add the sensor to the global plugin_objects
|
||||
plugin_objects.add_object(
|
||||
primaryId = deviceId,
|
||||
secondaryId = sensorName,
|
||||
watched1 = deviceName,
|
||||
watched2 = sensorType,
|
||||
watched3 = hash_value,
|
||||
watched4 = mac,
|
||||
extra = input_string,
|
||||
foreignKey = mac
|
||||
primaryId=self.deviceId,
|
||||
secondaryId=self.sensorName,
|
||||
watched1=self.deviceName,
|
||||
watched2=self.sensorType,
|
||||
watched3=self.hash,
|
||||
watched4=self.mac,
|
||||
extra=f"{self.deviceId}{self.deviceName}{self.sensorType}{self.sensorName}{self.icon}",
|
||||
foreignKey=self.mac
|
||||
)
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def publish_mqtt(mqtt_client, topic, message):
|
||||
@@ -273,29 +306,54 @@ def create_sensor(mqtt_client, deviceId, deviceName, sensorType, sensorName, ico
|
||||
#-------------------------------------------------------------------------------
|
||||
def mqtt_create_client():
|
||||
|
||||
# attempt reconnections on failure, ref https://www.emqx.com/en/blog/how-to-use-mqtt-in-python
|
||||
FIRST_RECONNECT_DELAY = 1
|
||||
RECONNECT_RATE = 2
|
||||
MAX_RECONNECT_COUNT = 12
|
||||
MAX_RECONNECT_DELAY = 60
|
||||
|
||||
mytransport = 'tcp' # or 'websockets'
|
||||
|
||||
def on_disconnect(mqtt_client, userdata, reason_code):
|
||||
def on_disconnect(mqtt_client, userdata, rc):
|
||||
|
||||
global mqtt_connected_to_broker
|
||||
|
||||
# REF: If we wanted a auto reconnect, a good source is here: https://www.emqx.com/en/blog/how-to-use-mqtt-in-python
|
||||
mqtt_connected_to_broker = False
|
||||
mylog('debug', [f"[{pluginName}] Connection terminated, reason_code: {reason_code}"])
|
||||
mylog('verbose', [f"[{pluginName}] Connection terminated, reason_code: {rc}"])
|
||||
reconnect_count, reconnect_delay = 0, FIRST_RECONNECT_DELAY
|
||||
while reconnect_count < MAX_RECONNECT_COUNT:
|
||||
mylog('verbose', [f"[{pluginName}] Reconnecting in {reconnect_delay} seconds..."])
|
||||
time.sleep(reconnect_delay)
|
||||
|
||||
def on_connect(mqtt_client, userdata, flags, reason_code, properties):
|
||||
try:
|
||||
mqtt_client.reconnect()
|
||||
mqtt_connected_to_broker = True # Signal connection
|
||||
mylog('verbose', [f"[{pluginName}] Reconnected successfully"])
|
||||
return
|
||||
except Exception as err:
|
||||
mylog('verbose', [f"[{pluginName}] {err} Reconnect failed. Retrying..."])
|
||||
pass
|
||||
|
||||
reconnect_delay *= RECONNECT_RATE
|
||||
reconnect_delay = min(reconnect_delay, MAX_RECONNECT_DELAY)
|
||||
reconnect_count += 1
|
||||
|
||||
mqtt_connected_to_broker = False
|
||||
|
||||
|
||||
def on_connect(mqtt_client, userdata, flags, rc, properties):
|
||||
|
||||
global mqtt_connected_to_broker
|
||||
|
||||
# REF: Good docu on reason codes: https://www.emqx.com/en/blog/mqtt5-new-features-reason-code-and-ack
|
||||
if reason_code == 0:
|
||||
if rc == 0:
|
||||
mylog('verbose', [f"[{pluginName}] Connected to broker"])
|
||||
mqtt_connected_to_broker = True # Signal connection
|
||||
else:
|
||||
mylog('verbose', [f"[{pluginName}] Connection failed, reason_code: {reason_code}"])
|
||||
mylog('verbose', [f"[{pluginName}] Connection failed, reason_code: {rc}"])
|
||||
mqtt_connected_to_broker = False
|
||||
|
||||
global mqtt_client
|
||||
global mqtt_connected_to_broker
|
||||
|
||||
# Paho will be soon not supporting V1 anymore, so this really should not be a user choice to start with
|
||||
# This code now uses V2 by default
|
||||
@@ -306,10 +364,13 @@ def mqtt_create_client():
|
||||
else:
|
||||
version = mqtt.MQTTv5
|
||||
|
||||
# we now hardcode the client id into here.
|
||||
# TODO: Add config ffor client id
|
||||
mqtt_client = mqtt.Client(
|
||||
client_id='netalertx',
|
||||
callback_api_version = mqtt.CallbackAPIVersion.VERSION2,
|
||||
transport=mytransport,
|
||||
protocol=mqtt.MQTTv5)
|
||||
protocol=version)
|
||||
mqtt_client.on_connect = on_connect
|
||||
mqtt_client.on_disconnect = on_disconnect
|
||||
|
||||
@@ -317,7 +378,15 @@ def mqtt_create_client():
|
||||
mqtt_client.tls_set()
|
||||
|
||||
mqtt_client.username_pw_set(username = get_setting_value('MQTT_USER'), password = get_setting_value('MQTT_PASSWORD'))
|
||||
mqtt_client.connect(host = get_setting_value('MQTT_BROKER'), port = get_setting_value('MQTT_PORT'))
|
||||
err_code = mqtt_client.connect(host = get_setting_value('MQTT_BROKER'), port = get_setting_value('MQTT_PORT'))
|
||||
if (err_code == mqtt.MQTT_ERR_SUCCESS):
|
||||
# We (prematurely) set the connection state to connected
|
||||
# the callback may be delayed
|
||||
mqtt_connected_to_broker = True
|
||||
# the client connects but connect callbacks will be called async and there may be a waiting time
|
||||
# Mosquitto works straight away
|
||||
# EMQX has a delay and does not update in loop below, so we cannot rely on it, we wait 1 sec
|
||||
time.sleep(1)
|
||||
mqtt_client.loop_start()
|
||||
|
||||
return mqtt_client
|
||||
@@ -346,7 +415,7 @@ def mqtt_start(db):
|
||||
row = get_device_stats(db)
|
||||
|
||||
# Publish (wrap into {} and remove last ',' from above)
|
||||
publish_mqtt(mqtt_client, f"system-sensors/sensor/{deviceId}/state",
|
||||
publish_mqtt(mqtt_client, f"{topic_root}/sensor/{deviceId}/state",
|
||||
{
|
||||
"online": row[0],
|
||||
"down": row[1],
|
||||
@@ -373,28 +442,32 @@ def mqtt_start(db):
|
||||
|
||||
for device in devices:
|
||||
|
||||
# debug statement
|
||||
# if 'Moto' in device["dev_Name"]:
|
||||
# # debug statement START 🔻
|
||||
# if 'Moto' not in device["dev_Name"]:
|
||||
# continue
|
||||
# # debug statement END 🔺
|
||||
|
||||
# Create devices in Home Assistant - send config messages
|
||||
deviceId = 'mac_' + device["dev_MAC"].replace(" ", "").replace(":", "_").lower()
|
||||
devDisplayName = re.sub('[^a-zA-Z0-9-_\\s]', '', device["dev_Name"])
|
||||
# Normalize the string and remove unwanted characters
|
||||
devDisplayName = re.sub('[^a-zA-Z0-9-_\\s]', '', normalize_string(device["dev_Name"]))
|
||||
|
||||
sensorConfig = create_sensor(mqtt_client, deviceId, devDisplayName, 'sensor', 'last_ip', 'ip-network', device["dev_MAC"])
|
||||
sensorConfig = create_sensor(mqtt_client, deviceId, devDisplayName, 'sensor', 'mac_address', 'folder-key-network', device["dev_MAC"])
|
||||
sensorConfig = create_sensor(mqtt_client, deviceId, devDisplayName, 'sensor', 'is_new', 'bell-alert-outline', device["dev_MAC"])
|
||||
sensorConfig = create_sensor(mqtt_client, deviceId, devDisplayName, 'sensor', 'vendor', 'cog', device["dev_MAC"])
|
||||
sensorConfig = create_sensor(mqtt_client, deviceId, devDisplayName, 'sensor', 'vendor', 'cog', device["dev_MAC"])
|
||||
sensorConfig = create_sensor(mqtt_client, deviceId, devDisplayName, 'sensor', 'first_connection', 'calendar-start', device["dev_MAC"])
|
||||
sensorConfig = create_sensor(mqtt_client, deviceId, devDisplayName, 'sensor', 'last_connection', 'calendar-end', device["dev_MAC"])
|
||||
|
||||
|
||||
devJson = {
|
||||
"last_ip": device["dev_LastIP"],
|
||||
"is_new": str(device["dev_NewDevice"]),
|
||||
"vendor": sanitize_string(device["dev_Vendor"]),
|
||||
"mac_address": str(device["dev_MAC"]),
|
||||
"last_connection": str(device["dev_LastConnection"]),
|
||||
"first_connection": str(device["dev_FirstConnection"])
|
||||
}
|
||||
"model": devDisplayName,
|
||||
"last_connection": prepTimeStamp(str(device["dev_LastConnection"])),
|
||||
"first_connection": prepTimeStamp(str(device["dev_FirstConnection"])) }
|
||||
|
||||
# bulk update device sensors in home assistant
|
||||
publish_mqtt(mqtt_client, sensorConfig.state_topic, devJson)
|
||||
@@ -444,8 +517,24 @@ def to_binary_sensor(input):
|
||||
result = "ON"
|
||||
return result
|
||||
|
||||
# -------------------------------------
|
||||
# Convert to format that is interpretable by Home Assistant
|
||||
def prepTimeStamp(datetime_str):
|
||||
try:
|
||||
# Attempt to parse the input string to ensure it's a valid datetime
|
||||
parsed_datetime = datetime.fromisoformat(datetime_str)
|
||||
|
||||
# If the parsed datetime is naive (i.e., does not contain timezone info), add UTC timezone
|
||||
if parsed_datetime.tzinfo is None:
|
||||
parsed_datetime = parsed_datetime.replace(tzinfo=conf.tz)
|
||||
|
||||
except ValueError:
|
||||
mylog('verbose', [f"[{pluginName}] Timestamp conversion failed of string '{datetime_str}'"])
|
||||
# Use the current time if the input format is invalid
|
||||
parsed_datetime = timeNowTZ() # Assuming this function returns the current time with timezone
|
||||
|
||||
# Convert to the required format with 'T' between date and time and ensure the timezone is included
|
||||
return parsed_datetime.isoformat() # This will include the timezone offset
|
||||
|
||||
# -------------INIT---------------------
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -8,3 +8,5 @@ You need Telegram bot to send notifications
|
||||
### Usage
|
||||
|
||||
- Go to settings and fill in relevant details.
|
||||
|
||||
Made by [@doctorixx](https://github.com/doctorixx) 🙏
|
||||
|
||||
7
front/plugins/avahi_scan/README.md
Executable file
7
front/plugins/avahi_scan/README.md
Executable file
@@ -0,0 +1,7 @@
|
||||
## Overview
|
||||
|
||||
Plugin for device name discovery via the [avahi](https://wiki.alpinelinux.org/wiki/MDNS) network utility supporting mDNS.
|
||||
|
||||
### Usage
|
||||
|
||||
- Check the Settings page for details.
|
||||
207
front/plugins/avahi_scan/avahi_scan.py
Executable file
207
front/plugins/avahi_scan/avahi_scan.py
Executable file
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import json
|
||||
import sqlite3
|
||||
import subprocess
|
||||
|
||||
# Define the installation path and extend the system path for plugin imports
|
||||
INSTALL_PATH = "/app"
|
||||
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
|
||||
|
||||
from plugin_helper import Plugin_Object, Plugin_Objects, decodeBase64
|
||||
from plugin_utils import get_plugins_configs
|
||||
from logger import mylog
|
||||
from const import pluginsPath, fullDbPath
|
||||
from helper import timeNowTZ, get_setting_value
|
||||
from notification import write_notification
|
||||
from database import DB
|
||||
from device import Device_obj
|
||||
import conf
|
||||
from pytz import timezone
|
||||
|
||||
# Make sure the TIMEZONE for logging is correct
|
||||
conf.tz = timezone(get_setting_value('TIMEZONE'))
|
||||
|
||||
# Define the current path and log file paths
|
||||
CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
|
||||
LOG_FILE = os.path.join(CUR_PATH, 'script.log')
|
||||
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log')
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
pluginName = 'AVAHISCAN'
|
||||
|
||||
def main():
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
|
||||
# timeout = get_setting_value('AVAHI_RUN_TIMEOUT')
|
||||
timeout = 20
|
||||
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
# Create a Device_obj instance
|
||||
device_handler = Device_obj(db)
|
||||
|
||||
# Retrieve devices
|
||||
unknown_devices = device_handler.getUnknown()
|
||||
|
||||
# Mock list of devices (replace with actual device_handler.getUnknown() in production)
|
||||
# unknown_devices = [
|
||||
# {'dev_MAC': '00:11:22:33:44:55', 'dev_LastIP': '192.168.1.121'},
|
||||
# {'dev_MAC': '00:11:22:33:44:56', 'dev_LastIP': '192.168.1.9'},
|
||||
# {'dev_MAC': '00:11:22:33:44:57', 'dev_LastIP': '192.168.1.82'},
|
||||
# ]
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Unknown devices count: {len(unknown_devices)}'])
|
||||
|
||||
if len(unknown_devices) > 0:
|
||||
# ensure service is running
|
||||
ensure_avahi_running()
|
||||
|
||||
for device in unknown_devices:
|
||||
domain_name = execute_name_lookup(device['dev_LastIP'], timeout)
|
||||
|
||||
# check if found and not a timeout ('to')
|
||||
if domain_name != '' and domain_name != 'to':
|
||||
plugin_objects.add_object(
|
||||
# "MAC", "IP", "Server", "Name"
|
||||
primaryId = device['dev_MAC'],
|
||||
secondaryId = device['dev_LastIP'],
|
||||
watched1 = '', # You can add any relevant info here if needed
|
||||
watched2 = domain_name,
|
||||
watched3 = '',
|
||||
watched4 = '',
|
||||
extra = '',
|
||||
foreignKey = device['dev_MAC'])
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Script finished'])
|
||||
|
||||
return 0
|
||||
|
||||
#===============================================================================
|
||||
# Execute scan
|
||||
#===============================================================================
|
||||
def execute_name_lookup(ip, timeout):
|
||||
"""
|
||||
Execute the avahi-resolve command on the IP.
|
||||
"""
|
||||
|
||||
args = ['avahi-resolve', '-a', ip]
|
||||
|
||||
# Execute command
|
||||
output = ""
|
||||
|
||||
try:
|
||||
mylog('verbose', [f'[{pluginName}] DEBUG CMD :', args])
|
||||
|
||||
# Run the subprocess with a forced timeout
|
||||
output = subprocess.check_output(args, universal_newlines=True, stderr=subprocess.STDOUT, timeout=timeout)
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] DEBUG OUTPUT : {output}'])
|
||||
|
||||
domain_name = ''
|
||||
|
||||
# Split the output into lines
|
||||
lines = output.splitlines()
|
||||
|
||||
# Look for the resolved IP address
|
||||
for line in lines:
|
||||
if ip in line:
|
||||
parts = line.split()
|
||||
if len(parts) > 1:
|
||||
domain_name = parts[1] # Second part is the resolved domain name
|
||||
else:
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - Unexpected output format: {line}'])
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Domain Name: {domain_name}'])
|
||||
|
||||
return domain_name
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - {e.output}'])
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
mylog('verbose', [f'[{pluginName}] TIMEOUT - the process forcefully terminated as timeout reached'])
|
||||
|
||||
if output == "":
|
||||
mylog('verbose', [f'[{pluginName}] Scan: FAIL - check logs'])
|
||||
else:
|
||||
mylog('verbose', [f'[{pluginName}] Scan: SUCCESS'])
|
||||
|
||||
return ''
|
||||
|
||||
# Function to ensure Avahi and its dependencies are running
|
||||
def ensure_avahi_running(attempt=1, max_retries=2):
|
||||
"""
|
||||
Ensure that D-Bus is running and the Avahi daemon is started, with recursive retry logic.
|
||||
"""
|
||||
mylog('verbose', [f'[{pluginName}] Attempt {attempt} - Ensuring D-Bus and Avahi daemon are running...'])
|
||||
|
||||
# Check rc-status
|
||||
try:
|
||||
subprocess.run(['rc-status'], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - Failed to check rc-status: {e.output}'])
|
||||
return
|
||||
|
||||
# Create OpenRC soft level
|
||||
subprocess.run(['touch', '/run/openrc/softlevel'], check=True)
|
||||
|
||||
# Add Avahi daemon to runlevel
|
||||
try:
|
||||
subprocess.run(['rc-update', 'add', 'avahi-daemon'], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - Failed to add Avahi to runlevel: {e.output}'])
|
||||
return
|
||||
|
||||
# Start the D-Bus service
|
||||
try:
|
||||
subprocess.run(['rc-service', 'dbus', 'start'], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - Failed to start D-Bus: {e.output}'])
|
||||
return
|
||||
|
||||
# Check Avahi status
|
||||
status_output = subprocess.run(['rc-service', 'avahi-daemon', 'status'], capture_output=True, text=True)
|
||||
if 'started' in status_output.stdout:
|
||||
mylog('verbose', [f'[{pluginName}] Avahi Daemon is already running.'])
|
||||
return
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Avahi Daemon is not running, attempting to start... (Attempt {attempt})'])
|
||||
|
||||
# Start the Avahi daemon
|
||||
try:
|
||||
subprocess.run(['rc-service', 'avahi-daemon', 'start'], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - Failed to start Avahi daemon: {e.output}'])
|
||||
|
||||
# Check status after starting
|
||||
status_output = subprocess.run(['rc-service', 'avahi-daemon', 'status'], capture_output=True, text=True)
|
||||
if 'started' in status_output.stdout:
|
||||
mylog('verbose', [f'[{pluginName}] Avahi Daemon successfully started.'])
|
||||
return
|
||||
|
||||
# Retry if not started and attempts are left
|
||||
if attempt < max_retries:
|
||||
mylog('verbose', [f'[{pluginName}] Retrying... ({attempt + 1}/{max_retries})'])
|
||||
ensure_avahi_running(attempt + 1, max_retries)
|
||||
else:
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - Avahi Daemon failed to start after {max_retries} attempts.'])
|
||||
|
||||
# rc-update add avahi-daemon
|
||||
# rc-service avahi-daemon status
|
||||
# rc-service avahi-daemon start
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
330
front/plugins/avahi_scan/config.json
Executable file
330
front/plugins/avahi_scan/config.json
Executable file
@@ -0,0 +1,330 @@
|
||||
{
|
||||
"code_name": "avahi_scan",
|
||||
"unique_prefix": "AVAHISCAN",
|
||||
"plugin_type": "other",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"execution_order" : "Layer_3",
|
||||
"show_ui": true,
|
||||
"localized": ["display_name", "description", "icon"],
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "AVAHISCAN (Name discovery)"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "<i class=\"fa-solid fa-search\"></i>"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "A plugin to discover device names via mDNS."
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"name": "ips",
|
||||
"type": "sql",
|
||||
"value": "SELECT dev_LastIP from DEVICES order by dev_MAC",
|
||||
"timeoutMultiplier": true
|
||||
}
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
"events": ["run"],
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{ "elementType": "select", "elementOptions": [], "transformers": [] }
|
||||
]
|
||||
},
|
||||
"default_value": "before_name_updates",
|
||||
"options": [
|
||||
"disabled",
|
||||
"before_name_updates",
|
||||
"on_new_device",
|
||||
"once",
|
||||
"schedule",
|
||||
"always_after_scan"
|
||||
],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When to run"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Cuándo ejecutar"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Wann laufen"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "When the plugin should be executed. If enabled this will execute the scan until there are no <code>(unknown)</code> or <code>(name not found)</code> devices. Setting this to <code>on_new_device</code> or a daily <code>schedule</code> is recommended."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "CMD",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [{ "readonly": "true" }],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": "python3 /app/front/plugins/avahi_scan/avahi_scan.py",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Command to run. This can not be changed"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Comando a ejecutar. Esto no se puede cambiar"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Befehl zum Ausführen. Dies kann nicht geändert werden"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_SCHD",
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{ "elementType": "input", "elementOptions": [], "transformers": [] }
|
||||
]
|
||||
},
|
||||
"default_value": "*/30 * * * *",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Schedule"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Schedule"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#AVAHISCAN_RUN\"><code>AVAHISCAN_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Solo está habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#AVAHISCAN_RUN\"><code>AVAHISCAN_RUN</code></a>. Asegúrese de ingresar la programación en el formato similar a cron correcto (por ejemplo, valide en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, ingresar <code>0 4 * * *</code> ejecutará el escaneo después de las 4 a.m. en el <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ código> que configuró arriba</a>. Se ejecutará la PRÓXIMA vez que pase el tiempo."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nur aktiviert, wenn Sie <code>schedule</code> in der <a href=\"#AVAHISCAN_RUN\"><code>AVAHISCAN_RUN</code>-Einstellung</a> auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Wenn Sie beispielsweise <code>0 4 * * *</code> eingeben, wird der Scan nach 4 Uhr morgens in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ ausgeführt. Code> den Sie oben festgelegt haben</a>. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "RUN_TIMEOUT",
|
||||
"type": {
|
||||
"dataType": "integer",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [{ "type": "number" }],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": 10,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Run timeout"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo límite de ejecución"
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Zeitüberschreitung"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Maximum time per device scan in seconds to wait for the script to finish. If this time is exceeded the script is aborted."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"database_column_definitions": [
|
||||
{
|
||||
"column": "Object_PrimaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "device_name_mac",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "MAC"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "MAC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Object_SecondaryID",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "IP"
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "IP"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value1",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Server"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Watched_Value2",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Name"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeCreated",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Created"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "DateTimeChanged",
|
||||
"css_classes": "col-sm-2",
|
||||
"show": true,
|
||||
"type": "label",
|
||||
"default_value": "",
|
||||
"options": [],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Changed"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"column": "Status",
|
||||
"css_classes": "col-sm-1",
|
||||
"show": true,
|
||||
"type": "replace",
|
||||
"default_value": "",
|
||||
"options": [
|
||||
{
|
||||
"equals": "watched-not-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-square-check'></i><div></div>"
|
||||
},
|
||||
{
|
||||
"equals": "watched-changed",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-triangle-exclamation'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "new",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-circle-plus'></i></div>"
|
||||
},
|
||||
{
|
||||
"equals": "missing-in-last-scan",
|
||||
"replacement": "<div style='text-align:center'><i class='fa-solid fa-question'></i></div>"
|
||||
}
|
||||
],
|
||||
"localized": ["name"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Status"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,6 +2,23 @@
|
||||
|
||||
Plugin to run regular database cleanup tasks. It is strongly recommended to have an hourly or at least daily schedule running.
|
||||
|
||||
The database cleanup plugin (DBCLNP) helps maintain the system by removing outdated or unnecessary data, ensuring smooth operation. Below are the key settings that control the cleanup process:
|
||||
|
||||
- **`PLUGINS_KEEP_HIST`**:
|
||||
Specifies how many historical records to retain for each plugin. Recommended value: `500` entries.
|
||||
|
||||
- **`HRS_TO_KEEP_NEWDEV`**:
|
||||
Defines how long, in hours, newly discovered device records should be kept. Once the specified time has passed, the records will be deleted if tehy still are marked as NEW. Recommended value: `0` (no auto delete).
|
||||
|
||||
- **`DAYS_TO_KEEP_EVENTS`**:
|
||||
Specifies the number of days to retain event logs. Event entries older than the given number of days will be automatically deleted during cleanup. Recommended value: `30` days.
|
||||
|
||||
- **`PHOLUS_DAYS_DATA`**:
|
||||
Deletes all data older than specified number of days for teh Pholus plugin used for name discovery. Recommended value: `30` days.
|
||||
|
||||
By fine-tuning these settings, you ensure that the database remains optimized, preventing performance degradation in the NetAlertX system.
|
||||
|
||||
|
||||
### Usage
|
||||
|
||||
- Check the Settings page for details.
|
||||
|
||||
@@ -25,24 +25,7 @@
|
||||
"string": "A plugin to schedule database cleanup & upkeep tasks."
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"name": "pluginskeephistory",
|
||||
"type": "setting",
|
||||
"value": "PLUGINS_KEEP_HIST"
|
||||
},
|
||||
{
|
||||
"name": "daystokeepevents",
|
||||
"type": "setting",
|
||||
"value": "DAYS_TO_KEEP_EVENTS"
|
||||
},
|
||||
{
|
||||
"name": "hourstokeepnewdevice",
|
||||
"type": "setting",
|
||||
"value": "HRS_TO_KEEP_NEWDEV"
|
||||
}
|
||||
],
|
||||
|
||||
"params": [],
|
||||
"settings": [
|
||||
{
|
||||
"function": "RUN",
|
||||
@@ -89,7 +72,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": "python3 /app/front/plugins/db_cleanup/script.py pluginskeephistory={pluginskeephistory} hourstokeepnewdevice={hourstokeepnewdevice} daystokeepevents={daystokeepevents} pholuskeepdays={pholuskeepdays}",
|
||||
"default_value": "python3 /app/front/plugins/db_cleanup/script.py",
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
@@ -150,14 +133,6 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Only enabled if you select <code>schedule</code> in the <a href=\"#DBCLNP_RUN\"><code>DBCLNP_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Solo está habilitado si selecciona <code>schedule</code> en la configuración <a href=\"#DBCLNP_RUN\"><code>DBCLNP_RUN</code></a>. Asegúrese de ingresar la programación en el formato similar a cron correcto (por ejemplo, valide en <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Por ejemplo, ingresar <code>0 4 * * *</code> ejecutará el escaneo después de las 4 a.m. en el <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ código> que configuró arriba</a>. Se ejecutará la PRÓXIMA vez que pase el tiempo."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Nur aktiviert, wenn Sie <code>schedule</code> in der <a href=\"#DBCLNP_RUN\"><code>DBCLNP_RUN</code>-Einstellung</a> auswählen. Stellen Sie sicher, dass Sie den Zeitplan im richtigen Cron-ähnlichen Format eingeben (z. B. validieren unter <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). Wenn Sie beispielsweise <code>0 4 * * *</code> eingeben, wird der Scan nach 4 Uhr morgens in der <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</ ausgeführt. Code> den Sie oben festgelegt haben</a>. Wird das NÄCHSTE Mal ausgeführt, wenn die Zeit vergeht."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -173,7 +148,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": 30,
|
||||
"default_value": 300,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
@@ -194,14 +169,6 @@
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Maximale Zeit in Sekunden, die auf den Abschluss des Skripts gewartet werden soll. Bei Überschreitung dieser Zeit wird das Skript abgebrochen."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -32,24 +32,17 @@ pluginName = 'DBCLNP'
|
||||
|
||||
def main():
|
||||
|
||||
parser = argparse.ArgumentParser(description='DB cleanup tasks')
|
||||
parser.add_argument('pluginskeephistory', action="store", help="TBC")
|
||||
parser.add_argument('hourstokeepnewdevice', action="store", help="TBC")
|
||||
parser.add_argument('daystokeepevents', action="store", help="TBC")
|
||||
parser.add_argument('pholuskeepdays', action="store", help="TBC") # unused
|
||||
|
||||
values = parser.parse_args()
|
||||
|
||||
PLUGINS_KEEP_HIST = int(values.pluginskeephistory.split('=')[1])
|
||||
HRS_TO_KEEP_NEWDEV = int(values.hourstokeepnewdevice.split('=')[1])
|
||||
DAYS_TO_KEEP_EVENTS = int(values.daystokeepevents.split('=')[1])
|
||||
PLUGINS_KEEP_HIST = int(get_setting_value("PLUGINS_KEEP_HIST"))
|
||||
HRS_TO_KEEP_NEWDEV = int(get_setting_value("HRS_TO_KEEP_NEWDEV"))
|
||||
DAYS_TO_KEEP_EVENTS = int(get_setting_value("DAYS_TO_KEEP_EVENTS"))
|
||||
PHOLUS_DAYS_DATA = get_setting_value("PHOLUS_DAYS_DATA")
|
||||
CLEAR_NEW_FLAG = get_setting_value("CLEAR_NEW_FLAG")
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
|
||||
|
||||
# Execute cleanup/upkeep
|
||||
cleanup_database(fullDbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST)
|
||||
cleanup_database(fullDbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST, CLEAR_NEW_FLAG)
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Cleanup complete'])
|
||||
|
||||
@@ -58,7 +51,7 @@ def main():
|
||||
#===============================================================================
|
||||
# Cleanup / upkeep database
|
||||
#===============================================================================
|
||||
def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST):
|
||||
def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP_NEWDEV, PLUGINS_KEEP_HIST, CLEAR_NEW_FLAG):
|
||||
"""
|
||||
Cleaning out old records from the tables that don't need to keep all data.
|
||||
"""
|
||||
@@ -151,6 +144,17 @@ def cleanup_database (dbPath, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA, HRS_TO_KEEP
|
||||
mylog('verbose', [f'[{pluginName}] Query: {query} '])
|
||||
cursor.execute (query)
|
||||
|
||||
# -----------------------------------------------------
|
||||
# Clear New Flag
|
||||
if CLEAR_NEW_FLAG != 0:
|
||||
mylog('verbose', [f'[{pluginName}] Devices: Clear "New Device" flag for all devices older than {str(CLEAR_NEW_FLAG)} hours (CLEAR_NEW_FLAG setting)'])
|
||||
query = f"""UPDATE Devices SET dev_NewDevice = 0 WHERE dev_NewDevice = 1 AND date(dev_FirstConnection, '+{str(CLEAR_NEW_FLAG)} hour') < date('now')"""
|
||||
# select * from Devices where dev_NewDevice = 1 AND date(dev_FirstConnection, '+3 hour' ) < date('now')
|
||||
mylog('verbose', [f'[{pluginName}] Query: {query} '])
|
||||
cursor.execute(query)
|
||||
|
||||
|
||||
|
||||
# -----------------------------------------------------
|
||||
# Cleanup Pholus_Scan
|
||||
if PHOLUS_DAYS_DATA != "" and PHOLUS_DAYS_DATA != 0:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"code_name": "dhcp_servers",
|
||||
"unique_prefix": "DHCPSRVS",
|
||||
"plugin_type": "other",
|
||||
"execution_order" : "Layer_3",
|
||||
"execution_order": "Layer_3",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
"show_ui": true,
|
||||
@@ -349,7 +349,11 @@
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{ "elementType": "input", "elementOptions": [], "transformers": [] }
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [{ "readonly": "true" }],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": "python3 /app/front/plugins/dhcp_servers/script.py",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
A plugin responsible for general maintenance tasks. These currently include:
|
||||
|
||||
- app.log cleanup
|
||||
- **`MAINT_LOG_LENGTH`**: app.log cleanup. Recommended value: `10000` lines. Increase if debugging an issue.
|
||||
|
||||
### Usage
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": 30,
|
||||
"default_value": 300,
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"code_name": "mikrotik_scan",
|
||||
"unique_prefix": "MTSCAN",
|
||||
"plugin_type": "other",
|
||||
"plugin_type": "device_scanner",
|
||||
"execution_order" : "Layer_4",
|
||||
"enabled": true,
|
||||
"data_source": "script",
|
||||
@@ -11,7 +11,7 @@
|
||||
"display_name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Mikrotik (Name discovery)"
|
||||
"string": "Mikrotik (Device discovery)"
|
||||
}
|
||||
],
|
||||
"icon": [
|
||||
@@ -23,7 +23,7 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "A plugin to discover device names."
|
||||
"string": "A plugin to discover devices via Mikrotik."
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# test script by running:
|
||||
# tbc
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
@@ -40,42 +38,35 @@ pluginName = 'MTSCAN'
|
||||
|
||||
def main():
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
mylog('verbose', [f'[{pluginName}] In script'])
|
||||
|
||||
mt_host = get_setting_value('MTSCAN_MT_HOST')
|
||||
mt_port = get_setting_value('MTSCAN_MT_PORT')
|
||||
mt_user = get_setting_value('MTSCAN_MT_USER')
|
||||
mt_password = get_setting_value('MTSCAN_MT_PASS')
|
||||
|
||||
#mylog('verbose', [f'[{pluginName}] Router: {mt_host}:{mt_port} user: {mt_user}, pass: {mt_password}'])
|
||||
# Create a database connection
|
||||
db = DB() # instance of class DB
|
||||
db.open()
|
||||
# init global variables
|
||||
global MT_HOST, MT_PORT, MT_USER, MT_PASS
|
||||
|
||||
# Initialize the Plugin obj output file
|
||||
plugin_objects = Plugin_Objects(RESULT_FILE)
|
||||
|
||||
# Create a Device_obj instance
|
||||
device_handler = Device_obj(db)
|
||||
# Mikrotik settings
|
||||
MT_HOST = get_setting_value('MTSCAN_MT_HOST')
|
||||
MT_PORT = get_setting_value('MTSCAN_MT_PORT')
|
||||
MT_USER = get_setting_value('MTSCAN_MT_USER')
|
||||
MT_PASS = get_setting_value('MTSCAN_MT_PASS')
|
||||
|
||||
# Retrieve devices
|
||||
#unknown_devices = device_handler.getUnknown()
|
||||
#mylog('verbose', [f'[{pluginName}] Unknown devices count: {len(unknown_devices)}'])
|
||||
plugin_objects = get_entries(plugin_objects)
|
||||
|
||||
all_devices = device_handler.getAll()
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Scan finished, found {len(plugin_objects)} devices'])
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] all devices count: {len(all_devices)}'])
|
||||
|
||||
device_map = {d['dev_MAC']:d['dev_LastIP'] for d in all_devices}
|
||||
def get_entries(plugin_objects: Plugin_Objects) -> Plugin_Objects:
|
||||
|
||||
try:
|
||||
# connect router
|
||||
api = connect(username=mt_user, password=mt_password, host=mt_host, port=mt_port)
|
||||
api = connect(username=MT_USER, password=MT_PASS, host=MT_HOST, port=MT_PORT)
|
||||
|
||||
# get dhcp leases
|
||||
leases = api('/ip/dhcp-server/lease/print')
|
||||
|
||||
|
||||
|
||||
for lease in leases:
|
||||
lease_id = lease.get('.id')
|
||||
@@ -84,56 +75,31 @@ def main():
|
||||
host_name = lease.get('host-name')
|
||||
comment = lease.get('comment')
|
||||
last_seen = lease.get('last-seen')
|
||||
status = lease.get('status')
|
||||
|
||||
mylog('verbose', [f"ID: {lease_id}, Address: {address}, MAC Address: {mac_address}, Host Name: {host_name}, Comment: {comment}, Last Seen: {last_seen}"])
|
||||
if mac_address in device_map.keys():
|
||||
device_name = host_name
|
||||
if comment != '':
|
||||
device_name = comment
|
||||
|
||||
mylog('verbose', [f"ID: {lease_id}, Address: {address}, MAC Address: {mac_address}, Host Name: {host_name}, Comment: {comment}, Last Seen: {last_seen}, Status: {status}"])
|
||||
|
||||
if (status == "bound"):
|
||||
plugin_objects.add_object(
|
||||
# "Name-MAC", "LastIP", "IP", "Name","Host","LastSeen","Comment"
|
||||
primaryId = mac_address,
|
||||
secondaryId = device_map[mac_address],
|
||||
secondaryId = address,
|
||||
watched1 = address,
|
||||
watched2 = device_name,
|
||||
watched3 = host_name,
|
||||
watched4 = last_seen,
|
||||
watched2 = host_name,
|
||||
watched3 = last_seen,
|
||||
watched4 = '',
|
||||
extra = '',
|
||||
helpVal1 = comment,
|
||||
foreignKey = mac_address)
|
||||
|
||||
plugin_objects.write_result_file()
|
||||
|
||||
except TrapError as e:
|
||||
mylog('error', [f"An error occurred: {e}"])
|
||||
except Exception as e:
|
||||
mylog('error', [f"Failed to connect to MikroTik API: {e}"])
|
||||
|
||||
|
||||
#for device in unknown_devices:
|
||||
# domain_name, dns_server = execute_nslookup(device['dev_LastIP'], timeout)
|
||||
|
||||
# if domain_name != '':
|
||||
# plugin_objects.add_object(
|
||||
# # "MAC", "IP", "Server", "Name"
|
||||
# primaryId = device['dev_MAC'],
|
||||
# secondaryId = device['dev_LastIP'],
|
||||
# watched1 = dns_server,
|
||||
# watched2 = domain_name,
|
||||
# watched3 = '',
|
||||
# watched4 = '',
|
||||
# extra = '',
|
||||
# foreignKey = device['dev_MAC'])
|
||||
|
||||
#plugin_objects.write_result_file()
|
||||
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Script finished'])
|
||||
|
||||
return 0
|
||||
return plugin_objects
|
||||
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# BEGIN
|
||||
|
||||
@@ -56,7 +56,7 @@ def main():
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Unknown devices count: {len(unknown_devices)}'])
|
||||
|
||||
# TEST
|
||||
# TEST - below is a WINDOWS host IP
|
||||
# execute_name_lookup('192.168.1.121', timeout)
|
||||
|
||||
for device in unknown_devices:
|
||||
@@ -86,7 +86,7 @@ def main():
|
||||
#===============================================================================
|
||||
def execute_name_lookup (ip, timeout):
|
||||
"""
|
||||
Execute the NBLOOKUP command on IP.
|
||||
Execute the NBTSCAN command on IP.
|
||||
"""
|
||||
|
||||
args = ['nbtscan', ip]
|
||||
@@ -95,6 +95,8 @@ def execute_name_lookup (ip, timeout):
|
||||
output = ""
|
||||
|
||||
try:
|
||||
mylog('verbose', [f'[{pluginName}] DEBUG CMD :', args])
|
||||
|
||||
# try runnning a subprocess with a forced (timeout) in case the subprocess hangs
|
||||
output = subprocess.check_output (args, universal_newlines=True, stderr=subprocess.STDOUT, timeout=(timeout), text=True)
|
||||
|
||||
@@ -112,8 +114,10 @@ def execute_name_lookup (ip, timeout):
|
||||
if 'Doing NBT name scan' not in line and ip in line:
|
||||
# Split the line and extract the primary NetBIOS name
|
||||
parts = line.split()
|
||||
if parts:
|
||||
if len(parts) > 1:
|
||||
domain_name = parts[1]
|
||||
else:
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - Unexpected output format: {line}'])
|
||||
|
||||
|
||||
mylog('verbose', [f'[{pluginName}] Domain Name: {domain_name}'])
|
||||
@@ -125,9 +129,7 @@ def execute_name_lookup (ip, timeout):
|
||||
# if "NXDOMAIN" in e.output:
|
||||
# mylog('verbose', [f'[{pluginName}]', f"No PTR record found for IP: {ip}"])
|
||||
# else:
|
||||
mylog('verbose', [f'[{pluginName}]', e.output])
|
||||
# Handle other errors here
|
||||
# mylog('verbose', [f'[{pluginName}] ⚠ ERROR - check logs'])
|
||||
mylog('verbose', [f'[{pluginName}] ⚠ ERROR - {e.output}'])
|
||||
|
||||
except subprocess.TimeoutExpired as timeErr:
|
||||
mylog('verbose', [f'[{pluginName}] TIMEOUT - the process forcefully terminated as timeout reached'])
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": ["_in"] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-sm-2" },
|
||||
{ "cssClasses": "col-xs-12" },
|
||||
{ "onClick": "addList(this, false)" },
|
||||
{ "getStringKey": "Gen_Add" }
|
||||
],
|
||||
@@ -219,7 +219,7 @@
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": [] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-sm-3" },
|
||||
{ "cssClasses": "col-xs-6" },
|
||||
{ "onClick": "removeFromList(this)" },
|
||||
{ "getStringKey": "Gen_Remove_Last" }
|
||||
],
|
||||
@@ -230,7 +230,7 @@
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": [] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-sm-3" },
|
||||
{ "cssClasses": "col-xs-6" },
|
||||
{ "onClick": "removeAllOptions(this)" },
|
||||
{ "getStringKey": "Gen_Remove_All" }
|
||||
],
|
||||
@@ -261,7 +261,7 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "All the newly discovered device names are clened up by applying the following REGEX expression in this order. All the below are replaced by a blank string."
|
||||
"string": "All the newly discovered device names are cleaned up by applying the following REGEX expression in this order. All the below are replaced by a blank string."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -977,7 +977,27 @@
|
||||
"type": {
|
||||
"dataType": "string",
|
||||
"elements": [
|
||||
{ "elementType": "select", "elementOptions": [], "transformers": [] }
|
||||
{
|
||||
"elementType": "span",
|
||||
"elementOptions": [
|
||||
{ "cssClasses": "input-group-addon iconPreview" },
|
||||
{ "getStringKey": "Gen_SelectToPreview" },
|
||||
{ "customId": "NEWDEV_dev_Icon_preview" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "select",
|
||||
"elementHasInputValue": 1,
|
||||
"elementOptions": [
|
||||
{ "cssClasses": "col-xs-12" },
|
||||
{
|
||||
"onChange": "updateIconPreview(this)"
|
||||
},
|
||||
{ "customParams": "NEWDEV_dev_Icon,NEWDEV_dev_Icon_preview" }
|
||||
],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": "",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "select",
|
||||
"elementOptions": [{ "multiple": "true" }],
|
||||
"elementOptions": [{ "multiple": "true", "ordeable": "true" }],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
@@ -65,15 +65,15 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Specifies which events trigger notifications. Remove the event type(s) you do not want to get notified on. This setting overrides device-specific settings in the UI. (<code>CTRL + Click</code> to select/deselect)."
|
||||
"string": "Specifies which events trigger notifications. Remove the event type(s) you do not want to get notified on. This setting overrides device-specific settings in the UI."
|
||||
},
|
||||
{
|
||||
"language_code": "de_de",
|
||||
"string": "Spezifiziert, bei welchen Events Benachrichtigungen versendet werden. Entfernen Sie die Eventtypen, bei welchen Sie nicht benachrichtigt werden wollen. Diese Einstellung überschreibt gerätespezifische Einstellungen im UI. (<code>STRG + klicken</code> zum aus-/abwählen)."
|
||||
"string": "Spezifiziert, bei welchen Events Benachrichtigungen versendet werden. Entfernen Sie die Eventtypen, bei welchen Sie nicht benachrichtigt werden wollen. Diese Einstellung überschreibt gerätespezifische Einstellungen im UI."
|
||||
},
|
||||
{
|
||||
"language_code": "es_es",
|
||||
"string": "Especifica que eventos envían notificaciones. Elimina los tipos de eventos de los que no quieras recibir notificaciones. Este ajuste sobreescribe los ajustes específicos de los dispositivos en la interfaz. (<code>CTRL + Clic</code> para seleccionar / deseleccionar)."
|
||||
"string": "Especifica que eventos envían notificaciones. Elimina los tipos de eventos de los que no quieras recibir notificaciones. Este ajuste sobreescribe los ajustes específicos de los dispositivos en la interfaz."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -125,7 +125,7 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "You can specify a SQL where condition to filter out New Devices from notifications. For example <code>AND dev_LastIP NOT LIKE '192.168.3.%'</code> will always exlude New Device notifications for all devices with the IP starting with <code>192.168.3.%</code>."
|
||||
"string": "You can specify a SQL where condition to filter out New Devices from notifications. For example <code>AND dev_LastIP NOT LIKE '192.168.3.%'</code> will always exclude New Device notifications for all devices with the IP starting with <code>192.168.3.%</code>."
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -149,7 +149,7 @@
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "You can specify a SQL where condition to filter out Events from notifications. For example <code>AND dev_LastIP NOT LIKE '192.168.3.%'</code> will always exlude New Device notifications for all devices with the IP starting with <code>192.168.3.%</code>."
|
||||
"string": "You can specify a SQL where condition to filter out Events from notifications. For example <code>AND dev_LastIP NOT LIKE '192.168.3.%'</code> will always exclude New Device notifications for all devices with the IP starting with <code>192.168.3.%</code>."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1057,7 +1057,7 @@ def main():
|
||||
elif values.rdns_scanning:
|
||||
file_print_pr("[DEBUG] Timestamp 45: ", timeNow())
|
||||
dns_query=None
|
||||
ipn = ipaddress.ip_network(values.rdns_scanning)
|
||||
ipn = ipaddress.ip_network(values.rdns_scanning, strict=False)
|
||||
for ip in ipn.hosts():
|
||||
the_query = ip.reverse_pointer
|
||||
if not dns_query:
|
||||
|
||||
@@ -1,41 +1,63 @@
|
||||
## Overview
|
||||
|
||||
Synchronization plugin to synchronize multiple app instances. The Plugin can sychronize 2 types of data:
|
||||
The synchronization plugin is designed to synchronize data across multiple instances of the app. It supports the following data synchronization modes:
|
||||
|
||||
1. 💻 Devices: The plugin sends an encrypted `table_devices.json` file to synchronize the whole Devices DB table.
|
||||
1. 🔌 Plugin data: The plugin sends encrypted `last_result.log` files for individual plugins.
|
||||
1. **💻 Devices**: Sends an encrypted `table_devices.json` file to synchronize the entire Devices database table.
|
||||
2. **🔌 Plugin Data**: Sends encrypted `last_result.log` files for individual plugins.
|
||||
|
||||
> [!TIP]
|
||||
> `[n]` indicates a setting that is usually specified for the node instance. `[n,h]` indicates a setting used both, on the node and on the hub instance.
|
||||
> **Note:** `[n]` indicates a setting specified for the node instance, and `[n,h]` indicates a setting used on both the node and the hub instances.
|
||||
|
||||
### Synchronizing 💻 Devices data or 🔌 Plugins data
|
||||
### Synchronization Modes
|
||||
|
||||
Most of the setups will probably only use 💻 Devices synchronization. 🔌 Plugins data will be probably used in only special use cases.
|
||||
The plugin operates in three different modes based on the configuration settings:
|
||||
|
||||
#### [n] Node (Source) Settings
|
||||
1. **Mode 1: PUSH (NODE)** - Sends data from the node to the hub.
|
||||
- This mode is activated if `SYNC_hub_url` is set and either `SYNC_devices` or `SYNC_plugins` is enabled.
|
||||
- **Actions**:
|
||||
- Sends `table_devices.json` to the hub if `SYNC_devices` is enabled.
|
||||
- Sends individual plugin `last_result.log` files to the hub if `SYNC_plugins` is enabled.
|
||||
|
||||
- When to run [n,h] `SYNC_RUN`
|
||||
- Schedule [n,h] `SYNC_RUN_SCHD`
|
||||
- API token [n,h] `SYNC_api_token`
|
||||
- Encryption Key [n,h] `SYNC_encryption_key`
|
||||
- Node name [n] `SYNC_node_name`
|
||||
- Hub URL [n] `SYNC_hub_url`
|
||||
- Sync Devices [n] `SYNC_devices` or Sync Plugins [n] `SYNC_plugins` (or both)
|
||||
2. **Mode 2: PULL (HUB)** - Retrieves data from nodes to the hub.
|
||||
- This mode is activated if `SYNC_nodes` is set.
|
||||
- **Actions**:
|
||||
- Retrieves data from configured nodes using the API and saves it locally for further processing.
|
||||
|
||||
#### [h] Hub (Target) Settings
|
||||
3. **Mode 3: RECEIVE (HUB)** - Processes received data on the hub.
|
||||
- Activated when data is received in Mode 2 and is ready to be processed.
|
||||
- **Actions**:
|
||||
- Decodes received data files, processes them, and updates the Devices table accordingly.
|
||||
|
||||
- When to run [n,h] `SYNC_RUN`
|
||||
- Schedule [n,h] `SYNC_RUN_SCHD`
|
||||
- API token [n,h] `SYNC_api_token`
|
||||
- Encryption Key [n,h] `SYNC_encryption_key`
|
||||
### Settings
|
||||
|
||||
#### Node (Source) Settings `[n]`
|
||||
|
||||
- **When to Run** `[n,h]`: `SYNC_RUN`
|
||||
- **Schedule** `[n,h]`: `SYNC_RUN_SCHD`
|
||||
- **API Token** `[n,h]`: `SYNC_api_token`
|
||||
- **Encryption Key** `[n,h]`: `SYNC_encryption_key`
|
||||
- **Node Name** `[n]`: `SYNC_node_name`
|
||||
- **Hub URL** `[n]`: `SYNC_hub_url`
|
||||
- **Sync Devices** `[n]`: `SYNC_devices`
|
||||
- **Sync Plugins** `[n]`: `SYNC_plugins`
|
||||
|
||||
#### Hub (Target) Settings `[h]`
|
||||
|
||||
- **When to Run** `[n,h]`: `SYNC_RUN`
|
||||
- **Schedule** `[n,h]`: `SYNC_RUN_SCHD`
|
||||
- **API Token** `[n,h]`: `SYNC_api_token`
|
||||
- **Encryption Key** `[n,h]`: `SYNC_encryption_key`
|
||||
- **Nodes to Pull From** `[h]`: `SYNC_nodes`
|
||||
|
||||
### Usage
|
||||
|
||||
- Head to **Settings** > **Sync Hub** to adjust the default values.
|
||||
1. **Adjust Settings**:
|
||||
- Navigate to **Settings** > **Sync Hub** to modify default settings.
|
||||
2. **Data Flow**:
|
||||
- Nodes send or receive data based on the specified modes, either pushing data to the hub or pulling from nodes.
|
||||
|
||||
### Notes
|
||||
|
||||
- If a MAC address already exists on the hub, the device will be skipped in the data coming from this SYNC plugin.
|
||||
- Existing devices on the hub will not be updated by the data received from this SYNC plugin if their MAC addresses are already present.
|
||||
- It is recommended to use Device synchronization primarily. Plugin data synchronization is more suitable for specific use cases.
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -46,9 +46,9 @@
|
||||
]
|
||||
},
|
||||
|
||||
"default_value": "disabled",
|
||||
"options": [
|
||||
"disabled",
|
||||
"default_value": "unused",
|
||||
"options": [
|
||||
"unused",
|
||||
"once",
|
||||
"schedule",
|
||||
"always_after_scan",
|
||||
@@ -159,6 +159,81 @@
|
||||
"string": "Encryption key used to encrypt the data before sending and for decryption on the hub. The key needs to be the same on the hub and on the nodes."
|
||||
}
|
||||
]
|
||||
},{
|
||||
"function": "nodes",
|
||||
"type": {
|
||||
"dataType": "array",
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "input",
|
||||
"elementOptions": [
|
||||
{ "placeholder": "Enter full url" },
|
||||
{ "suffix": "_in" },
|
||||
{ "cssClasses": "col-sm-10" },
|
||||
{ "prefillValue": "null" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "button",
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": ["_in"] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-xs-12" },
|
||||
{ "onClick": "addList(this, false)" },
|
||||
{ "getStringKey": "Gen_Add" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "select",
|
||||
"elementHasInputValue": 1,
|
||||
"elementOptions": [
|
||||
{ "multiple": "true" },
|
||||
{ "readonly": "true" },
|
||||
{ "editable": "true" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "button",
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": [] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-xs-6" },
|
||||
{ "onClick": "removeAllOptions(this)" },
|
||||
{ "getStringKey": "Gen_Remove_All" }
|
||||
],
|
||||
"transformers": []
|
||||
},
|
||||
{
|
||||
"elementType": "button",
|
||||
"elementOptions": [
|
||||
{ "sourceSuffixes": [] },
|
||||
{ "separator": "" },
|
||||
{ "cssClasses": "col-xs-6" },
|
||||
{ "onClick": "removeFromList(this)" },
|
||||
{ "getStringKey": "Gen_Remove_Last" }
|
||||
],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"default_value": [],
|
||||
"options": [],
|
||||
"localized": ["name", "description"],
|
||||
"name": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "Nodes [h]"
|
||||
}
|
||||
],
|
||||
"description": [
|
||||
{
|
||||
"language_code": "en_us",
|
||||
"string": "If specified, the hub will pull Devices data from the listed nodes."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"function": "hub_url",
|
||||
@@ -246,7 +321,7 @@
|
||||
"elements": [
|
||||
{
|
||||
"elementType": "select",
|
||||
"elementOptions": [{ "multiple": "true" }],
|
||||
"elementOptions": [{ "multiple": "true", "ordeable": "true" }],
|
||||
"transformers": []
|
||||
}
|
||||
]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user