Commit Graph

80 Commits

Author SHA1 Message Date
fuomag9
a45a156068 fix pages viewing 2026-02-27 19:49:11 +01:00
fuomag9
8bf07011f9 feat: add paginated list functions to DB models
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 17:58:23 +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
97ba5547f1 feat: add ACME cert scanner utility
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 17:48:55 +01:00
fuomag9
e75018d686 fix: exclude IP address hosts from analytics host list
Only show configured domain names, not raw IPs (e.g. 127.0.0.1:80,
46.225.8.152) that appear in traffic events from direct access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 11:47:03 +01:00
fuomag9
cf74451e9a feat: MUI date-time pickers, multiselect hosts with search, fix host list
- Replace native datetime-local inputs with @mui/x-date-pickers DateTimePicker
  (proper dark-themed calendar popover with time picker, DD/MM/YYYY HH:mm format,
  min/max constraints between pickers, 24h clock)
- Replace single-host Select with Autocomplete (multiple, disableCloseOnSelect):
  checkbox per option, chip display with limitTags=2, built-in search/filter
- getAnalyticsHosts() now unions traffic event hosts WITH all configured proxy host
  domains (parsed from proxyHosts.domains JSON), so every proxy appears in the list
- analytics-db: buildWhere accepts hosts: string[] (empty = all); uses inArray for
  multi-host filtering via drizzle-orm
- All 6 API routes updated: accept hosts param (comma-separated) instead of host

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 11:42:54 +01:00
fuomag9
9e2007eb0c feat: add custom date range picker, fix country click highlight on map
- Analytics default interval changed to 1h
- Add 'Custom' toggle option with datetime-local pickers (pre-filled to last 24h)
- Refactor analytics-db: buildWhere now takes from/to unix timestamps instead of Interval
- Export INTERVAL_SECONDS from analytics-db for route reuse
- All 6 API routes accept from/to params (fallback to interval if absent)
- Timeline bucket size computed from duration rather than hardcoded per interval
- Fix map country click highlight: bake isSelected into GeoJSON features (data-driven)
  instead of relying on Layer filter prop updates (unreliable in react-map-gl v8)
- Split highlight into countries-selected (data-driven) and countries-hover (filter-driven)
- Show tooltip at country centroid when selected via table, hover takes precedence

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 10:38:02 +01:00
fuomag9
608fb9c6fe fix: detect blocked requests via caddy-blocker log entries, add country click→map highlight 2026-02-27 09:22:06 +01:00
fuomag9
69f222e51f feat: migrate world map to react-map-gl/maplibre with Natural Earth projection
- Replace D3/SVG choropleth with react-map-gl MapGL component
- Use Natural Earth projection for proper world view
- Embed traffic data (norm, total, blocked, alpha2) as GeoJSON properties
- Use feature state only for hover highlighting
- Add 1h and 12h interval options to analytics
- Add worker-src blob: to CSP for MapLibre web workers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 00:43:01 +01:00
fuomag9
8be69d2774 feat: add analytics dashboard with traffic monitoring
- Parse Caddy access logs every 30s into traffic_events SQLite table
- GeoIP country lookup via maxmind (GeoLite2-Country.mmdb)
- 90-day retention with automatic purge
- Analytics page with interval (24h/7d/30d) and per-host filtering:
  - Stats cards: total requests, unique IPs, blocked count, block rate
  - Requests-over-time area chart (ApexCharts)
  - SVG world choropleth map (d3-geo + topojson-client, React 19 compatible)
  - Top countries table with flag emojis
  - HTTP protocol donut chart
  - Top user agents horizontal bar chart
  - Recent blocked requests table with pagination
