mirror of
https://github.com/infinition/Bjorn.git
synced 2025-12-13 16:14:57 +00:00
BREAKING CHANGE: Complete refactor of architecture to prepare BJORN V2 release, APIs, assets, and UI, webapp, logics, attacks, a lot of new features...
This commit is contained in:
81
resources/default_config/actions/presence_left.py
Normal file
81
resources/default_config/actions/presence_left.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# actions/presence_left.py
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
PresenceLeave — Sends a Discord webhook when the targeted host LEAVES the network.
|
||||
- Triggered by the scheduler ONLY on transition ON->OFF (b_trigger="on_leave").
|
||||
- Targeting via b_requires (e.g. {"any":[{"mac_is":"AA:BB:..."}]}).
|
||||
- The action does not query anything: it only notifies when called.
|
||||
"""
|
||||
|
||||
import requests
|
||||
from typing import Optional
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
from logger import Logger
|
||||
from shared import SharedData # only if executed directly for testing
|
||||
|
||||
logger = Logger(name="PresenceLeave", level=logging.DEBUG)
|
||||
|
||||
# --- Metadata (truth is in DB; here for reference/consistency) --------------
|
||||
b_class = "PresenceLeave"
|
||||
b_module = "presence_left"
|
||||
b_status = "PresenceLeave"
|
||||
b_port = None
|
||||
b_service = None
|
||||
b_parent = None
|
||||
b_priority = 90
|
||||
b_cooldown = 0 # not needed: on_leave only fires on leave transition
|
||||
b_rate_limit = None
|
||||
b_trigger = "on_leave" # <-- Host LEFT the network (ON -> OFF since last scan)
|
||||
b_requires = {"any":[{"mac_is":"60:57:c8:51:63:fb"}]} # adapt as needed
|
||||
|
||||
# Replace with your webhook (can reuse the same as PresenceJoin)
|
||||
DISCORD_WEBHOOK_URL = "https://discordapp.com/api/webhooks/1416433823456956561/MYc2mHuqgK_U8tA96fs2_-S1NVchPzGOzan9EgLr4i8yOQa-3xJ6Z-vMejVrpPfC3OfD"
|
||||
|
||||
class PresenceLeave:
|
||||
def __init__(self, shared_data):
|
||||
self.shared_data = shared_data
|
||||
|
||||
def _send(self, text: str) -> None:
|
||||
if not DISCORD_WEBHOOK_URL or "webhooks/" not in DISCORD_WEBHOOK_URL:
|
||||
logger.error("PresenceLeave: DISCORD_WEBHOOK_URL missing/invalid.")
|
||||
return
|
||||
try:
|
||||
r = requests.post(DISCORD_WEBHOOK_URL, json={"content": text}, timeout=6)
|
||||
if r.status_code < 300:
|
||||
logger.info("PresenceLeave: webhook sent.")
|
||||
else:
|
||||
logger.error(f"PresenceLeave: HTTP {r.status_code}: {r.text}")
|
||||
except Exception as e:
|
||||
logger.error(f"PresenceLeave: webhook error: {e}")
|
||||
|
||||
def execute(self, ip: Optional[str], port: Optional[str], row: dict, status_key: str):
|
||||
"""
|
||||
Called by the orchestrator when the scheduler detected the disconnection.
|
||||
ip/port = last known target (if available), row = host info.
|
||||
"""
|
||||
try:
|
||||
mac = row.get("MAC Address") or row.get("mac_address") or "MAC"
|
||||
host = row.get("hostname") or (row.get("hostnames") or "").split(";")[0] if row.get("hostnames") else None
|
||||
ip_s = (ip or (row.get("IPs") or "").split(";")[0] or "").strip()
|
||||
|
||||
# Add timestamp in UTC
|
||||
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
|
||||
|
||||
msg = f"❌ **Presence lost**\n"
|
||||
msg += f"- Host: {host or 'unknown'}\n"
|
||||
msg += f"- MAC: {mac}\n"
|
||||
if ip_s:
|
||||
msg += f"- Last IP: {ip_s}\n"
|
||||
msg += f"- Time: {timestamp}"
|
||||
|
||||
self._send(msg)
|
||||
return "success"
|
||||
except Exception as e:
|
||||
logger.error(f"PresenceLeave error: {e}")
|
||||
return "failed"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sd = SharedData()
|
||||
logger.info("PresenceLeave ready (direct mode).")
|
||||
Reference in New Issue
Block a user