Commit graph

138 commits

Author SHA1 Message Date
5cd3bc75f2 checkers: show worst check status badge on domain list
Add DomainWithCheckStatus model and GetWorstDomainStatuses usecase to
compute the most critical checker status per domain. The GET /domains
endpoint now returns status alongside each domain. The frontend domain
store, list components, and table row display dynamic status badges
with color and icon instead of a hardcoded "OK".

ZoneList is made generic (T extends HappydnsDomain) so the badges
snippet preserves the caller's concrete type without unsafe casts.
2026-04-15 15:35:57 +07:00
2beb84e147 checkers: add API controllers, routes, and app wiring
Wire up the checker system to the HTTP layer:
- API controllers for checker operations, options, plans, and results
- Scoped routes at domain and service level
- Admin controllers for checker config and scheduler management
- App initialization: create usecases, start/stop scheduler
- Zone controller updated to include per-service check status
2026-04-15 11:12:55 +07:00
577a39df56 checkers: add usecases, engine, and scheduler
Implement the checker business logic:
- CheckerOptionsUsecase: scope-based option resolution, validation,
  auto-fill from execution context (domain, zone, service)
- CheckPlanUsecase: CRUD for user scheduling configurations
- CheckStatusUsecase: aggregated status queries, execution history
- CheckerEngine: full execution pipeline (observe, evaluate, aggregate)
- Scheduler: background job executor with auto-discovery, min-heap
  queue, worker pool, and jitter-based scheduling
2026-04-15 11:12:55 +07:00
893fc4bfe6 checkers: add storage interfaces, implementations, and tidy
Add the persistence layer for the checker system:
- Storage interfaces (CheckPlanStorage, CheckerOptionsStorage,
  CheckEvaluationStorage, ExecutionStorage, ObservationSnapshotStorage,
  SchedulerStateStorage) in the usecase/checker package
- KV-based implementations for LevelDB/Oracle NoSQL/InMemory backends
- Integrate checker storage into the main Storage interface
- Add tidy methods for checker entities (plans, configurations,
  evaluations, executions, snapshots, observation cache) and
  secondary index cleanup
2026-04-15 11:12:55 +07:00
0c48e960cb checkers: load external checker plugins from .so files
Scan -plugins-directory paths at startup, open each .so via plugin.Open,
look up the NewCheckerPlugin symbol from checker-sdk-go, and register the
returned definition and observation provider in the global checker
registries. A pluginLoader indirection keeps the door open for future
plugin kinds.
2026-04-15 11:12:55 +07:00
2f9f44a66d checkers: introduce checker subsystem foundation
Add the checker-sdk-go dependency and build the core checker
infrastructure:
- Domain model types: CheckTarget, CheckPlan, Execution,
  CheckEvaluation, CheckerDefinition, CheckerOptions,
  ObservationSnapshot, and associated interfaces
- Observation collection engine with concurrent per-key gathering
- Checker and observation provider registries (wrapping checker-sdk-go)
- WorstStatusAggregator for combining rule evaluation results
2026-04-15 11:12:55 +07:00
e73ed40d5c fix: use validate instead of binding for zero-value fields
Switch ServiceMeta.Domain, ServiceMeta.Ttl, ServiceMeta.NbResources,
and ZoneMeta.DefaultTTL from binding:"required" to validate:"required".
This keeps them marked as required in the OpenAPI spec (swaggo reads
both tags) without gin rejecting valid zero values (0 for uint32,
"" for root domain).
2026-04-11 12:25:10 +07:00
99edd8a66c fix: use DomainCreationInput for domain creation endpoint and service
CreateDomain now takes a DomainCreationInput and returns the created
Domain, so the controller no longer needs to construct an intermediate
Domain struct and the response includes the server-assigned fields.

Fixes: https://github.com/happyDomain/happydomain/issues/44
2026-04-11 12:25:10 +07:00
47d7893b91 Add readonly struct tags to immutable model fields
Mark fields like IDs, timestamps, zone_history, and settings as
readonly in swagger documentation to indicate they are not user-writable.
2026-04-04 22:05:28 +07:00
3e3b23a0c4 Replace any types with proper TypeScript types in web API and model files 2026-04-04 22:05:28 +07:00
4f3a1d7f7b Add format:"date-time" struct tags to time.Time model fields 2026-04-04 22:05:28 +07:00
7081f3d571 Add binding:required tags and narrow input types for API endpoints
Introduce dedicated input types (DomainUpdateInput, SessionInput) to limit
writable fields on update endpoints, and add binding:required tags across
model structs to improve validation and Swagger documentation accuracy.
2026-04-04 22:05:28 +07:00
899f3e0989 Fix Swagger annotations in controllers
- Fix typos in session.go (@Prodsce -> @Produce, @Ssccess -> @Success)
- Add missing @Param body annotations for CreateSession and UpdateSession
- Update ApplyZoneForm param description to reference correct type
- Add swaggertype tags to Identifier slices for correct OpenAPI output
2026-04-04 22:05:28 +07:00
e9db206e78 Add context.Context to ProviderUsecase and DomainUsecase interfaces
All checks were successful
continuous-integration/drone/push Build is passing
Propagate context.Context as first parameter through all provider and
domain usecase interface methods that didn't already have it. This is
a prerequisite for the upcoming secret management layer, which needs
request-scoped context to carry session-derived encryption keys.
2026-03-30 21:54:54 +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
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
36a7d8e9d3 Fix email validation HMAC weakness and prevent user enumeration on registration 2026-03-16 19:44:14 +07:00
c850cfb0db Refactor orchestrator: add context.Context, fix error handling, use interfaces
- Handle AppendDomainLog errors with log.Printf instead of silently discarding
- Add NoopDomainLogAppender for null object pattern
2026-03-16 19:44:14 +07:00
2572e8c319 Preserve service metadata across zone re-analyses
After AnalyzeZone rebuilds services from raw DNS records, metadata that
cannot be derived from DNS (Id, UserComment, OwnerId, Aliases, TTL, and
service-specific fields like OpenPGP/SMimeCert Username) was lost.

