Spaces:
Sleeping
Sleeping
Commit
·
d58a19f
1
Parent(s):
5182442
Docker added
Browse files- backend/Dockerfile +29 -0
- backend/app.py +27 -34
- backend/requirements.txt +4 -1
backend/Dockerfile
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 1. Use a standard Python image
|
| 2 |
+
FROM python:3.9-slim
|
| 3 |
+
|
| 4 |
+
# 2. Install system-level tools needed for Scapy and Network monitoring
|
| 5 |
+
RUN apt-get update && apt-get install -y \
|
| 6 |
+
libpcap-dev \
|
| 7 |
+
gcc \
|
| 8 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 9 |
+
|
| 10 |
+
# 3. Create a non-root user for security (Hugging Face requirement)
|
| 11 |
+
RUN useradd -m -u 1000 user
|
| 12 |
+
USER user
|
| 13 |
+
ENV PATH="/home/user/.local/bin:${PATH}"
|
| 14 |
+
|
| 15 |
+
# 4. Set the working directory
|
| 16 |
+
WORKDIR /home/user/app
|
| 17 |
+
|
| 18 |
+
# 5. Copy and install requirements
|
| 19 |
+
COPY --chown=user requirements.txt .
|
| 20 |
+
RUN pip install --no-cache-dir --user -r requirements.txt
|
| 21 |
+
|
| 22 |
+
# 6. Copy the rest of your code
|
| 23 |
+
COPY --chown=user . .
|
| 24 |
+
|
| 25 |
+
# 7. Hugging Face uses port 7860 by default
|
| 26 |
+
EXPOSE 7860
|
| 27 |
+
|
| 28 |
+
# 8. Start the server using Gunicorn + Eventlet (Best for SocketIO)
|
| 29 |
+
CMD ["gunicorn", "--worker-class", "eventlet", "-w", "1", "--bind", "0.0.0.0:7860", "app:app"]
|
backend/app.py
CHANGED
|
@@ -1,64 +1,57 @@
|
|
| 1 |
-
# =============================================================
|
| 2 |
-
# FILE: app.py
|
| 3 |
-
# Optimized Flask + SocketIO entry (threading mode, no debug)
|
| 4 |
-
# =============================================================
|
| 5 |
import logging
|
| 6 |
from flask import Flask, jsonify
|
| 7 |
from flask_cors import CORS
|
| 8 |
from flask_socketio import SocketIO
|
| 9 |
-
import os
|
| 10 |
-
|
| 11 |
|
| 12 |
# lightweight logging
|
| 13 |
logging.getLogger('werkzeug').setLevel(logging.ERROR)
|
| 14 |
logging.getLogger('socketio').setLevel(logging.ERROR)
|
| 15 |
|
| 16 |
-
|
| 17 |
app = Flask(__name__)
|
| 18 |
-
CORS(app, resources={r"/api/*": {"origins": "*"}})
|
| 19 |
|
|
|
|
|
|
|
| 20 |
|
| 21 |
-
# Use threading mode to avoid eventlet monkey-patch issues with Scapy/IO
|
| 22 |
socketio = SocketIO(app, cors_allowed_origins="*", async_mode="threading")
|
| 23 |
|
| 24 |
-
|
| 25 |
-
# Mail initialization is left as-is but keep credentials out of source in production
|
| 26 |
try:
|
| 27 |
from extensions import mail
|
| 28 |
app.config.update(
|
| 29 |
MAIL_SERVER="smtp.gmail.com",
|
| 30 |
MAIL_PORT=587,
|
| 31 |
MAIL_USE_TLS=True,
|
| 32 |
-
# --- SECURITY FIX: Fetch credentials from environment variables ---
|
| 33 |
MAIL_USERNAME=os.environ.get("MAIL_USERNAME"),
|
| 34 |
MAIL_PASSWORD=os.environ.get("MAIL_PASSWORD"),
|
| 35 |
-
# -----------------------------------------------------------------
|
| 36 |
MAIL_DEFAULT_SENDER=("Adaptive AI NIDS", os.environ.get("MAIL_USERNAME"))
|
| 37 |
)
|
| 38 |
mail.init_app(app)
|
| 39 |
-
|
| 40 |
except Exception:
|
| 41 |
-
# If mail is not available in dev/test, continue gracefully
|
| 42 |
pass
|
| 43 |
|
| 44 |
-
|
| 45 |
-
# lazy import of sniffer so import side-effects are minimal
|
| 46 |
sniffer = None
|
| 47 |
|
| 48 |
-
|
| 49 |
def _get_sniffer():
|
| 50 |
global sniffer
|
| 51 |
if sniffer is None:
|
| 52 |
-
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
return sniffer
|
| 55 |
|
| 56 |
-
|
| 57 |
-
# Register blueprints lazily to avoid heavy imports at startup
|
| 58 |
def register_blueprints(app):
|
| 59 |
from importlib import import_module
|
| 60 |
-
|
| 61 |
-
|
| 62 |
routes = [
|
| 63 |
("routes.live_route", "live_bp", "/api/live"),
|
| 64 |
("routes.logs_route", "logs_bp", "/api/logs"),
|
|
@@ -83,26 +76,26 @@ def register_blueprints(app):
|
|
| 83 |
bp = getattr(mod, varname)
|
| 84 |
app.register_blueprint(bp, url_prefix=prefix)
|
| 85 |
print(f"✅ Registered route: {module_name} -> {prefix}")
|
| 86 |
-
|
| 87 |
except Exception as e:
|
| 88 |
print(f"⚠️ Skipping {module_name}: {e}")
|
| 89 |
|
| 90 |
register_blueprints(app)
|
| 91 |
|
| 92 |
-
|
| 93 |
@app.route("/")
|
| 94 |
def home():
|
|
|
|
|
|
|
| 95 |
s = _get_sniffer()
|
|
|
|
| 96 |
return jsonify({
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
|
|
|
|
|
|
| 100 |
})
|
| 101 |
|
| 102 |
-
|
| 103 |
-
# --- REMOVED: The local run block is removed. Gunicorn will handle startup on Render. ---
|
| 104 |
if __name__ == "__main__":
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
socketio.run(app, host="0.0.0.0", port=5000, debug=False)
|
| 108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import logging
|
| 2 |
from flask import Flask, jsonify
|
| 3 |
from flask_cors import CORS
|
| 4 |
from flask_socketio import SocketIO
|
| 5 |
+
import os
|
| 6 |
+
import socket
|
| 7 |
|
| 8 |
# lightweight logging
|
| 9 |
logging.getLogger('werkzeug').setLevel(logging.ERROR)
|
| 10 |
logging.getLogger('socketio').setLevel(logging.ERROR)
|
| 11 |
|
|
|
|
| 12 |
app = Flask(__name__)
|
|
|
|
| 13 |
|
| 14 |
+
# UPDATED: More robust CORS for deployment
|
| 15 |
+
CORS(app, resources={r"/api/*": {"origins": "*"}})
|
| 16 |
|
|
|
|
| 17 |
socketio = SocketIO(app, cors_allowed_origins="*", async_mode="threading")
|
| 18 |
|
| 19 |
+
# Mail initialization
|
|
|
|
| 20 |
try:
|
| 21 |
from extensions import mail
|
| 22 |
app.config.update(
|
| 23 |
MAIL_SERVER="smtp.gmail.com",
|
| 24 |
MAIL_PORT=587,
|
| 25 |
MAIL_USE_TLS=True,
|
|
|
|
| 26 |
MAIL_USERNAME=os.environ.get("MAIL_USERNAME"),
|
| 27 |
MAIL_PASSWORD=os.environ.get("MAIL_PASSWORD"),
|
|
|
|
| 28 |
MAIL_DEFAULT_SENDER=("Adaptive AI NIDS", os.environ.get("MAIL_USERNAME"))
|
| 29 |
)
|
| 30 |
mail.init_app(app)
|
|
|
|
| 31 |
except Exception:
|
|
|
|
| 32 |
pass
|
| 33 |
|
|
|
|
|
|
|
| 34 |
sniffer = None
|
| 35 |
|
|
|
|
| 36 |
def _get_sniffer():
|
| 37 |
global sniffer
|
| 38 |
if sniffer is None:
|
| 39 |
+
try:
|
| 40 |
+
# CLOUD GUARD: Don't import sniffer if on a cloud server that blocks raw sockets
|
| 41 |
+
# Render and Hugging Face usually set specific env variables
|
| 42 |
+
if os.environ.get("RENDER") or os.environ.get("SPACE_ID"):
|
| 43 |
+
print("⚠️ Cloud environment detected. Skipping sniffer initialization.")
|
| 44 |
+
return None
|
| 45 |
+
|
| 46 |
+
from capture.live_manager import sniffer as _s
|
| 47 |
+
sniffer = _s
|
| 48 |
+
except Exception as e:
|
| 49 |
+
print(f"⚠️ Could not initialize sniffer: {e}")
|
| 50 |
+
return None
|
| 51 |
return sniffer
|
| 52 |
|
|
|
|
|
|
|
| 53 |
def register_blueprints(app):
|
| 54 |
from importlib import import_module
|
|
|
|
|
|
|
| 55 |
routes = [
|
| 56 |
("routes.live_route", "live_bp", "/api/live"),
|
| 57 |
("routes.logs_route", "logs_bp", "/api/logs"),
|
|
|
|
| 76 |
bp = getattr(mod, varname)
|
| 77 |
app.register_blueprint(bp, url_prefix=prefix)
|
| 78 |
print(f"✅ Registered route: {module_name} -> {prefix}")
|
|
|
|
| 79 |
except Exception as e:
|
| 80 |
print(f"⚠️ Skipping {module_name}: {e}")
|
| 81 |
|
| 82 |
register_blueprints(app)
|
| 83 |
|
|
|
|
| 84 |
@app.route("/")
|
| 85 |
def home():
|
| 86 |
+
# Detect environment for frontend awareness
|
| 87 |
+
is_cloud = os.environ.get("RENDER") or os.environ.get("SPACE_ID")
|
| 88 |
s = _get_sniffer()
|
| 89 |
+
|
| 90 |
return jsonify({
|
| 91 |
+
"status": "✅ Backend Active",
|
| 92 |
+
"env": "cloud" if is_cloud else "local",
|
| 93 |
+
"capture_capability": "limited" if is_cloud else "full",
|
| 94 |
+
"capture_running": s.is_running() if s else False,
|
| 95 |
+
"tip": "Live sniffing requires local deployment."
|
| 96 |
})
|
| 97 |
|
|
|
|
|
|
|
| 98 |
if __name__ == "__main__":
|
| 99 |
+
print("🚀 Starting Adaptive AI NIDS Backend...")
|
| 100 |
+
socketio.run(app, host="0.0.0.0", port=5000, debug=False)
|
|
|
|
| 101 |
|
backend/requirements.txt
CHANGED
|
@@ -39,4 +39,7 @@ Flask-SocketIO
|
|
| 39 |
fpdf
|
| 40 |
requests
|
| 41 |
psutil
|
| 42 |
-
groq
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
fpdf
|
| 40 |
requests
|
| 41 |
psutil
|
| 42 |
+
groq
|
| 43 |
+
gunicorn
|
| 44 |
+
eventlet
|
| 45 |
+
huggingface_hub
|