diff --git a/README.md b/README.md index bc2e793..8abc7ba 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,126 @@ -# notify-gateway +# Notify Gateway +Go-Gateway mit ntfy-, Gotify-, Webhook-, IMAP- und Discord-Eingängen. Regeln verteilen Nachrichten über eine persistente Outbox an Divera247, Discord, HTTP-Webhooks, SMTP, ntfy und Gotify. + +**Stand:** `0.1.0-alpha.5` – mit SQLite-Outbox, Wiederholungen, Deduplizierung und Zustellhistorie. Standardmäßig ist `divera.dry_run=true`; zusätzliche Ausgänge starten mit `live=false`. + +## Ausgänge einrichten + +1. Unter **Ausgänge** einen Ausgang anlegen: Name, eindeutige ID, Provider und dessen Verbindungsdaten. +2. Unter **Zuordnungen** als Ziel **Discord**, **HTTP-Webhook**, **SMTP**, **ntfy** oder **Gotify** und den Ausgang wählen. Quelle, Filter und Titel-/Text-Templates konfigurieren. +3. Mit **Regel prüfen** das Payload ansehen, anschließend speichern. Eingehende Testmeldungen erzeugen im Dry-Run ein Ergebnis ohne Netzwerkversand. +4. Für echten Versand **Live-Versand aktivieren** am jeweiligen Ausgang einschalten und speichern. Dieser Schalter ist unabhängig von `divera.dry_run`. + +Mehrere passende Regeln erzeugen unabhängige Zustellaufträge. HTTP-Eingänge antworten nach Speicherung mit **202 Accepted** und einer Referenz. Mit `Idempotency-Key` lassen sich Wiederholungen derselben Nachricht deduplizieren. Temporäre Versandfehler werden bis zu achtmal versucht; erfolgreiche Ziele werden dabei nicht erneut versendet. Status und manuelle Wiederholung stehen unter **Zustellhistorie** bereit. + +Discord sendet Titel und Meldung, getrennt durch einen Zeilenumbruch, als Text. Leere Texte und Inhalte über 2000 UTF-16-Codeeinheiten werden abgelehnt, Mentions sind deaktiviert. Der Adapter verwendet `wait=true` für eine bestätigte API-Antwort. Siehe [Discord-Webhooks](https://docs.discord.com/developers/resources/webhook#execute-webhook). + +HTTP-Webhooks erhalten per POST JSON mit `source`, `channel`, `title`, `message`, `address`, `priority`, `tags` und `received_at`. Raw-Eingangsdaten und Divera247-Extras werden nicht automatisch weitergegeben. Weiterleitungen werden blockiert. Die neuen Ausgänge liefern keine Remote-Antworttexte oder Ziel-URLs an den Eingang zurück. + +Beispiele stehen in `config.example.json`. Bestehende Konfigurationen bleiben verwendbar; beim Start entsteht zusätzlich `outbox.db` daneben. Einrichtung von SMTP/IMAP und Discord, Zustellgarantien, Metriken und Backups: [OPERATIONS.md](OPERATIONS.md). Ausbauplan: [PROVIDER_PLAN.md](PROVIDER_PLAN.md). + +## Bereits enthalten + +- Go 1.23+, SQLite ohne CGO, IMAP/MIME und bcrypt als versionierte Go-Abhängigkeiten. +- Persistente, atomar geschriebene JSON-Konfiguration (`0600`). +- Admin-WebUI mit Session-Login, formularbasierter Konfiguration, Passwortwechsel, Divera247-Verbindungstest und Stammdaten-Auswahl. +- Eingangs-Authentifizierung per Bearer-Token, ntfy-kompatiblem Basic-Auth-Passwort bzw. Gotify-`token`/`X-Gotify-Key`. +- ntfy-Publish als Text, JSON und GET-Trigger (`trigger`, `send`, `publish`). +- Gotify-kompatibler `POST /message?token=...` sowie `/in/gotify/message`. +- Generischer `POST/PUT /in/webhook/{channel}` für JSON, Formular- oder Text-Payloads. +- Regel-Engine mit Quelle, Kanal-, Titel- und Meldungs-Regex sowie Mindestpriorität; Regeln werden in der WebUI grafisch bearbeitet und können per Payload-Vorschau getestet werden. +- Mapping auf Divera247 Alarm, Mitteilung (News) oder Termin (Event), inkl. Stichwort, Meldung, Ort, Empfänger-Typ, Einheit(en), Gruppen, Personen, Fahrzeuge und Versandwege. Einheitsübergreifende Zuordnungen können pro Einheit die Empfängerart Alle/Gruppen/Personen setzen. +- Freies `extra`-Objekt je Mapping, um zusätzliche Divera247-Felder ohne Codeänderung zu übergeben. +- Divera247-v2-Client für CRUD, Archivieren, Lesen, Rückmeldungen, Reichweite, Downloads, Anhänge, Alarm schließen, Event-ICS und Pull-Daten. Zusätzlich steht ein generischer Request-Pfad für noch nicht typisierte API-Funktionen bereit. +- Dockerfile, Compose-Beispiel und Unit-Tests. + +## Start + +```bash +export GATEWAY_ADMIN_PASSWORD='ein-langes-einmaliges-passwort' +go run ./cmd/gateway -config ./data/config.json +``` + +Danach: `http://localhost:8080/ui/`. Wenn beim ersten Start kein `GATEWAY_ADMIN_PASSWORD` gesetzt ist, erzeugt das Gateway einmalig ein Admin-Passwort und schreibt es ins Start-Log. + +Die automatisch erzeugte Konfiguration startet mit `divera.dry_run=true`. Erst nach Eintragen des Divera247-Accesskeys und einem erfolgreichen Test sollte Dry-Run deaktiviert werden. + + +## WebUI + +Die WebUI unter `http://localhost:8080/ui/` ist in Bereiche für **Divera247**, **Eingänge**, **Zuordnungen** sowie **Server & Sicherheit** gegliedert. Die Konfiguration erfolgt über Formulare; ein direkter JSON-Editor ist für den normalen Betrieb nicht mehr nötig. + +Unter **Divera247** können Accesskey, UCR, Timeout und Dry-Run gepflegt werden. Die Stammdaten werden primär über die stabile v2-Schnittstelle `pull/all` geladen. Für PRO-/Mehrfacheinheiten wertet das Gateway `data.ucr` aus und lädt jede erreichbare User-Cluster-Relation separat; Benutzer werden aus `data.cluster.consumer` übernommen, wobei der numerische Collection-Key als **UCR-ID** für gezielte Alarmempfänger erhalten bleibt. Der v3-Endpunkt `user-cluster-relations` dient nur noch als Fallback, falls v2 keine Personen liefert. Die Stammdaten stehen anschließend in Zuordnungsregeln als Such- und Auswahlfelder zur Verfügung. Die Regelvorschau zeigt das resultierende Divera247-Payload, ohne es zu versenden. + +## Beispiel: ntfy -> Divera247 Alarm + +In der WebUI oder in `config.json` ein Mapping aktivieren und z. B. einen Token für Topic `alarm` setzen. Anschließend: + +```bash +curl -X POST \ + -H 'Authorization: Bearer replace-me' \ + -H 'Title: FEUER3' \ + -H 'Priority: high' \ + --data 'Unklare Rauchentwicklung' \ + http://localhost:8080/ntfy/alarm +``` + +JSON-Publish ist unter `/ntfy` oder `/in/ntfy` möglich: + +```bash +curl -X POST -H 'Authorization: Bearer replace-me' \ + -H 'Content-Type: application/json' \ + -d '{"topic":"alarm","title":"TH1","message":"Baum auf Straße","priority":4}' \ + http://localhost:8080/ntfy +``` + +## Beispiel: Gotify + +```bash +curl -X POST 'http://localhost:8080/message?token=replace-me' \ + -H 'Content-Type: application/json' \ + -d '{"title":"Meldung","message":"Test","priority":5}' +``` + +## Konfigurationsmodell + +Die Datei `config.example.json` zeigt das vollständige derzeitige Schema. Ein Mapping kann insbesondere diese Divera247-Ziele setzen: + +- `target`: `alarm`, `news`, `event` +- `title_template`, `text_template`, `address_template` +- `notification_type`: 1 Einheit/Standort, 2 alle, 3 Gruppen, 4 Benutzer (entsprechend Divera247) +- `cluster_routes` (empfohlen für einheitsübergreifend, z. B. `{"123": 2}`), alternativ `clusters`, sowie `groups`, `users`, `vehicles` +- `send_push`, `send_sms`, `send_call`, `send_mail`, `send_pager` +- `private_mode` +- `extra`: zusätzliche API-Felder (z. B. `foreign_id`, `priority`, `response_time`, Event-Zeitstempel usw.) + +Templates sind Go-`text/template` und erhalten das normalisierte Eingangsobjekt (`.Source`, `.Channel`, `.Title`, `.Message`, `.Address`, `.Priority`, `.Tags`, `.Raw`, `.ReceivedAt`). + +## Sicherheitshinweise zum Alpha-Stand + +- Die WebUI gehört hinter TLS (Reverse Proxy oder direkt späterer TLS-Support). +- Divera247-Accesskey und Ingress-Tokens liegen derzeit in der Konfigurationsdatei; Dateirechte werden auf `0600` gesetzt. Secret-Verschlüsselung/Secret-Store ist ein geplanter Schritt. +- Neue Passwörter verwenden bcrypt; vorhandene SHA-256-Hashes werden beim Login migriert. CSRF-Schutz, CSP, Größenlimits und Login-Rate-Limit sind integriert. +- Für echte Alarmierung zuerst mit einer Divera247-Testeinheit und `dry_run=true` prüfen. + +Siehe `PROJECT_PLAN.md` und `API_SUPPORT.md` für Roadmap und Abdeckungsstand. + +## Entwicklung prüfen + +```sh +go test ./... +go vet ./... +node scripts/check-ui.cjs +``` + +Die Provider-Tests verwenden lokale HTTP-Testserver und Dry-Run; echte Nachrichten +werden dabei nicht versendet. Die UI-Prüfung kontrolliert JavaScript-Syntax und +eindeutige DOM-IDs. Zusätzlich existiert ein Browser-Test mit Chrome/Edge: + +```sh +go build -o .cache/gateway-smoke.exe ./cmd/gateway +node scripts/browser-smoke.cjs +``` + +Er startet eine separate Testinstanz mit eigenem Profil und Dry-Run und prüft +Login, Formulare, Vorschau, Speichern und Zustellhistorie.