Commit graph

1,676 commits

Author SHA1 Message Date
f9d66bf53e security: validate session ID format from Authorization header
Bearer tokens and Basic Auth usernames were used as session IDs without
any format validation, allowing arbitrary strings (including crafted or
very long values) to reach the storage layer as untrusted session IDs.

Restrict accepted session IDs to the exact format produced by
NewSessionID(): standard base32 alphabet [A-Z2-7], exactly 103 chars.
Any token that does not match is ignored, resulting in a new anonymous
session instead of a storage lookup with attacker-controlled input.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 15:03:49 +07:00
8ab02dffa8 security: propagate DeleteSession error in Save when MaxAge < 0
Previously, if session deletion failed (e.g. storage error), the error
was silently swallowed. The stale session could still be replayed via
Bearer token even after the client-side cookie was cleared.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 15:03:49 +07:00
90f07a215c security: rotate session ID on login to prevent session fixation
The server-side session store (gorilla/sessions backed by DB) reused the
same session ID across login: session.Clear() only zeroed the values map
but left session.ID unchanged. An attacker who planted a known session ID
before authentication retained access after the victim logged in.

Fix with a two-phase save:
1. Delete the old session from the DB (MaxAge=-1 save), expiring the cookie.
2. Reset the underlying gorilla Session.ID to "" so the store generates a
   fresh ID, then save the authenticated session with original cookie options
   (Secure, Path, MaxAge) preserved via a duck-typed interface assertion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 15:03:49 +07:00
b0b79efceb security: decouple failure tracking from captcha provider
Previously, RecordFailure/RecordSuccess were only called when a captcha
provider was configured, making brute-force tracking entirely inactive
on deployments without one.

- Always track login failures and successes regardless of captcha config
- When threshold is crossed with a captcha provider: 401 + captcha_required (existing behaviour)
- When threshold is crossed without a captcha provider: 429 + rate_limited flag
- Frontend: show a rate-limited message and disable the submit button on 429
- Add errors.rate-limited translation key to all locales

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 15:03:49 +07:00
d6e442f02b security: prevent email enumeration via timing side-channel
When the requested email does not exist, the function returned in
microseconds, while a valid email with wrong password took ~100ms
(bcrypt). An attacker could enumerate valid accounts by measuring
response latency.

Add a dummy bcrypt.CompareHashAndPassword call on the not-found path so
both branches take a comparable amount of time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 15:03:49 +07:00
a2c060639a security: remove email PII from error messages, log at HTTP boundary
Email addresses embedded in error strings could leak to arbitrary log
sinks or error responses as errors propagate. Strip them from the usecase
errors and instead log `IP email: reason` once at the controller level,
keeping fail2ban/CrowdSec-compatible log lines.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 15:03:49 +07:00
c16e9c243f Transparently rehash passwords with outdated bcrypt cost on login
Add a bcryptCost constant to centralize the target cost (12), a
NeedsRehash() method that checks the stored hash cost via bcrypt.Cost(),
and trigger a transparent rehash in AuthenticateUserWithPassword when
the stored hash is below the current target.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 13:06:20 +07:00
46a5d15aa4 security: increase bcrypt cost from default (10) to 12
OWASP now recommends bcrypt cost >= 12. Using the implicit default cost
of 0 (which maps to 10) is below current recommendations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 13:06:20 +07:00
043b81a350 security: enforce 72-character maximum password length
bcrypt silently truncates input at 72 bytes. Without an explicit maximum,
a user could set a 200-char password and log in with only the first 72
chars, and very long passwords could be used for a CPU-based DoS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 13:06:20 +07:00
a5601451cf fix(deps): update module golang.org/x/crypto to v0.49.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-11 23:12:39 +00:00
ce31eb09c4 fix(deps): update module golang.org/x/oauth2 to v0.36.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-11 13:13:14 +00:00
4f5f8b0ee6 chore(deps): update module github.com/happydomain/dnscontrol/v4 to v4.36.100
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-11 18:30:41 +07:00
0b1c5c789d chore(deps): update dependency go to v1.26.1 2026-03-11 18:30:41 +07:00
dcde50f56a web: Highlight current session with a Badge 2026-03-11 18:30:41 +07:00
6565b25473 fix: use first 6 bytes of SHA-256 for session fingerprint display
SHA-1 is cryptographically broken. Replace with SHA-256 and slice to
the first 6 bytes (12 hex chars) for a compact, human-readable token
fingerprint. 48 bits is more than sufficient to distinguish a handful
of active sessions without sacrificing readability.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 18:30:41 +07:00
378227d708 fix: return 204 No Content on session delete
DeleteSession was returning 200 with a null body instead of the
semantically correct 204 No Content. Updated the Swagger annotation
to match the new status code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 18:30:41 +07:00
36890cc432 web: Fix infinite loop on 401 when user is not logged in 2026-03-11 18:30:41 +07:00
d99e31d587 web: Increase margin under root domain name 2026-03-11 18:30:41 +07:00
a60489d0cf fix: update LastLoggedIn on successful password authentication
The field existed but was never written, making it useless for security
auditing. Record the time at each successful login and persist it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 18:30:41 +07:00
8cf643131d web: fix ServiceCombined JSON serialization for new service creation 2026-03-11 18:30:41 +07:00
54857e19c6 web: cache zone diff API results to avoid redundant network calls 2026-03-06 14:43:09 +07:00
7b8e6600fe web: replace /domains/new navigation with PickProvider modal
Introduces ProviderPicker and PickProvider reusable components so that
adding a domain from NewDomainInput or FilterDomainInput opens an
inline provider-selection modal instead of navigating away to
/domains/new/:dn.
2026-03-06 14:43:09 +07:00
e8af55a989 web: display onboarding form on home page with ?onboarding 2026-03-06 14:43:09 +07:00
03be1f7348 web: replace domains home page with an interactive table 2026-03-06 14:43:09 +07:00
0677b82dfc web: relook provider edit page and add provider sidebar 2026-03-06 14:43:09 +07:00
5f6b9a22b9 web: sync home filter state with URL query params 2026-03-06 14:43:02 +07:00
2e7713fec0 web: Format files and remove unused dependencies 2026-03-06 12:44:15 +07:00
827a92e77e web: replace providers list with an interactive table
Replace the ListGroup-based provider list with a Bootstrap Table on the
providers page. Rows are clickable to edit, the domain count links to
the domains page pre-filtered by provider, and action buttons handle
propagation correctly.
2026-03-06 12:44:15 +07:00
6a00090d0c web: replace providers/new page with NewProvider modal
Replace the dedicated provider type selection page with a modal,
using a module-level controller pattern. The /providers/new route
now redirects to /providers?newProvider, which auto-opens the modal.
2026-03-06 12:44:15 +07:00
6360938660 README: Include Matrix badge 2026-03-06 12:44:15 +07:00
77f9dde4bf web: add PageTitle component and apply it across all pages
Introduces a reusable PageTitle component with a teal overline accent,
display-3 heading, optional monospace domain label, subtitle, and a
children slot for future domain health/check badges. Applied consistently
to the zone viewer, history, logs, export, import, resolver, providers,
account settings, and new-domain pages.
2026-03-06 12:44:15 +07:00
5ece0f15ca web: document all functions in dns.ts with JSDoc 2026-03-06 12:44:15 +07:00
ba29d13a17 web: add service details offcanvas with DNS records and actions
Introduce ServiceDetailsOffcanvas, an offcanvas panel that opens when
clicking a service card. It displays the service description, its DNS
records, and provides actions buttons.

