Commit graph

2,126 commits

Author SHA1 Message Date
455e2301a7 providers: add Scaleway provider via libdns/scaleway 2026-07-12 20:46:15 +08:00
75861fe990 help: map app routes to the correct help pages
Update getHelpPathFromRoute to point at the help pages that actually
exist: rename source-* links to provider-*, the home alias to domains,
and add coverage for login, signup, notifications, provider features,
domain history, import/export, subdomains, services, checks,
availability and whois routes.
2026-07-12 20:46:15 +08:00
ef4d4f601b web: add ETags to no-cache index.html and manifest.json
Both documents are served no-cache but had no validator, so every
revalidation re-downloaded the full body and could never return 304.
Serve them via http.ServeContent with an ETag computed once at handler
creation, letting conditional requests answer 304. manifest.json is now
pre-rendered once instead of re-read and re-transformed per request.
2026-07-12 20:46:15 +08:00
d20b758c52 web: always revalidate service-worker.js
The service worker controls all client-side caching, so it must never be
pinned to an old version. It was served with no explicit cache policy;
mark it no-cache so updates are always picked up.
2026-07-12 20:46:15 +08:00
d19a28783a web: stop marking stable static assets immutable
/fonts, /img and /favicon.ico live at stable, non-content-hashed URLs, so
the 7-day immutable header meant a changed favicon, image or font would
not reach already-cached clients for up to a week.

Serve them with a revalidated policy (max-age=86400, must-revalidate) set
on the successful response instead, and drop the now-unused immutable
middleware. Only the content-hashed /_app tree keeps immutable.
2026-07-12 20:46:15 +08:00
b9f3314e12 web: don't let /_app 404s be cached as immutable
The immutable middleware set Cache-Control before the handler ran, so a
missing content-hashed asset under /_app/immutable/ 404'd with the 7-day
immutable header still attached: a stale client could pin a negative
response for a week. The stale-bundle fallback also only covered .js,
leaving dropped .css (and other) chunks exposed.

Open the asset first and set the immutable directive only on a successful
serve, so a 404 never inherits it. Broaden the stale-asset path to mark
any missing /_app/immutable/ response no-cache, still returning the
self-healing reload module for .js.
2026-07-12 20:46:15 +08:00
2b9dd2d503 checker: make remote endpoint HTTP timeout configurable
Surface the remote (externalized) checker HTTP timeout through the
standard config plumbing instead of a hidden env var: add
Options.CheckerHTTPTimeout, register the -checker-http-timeout CLI flag
(default 120s), and wire it into the shared client via SetHTTPTimeout at
startup.
2026-07-12 20:46:15 +08:00
cd7d9a73a7 chore(deps): lock file maintenance
Some checks failed
continuous-integration/drone/push Build is failing
2026-07-07 21:11:43 +00:00
8eeadc0bbe chore(deps): update go toolchain directive to v1.26.5
Some checks are pending
continuous-integration/drone/push Build is running
2026-07-07 20:12:51 +00:00
1ac1c699da fix(deps): update module git.happydns.org/checker-tls to v0.8.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-18 10:13:04 +00:00
f79845b6e5 fix(deps): update module git.happydns.org/checker-ssh to v0.3.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-18 09:13:00 +00:00
51e7d5ad66 fix(deps): update module git.happydns.org/checker-ptr to v0.2.0
Some checks are pending
continuous-integration/drone/push Build is running
2026-06-18 08:13:10 +00:00
0d1de28565 fix(deps): update module git.happydns.org/checker-ping to v0.4.0
Some checks are pending
continuous-integration/drone/push Build is running
2026-06-18 07:10:45 +00:00
2ce8b61e55 fix(deps): update module git.happydns.org/checker-http to v0.3.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-18 04:13:13 +00:00
828a725dae fix(deps): update module git.happydns.org/checker-alias to v0.3.3
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-18 03:10:15 +00:00
25cb7a4e29 fix(deps): update module github.com/coreos/go-oidc/v3 to v3.19.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-17 23:13:24 +00:00
fac1f4046b fix(deps): update module git.happydns.org/checker-ping to v0.3.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-17 22:13:12 +00:00
10c88d7608 fix(deps): update module git.happydns.org/checker-alias to v0.3.1
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-17 21:10:41 +00:00
12f38de719 fix(deps): update module github.com/prometheus/common to v0.69.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-17 09:10:52 +00:00
664e029708 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-15 00:12:12 +00:00
96935f11c5 web: recover stale cached clients after deploy instead of freezing
All checks were successful
continuous-integration/drone/push Build is passing
The SPA references content-hashed bundles under /_app/immutable/ embedded
in the binary. After a deploy the binary ships new hashes and drops the old
ones, so a browser reusing a cached HTML page (or a stale /_app bundle)
requests hashes that 404: the page renders but the app never starts, leaving
it visible but frozen.

