feat(proxy): add proxy deletion API endpoint
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.
This commit is contained in:
@@ -65,6 +65,7 @@ For detailed API documentation, please see [docs/api.md](docs/api.md)
|
||||
- [ ] Add user config modify API
|
||||
- [ ] Add frpc instance running status management API
|
||||
- [ ] Add frpc instance log display API
|
||||
- [ ] Fix random database lock when processing logs
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+115
@@ -135,3 +135,118 @@ func addFrpcProxy(info FrpcProxyInfo) string {
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ func setupRoutes() {
|
||||
http.HandleFunc("/frpcAct/instanceMgr/modify", ModifyInstanceHandler)
|
||||
http.HandleFunc("/frpcAct/instanceMgr/list", ListInstancesHandler)
|
||||
http.HandleFunc("/frpcAct/proxyMgr/create", CreateProxyHandler)
|
||||
http.HandleFunc("/frpcAct/proxyMgr/delete", DeleteProxyHandler)
|
||||
|
||||
http.HandleFunc("/", NotFoundHandler)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user