Replace monolithic CLI and web server with route-based Flask API. New routes: api_commands, api_build, api_can, api_monitor, api_ota, api_tunnel. Add honeypot security dashboard with real-time SSE, MITRE ATT&CK mapping, kill chain analysis. New TUI with commander/help modules. Add session management, tunnel proxy core, CAN bus data store. Docker support.
126 lines
4.0 KiB
Python
126 lines
4.0 KiB
Python
"""Configuration loader for camera server module - reads from .env file."""
|
|
|
|
import os
|
|
import sys
|
|
import warnings
|
|
from pathlib import Path
|
|
from dotenv import load_dotenv
|
|
|
|
# Load .env file from c2 root directory
|
|
C2_ROOT = Path(__file__).parent.parent
|
|
ENV_FILE = C2_ROOT / ".env"
|
|
|
|
_ENV_LOADED = False
|
|
if ENV_FILE.exists():
|
|
load_dotenv(ENV_FILE)
|
|
_ENV_LOADED = True
|
|
else:
|
|
# Try .env.example as fallback for development
|
|
example_env = C2_ROOT / ".env.example"
|
|
if example_env.exists():
|
|
load_dotenv(example_env)
|
|
warnings.warn(
|
|
"No .env file found — loaded .env.example defaults. "
|
|
"Copy .env.example to .env and set secure values before production use.",
|
|
stacklevel=2,
|
|
)
|
|
|
|
|
|
def _get_bool(key: str, default: bool = False) -> bool:
|
|
"""Get boolean value from environment."""
|
|
val = os.getenv(key, str(default)).lower()
|
|
return val in ("true", "1", "yes", "on")
|
|
|
|
|
|
def _get_int(key: str, default: int) -> int:
|
|
"""Get integer value from environment."""
|
|
try:
|
|
return int(os.getenv(key, default))
|
|
except ValueError:
|
|
return default
|
|
|
|
|
|
# C2 Server
|
|
C2_HOST = os.getenv("C2_HOST", "0.0.0.0")
|
|
C2_PORT = _get_int("C2_PORT", 2626)
|
|
|
|
# UDP Server configuration
|
|
UDP_HOST = os.getenv("UDP_HOST", "0.0.0.0")
|
|
UDP_PORT = _get_int("UDP_PORT", 5000)
|
|
UDP_BUFFER_SIZE = _get_int("UDP_BUFFER_SIZE", 65535)
|
|
|
|
# Flask Web Server configuration
|
|
WEB_HOST = os.getenv("WEB_HOST", "0.0.0.0")
|
|
WEB_PORT = _get_int("WEB_PORT", 8000)
|
|
|
|
# Security
|
|
SECRET_TOKEN = os.getenv("CAMERA_SECRET_TOKEN", "Sup3rS3cretT0k3n").encode()
|
|
FLASK_SECRET_KEY = os.getenv("FLASK_SECRET_KEY", "change_this_for_prod")
|
|
|
|
# Credentials
|
|
DEFAULT_USERNAME = os.getenv("WEB_USERNAME", "admin")
|
|
DEFAULT_PASSWORD = os.getenv("WEB_PASSWORD", "admin")
|
|
|
|
# Storage paths
|
|
IMAGE_DIR = os.getenv("IMAGE_DIR", str(C2_ROOT / "static" / "streams"))
|
|
|
|
# Video recording
|
|
VIDEO_ENABLED = _get_bool("VIDEO_ENABLED", True)
|
|
VIDEO_PATH = os.getenv("VIDEO_PATH", str(C2_ROOT / "static" / "streams" / "record.avi"))
|
|
VIDEO_FPS = _get_int("VIDEO_FPS", 10)
|
|
VIDEO_CODEC = os.getenv("VIDEO_CODEC", "MJPG")
|
|
|
|
# Multilateration
|
|
MULTILAT_AUTH_TOKEN = os.getenv("MULTILAT_AUTH_TOKEN", "multilat_secret_token")
|
|
|
|
# Rate Limiting
|
|
RATE_LIMIT_DEFAULT = os.getenv("RATE_LIMIT_DEFAULT", "200 per minute")
|
|
RATE_LIMIT_LOGIN = os.getenv("RATE_LIMIT_LOGIN", "5 per minute")
|
|
|
|
# CORS
|
|
CORS_ALLOWED_ORIGINS = [
|
|
o.strip() for o in os.getenv("CORS_ALLOWED_ORIGINS", "").split(",") if o.strip()
|
|
]
|
|
|
|
# Tunnel / SOCKS5 Proxy
|
|
TUNNEL_SOCKS_HOST = os.getenv("TUNNEL_SOCKS_HOST", "127.0.0.1")
|
|
TUNNEL_SOCKS_PORT = _get_int("TUNNEL_SOCKS_PORT", 1080)
|
|
TUNNEL_LISTEN_PORT = _get_int("TUNNEL_LISTEN_PORT", 2627)
|
|
|
|
# Insecure default values that must be changed for production
|
|
_INSECURE_DEFAULTS = {
|
|
"FLASK_SECRET_KEY": "change_this_for_prod",
|
|
"CAMERA_SECRET_TOKEN": "Sup3rS3cretT0k3n",
|
|
"MULTILAT_AUTH_TOKEN": "multilat_secret_token",
|
|
}
|
|
|
|
|
|
def validate_config():
|
|
"""Check that no insecure default values are still in use.
|
|
|
|
Prints warnings for each insecure default found.
|
|
Returns True if configuration is safe, False otherwise.
|
|
"""
|
|
insecure = []
|
|
if FLASK_SECRET_KEY == _INSECURE_DEFAULTS["FLASK_SECRET_KEY"]:
|
|
insecure.append("FLASK_SECRET_KEY")
|
|
if SECRET_TOKEN == _INSECURE_DEFAULTS["CAMERA_SECRET_TOKEN"].encode():
|
|
insecure.append("CAMERA_SECRET_TOKEN")
|
|
if MULTILAT_AUTH_TOKEN == _INSECURE_DEFAULTS["MULTILAT_AUTH_TOKEN"]:
|
|
insecure.append("MULTILAT_AUTH_TOKEN")
|
|
if DEFAULT_USERNAME == "admin" and DEFAULT_PASSWORD == "admin":
|
|
insecure.append("WEB_USERNAME/WEB_PASSWORD (admin/admin)")
|
|
|
|
if insecure:
|
|
print("\n" + "=" * 60)
|
|
print(" WARNING: Insecure default values detected!")
|
|
print("=" * 60)
|
|
for name in insecure:
|
|
print(f" - {name}")
|
|
print()
|
|
print(" Set these in your .env file before production use.")
|
|
print(" See .env.example for reference.")
|
|
print("=" * 60 + "\n")
|
|
return False
|
|
return True
|