routeros_dns/webserver.go
2026-02-26 21:37:26 +01:00

212 lines
3.9 KiB
Go

package main
import (
// External
"git.gibonuddevalla.se/go/html_template"
// Standard
"embed"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
)
var (
htmlEngine HTMLTemplate.Engine
//go:embed static
staticFS embed.FS
//go:embed views
viewFS embed.FS
)
func registerWebserverHandlers() { // {{{
var err error
htmlEngine, err = HTMLTemplate.NewEngine(viewFS, staticFS, flagDev)
if err != nil {
logger.Error("webserver", "error", err)
os.Exit(1)
}
http.HandleFunc("/", rootHandler)
http.HandleFunc("GET /devices", actionDevices)
http.HandleFunc("POST /device", actionDeviceUpdate)
http.HandleFunc("GET /device/{dev}/dns_records", actionDNSRecords)
http.HandleFunc("POST /device/{dev}/record", actionRecordSave)
http.HandleFunc("DELETE /device/{dev}/record/{id}", actionRecordDelete)
} // }}}
func startWebserver() { // {{{
listen := fmt.Sprintf("%s:%d", config.Network.Address, config.Network.Port)
logger.Info("webserver", "listen", listen)
http.ListenAndServe(listen, nil)
} // }}}
func httpError(w http.ResponseWriter, err error) { // {{{
resp := struct {
OK bool
Error string
}{
false,
err.Error(),
}
j, _ := json.Marshal(resp)
w.Write(j)
} // }}}
func rootHandler(w http.ResponseWriter, r *http.Request) { // {{{
if r.URL.Path == "/" {
page := HTMLTemplate.SimplePage{}
page.Layout = "main"
page.Page = "index"
var err error
data := make(map[string]any)
data["VERSION"] = VERSION
page.Data = data
err = htmlEngine.Render(page, w, r)
if err != nil {
w.Write([]byte(err.Error()))
return
}
return
}
htmlEngine.StaticResource(w, r)
} // }}}
func actionDevices(w http.ResponseWriter, r *http.Request) { // {{{
var devs []Device
for _, dev := range config.Devices {
dev.Password = ""
devs = append(devs, dev)
}
j, _ := json.Marshal(struct {
OK bool
Devices []Device
}{
true,
devs,
})
w.Write(j)
} // }}}
func actionDeviceUpdate(w http.ResponseWriter, r *http.Request) { // {{{
var req struct {
CurrentName string
Device Device
}
body, _ := io.ReadAll(r.Body)
err := json.Unmarshal(body, &req)
if err != nil {
httpError(w, err)
return
}
device, err := config.UpdateDevice(req.CurrentName, req.Device)
if err != nil {
httpError(w, err)
return
}
device.Password = "" // don't leak unnecessarily
j, _ := json.Marshal(struct {
OK bool
Device Device
}{
true,
device,
})
w.Write(j)
} // }}}
func actionDNSRecords(w http.ResponseWriter, r *http.Request) { // {{{
devname := r.PathValue("dev")
device, err := routerosDevice(devname)
if err != nil {
httpError(w, err)
return
}
var records []DNSRecord
records, err = device.StaticDNSEntries()
if err != nil {
httpError(w, err)
return
}
j, _ := json.Marshal(struct {
OK bool
Records []DNSRecord
}{
true,
records,
})
w.Write(j)
} // }}}
func actionRecordSave(w http.ResponseWriter, r *http.Request) { // {{{
devName := r.PathValue("dev")
device, err := routerosDevice(devName)
if err != nil {
httpError(w, err)
return
}
body, _ := io.ReadAll(r.Body)
var record DNSRecord
err = json.Unmarshal(body, &record)
if err != nil {
httpError(w, err)
return
}
entry, err := device.UpdateDNSEntry(record.toDNSEntry())
if err != nil {
httpError(w, err)
logger.Error("webserver", "op", "record_save", "error", err)
return
}
record = NewDNSRecord(entry)
j, _ := json.Marshal(struct {
OK bool
Record DNSRecord
}{true, record})
w.Write(j)
} // }}}
func actionRecordDelete(w http.ResponseWriter, r *http.Request) { // {{{
devName := r.PathValue("dev")
device, err := routerosDevice(devName)
if err != nil {
httpError(w, err)
return
}
id := r.PathValue("id")
if id == "" {
httpError(w, errors.New("No ID provided"))
return
}
err = device.DeleteDNSEntry(id)
if err != nil {
httpError(w, err)
logger.Error("webserver", "op", "record_delete", "error", err)
return
}
j, _ := json.Marshal(struct {
OK bool
}{true})
w.Write(j)
} // }}}