Implement handler for deleting frpc proxies with proper validation and error handling. The endpoint checks user permissions, validates input, removes the proxy configuration from the instance file, and returns appropriate responses.
253 lines
8.6 KiB
Go
253 lines
8.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"super-frpc/postLog"
|
|
)
|
|
|
|
type CreateProxyRequest struct {
|
|
InstanceID string `json:"instanceID"`
|
|
ProxyInfo FrpcProxyInfo `json:"proxyInfo"`
|
|
}
|
|
|
|
func CreateProxyHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[CreateProxyHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to read request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Failed to read request body")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
|
|
var reqMap map[string]interface{}
|
|
if err := json.Unmarshal(body, &reqMap); err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to unmarshal request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
|
|
return
|
|
}
|
|
|
|
instanceID := getStringFromMap(reqMap, "instanceID")
|
|
if instanceID == "" {
|
|
postLog.Error("[CreateProxyHandler] instanceID is required")
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
proxyInfoMap, ok := reqMap["proxyInfo"].(map[string]interface{})
|
|
if !ok {
|
|
postLog.Error("[CreateProxyHandler] Invalid proxyInfo format")
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid proxyInfo format")
|
|
return
|
|
}
|
|
|
|
proxyInfo := FrpcProxyInfo{
|
|
Name: getStringFromMap(proxyInfoMap, "name"),
|
|
Type: getStringFromMap(proxyInfoMap, "type"),
|
|
LocalIP: getStringFromMap(proxyInfoMap, "localIP"),
|
|
LocalPort: getStringFromMap(proxyInfoMap, "localPort"),
|
|
RemotePort: getStringFromMap(proxyInfoMap, "remotePort"),
|
|
}
|
|
|
|
if proxyInfo.Name == "" || proxyInfo.Type == "" || proxyInfo.LocalIP == "" ||
|
|
proxyInfo.LocalPort == "" || proxyInfo.RemotePort == "" {
|
|
postLog.Error("[CreateProxyHandler] Missing required fields in proxyInfo")
|
|
SendErrorResponse(w, http.StatusBadRequest, "Missing required fields in proxyInfo")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
|
|
return
|
|
}
|
|
|
|
userType, err := GetUserType(userID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to get user type: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user type")
|
|
return
|
|
} else if userType != "admin" && userType != "superuser" {
|
|
SendErrorResponse(w, http.StatusForbidden, "Permission Denied")
|
|
return
|
|
}
|
|
|
|
var instance FrpcInstance
|
|
instanceIDInt, _ := strconv.Atoi(instanceID)
|
|
instance, err = DBQueryFrpcInstanceByID(instanceIDInt)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to query instance: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
|
|
return
|
|
}
|
|
|
|
if instance.UserID != userID {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Instance not found for user %d", userID))
|
|
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
|
return
|
|
}
|
|
|
|
configContent, err := os.ReadFile(instance.ConfigPath)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to read config file %s: %v", instance.ConfigPath, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
|
|
return
|
|
}
|
|
|
|
proxyConfig := addFrpcProxy(proxyInfo)
|
|
updatedContent := string(configContent) + proxyConfig
|
|
|
|
if err := os.WriteFile(instance.ConfigPath, []byte(updatedContent), 0644); err != nil {
|
|
postLog.Error(fmt.Sprintf("[CreateProxyHandler] Failed to write config file %s: %v", instance.ConfigPath, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to write config file")
|
|
return
|
|
}
|
|
|
|
SendSuccessResponse(w, "Proxy created successfully", map[string]interface{}{
|
|
"instanceName": instance.Name,
|
|
"instanceID": instance.ID,
|
|
"configPath": instance.ConfigPath,
|
|
"proxyName": proxyInfo.Name,
|
|
})
|
|
postLog.Info(fmt.Sprintf("[CreateProxyHandler] Proxy %s created successfully for instance %s", proxyInfo.Name, instance.Name))
|
|
}
|
|
|
|
func addFrpcProxy(info FrpcProxyInfo) string {
|
|
var sb strings.Builder
|
|
sb.WriteString("\n[[proxies]]\n")
|
|
sb.WriteString(fmt.Sprintf("name = %s\n", info.Name))
|
|
sb.WriteString(fmt.Sprintf("type = %s\n", info.Type))
|
|
sb.WriteString(fmt.Sprintf("local_ip = %s\n", info.LocalIP))
|
|
sb.WriteString(fmt.Sprintf("local_port = %s\n", info.LocalPort))
|
|
sb.WriteString(fmt.Sprintf("remote_port = %s\n", info.RemotePort))
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
func DeleteProxyHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
SendErrorResponse(w, http.StatusMethodNotAllowed, "Invalid request method")
|
|
postLog.Debug(fmt.Sprintf("[DeleteProxyHandler] Invalid request method: %s", r.Method))
|
|
return
|
|
}
|
|
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to read request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Failed to read request body")
|
|
return
|
|
}
|
|
defer r.Body.Close()
|
|
|
|
var reqMap map[string]interface{}
|
|
if err := json.Unmarshal(body, &reqMap); err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to unmarshal request body: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request format")
|
|
return
|
|
}
|
|
|
|
instanceID := getStringFromMap(reqMap, "instanceID")
|
|
if instanceID == "" {
|
|
postLog.Error("[DeleteProxyHandler] instanceID is required")
|
|
SendErrorResponse(w, http.StatusBadRequest, "instanceID is required")
|
|
return
|
|
}
|
|
|
|
proxyName := getStringFromMap(reqMap, "proxyName")
|
|
if proxyName == "" {
|
|
postLog.Error("[DeleteProxyHandler] proxyName is required")
|
|
SendErrorResponse(w, http.StatusBadRequest, "proxyName is required")
|
|
return
|
|
}
|
|
|
|
userID, _, err := ValidateRequestWithHeader(w, r)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to validate request header: %v", err))
|
|
SendErrorResponse(w, http.StatusBadRequest, "Invalid request header")
|
|
return
|
|
}
|
|
|
|
userType, err := GetUserType(userID)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to get user type: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to get user type")
|
|
return
|
|
} else if userType != "admin" && userType != "superuser" {
|
|
SendErrorResponse(w, http.StatusForbidden, "Permission Denied")
|
|
return
|
|
}
|
|
|
|
var instance FrpcInstance
|
|
instanceIDInt, _ := strconv.Atoi(instanceID)
|
|
instance, err = DBQueryFrpcInstanceByID(instanceIDInt)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to query instance: %v", err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to query instance")
|
|
return
|
|
}
|
|
|
|
if instance.UserID != userID {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Instance not found for user %d", userID))
|
|
SendErrorResponse(w, http.StatusNotFound, "Instance not found")
|
|
return
|
|
}
|
|
|
|
configContent, err := os.ReadFile(instance.ConfigPath)
|
|
if err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to read config file %s: %v", instance.ConfigPath, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to read config file")
|
|
return
|
|
}
|
|
|
|
lines := strings.Split(string(configContent), "\n")
|
|
var newLines []string
|
|
var i int
|
|
for i < len(lines) {
|
|
if strings.HasPrefix(lines[i], "[[proxies]]") {
|
|
nameLine := i + 1
|
|
if nameLine < len(lines) && strings.HasPrefix(lines[nameLine], "name = ") {
|
|
currentProxyName := strings.TrimSpace(strings.TrimPrefix(lines[nameLine], "name = "))
|
|
if currentProxyName == proxyName {
|
|
i += 6
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
newLines = append(newLines, lines[i])
|
|
i++
|
|
}
|
|
|
|
if len(newLines) == len(lines) {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Proxy %s not found in config file %s", proxyName, instance.ConfigPath))
|
|
SendErrorResponse(w, http.StatusNotFound, "Proxy not found")
|
|
return
|
|
}
|
|
|
|
updatedContent := strings.Join(newLines, "\n")
|
|
if err := os.WriteFile(instance.ConfigPath, []byte(updatedContent), 0644); err != nil {
|
|
postLog.Error(fmt.Sprintf("[DeleteProxyHandler] Failed to write config file %s: %v", instance.ConfigPath, err))
|
|
SendErrorResponse(w, http.StatusInternalServerError, "Failed to write config file")
|
|
return
|
|
}
|
|
|
|
SendSuccessResponse(w, "Proxy deleted successfully", map[string]interface{}{
|
|
"instanceName": instance.Name,
|
|
"instanceID": instance.ID,
|
|
"configPath": instance.ConfigPath,
|
|
"proxyName": proxyName,
|
|
})
|
|
postLog.Info(fmt.Sprintf("[DeleteProxyHandler] Proxy %s deleted successfully from instance %s", proxyName, instance.Name))
|
|
}
|