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

View File

@@ -1,5 +1,5 @@
"""
Bifrost — Pwnagotchi-compatible WiFi recon engine for Bjorn.
"""__init__.py - Bifrost, pwnagotchi-compatible WiFi recon engine for Bjorn.
Runs as a daemon thread alongside MANUAL/AUTO/AI modes.
"""
import os
@@ -42,7 +42,7 @@ class BifrostEngine:
# Wait for any previous thread to finish before re-starting
if self._thread and self._thread.is_alive():
logger.warning("Previous Bifrost thread still running waiting ...")
logger.warning("Previous Bifrost thread still running - waiting ...")
self._stop_event.set()
self._thread.join(timeout=15)
@@ -82,7 +82,7 @@ class BifrostEngine:
logger.info("Bifrost engine stopped")
def _loop(self):
"""Main daemon loop setup monitor mode, start bettercap, create agent, run recon cycle."""
"""Main daemon loop - setup monitor mode, start bettercap, create agent, run recon cycle."""
try:
# Install compatibility shim for pwnagotchi plugins
from bifrost import plugins as bfplugins
@@ -94,15 +94,15 @@ class BifrostEngine:
if self._monitor_failed:
logger.error(
"Monitor mode setup failed Bifrost cannot operate without monitor "
"Monitor mode setup failed - Bifrost cannot operate without monitor "
"mode. For Broadcom chips (Pi Zero W/2W), install nexmon: "
"https://github.com/seemoo-lab/nexmon "
"https://github.com/seemoo-lab/nexmon - "
"Or use an external USB WiFi adapter with monitor mode support.")
# Teardown first (restores network services) BEFORE switching mode,
# so the orchestrator doesn't start scanning on a dead network.
self._teardown_monitor_mode()
self._running = False
# Now switch mode back to AUTO the network should be restored.
# Now switch mode back to AUTO - the network should be restored.
# We set the flag directly FIRST (bypass setter to avoid re-stopping),
# then ensure manual_mode/ai_mode are cleared so getter returns AUTO.
try:
@@ -112,7 +112,7 @@ class BifrostEngine:
self.shared_data.manual_mode = False
self.shared_data.ai_mode = False
self.shared_data.invalidate_config_cache()
logger.info("Bifrost auto-disabled due to monitor mode failure mode: AUTO")
logger.info("Bifrost auto-disabled due to monitor mode failure - mode: AUTO")
except Exception:
pass
return
@@ -133,7 +133,7 @@ class BifrostEngine:
# Initialize agent
self.agent.start()
logger.info("Bifrost agent started entering recon cycle")
logger.info("Bifrost agent started - entering recon cycle")
# Main recon loop (port of do_auto_mode from pwnagotchi)
while not self._stop_event.is_set():
@@ -208,7 +208,7 @@ class BifrostEngine:
return True
except Exception:
pass
# nexutil exists assume usable even without dmesg confirmation
# nexutil exists - assume usable even without dmesg confirmation
return True
@staticmethod
@@ -239,10 +239,10 @@ class BifrostEngine:
"""Put the WiFi interface into monitor mode.
Strategy order:
1. Nexmon for Broadcom brcmfmac chips (Pi Zero W / Pi Zero 2 W)
1. Nexmon - for Broadcom brcmfmac chips (Pi Zero W / Pi Zero 2 W)
Uses: iw phy <phy> interface add mon0 type monitor + nexutil -m2
2. airmon-ng for chipsets with proper driver support (Atheros, Realtek, etc.)
3. iw direct fallback for other drivers
2. airmon-ng - for chipsets with proper driver support (Atheros, Realtek, etc.)
3. iw - direct fallback for other drivers
"""
self._monitor_torn_down = False
self._nexmon_used = False
@@ -270,7 +270,7 @@ class BifrostEngine:
if self._has_nexmon():
if self._setup_nexmon(base_iface, cfg):
return
# nexmon setup failed don't try other strategies, they won't work either
# nexmon setup failed - don't try other strategies, they won't work either
self._monitor_failed = True
return
else:
@@ -410,7 +410,7 @@ class BifrostEngine:
logger.error("Monitor interface %s not created", mon_iface)
return False
# Success update config to use mon0
# Success - update config to use mon0
cfg['bifrost_iface'] = mon_iface
self._mon_iface = mon_iface
self._nexmon_used = True

View File

@@ -1,5 +1,5 @@
"""
Bifrost — WiFi recon agent.
"""agent.py - Bifrost WiFi recon agent.
Ported from pwnagotchi/agent.py using composition instead of inheritance.
"""
import time
@@ -22,7 +22,7 @@ logger = Logger(name="bifrost.agent", level=logging.DEBUG)
class BifrostAgent:
"""WiFi recon agent drives bettercap, captures handshakes, tracks epochs."""
"""WiFi recon agent - drives bettercap, captures handshakes, tracks epochs."""
def __init__(self, shared_data, stop_event=None):
self.shared_data = shared_data
@@ -170,7 +170,7 @@ class BifrostAgent:
err_msg = str(e)
if 'Operation not supported' in err_msg or 'EOPNOTSUPP' in err_msg:
logger.error(
"wifi.recon failed: %s Your WiFi chip likely does NOT support "
"wifi.recon failed: %s - Your WiFi chip likely does NOT support "
"monitor mode. The built-in Broadcom chip on Raspberry Pi Zero/Zero 2 "
"has limited monitor mode support. Use an external USB WiFi adapter "
"(e.g. Alfa AWUS036ACH, Panda PAU09) that supports monitor mode and "
@@ -362,7 +362,7 @@ class BifrostAgent:
logger.error("Error setting channel: %s", e)
def next_epoch(self):
"""Transition to next epoch evaluate mood."""
"""Transition to next epoch - evaluate mood."""
self.automata.next_epoch(self.epoch)
# Persist epoch to DB
data = self.epoch.data()
@@ -393,7 +393,7 @@ class BifrostAgent:
has_ws = True
except ImportError:
has_ws = False
logger.warning("websockets package not installed using REST event polling "
logger.warning("websockets package not installed - using REST event polling "
"(pip install websockets for real-time events)")
if has_ws:
@@ -417,7 +417,7 @@ class BifrostAgent:
loop.close()
def _rest_event_loop(self):
"""REST-based fallback event poller polls /api/events every 2s."""
"""REST-based fallback event poller - polls /api/events every 2s."""
while not self._stop_event.is_set():
try:
events = self.bettercap.events()

View File

@@ -1,5 +1,5 @@
"""
Bifrost — Mood state machine.
"""automata.py - Bifrost mood state machine.
Ported from pwnagotchi/automata.py.
"""
import logging

View File

@@ -1,5 +1,5 @@
"""
Bifrost — Bettercap REST API client.
"""bettercap.py - Bifrost bettercap REST API client.
Ported from pwnagotchi/bettercap.py using urllib (no requests dependency).
"""
import json
@@ -54,16 +54,16 @@ class BettercapClient:
raise Exception("bettercap unreachable: %s" % e.reason)
def session(self):
"""GET /api/session current bettercap state."""
"""GET /api/session - current bettercap state."""
return self._request('GET', '/session')
def run(self, command, verbose_errors=True):
"""POST /api/session execute a bettercap command."""
"""POST /api/session - execute a bettercap command."""
return self._request('POST', '/session', {'cmd': command},
verbose_errors=verbose_errors)
def events(self):
"""GET /api/events poll recent events (REST fallback)."""
"""GET /api/events - poll recent events (REST fallback)."""
try:
result = self._request('GET', '/events', verbose_errors=False)
# Clear after reading so we don't reprocess
@@ -80,7 +80,7 @@ class BettercapClient:
Args:
consumer: async callable that receives each message string.
stop_event: optional threading.Event exit when set.
stop_event: optional threading.Event - exit when set.
"""
import websockets
import asyncio
@@ -99,5 +99,5 @@ class BettercapClient:
except Exception as ex:
if stop_event and stop_event.is_set():
return
logger.debug("Websocket error: %s reconnecting...", ex)
logger.debug("Websocket error: %s - reconnecting...", ex)
await asyncio.sleep(2)

View File

@@ -1,7 +1,6 @@
"""
Bifrost — Pwnagotchi compatibility shim.
Registers `pwnagotchi` in sys.modules so existing plugins can
`import pwnagotchi` and get Bifrost-backed implementations.
"""compat.py - Pwnagotchi compatibility shim.
Registers `pwnagotchi` in sys.modules so existing plugins resolve to Bifrost.
"""
import sys
import time
@@ -56,7 +55,7 @@ def install_shim(shared_data, bifrost_plugins_module):
return 0.0
def _reboot():
pass # no-op in Bifrost we don't auto-reboot
pass # no-op in Bifrost - we don't auto-reboot
pwn.name = _name
pwn.set_name = _set_name

View File

@@ -1,5 +1,5 @@
"""
Bifrost — Epoch tracking.
"""epoch.py - Bifrost epoch tracking and reward signals.
Ported from pwnagotchi/ai/epoch.py + pwnagotchi/ai/reward.py.
"""
import time
@@ -17,7 +17,7 @@ NUM_CHANNELS = 14 # 2.4 GHz channels
# ── Reward function (from pwnagotchi/ai/reward.py) ──────────────
class RewardFunction:
"""Reward signal for RL higher is better."""
"""Reward signal for RL - higher is better."""
def __call__(self, epoch_n, state):
eps = 1e-20
@@ -181,7 +181,7 @@ class BifrostEpoch:
self.num_slept += inc
def next(self):
"""Transition to next epoch compute reward, update streaks, reset counters."""
"""Transition to next epoch - compute reward, update streaks, reset counters."""
# Update activity streaks
if not self.any_activity and not self.did_handshakes:
self.inactive_for += 1

View File

@@ -1,5 +1,5 @@
"""
Bifrost — ASCII face definitions.
"""faces.py - Bifrost ASCII face definitions.
Ported from pwnagotchi/ui/faces.py with full face set.
"""

View File

@@ -1,7 +1,6 @@
"""
Bifrost — Plugin system.
"""plugins.py - Bifrost plugin system.
Ported from pwnagotchi/plugins/__init__.py with ThreadPoolExecutor.
Compatible with existing pwnagotchi plugin files.
"""
import os
import glob
@@ -130,7 +129,7 @@ def load_from_path(path, enabled=()):
if not path or not os.path.isdir(path):
return loaded
logger.debug("loading plugins from %s enabled: %s", path, enabled)
logger.debug("loading plugins from %s - enabled: %s", path, enabled)
for filename in glob.glob(os.path.join(path, "*.py")):
plugin_name = os.path.basename(filename.replace(".py", ""))
database[plugin_name] = filename

View File

@@ -1,5 +1,5 @@
"""
Bifrost — Voice / status messages.
"""voice.py - Bifrost voice / status messages.
Ported from pwnagotchi/voice.py, uses random choice for personality.
"""
import random