package utils import ( "encoding/json" "fmt" "net/http" "strconv" "time" "strings" "super-frpc/database" "super-frpc/global" "super-frpc/postLog" "super-frpc/session" ) type Response struct { Success bool `json:"success"` Message string `json:"message,omitempty"` Data interface{} `json:"data,omitempty"` } // SendErrorResponse sends an error response with the specified status code and message. // If data is provided, it is included in the response. func SendErrorResponse(w http.ResponseWriter, statusCode int, message string, data ...interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) resp := Response{ Success: false, Message: message, } if len(data) > 0 { resp.Data = data[0] } jsonResp, err := json.Marshal(resp) if err != nil { postLog.Error(fmt.Sprintf("Failed to marshal error response: %v", err)) return } w.Write(jsonResp) } // SendSuccessResponse sends a success response with the specified message and data. // If data is provided, it is included in the response. func SendSuccessResponse(w http.ResponseWriter, message string, data interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) resp := Response{ Success: true, Message: message, Data: data, } jsonResp, err := json.Marshal(resp) if err != nil { postLog.Error(fmt.Sprintf("Failed to marshal success response: %v", err)) return } w.Write(jsonResp) } // Auth authenticates the request. // It checks the request method, timestamp, and token. // If any of these checks fail, it returns an error. // If no error occurs, it returns the user ID. func Auth(w http.ResponseWriter, r *http.Request, targetMethod string, allowedUserLevels ...string) (int, error) { if r.Method != targetMethod { return 0, fmt.Errorf("Method not allowed: %s", targetMethod) } if !global.Is.Debug && !session.ValidateTimeStamp(r.Header, global.Is.Debug) { return 0, fmt.Errorf("Invalid or missing X-Timestamp in header") } userID, err := session.ExtractUserIDFromToken(r.Header.Get("X-Token")) if err != nil { return 0, fmt.Errorf("Invalid token format: %w", err) } if err := session.ValidateToken(userID, r.Header.Get("X-Token")); err != nil { return 0, fmt.Errorf("Token validation failed: %w", err) } if len(allowedUserLevels) > 0 { currentUser, err := database.DBQuerySpecificUser(userID) if err != nil { return 0, fmt.Errorf("Failed to query user: %w", err) } allowed := false for _, level := range allowedUserLevels { if currentUser.Type == level { allowed = true break } } if !allowed { return 0, fmt.Errorf("User level not allowed: required one of %v, got %s", allowedUserLevels, currentUser.Type) } } return userID, nil } func GetUserType(userID int) (string, error) { user, err := database.GetUserByID(userID) if err != nil { return "", fmt.Errorf("Failed to get user type: %w", err) } return user.Type, nil } func GetClientIP(r *http.Request) string { forwarded := r.Header.Get("X-Forwarded-For") if forwarded != "" { return forwarded } return r.RemoteAddr } func LogRequest(r *http.Request, userID int) { postLog.Info(fmt.Sprintf("[%s] %s %s - UserID: %d - IP: %s", time.Now().Format("2006-01-02 15:04:05"), r.Method, r.URL.Path, userID, GetClientIP(r), )) } func IntToString(i int) string { return strconv.Itoa(i) } func GetTextMiddle(text, left, right string) string { start := 0 if left != "" { idx := strings.Index(text, left) if idx == -1 { return "" } start = idx + len(left) } if right == "" { if start > len(text) { return "" } return text[start:] } endIdx := strings.Index(text[start:], right) if endIdx == -1 { return "" } return text[start : start+endIdx] } func GetCmdType(source string) string { return GetTextMiddle(source, "[", "]") } func GetCmdParams(source string, param string) string { return GetTextMiddle(source, "<"+param+">", "") }