Commit Graph

57 Commits

Author SHA1 Message Date
fuomag9
03c8f40417 Add forward auth portal — CPM as built-in IdP replacing Authentik
CPM can now act as its own forward auth provider for proxied sites.
Users authenticate at a login portal (credentials or OAuth) and Caddy
gates access via a verify subrequest, eliminating the need for external
IdPs like Authentik.

Key components:
- Forward auth flow: verify endpoint, exchange code callback, login portal
- User groups with membership management
- Per-proxy-host access control (users and/or groups)
- Caddy config generation for forward_auth handler + callback route
- OAuth and credential login on the portal page
- Admin UI: groups page, inline user/group assignment in proxy host form
- REST API: /api/v1/groups, /api/v1/forward-auth-sessions, per-host access
- Integration tests for groups and forward auth schema

Also fixes mTLS E2E test selectors broken by the RBAC refactor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 22:32:17 +02:00
fuomag9
277ae6e79c Add mTLS RBAC with path-based access control, role/cert trust model, and comprehensive tests
Implements full role-based access control for mTLS client certificates:
- Database: mtls_roles, mtls_certificate_roles, mtls_access_rules tables with migration
- Models: CRUD for roles, cert-role assignments, path-based access rules
- Caddy config: HTTP-layer RBAC enforcement via CEL fingerprint matching in subroutes
- New trust model: select individual certs or entire roles instead of CAs (derives CAs automatically)
- REST API: /api/v1/mtls-roles, cert assignments, proxy-host access rules endpoints
- UI: Roles management tab (card-based), cert/role trust picker, inline RBAC rule editor
- Fix: dialog autoclose bug after creating proxy host (key-based remount)
- Tests: 85 new tests (785 total) covering models, schema, RBAC route generation, leaf override, edge cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 18:40:21 +02:00
fuomag9
e26d7a2c3f feat: improve LocationRulesFields UI and add unit tests for buildLocationReverseProxy
- Replace textarea with per-upstream rows (protocol dropdown + address input),
  matching the existing UpstreamInput component pattern
- Export buildLocationReverseProxy for testing
- Add 14 unit tests covering: dial formatting, HTTPS/TLS transport,
  host header preservation, path sanitization, IPv6, mixed upstreams

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 14:51:08 +01:00
fuomag9
447dbcedde feat: add LocationRulesFields UI component and form wiring
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:51:08 +01:00
fuomag9
fce32318ce fix: remove unused imports and update dependencies
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 09:31:50 +01:00
fuomag9
9c60d11c2c feat: improve UI contrast, dark mode, dialog sizing, color coherence, and add table sorting
- Fix dialog scrollability (flex layout + max-h-[90dvh]) and increase L4 dialog to lg width
- Add styled enable card to L4 dialog matching proxy host pattern
- Unify section colors across proxy host and L4 dialogs (cyan=LB, emerald=DNS, violet=upstream DNS, rose=geo, amber=mTLS)
- Improve light mode contrast: muted-foreground oklch 0.552→0.502, remove opacity modifiers on secondary text
- Improve dark mode: boost muted-foreground to 0.85, increase border opacity 10%→16%, input 15%→20%
- Add bg-card to DataTable wrapper and bg-muted/40 to table headers for surface hierarchy
- Add semantic badge variants (success, warning, info, muted) and StatusChip dark mode fix
- Add server-side sortable columns to Proxy Hosts and L4 Proxy Hosts (name, upstream, status, protocol, listen)
- Add sortKey to DataTable Column type with clickable sort headers (ArrowUp/Down indicators, URL param driven)
- Fix E2E test selectors for shadcn UI (label associations, combobox roles, dropdown menus, mobile drawer)
- Add htmlFor/id to proxy host form fields and aria-labels to select triggers for accessibility
- Add sorting E2E tests for both proxy host pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 22:17:56 +01:00
fuomag9
98105eba89 fix: apply shadcn violet OKLCH theme and fix SelectItem empty value crash
- Replace HSL-based indigo theme with official shadcn violet OKLCH theme
  in globals.css for proper contrast in both light and dark mode
