Commit graph

2,092 commits

Author SHA1 Message Date
1ecbc03143 fix(kvtpl): Unable to fully restore a fresh backup
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-06 20:14:20 +09:00
fe988aff0b fix(restore): reject backups from a mismatching schema version
Backup payloads carry the source SchemaVersion but Restore ignored it,
silently importing data shaped for a different schema. Compare against
the current store schema upfront and abort with a clear error;
versionless legacy dumps (Version == 0) are still accepted.
2026-06-06 20:14:20 +09:00
d0c4e46980 fix(restore): tolerate service bodies with nil inner pointers
A backup payload whose service body lost its inner pointer (e.g. a PTR
without Record) caused Service.MarshalJSON to panic during restore,
aborting the whole zone write. Wrap GenComment/GetNbResources in a
recover so the surrounding zone still persists, and nil-guard
PTR.GenComment to avoid the dereference in the first place.
2026-06-06 20:14:20 +09:00
12cde8089f feat(ionos): split auth token into public prefix and secret fields
Users no longer need to know the dot-delimited token format; the provider
form now collects the public prefix and secret separately and joins them
when constructing the libdns provider.
2026-06-06 20:14:20 +09:00
b855b17fee metrics: add method label to storage operation metrics
Distinguish full-scan call sites from point lookups that share the same
operation+entity labels (e.g. GetAuthUserByEmail vs GetAuthUser), and
extend the duration histogram buckets to 30s so scan tails are visible
instead of collapsing into +Inf.
2026-06-06 20:14:20 +09:00
7a735618a4 feat(checker): consume CheckEnabler eligibility gate from SDK
Bump checker-sdk-go to v1.10.0 and apply the whole-checker eligibility
verdict (Eligible/EligibilityReason from POST /definition) with fail-open
semantics: hide/skip a checker only on a definitive negative. The listing
flow drops ineligible checkers from the "what runs" view and annotates them
in the management view; the scheduler honours the verdict at launch time.
2026-06-06 20:14:19 +09:00
5ccf81173f feat(checker): add domain availability watchlist
Introduce a DomainAvailabilityWatch entity (model, storage, usecase and
REST endpoints) letting a user track a domain they do not own and get
notified the moment it becomes available for registration. A dedicated
domain_availability checker reads WHOIS/RDAP via pkg/domaininfo and inverts
the status (OK while registered, Crit once free) so the existing dispatcher
fires exactly once on the transition. The scheduler enumerates watches and
enqueues the check, carrying the watch id in CheckTarget.DomainId; autofill
and notification payloads fall back to the watch store to resolve the name.
Watches are included in per-user backup/restore. The web UI adds an
availability watchlist page and navigation entry.
2026-06-06 20:14:01 +09:00
0d40971940 feat(domains): support monitor-only domains without a provider
Make Domain.ProviderId optional so a user can monitor the registration
status (WHOIS/expiry, lock, propagation) of a domain hosted on a provider
happyDomain does not support. Add Domain.IsManaged() and guard the
provider-coupled paths (zone import, correction listing, tidy) so a
monitor-only domain degrades cleanly instead of dereferencing a missing
provider. The web add-domain flow gains a "monitor only" option and the
domain detail view hides zone editing for these domains.
2026-06-06 20:14:01 +09:00
337173ec63 leveldb: compact the keyspace periodically to reclaim tombstones
Deletes from the retention janitor and tidy passes leave tombstones that
LevelDB only compacts opportunistically, slowing prefix scans for hours. A
background worker now runs a full-keyspace CompactRange on a configurable
interval (-leveldb-compaction-interval, default 24h, 0 disables). Its
lifecycle is bound to the store: Close stops the worker before closing the
DB so no compaction races the close.
2026-06-06 20:14:01 +09:00
ae5e9f7ed3 leveldb: tune engine options and expose them as flags
Open LevelDB with a larger block cache, write buffer, open-files cache,
compaction table size and a Bloom filter instead of the small goleveldb
defaults, since the workload is dominated by point lookups. All values
are exposed as flags so operators can tune them per deployment.

