212 lines
3.9 KiB
Go
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)
|
|
} // }}}
|