Skip to content

Commit 95f6e88

Browse files
authored
Merge branch 'ulsklyc:main' into main
2 parents 1c7b6a5 + bb7ced5 commit 95f6e88

99 files changed

Lines changed: 8364 additions & 203 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ SYNC_INTERVAL_MINUTES=15
8080
# WEBDAV_BACKUP_PATH=/oikos/backups/
8181
# WEBDAV_BACKUP_KEEP=10 # Remote backups to keep (default: 7)
8282

83+
# WebDAV Document Storage (optional — stores newly uploaded document files remotely)
84+
# Non-empty values override the corresponding database settings. Existing WebDAV
85+
# documents remain readable when new WebDAV uploads are disabled. Use this trusted
86+
# deployment configuration for private/LAN WebDAV targets; UI-managed URLs must be public.
87+
# DOCUMENT_STORAGE_WEBDAV_ENABLED=false
88+
# DOCUMENT_STORAGE_WEBDAV_URL=https://cloud.example.com/remote.php/dav/files/username/
89+
# DOCUMENT_STORAGE_WEBDAV_USERNAME=username
90+
# DOCUMENT_STORAGE_WEBDAV_PASSWORD=secret
91+
# DOCUMENT_STORAGE_WEBDAV_PATH=yuvomi-documents
92+
8393
# Security
8494
RATE_LIMIT_WINDOW_MS=60000
8595
RATE_LIMIT_MAX_ATTEMPTS=5

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ data/
3434
.idea/
3535
*.swp
3636
*.swo
37-
.codex
3837
AGENTS.md
3938

4039
# Claude Code — share skills/agents/rules/hooks/settings; keep local permissions and worktrees out

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.70.2] - 2026-06-10
11+
12+
### Security
13+
- **WebDAV document storage**: UI-managed targets now reject private, loopback, link-local, internal-DNS, and DNS-rebinding destinations both before persistence and during socket lookup. Trusted private-network targets remain available through `DOCUMENT_STORAGE_WEBDAV_URL`.
14+
- **WebDAV path normalization**: replaced ambiguous trailing-slash regular expressions with linear path processing to prevent polynomial-time matching on attacker-controlled configuration.
15+
16+
## [0.70.1] - 2026-06-10
17+
18+
### Removed
19+
- **Repository metadata**: removed the last published reference to an internal development tool.
20+
21+
## [0.70.0] - 2026-06-10
22+
23+
### Added
24+
- **WebDAV document storage**: admins can select WebDAV as the global destination for new document files, including calendar attachments, with per-field environment overrides, connection tests, protected configuration changes, and clear local/WebDAV/DMS status throughout the interface.
25+
26+
### Changed
27+
- **Document binary handling**: previews, downloads, calendar attachments, deletion, and Paperless/DMS uploads now share one storage layer. Existing local files stay local, failed WebDAV uploads never fall back silently, failed database writes clean up staged remote files, and database backups explicitly exclude WebDAV binaries, which must be backed up separately.
28+
29+
## [0.69.0] - 2026-06-10
30+
31+
### Added
32+
- **Documents — Paperless-ngx (DMS) integration**: admins can connect a Paperless-ngx document management system in Settings (server URL + API token, with a connection test). Multiple DMS accounts are supported.
33+
- **Link from DMS**: search a connected DMS and link existing documents into the Documents module as references — the binary stays in the DMS and is not duplicated. Previews and downloads of linked documents are proxied live from the DMS, while each document's family/restricted/private visibility is still enforced.
34+
- **Upload to DMS**: push a local document up into the connected DMS (asynchronous OCR ingestion); when several DMS accounts are configured, an account picker lets you choose the target.
35+
36+
All DMS operations are admin-only, and the API token is never returned in responses. The integration uses a provider-pluggable adapter layer (Paperless-ngx is the first adapter) and requires no new environment variables — everything is configured in-app.
37+
38+
## [0.68.4] - 2026-06-09
39+
40+
### Fixed
41+
- **Documents**: PDF previews no longer fail with "This page was blocked by Chrome" in Chromium-based browsers. The preview iframe dropped its `sandbox` attribute (Chromium refuses to start its internal PDF viewer inside sandboxed frames) and the `/documents/:id/preview` endpoint now sends a PDF-specific Content-Security-Policy (`default-src 'self'`) instead of the strict `default-src 'none'` that blocked the native viewer. PDFs are still served same-origin as `application/pdf` with `X-Content-Type-Options: nosniff`, so no scripts can execute; non-PDF previews keep the strict policy.
42+
1043
## [0.68.3] - 2026-06-09
1144