Also remove raw DNS record from service form.
2026-03-06 12:44:15 +07:00
efebd7e4e2 web: add DNS syntax highlighting with highlight.js
Install highlight.js and apply DNS zone file syntax highlighting on the
export page and in the RecordText component. Uses the github theme and
imports only the dns language to keep the bundle small.
2026-03-05 16:25:44 +07:00
044c6da31a web: replace ModalViewZone with a dedicated export page
Convert the zone file viewer from a modal dialog to a dedicated page at
/domains/[dn]/export, following the same pattern used for service pages.
Adds a "Copy to clipboard" button in the page title bar and adds the
common.copy-clipboard translation key to all supported locales.
2026-03-05 16:25:44 +07:00
91c431f23c web: Improve abstract view 2026-03-05 16:25:44 +07:00
35ea32dcea web: centralize service help link logic in HelpButton component
Introduce a helpLinkOverride store so the Header's help button can
display context-sensitive service docs. Move the svctype-to-URL
computation into Help.svelte (service prop + $effect), removing the
duplicated helpLink functions from the service edit page and the modal
Footer. Pages now render <HelpButton {service} /> to drive the override
without showing a redundant per-page button.
2026-03-05 16:25:44 +07:00
acf7c0d152 web: replace service modal with dedicated page and sidebar
Replace the Service modal component with a dedicated service page route
and a ServiceSidebar component, improving navigation by giving each
service its own URL under [subdomain]/[serviceid].
2026-03-05 16:25:44 +07:00
633a3d6c72 web: focus newly added SPF directive input on creation 2026-03-04 02:24:38 +07:00
36bf664eaa web: sync sidebar scroll with visible subdomain in main content
Use IntersectionObserver to track which subdomain section is currently
visible in the top 30% of the viewport, bold the matching sidebar link,
and auto-scroll the sidebar to keep it in view with scroll-margin-block
so adjacent items remain visible.
2026-03-04 02:24:38 +07:00
7217b6ab18 web: improve subdomain list styling with domain part highlighting
Split subdomain display to show the subdomain and domain parts
separately, making the root domain bold and dimming the domain
suffix. Add hover bold effect for text-dark links.
2026-03-04 02:24:38 +07:00
eb5e0adc0f web: extract zone sidebar into dedicated ZoneSidebar component
Refactor the domain layout by moving the zone-specific sidebar content
(subdomain list, zone actions dropdown) into a new ZoneSidebar.svelte
component, improving separation of concerns between zone and service views.
2026-03-04 02:24:38 +07:00
0782f99c19 docs: improve README with badges, ToC, contributing and license sections
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-02 10:35:58 +07:00
d588ade59d web: replace deprecated cuid with @paralleldrive/cuid2
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-02 10:08:27 +07:00
ec51c095d8 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-02 01:18:49 +00:00
e8a6f2bdbd web: Add transition to VoxPeople card and fix URL param
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-01 17:41:02 +07:00
f0bf1b0b62 web: Integrate BasePath support into frontend and fix web route serving 2026-03-01 17:41:02 +07:00
64c86df9ac Support configurable BasePath for hosting at a sub-path 2026-03-01 17:41:01 +07:00
bf34051069 Reformat manifest.json, add id and fix spelling 2026-03-01 17:40:20 +07:00
ac441a0a25 web: fix service worker caching bugs
- Add network fallback for asset cache misses (prevents broken requests
  on install race conditions)
- Fix query string stripping to use a clean Request instead of copying
  event.request options
- Await cache.put() calls to prevent incomplete writes on SW termination
- Expand auth path exclusion to startsWith("/api/auth") to cover all
  auth-related endpoints
2026-03-01 17:40:20 +07:00