Skip to content

feat(portal): Pi-hole-Portal-Widget pro-Besitzer + Haushalt (TP2b) - #193

Merged
CallMeTechie merged 11 commits into
masterfrom
feature/pihole-portal-owner
Jun 26, 2026
Merged

CallMeTechie merged 11 commits into
masterfrom
feature/pihole-portal-owner

Conversation

@CallMeTechie

Copy link
Copy Markdown
Owner

Pi-hole-Portal-Widget pro-Besitzer + Haushalt (Teilprojekt 2b)

Schließt die Initiative „Pi-hole im Portal" ab (TP1 #189 → TP2a #192TP2b). Erweitert das TP2a-„DNS-Schutz"-Widget um zwei login-gegatete Ansichten:

  • Ich (pro-Besitzer): Summe der DNS-Zahlen über alle Geräte einer Person.
  • Haushalt: globale Pi-hole-Gesamtsumme.

Segment-Umschalter [Gerät] Ich Haushalt in der bestehenden Karte; der bisherige zero-login Gerät-Scope (TP2a) bleibt unverändert.

Architektur (5 isolierte Bausteine, keine DB-Migration)

Baustein Inhalt
Seam Neue Middleware portalOwner (nach portalIdentity gemountet) — setzt req.portalOwnerId/portalOwnerSource/portalLoggedIn. portalIdentity bleibt unangetastet.
Aggregation peers.peersOfOwner(userId) (direkter peers.user_id-Lookup aus TP1) + Cache-Summe, kein N+1.
Endpoint owner GET /api/v1/portal/pihole/owner — gewhitelistetes Aggregat {total,blocked,allowed,blockedPct,deviceCount,asOf}.
Endpoint household GET /api/v1/portal/pihole/household{total,blocked,blockedPct,activeClients,asOf}, immer login-gegatet.
Setting portal.trust_owner_mapping (Default aus) + Admin-Toggle in allen 3 Themes mit Kiosk-Pflicht-Hinweis.
Widget Scope-aware Render + Segment-Umschalter in portal.js/portal.njk.

Sicherheits-Invarianten (jede testgesichert)

  • Kein IDOR: Owner-ID kommt NUR aus req.session.userId (eingeloggt) oder — nur bei aktivem Trust und ohne Session — aus peers.user_id des identifizierten Geräts. Nie aus Body/Query/Header; die Endpoints nehmen keinen ownerId-Parameter. IDOR-Negativtest vorhanden.
  • Präzedenz: authentifizierte Session schlägt Geräte-Vertrauen immer (User A auf B's Gerät sieht A).
  • Haushalt immer login — der Trust-Schalter lockert NUR pro-Besitzer.
  • Default off ohne on()-Falle: settings.get('portal.trust_owner_mapping','0') !== '0' (nicht der on()-Helfer, der '1' defaultet).
  • Kein Leak: beide Endpoints liefern nur Aggregate — nie rohe topClients/IPs/peerId/user_id/owner_name/fremde Geräte. Verhaltens- + struktureller Leak-Test (server + client).
  • deleted-user (Session gültig, peers.user_id genullt) → no_data, nicht no_owner.
  • DOM-sichere Login-Affordanz (createElement/textContent, kein innerHTML mit Daten/i18n). i18n en+de. Parametrisiertes SQL.

Tests

  • TP2b-Suite 27/27 grün: peers_of_owner, portal_trust_setting, portal_owner_middleware (Präzedenz-Matrix), pihole_portal_owner (inkl. IDOR-Negativ + deleted-user + collapsed/no_owner/feature-off), pihole_portal_household (login_required auch bei Trust an), owner_household_no_leak (verhaltens + strukturell), portal_trust_settings_ui, scope_js, scope_markup.
  • Regression 34/34 grün (portal_identity, portal_identity_dynamic, portal_api, pihole_portal_device, peers*); git diff bestätigt portalIdentity.js unangetastet; i18n-Parität grün.
  • Finales whole-branch opus-Review: Ready to merge (alle 10 harten Constraints PASS). Eine Important-UX-Finding (transientes unavailable versteckte den Umschalter im Haushalt-Scope vor dem ersten Sync) direkt gefixt — Karten-Hide nur noch für device-Scope.

Folge-Tickets (außerhalb Scope)

  • count-Parameter in getTopClients für volle Top-N-Genauigkeit (geteilt mit TP2a; bis dahin transparenter „Snapshot"-Hinweis).
  • destroyByUserId beim User-Löschen (Session-Invalidierung; vorbestehender Gap).

🤖 Generated with Claude Code

https://claude.ai/code/session_01PrxALUszC9wFkYv1fedKyd

@CallMeTechie
CallMeTechie merged commit 9b1de7f into master Jun 26, 2026
8 checks passed
@CallMeTechie
CallMeTechie deleted the feature/pihole-portal-owner branch June 26, 2026 07:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant