Commit graph

51 commits

Author SHA1 Message Date
d57c0849a6 compliance: MX record sync validators
Validates a MX record set (svcs.MXs) at edit time:

- Null MX (RFC 7505): a "." target must be the only MX in the set, with
  preference 0. Both deviations are surfaced.
- Targets: invalid hostnames, out-of-range preferences (uint16) and
  duplicate targets (case-insensitive on the FQDN).
- Cross-zone: flags MX targets that are CNAME owners in the same zone
  (RFC 5321 sec. 5.1) and warns when an in-zone target lacks any
  A/AAAA service. External targets are left to runtime checkers.

Unit tests cover happy paths, the null-MX edge cases, target/preference
validation, duplicate detection and the in-zone cross checks (CNAME
collision, missing address, apex target).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
8a340251b7 bimi: support BIMI declination records
The BIMI draft lets a domain explicitly opt out of BIMI by publishing
a record with v=BIMI1 and an empty l= tag. Surface that in the editor
and treat it as a first-class case in compliance.

- bimi.ts gains isBIMIDeclination() and stringifyBIMIDeclination().
- The editor adds a "Decline to participate in BIMI" checkbox; when
  checked, the l/a/e fields are hidden and the TXT record is rewritten
  to "v=BIMI1;l=". The checkbox is auto-detected when an existing
  declination record is loaded.
- The compliance validator detects declination right after the
  selector and version checks, emits a single bimi.declination info
  message, and skips the URL/cross-record checks that no longer apply.
- Locales updated (en, fr).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
87daea03d3 compliance: BIMI record sync validators
Plugs the BIMI editor into the records-compliance framework.

Validators run synchronously and surface:

- Owner-name shape: <selector>._bimi (rejects empty selectors and
  non-label characters).
- Version: only "BIMI1" is accepted by the current draft.
- Logo URL: l= is mandatory, must be HTTPS, warns when the path does
  not end in .svg.
- VMC URL: optional but flagged as info when missing (Gmail and Yahoo
  need it). Must be HTTPS when present; info if it does not look like
  a .pem file.
- Evidence URL: must be HTTPS when present.
- Cross-record DMARC check: warns when no DMARC is published or when
  every DMARC at the apex sits at p=none, since BIMI is only honoured
  with an enforcing DMARC policy.

Locales added under compliance.bimi for en and fr. The new validator
self-registers via $lib/services/compliance/registry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
100d403a8b compliance: DMARC cross-checks against zone DKIM and SPF
Extends the compliance context with findAllServices(type?) so a
validator can iterate every service in the zone, not just a single
subdomain. The DMARC validator now uses it to flag configurations
where alignment is structurally impossible:

- p=quarantine|reject and the zone has neither a DKIM nor an SPF
  record -> error: every legitimate message will fail DMARC.
- p=none in the same situation -> warning: DMARC has nothing to
  align against, monitoring data will be empty.
- adkim=s (strict DKIM alignment) with no DKIM record published
  anywhere in the zone -> warning: only SPF alignment can succeed.

Cross-checks are skipped when the zone state is not provided
(ctx.zone === null), so unit tests and isolated calls keep the
previous behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
f4fd57facc compliance: MTA-STS async policy fetch
Wires the new POST /api/resolver/mta-sts-policy endpoint into the
MTA-STS validator. The async pass runs after the local TXT checks,
debounced and cancellable through EditorCompliance, and surfaces:

- Transport-level failures: dns-error, tls-error, fetch-error,
  too-large.
- HTTP-level failures: not-found (404), http-error (other non-2xx),
  redirect (server tried to redirect, RFC 8461 sec. 3.3 forbids it).
- Policy file content: missing/invalid version, missing/invalid mode,
  mode=none (warning, effectively disabled), mode=testing (info),
  missing mx in enforce/testing modes, missing/out-of-range max_age
  (0..31557600), short max_age (< 1 day, warning).

Adds a fetchMTAStsPolicy() wrapper to $lib/api/resolver.ts that accepts
an AbortSignal so the EditorCompliance debounce + abort plumbing covers
this validator like it does for SPF.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
4498c1f1c4 compliance: TLS-RPT record sync validators
Adds checks for svcs.TLS_RPT against RFC 8460 sec. 3.

The validator surfaces:

