feature: Change state management from global variables to object passing
This restructures dbcore (now the db package) and jwtcore (now the jwt package) to use a single struct. There is now a state package, which contains a struct with the full application state. After this, instead of initializing the API routes directly in the main function, the state object gets passed, and the API routes get initialized with their accompanying code. One fix done to reduce memory usage and increase speed is that the validator object is now persistent across requests, instead of recreating it each time. This should speed things up slightly, and improve memory usage. One additional chore done is that the database models have been moved to be a seperate file from the DB initialization itself.
This commit is contained in:
parent
71d53990de
commit
d56a8eb7bf
23 changed files with 1901 additions and 2161 deletions
|
@ -5,13 +5,12 @@ import (
|
|||
"net/http"
|
||||
|
||||
"git.terah.dev/imterah/hermes/backend/api/backendruntime"
|
||||
"git.terah.dev/imterah/hermes/backend/api/dbcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/jwtcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/db"
|
||||
"git.terah.dev/imterah/hermes/backend/api/permissions"
|
||||
"git.terah.dev/imterah/hermes/backend/api/state"
|
||||
"git.terah.dev/imterah/hermes/backend/commonbackend"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type ConnectionsRequest struct {
|
||||
|
@ -37,127 +36,130 @@ type ConnectionsResponse struct {
|
|||
Data []*SanitizedConnection `json:"data"`
|
||||
}
|
||||
|
||||
func GetConnections(c *gin.Context) {
|
||||
var req ConnectionsRequest
|
||||
func SetupGetConnections(state *state.State) {
|
||||
state.Engine.POST("/api/v1/forward/connections", func(c *gin.Context) {
|
||||
var req ConnectionsRequest
|
||||
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err := validator.New().Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
user, err := jwtcore.GetUserFromJWT(req.Token)
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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",
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.visibleConn") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
if err := state.Validator.Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var proxy dbcore.Proxy
|
||||
proxyRequest := dbcore.DB.Where("id = ?", req.Id).First(&proxy)
|
||||
user, err := state.JWT.GetUserFromJWT(req.Token)
|
||||
|
||||
if proxyRequest.Error != nil {
|
||||
log.Warnf("failed to find proxy: %s", proxyRequest.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to find forward entry",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
proxyExists := proxyRequest.RowsAffected > 0
|
||||
|
||||
if !proxyExists {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "No forward entry found",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendRuntime, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Couldn't fetch backend runtime",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backendRuntime.ProcessCommand(&commonbackend.ProxyConnectionsRequest{})
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("Failed to get response for backend: %s", err.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to get status response from backend",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
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,
|
||||
},
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, &ConnectionsResponse{
|
||||
Success: true,
|
||||
Data: sanitizedConnections,
|
||||
})
|
||||
default:
|
||||
log.Warnf("Got illegal response type for backend: %T", responseMessage)
|
||||
if !permissions.UserHasPermission(user, "routes.visibleConn") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Got illegal response type",
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var proxy db.Proxy
|
||||
proxyRequest := state.DB.DB.Where("id = ?", req.Id).First(&proxy)
|
||||
|
||||
if proxyRequest.Error != nil {
|
||||
log.Warnf("failed to find proxy: %s", proxyRequest.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to find forward entry",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
proxyExists := proxyRequest.RowsAffected > 0
|
||||
|
||||
if !proxyExists {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "No forward entry found",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendRuntime, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Couldn't fetch backend runtime",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backendRuntime.ProcessCommand(&commonbackend.ProxyConnectionsRequest{})
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("Failed to get response for backend: %s", err.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to get status response from backend",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
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",
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,13 +5,12 @@ import (
|
|||
"net/http"
|
||||
|
||||
"git.terah.dev/imterah/hermes/backend/api/backendruntime"
|
||||
"git.terah.dev/imterah/hermes/backend/api/dbcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/jwtcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/db"
|
||||
"git.terah.dev/imterah/hermes/backend/api/permissions"
|
||||
"git.terah.dev/imterah/hermes/backend/api/state"
|
||||
"git.terah.dev/imterah/hermes/backend/commonbackend"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type ProxyCreationRequest struct {
|
||||
|
@ -26,150 +25,153 @@ type ProxyCreationRequest struct {
|
|||
AutoStart *bool `json:"autoStart"`
|
||||
}
|
||||
|
||||
func CreateProxy(c *gin.Context) {
|
||||
var req ProxyCreationRequest
|
||||
func SetupCreateProxy(state *state.State) {
|
||||
state.Engine.POST("/api/v1/forward/create", func(c *gin.Context) {
|
||||
var req ProxyCreationRequest
|
||||
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err := validator.New().Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
user, err := jwtcore.GetUserFromJWT(req.Token)
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.add") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if req.Protocol != "tcp" && req.Protocol != "udp" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Protocol must be either 'tcp' or 'udp'",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var backend dbcore.Backend
|
||||
backendRequest := dbcore.DB.Where("id = ?", req.ProviderID).First(&backend)
|
||||
|
||||
if backendRequest.Error != nil {
|
||||
log.Warnf("failed to find if backend exists or not: %s", backendRequest.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to find if backend exists",
|
||||
})
|
||||
}
|
||||
|
||||
backendExists := backendRequest.RowsAffected > 0
|
||||
|
||||
if !backendExists {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Could not find backend",
|
||||
})
|
||||
}
|
||||
|
||||
autoStart := false
|
||||
|
||||
if req.AutoStart != nil {
|
||||
autoStart = *req.AutoStart
|
||||
}
|
||||
|
||||
proxy := &dbcore.Proxy{
|
||||
UserID: user.ID,
|
||||
BackendID: req.ProviderID,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
Protocol: req.Protocol,
|
||||
SourceIP: req.SourceIP,
|
||||
SourcePort: req.SourcePort,
|
||||
DestinationPort: req.DestinationPort,
|
||||
AutoStart: autoStart,
|
||||
}
|
||||
|
||||
if result := dbcore.DB.Create(proxy); result.Error != nil {
|
||||
log.Warnf("failed to create proxy: %s", result.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to add forward rule to database",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if autoStart {
|
||||
backend, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"id": proxy.ID,
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backend.ProcessCommand(&commonbackend.AddProxy{
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestPort: proxy.DestinationPort,
|
||||
Protocol: proxy.Protocol,
|
||||
})
|
||||
if err := state.Validator.Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
user, err := state.JWT.GetUserFromJWT(req.Token)
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("Failed to get response for backend #%d: %s", proxy.BackendID, err.Error())
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to get response from backend",
|
||||
return
|
||||
} else {
|
||||
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",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.add") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
case *commonbackend.ProxyStatusResponse:
|
||||
if !responseMessage.IsActive {
|
||||
log.Warnf("Failed to start proxy for backend #%d", proxy.BackendID)
|
||||
}
|
||||
default:
|
||||
log.Errorf("Got illegal response type for backend #%d: %T", proxy.BackendID, responseMessage)
|
||||
}
|
||||
}
|
||||
if req.Protocol != "tcp" && req.Protocol != "udp" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Protocol must be either 'tcp' or 'udp'",
|
||||
})
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"id": proxy.ID,
|
||||
return
|
||||
}
|
||||
|
||||
var backend db.Backend
|
||||
backendRequest := state.DB.DB.Where("id = ?", req.ProviderID).First(&backend)
|
||||
|
||||
if backendRequest.Error != nil {
|
||||
log.Warnf("failed to find if backend exists or not: %s", backendRequest.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to find if backend exists",
|
||||
})
|
||||
}
|
||||
|
||||
backendExists := backendRequest.RowsAffected > 0
|
||||
|
||||
if !backendExists {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Could not find backend",
|
||||
})
|
||||
}
|
||||
|
||||
autoStart := false
|
||||
|
||||
if req.AutoStart != nil {
|
||||
autoStart = *req.AutoStart
|
||||
}
|
||||
|
||||
proxy := &db.Proxy{
|
||||
UserID: user.ID,
|
||||
BackendID: req.ProviderID,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
Protocol: req.Protocol,
|
||||
SourceIP: req.SourceIP,
|
||||
SourcePort: req.SourcePort,
|
||||
DestinationPort: req.DestinationPort,
|
||||
AutoStart: autoStart,
|
||||
}
|
||||
|
||||
if result := state.DB.DB.Create(proxy); result.Error != nil {
|
||||
log.Warnf("failed to create proxy: %s", result.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to add forward rule to database",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if autoStart {
|
||||
backend, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"id": proxy.ID,
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backend.ProcessCommand(&commonbackend.AddProxy{
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestPort: proxy.DestinationPort,
|
||||
Protocol: proxy.Protocol,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("Failed to get response for backend #%d: %s", proxy.BackendID, err.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to get response from backend",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
case *commonbackend.ProxyStatusResponse:
|
||||
if !responseMessage.IsActive {
|
||||
log.Warnf("Failed to start proxy for backend #%d", proxy.BackendID)
|
||||
}
|
||||
default:
|
||||
log.Errorf("Got illegal response type for backend #%d: %T", proxy.BackendID, responseMessage)
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"id": proxy.ID,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,12 +5,11 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.terah.dev/imterah/hermes/backend/api/dbcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/jwtcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/db"
|
||||
"git.terah.dev/imterah/hermes/backend/api/permissions"
|
||||
"git.terah.dev/imterah/hermes/backend/api/state"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type ProxyLookupRequest struct {
|
||||
|
@ -43,141 +42,143 @@ type ProxyLookupResponse struct {
|
|||
Data []*SanitizedProxy `json:"data"`
|
||||
}
|
||||
|
||||
func LookupProxy(c *gin.Context) {
|
||||
var req ProxyLookupRequest
|
||||
func SetupLookupProxy(state *state.State) {
|
||||
state.Engine.POST("/api/v1/forward/lookup", func(c *gin.Context) {
|
||||
var req ProxyLookupRequest
|
||||
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err := validator.New().Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
user, err := jwtcore.GetUserFromJWT(req.Token)
|
||||
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
log.Warnf("Failed to get user from the provided JWT token: %s", err.Error())
|
||||
}
|
||||
|
||||
if err := state.Validator.Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
user, err := state.JWT.GetUserFromJWT(req.Token)
|
||||
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.visible") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if req.Protocol != nil {
|
||||
if *req.Protocol != "tcp" && *req.Protocol != "udp" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Protocol specified in body must either be 'tcp' or 'udp'",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
proxies := []db.Proxy{}
|
||||
|
||||
queryString := []string{}
|
||||
queryParameters := []interface{}{}
|
||||
|
||||
if req.Id != nil {
|
||||
queryString = append(queryString, "id = ?")
|
||||
queryParameters = append(queryParameters, req.Id)
|
||||
}
|
||||
|
||||
if req.Name != nil {
|
||||
queryString = append(queryString, "name = ?")
|
||||
queryParameters = append(queryParameters, req.Name)
|
||||
}
|
||||
|
||||
if req.Description != nil {
|
||||
queryString = append(queryString, "description = ?")
|
||||
queryParameters = append(queryParameters, req.Description)
|
||||
}
|
||||
|
||||
if req.SourceIP != nil {
|
||||
queryString = append(queryString, "name = ?")
|
||||
queryParameters = append(queryParameters, req.Name)
|
||||
}
|
||||
|
||||
if req.SourcePort != nil {
|
||||
queryString = append(queryString, "source_port = ?")
|
||||
queryParameters = append(queryParameters, req.SourcePort)
|
||||
}
|
||||
|
||||
if req.DestinationPort != nil {
|
||||
queryString = append(queryString, "destination_port = ?")
|
||||
queryParameters = append(queryParameters, req.DestinationPort)
|
||||
}
|
||||
|
||||
if req.ProviderID != nil {
|
||||
queryString = append(queryString, "backend_id = ?")
|
||||
queryParameters = append(queryParameters, req.ProviderID)
|
||||
}
|
||||
|
||||
if req.AutoStart != nil {
|
||||
queryString = append(queryString, "auto_start = ?")
|
||||
queryParameters = append(queryParameters, req.AutoStart)
|
||||
}
|
||||
|
||||
if req.Protocol != nil {
|
||||
queryString = append(queryString, "protocol = ?")
|
||||
queryParameters = append(queryParameters, req.Protocol)
|
||||
}
|
||||
|
||||
if err := state.DB.DB.Where(strings.Join(queryString, " AND "), queryParameters...).Find(&proxies).Error; err != nil {
|
||||
log.Warnf("failed to get proxies: %s", err.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to parse token",
|
||||
"error": "Failed to get proxies",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.visible") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
sanitizedProxies := make([]*SanitizedProxy, len(proxies))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if req.Protocol != nil {
|
||||
if *req.Protocol != "tcp" && *req.Protocol != "udp" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "Protocol specified in body must either be 'tcp' or 'udp'",
|
||||
})
|
||||
|
||||
return
|
||||
for proxyIndex, proxy := range proxies {
|
||||
sanitizedProxies[proxyIndex] = &SanitizedProxy{
|
||||
Id: proxy.ID,
|
||||
Name: proxy.Name,
|
||||
Description: proxy.Description,
|
||||
Protcol: proxy.Protocol,
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestinationPort: proxy.DestinationPort,
|
||||
ProviderID: proxy.BackendID,
|
||||
AutoStart: proxy.AutoStart,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proxies := []dbcore.Proxy{}
|
||||
|
||||
queryString := []string{}
|
||||
queryParameters := []interface{}{}
|
||||
|
||||
if req.Id != nil {
|
||||
queryString = append(queryString, "id = ?")
|
||||
queryParameters = append(queryParameters, req.Id)
|
||||
}
|
||||
|
||||
if req.Name != nil {
|
||||
queryString = append(queryString, "name = ?")
|
||||
queryParameters = append(queryParameters, req.Name)
|
||||
}
|
||||
|
||||
if req.Description != nil {
|
||||
queryString = append(queryString, "description = ?")
|
||||
queryParameters = append(queryParameters, req.Description)
|
||||
}
|
||||
|
||||
if req.SourceIP != nil {
|
||||
queryString = append(queryString, "name = ?")
|
||||
queryParameters = append(queryParameters, req.Name)
|
||||
}
|
||||
|
||||
if req.SourcePort != nil {
|
||||
queryString = append(queryString, "source_port = ?")
|
||||
queryParameters = append(queryParameters, req.SourcePort)
|
||||
}
|
||||
|
||||
if req.DestinationPort != nil {
|
||||
queryString = append(queryString, "destination_port = ?")
|
||||
queryParameters = append(queryParameters, req.DestinationPort)
|
||||
}
|
||||
|
||||
if req.ProviderID != nil {
|
||||
queryString = append(queryString, "backend_id = ?")
|
||||
queryParameters = append(queryParameters, req.ProviderID)
|
||||
}
|
||||
|
||||
if req.AutoStart != nil {
|
||||
queryString = append(queryString, "auto_start = ?")
|
||||
queryParameters = append(queryParameters, req.AutoStart)
|
||||
}
|
||||
|
||||
if req.Protocol != nil {
|
||||
queryString = append(queryString, "protocol = ?")
|
||||
queryParameters = append(queryParameters, req.Protocol)
|
||||
}
|
||||
|
||||
if err := dbcore.DB.Where(strings.Join(queryString, " AND "), queryParameters...).Find(&proxies).Error; err != nil {
|
||||
log.Warnf("failed to get proxies: %s", err.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to get proxies",
|
||||
c.JSON(http.StatusOK, &ProxyLookupResponse{
|
||||
Success: true,
|
||||
Data: sanitizedProxies,
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
sanitizedProxies := make([]*SanitizedProxy, len(proxies))
|
||||
|
||||
for proxyIndex, proxy := range proxies {
|
||||
sanitizedProxies[proxyIndex] = &SanitizedProxy{
|
||||
Id: proxy.ID,
|
||||
Name: proxy.Name,
|
||||
Description: proxy.Description,
|
||||
Protcol: proxy.Protocol,
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestinationPort: proxy.DestinationPort,
|
||||
ProviderID: proxy.BackendID,
|
||||
AutoStart: proxy.AutoStart,
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, &ProxyLookupResponse{
|
||||
Success: true,
|
||||
Data: sanitizedProxies,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,13 +5,12 @@ import (
|
|||
"net/http"
|
||||
|
||||
"git.terah.dev/imterah/hermes/backend/api/backendruntime"
|
||||
"git.terah.dev/imterah/hermes/backend/api/dbcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/jwtcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/db"
|
||||
"git.terah.dev/imterah/hermes/backend/api/permissions"
|
||||
"git.terah.dev/imterah/hermes/backend/api/state"
|
||||
"git.terah.dev/imterah/hermes/backend/commonbackend"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type ProxyRemovalRequest struct {
|
||||
|
@ -19,134 +18,133 @@ type ProxyRemovalRequest struct {
|
|||
ID uint `validate:"required" json:"id"`
|
||||
}
|
||||
|
||||
func RemoveProxy(c *gin.Context) {
|
||||
var req ProxyRemovalRequest
|
||||
func SetupRemoveProxy(state *state.State) {
|
||||
state.Engine.POST("/api/v1/forward/remove", func(c *gin.Context) {
|
||||
var req ProxyRemovalRequest
|
||||
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := validator.New().Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
if err := state.Validator.Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
user, err := jwtcore.GetUserFromJWT(req.Token)
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
user, err := state.JWT.GetUserFromJWT(req.Token)
|
||||
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.remove") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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": "Missing permissions",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.remove") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
var proxy *db.Proxy
|
||||
proxyRequest := state.DB.DB.Where("id = ?", req.ID).Find(&proxy)
|
||||
|
||||
return
|
||||
}
|
||||
if proxyRequest.Error != nil {
|
||||
log.Warnf("failed to find if proxy exists or not: %s", proxyRequest.Error.Error())
|
||||
|
||||
var proxy *dbcore.Proxy
|
||||
proxyRequest := dbcore.DB.Where("id = ?", req.ID).Find(&proxy)
|
||||
|
||||
if proxyRequest.Error != nil {
|
||||
log.Warnf("failed to find if proxy exists or not: %s", proxyRequest.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to find if forward rule exists",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
proxyExists := proxyRequest.RowsAffected > 0
|
||||
|
||||
if !proxyExists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Forward rule doesn't exist",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err := dbcore.DB.Delete(proxy).Error; err != nil {
|
||||
log.Warnf("failed to delete proxy: %s", err.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to delete forward rule",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backend, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Couldn't fetch backend runtime",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backend.ProcessCommand(&commonbackend.RemoveProxy{
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestPort: proxy.DestinationPort,
|
||||
Protocol: proxy.Protocol,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("Failed to get response for backend #%d: %s", proxy.BackendID, err.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to get response from backend. Proxy was still successfully deleted",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
case *commonbackend.ProxyStatusResponse:
|
||||
if responseMessage.IsActive {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to stop proxy. Proxy was still successfully deleted",
|
||||
"error": "Failed to find if forward rule exists",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
default:
|
||||
log.Errorf("Got illegal response type for backend #%d: %T", proxy.BackendID, responseMessage)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Got invalid response from backend. Proxy was still successfully deleted",
|
||||
proxyExists := proxyRequest.RowsAffected > 0
|
||||
|
||||
if !proxyExists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Forward rule doesn't exist",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err := state.DB.DB.Delete(proxy).Error; err != nil {
|
||||
log.Warnf("failed to delete proxy: %s", err.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to delete forward rule",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backend, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Couldn't fetch backend runtime",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backend.ProcessCommand(&commonbackend.RemoveProxy{
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestPort: proxy.DestinationPort,
|
||||
Protocol: proxy.Protocol,
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Warnf("Failed to get response for backend #%d: %s", proxy.BackendID, err.Error())
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to get response from backend. Proxy was still successfully deleted",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
case *commonbackend.ProxyStatusResponse:
|
||||
if responseMessage.IsActive {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to stop proxy. Proxy was still successfully deleted",
|
||||
})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
})
|
||||
}
|
||||
default:
|
||||
log.Errorf("Got illegal response type for backend #%d: %T", proxy.BackendID, responseMessage)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Got invalid response from backend. Proxy was still successfully deleted",
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,13 +5,12 @@ import (
|
|||
"net/http"
|
||||
|
||||
"git.terah.dev/imterah/hermes/backend/api/backendruntime"
|
||||
"git.terah.dev/imterah/hermes/backend/api/dbcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/jwtcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/db"
|
||||
"git.terah.dev/imterah/hermes/backend/api/permissions"
|
||||
"git.terah.dev/imterah/hermes/backend/api/state"
|
||||
"git.terah.dev/imterah/hermes/backend/commonbackend"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type ProxyStartRequest struct {
|
||||
|
@ -19,124 +18,119 @@ type ProxyStartRequest struct {
|
|||
ID uint `validate:"required" json:"id"`
|
||||
}
|
||||
|
||||
func StartProxy(c *gin.Context) {
|
||||
var req ProxyStartRequest
|
||||
func SetupStartProxy(state *state.State) {
|
||||
state.Engine.POST("/api/v1/forward/start", func(c *gin.Context) {
|
||||
var req ProxyStartRequest
|
||||
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := validator.New().Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
if err := state.Validator.Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
user, err := jwtcore.GetUserFromJWT(req.Token)
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
user, err := state.JWT.GetUserFromJWT(req.Token)
|
||||
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.start") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.start") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var proxy *dbcore.Proxy
|
||||
proxyRequest := dbcore.DB.Where("id = ?", req.ID).Find(&proxy)
|
||||
|
||||
if proxyRequest.Error != nil {
|
||||
log.Warnf("failed to find if proxy exists or not: %s", proxyRequest.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to find if forward rule exists",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
proxyExists := proxyRequest.RowsAffected > 0
|
||||
|
||||
if !proxyExists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Forward rule doesn't exist",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backend, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Couldn't fetch backend runtime",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backend.ProcessCommand(&commonbackend.AddProxy{
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestPort: proxy.DestinationPort,
|
||||
Protocol: proxy.Protocol,
|
||||
})
|
||||
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
case error:
|
||||
log.Warnf("Failed to get response for backend #%d: %s", proxy.BackendID, responseMessage.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to get response from backend",
|
||||
})
|
||||
|
||||
return
|
||||
case *commonbackend.ProxyStatusResponse:
|
||||
if !responseMessage.IsActive {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to start proxy",
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
break
|
||||
default:
|
||||
log.Errorf("Got illegal response type for backend #%d: %T", proxy.BackendID, responseMessage)
|
||||
var proxy *db.Proxy
|
||||
proxyRequest := state.DB.DB.Where("id = ?", req.ID).Find(&proxy)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Got invalid response from backend. Proxy was still successfully deleted",
|
||||
if proxyRequest.Error != nil {
|
||||
log.Warnf("failed to find if proxy exists or not: %s", proxyRequest.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to find if forward rule exists",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
proxyExists := proxyRequest.RowsAffected > 0
|
||||
|
||||
if !proxyExists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Forward rule doesn't exist",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backend, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Couldn't fetch backend runtime",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backend.ProcessCommand(&commonbackend.AddProxy{
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestPort: proxy.DestinationPort,
|
||||
Protocol: proxy.Protocol,
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
case error:
|
||||
log.Warnf("Failed to get response for backend #%d: %s", proxy.BackendID, responseMessage.Error())
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to get response from backend",
|
||||
})
|
||||
case *commonbackend.ProxyStatusResponse:
|
||||
if !responseMessage.IsActive {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to start proxy",
|
||||
})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
})
|
||||
}
|
||||
default:
|
||||
log.Errorf("Got illegal response type for backend #%d: %T", proxy.BackendID, responseMessage)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Got invalid response from backend. Proxy was likely still successfully started",
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,13 +5,12 @@ import (
|
|||
"net/http"
|
||||
|
||||
"git.terah.dev/imterah/hermes/backend/api/backendruntime"
|
||||
"git.terah.dev/imterah/hermes/backend/api/dbcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/jwtcore"
|
||||
"git.terah.dev/imterah/hermes/backend/api/db"
|
||||
"git.terah.dev/imterah/hermes/backend/api/permissions"
|
||||
"git.terah.dev/imterah/hermes/backend/api/state"
|
||||
"git.terah.dev/imterah/hermes/backend/commonbackend"
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type ProxyStopRequest struct {
|
||||
|
@ -19,124 +18,119 @@ type ProxyStopRequest struct {
|
|||
ID uint `validate:"required" json:"id"`
|
||||
}
|
||||
|
||||
func StopProxy(c *gin.Context) {
|
||||
var req ProxyStopRequest
|
||||
func SetupStopProxy(state *state.State) {
|
||||
state.Engine.POST("/api/v1/forward/stop", func(c *gin.Context) {
|
||||
var req ProxyStartRequest
|
||||
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
if err := c.BindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to parse body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := validator.New().Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
if err := state.Validator.Struct(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": fmt.Sprintf("Failed to validate body: %s", err.Error()),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
user, err := jwtcore.GetUserFromJWT(req.Token)
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
user, err := state.JWT.GetUserFromJWT(req.Token)
|
||||
|
||||
if err != nil {
|
||||
if err.Error() == "token is expired" || err.Error() == "user does not exist" {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.stop") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
||||
return
|
||||
} else {
|
||||
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": "Missing permissions",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !permissions.UserHasPermission(user, "routes.stop") {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "Missing permissions",
|
||||
})
|
||||
var proxy *db.Proxy
|
||||
proxyRequest := state.DB.DB.Where("id = ?", req.ID).Find(&proxy)
|
||||
|
||||
return
|
||||
}
|
||||
if proxyRequest.Error != nil {
|
||||
log.Warnf("failed to find if proxy exists or not: %s", proxyRequest.Error.Error())
|
||||
|
||||
var proxy *dbcore.Proxy
|
||||
proxyRequest := dbcore.DB.Where("id = ?", req.ID).Find(&proxy)
|
||||
|
||||
if proxyRequest.Error != nil {
|
||||
log.Warnf("failed to find if proxy exists or not: %s", proxyRequest.Error.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Failed to find if forward rule exists",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
proxyExists := proxyRequest.RowsAffected > 0
|
||||
|
||||
if !proxyExists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Forward rule doesn't exist",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backend, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Couldn't fetch backend runtime",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backend.ProcessCommand(&commonbackend.RemoveProxy{
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestPort: proxy.DestinationPort,
|
||||
Protocol: proxy.Protocol,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Warnf("Failed to get response for backend #%d: %s", proxy.BackendID, err.Error())
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to get response from backend",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
case *commonbackend.ProxyStatusResponse:
|
||||
if responseMessage.IsActive {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to stop proxy",
|
||||
"error": "Failed to find if forward rule exists",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
default:
|
||||
log.Errorf("Got illegal response type for backend #%d: %T", proxy.BackendID, responseMessage)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Got invalid response from backend. Proxy was still successfully deleted",
|
||||
proxyExists := proxyRequest.RowsAffected > 0
|
||||
|
||||
if !proxyExists {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Forward rule doesn't exist",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backend, ok := backendruntime.RunningBackends[proxy.BackendID]
|
||||
|
||||
if !ok {
|
||||
log.Warnf("Couldn't fetch backend runtime from backend ID #%d", proxy.BackendID)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Couldn't fetch backend runtime",
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
backendResponse, err := backend.ProcessCommand(&commonbackend.RemoveProxy{
|
||||
SourceIP: proxy.SourceIP,
|
||||
SourcePort: proxy.SourcePort,
|
||||
DestPort: proxy.DestinationPort,
|
||||
Protocol: proxy.Protocol,
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
switch responseMessage := backendResponse.(type) {
|
||||
case error:
|
||||
log.Warnf("Failed to get response for backend #%d: %s", proxy.BackendID, responseMessage.Error())
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to get response from backend",
|
||||
})
|
||||
case *commonbackend.ProxyStatusResponse:
|
||||
if responseMessage.IsActive {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "failed to stop proxy",
|
||||
})
|
||||
} else {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
})
|
||||
}
|
||||
default:
|
||||
log.Errorf("Got illegal response type for backend #%d: %T", proxy.BackendID, responseMessage)
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "Got invalid response from backend. Proxy was likely still successfully stopped",
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue