feat: Add login page with dynamic RGB effects and password toggle functionality

feat: Implement package management utilities with JSON endpoints for listing and uninstalling packages

feat: Create plugin management utilities with endpoints for listing, configuring, and installing plugins

feat: Develop schedule and trigger management utilities with CRUD operations for schedules and triggers
This commit is contained in:
infinition
2026-03-19 00:40:04 +01:00
parent 3fa4d5742a
commit b0584a1a8e
176 changed files with 7795 additions and 1781 deletions

156
bjorn_plugin.py Normal file
View File

@@ -0,0 +1,156 @@
"""bjorn_plugin.py - Base class and helpers for Bjorn plugins."""
import logging
from typing import Any, Dict, Optional
from logger import Logger
class PluginLogger:
"""Per-plugin logger that prefixes all messages with the plugin ID.
Caches Logger instances by name to prevent handler accumulation on reload."""
_cache: dict = {} # class-level cache: name -> Logger instance
def __init__(self, plugin_id: str):
name = f"plugin.{plugin_id}"
if name not in PluginLogger._cache:
PluginLogger._cache[name] = Logger(name=name, level=logging.DEBUG)
self._logger = PluginLogger._cache[name]
def info(self, msg: str):
self._logger.info(msg)
def warning(self, msg: str):
self._logger.warning(msg)
def error(self, msg: str):
self._logger.error(msg)
def debug(self, msg: str):
self._logger.debug(msg)
def success(self, msg: str):
self._logger.success(msg)
class BjornPlugin:
"""
Base class every Bjorn plugin must extend.
Provides:
- Access to shared_data, database, and config
- Convenience wrappers for status/progress/comment
- Hook methods to override for event-driven behavior
- Standard action interface (execute) for action-type plugins
Usage:
class MyPlugin(BjornPlugin):
def setup(self):
self.log.info("Ready!")
def on_credential_found(self, cred):
self.log.info(f"New cred: {cred}")
"""
def __init__(self, shared_data, meta: dict, config: dict):
"""
Args:
shared_data: The global SharedData singleton.
meta: Parsed plugin.json manifest.
config: User-editable config values (from DB, merged with schema defaults).
"""
self.shared_data = shared_data
self.meta = meta
self.config = config
self.db = shared_data.db
self.log = PluginLogger(meta.get("id", "unknown"))
self.timeout = (meta.get("action") or {}).get("timeout", 300)
self._plugin_id = meta.get("id", "unknown")
# ── Convenience wrappers ─────────────────────────────────────────
def set_progress(self, pct: str):
"""Update the global progress indicator (e.g., '42%')."""
self.shared_data.bjorn_progress = pct
def set_status(self, text: str):
"""Update the main status text shown on display and web UI."""
self.shared_data.bjorn_status_text = text
def set_comment(self, **params):
"""Update the EPD comment parameters."""
self.shared_data.comment_params = params
# ── Lifecycle ────────────────────────────────────────────────────
def setup(self) -> None:
"""Called once when the plugin is loaded. Override to initialize resources."""
pass
def teardown(self) -> None:
"""Called when the plugin is unloaded or Bjorn shuts down. Override to cleanup."""
pass
# ── Action interface (type="action" plugins only) ────────────────
def execute(self, ip: str, port: str, row: dict, status_key: str) -> str:
"""
Called by the orchestrator for action-type plugins.
Args:
ip: Target IP address.
port: Target port (may be empty string).
row: Dict with keys: MAC Address, IPs, Ports, Alive.
status_key: Action class name (for status tracking).
Returns:
'success' or 'failed' (string, case-sensitive).
"""
raise NotImplementedError(
f"Plugin {self._plugin_id} is type='action' but does not implement execute()"
)
# ── Hook methods (override selectively) ──────────────────────────
def on_host_discovered(self, host: dict) -> None:
"""Hook: called when a new host is found by the scanner.
Args:
host: Dict with mac_address, ips, hostnames, vendor, etc.
"""
pass
def on_credential_found(self, cred: dict) -> None:
"""Hook: called when new credentials are discovered.
Args:
cred: Dict with service, mac, ip, user, password, port.
"""
pass
def on_vulnerability_found(self, vuln: dict) -> None:
"""Hook: called when a new vulnerability is found.
Args:
vuln: Dict with ip, port, cve_id, severity, description.
"""
pass
def on_action_complete(self, action_name: str, success: bool, target: dict) -> None:
"""Hook: called after any action finishes execution.
Args:
action_name: The b_class of the action that completed.
success: True if action returned 'success'.
target: Dict with mac, ip, port.
"""
pass
def on_scan_complete(self, results: dict) -> None:
"""Hook: called after a network scan cycle finishes.
Args:
results: Dict with hosts_found, new_hosts, scan_duration, etc.
"""
pass