1245
### Changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ Each module is independent. Use what fits, skip what doesn't.
158158
| ![meals](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/meals.png) | **Meals** | Weekly drag-and-drop planner with multiple items per slot. Direct export to shopping list. |
159159
| ![recipes](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/recipes.png) | **Recipes** | Create, duplicate, and scale recipes. Pre-fill meal slots or save any planned meal as a recipe. |
160160
| ![calendar](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/calendar.png) | **Calendar** | Google Calendar (OAuth) and CalDAV sync (iCloud, Nextcloud, Radicale). ICS subscriptions, recurring events, file attachments, public & school holiday overlays (OpenHolidays), month and agenda views. |
161-
| ![documents](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/documents.png) | **Documents** | Upload and organize family files. Folders, tags, per-document visibility controls, in-browser preview, drag-and-drop. |
161+
| ![documents](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/documents.png) | **Documents** | Upload and organize family files. Folders, tags, per-document visibility controls, in-browser preview, drag-and-drop. New files, including calendar attachments, can optionally use WebDAV storage; Paperless-ngx (DMS) linking and uploads remain supported. |
162162
| ![budget](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/budget.png) | **Budget** | Income, expenses, recurring entries, trend charts, CSV export. Split Expenses with automatic debt simplification. |
163163
| ![housekeeping](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/housekeeping.png) | **Housekeeping** | Manage household staff — schedules, check-in/out, daily or hourly billing, chores, supply requests. |
164164
| ![notes](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/notes.png) | **Notes & Contacts** | Colored sticky notes with Markdown. Contact directory with CardDAV sync. |
@@ -168,6 +168,10 @@ Each module is independent. Use what fits, skip what doesn't.
168168
| ![api-tokens](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/api-tokens.png) | **API Tokens** | Named Bearer / X-API-Key tokens for integrations. OpenAPI 3.0 spec included. |
169169
| ![backup](https://raw.githubusercontent.com/ulsklyc/yuvomi/main/docs/icons/backup.png) | **Backup** | Manual and scheduled database backup and restore, with automatic pre-restore rollback. Optional WebDAV upload target (Nextcloud, ownCloud, Hetzner, etc.). |
170170

171+
> **WebDAV document storage needs its own backup.** SQLite/database backups contain document metadata and links, but not document binaries stored on WebDAV. Back up the WebDAV target separately.
172+
> WebDAV targets configured in the admin UI must resolve to public network addresses. For a trusted
173+
> LAN or loopback target, set `DOCUMENT_STORAGE_WEBDAV_URL` through the deployment environment.
174+
171175
---
172176

173177
## Design & technology
@@ -259,7 +263,7 @@ Open `http://localhost:3000`. The first visit walks you through creating your ad
259263

260264
[Installation](docs/installation.md)  ·  [Spec & data model](docs/SPEC.md)  ·  [Modules](MODULES.md)  ·  [Contributing](CONTRIBUTING.md)  ·  [Security](SECURITY.md)  ·  [Privacy for self-hosters](docs/PRIVACY-FOR-SELFHOSTERS.md)  ·  [Changelog](CHANGELOG.md)  ·  [Backlog](BACKLOG.md)
261265

262-
If you self-host Yuvomi in a GDPR context (EU/EEA, processing other people's data), read [docs/PRIVACY-FOR-SELFHOSTERS.md](docs/PRIVACY-FOR-SELFHOSTERS.md) before going live: it covers third-country assessments for every external service (weather, CalDAV/CardDAV, OIDC, WebDAV backup), data-processing-agreement notes, log-retention guidance, and a records-of-processing template.
266+
If you self-host Yuvomi in a GDPR context (EU/EEA, processing other people's data), read [docs/PRIVACY-FOR-SELFHOSTERS.md](docs/PRIVACY-FOR-SELFHOSTERS.md) before going live: it covers third-country assessments for every external service (weather, CalDAV/CardDAV, OIDC, WebDAV backup and document storage), data-processing-agreement notes, log-retention guidance, and a records-of-processing template.
263267

264268
---
265269

SECURITY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ Vulnerabilities that require physical access to the host or root on the server a
3838
- API rate limiting (300 requests/min per IP)
3939
- Content Security Policy via Helmet (`self`-only)
4040
- Optional SQLCipher AES-256 database encryption (built into the official Docker image; enable by setting `DB_ENCRYPTION_KEY`. Bare-metal installs require a SQLCipher-enabled build of better-sqlite3.)
41+
- Existing WebDAV documents protect their connection configuration: changing the URL, username, password, or base path requires explicit admin confirmation and a successful read test against an existing object; required connection data cannot be removed while WebDAV documents exist
42+
- UI-managed WebDAV document-storage URLs are protected against SSRF: private, loopback, link-local, internal-DNS, and DNS-rebinding targets are rejected before persistence and during socket lookup. Trusted private-network targets require the deployment-controlled `DOCUMENT_STORAGE_WEBDAV_URL` override
4143
- No API endpoint accessible without session auth (except login)
4244
- `SESSION_SECRET` is mandatory - server refuses to start if unset
4345

docs/PRIVACY-FOR-SELFHOSTERS.md

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
- 2.3 [CalDAV/CardDAV-Sync](#23-caldavcarddav-sync)
2828
- 2.4 [OIDC-Provider (Single Sign-On)](#24-oidc-provider-single-sign-on)
2929
- 2.5 [WebDAV-Backup](#25-webdav-backup)
30+
- 2.6 [WebDAV-Dokumentspeicher](#26-webdav-dokumentspeicher)
3031
3. [Logging und Speicherbegrenzung](#3-logging-und-speicherbegrenzung-art-5-abs-1-lit-e-dsgvo)
3132
4. [Haushaltsausnahme](#4-haushaltsausnahme-art-2-abs-2-lit-c-dsgvo)
3233
5. [Verarbeitungsverzeichnis-Vorlage (Art. 30 DSGVO)](#5-verarbeitungsverzeichnis-vorlage-art-30-dsgvo)
@@ -69,6 +70,7 @@ Betreiber daraus resultieren.
6970
| CalDAV/CardDAV-Server | `server/services/caldav-sync.js`, `server/services/cardav-sync.js` | nur wenn Nutzer einen Sync konfiguriert | abhängig vom Provider | ja, bei kommerziellen Anbietern (siehe 2.3) |
7071
| OIDC-Provider | `server/auth.js`, `server/services/oidc.js` | nur wenn konfiguriert | abhängig vom Provider | meistens ja (siehe 2.4) |
7172
| WebDAV-Backup | `server/services/backup-webdav.js` | nur wenn konfiguriert | abhängig vom Provider | ja, bei kommerziellen Anbietern (siehe 2.5) |
73+
| WebDAV-Dokumentspeicher | `server/services/document-storage.js` | nur wenn konfiguriert | abhängig vom Provider | ja, bei kommerziellen Anbietern (siehe 2.6) |
7274

7375
### 2.1 Open-Meteo (Wetter-Standard)
7476

@@ -165,9 +167,11 @@ Konfiguration so, dass du auf einen EU-Provider umstellen könntest.
165167
`server/routes/backup.js` und `server/services/backup-scheduler.js`.
166168
- **Aktiv nur, wenn:** du WebDAV-Backups in deinen Backup-Einstellungen
167169
konfigurierst.
168-
- **Was wird übertragen:** Backup-Archive deiner Yuvomi-Instanz inkl. **aller
169-
Nutzdaten** — Kontakte, Termine, Notizen, Dokumente. Das ist datenschutz-
170-
rechtlich der sensibelste Datenstrom.
170+
- **Was wird übertragen:** Backup-Archive deiner Yuvomi-Instanz mit allen
171+
SQLite-Nutzdaten — Kontakte, Termine, Notizen sowie Dokument-Metadaten und
172+
lokal gespeicherte Dokumentdateien. Dateien aus dem separaten
173+
WebDAV-Dokumentspeicher sind nicht enthalten. Das Backup ist
174+
datenschutzrechtlich ein besonders sensibler Datenstrom.
171175
- **Drittland-Bewertung — abhängig vom Anbieter:**
172176
| Anbieter | Standort | Bewertung |
173177
|---|---|---|
@@ -183,6 +187,28 @@ Konfiguration so, dass du auf einen EU-Provider umstellen könntest.
183187
WebDAV-Provider zum reinen Speicheranbieter ohne Klartextzugriff. Halte
184188
die Verschlüsselungs-Passphrase getrennt vom Backup-Speicherort.
185189

190+
### 2.6 WebDAV-Dokumentspeicher
191+
192+
- **Code-Stelle:** `server/services/document-storage.js`, gesteuert über
193+
`server/routes/documents.js`.
194+
- **Aktiv nur, wenn:** ein Admin WebDAV als Ziel für neue Dokumentdateien
195+
aktiviert oder die entsprechenden `DOCUMENT_STORAGE_WEBDAV_*`-Variablen
196+
setzt.
197+
- **Was wird übertragen:** neu hochgeladene Dokumentdateien einschließlich
198+
neuer Kalenderanhänge, außerdem Basic-Auth-Zugangsdaten und die IP-Adresse
199+
des Yuvomi-Servers. Dateinamen werden nicht als Objektpfad übernommen; die
200+
Dateien können dennoch unmittelbar personenbezogene oder besonders
201+
schützenswerte Inhalte enthalten.
202+
- **Drittland und AVV:** Es gelten dieselben providerabhängigen Bewertungen
203+
wie beim WebDAV-Backup in Abschnitt 2.5. Bei einem kommerziellen Hoster ist
204+
außerhalb der Haushaltsausnahme ein AVV erforderlich; bei Anbietern außerhalb
205+
des EWR sind zusätzlich Angemessenheitsbeschluss, DPF oder SCCs mit TIA zu
206+
prüfen.
207+
- **Empfehlung:** Bevorzuge einen selbst gehosteten oder in der EU betriebenen
208+
WebDAV-Dienst, beschränke den Zugriff auf ein eigenes Verzeichnis und sichere
209+
dieses Ziel separat. SQLite-Backups enthalten nur Metadaten und
210+
Speicher-Schlüssel, nicht die dort abgelegten Binärdateien.
211+
186212
---
187213

188214
## 3. Logging und Speicherbegrenzung (Art. 5 Abs. 1 lit. e DSGVO)
@@ -299,7 +325,8 @@ konkrete Konfiguration ein und ergänze um eigene Verarbeitungen.
299325
| 3 | Kontakte / CardDAV | Adressbuch | Art. 6 Abs. 1 lit. b/f | Nutzer, Kontakte | Name, Adresse, Telefon, E-Mail | CardDAV-Server (falls Sync) | <<je nach Anbieter>> | bis Löschung | TLS, AVV |
300326
| 4 | Wetter | Anzeige Vorhersage | Art. 6 Abs. 1 lit. b | Nutzer | Koordinaten/Ortsname | Open-Meteo (CH); ggf. OpenWeather (UK) | CH/UK Angemessenheit | sofort nach Anfrage | TLS |
301327
| 5 | Backups | Datensicherung | Art. 6 Abs. 1 lit. f | Nutzer und alle Datensubjekte der App | Vollbackup der DB | <<WebDAV-Provider>> | <<Aufbewahrungs-Konzept, z. B. 30 Tage rollierend>> | Verschlüsselung vor Upload, AVV |
302-
| 6 | Sicherheits-/Betriebs-Logs | Missbrauchserkennung, Fehlersuche | Art. 6 Abs. 1 lit. f | Nutzer / Login-Versuchende | IP bei fehlgeschlagenen Logins, Fehler-Stacktraces | nur lokal | nein | **max. 30 Tage** | Rotation, Zugangsbeschränkung |
328+
| 6 | Dokumentablage | Gemeinsame Ablage und Kalenderanhänge | Art. 6 Abs. 1 lit. b/f | Nutzer und in Dokumenten genannte Personen | Dokumentdateien, Anhänge, Metadaten | <<WebDAV-Provider, falls aktiv>> | <<je nach Anbieter>> | bis Löschung durch Nutzer | TLS, eigener Pfad, AVV, separates Backup |
329+
| 7 | Sicherheits-/Betriebs-Logs | Missbrauchserkennung, Fehlersuche | Art. 6 Abs. 1 lit. f | Nutzer / Login-Versuchende | IP bei fehlgeschlagenen Logins, Fehler-Stacktraces | nur lokal | nein | **max. 30 Tage** | Rotation, Zugangsbeschränkung |
303330

304331
### 5.3 Auftragsverarbeiter (Art. 28)
305332

@@ -308,7 +335,7 @@ konkrete Konfiguration ein und ergänze um eigene Verarbeitungen.
308335
| <<z. B. Hetzner Online GmbH>> | Server-Hosting | <<Datum>> | DE | AVV nach Art. 28; ISO 27001 |
309336
| <<OpenWeather Ltd.>> | Wetter-API (falls aktiv) | <<Datum>> | UK | Angemessenheit; DPA |
310337
| <<OIDC-Provider>> | Authentifizierung | <<Datum>> | <<EU/USA>> | <<AVV; ggf. DPF + SCCs>> |
311-
| <<WebDAV-Provider>> | Backup-Storage | <<Datum>> | <<je nach Anbieter>> | <<AVV; Verschlüsselung clientseitig>> |
338+
| <<WebDAV-Provider>> | Backup- und/oder Dokument-Storage | <<Datum>> | <<je nach Anbieter>> | <<AVV; Verschlüsselung für Backups; Zugriffsbeschränkung>> |
312339

313340
---
314341

0 commit comments

Comments
 (0)