- routes.go: serve the page HTML (and the rewritten manifest.json) with
  Cache-Control no-cache so clients always revalidate and load a page that
  points at bundles which actually exist; /_app/* stays immutable.
- routes.go: when a missing /_app/immutable/*.js is requested (a stale cached
  client), return a self-healing reload module (200) instead of a dead 404 so
  already-stuck clients recover on their own.

The reload module is issued synchronously and throws at the end of evaluation
so the failing import() rejects: SvelteKit's bootstrap never reaches
kit.start(...), avoiding a "kit.start is not a function" TypeError. We do not
touch the Cache Storage API: the service worker manages its own cache
lifecycle and async caches.* work would lose the race against kit.start.
2026-06-14 21:44:20 +09:00
16bc06359c web: fix service update navigating to stale zone after edit
Some checks failed
continuous-integration/drone/push Build is failing
When updating a service on a published zone, the backend creates a new
derivative zone with a new ID. The frontend was navigating back using the
old zone ID, causing the layout loader to re-fetch the pre-update zone and
overwrite the store, making the change appear lost. Unify add and update
paths to always refresh domains and navigate to the returned zone ID.
2026-06-13 16:15:10 +09:00
677d4df980 providers: add DreamHost support 2026-06-13 16:15:08 +09:00
c40f99d0f6 providers: add GoDaddy support
Implement the GoDaddy provider on top of libdns/godaddy, exposing an API
Key and API Secret combined into the sso-key token used by the GoDaddy
API.
2026-06-13 16:15:08 +09:00
dd7730e1ad chore(deps): update alpine docker tag to v3.24
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-09 21:10:50 +00:00
8acfc58871 fix(deps): update module golang.org/x/crypto to v0.53.0
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-08 17:10:48 +00:00
7e4a1701ab chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-08 03:11:21 +00:00
50812a1c54 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-08 00:12:43 +00:00
6c2b2595ab web: use toasts for checker schedule save status
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-08 09:08:21 +09:00
ade3c82f86 admin: add invitation flow for auth users
Add a "Send Invitation" action on the admin auth-users page that
creates an account with an already verified email and emails the
recipient a recovery link worded as an invitation to try happyDomain.
2026-06-08 09:08:21 +09:00
e86ae83a06 web-admin: fix email verification status check for undefined value
The emailVerification field is optional (string | undefined), so an
unverified email yields undefined, not null. The strict !== null check
wrongly treated it as verified, showing the Verified badge and the
Mark as Unverified button. Use loose != null to catch both cases.
2026-06-08 09:08:21 +09:00
2ca721d948 config: warn when disable-embedded-login has no alternative auth
When -disable-embedded-login is set but neither OIDC nor -external-auth is
configured, the embedded login form stays visible to avoid lockout, making
the flag a no-op. Emit a startup warning so operators understand why login
is still available.
2026-06-08 09:08:21 +09:00
e1558ddcfa docker: Fix volume path 2026-06-08 09:08:21 +09:00
54100fa747 kvtpl: bound storage key sizes within the 64-char backend limit
Hash variable-length key components (checker names, targets, session
hashes) and compact the reverse-chrono segment so secondary index and
notification-state keys stay within the 64-char limit some KV backends
enforce. Add migrateFrom12 to rewrite the affected keys and key_size_test
to assert the bound for every key builder.
2026-06-08 09:08:21 +09:00
b641f893bb web: Fix is_auth_user call when not auth_user
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-06 22:04:11 +09:00
d5a651ad70 web: In case of error, fallback on rules 2026-06-06 22:04:11 +09:00
e453e20916 web: Disable buttons to run tests when checker scheduler is disabled 2026-06-06 22:04:11 +09:00
73f36271dc web: missing split checker config from runtime results 2026-06-06 22:04:11 +09:00
568e5e4700 fix(kvtpl): Unable to fully restore a fresh backup 2026-06-06 21:25:21 +09:00
1aecfabe64 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 21:25:21 +09:00
279e908a35 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 21:25:21 +09:00
38d8c6f0e3 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 21:25:21 +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