🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
217 lines
6.4 KiB
Markdown
217 lines
6.4 KiB
Markdown
# Plugin Architecture Instructions
|
|
|
|
## Overview
|
|
|
|
Dangerous Pi uses a plugin system that supports:
|
|
- Remote installation from GitHub releases
|
|
- Automatic pip dependency management
|
|
- Hardware access (GPIO, I2C, SPI, serial) with permission enforcement
|
|
- WebSocket broadcasting for real-time updates
|
|
- Header widgets for UI notifications
|
|
- Permission declarations with user consent at install time
|
|
|
|
## Plugin Distribution Model
|
|
|
|
**Each plugin lives in its own GitHub repo** (e.g., `org/dangerous-pi-multi-flasher`).
|
|
|
|
### Registry Format
|
|
A central registry repo (`dangerous-pi-plugin-registry`) contains `plugins.json`:
|
|
```json
|
|
{
|
|
"version": "1.0.0",
|
|
"plugins": [
|
|
{
|
|
"id": "plugin_id",
|
|
"name": "Plugin Name",
|
|
"repo": "org/repo-name",
|
|
"description": "Description",
|
|
"author": "Author",
|
|
"latest_version": "1.0.0"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Plugin Release Format
|
|
Each plugin repo publishes GitHub releases with:
|
|
- `plugin.tar.gz` - The plugin archive
|
|
- `plugin.json` - Metadata with checksum and dependencies
|
|
|
|
### plugin.json Schema
|
|
```json
|
|
{
|
|
"id": "plugin_id",
|
|
"name": "Plugin Name",
|
|
"version": "1.0.0",
|
|
"description": "Description",
|
|
"author": "Author",
|
|
"checksum": "sha256:...",
|
|
"dependencies": ["package>=1.0.0"],
|
|
"permissions": ["gpio", "i2c", "network_access"],
|
|
"min_app_version": "1.0.0"
|
|
}
|
|
```
|
|
|
|
## Plugin Directory Structure
|
|
|
|
```
|
|
app/plugins/{plugin_id}/
|
|
plugin.json # Metadata manifest
|
|
main.py # Entry point (extends PluginBase)
|
|
services/ # Business logic
|
|
__init__.py
|
|
{service}.py
|
|
api/ # FastAPI router (optional)
|
|
__init__.py
|
|
router.py
|
|
```
|
|
|
|
## Creating a Plugin
|
|
|
|
### 1. Extend PluginBase
|
|
```python
|
|
from backend.managers.plugin_manager import PluginBase, PluginMetadata
|
|
|
|
class MyPlugin(PluginBase):
|
|
async def on_load(self):
|
|
# Initialize services
|
|
pass
|
|
|
|
async def on_enable(self):
|
|
# Register hooks, start functionality
|
|
self.register_hook("hook_name", self.my_callback)
|
|
|
|
async def on_disable(self):
|
|
# Stop functionality
|
|
pass
|
|
|
|
async def on_unload(self):
|
|
# Cleanup resources
|
|
pass
|
|
```
|
|
|
|
### 2. Register Hooks
|
|
Available hooks:
|
|
- `pm3_command` - Triggered on Proxmark3 commands
|
|
- `update_check` - Triggered on system update checks
|
|
- Custom hooks can be added
|
|
|
|
### 3. Add API Routes (Optional)
|
|
Plugins can expose their own FastAPI routers mounted under `/api/plugins/{plugin_id}/`
|
|
|
|
### 4. Register Header Widgets
|
|
Display notifications in the UI header:
|
|
```python
|
|
from backend.managers.plugin_manager import WidgetSeverity
|
|
|
|
class MyPlugin(PluginBase):
|
|
async def on_enable(self):
|
|
# Register a header widget
|
|
self.register_widget(
|
|
widget_id="status", # Becomes "plugin.my_plugin.status"
|
|
severity=WidgetSeverity.INFO,
|
|
message="Plugin is active",
|
|
icon="🔌",
|
|
dismissible=True,
|
|
action_label="Settings", # Optional
|
|
action_url="/settings#plugins"
|
|
)
|
|
|
|
async def on_disable(self):
|
|
# Clean up widget
|
|
self.unregister_widget("status")
|
|
```
|
|
|
|
Widget severity levels: `INFO`, `WARNING`, `ERROR`, `SUCCESS`
|
|
|
|
### 5. Broadcast WebSocket Events
|
|
Send real-time updates to connected clients (requires `websocket` permission):
|
|
```python
|
|
class MyPlugin(PluginBase):
|
|
async def some_operation(self):
|
|
# Broadcast event to all connected clients
|
|
# Event type becomes: "plugin.my_plugin.progress"
|
|
await self.broadcast_event("progress", {
|
|
"percent": 50,
|
|
"message": "Processing..."
|
|
})
|
|
```
|
|
|
|
WebSocket events are rate-limited to 10 events/second per plugin.
|
|
|
|
### 6. Access Hardware
|
|
Get controlled access to hardware interfaces (requires permissions in plugin.json):
|
|
```python
|
|
class MyPlugin(PluginBase):
|
|
def setup_hardware(self):
|
|
# Requires "i2c" permission
|
|
i2c = self.get_i2c(bus=1)
|
|
|
|
# Requires "gpio" permission
|
|
gpio = self.get_gpio()
|
|
|
|
# Requires "spi" permission
|
|
spi = self.get_spi(bus=0, device=0)
|
|
|
|
# Requires "serial" permission
|
|
serial = self.get_serial("/dev/ttyUSB0", baudrate=9600)
|
|
```
|
|
|
|
## Available Permissions
|
|
|
|
| Permission | Description | Methods Unlocked |
|
|
|------------|-------------|------------------|
|
|
| `gpio` | Access GPIO pins | `get_gpio()` |
|
|
| `i2c` | Access I2C bus | `get_i2c()` |
|
|
| `spi` | Access SPI bus | `get_spi()` |
|
|
| `serial` | Access serial ports | `get_serial()` |
|
|
| `websocket` | Broadcast WebSocket events | `broadcast_event()` |
|
|
| `camera` | Access camera | (future) |
|
|
| `network_access` | Make network requests | (unrestricted) |
|
|
| `pm3_flash` | Flash PM3 devices | (via hooks) |
|
|
| `script_execution` | Execute user scripts | (sandboxed) |
|
|
|
|
**Note:** Hardware permissions (`gpio`, `i2c`, `spi`, `serial`) require user consent at install time.
|
|
Attempting to use hardware methods without the required permission raises `PermissionError`.
|
|
|
|
## Hardware Libraries
|
|
|
|
Plugins can depend on these for hardware access:
|
|
- `RPi.GPIO` - GPIO pin control
|
|
- `smbus2` - I2C communication
|
|
- `spidev` - SPI communication
|
|
- `gpiozero` - Higher-level GPIO abstraction
|
|
- `pyserial` - Serial/UART communication
|
|
- `opencv-python-headless` - Camera/image processing
|
|
|
|
## Key Files
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `app/backend/managers/plugin_manager.py` | Core plugin framework, widgets, permissions |
|
|
| `app/backend/services/hardware_service.py` | Hardware access layer (I2C, GPIO, SPI, Serial) |
|
|
| `app/backend/websocket/notifications.py` | WebSocket event broadcasting |
|
|
| `app/backend/api/plugins.py` | Plugin API endpoints |
|
|
| `app/backend/api/system.py` | Widget API endpoints (`/api/system/widgets`) |
|
|
| `app/frontend/app/components/HeaderWidgets.tsx` | Widget UI component |
|
|
| `app/plugins/hello_world/` | Reference implementation |
|
|
|
|
## Installation Sources
|
|
|
|
1. **From registry** - Browse webstore → select plugin → auto-install
|
|
2. **Direct URL** - Install from any GitHub release URL
|
|
|
|
## Security Guidelines
|
|
|
|
- Verify SHA256 checksums before extraction
|
|
- Only install pip packages from PyPI
|
|
- Sandbox script execution (no os, sys, subprocess access)
|
|
- Display permissions to user before installation
|
|
- Log all plugin installations
|
|
|
|
## Related Plans
|
|
|
|
See `/home/work/.claude/plans/tranquil-toasting-clover.md` for the full implementation plan including:
|
|
- Multi-Flasher Plugin (parallel PM3 firmware flashing)
|
|
- Color Detector Plugin (webcam color detection + WebREPL)
|