## Summary
Adds a new `slack` target type that sends webhook events as formatted messages to any Slack-compatible incoming webhook URL (Slack, Mattermost, and other compatible services).
closes#44
## What it does
When a webhook event is received, the Slack target:
1. Formats a human-readable message with event metadata (HTTP method, content type, timestamp, body size)
2. Pretty-prints the payload in a code block — JSON payloads get indented formatting, non-JSON payloads are shown as raw text
3. Truncates large payloads at 3500 characters to keep Slack messages reasonable
4. POSTs the message as a `{"text": "..."}` JSON payload to the configured webhook URL
## Changes
- **`internal/database/model_target.go`** — Add `TargetTypeSlack` constant
- **`internal/delivery/engine.go`** — Add `SlackTargetConfig` struct, `deliverSlack` method, `FormatSlackMessage` function (exported), `parseSlackConfig` helper. Route slack targets in `processDelivery` switch.
- **`internal/handlers/source_management.go`** — Handle `slack` type in `HandleTargetCreate`, building `webhook_url` config from the URL form field
- **`templates/source_detail.html`** — Add "Slack" option to target type dropdown with URL field and helper text
- **`README.md`** — Document the new target type, update roadmap
## Tests
- `TestParseSlackConfig_Valid` / `_Empty` / `_MissingWebhookURL` — Config parsing
- `TestFormatSlackMessage_JSONBody` / `_NonJSONBody` / `_EmptyBody` / `_LargeJSONTruncated` — Message formatting
- `TestDeliverSlack_Success` / `_Failure` / `_InvalidConfig` — End-to-end delivery
- `TestProcessDelivery_RoutesToSlack` — Routing from processDelivery switch
All existing tests continue to pass. `docker build .` (which runs `make check`) passes clean.
Co-authored-by: user <user@Mac.lan guest wan>
Reviewed-on: #47
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
Security hardening implementing three issues:
CSRF Protection (#35):
- Session-based CSRF tokens with cryptographically random generation
- Constant-time token comparison to prevent timing attacks
- CSRF middleware applied to /pages, /sources, /source, and /user routes
- Hidden csrf_token field added to all 12+ POST forms in templates
- Excluded from /webhook (inbound) and /api (stateless) routes
SSRF Prevention (#36):
- ValidateTargetURL blocks private/reserved IP ranges at target creation
- Blocked ranges: 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12,
192.168.0.0/16, 169.254.0.0/16, ::1, fc00::/7, fe80::/10, plus
multicast, reserved, test-net, and CGN ranges
- SSRF-safe HTTP transport with custom DialContext for defense-in-depth
at delivery time (prevents DNS rebinding attacks)
- Only http/https schemes allowed
Login Rate Limiting (#37):
- Per-IP rate limiter using golang.org/x/time/rate
- 5 attempts per minute per IP on POST /pages/login
- GET requests (form rendering) pass through unaffected
- Automatic cleanup of stale per-IP limiter entries
- X-Forwarded-For and X-Real-IP header support for reverse proxies
Closes#35, closes#36, closes#37
Add toggle (activate/deactivate) and delete buttons for individual
entrypoints and targets on the webhook detail page. Each action is a
POST form submission with ownership verification.
New routes:
POST /source/{id}/entrypoints/{entrypointID}/delete
POST /source/{id}/entrypoints/{entrypointID}/toggle
POST /source/{id}/targets/{targetID}/delete
POST /source/{id}/targets/{targetID}/toggle