List and delete accounts with last-admin and Administrators-group guards, and expose editable network settings via the configuration UI.
101 lines
2.9 KiB
Go
101 lines
2.9 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
|
|
"codeberg.org/SquidSE/ClusterCanvas/service/internal/auth"
|
|
"codeberg.org/SquidSE/ClusterCanvas/service/internal/settings"
|
|
)
|
|
|
|
type networkResponse struct {
|
|
Network settings.NetworkSettings `json:"network"`
|
|
}
|
|
|
|
type putNetworkRequest struct {
|
|
Network settings.NetworkSettings `json:"network"`
|
|
}
|
|
|
|
func networkGetHandler(configDir string) http.HandlerFunc {
|
|
return func(writer http.ResponseWriter, request *http.Request) {
|
|
settingsPayload, err := loadSettingsOrDefault(configDir)
|
|
if err != nil {
|
|
writeJSON(writer, http.StatusInternalServerError, apiErrorResponse{Error: err.Error()})
|
|
return
|
|
}
|
|
|
|
writeJSON(writer, http.StatusOK, networkResponse{
|
|
Network: settings.EffectiveNetwork(settingsPayload.Network),
|
|
})
|
|
}
|
|
}
|
|
|
|
func networkPutHandler(configDir string) http.HandlerFunc {
|
|
return func(writer http.ResponseWriter, request *http.Request) {
|
|
if err := authorizeNetworkWrite(request); err != nil {
|
|
writeJSON(writer, http.StatusForbidden, apiErrorResponse{Error: err.Error()})
|
|
return
|
|
}
|
|
|
|
var payload putNetworkRequest
|
|
if err := json.NewDecoder(request.Body).Decode(&payload); err != nil {
|
|
writeJSON(writer, http.StatusBadRequest, apiErrorResponse{Error: "invalid JSON body"})
|
|
return
|
|
}
|
|
|
|
if err := validateNetworkSettings(payload.Network); err != nil {
|
|
writeJSON(writer, http.StatusBadRequest, apiErrorResponse{Error: err.Error()})
|
|
return
|
|
}
|
|
|
|
network := settings.EffectiveNetwork(payload.Network)
|
|
clientIP := auth.ClientIP(request)
|
|
if wouldLockOut, reason := auth.WouldLockOut(clientIP, network); wouldLockOut {
|
|
message := "these settings would lock out your current IP"
|
|
if reason != "" {
|
|
message = message + ": " + reason
|
|
}
|
|
writeJSON(writer, http.StatusBadRequest, apiErrorResponse{Error: message})
|
|
return
|
|
}
|
|
|
|
settingsPayload, err := loadSettingsOrDefault(configDir)
|
|
if err != nil {
|
|
writeJSON(writer, http.StatusInternalServerError, apiErrorResponse{Error: err.Error()})
|
|
return
|
|
}
|
|
|
|
settingsPayload.Network = network
|
|
if err := settings.SaveSettings(configDir, settingsPayload); err != nil {
|
|
writeJSON(writer, http.StatusInternalServerError, apiErrorResponse{Error: err.Error()})
|
|
return
|
|
}
|
|
|
|
writeJSON(writer, http.StatusOK, networkResponse{Network: network})
|
|
}
|
|
}
|
|
|
|
func authorizeNetworkWrite(_ *http.Request) error {
|
|
// TODO: integrate authz middleware.
|
|
return nil
|
|
}
|
|
|
|
func validateNetworkSettings(network settings.NetworkSettings) error {
|
|
if err := auth.ValidateListenAddress(network.ListenAddress); err != nil {
|
|
return err
|
|
}
|
|
if err := auth.ValidateHostname(network.PublicHostname); err != nil {
|
|
return err
|
|
}
|
|
if err := auth.ValidateAccessRules(network.Rules); err != nil {
|
|
return err
|
|
}
|
|
switch network.AccessMode {
|
|
case settings.AccessModeOpen, settings.AccessModeWhitelist, settings.AccessModeBlacklist:
|
|
return nil
|
|
default:
|
|
return errors.New("network.access_mode must be open, whitelist, or blacklist")
|
|
}
|
|
}
|