MCPcopy Create free account
hub / github.com/PierreGode/Ragnar / PushoverService

Class PushoverService

pushover_service.py:16–304  ·  view source on GitHub ↗

Lightweight wrapper around the Pushover HTTP API.

Source from the content-addressed store, hash-verified

14
15
16class PushoverService:
17 """Lightweight wrapper around the Pushover HTTP API."""
18
19 def __init__(self, shared_data):
20 self.shared_data = shared_data
21 self._lock = threading.Lock()
22 # Tracks already-notified items to avoid spamming
23 self._notified_devices = set() # set of IPs ever notified (persisted across restarts via DB load)
24 self._offline_devices = set() # IPs that went offline this session (for back-online detection)
25 self._last_notified_vuln_count = 0 # last count we sent a vuln alert for
26 self._notified_creds = 0 # last known cred count
27 self._last_send_ts = 0.0 # rate-limit: min 2 s between sends
28 self._startup_ts = time.time() # suppress device notifications shortly after restart
29 self._startup_grace_s = 90 # seconds to wait before sending device alerts
30 self._load_known_state_from_db()
31
32 # ------------------------------------------------------------------
33 # DB state loader — prevents restart-triggered false notifications
34 # ------------------------------------------------------------------
35
36 def _load_known_state_from_db(self):
37 """Pre-populate _notified_devices and _last_notified_vuln_count from the DB
38 so that a restart does not re-notify about already-known devices/vulns."""
39 try:
40 db = getattr(self.shared_data, 'db', None)
41 if db is None:
42 return
43 with db.get_connection() as conn:
44 cursor = conn.cursor()
45 # Load all known IPs
46 cursor.execute("SELECT ip FROM hosts WHERE ip IS NOT NULL AND ip != ''")
47 rows = cursor.fetchall()
48 with self._lock:
49 for row in rows:
50 # sqlite3.Row supports index access but has no .get()
51 ip = row[0] if row else ''
52 if ip:
53 self._notified_devices.add(ip)
54 # Load current vuln count as baseline (so we only alert on genuinely new ones)
55 cursor.execute(
56 "SELECT COUNT(*) FROM hosts "
57 "WHERE vulnerabilities IS NOT NULL AND vulnerabilities != '' AND vulnerabilities != 'None'"
58 )
59 row = cursor.fetchone()
60 baseline = row[0] if row else 0
61 with self._lock:
62 self._last_notified_vuln_count = baseline
63 # Load credential baseline count
64 try:
65 cursor.execute("SELECT COUNT(*) FROM hosts WHERE credentials IS NOT NULL AND credentials != '' AND credentials != 'None'")
66 cred_row = cursor.fetchone()
67 cred_baseline = cred_row[0] if cred_row else 0
68 with self._lock:
69 self._notified_creds = cred_baseline
70 except Exception:
71 pass # credentials column may not exist
72 logger.debug(
73 f"Pushover: loaded {len(self._notified_devices)} known IPs, "

Callers 4

_rusense_pushoverFunction · 0.90
sync_vulnerability_countFunction · 0.90
sync_all_countsFunction · 0.90
test_pushoverFunction · 0.90

Calls

no outgoing calls

Tested by 1

test_pushoverFunction · 0.72