From 7b1f59d86a3cddb4e17668e1403f887208c49857 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Thu, 29 Apr 2021 11:23:32 +0200 Subject: [PATCH] deployment api completed (#11) --- internal/server/api.go | 63 ++++++++++++++++++++++++-- internal/server/docs/docs.go | 87 ++++++++++++++++++++++++++++++++---- internal/server/routes.go | 3 +- 3 files changed, 141 insertions(+), 12 deletions(-) diff --git a/internal/server/api.go b/internal/server/api.go index 9576536..67e2105 100644 --- a/internal/server/api.go +++ b/internal/server/api.go @@ -732,6 +732,63 @@ func (s *ApiServer) PatchDevice(c *gin.Context) { c.JSON(http.StatusNotImplemented, device) } +type PeerDeploymentInformation struct { + PublicKey string + Identifier string + Device string + DeviceIdentifier string +} + +// GetPeerDeploymentInformation godoc +// @Tags Provisioning +// @Summary Retrieves all active peers for the given email address +// @Produce json +// @Param email path string true "Email Address" +// @Success 200 {object} []PeerDeploymentInformation "All active WireGuard peers" +// @Failure 401 {object} ApiError +// @Failure 403 {object} ApiError +// @Failure 404 {object} ApiError +// @Router /provisioning/peers/{email} [get] +// @Security GeneralBasicAuth +func (s *ApiServer) GetPeerDeploymentInformation(c *gin.Context) { + email := c.Param("email") + if email == "" { + c.JSON(http.StatusBadRequest, ApiError{Message: "email parameter must be specified"}) + return + } + + // Get authenticated user to check permissions + username, _, _ := c.Request.BasicAuth() + user := s.s.users.GetUser(username) + + if !user.IsAdmin && user.Email != email { + c.JSON(http.StatusForbidden, ApiError{Message: "not enough permissions to access this resource"}) + return + } + + peers := s.s.peers.GetPeersByMail(email) + result := make([]PeerDeploymentInformation, 0, len(peers)) + for i := range peers { + if peers[i].DeactivatedAt != nil { + continue // skip deactivated peers + } + + device := s.s.peers.GetDevice(peers[i].DeviceName) + if device.Type != wireguard.DeviceTypeServer { + continue // Skip peers on non-server devices + } + + result = append(result, PeerDeploymentInformation{ + PublicKey: peers[i].PublicKey, + Identifier: peers[i].Identifier, + Device: device.DeviceName, + DeviceIdentifier: device.DisplayName, + }) + } + + c.JSON(http.StatusOK, result) +} + // GetPeerDeploymentConfig godoc // @Tags Provisioning // @Summary Retrieves the peer config for the given public key @@ -760,7 +817,7 @@ func (s *ApiServer) GetPeerDeploymentConfig(c *gin.Context) { username, _, _ := c.Request.BasicAuth() user := s.s.users.GetUser(username) - if !user.IsAdmin && user.Email == peer.Email { + if !user.IsAdmin && user.Email != peer.Email { c.JSON(http.StatusForbidden, ApiError{Message: "not enough permissions to access this resource"}) return } @@ -799,7 +856,7 @@ type ProvisioningRequest struct { // @Failure 401 {object} ApiError // @Failure 403 {object} ApiError // @Failure 404 {object} ApiError -// @Router /provisioning/peer [post] +// @Router /provisioning/peers [post] // @Security GeneralBasicAuth func (s *ApiServer) PostPeerDeploymentConfig(c *gin.Context) { req := ProvisioningRequest{} @@ -817,7 +874,7 @@ func (s *ApiServer) PostPeerDeploymentConfig(c *gin.Context) { return } - if !user.IsAdmin && user.Email == req.Email { + if !user.IsAdmin && user.Email != req.Email { c.JSON(http.StatusForbidden, ApiError{Message: "not enough permissions to access this resource"}) return } diff --git a/internal/server/docs/docs.go b/internal/server/docs/docs.go index ab7026d..96193ca 100644 --- a/internal/server/docs/docs.go +++ b/internal/server/docs/docs.go @@ -1039,7 +1039,58 @@ var doc = `{ } } }, - "/provisioning/peer": { + "/provisioning/peer/{pkey}": { + "get": { + "security": [ + { + "GeneralBasicAuth": [] + } + ], + "produces": [ + "text/plain" + ], + "tags": [ + "Provisioning" + ], + "summary": "Retrieves the peer config for the given public key", + "parameters": [ + { + "type": "string", + "description": "Public Key (Base 64)", + "name": "pkey", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "The WireGuard configuration file", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/server.ApiError" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/server.ApiError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/server.ApiError" + } + } + } + } + }, + "/provisioning/peers": { "post": { "security": [ { @@ -1095,7 +1146,7 @@ var doc = `{ } } }, - "/provisioning/peer/{pkey}": { + "/provisioning/peers/{email}": { "get": { "security": [ { @@ -1103,26 +1154,29 @@ var doc = `{ } ], "produces": [ - "text/plain" + "application/json" ], "tags": [ "Provisioning" ], - "summary": "Retrieves the peer config for the given public key", + "summary": "Retrieves all active peers for the given email address", "parameters": [ { "type": "string", - "description": "Public Key (Base 64)", - "name": "pkey", + "description": "Email Address", + "name": "email", "in": "path", "required": true } ], "responses": { "200": { - "description": "The WireGuard configuration file", + "description": "All active WireGuard peers", "schema": { - "type": "string" + "type": "array", + "items": { + "$ref": "#/definitions/server.PeerDeploymentInformation" + } } }, "401": { @@ -1168,6 +1222,23 @@ var doc = `{ } } }, + "server.PeerDeploymentInformation": { + "type": "object", + "properties": { + "device": { + "type": "string" + }, + "deviceIdentifier": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "publicKey": { + "type": "string" + } + } + }, "server.ProvisioningRequest": { "type": "object", "required": [ diff --git a/internal/server/routes.go b/internal/server/routes.go index 7c4598e..70284a4 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -107,8 +107,9 @@ func SetupApiRoutes(s *Server) { apiV1Deployment := s.server.Group("/api/v1/provisioning") apiV1Deployment.Use(s.RequireApiAuthentication("")) + apiV1Deployment.GET("/peers/:email", api.GetPeerDeploymentInformation) apiV1Deployment.GET("/peer/:pkey", api.GetPeerDeploymentConfig) - apiV1Deployment.POST("/peer", api.PostPeerDeploymentConfig) + apiV1Deployment.POST("/peers", api.PostPeerDeploymentConfig) // Swagger doc/ui s.server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))