overrides
build / build-push (push) Successful in 29s

This commit is contained in:
mats committed 2026-09-28 16:25:55 +02:00
1 parent 98b65945f6
commit 0b6dcbd547
13 files changed
+417 -68

No files matched your search

+11 -4
View File
@@ -67,7 +67,8 @@ type Hooks struct {
DomainCheck func(name string) (any, error)
// Resolve runs one query through the live pipeline and reports the
// outcome, so the console can test the server it is talking to.
Resolve func(ctx context.Context, name, qtype string) (any, error)
Resolve func(ctx context.Context, name, qtype string) (any, error)
ResolveUpstream func(ctx context.Context, name, qtype, upstream string) (any, error)
// ListDomains pages the compiled rules.
ListDomains func(q DomainQuery) (any, error)
// AddDomain adds an inline rule and persists it.
@@ -75,9 +76,12 @@ type Hooks struct {
// DeleteDomain removes a rule and persists the change.
DeleteDomain func(ctx context.Context, name, action, list string) error
// LocalZones lists, saves and deletes UI-managed DNS master files.
LocalZones func(ctx context.Context) ([]ZoneFile, error)
SaveLocalZone func(ctx context.Context, name, content string) error
DeleteLocalZone func(ctx context.Context, name string) error
LocalZones func(ctx context.Context) ([]ZoneFile, error)
SaveLocalZone func(ctx context.Context, name, content string) error
DeleteLocalZone func(ctx context.Context, name string) error
AddressOverrides func(ctx context.Context) (any, error)
SaveAddressOverride func(ctx context.Context, domain, address string) error
DeleteAddressOverride func(ctx context.Context, domain string) error
// ListZones returns the compiled local zones with their records and
// delegations, and whether the API may rewrite them.
ListZones func() (any, error)
@@ -290,6 +294,9 @@ func (s *Server) routes(cfg *config.Config) *http.ServeMux {
mux.Handle("DELETE "+base+"domains/{name...}", s.authed(s.handleDomainDelete, true))
mux.Handle("GET "+base+"domains/check", s.authed(s.handleDomainCheck, false))
mux.Handle("POST "+base+"dns/test", s.authed(s.handleDNSTest, false))
mux.Handle("GET "+base+"address-overrides", s.authed(s.handleAddressOverrides, false))
mux.Handle("PUT "+base+"address-overrides", s.authed(s.handleAddressOverridePut, true))
mux.Handle("DELETE "+base+"address-overrides/{domain}", s.authed(s.handleAddressOverrideDelete, true))
mux.Handle("GET "+base+"local-zones", s.authed(s.handleLocalZones, false))
mux.Handle("PUT "+base+"local-zones/{name}", s.authed(s.handleLocalZonePut, true))
mux.Handle("DELETE "+base+"local-zones/{name}", s.authed(s.handleLocalZoneDelete, true))
+63 -3
View File
@@ -1,7 +1,9 @@
package api
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
@@ -188,8 +190,9 @@ func (s *Server) handleDNSTest(w http.ResponseWriter, r *http.Request) {
return
}
var in struct {
Name string `json:"name"`
QType string `json:"type"`
Name string `json:"name"`
QType string `json:"type"`
Upstream string `json:"upstream"`
}
if err := decodeJSON(r, &in); err != nil {
writeError(w, http.StatusBadRequest, "malformed request body")
@@ -200,7 +203,20 @@ func (s *Server) handleDNSTest(w http.ResponseWriter, r *http.Request) {
writeError(w, http.StatusBadRequest, "name is required")
return
}
v, err := s.hooks.Resolve(r.Context(), name, in.QType)
resolve := s.hooks.Resolve
if in.Upstream != "" {
resolve = func(ctx context.Context, n, qt string) (any, error) {
if s.hooks.ResolveUpstream == nil {
return nil, errors.New("direct upstream lookup unavailable")
}
return s.hooks.ResolveUpstream(ctx, n, qt, in.Upstream)
}
}
if resolve == nil {
writeError(w, http.StatusNotImplemented, "dns test not available")
return
}
v, err := resolve(r.Context(), name, in.QType)
if err != nil {
writeJSON(w, http.StatusOK, map[string]any{"name": name, "error": err.Error()})
return
@@ -208,6 +224,50 @@ func (s *Server) handleDNSTest(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, v)
}
func (s *Server) handleAddressOverrides(w http.ResponseWriter, r *http.Request) {
if s.hooks.AddressOverrides == nil {
writeError(w, http.StatusNotImplemented, "address overrides unavailable")
return
}
v, err := s.hooks.AddressOverrides(r.Context())
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
writeJSON(w, http.StatusOK, v)
}
func (s *Server) handleAddressOverridePut(w http.ResponseWriter, r *http.Request) {
if s.hooks.SaveAddressOverride == nil {
writeError(w, http.StatusNotImplemented, "address overrides are read-only")
return
}
var in struct {
Domain string `json:"domain"`
Address string `json:"address"`
}
if decodeJSON(r, &in) != nil {
writeError(w, http.StatusBadRequest, "malformed request body")
return
}
if err := s.hooks.SaveAddressOverride(r.Context(), in.Domain, in.Address); err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
}
writeJSON(w, http.StatusOK, map[string]any{"ok": true})
}
func (s *Server) handleAddressOverrideDelete(w http.ResponseWriter, r *http.Request) {
if s.hooks.DeleteAddressOverride == nil {
writeError(w, http.StatusNotImplemented, "address overrides are read-only")
return
}
domain := r.PathValue("domain")
if err := s.hooks.DeleteAddressOverride(r.Context(), domain); err != nil {
writeError(w, http.StatusBadRequest, err.Error())
return
}
writeJSON(w, http.StatusOK, map[string]any{"ok": true})
}
func (s *Server) handleLocalZones(w http.ResponseWriter, r *http.Request) {
if s.hooks.LocalZones == nil {
writeError(w, http.StatusNotImplemented, "local zone editor is unavailable")