- Update tailwind.config.ts to use var(--...) instead of hsl(var(--...))
  for OKLCH color space compatibility
- Fix Radix UI crash: replace SelectItem value="" with "__none__" sentinel
  in HostDialogs.tsx and L4HostDialogs.tsx (empty string value is invalid)
  Form action parsers already return null for non-numeric values

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 16:39:38 +01:00
fuomag9
86fa669590 feat: rewrite CA cert dialogs with shadcn
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 13:52:48 +01:00
fuomag9
5d96f978ec feat: rewrite L4 proxy components with shadcn
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 13:49:38 +01:00
fuomag9
bca14e0fe0 feat: rewrite proxy-host feature components with shadcn
Replace all MUI imports (Stack, Box, Typography, TextField, Switch, Checkbox,
Collapse, Accordion, Chip, etc.) with shadcn/ui + Tailwind equivalents across
all 13 proxy host component files. Lucide icons replace MUI icons throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 13:44:13 +01:00
fuomag9
3ec228d6e1 fix: use semantic color tokens in StatusChip for light/dark compat 2026-03-22 11:35:24 +01:00
fuomag9
df2e215b0f fix: add loading skeletons to DataTable, remove duplicate close in AppDialog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 11:32:42 +01:00
fuomag9
37c4595757 feat: rewrite core UI primitives with shadcn
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 11:30:12 +01:00
fuomag9
9228484177 feat: install shadcn/ui component primitives
Adds 24 shadcn/ui component files to src/components/ui/ via the shadcn CLI, installs required @radix-ui/* and related dependencies, and updates components.json aliases to resolve under src/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 11:23:04 +01:00
fuomag9
b5ef7aab7b fix: resolve all lint errors from L4 feature
- Remove unused Box/Collapse from L4PortsApplyBanner
- Remove unused Stack from RedirectsFields
- Remove unused updateL4ProxyHost import from validation test
- Add eslint-disable-next-line for require() in vi.hoisted() blocks
  (necessary pattern since vi.hoisted runs before ESM imports)
- Add file-level eslint-disable no-explicit-any for test files that
  intentionally pass invalid types to test validation logic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 00:37:52 +01:00
fuomag9
00c9bff8b4 feat: instant banner refresh on L4 mutations + master-slave L4 sync
Banner (L4PortsApplyBanner):
- Accept refreshSignal prop; re-fetch /api/l4-ports when it changes
- Signal fires immediately after create/edit/delete/toggle in L4ProxyHostsClient
  without waiting for a page reload

Master-slave replication (instance-sync):
- Add l4ProxyHosts to SyncPayload.data (optional for backward compat
  with older master instances that don't include it)
- buildSyncPayload: query and include l4ProxyHosts, sanitize ownerUserId
- applySyncPayload: clear and re-insert l4ProxyHosts in transaction;
  call applyL4Ports() if port diff requires it so the slave's sidecar
  recreates caddy with the correct ports
- Sync route: add isL4ProxyHost validator; backfill missing field from
  old masters; validate array when present

Tests (25 new tests):
- instance-sync.test.ts: buildSyncPayload includes L4 data, sanitizes ownerUserId;
  applySyncPayload replaces L4 hosts, handles missing field, writes trigger
  when ports differ, skips trigger when ports already match
- l4-ports-apply-banner.test.ts: banner refreshSignal contract + client
  increments counter on all mutation paths

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 00:22:44 +01:00
fuomag9
3a4a4d51cf feat: add L4 (TCP/UDP) proxy host support via caddy-l4
- New l4_proxy_hosts table and Drizzle migration (0015)
- Full CRUD model layer with validation, audit logging, and Caddy config
  generation (buildL4Servers integrating into buildCaddyDocument)
- Server actions, paginated list page, create/edit/delete dialogs
- L4 port manager sidecar (docker/l4-port-manager) that auto-recreates
  the caddy container when port mappings change via a trigger file
- Auto-detects Docker Compose project name from caddy container labels
- Supports both named-volume and bind-mount (COMPOSE_HOST_DIR) deployments
- getL4PortsStatus simplified: status file is sole source of truth,
  trigger files deleted after processing to prevent stuck 'Waiting' banner
- Navigation entry added (CableIcon)
- Tests: unit (entrypoint.sh invariants + validation), integration (ports
  lifecycle + caddy config), E2E (CRUD + functional routing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 00:11:16 +01:00
fuomag9
4b5323a7bf feat: add structured redirects and path prefix rewrite for proxy hosts
Adds two new UI-configurable Caddy patterns that previously required raw JSON:
- Per-path redirect rules (from/to/status) emitted as a subroute handler before
  auth so .well-known paths work without login; supports full URLs, cross-domain
  targets, and wildcard path patterns (e.g. /.well-known/*)
- Path prefix rewrite that prepends a segment to every request before proxying
  (e.g. /recipes → upstream sees /recipes/original/path)

Config is stored in the existing meta JSON column (no schema migration). Includes
integration tests for meta serialization and E2E functional tests against a real
Caddy instance covering relative/absolute destinations, all 3xx status codes, and
various wildcard combinations. Adds traefik/whoami to the test stack to verify
rewritten paths actually reach the upstream.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 17:53:33 +01:00
fuomag9
d86d1400d7 feat: enable HSTS subdomains by default
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 23:15:28 +01:00
fuomag9
73c90894b1 Handle wildcard proxy hosts and stabilize test coverage
- accept wildcard proxy host domains like *.example.com with validation and normalization
- make exact hosts win over overlapping wildcards in generated routes and TLS policies
- add unit coverage for host-pattern priority and wildcard domain handling
- add a single test:all entry point and clean up lint/typecheck issues so the suite runs cleanly
- run mobile layout Playwright checks under both chromium and mobile-iphone
2026-03-14 01:03:34 +01:00
fuomag9
cf7eb7757e fix: address code review — responsive overflow, map minWidth, DataTable mobile click handler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 09:58:45 +01:00
fuomag9
ee8c3095ab feat: add mobileCard prop to DataTable for card view on mobile
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 00:29:45 +01:00
fuomag9
44dc7d128b feat: stack PageHeader vertically on mobile 2026-03-12 00:28:26 +01:00
fuomag9
9a82ad9033 hide revoked client certs by default, add show-revoked toggle
- IssuedCertsPanel preview: only show active (non-revoked) certs
- ManageIssuedClientCertsDialog: filter out revoked by default; show
  "Show revoked (N)" toggle when revoked certs exist

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 22:38:18 +01:00
fuomag9
6ecd195073 redesign certificates page: tabs, drawers, relative expiry, status bar
- Split ACME / Imported / CA-mTLS into tabs with count badges
- Add clickable status summary bar (expired / expiring soon / healthy)
- Per-tab search filter by name and domain
- Replace accordion cards with DataTable for imported certs
- Slide-in Drawers (480 px) for add/edit imported and CA certs
- File upload + show/hide toggle for private key in ImportCertDrawer
- CaCertDrawer: Generate / Import PEM tabs for add, simple form for edit
- CA tab: expandable rows showing issued client certs inline
- RelativeTime component: "in 45 days" / "EXPIRED 3 days ago" with date tooltip
- Remove CreateCaCertDialog and EditCaCertDialog (replaced by CaCertDrawer)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 22:36:46 +01:00
fuomag9
9fa57bcf28 fix mTLS: use trusted_leaf_certs for issued certs, surface CA delete errors
Two bugs fixed:

1. buildClientAuthentication was placing issued leaf cert PEMs into
   trusted_ca_certs. Caddy uses that field for CA chain validation, not
   leaf pinning — putting leaf certs there made chain verification fail
   for every presented client cert, causing the browser to be asked
   repeatedly. Fixed by using trusted_leaf_certs for managed CAs.

2. If all issued certs for a CA were revoked, the active cert map would
   be empty and the code fell back to trusting the CA cert directly,
   effectively un-revoking everything. Fixed by tracking which CAs have
   ever had issued certs (including revoked) and keeping them in
   trusted_leaf_certs mode permanently (empty list = no one trusted).

Also fix CA certificate delete action not surfacing the error message
to the user in production (Next.js strips thrown error messages in
server actions). Changed to return { success, error } and updated the
client dialog to check the result instead of using try/catch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 18:21:48 +01:00
fuomag9
7760f2d2c8 normalise stale DetectionOnly engine mode on WafFields init
Old DB records may still have mode='DetectionOnly'. The previous
value?.mode ?? 'inherit' would pass that string into state, leaving no
engine mode button selected. Explicitly accept only 'Off'/'On'; anything
else (including legacy DetectionOnly) falls back to 'inherit'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 17:33:39 +01:00
fuomag9
b348dae4be remove DetectionOnly WAF mode
DetectionOnly was fundamentally broken in coraza-caddy (actually blocks
requests via anomaly scoring), caused massive audit log flooding, and the
threshold workaround had several issues:
- t:none is meaningless in a SecAction (no target to transform)
- SecRuleEngine directive ordering relative to SecAction is implementation-
  defined, making the override fragile
- host.mode ?? 'DetectionOnly' fallbacks silently gave any host without an
  explicit mode the broken DetectionOnly behaviour

Changes:
- Remove DetectionOnly from UI (global settings radio, per-host engine mode)
- Coerce legacy DB values of 'DetectionOnly' to 'On' in buildWafHandler
- Fix fallback defaults: host.mode ?? 'DetectionOnly' → host.mode ?? 'On'
- Fix action parsers: unknown mode defaults to 'On' (was 'DetectionOnly')
- Fix global settings defaultValue: ?? 'DetectionOnly' → ?? 'On' (or 'Off')
- Remove the fragile threshold SecAction workaround
- Update types: mode is now 'Off' | 'On' throughout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 17:27:08 +01:00
fuomag9
044f012dd0 Added issued-client-cert tracking and revocation for mTLS 2026-03-06 14:53:17 +01:00
fuomag9
6acd51b578 export as .p12 2026-03-06 13:25:06 +01:00
fuomag9
c76004f8ac better pki 2026-03-06 00:22:30 +01:00
fuomag9
f3358c20cd feat: add mTLS support for proxy hosts
- New `ca_certificates` table for reusable CA certs (migration 0011)
- CA cert CRUD model, server actions, and UI dialogs
- Proxy host create/edit dialogs include mTLS toggle + CA cert selection
- Caddy config generates `client_authentication` TLS policy blocks with
  `require_and_verify` mode for hosts with mTLS enabled
- CA certs sync to slave instances via instance-sync payload
- Certificates page shows CA Certificates section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 20:29:55 +01:00
fuomag9
d959fdf836 if waf for a host is not configured, suppressing a rule for a host should automatically set it to "merge with global" and enabled. 2026-03-04 21:27:15 +01:00
fuomag9
7341070c0d Fix rule parsing for single reverse proxies 2026-03-04 21:16:11 +01:00
fuomag9
77d3e35c63 feat: clickable WAF event rows with detail drawer
- WafEvent model: expose rawData field from DB
- DataTable: add optional onRowClick prop with hover cursor
- WafEventsClient: clicking a row opens a right-side drawer showing
  all event fields plus the raw Coraza audit JSON (pretty-printed)

Safety: rawData is rendered via JSON.stringify into a <pre> element,
never via dangerouslySetInnerHTML, so attack payloads are displayed
as inert text.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 18:21:08 +01:00
fuomag9
edd4e6879f fix: make WAF events table fit in viewport
- DataTable: add overflowX auto to TableContainer + minWidth 600
- WAF events: tighten column widths (Time 150, Host 150, IP 140,
  Method 60), add ellipsis+tooltip on Host column, let Rule Message
  expand to fill remaining space

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 08:26:36 +01:00
fuomag9
634f8f1593 fix WafFields: add missing waf_enabled hidden input
The enabled switch state was never submitted to the form, so the host
WAF config was always saved as enabled: false regardless of the toggle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 01:52:34 +01:00
fuomag9
1a56e5e842 better ui 2026-03-04 00:31:02 +01:00
fuomag9
0dad675c6d feat: integrate Coraza WAF with full UI and event logging
- Add coraza-caddy/v2 to Caddy Docker build
- Add waf_events + waf_log_parse_state DB tables (migration 0010)
- Add WafSettings type and get/save functions to settings
- Add WafHostConfig/WafMode types to proxy-hosts model
- Add resolveEffectiveWaf + buildWafHandler to caddy config generation
- Create waf-log-parser.ts: parse Coraza JSON audit log → waf_events
- Add WafFields.tsx per-host WAF UI (accordion, mode, CRS, directives)
- Add global WAF settings card to SettingsClient
- Add WAF Events dashboard page with search, pagination, severity chips
- Add WAF Events nav link to sidebar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 22:16:34 +01:00
fuomag9
8555de7b9d fix: use numeric timestamp comparison for cert expiry; extract PaginationBar to avoid unconditional useSearchParams subscription
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 17:56:23 +01:00
fuomag9
89c5d4b838 feat: add pagination support to DataTable component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 17:53:23 +01:00
fuomag9
2096ebf1ed fix: replace Outlined icon variants with filled equivalents for visual consistency
Replace DeleteOutline→Delete, CheckCircleOutline→CheckCircle, ErrorOutline→Error,
RemoveCircleOutline→RemoveCircle, InfoOutlined→Info across all dashboard components.
Replace custom SVG bar chart in OverviewClient with BarChartIcon.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 15:25:19 +01:00
fuomag9
674e06e3c9 feat: replace country/continent TagInputs with visual flag pickers
Countries:
- Searchable chip grid (flag emoji + name + code) with 249 countries
- Instant search by name or ISO code prefix
- Select matching / Clear matching when search is active
- Select all / Clear all when no search
- Selected-count indicator in toolbar
- Summary strip showing all selected when search is active
- Custom thin scrollbar, 220px viewport

Continents:
- 7 clickable tiles with emoji + name + code
- Select all / Clear all toolbar
- Warning/success color theming per block/allow tab

Both pickers:
- accentColor prop (warning=orange for block, success=green for allow)
- Hidden form input for server compatibility
- Smooth 120ms transitions

Also simplified TagInput to a plain TextField with inline chips
(removes Autocomplete dependency for freeform fields like ASNs/CIDRs/IPs)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 01:31:12 +01:00
fuomag9
0758e5b27a feat: support fail_closed option from caddy-blocker-plugin
New field from upstream plugin: when the real client IP is
indeterminate (trusted proxy present but no usable XFF entry),
fail_closed=true blocks the request instead of passing it through.

- Add fail_closed to GeoBlockSettings type
- Include in mergeGeoBlockSettings (OR semantics: either global or host enables it)
- Emit fail_closed in buildBlockerHandler (only when true)
- Parse geoblock_fail_closed from form in both settings and proxy-host actions
- Add Checkbox UI in the Advanced accordion of GeoBlockFields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 09:14:46 +01:00
fuomag9
ccef82cca8 feat: add GeoIP status API route and improved geoblock UI 2026-02-25 01:22:04 +01:00
fuomag9
18c890bb21 feat: redesign GeoBlockFields UI with tabs, Autocomplete tag inputs, and accordion 2026-02-23 23:55:40 +01:00
fuomag9
b0abb407c6 feat: add GeoBlockFields to create and edit proxy host dialogs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:56:38 +01:00
fuomag9
7165dc4b05 fix: always render geoblock_mode hidden input regardless of showModeSelector
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:56:38 +01:00
fuomag9
821842b3a9 feat: add GeoBlockFields UI component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:56:38 +01:00
fuomag9
32f232ebee better UI for dns pinning 2026-02-22 10:00:52 +01:00