feature: Implement connections API.

This commit is contained in:
imterah 2024-12-23 19:00:46 -05:00
parent 5ad69f6bbe
commit 5495fc4ae2
Signed by: imterah
GPG key ID: 8FA7DD57BA6CEA37

View file

@ -8,6 +8,7 @@ import (
"git.terah.dev/imterah/hermes/api/dbcore"
"git.terah.dev/imterah/hermes/api/jwtcore"
"git.terah.dev/imterah/hermes/api/permissions"
"git.terah.dev/imterah/hermes/commonbackend"
"github.com/charmbracelet/log"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
@ -18,17 +19,22 @@ type ConnectionsRequest struct {
Id uint `validate:"required" json:"id"`
}
type SanitizedBackends struct {
UserID uint `json:"user_id"`
Name string `json:"name"`
Description string `json:"description"`
Backend string `json:"backend"`
BackendParameters string `json:"backend_parameters"`
type ConnectionDetailsForConnection struct {
SourceIP string `json:"sourceIP"`
SourcePort uint16 `json:"sourcePort"`
DestPort uint16 `json:"destPort"`
}
type SanitizedConnection struct {
ClientIP string `json:"ip"`
Port uint16 `json:"port"`
ConnectionDetails *ConnectionDetailsForConnection `json:"connectionDetails"`
}
type ConnectionsResponse struct {
Success bool `json:"success"`
Data []*SanitizedBackends `json:"data"`
Success bool `json:"success"`
Data []*SanitizedConnection `json:"data"`
}
func Connections(c *gin.Context) {
@ -62,7 +68,7 @@ func Connections(c *gin.Context) {
log.Warnf("Failed to get user from the provided JWT token: %s", err.Error())
c.JSON(http.StatusInternalServerError, gin.H{
"error": "failed to parse token",
"error": "Failed to parse token",
})
return
@ -77,11 +83,11 @@ func Connections(c *gin.Context) {
return
}
var routes []dbcore.Proxy
routesRequest := dbcore.DB.Where("id = ?", req.Id).First(&routes)
var proxy dbcore.Proxy
proxyRequest := dbcore.DB.Where("id = ?", req.Id).First(&proxy)
if routesRequest.Error != nil {
log.Warnf("failed to find proxy: %s", routesRequest.Error)
if proxyRequest.Error != nil {
log.Warnf("failed to find proxy: %s", proxyRequest.Error)
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Failed to find forward entry",
@ -90,9 +96,9 @@ func Connections(c *gin.Context) {
return
}
routesExist := routesRequest.RowsAffected > 0
proxyExists := proxyRequest.RowsAffected > 0
if !routesExist {
if !proxyExists {
c.JSON(http.StatusBadRequest, gin.H{
"error": "No forward entry found",
})
@ -100,13 +106,81 @@ func Connections(c *gin.Context) {
return
}
// FIXME(greysoh): not finished
var backends []dbcore.Backend
var backend dbcore.Backend
backendRequest := dbcore.DB.Where("id = ?", proxy.BackendID).First(&backend)
sanitizedBackends := make([]*SanitizedBackends, len(backends))
if backendRequest.Error != nil {
log.Warnf("failed to find backend: %s", backendRequest.Error)
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": sanitizedBackends,
})
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Failed to find backend entry",
})
return
}
backendExists := backendRequest.RowsAffected > 0
if !backendExists {
c.JSON(http.StatusBadRequest, gin.H{
"error": "No forward entry found",
})
return
}
backendRuntime, ok := backendruntime.RunningBackends[backend.ID]
if !ok {
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", backend.ID)
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Couldn't fetch backend runtime",
})
return
}
backendRuntime.RuntimeCommands <- &commonbackend.ProxyConnectionsRequest{
Type: "proxyConnectionsRequest",
}
backendResponse := <-backendRuntime.RuntimeCommands
switch responseMessage := backendResponse.(type) {
case error:
log.Warnf("Failed to get response for backend: %s", responseMessage.Error())
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Failed to get status response from backend",
})
case *commonbackend.ProxyConnectionsResponse:
sanitizedConnections := []*SanitizedConnection{}
for _, connection := range responseMessage.Connections {
if connection.SourceIP == proxy.SourceIP && connection.SourcePort == proxy.SourcePort && proxy.DestinationPort == proxy.DestinationPort {
sanitizedConnections = append(sanitizedConnections, &SanitizedConnection{
ClientIP: connection.ClientIP,
Port: connection.ClientPort,
ConnectionDetails: &ConnectionDetailsForConnection{
SourceIP: proxy.SourceIP,
SourcePort: proxy.SourcePort,
DestPort: proxy.DestinationPort,
},
})
}
}
c.JSON(http.StatusOK, &ConnectionsResponse{
Success: true,
Data: sanitizedConnections,
})
default:
log.Warnf("Got illegal response type for backend: %T", responseMessage)
c.JSON(http.StatusInternalServerError, gin.H{
"error": "Got illegal response type",
})
}
}