asd
This commit is contained in:
@@ -49,6 +49,9 @@ services:
|
||||
DATABASE_URL: postgresql://${POSTGRES_USER:-adctrl}:${POSTGRES_PASSWORD:-adctrl_secure_password}@postgres:5432/${POSTGRES_DB:-adctrl}
|
||||
SECRET_TOKEN: ${SECRET_TOKEN}
|
||||
SCOREBOARD_WS_URL: ${SCOREBOARD_WS_URL:-ws://10.60.0.1:8080/api/events}
|
||||
SCOREBOARD_API_URL: ${SCOREBOARD_API_URL:-http://10.60.0.1:8080/api}
|
||||
USE_HTTP_POLLING: ${USE_HTTP_POLLING:-false}
|
||||
POLLING_INTERVAL: ${POLLING_INTERVAL:-10}
|
||||
OUR_TEAM_ID: ${OUR_TEAM_ID:-1}
|
||||
ALERT_THRESHOLD_POINTS: ${ALERT_THRESHOLD_POINTS:-100}
|
||||
ALERT_THRESHOLD_TIME: ${ALERT_THRESHOLD_TIME:-300}
|
||||
|
||||
@@ -17,6 +17,9 @@ from contextlib import asynccontextmanager
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://adctrl:adctrl@postgres:5432/adctrl")
|
||||
SECRET_TOKEN = os.getenv("SECRET_TOKEN", "change-me-in-production")
|
||||
SCOREBOARD_WS_URL = os.getenv("SCOREBOARD_WS_URL", "ws://scoreboard:8080/api/events")
|
||||
SCOREBOARD_API_URL = os.getenv("SCOREBOARD_API_URL", "http://10.60.0.1:8080/api")
|
||||
USE_HTTP_POLLING = os.getenv("USE_HTTP_POLLING", "false").lower() == "true"
|
||||
POLLING_INTERVAL = int(os.getenv("POLLING_INTERVAL", "10")) # seconds
|
||||
OUR_TEAM_ID = int(os.getenv("OUR_TEAM_ID", "1"))
|
||||
ALERT_THRESHOLD_POINTS = float(os.getenv("ALERT_THRESHOLD_POINTS", "100"))
|
||||
ALERT_THRESHOLD_TIME = int(os.getenv("ALERT_THRESHOLD_TIME", "300")) # seconds
|
||||
@@ -184,6 +187,58 @@ async def send_telegram_alert(message: str):
|
||||
except Exception as e:
|
||||
print(f"Error sending telegram alert: {e}")
|
||||
|
||||
async def http_polling_listener():
|
||||
"""Poll scoreboard HTTP API for attacks as alternative to WebSocket"""
|
||||
last_round = 0
|
||||
|
||||
while True:
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# Try to fetch scoreboard data
|
||||
# Common ForcAD endpoints: /api/scoreboard, /api/teams, /api/attacks
|
||||
endpoints_to_try = [
|
||||
f"{SCOREBOARD_API_URL}/attacks",
|
||||
f"{SCOREBOARD_API_URL}/scoreboard",
|
||||
f"{SCOREBOARD_API_URL}/flag_stats"
|
||||
]
|
||||
|
||||
for endpoint in endpoints_to_try:
|
||||
try:
|
||||
async with session.get(endpoint, timeout=aiohttp.ClientTimeout(total=5)) as resp:
|
||||
if resp.status == 200:
|
||||
data = await resp.json()
|
||||
print(f"✓ Fetched data from {endpoint}")
|
||||
|
||||
# Process based on response structure
|
||||
if isinstance(data, list):
|
||||
# List of attacks/events
|
||||
for item in data:
|
||||
await process_attack_event(item)
|
||||
elif isinstance(data, dict):
|
||||
# Could be scoreboard with nested data
|
||||
# Try common keys
|
||||
for key in ['attacks', 'flags', 'events', 'data']:
|
||||
if key in data and isinstance(data[key], list):
|
||||
for item in data[key]:
|
||||
await process_attack_event(item)
|
||||
break
|
||||
else:
|
||||
# Might be a single event
|
||||
await process_attack_event(data)
|
||||
|
||||
break # Success, no need to try other endpoints
|
||||
except aiohttp.ClientError as e:
|
||||
print(f"Failed to fetch from {endpoint}: {e}")
|
||||
continue
|
||||
except json.JSONDecodeError:
|
||||
print(f"Invalid JSON from {endpoint}")
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
print(f"HTTP polling error: {e}")
|
||||
|
||||
await asyncio.sleep(POLLING_INTERVAL)
|
||||
|
||||
async def websocket_listener():
|
||||
"""Listen to scoreboard WebSocket for events"""
|
||||
reconnect_delay = 5
|
||||
@@ -248,8 +303,17 @@ async def lifespan(app: FastAPI):
|
||||
global db_pool, ws_task
|
||||
db_pool = await asyncpg.create_pool(DATABASE_URL, min_size=2, max_size=10)
|
||||
|
||||
# Start WebSocket listener
|
||||
ws_task = asyncio.create_task(websocket_listener())
|
||||
# Start listener based on configuration
|
||||
if USE_HTTP_POLLING:
|
||||
print(f"Starting HTTP polling mode (interval: {POLLING_INTERVAL}s)")
|
||||
print(f"Scoreboard API: {SCOREBOARD_API_URL}")
|
||||
ws_task = asyncio.create_task(http_polling_listener())
|
||||
else:
|
||||
print(f"Starting WebSocket listener mode")
|
||||
print(f"Scoreboard WS: {SCOREBOARD_WS_URL}")
|
||||
ws_task = asyncio.create_task(websocket_listener())
|
||||
|
||||
print(f"Our team ID: {OUR_TEAM_ID}")
|
||||
|
||||
yield
|
||||
|
||||
@@ -268,7 +332,13 @@ app = FastAPI(title="Scoreboard Injector", lifespan=lifespan)
|
||||
# API Endpoints
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
return {"status": "ok", "timestamp": datetime.utcnow().isoformat()}
|
||||
return {
|
||||
"status": "ok",
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"team_id": OUR_TEAM_ID,
|
||||
"mode": "http_polling" if USE_HTTP_POLLING else "websocket",
|
||||
"scoreboard_url": SCOREBOARD_API_URL if USE_HTTP_POLLING else SCOREBOARD_WS_URL
|
||||
}
|
||||
|
||||
@app.get("/stats", dependencies=[Depends(verify_token)])
|
||||
async def get_stats():
|
||||
@@ -409,6 +479,56 @@ async def inject_test_attack(attacker_id: int, victim_id: int, service: str = "t
|
||||
await process_attack_event(test_event)
|
||||
return {"status": "injected", "event": test_event}
|
||||
|
||||
@app.get("/debug/scoreboard", dependencies=[Depends(verify_token)])
|
||||
async def debug_scoreboard():
|
||||
"""Check if scoreboard is reachable and show raw data"""
|
||||
results = {
|
||||
"mode": "http_polling" if USE_HTTP_POLLING else "websocket",
|
||||
"endpoints_tested": []
|
||||
}
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# Test WebSocket
|
||||
results["websocket_url"] = SCOREBOARD_WS_URL
|
||||
try:
|
||||
async with session.ws_connect(SCOREBOARD_WS_URL, timeout=aiohttp.ClientTimeout(total=5)) as ws:
|
||||
results["websocket_status"] = "reachable"
|
||||
except Exception as e:
|
||||
results["websocket_status"] = f"unreachable: {str(e)}"
|
||||
|
||||
# Test HTTP endpoints
|
||||
results["http_api_url"] = SCOREBOARD_API_URL
|
||||
endpoints = [
|
||||
"/attacks",
|
||||
"/scoreboard",
|
||||
"/flag_stats",
|
||||
"/teams",
|
||||
"/events"
|
||||
]
|
||||
|
||||
for endpoint in endpoints:
|
||||
url = f"{SCOREBOARD_API_URL}{endpoint}"
|
||||
try:
|
||||
async with session.get(url, timeout=aiohttp.ClientTimeout(total=5)) as resp:
|
||||
data = await resp.text()
|
||||
results["endpoints_tested"].append({
|
||||
"url": url,
|
||||
"status": resp.status,
|
||||
"reachable": resp.status == 200,
|
||||
"data_preview": data[:500] if resp.status == 200 else None
|
||||
})
|
||||
except Exception as e:
|
||||
results["endpoints_tested"].append({
|
||||
"url": url,
|
||||
"reachable": False,
|
||||
"error": str(e)
|
||||
})
|
||||
except Exception as e:
|
||||
results["error"] = str(e)
|
||||
|
||||
return results
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=8002)
|
||||
|
||||
Reference in New Issue
Block a user