mirror of
https://github.com/infinition/Bjorn.git
synced 2026-03-19 10:10:24 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Bifrost — Mood state machine.
|
||||
"""automata.py - Bifrost mood state machine.
|
||||
|
||||
Ported from pwnagotchi/automata.py.
|
||||
"""
|
||||
import logging
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Bifrost — ASCII face definitions.
|
||||
"""faces.py - Bifrost ASCII face definitions.
|
||||
|
||||
Ported from pwnagotchi/ui/faces.py with full face set.
|
||||
"""
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user