- Wrong owner name (must be _smtp._tls.<domain>).
- Missing or non-TLSRPTv1 v= tag.
- Missing rua= report destination.
- Empty entries inside rua=.
- rua URIs that are neither mailto: nor http(s):.
- Malformed mailto URIs (missing @ or domain).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
04d0d83965 compliance: MTA-STS record sync validators
Adds checks for svcs.MTA_STS against RFC 8461 sec. 3.1.

The validator surfaces:

- Wrong owner name (must be _mta-sts.<domain>).
- Missing or non-STSv1 v= tag.
- Missing id= tag.
- id= containing characters outside [A-Za-z0-9] or longer than 32 chars.

The TXT only carries the policy pointer; the actual policy file at
mta-sts.<domain>/.well-known/mta-sts.txt is out of scope here and will
need an HTTPS fetch (out of scope for the sync pass).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
cec4f11c7d compliance: DMARC record sync validators
Adds compliance checks for svcs.DMARC against RFC 7489.

The validator parses the published TXT and surfaces:

- Wrong owner name (record must live at _dmarc.<domain>).
- Missing or non-DMARC1 v= tag.
- Missing, unknown, or "monitoring-only" p= policy.
- Invalid sp= subdomain policy.
- Invalid adkim/aspf alignment values.
- pct= out of [0..100] (error) and pct < 100 (info, partial deployment).
- Non-positive or non-numeric ri=.
- Unknown fo= entries (0 / 1 / d / s) and unknown rf= formats (afrf).
- Empty or malformed rua/ruf URIs (mailto and http(s) accepted; mailto
  size suffix !N preserved).

A 25-case test suite covers each issue id, plus happy paths for a
minimal reject record and rua mailto/http URIs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
a210526287 compliance: SPF async recursive flatten
Wires the new POST /api/resolver/spf-flatten endpoint into the SPF
validator. The async path runs after the local checks, debounced and
cancellable through EditorCompliance, and surfaces:

- spf.recursive-many-lookups / spf.recursive-too-many-lookups based on
  the recursive lookupCount returned by the backend
- spf.too-many-void-lookups when more than 2 NXDOMAIN/NoData responses
  occur during the walk (RFC 7208 §4.6.4)
- per-include diagnostics: spf.include-loop, spf.include-no-spf,
  spf.include-resolver-error, spf.include-error — pointing at the exact
  domain and mechanism that failed

The async pass is skipped entirely when the local lookup budget is 0,
to avoid a network roundtrip on records that obviously cannot exceed
the limit.

A small flattenSPF() helper is added to $lib/api/resolver.ts to wrap
the auto-generated SDK call and accept an AbortSignal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
a6f32a5f02 compliance: SPF local validators
Extracts the SPF parser/serializer out of the editor into
$lib/services/spf.ts (matching dmarc.ts / mta_sts.ts) and adds a sync
validator that flags non-recursive issues against RFC 7208:

- missing or wrong v=spf1
- absence / multiplicity / non-final placement of ‘all’
- redirect= combined with ‘all’ or duplicated
- ptr deprecation (RFC 7208 §5.5)
- local DNS-lookup budget (warn ≥8, error >10) — recursive flatten will
  come later via an async backend endpoint
- mechanisms missing values, empty terms, duplicates, length cap

24 unit tests cover positive and negative cases. The editor itself loses
its inline parser and reuses the shared module; behavior is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:30 +07:00
f435f06a62 compliance: always show panel when validators are registered
Previously the compliance section stayed completely hidden until at
least one issue was reported, which made it indistinguishable from a
broken validator hookup. The panel now renders as soon as a validator
is registered for the current service type, with a "All checks passed"
status when the issue list is empty and the async pass is idle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:29 +07:00
e9ebecc4cd compliance: DKIM record sync validators
Plugs the first per-record compliance validator into the framework.

Validates a DKIM TXT record (svcs.DKIMRecord) at edit time:

- Selector: must be present, must match the label charset.
- Version: only "DKIM1" is accepted (RFC 6376 sec. 3.6.1).
- Public key: detects missing p=, empty p= (revocation, warning), and
  non-base64 payloads. Warns on RSA keys shorter than ~2048 bits and
  errors on RSA keys shorter than ~1024 bits per RFC 8301.
- Algorithms: warns on SHA-1 (RFC 8301) and unknown hashes; flags
  unknown key types or service types.
