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)) }