feat(webhooks): security hardening, tests, full documentation audit & polish (Phase 6)
Build and Push Docker Image / build (push) Successful in 41s
Docs Check / Markdown lint (push) Successful in 48s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 57s
CI / Security audit (push) Successful in 1m23s
CI / Tests & coverage (push) Successful in 1m36s
Docs Check / Mermaid diagram parse check (push) Successful in 1m43s
Build and Push Docker Image / build (push) Successful in 41s
Docs Check / Markdown lint (push) Successful in 48s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 57s
CI / Security audit (push) Successful in 1m23s
CI / Tests & coverage (push) Successful in 1m36s
Docs Check / Mermaid diagram parse check (push) Successful in 1m43s
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
|
||||
**sofarr** is a personal media download dashboard that aggregates and displays real-time download progress from all your media automation services. Named for the experience of checking what has downloaded "so far" while you wait comfortably on your "sofa" for Sonarr, Radarr, and your download clients to do their thing!
|
||||
|
||||
Version 1.4.x adds **real-time webhook integration**: Sonarr and Radarr can push events directly to sofarr, eliminating polling latency and automatically reducing background API calls when webhooks are active.
|
||||
|
||||
## What It Does
|
||||
|
||||
sofarr connects to your media stack and shows you a personalized view of:
|
||||
@@ -12,27 +14,59 @@ sofarr connects to your media stack and shows you a personalized view of:
|
||||
- **Recently Completed** - History tab showing imported and failed downloads from Sonarr/Radarr with deduplication and upgrade-awareness
|
||||
- **User Matching** - Downloads are matched to you based on tags in Sonarr/Radarr
|
||||
- **Multi-Instance Support** - Connect to multiple instances of each service
|
||||
- **Webhook Push Updates** - Sonarr/Radarr push events instantly to sofarr; dashboard updates in < 1s after a grab or import
|
||||
- **Smart Polling** - Background polling automatically reduces (or skips) API calls for instances with active webhooks, with configurable fallback
|
||||
|
||||
## How It Works
|
||||
|
||||
### Architecture Overview
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌──────────────┐ ┌─────────────────────────────┐
|
||||
│ Browser │────▶│ sofarr │────▶│ SABnzbd (Usenet downloads) │
|
||||
│ (User) │◀────│ Server │ │ qBittorrent (Torrents) │
|
||||
└─────────────┘ └──────────────┘ │ Transmission (Torrents) │
|
||||
│ │ rTorrent (Torrents) │
|
||||
│ │ Sonarr (TV management) │
|
||||
│ │ Radarr (Movie management) │
|
||||
│ │ Emby (User authentication) │
|
||||
▼ └─────────────────────────────┘
|
||||
┌──────────────┐
|
||||
│ Dashboard │
|
||||
│ Aggregator │
|
||||
└──────────────┘
|
||||
┌─────────────┐ ┌──────────────────────────────────────────────┐
|
||||
│ Browser │────▶│ sofarr Server │
|
||||
│ (User) │◀────│ Auth · Dashboard · History · Webhooks │
|
||||
└─────────────┘ │ │
|
||||
SSE push ◀───────│ Poller (smart: skips when webhooks active) │
|
||||
│ Cache · PDCA Download Registry · PALDRA │
|
||||
└───┬─────────────────────────┬────────────────┘
|
||||
│ polls (background) │ receives webhooks
|
||||
▼ │
|
||||
┌──────────────────────────┐ ┌─────────▼───────────────────┐
|
||||
│ Download Clients │ │ *arr Services │
|
||||
│ SABnzbd (Usenet) │ │ Sonarr (TV management) │
|
||||
│ qBittorrent (Torrent) │◀───│ Radarr (Movie management) │
|
||||
│ Transmission (Torrent) │ └─────────────────────────────┘
|
||||
│ rTorrent (Torrent) │
|
||||
└──────────────────────────┘
|
||||
│
|
||||
Emby / Jellyfin
|
||||
(User authentication)
|
||||
```
|
||||
|
||||
**Three pluggable layers power sofarr:**
|
||||
|
||||
| Layer | Name | What it does |
|
||||
|-------|------|--------------|
|
||||
| Download clients | **PDCA** (Pluggable Download Client Architecture) | Normalised interface for SABnzbd, qBittorrent, Transmission, rTorrent; easy to add new clients |
|
||||
| *arr data retrieval | **PALDRA** (Pluggable *Arr Library Data Retrieval Architecture) | Unified fetch layer for Sonarr/Radarr queue, history, and tags across multiple instances |
|
||||
| Real-time push | **Webhook receiver** | Sonarr/Radarr POST events to sofarr; cache updated immediately; SSE pushes to browser in < 1s |
|
||||
|
||||
### Webhooks
|
||||
|
||||
When webhooks are configured, sofarr receives instant push notifications from Sonarr and Radarr whenever a download is grabbed, imported, failed, or renamed. The dashboard updates in under a second — no polling delay.
|
||||
|
||||
**Quick setup:**
|
||||
1. Set `SOFARR_WEBHOOK_SECRET` and `SOFARR_BASE_URL` in your `.env`
|
||||
2. Open the sofarr dashboard → **Webhooks Configuration** panel
|
||||
3. Click **Enable** next to each Sonarr/Radarr instance
|
||||
4. sofarr auto-configures the notification connection inside each *arr service
|
||||
|
||||
**Smart polling fallback:** Once webhooks are active, the background poller automatically skips queue/history API calls for those instances. If no webhook events arrive for `WEBHOOK_FALLBACK_TIMEOUT` minutes (default: 10), the poller resumes a full poll automatically.
|
||||
|
||||
**Webhook endpoints** (no user authentication required — protected by `X-Sofarr-Webhook-Secret`):
|
||||
- `POST /api/webhook/sonarr` — receives Sonarr events
|
||||
- `POST /api/webhook/radarr` — receives Radarr events
|
||||
|
||||
### The Matching Process
|
||||
|
||||
1. **User Authentication**: Login via Emby credentials
|
||||
@@ -194,6 +228,17 @@ POLL_INTERVAL=5000 # Background polling interval in ms (default
|
||||
# Set to 0 or "off" to disable (on-demand mode)
|
||||
```
|
||||
|
||||
### Webhooks & Smart Polling
|
||||
```bash
|
||||
# Required for webhook endpoints to accept events
|
||||
SOFARR_WEBHOOK_SECRET=your-secret # Shared secret (generate: openssl rand -hex 32)
|
||||
SOFARR_BASE_URL=https://sofarr.example.com # Public URL used by one-click setup
|
||||
|
||||
# Optional tuning
|
||||
WEBHOOK_FALLBACK_TIMEOUT=10 # Minutes without a webhook before forcing a full poll (default: 10)
|
||||
WEBHOOK_POLL_INTERVAL_MULTIPLIER=3 # Internal multiplier used by the skip logic (default: 3)
|
||||
```
|
||||
|
||||
### Download Clients (PDCA)
|
||||
|
||||
sofarr uses a **Pluggable Download Client Architecture (PDCA)** that provides a unified interface for all download clients. This enables consistent data normalization, easy addition of new client types, and centralized configuration management.
|
||||
@@ -327,6 +372,20 @@ sofarr polls all configured services in the background and caches the results. D
|
||||
### History
|
||||
- `GET /api/history/recent` — Recently completed downloads from Sonarr/Radarr history
|
||||
|
||||
### Webhook Receiver (no user auth — protected by `X-Sofarr-Webhook-Secret`)
|
||||
- `POST /api/webhook/sonarr` — receive Sonarr webhook events
|
||||
- `POST /api/webhook/radarr` — receive Radarr webhook events
|
||||
|
||||
### Webhook Management (requires auth + CSRF)
|
||||
- `GET /api/sonarr/api/v3/notification` — list Sonarr notification connections
|
||||
- `POST /api/sonarr/api/v3/notification` — create/update Sonarr notification connection
|
||||
- `GET /api/radarr/api/v3/notification` — list Radarr notification connections
|
||||
- `POST /api/radarr/api/v3/notification` — create/update Radarr notification connection
|
||||
- `POST /api/sonarr/webhook/enable` — one-click enable Sofarr webhook in Sonarr
|
||||
- `POST /api/radarr/webhook/enable` — one-click enable Sofarr webhook in Radarr
|
||||
- `POST /api/sonarr/webhook/test` — trigger a Sonarr test event
|
||||
- `POST /api/radarr/webhook/test` — trigger a Radarr test event
|
||||
|
||||
### Service APIs (proxy to your services)
|
||||
- `GET /api/sabnzbd/*` — SABnzbd API proxy
|
||||
- `GET /api/sonarr/*` — Sonarr API proxy
|
||||
@@ -370,7 +429,7 @@ npm run test:coverage # with V8 coverage report (outputs to coverage/)
|
||||
npm run test:ui # interactive Vitest UI
|
||||
```
|
||||
|
||||
145 tests across 10 test files covering the security-critical paths: auth middleware, CSRF protection, secret sanitization, config parsing, token store, qBittorrent utilities, and history deduplication/classification. See [`tests/README.md`](tests/README.md) for design decisions and coverage targets.
|
||||
290 tests across 18 test files covering auth middleware, CSRF protection, secret sanitization, config parsing, token store, qBittorrent utilities, history deduplication/classification, download client architecture, webhook endpoint security, input validation, replay protection, and webhook metrics integration. See [`tests/README.md`](tests/README.md) for design decisions and coverage targets.
|
||||
|
||||
## Development
|
||||
|
||||
|
||||
Reference in New Issue
Block a user