- Flags: surfaces t=y (testing) as info; warns on unknown flags.
- Granularity: marks g= as deprecated since RFC 6376.

A unit test suite exercises every issue id plus a few happy paths and
the empty-input case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:29 +07:00
bc43dec6ba compliance: add records-compliance infra (types, registry, editor panel)
Introduces the frontend-only compliance framework that lets each editor
contribute spec-conformance checks. The infra is self-contained:

- $lib/services/compliance.ts exposes ComplianceIssue/Severity/Validators
  types plus a small registry API.
- $lib/services/compliance/registry.ts is the central side-effect import
  point where per-record validators get wired up commit by commit.
- EditorCompliance.svelte renders sync issues immediately and runs async
  validators with a debounce + AbortController; it stays hidden when no
  validator is registered and when there are zero issues.
- ServiceEditor.svelte mounts the panel under every loaded editor; no
  per-editor wiring is needed.
- locales: new "compliance" namespace (en, fr) for shared UI strings.

No validators are registered yet, this commit is intentionally inert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:52:29 +07:00
57de739f80 web: add Prometheus metrics URL link to checker config page 2026-04-16 17:08:05 +07:00
8a546a8b41 domaininfo: add RDAP/WHOIS lookup feature
Introduces a domaininfo package with RDAP and WHOIS getters, exposed
through a new DomainInfoUsecase and /api/domaininfo/:domain route (also
mounted under domain scope). Adds a /whois frontend page and a zone
sidebar modal to display registrar, dates, nameservers and status.
2026-04-16 15:22:51 +07:00
e0dc19614f checker: enforce MaxChecksPerDay quota with interval-aware throttling
Some checks failed
continuous-integration/drone/push Build is failing
Wire UserQuota.MaxChecksPerDay field into the scheduler via the
UserGater: an in-memory daily counter per user
(reset at UTC midnight): gates scheduled executions, with a two-tier
heuristic that skips short-interval jobs first once the budget is 80%
consumed so rare/important checks are not starved by frequent
pings. Planned executions returned by ListPlannedExecutions are marked
with a new ExecutionRateLimited status when the user is over
budget. Manual API triggers bypass the quota.
2026-04-16 15:18:43 +07:00
fb02331f41 checkers: show children checkers on domain page and hide scheduling for non-domain checkers
Add a separate section on the domain checks page to display zone and
service-level checkers that can be configured but won't produce results
at the domain scope. Hide the scheduling and rules cards when configuring
a non-domain checker from the domain context.
2026-04-16 15:18:43 +07:00
4e034b0135 checkers: integrate rules as a view tab in execution detail page
Remove separate /rules pages and display rules as a tab alongside
metrics, HTML, and JSON views. Rules become the default view when
no metrics or HTML report is available. Status is now shown as a
colored badge in the rules table.
2026-04-16 15:18:43 +07:00
322ade2881 checkers: add frontend metrics chart on execution pages
Add Chart.js-based line chart for checker metrics. The chart appears
on the executions list page (aggregated) and on individual execution
detail pages. Metrics view mode is selectable via the sidebar alongside
HTML report and raw JSON views.
2026-04-16 15:18:43 +07:00
7a4de13ac6 checkers: add frontend UI components and routes
Add all checker UI pages and components:
- Checker list, config, schedule, and rules pages
- Execution list, detail, results, and rules pages
- Sidebar components for domain/service checker status
- Run check modal with option overrides and rule selection
- Domain-scoped and service-scoped check routes
- Admin pages for checker configuration and scheduler management
- Header navigation link for checkers section
2026-04-16 15:18:43 +07:00
ee560a699d checkers: add frontend API client, stores, and utilities
Add the frontend infrastructure for the checker UI:
- API client with scoped helpers for domain/service-level operations
- Svelte stores for checker state (currentExecution, currentCheckInfo)
- Utility functions for status colors, icons, i18n keys, date formatting
- Shared helpers: withInheritedPlaceholders, downloadBlob, collectAllOptionDocs
- English translations for all checker UI strings
- Zone model and form types extended for checker support
2026-04-16 15:18:43 +07:00
exyone
9a3f834129 Improve Chinese translation and fix English translation errors (manually translated)
Add Esperanto, Manchu, and Tibetan translations (AI-assisted with manual review)
2026-04-16 02:14:18 +07:00
197fd9c796 Redesign UI: modernize layout, login, resolver, and some components
Refresh the overall visual design across the frontend: floating labels
and centered card layout for auth pages, animated sidebar+results view
for the resolver, polished dropdown menus, toasts, and feedback widget,
and cleaner global styles (navbar shadow, border, transitions).
2026-04-14 05:08:01 +07:00
e103d2262a Add DNS propagation time tracking per service
After publishing zone corrections, compute and store a PropagatedAt
timestamp on each affected service indicating when old cached records
will have expired. For updated/deleted services, this is publish_time +
old service TTL. For new services, it uses the SOA minimum TTL
(negative cache duration), falling back to the zone's DefaultTTL.