Add a post-processing function ReassociateMetadata that matches new
services to old ones by type and subdomain (using RDATA hashing for
disambiguation) and transfers metadata. Services opt in to body-level
transfer via the new MetadataEnricher interface.
2026-03-14 11:06:49 +07:00
f4bcb1c9cf refactor: decompose Analyzer into recordPool and serviceAccumulator
Restructure the service analyzer architecture to improve maintainability:

- Extract recordPool (zone records + mark-delete claiming) and
  serviceAccumulator (service registry + domain normalization) as
  embedded structs in Analyzer
- Replace swap-delete with mark-delete to eliminate mutation-during-iteration
- Centralize domain normalization using helpers.DomainRelative
- Make Comment/NbResources lazy via Service.MarshalJSON instead of
  eager assignment at three separate call sites
- Extract SPF merging from usecase layer into services.CollectAndMergeSPF
- Add GetDefaultTTL accessor and comprehensive Analyzer doc comments
- Add round-trip test infrastructure covering MX, CNAME, CAA, TXT, SPF,
  DMARC, GSuite, Origin, Server and more
2026-03-14 11:06:49 +07:00
31950811c0 Merge SPF records from multiple services into single TXT record
RFC 7208 requires exactly one SPF record per domain. Previously, the
standalone SPF service and provider services like GSuite each emitted
their own SPF TXT record, producing invalid DNS when both existed.

Introduce SPFContributor interface so services can declare SPF
directives independently. At zone generation time, all contributions
for the same domain are merged into a single SPF record with the
strictest "all" policy winning. During zone import, GSuite claims its
directive via ClaimSPFDirective so the SPF analyzer excludes it from
the standalone SPF service.
2026-03-14 10:36:53 +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
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
ee0e22adf5 chore: apply Go naming conventions and minor code improvements 2026-03-01 17:38:12 +07:00
f457071d5d chore: replace interface{} with any across the codebase
Use the modern Go type alias `any` instead of `interface{}` throughout
all packages for improved readability and consistency with current Go idioms.
2026-03-01 17:38:04 +07:00
c9552fa9b2 Remove UsecaseDependancies service locator pattern
All checks were successful
continuous-integration/drone/push Build is passing
Replace the UsecaseDependancies interface with plain Dependencies structs
defined locally in each route package. DeclareRoutes acts as the sole
composition root where use cases are resolved; sub-route functions and
controllers receive only the specific interfaces they need.
2026-02-14 10:49:46 +07:00
e0d8526577 Add Altcha captcha provider support
Some checks are pending
continuous-integration/drone/push Build is running
2026-02-13 12:29:14 +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
bee17f7761 Add missing json tag on all structs for better OpenAPI generation 2026-01-26 12:34:55 +08:00
2d39de5eb9 Add service initialization endpoint with DNS type detection
Implement backend-driven service initialization to replace hazardous
frontend initialization logic. Services can now provide custom
initialization via ServiceInitializer interface or get sensible
defaults automatically.
2026-01-12 10:19:33 +07:00
6add2f220e Refactor storage layer to use key-value template pattern
All checks were successful
continuous-integration/drone/tag Build is passing
Extract common key-value storage operations into internal/storage/kvtpl/
template directory. This consolidates duplicated logic from both leveldb
and inmemory implementations into reusable generic functions.

Key changes:
- Create kvtpl/ package with generic KV storage operations
- Consolidate iterator implementation using generics
- Update migration functions to use new template structure
- Refactor tests to work with new storage interface

This prepares the codebase for easier addition of new storage backends
by providing a consistent template layer.
2026-01-09 17:17:04 +07:00
21b9072bba Add comprehensive test coverage for model package 2026-01-09 15:34:31 +07:00
ae0f9018bb Can add and update records in service 2026-01-09 15:01:51 +07:00
f5911cb256 Can delete a record in a service 2026-01-08 18:15:37 +07:00
437cf4d80b Create copy of returned records 2026-01-07 22:26:19 +07:00
df825f1f50 Services stores records instead of abstact data 2026-01-07 22:26:19 +07:00
d6e49e0440 Update go modules and dnscontrol to v4.29.0 2025-12-24 19:03:33 +07:00
8fa8efcefc insights: Send stats about users' settings
Some checks failed
continuous-integration/drone/push Build is failing
2025-06-12 20:07:57 +02:00
ebb5d34be5 Use ListRecordsUC when generating zonefile 2025-06-10 09:53:44 +02:00
ce91b49a73 Create a usecase from API to extract domain creation on provider
Fixes a security issue where a user can create a domain on a provider
while DisableProviders option was set
2025-06-09 15:38:11 +02:00
b0e0ab6d9e Create a usecase from provider controller 2025-06-09 15:38:11 +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
b527e0ed26 Refactor usecases: create intermediate structs to facilitate tests 2025-05-28 23:02:22 +02:00
b2b6467575 Refactor domain/provider/zone usecase: split in multiple files 2025-05-28 23:02:22 +02:00
1408e04f45 Refactor domain's logs usecase: split in multiple files 2025-05-28 23:02:22 +02:00
0495ab4693 Refactor auth_user usecase: split in multiple files 2025-05-28 23:02:22 +02:00
cffbc104ae Refactor session usecase: split in multiple files 2025-05-28 22:00:02 +02:00
356e733e76 Move config struct to model, avoid dependancy to storage 2025-05-28 22:00:02 +02:00