Also fix the recovery path discarding the recovered DB handle, which
left the storage with a nil database after a successful RecoverFile.
2026-06-06 20:14:01 +09:00
3297b5e2a3 checker: reject checker IDs containing the storage key separator
A checker ID is embedded verbatim in several "|"-delimited storage keys
(chckrcfg|, chckpln-chkr|, chckexec-chkr|, ...). An ID containing "|"
would misalign key parsing and let records collide. Validate at the
registration boundary and refuse such IDs.
2026-06-06 20:14:01 +09:00
215ea177b1 storage: disable HTML escaping on the value marshal path
Route every backend write through a shared storage.Marshal helper that uses
a json.Encoder with SetEscapeHTML(false), so stored payloads no longer waste
encoder work escaping <, > and & that never reach a browser as raw HTML.
2026-06-06 20:14:01 +09:00
747a0a243a kvtpl: drop quadratic orphan-index scans in delete-by-checker
The fallback path in DeleteExecutionsByChecker and DeleteEvaluationsByChecker
scanned whole secondary-index prefixes per orphan, turning a delete loop into
O(orphans x index size). Rebuild the user and domain execution index keys
directly from the checker key's shared trailing segments instead, and leave the
planId-first plan index, unknowable from a missing primary, to the Tidy jobs.
Also remove the now-dead deleteCheckPlanSecondaryIndexesByPlanID.
2026-06-06 20:14:00 +09:00
925c05965b kvtpl: store empty value in notifrec user index
Align the notifrec-user index with the notifch/notifpref pattern: the
index now holds an empty value and records are resolved through the
primary key, dropping the previous double-write of the full record.
2026-06-06 20:14:00 +09:00
4618e01493 kvtpl: push LIMIT down to scan via reverse-chrono index keys
The checker, user and domain execution indexes and both evaluation
indexes now embed a reverse-chronological time segment, so a forward
prefix scan returns the newest entries first and stops at the requested
limit instead of loading every match and sorting it in memory.
GetLatestEvaluation becomes a single-row read. migrateFrom11 (still
unpublished) rebuilds the affected indexes from the primary records.
2026-06-06 20:14:00 +09:00
479e9554bc kvtpl: close PutDiscoveryObservationRef Get-then-Put race
Two concurrent writers targeting the same observation-ref primary key could
both observe the same old snapshot id, each stage a delete for it in their
batch, and each commit its own snap-index. The loser's snap-index would
outlive its primary write and the next cascade delete of THAT snapshot
would erase a primary that no longer belongs to it.

