add API endpoints to prepare fresh interfaces and peers (#432)

This commit is contained in:
Christoph Haas
2025-05-09 16:19:36 +02:00
parent f018babca7
commit 6a96925be7
7 changed files with 365 additions and 8 deletions

View File

@@ -15,6 +15,7 @@ import (
type InterfaceEndpointInterfaceService interface {
GetAll(context.Context) ([]domain.Interface, [][]domain.Peer, error)
GetById(context.Context, domain.InterfaceIdentifier) (*domain.Interface, []domain.Peer, error)
Prepare(context.Context) (*domain.Interface, error)
Create(context.Context, *domain.Interface) (*domain.Interface, error)
Update(context.Context, domain.InterfaceIdentifier, *domain.Interface) (*domain.Interface, []domain.Peer, error)
Delete(context.Context, domain.InterfaceIdentifier) error
@@ -49,6 +50,7 @@ func (e InterfaceEndpoint) RegisterRoutes(g *routegroup.Bundle) {
apiGroup.HandleFunc("GET /all", e.handleAllGet())
apiGroup.HandleFunc("GET /by-id/{id}", e.handleByIdGet())
apiGroup.HandleFunc("GET /prepare", e.handlePrepareGet())
apiGroup.HandleFunc("POST /new", e.handleCreatePost())
apiGroup.HandleFunc("PUT /by-id/{id}", e.handleUpdatePut())
apiGroup.HandleFunc("DELETE /by-id/{id}", e.handleDelete())
@@ -112,11 +114,38 @@ func (e InterfaceEndpoint) handleByIdGet() http.HandlerFunc {
}
}
// handlePrepareGet returns a gorm handler function.
//
// @ID interfaces_handlePrepareGet
// @Tags Interfaces
// @Summary Prepare a new interface record.
// @Description This endpoint returns a new interface with default values (fresh key pair, valid name, new IP address pool, ...).
// @Produce json
// @Success 200 {object} models.Interface
// @Failure 401 {object} models.Error
// @Failure 403 {object} models.Error
// @Failure 500 {object} models.Error
// @Router /interface/prepare [get]
// @Security BasicAuth
func (e InterfaceEndpoint) handlePrepareGet() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
iface, err := e.interfaces.Prepare(r.Context())
if err != nil {
status, model := ParseServiceError(err)
respond.JSON(w, status, model)
return
}
respond.JSON(w, http.StatusOK, models.NewInterface(iface, nil))
}
}
// handleCreatePost returns a gorm handler function.
//
// @ID interfaces_handleCreatePost
// @Tags Interfaces
// @Summary Create a new interface record.
// @Description This endpoint creates a new interface with the provided data. All required fields must be filled (e.g. name, private key, public key, ...).
// @Param request body models.Interface true "The interface data."
// @Produce json
// @Success 200 {object} models.Interface
@@ -155,6 +184,7 @@ func (e InterfaceEndpoint) handleCreatePost() http.HandlerFunc {
// @ID interfaces_handleUpdatePut
// @Tags Interfaces
// @Summary Update an interface record.
// @Description This endpoint updates an existing interface with the provided data. All required fields must be filled (e.g. name, private key, public key, ...).
// @Param id path string true "The interface identifier."
// @Param request body models.Interface true "The interface data."
// @Produce json

View File

@@ -16,6 +16,7 @@ type PeerService interface {
GetForInterface(context.Context, domain.InterfaceIdentifier) ([]domain.Peer, error)
GetForUser(context.Context, domain.UserIdentifier) ([]domain.Peer, error)
GetById(context.Context, domain.PeerIdentifier) (*domain.Peer, error)
Prepare(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Peer, error)
Create(context.Context, *domain.Peer) (*domain.Peer, error)
Update(context.Context, domain.PeerIdentifier, *domain.Peer) (*domain.Peer, error)
Delete(context.Context, domain.PeerIdentifier) error
@@ -51,6 +52,7 @@ func (e PeerEndpoint) RegisterRoutes(g *routegroup.Bundle) {
apiGroup.HandleFunc("GET /by-user/{id}", e.handleAllForUserGet())
apiGroup.HandleFunc("GET /by-id/{id}", e.handleByIdGet())
apiGroup.With(e.authenticator.LoggedIn(ScopeAdmin)).HandleFunc("GET /prepare/{id}", e.handlePrepareGet())
apiGroup.With(e.authenticator.LoggedIn(ScopeAdmin)).HandleFunc("POST /new", e.handleCreatePost())
apiGroup.With(e.authenticator.LoggedIn(ScopeAdmin)).HandleFunc("PUT /by-id/{id}", e.handleUpdatePut())
apiGroup.With(e.authenticator.LoggedIn(ScopeAdmin)).HandleFunc("DELETE /by-id/{id}", e.handleDelete())
@@ -156,12 +158,48 @@ func (e PeerEndpoint) handleByIdGet() http.HandlerFunc {
}
}
// handlePrepareGet returns a gorm handler function.
//
// @ID peers_handlePrepareGet
// @Tags Peers
// @Summary Prepare a new peer record for the given WireGuard interface.
// @Description This endpoint is used to prepare a new peer record. The returned data contains a fresh key pair and valid ip address.
// @Param id path string true "The interface identifier."
// @Produce json
// @Success 200 {object} models.Peer
// @Failure 400 {object} models.Error
// @Failure 401 {object} models.Error
// @Failure 403 {object} models.Error
// @Failure 404 {object} models.Error
// @Failure 500 {object} models.Error
// @Router /peer/prepare/{id} [get]
// @Security BasicAuth
func (e PeerEndpoint) handlePrepareGet() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id := request.Path(r, "id")
if id == "" {
respond.JSON(w, http.StatusBadRequest,
models.Error{Code: http.StatusBadRequest, Message: "missing interface id"})
return
}
peer, err := e.peers.Prepare(r.Context(), domain.InterfaceIdentifier(id))
if err != nil {
status, model := ParseServiceError(err)
respond.JSON(w, status, model)
return
}
respond.JSON(w, http.StatusOK, models.NewPeer(peer))
}
}
// handleCreatePost returns a gorm handler function.
//
// @ID peers_handleCreatePost
// @Tags Peers
// @Summary Create a new peer record.
// @Description Only admins can create new records.
// @Description Only admins can create new records. The peer record must contain all required fields (e.g., public key, allowed IPs).
// @Param request body models.Peer true "The peer data."
// @Produce json
// @Success 200 {object} models.Peer
@@ -200,7 +238,7 @@ func (e PeerEndpoint) handleCreatePost() http.HandlerFunc {
// @ID peers_handleUpdatePut
// @Tags Peers
// @Summary Update a peer record.
// @Description Only admins can update existing records.
// @Description Only admins can update existing records. The peer record must contain all required fields (e.g., public key, allowed IPs).
// @Param id path string true "The peer identifier."
// @Param request body models.Peer true "The peer data."
// @Produce json