From c933376deb4231c10b28a3a7c31b94c6ef6f912f Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Sun, 24 May 2026 22:09:09 +1000 Subject: [PATCH] BE: SYNC API logging --- docs/SECURITY.md | 2 +- server/api_server/sync_endpoint.py | 106 +++++++++++++++++++++++------ server/utils/datetime_utils.py | 2 +- 3 files changed, 86 insertions(+), 24 deletions(-) diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 35612495..1d1d9a3d 100755 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -8,7 +8,7 @@ This includes (but is not limited to): - Running NetAlertX only on networks where you have legal authorization - Keeping your deployment up to date with the latest patches -> NetAlertX is not responsible for misuse, misconfiguration, or unsecure deployments. Always test and secure your setup before exposing it to the outside world. +> NetAlertX is not responsible for misuse, misconfiguration, or insecure deployments. Always test and secure your setup before exposing it to the outside world. Users interacting with the UI are treated as trusted actors within the deployment model. Always properly secure and isolate your deployment before exposing it externally. # 🔐 Securing Your NetAlertX Instance diff --git a/server/api_server/sync_endpoint.py b/server/api_server/sync_endpoint.py index fe086a2a..36c46840 100755 --- a/server/api_server/sync_endpoint.py +++ b/server/api_server/sync_endpoint.py @@ -47,40 +47,102 @@ def handle_sync_get(): def handle_sync_post(): """Handle POST requests for SYNC (HUB receiving from NODE).""" - body = request.get_json(silent=True) or {} + + mylog("verbose", [ + "[SYNC API] ENTER handle_sync_post", + f"method={request.method}", + f"content_type={request.content_type}", + f"content_length={request.content_length}", + f"remote_addr={request.remote_addr}" + ]) + + # ---- RAW BODY (critical for debugging encoding / encryption issues) + try: + raw = request.get_data(cache=False) + mylog("verbose", [ + f"[SYNC API] raw_bytes_len={len(raw)}", + f"[SYNC API] raw_preview={raw[:200]}" + ]) + except Exception as e: + mylog("none", [f"[SYNC API] FAILED reading raw body: {e}"]) + return jsonify({"error": "failed reading body"}), 400 + + # ---- JSON PARSE (this is a very common failure point) + try: + body = request.get_json(force=False, silent=False) + mylog("verbose", [f"[SYNC API] parsed_json={body}"]) + except Exception as e: + mylog("none", [f"[SYNC API] JSON_PARSE_FAILED={e}"]) + return jsonify({"error": "invalid json"}), 400 + + # ---- EXTRACT FIELDS data = body.get("data", "") node_name = body.get("node_name", "") plugin = body.get("plugin", "") + mylog("verbose", [ + f"[SYNC API] node_name={repr(node_name)}", + f"[SYNC API] plugin={repr(plugin)}", + f"[SYNC API] data_type={type(data).__name__}", + f"[SYNC API] data_len={len(data) if isinstance(data, str) else 'non-string'}" + ]) + storage_path = INSTALL_PATH + "/log/plugins" - os.makedirs(storage_path, exist_ok=True) - - encoded_files = [ - f - for f in os.listdir(storage_path) - if f.startswith(f"last_result.{plugin}.encoded.{node_name}") - ] - decoded_files = [ - f - for f in os.listdir(storage_path) - if f.startswith(f"last_result.{plugin}.decoded.{node_name}") - ] - file_count = len(encoded_files + decoded_files) + 1 - - file_path_new = os.path.join( - storage_path, f"last_result.{plugin}.encoded.{node_name}.{file_count}.log" - ) try: + os.makedirs(storage_path, exist_ok=True) + mylog("verbose", [f"[SYNC API] storage_path_ready={storage_path}"]) + except Exception as e: + mylog("none", [f"[SYNC API] MKDIR_FAILED={e}"]) + return jsonify({"error": "storage path error"}), 500 + + # ---- FILE COUNT LOGIC + try: + encoded_files = [ + f for f in os.listdir(storage_path) + if f.startswith(f"last_result.{plugin}.encoded.{node_name}") + ] + decoded_files = [ + f for f in os.listdir(storage_path) + if f.startswith(f"last_result.{plugin}.decoded.{node_name}") + ] + file_count = len(encoded_files + decoded_files) + 1 + + mylog("verbose", [ + f"[SYNC API] encoded_files={len(encoded_files)}", + f"[SYNC API] decoded_files={len(decoded_files)}", + f"[SYNC API] file_count={file_count}" + ]) + except Exception as e: + mylog("none", [f"[SYNC API] LISTDIR_FAILED={e}"]) + return jsonify({"error": "listdir failed"}), 500 + + # ---- FILE PATH + file_path_new = os.path.join( + storage_path, + f"last_result.{plugin}.encoded.{node_name}.{file_count}.log" + ) + + mylog("verbose", [f"[SYNC API] file_path_new={file_path_new}"]) + + # ---- WRITE FILE (final critical point) + try: + if not isinstance(data, str): + data = str(data) + with open(file_path_new, "w") as f: f.write(data) + except Exception as e: - msg = f"[Plugin: SYNC] Failed to store data: {e}" - write_notification(msg, "alert", timeNowUTC()) - mylog("verbose", [msg]) - return jsonify({"error": msg}), 500 + import traceback + mylog("none", [ + f"[SYNC API] WRITE_FAILED={e}", + traceback.format_exc() + ]) + return jsonify({"error": str(e)}), 500 msg = f"[Plugin: SYNC] Data received ({file_path_new})" write_notification(msg, "info", timeNowUTC()) mylog("verbose", [msg]) + return jsonify({"message": "Data received and stored successfully"}), 200 diff --git a/server/utils/datetime_utils.py b/server/utils/datetime_utils.py index 4366e7c0..d30238dc 100644 --- a/server/utils/datetime_utils.py +++ b/server/utils/datetime_utils.py @@ -6,7 +6,7 @@ import datetime import re import pytz from typing import Union, Optional -from zoneinfo import ZoneInfo, ZoneInfoNotFoundError +from zoneinfo import ZoneInfo import email.utils import conf # from const import *