Serialize the Get and the batch commit per primary key through a 64-shard
mutex table on KVStorage, picked by FNV-1a hash of the primary key.
2026-06-06 20:14:00 +09:00
c63c7d42ec kvtpl: migrate remaining multi-key writes to Batch
Migrate Update/Delete/Restore variants for executions, plans, evaluations,
channels, preferences, records, plus ReplaceDiscoveryEntries and the
cascading deletes to use the Batch primitive, so primary records and their
secondary indexes are committed atomically instead of leaving the tidy job
load-bearing.
2026-06-06 20:14:00 +09:00
5cf6ed4602 kvtpl: Implement transactions on KV databases 2026-06-06 20:14:00 +09:00
2ef0bfac91 kvtpl: Remove full-table scans on hot paths 2026-06-06 20:14:00 +09:00
2eb1f830b7 fix(deps): update module github.com/prometheus/common to v0.68.1
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-03 08:10:58 +00:00
4c3e368af4 chore(deps): update go toolchain directive to v1.26.4
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-02 22:13:23 +00:00
e517b5cb0d chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-01 00:11:41 +00:00
71f4cedf56 fix(deps): update module git.happydns.org/checker-sdk-go to v1.10.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-29 17:14:09 +00:00
df48d28971 fix(deps): update module github.com/prometheus/common to v0.68.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-29 16:10:55 +00:00
5580d92ad5 checker: add -disable-checker-scheduler to skip scheduler auto-start
All checks were successful
continuous-integration/drone/push Build is passing
Lets operators boot without the checker scheduler running. It can still
be enabled at runtime through the admin API.
2026-05-29 09:04:17 +08:00
5b7271ed2d web: extract Sidebar component from domain layout 2026-05-26 11:54:13 +08:00
c22cdc91e8 hadmin: use HAPPYDOMAIN_ADMIN_BIND and handle TCP addresses
All checks were successful
continuous-integration/drone/push Build is passing
Replace the non-standard HAPPYDOMAIN_SOCKET variable with
HAPPYDOMAIN_ADMIN_BIND, matching the config env var. Handle TCP bind
addresses (:8080, 0.0.0.0:8080, [::]:8080) in addition to Unix sockets.
2026-05-25 23:39:19 +08:00
195430de83 fix(deps): update module git.happydns.org/checker-resolver-propagation to v0.2.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-25 23:10:57 +08:00
809cb58621 fix: use %v instead of %q for ServiceMessage in error format
All checks were successful
continuous-integration/drone/push Build is passing
2026-05-25 18:37:54 +08:00
6bf47a673f Upgrade dnscontrol to the latest release
Some checks failed
continuous-integration/drone/push Build is failing
Include the org migration from StackExchange to DNSControl

Add the new Netbird API
2026-05-25 18:15:25 +08:00
ce0e8e2cfe web: sort listScopedCheckers results alphabetically at the source
Move the by-name sort into listScopedCheckers so every consumer gets a
stable ordering, and drop the redundant sort wrappers in CheckerListPage
and CheckResultsDashboard.
2026-05-25 16:34:08 +08:00
02a53e85ce checker: filter listing to scheduled checkers by default
Add with_availables query param to checker status endpoint; restrict
default listing to checkers that auto-schedule or have an active plan.
Introduce IsAutoScheduled helper unifying scheduler eligibility logic.
2026-05-25 16:10:27 +08:00
3213d00ff4 web: split checker config (/checkers) from runtime results (/checks)
The route at /domains/[dn]/checks listed checker configurations, not check
runs. Rename it to /checkers and use /checks for a new aggregated dashboard
that surfaces the latest result for every enabled checker across the domain
and its services in one place. Same split applied at service scope.
2026-05-25 16:10:24 +08:00
758c889c8f feat(admin): add per-user stats endpoint and stats view
All checks were successful
continuous-integration/drone/push Build is passing
Expose GET /api/users/stats returning provider, domain and zone counts
per user. Zone count is derived from the ZoneHistory length of each
domain. Wire the new endpoint in the admin UI as a sortable table at
/users/stats.
2026-05-25 12:31:07 +08:00
e438c5d25e refactor: use Identifier.Equals() instead of bytes.Equal 2026-05-25 12:25:43 +08:00
180f125dcb Include local database and more binary products 2026-05-25 12:25:43 +08:00
f28cdefa8b Add user data export (GDPR/DSAR)
Refactors the admin backup usecase to share per-user collection logic
via backupOneUser(), then adds BackupUser() which filters system-wide
collections (checker configs, plans, evaluations, executions, discovery)
down to the requesting user by UserId.

