diff --git a/README.md b/README.md index ffdb7f4..ba4ab52 100644 --- a/README.md +++ b/README.md @@ -1,94 +1,835 @@ # archivmail -Selbst gehostetes Mail-Archiv-System für Unternehmen. E-Mails werden aus IMAP, SMTP und EML/MBOX-Quellen importiert, volltext-indexiert (Xapian) und verschlüsselt archiviert. +Ein selbst gehostetes, unternehmenstaugliches Mail-Archiv-System. Empfängt E-Mails über SMTP (BCC-Journaling), IMAP oder Datei-Upload, speichert sie verschlüsselt, indexiert sie für Volltextsuche und stellt sie über eine Web-Oberfläche zur Verfügung. -## Features +--- -- Import via IMAP, SMTP-Journaling und EML/MBOX-Upload -- Volltext-Suche über Xapian -- AES-256-GCM-Verschlüsselung der archivierten Mails -- Anhang-Deduplizierung -- Rollenmodell: `user`, `auditor`, `admin` -- Audit-Log (PostgreSQL + Append-only Logdatei) +## Inhaltsverzeichnis + +- [Funktionsübersicht](#funktionsübersicht) +- [Architektur](#architektur) +- [Voraussetzungen](#voraussetzungen) +- [Installation](#installation) +- [Konfiguration](#konfiguration) +- [Systemd-Dienste](#systemd-dienste) +- [Funktionen im Detail](#funktionen-im-detail) + - [Authentifizierung & Rollen](#authentifizierung--rollen) + - [SMTP-Eingang (BCC-Journaling)](#smtp-eingang-bcc-journaling) + - [IMAP-Import & Auto-Sync](#imap-import--auto-sync) + - [EML/MBOX Web-Upload](#emlmbox-web-upload) + - [Speicherung & Verschlüsselung](#speicherung--verschlüsselung) + - [Volltext-Suche](#volltext-suche) + - [E-Mail-Ansicht](#e-mail-ansicht) + - [E-Mail-Export](#e-mail-export) + - [Admin-Dashboard](#admin-dashboard) + - [Audit-Log](#audit-log) + - [Integritätsprüfung](#integritätsprüfung) + - [CLI Import & Export](#cli-import--export) + - [Mailpiler Migration](#mailpiler-migration) +- [REST API](#rest-api) +- [In Entwicklung](#in-entwicklung) +- [Update](#update) + +--- + +## Funktionsübersicht + +| Funktion | Status | +|----------|--------| +| Authentifizierung & Rollen (Admin / Auditor / User) | ✅ Deployed | +| SMTP-Eingang via BCC-Journaling | ✅ Deployed | +| IMAP-Import manuell & automatischer Sync | ✅ Deployed | +| EML/MBOX Web-Upload (Admin) | ✅ Deployed | +| AES-256-GCM verschlüsselte Speicherung | ✅ Deployed | +| Xapian Volltext-Indexierung (async) | ✅ Deployed | +| Volltext-Suche mit Filtern & Sortierung | ✅ Deployed | +| E-Mail-Ansicht mit HTML-Sandbox | ✅ Deployed | +| E-Mail-Export als EML / PDF / ZIP | ✅ Deployed | +| Admin-Dashboard (CPU, RAM, Disk, Archiv-Stats) | ✅ Deployed | +| Audit-Log (Suche, Login, Import, Export) | ✅ Deployed | +| SHA-256 Integritätsprüfung | ✅ Deployed | +| CLI: `archivmail import` / `export` | ✅ Deployed | +| Mailpiler → archivmail Migration | ✅ Deployed | +| Dienste-Verwaltung im Admin-Bereich | ✅ Deployed | +| Ordner- & Label-Verwaltung | 🔄 In Progress | +| POP3-Import | 🔄 In Progress | +| REST API für externe Anbindung (CRM) | 🔄 In Progress | +| LDAP / Active Directory | 🔄 In Progress | + +--- + +## Architektur + +``` + ┌─────────────────────────────────────┐ + │ archivmail (Go-Binary) │ + │ │ + Postfix BCC ──┤── SMTP-Daemon (Port 2525) │ + IMAP-Server ──┤── IMAP-Importer + Scheduler │──► PostgreSQL + Web-Upload ──┤── HTTP API (Port 8080) │ (Metadaten) + │ │ │ + │ ▼ │──► /var/archivmail/store + │ Async Index Worker │ (AES-256-GCM) + │ │ │ + │ ▼ │──► /var/archivmail/xapian + │ Xapian Index │ (Volltext-Index) + └─────────────────────────────────────┘ + ▲ + │ /api/* + ┌─────────────────────────────────────┐ + │ Next.js Frontend (Port 3000) │ + │ / /search /mail/[id] /admin │ + │ /imap │ + └─────────────────────────────────────┘ +``` + +**Komponenten:** + +| Komponente | Technologie | Beschreibung | +|------------|-------------|--------------| +| Backend | Go 1.23 | REST API, SMTP-Daemon, IMAP-Importer, Storage, Indexierung | +| Frontend | Next.js 16 (TypeScript) | Web-Oberfläche, Tailwind CSS, shadcn/ui | +| Datenbank | PostgreSQL | Metadaten, Benutzer, Audit-Log, Session-Blacklist | +| Volltextsuche | Xapian | BM25-Ranking, Wildcards, Feldpräfixe | +| Speicherung | Dateisystem | AES-256-GCM verschlüsselt, SHA-256 Integrität | + +--- + +## Voraussetzungen + +**Server:** +- Debian 12 / Ubuntu 22.04 oder neuer +- Go ≥ 1.23 (mit CGO für Xapian) +- Node.js ≥ 20 +- PostgreSQL ≥ 14 +- libxapian-dev + +**Ports (Standard):** +- `8080` – HTTP API (Backend) +- `3000` – Web-Frontend +- `2525` – SMTP-Eingang (BCC-Journaling) + +--- ## Installation +### Automatisch (empfohlen) + ```bash -# Systembenutzer anlegen -useradd -r -s /sbin/nologin archivmail - -# Verzeichnisse anlegen -mkdir -p /etc/archivmail -mkdir -p /var/archivmail/store -mkdir -p /var/archivmail/astore -mkdir -p /var/lib/archivmail/xapian -mkdir -p /var/log/archivmail - -# Berechtigungen setzen -chown -R archivmail:archivmail /var/archivmail /var/lib/archivmail /var/log/archivmail - -# Encryption Key generieren -openssl rand -base64 32 > /etc/archivmail/keyfile -chmod 400 /etc/archivmail/keyfile -chown archivmail:archivmail /etc/archivmail/keyfile - -# Konfiguration -cp config.example.yml /etc/archivmail/config.yml -# config.yml anpassen (Datenbank, SMTP-Port, etc.) - -# Systemd-Service aktivieren -cp archivmail.service /lib/systemd/system/ -systemctl daemon-reload -systemctl enable --now archivmail +curl -fsSL https://gitea.perlbach24.de/scripte/archivmail/raw/branch/main/update.sh | bash ``` -## Verzeichnisstruktur +Das Skript: +1. Klont/aktualisiert den Quellcode +2. Baut Backend (Go + CGO/Xapian) und Frontend (Next.js) +3. Stoppt Dienste, spielt Binaries ein, startet Dienste neu +4. Führt Datenbankmigrationen durch -``` -/etc/archivmail/ -├── config.yml # Hauptkonfiguration -└── keyfile # AES-256-GCM Key (chmod 400) +### Manuell -/var/archivmail/ -├── store/ # Mailkörper (.m, verschlüsselt) -│ └── ///xxxxx.m -└── astore/ # Anhänge dedupliziert (verschlüsselt) - └── +```bash +# Quellcode +git clone https://gitea.perlbach24.de/scripte/archivmail.git /opt/archivmail/_build +cd /opt/archivmail/_build -/var/lib/archivmail/ -└── xapian/ # Volltext-Index +# Backend bauen +CGO_ENABLED=1 go build -tags xapian -buildvcs=false \ + -o /opt/archivmail/bin/archivmail ./cmd/archivmail/ -/var/log/archivmail/ -└── audit.log # Audit-Log (JSON Lines, append-only) +# Frontend bauen +npm ci && npm run build +rsync -a --delete .next/standalone/ /opt/archivmail/web/ +rsync -a --delete .next/static/ /opt/archivmail/web/.next/static/ ``` -## Standard-Zugangsdaten +### Konfigurationsdatei anlegen -> **Wichtig:** Passwörter nach dem ersten Login ändern! +```bash +mkdir -p /etc/archivmail /var/archivmail/{store,astore,xapian} /var/log/archivmail -| Benutzer | Passwort | Rolle | -|----------|----------|-------| -| `admin@archivmail` | `archivmailrockz` | Admin (Konfiguration, Nutzerverwaltung) | -| `auditor@archivmail` | `archivmailrockz` | Auditor (alle E-Mails + Audit-Log) | +cat > /etc/archivmail/config.yml << 'EOF' +server: + api_port: 8080 + smtp_port: 2525 -### Rollenübersicht +database: + host: 127.0.0.1 + port: 5432 + name: archivmail + user: archivmail + password: SICHERES_PASSWORT + sslmode: disable -| Rolle | E-Mails (eigene) | E-Mails (alle) | Audit-Log | Konfiguration | -|-------|:-:|:-:|:-:|:-:| -| `user` | ✅ | ❌ | ❌ | ❌ | -| `auditor` | ✅ | ✅ | ✅ | ❌ | -| `admin` | ❌ | ❌ | ❌ | ✅ | +storage: + store_path: /var/archivmail/store + astore_path: /var/archivmail/astore + xapian_path: /var/archivmail/xapian + keyfile: /etc/archivmail/keyfile -## Technologie +audit: + log_path: /var/log/archivmail/audit.log + retention_days: 0 -| Komponente | Technologie | -|-----------|-------------| -| Backend | Go | -| Datenbank | PostgreSQL | -| Volltext-Index | Xapian | -| Verschlüsselung | AES-256-GCM | -| Webserver | eingebettet (Go net/http) | +smtp: + enabled: true + bind: ":2525" + domain: "archivmail.firma.de" + allowed_ips: + - 127.0.0.1 + - 192.168.1.0/24 # Postfix-Server-IP(s) -## Lizenz +api: + bind: ":8080" + secret: ZUFAELLIGER_JWT_SECRET_MINDESTENS_32_ZEICHEN -Proprietär +index: + path: /var/archivmail/xapian + backend: xapian + batch_size: 100 + async_queue_size: 1000 +EOF + +# AES-256 Schlüssel generieren +dd if=/dev/urandom bs=32 count=1 > /etc/archivmail/keyfile +chmod 600 /etc/archivmail/keyfile +``` + +--- + +## Konfiguration + +### Vollständige Konfigurationsreferenz + +```yaml +server: + api_port: 8080 # HTTP-API Port + smtp_port: 2525 # SMTP-Eingang Port (Fallback wenn smtp.bind nicht gesetzt) + +database: + host: 127.0.0.1 + port: 5432 + name: archivmail + user: archivmail + password: "" + sslmode: disable # disable | require | verify-full + +storage: + store_path: /var/archivmail/store # Haupt-Mailspeicher (AES-256-GCM) + astore_path: /var/archivmail/astore # Anhang-Speicher + xapian_path: /var/archivmail/xapian # Xapian-Datenbankpfad (auch in index.path) + keyfile: /etc/archivmail/keyfile # 32-Byte AES-Schlüsseldatei + +smtp: + enabled: true + bind: ":2525" # TCP-Adresse zum Lauschen + domain: "archivmail" # EHLO-Domainname + tls_cert: "" # Pfad zum TLS-Zertifikat (leer = kein TLS) + tls_key: "" # Pfad zum TLS-Schlüssel + max_size_mb: 50 # Maximale E-Mail-Größe in MB + allowed_ips: # Nur diese IPs dürfen zustellen + - 127.0.0.1 + +api: + bind: ":8080" + secret: "" # JWT-Signaturschlüssel (mind. 32 Zeichen, zufällig) + +index: + path: /var/archivmail/xapian + backend: xapian # xapian (einziger unterstützter Backend) + batch_size: 100 # Dokumente pro Index-Batch + async_queue_size: 1000 # Größe der asynchronen Index-Queue + +audit: + log_path: /var/log/archivmail/audit.log + retention_days: 0 # 0 = unbegrenzt + +logging: + path: "" # leer = stdout + level: info # debug | info | warn | error +``` + +--- + +## Systemd-Dienste + +Das System läuft mit zwei Systemd-Units: + +| Dienst | Beschreibung | Port | +|--------|--------------|------| +| `archivmail` | Go-Backend (API + SMTP + IMAP-Scheduler) | 8080, 2525 | +| `archivmail-web` | Next.js-Frontend | 3000 | + +```bash +# Status prüfen +systemctl status archivmail archivmail-web + +# Logs +journalctl -u archivmail -f +journalctl -u archivmail-web -f + +# Neustart +systemctl restart archivmail archivmail-web +``` + +--- + +## Funktionen im Detail + +### Authentifizierung & Rollen + +**Rollen:** + +| Rolle | Rechte | +|-------|--------| +| `admin` | Vollzugriff: Benutzer verwalten, IMAP einrichten, Dienste steuern, alles suchen/exportieren | +| `auditor` | Audit-Log lesen, alle E-Mails suchen und exportieren | +| `user` | Nur eigene E-Mails suchen und lesen (Matching auf E-Mail-Adresse) | + +**Sicherheit:** +- Passwörter mit bcrypt (Cost 12) +- Sessions als httpOnly SameSite=Strict Cookie (`archivmail_session`) +- JWT mit zufälligem JTI (kryptografische Entropie, 16 Byte) +- Token-Blacklist in PostgreSQL (Logout invalidiert Token sofort) +- Rate-Limiting: max. 5 Fehlversuche in 15 Minuten → HTTP 429 +- Login-Versuche in `login_attempts`-Tabelle protokolliert +- Letzter Login wird gespeichert (`last_login_at`) + +**Erstmalige Einrichtung:** + +Beim ersten Start werden automatisch zwei Benutzer mit zufälligen Passwörtern angelegt: + +``` +╔══════════════════════════════════════════════════════════════╗ +║ ARCHIVMAIL — ERSTMALIGE EINRICHTUNG ║ +║ Initiale Zugangsdaten (NUR EINMAL ANGEZEIGT): ║ +║ admin : ║ +║ auditor : ║ +║ Passwörter sofort nach dem ersten Login ändern! ║ +╚══════════════════════════════════════════════════════════════╝ +``` + +--- + +### SMTP-Eingang (BCC-Journaling) + +Der eingebettete SMTP-Daemon empfängt E-Mails von Postfix (oder anderem MTA) über BCC-Weiterleitung. + +**Funktionsweise:** +``` +Absender → Postfix → Empfänger + │ + └── always_bcc → archivmail SMTP (Port 2525) + │ + ▼ + Speicherung + Indexierung +``` + +**Postfix-Konfiguration (`/etc/postfix/main.cf`):** +``` +# Alle ausgehenden Mails archivieren: +always_bcc = archiv@archivmail-host + +# Oder granular per Nutzer: +sender_bcc_maps = hash:/etc/postfix/sender_bcc +``` + +**Sicherheit:** +- Kein SMTP AUTH – Vertrauen ausschließlich über IP-Allowlist +- IP-Allowlist in `smtp.allowed_ips` konfigurieren +- 250 OK erst nach erfolgreicher Speicherung (kein Datenverlust) +- 250 OK auch bei Duplikaten (Postfix stellt nicht erneut zu) +- Maximale E-Mail-Größe konfigurierbar (`smtp.max_size_mb`, Standard: 50 MB) +- Optionale TLS/STARTTLS-Unterstützung (`smtp.tls_cert` / `smtp.tls_key`) + +**API-Endpunkt:** +``` +GET /api/admin/smtp/status +``` + +--- + +### IMAP-Import & Auto-Sync + +E-Mails von IMAP-Postfächern importieren – einmalig (Altbestände) oder automatisch als Hintergrundjob. + +**Verbindung einrichten (Web-UI unter `/imap`):** + +| Feld | Beschreibung | +|------|--------------| +| Name | Bezeichnung der Verbindung | +| Host / Port | IMAP-Server-Adresse | +| TLS | `ssl` (IMAPS), `starttls`, `none` | +| Benutzername / Passwort | IMAP-Zugangsdaten (Passwort AES-256-GCM verschlüsselt in DB) | +| Ausgeschlossene Ordner | Ordner die nicht importiert werden | + +**Sync-Intervall:** + +| Wert | Verhalten | +|------|-----------| +| 0 | Automatischer Sync deaktiviert | +| 5–1440 | Sync alle N Minuten (Hintergrund-Goroutine) | + +**Inkrementeller Sync:** +- UID-basiert: Nur neue Nachrichten seit letztem Sync werden heruntergeladen +- Exponentielles Backoff bei Fehlern: 1s → 60s → 300s (3 Versuche) +- Duplikat-Erkennung via Content-Hash + +**API-Endpunkte:** +``` +GET /api/imap # Verbindungen auflisten +POST /api/imap # Neue Verbindung anlegen +DELETE /api/imap/{id} # Verbindung löschen +PATCH /api/imap/{id} # Sync-Intervall ändern +POST /api/imap/test # Verbindung testen + Ordner auflisten +POST /api/imap/{id}/import # Vollständigen Import starten +GET /api/imap/{id}/progress # Import-Fortschritt abfragen +POST /api/imap/{id}/sync # Manuellen inkrementellen Sync auslösen +``` + +--- + +### EML/MBOX Web-Upload + +E-Mails direkt über die Admin-Oberfläche hochladen (Tab „Import" unter `/admin`). + +**Unterstützte Formate:** +- `.eml` – einzelne RFC-2822 E-Mail +- `.mbox` – MBOX-Datei mit beliebig vielen E-Mails + +**Ablauf:** +1. Dateien per Drag-and-Drop oder Datei-Dialog hochladen +2. Backend startet Hintergrund-Import-Job, gibt sofort `job_id` zurück +3. Frontend pollt alle 1,5 Sekunden den Fortschritt +4. Abschlussbericht: Importiert / Übersprungen (Duplikate) / Fehler + +**API-Endpunkte:** +``` +POST /api/admin/upload # Multipart-Upload starten +GET /api/admin/upload/{jobID}/progress # Fortschritt abfragen +``` + +--- + +### Speicherung & Verschlüsselung + +Alle E-Mails werden verschlüsselt auf dem Dateisystem gespeichert. + +**Verschlüsselung:** +- Algorithmus: AES-256-GCM (authentifizierte Verschlüsselung) +- Schlüssel: 32-Byte-Datei (`keyfile` in Konfiguration) +- Nonce: 12 Byte, kryptografisch zufällig, pro E-Mail neu generiert +- Dateiformat: `[12-Byte Nonce][verschlüsselte Daten]` + +**Datei-ID / Integrität:** +- Jede E-Mail erhält als ID den SHA-256-Hash des Klartexts +- Duplikat-Erkennung: gleicher Hash → gleiche Datei, Speicherung übersprungen +- ID dient gleichzeitig als Integritätsnachweis + +**PostgreSQL-Metadaten (`emails`-Tabelle):** + +| Spalte | Typ | Beschreibung | +|--------|-----|--------------| +| `id` | TEXT PK | SHA-256 Hash des E-Mail-Rohtexts | +| `from_addr` | TEXT | Absender | +| `to_addrs` | TEXT[] | Empfänger | +| `subject` | TEXT | Betreff | +| `message_id` | TEXT | RFC-2822 Message-ID | +| `mail_date` | TIMESTAMPTZ | Sendedatum | +| `size_bytes` | INTEGER | Größe in Bytes | +| `has_attachments` | BOOLEAN | Hat Anhänge | +| `stored_at` | TIMESTAMPTZ | Archivierungszeitpunkt | +| `indexed_at` | TIMESTAMPTZ | Indexierungszeitpunkt (NULL = ausstehend) | +| `verify_ok` | BOOLEAN | Letztes Integritätsprüfungsergebnis | +| `verified_at` | TIMESTAMPTZ | Zeitpunkt der letzten Prüfung | + +**Async Index Worker:** +- Eingehende E-Mails werden sofort gespeichert +- Indexierung erfolgt asynchron über einen Go-Channel (Queue-Größe: 1000) +- Backfill beim Start: Nicht indexierte E-Mails werden nachindexiert + +--- + +### Volltext-Suche + +Suche über alle archivierten E-Mails per Xapian-Index unter `/search`. + +**Suchfelder:** +- Freitext (durchsucht Betreff, Body, Absender, Empfänger, Anhangsnamen) +- Absender-Filter (`from`) +- Empfänger-Filter (`to`) +- Zeitraum (`date_from` / `date_to`, ISO 8601: `2024-01-01`) +- Nur Mails mit Anhängen (`has_attachment`) +- Sortierung: `date_desc` (Standard), `date_asc`, `relevance` + +**Xapian-Suchsyntax:** +``` +Rechnung AND 2024 # UND-Verknüpfung +"Angebot Projekt X" # Phrase +Rechn* # Wildcard +from:chef@firma.de # Feldpräfix +subject:Urlaubsantrag # Feldpräfix +``` + +**Paginierung:** 25 Ergebnisse pro Seite (konfigurierbar via `page_size`) + +**Rollenfilter:** +- `user`: sieht nur E-Mails an/von der eigenen E-Mail-Adresse +- `admin` / `auditor`: sieht alle E-Mails + +**API-Endpunkt:** +``` +GET /api/search?q=...&from=...&to=...&date_from=...&date_to=...&has_attachment=true&sort=date_desc&page=1&page_size=25 +``` + +--- + +### E-Mail-Ansicht + +Vollständige Darstellung einer archivierten E-Mail unter `/mail/[id]`. + +**Funktionen:** +- HTML-Body original dargestellt in `