The propagation detection reuses the same service matching technique as
ReassociateMetadata (subdomain + type + ServiceRDataHash). Both the
published snapshot and the WIP zone are stamped.
2026-03-30 11:58:02 +07:00
7d89e120a9 web: Add propagation loading screen and wait.preparation/propagation locale keys
All checks were successful
continuous-integration/drone/push Build is passing
2026-03-22 07:42:13 +07:00
a47d0d4196 web: Add service.edit locale key and use it in ServiceDetailsOffcanvas 2026-03-22 07:42:13 +07:00
a7b225b9df Rework zone diff/apply flow: separate diff from provider API, support partial apply
Decouple diff computation from executable provider closures by fetching
provider records and computing diffs locally via DNSControlDiffByRecord.
On apply, build a target record set from user-selected corrections using
BuildTargetRecords, then ask the provider for executable corrections
against that target. A published snapshot is inserted at ZoneHistory[1]
while the WIP zone at position 0 remains unchanged.
2026-03-16 19:46:09 +07:00
07b5553369 Add public DNS record generator pages at /generator
Expose service editors publicly (no auth required) at /generator for
SEO discoverability. Each page shows an interactive editor alongside
a live DNS zone record preview powered by a new POST
/service_specs/:ssid/records backend endpoint.
2026-03-16 19:44:13 +07:00
943d9b2a0c web: Add drag-and-drop domain group reassignment in ZoneList
When display_by_groups is enabled, domains are now draggable and group
containers act as drop targets. Dropping a domain onto a different group
updates its group via the API and refreshes the domain list.
2026-03-15 17:40:15 +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
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
03be1f7348 web: replace domains home page with an interactive table 2026-03-06 14:43:09 +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
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
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
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
d664bee36d web: Fix coding-style issues 2026-03-01 17:40:20 +07:00
0090054324 Add CAPTCHA support for login and registration
Integrates optional bot protection on the registration endpoint (always
required when a provider is configured) and the login endpoint (triggered
after N consecutive failures for the same IP or email address).

Supported providers: hCaptcha, reCAPTCHA v2, Cloudflare Turnstile.
2026-02-13 11:31:37 +07:00
3bada097a7 ui: Modernize aspects of the resolver page 2026-01-14 17:34:15 +08:00
a20f52f0a7 ui: Modernize aspects of providers page 2026-01-14 17:34:05 +08:00
e17649d5f2 ui: Modernize aspects of settings page 2026-01-14 17:17:55 +08:00
e8e2f2de0b ui: Improve domain settings dropdown
Fixes: https://github.com/happyDomain/happydomain/issues/43
2026-01-13 21:12:00 +07:00
dc880d31a8 Handle CAA issuevmc, contactemail and contactphone
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2026-01-12 15:46:41 +07:00
f1f65a9b13 ui: Refactor components architecture 2026-01-08 18:15:37 +07:00
e874d9aa44 Finish no-mail mode support for standalone deployments
All checks were successful
continuous-integration/drone/push Build is passing
2026-01-02 21:48:45 +07:00
d30baef2bd Refactor SubdomainItem: split Header 2025-06-19 15:37:14 +02:00
b50201e1f9 Remove label to Spinner components 2025-06-18 02:08:26 +02:00
050cf79cd1 Add a search input in service selector modal
Closes: https://github.com/happyDomain/happydomain/issues/23
2025-05-31 20:54:21 +02:00
18cf82ea89 Rework domain list page: add a search field 2025-05-31 20:54:21 +02:00
f63860af83 Can create domain directly on the provider if supported
All checks were successful
continuous-integration/drone/push Build is passing
Closes: https://github.com/happyDomain/happydomain/issues/24
2025-05-28 23:02:22 +02:00