Add Bootstrap and AgentSyncBundle handlers to gateway package with X-Gateway-Bootstrap-Token header authentication. Implement UpsertByName repository method for idempotent gateway registration. Update gateway entrypoint script to auto-generate keys and bootstrap gateway on first run, persisting gateway ID to disk. Add GATEWAY_BOOTSTRAP_TOKEN config and update environment variables for gateway name, bootstrap URL, and sync URL.
92 lines
2.5 KiB
Go
92 lines
2.5 KiB
Go
package gateway
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"nexavpn/backend/internal/apiutil"
|
|
)
|
|
|
|
type Handler struct {
|
|
service *Service
|
|
bootstrapToken string
|
|
}
|
|
|
|
func NewHandler(service *Service, bootstrapToken string) *Handler {
|
|
return &Handler{service: service, bootstrapToken: bootstrapToken}
|
|
}
|
|
|
|
func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
|
|
items, err := h.service.List(r.Context())
|
|
if err != nil {
|
|
apiutil.Error(w, http.StatusInternalServerError, "gateways_list_failed", "unable to list gateways")
|
|
return
|
|
}
|
|
|
|
apiutil.JSON(w, http.StatusOK, items)
|
|
}
|
|
|
|
func (h *Handler) SyncBundle(w http.ResponseWriter, r *http.Request) {
|
|
bundle, err := h.service.BuildSyncBundle(r.Context(), chi.URLParam(r, "id"))
|
|
if err != nil {
|
|
apiutil.Error(w, http.StatusBadRequest, "gateway_sync_failed", "unable to build sync bundle")
|
|
return
|
|
}
|
|
|
|
apiutil.JSON(w, http.StatusOK, bundle)
|
|
}
|
|
|
|
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
|
var input UpdateRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
|
apiutil.Error(w, http.StatusBadRequest, "invalid_json", "invalid request body")
|
|
return
|
|
}
|
|
|
|
item, err := h.service.Update(r.Context(), chi.URLParam(r, "id"), input)
|
|
if err != nil {
|
|
apiutil.Error(w, http.StatusBadRequest, "gateway_update_failed", "unable to update gateway")
|
|
return
|
|
}
|
|
|
|
apiutil.JSON(w, http.StatusOK, item)
|
|
}
|
|
|
|
func (h *Handler) Bootstrap(w http.ResponseWriter, r *http.Request) {
|
|
if r.Header.Get("X-Gateway-Bootstrap-Token") != h.bootstrapToken {
|
|
apiutil.Error(w, http.StatusUnauthorized, "unauthorized", "invalid gateway bootstrap token")
|
|
return
|
|
}
|
|
|
|
var input BootstrapRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
|
apiutil.Error(w, http.StatusBadRequest, "invalid_json", "invalid request body")
|
|
return
|
|
}
|
|
|
|
item, err := h.service.Bootstrap(r.Context(), input)
|
|
if err != nil {
|
|
apiutil.Error(w, http.StatusBadRequest, "gateway_bootstrap_failed", "unable to bootstrap gateway")
|
|
return
|
|
}
|
|
|
|
apiutil.JSON(w, http.StatusOK, item)
|
|
}
|
|
|
|
func (h *Handler) AgentSyncBundle(w http.ResponseWriter, r *http.Request) {
|
|
if r.Header.Get("X-Gateway-Bootstrap-Token") != h.bootstrapToken {
|
|
apiutil.Error(w, http.StatusUnauthorized, "unauthorized", "invalid gateway bootstrap token")
|
|
return
|
|
}
|
|
|
|
bundle, err := h.service.BuildSyncBundle(r.Context(), chi.URLParam(r, "id"))
|
|
if err != nil {
|
|
apiutil.Error(w, http.StatusBadRequest, "gateway_sync_failed", "unable to build sync bundle")
|
|
return
|
|
}
|
|
|
|
apiutil.JSON(w, http.StatusOK, bundle)
|
|
}
|