Wires the backup usecase into the public API dependency graph and adds
a download button in the /me settings page near the delete-account
section.
2026-05-25 12:25:43 +08:00
f2a13fc12c chore(deps): replace svelte-preprocess with vitePreprocess
All checks were successful
continuous-integration/drone/push Build is passing
svelte-preprocess v6 dropped the TypeScript transformer since Svelte 5
and @sveltejs/vite-plugin-svelte handle TypeScript natively via Vite.
2026-05-25 11:30:36 +08:00
f19b686348 chore(deps): lock file maintenance
Some checks failed
continuous-integration/drone/push Build is failing
2026-05-25 03:10:42 +00:00
7f07e06806 providers: add Spaceship DNS provider
Some checks are pending
continuous-integration/drone/push Build is running
2026-05-25 10:49:09 +08:00
0ee081eb8c providers: add TOTP key support to INWX provider
Bug: https://github.com/happyDomain/happydomain/issues/46
2026-05-25 10:49:04 +08:00
e1eac4dd1f web: refactor checker config pages to scope-aware unified groups layout
Some checks failed
continuous-integration/drone/push Build is failing
Replace the per-route editableGroups/readOnlyGroups callback pair in
CheckerConfigPage with a single groups prop that returns both lists, and
switch all call-sites to buildOptionGroupLayout. Add showCheckerInfo and
showExecutions flags so the admin checker page can reuse CheckerConfigPage
without schedule controls or execution links.

CheckerOptionsPanel now shows an "Overriding inherited" badge and a
"Reset to inherited" link for fields where a local value shadows an
inherited one. CheckerOptionsGroups shows the effective inherited value
next to the type hint in read-only groups.
2026-05-24 18:24:50 +08:00
6954f312f9 web: add serviceOpts support and buildOptionGroupLayout utility
Extend collectAllOptionDocs, splitPositionalOptions, and
collectAutoFillKeys to include serviceOpts alongside the existing
adminOpts/userOpts/domainOpts buckets.

Add buildOptionGroupLayout which derives editable/read-only group lists
from the checker's option documentation and a CheckerPageScope ("admin",
"domain", or "service"). This consolidates the per-route hand-curated
arrays into one place.

Improve splitPositionalOptions with an optional isCurrentScope predicate
so the correct positional is selected for the page's scope instead of
always taking the last stored entry.
2026-05-24 18:24:36 +08:00
6005dbd18a web: add admin scope support to checker API helpers
Make CheckerScope.domainId optional so callers can target the global
admin scope (no domain). getScopedCheckStatus, getScopedCheckOptions,
and updateScopedCheckOptions now short-circuit to the admin /checkers/*
routes when domainId is absent. All narrower-scope callsites gain the
non-null assertion required by the type change.
2026-05-24 18:24:21 +08:00
576b7bc406 checkers: fix options usecase: copy-on-return and filter scope-inappropriate options
Callers like MergeCheckerOptions and SetCheckerOption mutated the map
returned by getScopedOptions before persisting; the store may hand back
a shared reference so mutating it caused silent state corruption. Return
a copy instead.

Add filterOptionsForScope which drops auto-fill keys (system-provided at
runtime) and NoOverride keys declared at a broader scope, so saving at a
narrow scope cannot accidentally persist fields that belong elsewhere.
2026-05-24 18:23:52 +08:00
b9dacbcaea notification: use per-channel email address for notification payloads 2026-05-24 18:23:45 +08:00
6ceebe2adb web: disable metrics/json view buttons when data is unavailable
Add a `disableMetrics` store that gets set when metrics fail to load,
preventing users from switching to a broken metrics view. Also disable
the JSON view button when no observations data is present.
2026-05-24 18:23:42 +08:00
71654269b6 checkers: normalize EPP lock statuses before comparing
Some checks failed
continuous-integration/drone/push Build is failing
WHOIS data may report statuses as "client transfer prohibited" (spaced,
lowercase) while the configured required value is camelCase
"clientTransferProhibited". Strip spaces, dashes and underscores when
comparing so all common formats match.
2026-05-24 17:26:35 +08:00
680e4dc6e2 web: Improve ui when captcha is required 2026-05-24 17:26:35 +08:00
47049c5b6e web: fix screen freeze after service deletion when zone ID changes
Remove the invalid bind:rr chain between RecordLine and RecordText (RecordText only reads rr, never writes back), and use refreshDomains + invalidateAll instead of directly setting thisZone when the returned zone has a new ID, matching the pattern already used in the domain layout.
2026-05-24 17:26:35 +08:00