mirror of
https://github.com/infinition/Bjorn.git
synced 2026-03-11 07:01:59 +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:
157
db_utils/software.py
Normal file
157
db_utils/software.py
Normal file
@@ -0,0 +1,157 @@
|
||||
# db_utils/software.py
|
||||
# Detected software (CPE) inventory operations
|
||||
|
||||
from typing import List, Optional
|
||||
import logging
|
||||
|
||||
from logger import Logger
|
||||
|
||||
logger = Logger(name="db_utils.software", level=logging.DEBUG)
|
||||
|
||||
|
||||
class SoftwareOps:
|
||||
"""Detected software (CPE) tracking operations"""
|
||||
|
||||
def __init__(self, base):
|
||||
self.base = base
|
||||
|
||||
def create_tables(self):
|
||||
"""Create detected software tables"""
|
||||
self.base.execute("""
|
||||
CREATE TABLE IF NOT EXISTS detected_software (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
mac_address TEXT NOT NULL,
|
||||
ip TEXT,
|
||||
hostname TEXT,
|
||||
port INTEGER NOT NULL DEFAULT 0,
|
||||
cpe TEXT NOT NULL,
|
||||
first_seen TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
last_seen TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
is_active INTEGER DEFAULT 1,
|
||||
UNIQUE(mac_address, port, cpe)
|
||||
);
|
||||
""")
|
||||
|
||||
# Migration for detected_software
|
||||
self.base.execute("""
|
||||
UPDATE detected_software SET port = 0 WHERE port IS NULL
|
||||
""")
|
||||
|
||||
# Detected software history (immutable log)
|
||||
self.base.execute("""
|
||||
CREATE TABLE IF NOT EXISTS detected_software_history (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
mac_address TEXT NOT NULL,
|
||||
ip TEXT,
|
||||
hostname TEXT,
|
||||
port INTEGER NOT NULL DEFAULT 0,
|
||||
cpe TEXT NOT NULL,
|
||||
event TEXT NOT NULL,
|
||||
seen_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
""")
|
||||
|
||||
logger.debug("Software detection tables created/verified")
|
||||
|
||||
# =========================================================================
|
||||
# SOFTWARE CRUD OPERATIONS
|
||||
# =========================================================================
|
||||
|
||||
def add_detected_software(self, mac_address: str, cpe: str, ip: Optional[str] = None,
|
||||
hostname: Optional[str] = None, port: Optional[int] = None) -> None:
|
||||
"""Upsert a (mac, port, cpe) tuple and record history (new/seen)"""
|
||||
p = int(port or 0)
|
||||
existed = self.base.query(
|
||||
"SELECT id FROM detected_software WHERE mac_address=? AND port=? AND cpe=? LIMIT 1",
|
||||
(mac_address, p, cpe)
|
||||
)
|
||||
if existed:
|
||||
self.base.execute("""
|
||||
UPDATE detected_software
|
||||
SET ip=COALESCE(?, detected_software.ip),
|
||||
hostname=COALESCE(?, detected_software.hostname),
|
||||
last_seen=CURRENT_TIMESTAMP,
|
||||
is_active=1
|
||||
WHERE mac_address=? AND port=? AND cpe=?
|
||||
""", (ip, hostname, mac_address, p, cpe))
|
||||
self.base.execute("""
|
||||
INSERT INTO detected_software_history(mac_address, ip, hostname, port, cpe, event)
|
||||
VALUES(?,?,?,?,?,'seen')
|
||||
""", (mac_address, ip, hostname, p, cpe))
|
||||
else:
|
||||
self.base.execute("""
|
||||
INSERT INTO detected_software(mac_address, ip, hostname, port, cpe, is_active)
|
||||
VALUES(?,?,?,?,?,1)
|
||||
""", (mac_address, ip, hostname, p, cpe))
|
||||
self.base.execute("""
|
||||
INSERT INTO detected_software_history(mac_address, ip, hostname, port, cpe, event)
|
||||
VALUES(?,?,?,?,?,'new')
|
||||
""", (mac_address, ip, hostname, p, cpe))
|
||||
|
||||
def update_detected_software_status(self, mac_address: str, current_cpes: List[str]) -> None:
|
||||
"""Mark absent CPEs as inactive, present ones as seen, insert new ones as needed"""
|
||||
rows = self.base.query(
|
||||
"SELECT cpe FROM detected_software WHERE mac_address=? AND is_active=1",
|
||||
(mac_address,)
|
||||
)
|
||||
existing = {r['cpe'] for r in rows}
|
||||
cur = set(current_cpes)
|
||||
|
||||
# Inactive
|
||||
for cpe in (existing - cur):
|
||||
self.base.execute("""
|
||||
UPDATE detected_software
|
||||
SET is_active=0, last_seen=CURRENT_TIMESTAMP
|
||||
WHERE mac_address=? AND cpe=? AND is_active=1
|
||||
""", (mac_address, cpe))
|
||||
self.base.execute("""
|
||||
INSERT INTO detected_software_history(mac_address, port, cpe, event)
|
||||
SELECT mac_address, port, cpe, 'inactive'
|
||||
FROM detected_software
|
||||
WHERE mac_address=? AND cpe=? LIMIT 1
|
||||
""", (mac_address, cpe))
|
||||
|
||||
# New
|
||||
for cpe in (cur - existing):
|
||||
self.add_detected_software(mac_address, cpe)
|
||||
|
||||
# Seen
|
||||
for cpe in (cur & existing):
|
||||
self.base.execute("""
|
||||
UPDATE detected_software
|
||||
SET last_seen=CURRENT_TIMESTAMP
|
||||
WHERE mac_address=? AND cpe=? AND is_active=1
|
||||
""", (mac_address, cpe))
|
||||
self.base.execute("""
|
||||
INSERT INTO detected_software_history(mac_address, port, cpe, event)
|
||||
SELECT mac_address, port, cpe, 'seen'
|
||||
FROM detected_software
|
||||
WHERE mac_address=? AND cpe=? LIMIT 1
|
||||
""", (mac_address, cpe))
|
||||
|
||||
# =========================================================================
|
||||
# MIGRATION HELPER
|
||||
# =========================================================================
|
||||
|
||||
def migrate_cpe_from_vulnerabilities(self) -> int:
|
||||
"""
|
||||
Migrate historical CPE entries wrongly stored in `vulnerabilities.vuln_id`
|
||||
into `detected_software`. Returns the number of rows migrated.
|
||||
"""
|
||||
rows = self.base.query("""
|
||||
SELECT id, mac_address, ip, hostname, COALESCE(port,0) AS port, vuln_id
|
||||
FROM vulnerabilities
|
||||
WHERE LOWER(vuln_id) LIKE 'cpe:%' OR UPPER(vuln_id) LIKE 'CPE:%'
|
||||
""")
|
||||
moved = 0
|
||||
for r in rows:
|
||||
vid = r['vuln_id']
|
||||
cpe = vid.split(':', 1)[1] if vid.upper().startswith('CPE:') else vid
|
||||
try:
|
||||
self.add_detected_software(r['mac_address'], cpe, r.get('ip'), r.get('hostname'), r.get('port'))
|
||||
self.base.execute("DELETE FROM vulnerabilities WHERE id=?", (r['id'],))
|
||||
moved += 1
|
||||
except Exception:
|
||||
# Best-effort migration; keep moving on errors
|
||||
pass
|
||||
return moved
|
||||
Reference in New Issue
Block a user