From bdb9377061d3d4beafef4bbe346484fd969488d1 Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Sun, 4 Jan 2026 11:27:34 +1100 Subject: [PATCH] PLG: ICMP v2 #1331 Signed-off-by: jokob-sk --- Dockerfile | 2 +- Dockerfile.debian | 22 +- front/plugins/icmp_scan/config.json | 67 +++++- front/plugins/icmp_scan/icmp.py | 204 +++++++++++++----- .../debian12/install_dependencies.debian12.sh | 8 +- install/proxmox/proxmox-install-netalertx.sh | 24 +-- install/ubuntu24/install.sh | 30 +-- 7 files changed, 254 insertions(+), 103 deletions(-) diff --git a/Dockerfile b/Dockerfile index db48dca5..ae9af083 100755 --- a/Dockerfile +++ b/Dockerfile @@ -129,7 +129,7 @@ ENV NETALERTX_USER=netalertx NETALERTX_GROUP=netalertx ENV LANG=C.UTF-8 -RUN apk add --no-cache bash mtr libbsd zip lsblk tzdata curl arp-scan iproute2 iproute2-ss nmap \ +RUN apk add --no-cache bash mtr libbsd zip lsblk tzdata curl arp-scan iproute2 iproute2-ss nmap fping \ nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake ca-certificates \ sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session python3 envsubst \ nginx supercronic shadow && \ diff --git a/Dockerfile.debian b/Dockerfile.debian index 2bee1a34..d393cf9f 100755 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -4,7 +4,7 @@ # treat a container as an operating system, which is an anti-pattern and a common source of # security issues. # -# The default Dockerfile/docker-compose image contains the following security improvements +# The default Dockerfile/docker-compose image contains the following security improvements # over the Debian image: # - read-only filesystem # - no sudo access @@ -25,7 +25,7 @@ # - minimal base image (Alpine Linux) # - minimal python environment (venv, no pip) # - minimal stripped web server -# - minimal stripped php environment +# - minimal stripped php environment # - minimal services (nginx, php-fpm, crond, no unnecessary services or service managers) # - minimal users and groups (netalertx and readonly only, no others) # - minimal permissions (read-only for most files and folders, write-only for necessary folders) @@ -36,8 +36,8 @@ # - Uses the same services as the development environment (nginx, php-fpm, crond) # - Uses the same environment variables as the development environment (only necessary ones, no others) # - Uses the same file and folder structure as the development environment (only necessary ones, no others) -# NetAlertX is designed to be run as an unattended network security monitoring appliance, which means it -# should be able to operate without human intervention. Overall, the hardened image is designed to be as +# NetAlertX is designed to be run as an unattended network security monitoring appliance, which means it +# should be able to operate without human intervention. Overall, the hardened image is designed to be as # secure as possible while still being functional and is recommended because you cannot attack a surface # that isn't there. @@ -92,7 +92,7 @@ ENV PHP_FPM_CONFIG_FILE=${SYSTEM_SERVICES_PHP_FOLDER}/php-fpm.conf #Python environment ENV PYTHONPATH=${NETALERTX_SERVER} -ENV PYTHONUNBUFFERED=1 +ENV PYTHONUNBUFFERED=1 ENV VIRTUAL_ENV=/opt/venv ENV VIRTUAL_ENV_BIN=/opt/venv/bin ENV PATH="${VIRTUAL_ENV}/bin:${PATH}:/services" @@ -107,9 +107,9 @@ ENV NETALERTX_DEBUG=0 #Container environment ENV ENVIRONMENT=debian -ENV USER=netalertx +ENV USER=netalertx ENV USER_ID=1000 -ENV USER_GID=1000 +ENV USER_GID=1000 # Todo, figure out why using a workdir instead of full paths don't work # Todo, do we still need all these packages? I can already see sudo which isn't needed @@ -127,16 +127,16 @@ RUN groupadd --gid "${USER_GID}" "${USER}" && \ usermod -a -G ${USER_GID} root && \ usermod -a -G ${USER_GID} www-data -COPY --chmod=775 --chown=${USER_ID}:${USER_GID} install/production-filesystem/ / +COPY --chmod=775 --chown=${USER_ID}:${USER_GID} install/production-filesystem/ / COPY --chmod=775 --chown=${USER_ID}:${USER_GID} . ${INSTALL_DIR}/ -# ❗ IMPORTANT - if you modify this file modify the /install/install_dependecies.debian.sh file as well ❗ +# ❗ IMPORTANT - if you modify this file modify the /install/install_dependecies.debian.sh file as well ❗ # hadolint ignore=DL3008,DL3027 RUN apt-get update && apt-get install -y --no-install-recommends \ tini snmp ca-certificates curl libwww-perl arp-scan sudo gettext-base \ - nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools \ - python3 python3-dev iproute2 nmap python3-pip zip git systemctl usbutils traceroute nbtscan openrc \ + nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools \ + python3 python3-dev iproute2 nmap fping python3-pip zip git systemctl usbutils traceroute nbtscan openrc \ busybox nginx nginx-core mtr python3-venv && \ rm -rf /var/lib/apt/lists/* diff --git a/front/plugins/icmp_scan/config.json b/front/plugins/icmp_scan/config.json index d96a4a7a..aa37c875 100755 --- a/front/plugins/icmp_scan/config.json +++ b/front/plugins/icmp_scan/config.json @@ -75,6 +75,34 @@ } ] }, + { + "function": "MODE", + "events": ["run"], + "type": { + "dataType": "string", + "elements": [ + { "elementType": "select", "elementOptions": [], "transformers": [] } + ] + }, + "default_value": "ping", + "options": [ + "ping", + "fping" + ], + "localized": ["name", "description"], + "name": [ + { + "language_code": "en_us", + "string": "Mode" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "Selects the ICMP engine to use. ping checks devices individually and works even when the ARP / neighbor cache is empty, but is slower on larger networks. fping scans IP ranges in parallel and is significantly faster, but relies on the system neighbor cache to resolve IP addresses to MAC addresses. For most networks, fping is recommended. The default command arguments ICMP_ARGS are compatible with both modes." + } + ] + }, { "function": "CMD", "type": { @@ -115,7 +143,7 @@ } ] }, - "default_value": "-i 0.5 -c 3 -W 4 -w 5", + "default_value": "-i 0.5 -c 3 -w 5", "options": [], "localized": ["name", "description"], "name": [ @@ -127,7 +155,7 @@ "description": [ { "language_code": "en_us", - "string": "Arguments passed to the ping command. Please be careful modifying these." + "string": "Arguments passed to the underlying ping or fping command. The default values are compatible with both modes and work well in most environments. Modify with care, and consult the relevant manual pages if advanced tuning is required." } ] }, @@ -159,6 +187,41 @@ } ] }, + { + "function": "FAKE_MAC", + "type": { + "dataType": "boolean", + "elements": [ + { + "elementType": "input", + "elementOptions": [ + { + "type": "checkbox" + } + ], + "transformers": [] + } + ] + }, + "default_value": false, + "options": [], + "localized": [ + "name", + "description" + ], + "name": [ + { + "language_code": "en_us", + "string": "Fake MAC" + } + ], + "description": [ + { + "language_code": "en_us", + "string": "If enabled and the mode is set to fping, the plugin will also discover new devices not already in the database. Enabling this setting generates a fake MAC address from the IP address to track devices. This may cause inconsistencies if IPs change or devices are re-discovered with a different MAC. Static IPs are recommended. Device type and icon might not be detected correctly, and some plugins may fail if they rely on a valid MAC address. When unchecked, devices without a MAC address are skipped." + } + ] + }, { "function": "RUN_SCHD", "type": { diff --git a/front/plugins/icmp_scan/icmp.py b/front/plugins/icmp_scan/icmp.py index 3e2a2664..c98db91b 100755 --- a/front/plugins/icmp_scan/icmp.py +++ b/front/plugins/icmp_scan/icmp.py @@ -16,6 +16,7 @@ from logger import mylog, Logger # noqa: E402 [flake8 lint suppression] from helper import get_setting_value # noqa: E402 [flake8 lint suppression] from const import logPath # noqa: E402 [flake8 lint suppression] from models.device_instance import DeviceInstance # noqa: E402 [flake8 lint suppression] +from utils.crypto_utils import string_to_mac_hash # noqa: E402 [flake8 lint suppression] import conf # noqa: E402 [flake8 lint suppression] from pytz import timezone # noqa: E402 [flake8 lint suppression] @@ -32,13 +33,39 @@ LOG_FILE = os.path.join(LOG_PATH, f'script.{pluginName}.log') RESULT_FILE = os.path.join(LOG_PATH, f'last_result.{pluginName}.log') +def parse_scan_subnets(subnets): + """Extract subnet and interface from SCAN_SUBNETS""" + ranges = [] + interfaces = [] + for entry in subnets: + parts = entry.split("--interface=") + ranges.append(parts[0].strip()) + if len(parts) > 1: + interfaces.append(parts[1].strip()) + return ranges, interfaces + + +def get_device_by_ip(ip, all_devices): + """Get existing device based on IP""" + for device in all_devices: + if device["devLastIP"] == ip: + return device + + return None + + def main(): mylog('verbose', [f'[{pluginName}] In script']) timeout = get_setting_value('ICMP_RUN_TIMEOUT') args = get_setting_value('ICMP_ARGS') - in_regex = get_setting_value('ICMP_IN_REGEX') + regex = get_setting_value('ICMP_IN_REGEX') + mode = get_setting_value('ICMP_MODE') + fakeMac = get_setting_value('ICMP_FAKE_MAC') + scan_subnets = get_setting_value("SCAN_SUBNETS") + + subnets, interfaces = parse_scan_subnets(scan_subnets) # Initialize the Plugin obj output file plugin_objects = Plugin_Objects(RESULT_FILE) @@ -50,33 +77,13 @@ def main(): all_devices = device_handler.getAll() # Compile the regex for efficiency if it will be used multiple times - regex_pattern = re.compile(in_regex) + regex_pattern = re.compile(regex) - # Filter devices based on the regex match - filtered_devices = [ - device for device in all_devices - if regex_pattern.match(device['devLastIP']) - ] + if mode == "ping": + plugin_objects = execute_ping(timeout, args, all_devices, regex_pattern, plugin_objects) - mylog('verbose', [f'[{pluginName}] Devices to PING: {len(filtered_devices)}']) - - for device in filtered_devices: - is_online, output = execute_scan(device['devLastIP'], timeout, args) - - mylog('verbose', [f"[{pluginName}] ip: {device['devLastIP']} is_online: {is_online}"]) - - if is_online: - plugin_objects.add_object( - # "MAC", "IP", "Name", "Output" - primaryId = device['devMac'], - secondaryId = device['devLastIP'], - watched1 = device['devName'], - watched2 = output.replace('\n', ''), - watched3 = '', - watched4 = '', - extra = '', - foreignKey = device['devMac'] - ) + elif mode == "fping": + plugin_objects = execute_fping(timeout, args, all_devices, plugin_objects, subnets, interfaces, fakeMac) plugin_objects.write_result_file() @@ -88,27 +95,24 @@ def main(): # =============================================================================== # Execute scan # =============================================================================== -def execute_scan(ip, timeout, args): +def execute_ping(timeout, args, all_devices, regex_pattern, plugin_objects): """ - Execute the ICMP command on IP. + Execute ICMP command on filtered devices. """ - icmp_args = ['ping'] + args.split() + [ip] + # Filter devices based on the regex match + filtered_devices = [ + device for device in all_devices + if regex_pattern.match(device['devLastIP']) + ] - # Execute command - output = "" + mylog('verbose', [f'[{pluginName}] Devices to PING: {len(filtered_devices)}']) - try: - # try runnning a subprocess with a forced (timeout) in case the subprocess hangs - output = subprocess.check_output( - icmp_args, - universal_newlines=True, - stderr=subprocess.STDOUT, - timeout=(timeout), - text=True - ) + for device in filtered_devices: - mylog('verbose', [f'[{pluginName}] DEBUG OUTPUT : {output}']) + cmd = ["ping"] + args.split() + [device['devLastIP']] + + output = "" # Parse output using case-insensitive regular expressions # Synology-NAS:/# ping -i 0.5 -c 3 -W 8 -w 9 192.168.1.82 @@ -128,31 +132,115 @@ def execute_scan(ip, timeout, args): # --- 192.168.1.92 ping statistics --- # 3 packets transmitted, 0 packets received, 100% packet loss - # TODO: parse output and return True if online, False if Offline (100% packet loss, bad address) - is_online = True + try: + output = subprocess.check_output( + cmd, universal_newlines=True, stderr=subprocess.STDOUT, timeout=timeout, text=True + ) + + mylog("verbose", [f"[{pluginName}] DEBUG OUTPUT : {output}"]) - # Check for 0% packet loss in the output - if re.search(r"0% packet loss", output, re.IGNORECASE): is_online = True - elif re.search(r"bad address", output, re.IGNORECASE): - is_online = False - elif re.search(r"100% packet loss", output, re.IGNORECASE): - is_online = False + if re.search(r"0% packet loss", output, re.IGNORECASE): + is_online = True + elif re.search(r"bad address", output, re.IGNORECASE): + is_online = False + elif re.search(r"100% packet loss", output, re.IGNORECASE): + is_online = False - return is_online, output + if is_online: - except subprocess.CalledProcessError as e: - # An error occurred, handle it - mylog('verbose', [f'[{pluginName}] ⚠ ERROR - check logs']) - mylog('verbose', [f'[{pluginName}]', e.output]) + plugin_objects.add_object( + # "MAC", "IP", "Name", "Output" + primaryId = device['devMac'], + secondaryId = device['devLastIP'], + watched1 = device['devName'], + watched2 = output.replace('\n', ''), + watched3 = '', + watched4 = '', + extra = '', + foreignKey = device['devMac'] + ) - return False, output + mylog('verbose', [f"[{pluginName}] ip: {device['devLastIP']} is_online: {is_online}"]) + + except subprocess.CalledProcessError as e: + mylog("verbose", [f"[{pluginName}] ⚠ ERROR - check logs"]) + mylog("verbose", [f"[{pluginName}]", e.output]) + except subprocess.TimeoutExpired: + mylog("verbose", [f"[{pluginName}] TIMEOUT - process terminated"]) + + return plugin_objects + + +def execute_fping(timeout, args, all_devices, plugin_objects, subnets, interfaces, fakeMac): + """ + Run fping command and return alive IPs + """ + cmd = ["fping", "-a"] + + if interfaces: + cmd += ["-I", ",".join(interfaces)] + + # Build a lookup dict once + device_map = {d["devLastIP"]: d for d in all_devices if d.get("devLastIP")} + + known_ips = list(device_map.keys()) + online_ips = [] + + cmd += args.split() + cmd += subnets + cmd += known_ips + + mylog("verbose", [f"[{pluginName}] fping cmd: {' '.join(cmd)}"]) + + try: + output = subprocess.check_output( + cmd, + stderr=subprocess.DEVNULL, + timeout=timeout, + text=True + ) + online_ips = [line.strip() for line in output.splitlines() if line.strip()] + + except subprocess.CalledProcessError: + online_ips = [] except subprocess.TimeoutExpired: - mylog('verbose', [f'[{pluginName}] TIMEOUT - the process forcefully terminated as timeout reached']) - return False, output + mylog("verbose", [f"[{pluginName}] fping timeout"]) + online_ips = [] - return False, output + # process all online IPs + for onlineIp in online_ips: + if onlineIp in known_ips: + # use lookup dict instead of looping + device = device_map.get(onlineIp) + if device: + plugin_objects.add_object( + primaryId = device['devMac'], + secondaryId = device['devLastIP'], + watched1 = device['devName'], + watched2 = 'mode:fping', + watched3 = '', + watched4 = '', + extra = '', + foreignKey = device['devMac'] + ) + else: + mylog("none", [f"[{pluginName}] ERROR reverse device lookup failed unexpectedly for {onlineIp}"]) + elif fakeMac: + fakeMacFromIp = string_to_mac_hash(onlineIp) + plugin_objects.add_object( + primaryId = fakeMacFromIp, + secondaryId = onlineIp, + watched1 = "(unknown)", + watched2 = 'mode:fping', + watched3 = '', + watched4 = '', + extra = '', + foreignKey = fakeMacFromIp + ) + else: + mylog('verbose', [f"[{pluginName}] Skipping: {onlineIp}, as new IP and ICMP_FAKE_MAC setting not enabled"]) # =============================================================================== diff --git a/install/debian12/install_dependencies.debian12.sh b/install/debian12/install_dependencies.debian12.sh index 5fb09738..0f0b66d5 100755 --- a/install/debian12/install_dependencies.debian12.sh +++ b/install/debian12/install_dependencies.debian12.sh @@ -17,19 +17,19 @@ fi # Check if script is run as root if [[ $EUID -ne 0 ]]; then - echo "This script must be run as root. Please use 'sudo'." + echo "This script must be run as root. Please use 'sudo'." exit 1 fi # Install dependencies apt-get install -y \ tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo gettext-base \ - nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools \ - python3 python3-dev iproute2 nmap python3-pip zip usbutils traceroute nbtscan avahi-daemon avahi-utils openrc build-essential git + nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools \ + python3 python3-dev iproute2 nmap fping python3-pip zip usbutils traceroute nbtscan avahi-daemon avahi-utils openrc build-essential git # alternate dependencies sudo apt-get install nginx nginx-core mtr php-fpm php8.2-fpm php-cli php8.2 php8.2-sqlite3 -y -sudo phpenmod -v 8.2 sqlite3 +sudo phpenmod -v 8.2 sqlite3 # setup virtual python environment so we can use pip3 to install packages apt-get install python3-venv -y diff --git a/install/proxmox/proxmox-install-netalertx.sh b/install/proxmox/proxmox-install-netalertx.sh index a1ed372e..64c3872e 100755 --- a/install/proxmox/proxmox-install-netalertx.sh +++ b/install/proxmox/proxmox-install-netalertx.sh @@ -9,7 +9,7 @@ set -o pipefail # Safe IFS IFS=$' \t\n' -# 🛑 Important: This is only used for the bare-metal install 🛑 +# 🛑 Important: This is only used for the bare-metal install 🛑 # Colors (guarded) if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then RESET='\e[0m' @@ -37,13 +37,13 @@ DB_FILE=app.db NGINX_CONF_FILE=netalertx.conf WEB_UI_DIR=/var/www/html/netalertx NGINX_CONFIG=/etc/nginx/conf.d/$NGINX_CONF_FILE -OUI_FILE="/usr/share/arp-scan/ieee-oui.txt" +OUI_FILE="/usr/share/arp-scan/ieee-oui.txt" FILEDB=$INSTALL_DIR/db/$DB_FILE -# DO NOT CHANGE ANYTHING ABOVE THIS LINE! +# DO NOT CHANGE ANYTHING ABOVE THIS LINE! # Check if script is run as root if [[ $EUID -ne 0 ]]; then - echo "This script must be run as root." + echo "This script must be run as root." exit 1 fi @@ -51,7 +51,7 @@ fi if [ -z "${NETALERTX_ASSUME_YES:-}" ] && [ -z "${ASSUME_YES:-}" ] && [ -z "${NETALERTX_FORCE:-}" ]; then printf "%b\n" "------------------------------------------------------------------------" printf "%b\n" "${RED}[WARNING] ${RESET}This script should be run on a fresh server" - printf "%b\n" "${RED}[WARNING] ${RESET}This script will install NetAlertX and will:" + printf "%b\n" "${RED}[WARNING] ${RESET}This script will install NetAlertX and will:" printf "%b\n" "${RED}[WARNING] ${RESET}• Update OS with apt-get update/upgrade" printf "%b\n" "${RED}[WARNING] ${RESET}• Overwrite existing files under ${INSTALL_DIR} " printf "%b\n" "${RED}[WARNING] ${RESET}• Wipe any existing database" @@ -137,7 +137,7 @@ printf "%b\n" "----------------------------------------------------------------- printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Detected OS: ${OS_ID} ${OS_VER}" printf "%b\n" "--------------------------------------------------------------------------" -if +if [ "${OS_ID}" = "ubuntu" ] && printf '%s' "${OS_VER}" | grep -q '^24'; then # Ubuntu 24.x typically ships PHP 8.3; add ondrej/php PPA and set 8.4 printf "%b\n" "--------------------------------------------------------------------------" @@ -152,15 +152,15 @@ elif printf "%b\n" "${GREEN}[INSTALLING] ${RESET}Debian 13 detected - using built-in PHP 8.4" printf "%b\n" "--------------------------------------------------------------------------" fi - + apt-get install -y --no-install-recommends \ tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo \ php8.4 php8.4-cgi php8.4-fpm php8.4-sqlite3 php8.4-curl sqlite3 dnsutils net-tools mtr \ - python3 python3-dev iproute2 nmap python3-pip zip usbutils traceroute nbtscan \ + python3 python3-dev iproute2 nmap fping python3-pip zip usbutils traceroute nbtscan \ avahi-daemon avahi-utils build-essential git gnupg2 lsb-release \ debian-archive-keyring python3-venv -if +if [ "${OS_ID}" = "ubuntu" ] && printf '%s' "${OS_VER}" | grep -q '^24'; then # Set PHP 8.4 as the default alternatives where applicable update-alternatives --set php /usr/bin/php8.4 || true systemctl enable php8.4-fpm || true @@ -211,7 +211,7 @@ source /opt/myenv/bin/activate python -m pip install --upgrade pip python -m pip install -r "${INSTALLER_DIR}/requirements.txt" -# Backup default NGINX site just in case +# Backup default NGINX site just in case if [ -L /etc/nginx/sites-enabled/default ] ; then rm /etc/nginx/sites-enabled/default elif [ -f /etc/nginx/sites-enabled/default ]; then @@ -350,7 +350,7 @@ printf "%b\n" "----------------------------------------------------------------- printf "%b\n" "${GREEN}[STARTING] ${RESET}Starting PHP and NGINX" printf "%b\n" "--------------------------------------------------------------------------" /etc/init.d/php8.4-fpm start -nginx -t || { +nginx -t || { printf "%b\n" "--------------------------------------------------------------------------" printf "%b\n" "${RED}[ERROR] ${RESET}NGINX config test failed!" printf "%b\n" "--------------------------------------------------------------------------"; exit 1; } @@ -405,7 +405,7 @@ systemctl daemon-reload systemctl enable netalertx.service systemctl start netalertx.service systemctl restart nginx - + # Verify service is running if systemctl is-active --quiet netalertx.service; then printf "%b\n" "--------------------------------------------------------------------------" diff --git a/install/ubuntu24/install.sh b/install/ubuntu24/install.sh index e934ee24..20eec65f 100755 --- a/install/ubuntu24/install.sh +++ b/install/ubuntu24/install.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# 🛑 Important: This is only used for the bare-metal install 🛑 +# 🛑 Important: This is only used for the bare-metal install 🛑 echo "---------------------------------------------------------" echo "[INSTALL] Starting NetAlertX installation for Ubuntu" @@ -34,7 +34,7 @@ ALWAYS_FRESH_INSTALL=false # Set to true to always reset /config and /db on eac # Check if script is run as root if [[ $EUID -ne 0 ]]; then - echo "[INSTALL] This script must be run as root. Please use 'sudo'." + echo "[INSTALL] This script must be run as root. Please use 'sudo'." exit 1 fi @@ -62,7 +62,7 @@ apt-get install -y --no-install-recommends \ # Install plugin dependencies apt-get install -y --no-install-recommends \ - dnsutils mtr arp-scan snmp iproute2 nmap zip usbutils traceroute nbtscan avahi-daemon avahi-utils + dnsutils mtr arp-scan snmp iproute2 nmap fping zip usbutils traceroute nbtscan avahi-daemon avahi-utils # nginx-core install nginx and nginx-common as dependencies apt-get install -y --no-install-recommends \ @@ -156,14 +156,14 @@ python3 -m venv "${VENV_DIR}" source "${VENV_DIR}/bin/activate" if [[ ! -f "${REQUIREMENTS_FILE}" ]]; then - echo "[INSTALL] requirements.txt not found at ${REQUIREMENTS_FILE}" - exit 1 + echo "[INSTALL] requirements.txt not found at ${REQUIREMENTS_FILE}" + exit 1 fi -pip3 install -r "${REQUIREMENTS_FILE}" || { - echo "[INSTALL] Failed to install Python dependencies" - exit 1 -} +pip3 install -r "${REQUIREMENTS_FILE}" || { + echo "[INSTALL] Failed to install Python dependencies" + exit 1 +} # We now should have all dependencies and files in place @@ -179,11 +179,11 @@ fi # if custom variables not set we do not need to do anything -if [ -n "${TZ}" ]; then - FILECONF=${INSTALL_DIR}/config/${CONF_FILE} +if [ -n "${TZ}" ]; then + FILECONF=${INSTALL_DIR}/config/${CONF_FILE} if [ -f "$FILECONF" ]; then sed -i -e "s|Europe/Berlin|${TZ}|g" "${INSTALL_DIR}/config/${CONF_FILE}" - else + else sed -i -e "s|Europe/Berlin|${TZ}|g" "${INSTALL_DIR}/back/${CONF_FILE}.bak" fi fi @@ -253,7 +253,7 @@ else if [ -f "${SYSTEM_SERVICES}/update_vendors.sh" ]; then "${SYSTEM_SERVICES}/update_vendors.sh" else - echo "[INSTALL] update_vendors.sh script not found in ${SYSTEM_SERVICES}." + echo "[INSTALL] update_vendors.sh script not found in ${SYSTEM_SERVICES}." fi fi @@ -282,12 +282,12 @@ touch "${INSTALL_DIR}"/api/user_notifications.json mkdir -p "${INSTALL_DIR}"/log/plugins -# DANGER ZONE: ALWAYS_FRESH_INSTALL +# DANGER ZONE: ALWAYS_FRESH_INSTALL if [ "${ALWAYS_FRESH_INSTALL}" = true ]; then echo "[INSTALL] ❗ ALERT /db and /config folders are cleared because the ALWAYS_FRESH_INSTALL is set to: ${ALWAYS_FRESH_INSTALL}❗" # Delete content of "/config/" rm -rf "${INSTALL_DIR}/config/"* - + # Delete content of "/db/" rm -rf "${INSTALL_DIR}/db/"* fi