- Traffic (24h) summary card on Overview page linking to analytics
- 7 authenticated API routes under /api/analytics/
- Share caddy-logs volume with web container (read-only)
- group_add caddy GID to web container for log file read access

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 20:43:23 +01:00
fuomag9
3442beba19 fix: expand private_ranges to CIDRs before passing to caddy-blocker-plugin
The blocker plugin only accepts literal IP/CIDR strings; Caddy's built-in
'private_ranges' shorthand is not understood by third-party modules.
Expand it to the equivalent CIDR list at config-build time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-26 01:25:08 +01:00
fuomag9
75044c8d9b fix: harden security post-review (JWT exposure, rate limiter, token expiry, timing)
- Raw JWT never sent to browser: page.tsx uses peekLinkingToken (read-only),
  client sends opaque linkingId, API calls retrieveLinkingToken server-side
- link-account rate limiter now uses isRateLimited/registerFailedAttempt/
  resetAttempts correctly (count only failures, reset on success)
- linking_tokens gains expiresAt column (indexed) + opportunistic expiry
  purge on insert to prevent unbounded table growth
- secureTokenCompare fixed: pad+slice to expected length so timing is
  constant regardless of submitted token length (no length leak)
- autoLinkOAuth uses config.oauth.allowAutoLinking (boolean) instead of
  process.env truthy check that mishandles OAUTH_ALLOW_AUTO_LINKING=false
- Add Permissions-Policy header; restore X-Frame-Options for legacy UAs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 20:58:21 +01:00
fuomag9
b2238f3101 fix: gate unsafe-eval to dev, drop redundant X-Frame-Options, document PKCE+state
- CSP script-src 'unsafe-eval' is now dev-only; Next.js HMR needs it in
  development but the production standalone build does not
- Remove X-Frame-Options: DENY since frame-ancestors 'none' in CSP supersedes
  it in all modern browsers; keeping both creates a maintenance hazard
- Add comment explaining why state check is added alongside PKCE default

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 20:36:43 +01:00
fuomag9
b5b15c2496 fix: use explicit empty Buffer as HKDF salt and log legacy key fallback
- Replace empty string "" salt with Buffer.alloc(0) for explicit intent
  in security-critical HKDF call
- Add console.warn when legacy SHA-256 decryption path is taken so
  operators can track when all secrets have been re-encrypted

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 20:33:45 +01:00
fuomag9
48385684f9 fix: add PKCE to OAuth checks and HTTP security response headers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 18:43:00 +01:00
fuomag9
a1c18cf09c fix: derive AES key with HKDF for key separation from JWT signing key
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 18:42:46 +01:00
fuomag9
66ad3e9431 fix: enforce unique provider+subject constraint and harden sync route
- Change providerSubjectIdx from index to uniqueIndex in schema.ts to
  prevent multiple users sharing the same (provider, subject) pair,
  which caused non-deterministic sign-in resolution via findFirst.
- Add migration 0008_unique_provider_subject.sql: DROP the existing
  non-unique index and CREATE UNIQUE INDEX in its place.
- Validate INSTANCE_SYNC_MAX_BYTES env var in sync route: fall back to
  10 MB default when the value is non-numeric (e.g. 'off') or
  non-positive, preventing NaN comparisons that silently disabled the
  size limit.
- Return a generic error message to callers on applySyncPayload /
  applyCaddyConfig failure instead of leaking the raw error string;
  the original message is still stored internally via setSlaveLastSync.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 18:41:12 +01:00
fuomag9
618982484c fix: verify OAuth provider email against pending link to prevent account takeover
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 18:36:41 +01:00
fuomag9
9a189ea342 fix: store OAuth linking token server-side, remove JWT from URL and audit log
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 09:31:27 +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
9254d8e910 fix: use node:http for Caddy admin API calls to avoid Sec-Fetch-Mode CORS triggering 2026-02-23 23:49:05 +01:00
fuomag9
85af993c77 fix: add Origin header to Caddy admin API requests to satisfy CORS origin check 2026-02-23 22:27:31 +01:00
fuomag9
497e58db14 fix: include admin origins in generated Caddy config so they survive /load 2026-02-23 21:50:50 +01:00
fuomag9
fd9aa986d9 fix: correct enabled logic in geoblock merge and route injection 2026-02-23 19:56:37 +01:00
fuomag9
80177bf067 feat: inject blocker handler into proxy routes for geoblocking
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:56:37 +01:00
fuomag9
f54b7db96f fix: align GeoBlock hydrators with existing patterns in proxy host model
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:56:37 +01:00
fuomag9
e6e35646c0 feat: add GeoBlock types and hydration to proxy host model
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:56:37 +01:00
fuomag9
15208313a8 feat: add GeoBlockSettings type and helpers to settings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 19:56:37 +01:00
fuomag9
bb8a0d1023 implemented upstream pinning 2026-02-22 01:11:56 +01:00
fuomag9
7e4df5e50b removed redirect feature 2026-02-13 22:53:11 +01:00
fuomag9
eecacfb271 The static response feature has been completely removed 2026-02-09 01:15:28 +01:00
fuomag9
6d56cf2288 deprecate deadhosts, move it to the GUI as a custom response feature 2026-02-07 00:51:48 +01:00
fuomag9
90916bd709 various security fixes
Sync secrets encrypted at rest
Sync endpoint hardening
Avatar upload SVG restriction
2026-01-25 11:27:14 +01:00
fuomag9
6fb39dc809 Implement slave-master architecture 2026-01-25 01:39:36 +01:00
fuomag9
648d12bf16 The fix now properly merges the DNS resolver config into the existing transport, preserving TLS settings for HTTPS upstreams 2026-01-22 22:44:31 +01:00
fuomag9
7f93e9e784 Implement custom dns servers 2026-01-22 20:47:56 +01:00
fuomag9
49cf4f5ed1 added load balancing settings 2026-01-21 22:23:17 +01:00
fuomag9
8ec483b14f fix some permission stuff 2026-01-04 18:49:24 +01:00
fuomag9
be21f46ad5 Added user tab and oauth2, streamlined readme 2025-12-28 15:14:56 +01:00
fuomag9
9ca8bb4f15 Revert "Fix Authentik outpost callback by preserving original Host header"
This reverts commit b2183bf856.
2025-11-19 20:25:01 +01:00
fuomag9
454edba677 Fix outpost upstream dial address parsing
The outpost upstream was being passed directly to Caddy's dial field with the
full URL (http://host:port), but Caddy expects just host:port. This was causing
DNS lookup errors with a leading slash (/authentik.bologna.local.fuo.fi).

Now properly parses the URL to extract just the hostname and port.
2025-11-19 20:22:38 +01:00
fuomag9
b2183bf856 Fix Authentik outpost callback by preserving original Host header
The outpost route now preserves the original request host (e.g., email.fuo.fi)
instead of changing it to the upstream host. This allows Authentik to properly
construct redirect URLs after processing authentication callbacks.
2025-11-19 20:06:15 +01:00
fuomag9
5cad15e20e re-ordered paths for allowing custom paths correctly 2025-11-19 18:35:00 +01:00
fuomag9
7ae51ad034 enforce admin role by reading user role instead of hardcoding 2025-11-19 18:06:24 +01:00
fuomag9
bc3e28d5ab fix callback on protected paths 2025-11-19 17:57:14 +01:00
fuomag9
ab64b67844 Potential fix for code scanning alert no. 5: Prototype-polluting function
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-11-15 10:25:13 +01:00
fuomag9
06dc28fabd Added user logs functionality 2025-11-14 23:27:05 +01:00
fuomag9
58ec7e321e undo loki stuff 2025-11-12 23:22:30 +01:00
fuomag9
fa65dc1b2c Corrected Configuration for trea/caddy-loki-logger 2025-11-12 22:38:58 +01:00
fuomag9
a172595790 I've corrected the Caddy configuration structure. The error was because I placed logging inside the apps object, but in Caddy's JSON config, logging must be at the root level, alongside admin and apps. 2025-11-12 22:28:59 +01:00