mirror of
https://github.com/MengMengCode/CLICD.git
synced 2026-08-09 15:02:13 +08:00
Add custom image handling and access policy management
- Implement tests for custom KVM and LXC image creation, ensuring invalid sources and architecture mismatches are rejected. - Introduce access policy management in CLI, allowing configuration of allowed sources and trusted proxies. - Add NAT network configuration with validation for RFC1918 compliance and subnet parsing. - Create panel access policy management, including normalization and evaluation of access decisions based on client IPs and forwarded headers. - Develop middleware for enforcing access policies in the server, returning appropriate responses for allowed and denied requests. - Enhance custom image downloading and validation, ensuring integrity and security of downloaded root filesystem archives. - Include comprehensive tests for all new functionalities to ensure reliability and correctness.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"clicd/internal/config"
|
||||
)
|
||||
|
||||
type panelAccessPolicyResponse struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
AllowedSources []string `json:"allowed_sources"`
|
||||
TrustedProxies []string `json:"trusted_proxies"`
|
||||
CurrentSource string `json:"current_source"`
|
||||
DirectSource string `json:"direct_source"`
|
||||
UsingForwarded bool `json:"using_forwarded"`
|
||||
}
|
||||
|
||||
func HandlePanelAccessPolicy(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
jsonResponse(w, http.StatusOK, APIResponse{Success: true, Data: panelAccessPolicyStatus(r, config.AppConfig.PanelAccessPolicy)})
|
||||
case http.MethodPut:
|
||||
updatePanelAccessPolicy(w, r)
|
||||
default:
|
||||
jsonResponse(w, http.StatusMethodNotAllowed, APIResponse{Success: false, Message: "Method not allowed"})
|
||||
}
|
||||
}
|
||||
|
||||
func updatePanelAccessPolicy(w http.ResponseWriter, r *http.Request) {
|
||||
var requested config.PanelAccessPolicy
|
||||
if err := json.NewDecoder(r.Body).Decode(&requested); err != nil {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: "Invalid request body"})
|
||||
return
|
||||
}
|
||||
normalized, err := config.NormalizePanelAccessPolicy(requested)
|
||||
if err != nil {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{Success: false, Message: err.Error()})
|
||||
return
|
||||
}
|
||||
decision := evaluatePanelRequest(r, normalized)
|
||||
if normalized.Enabled && !decision.Allowed {
|
||||
jsonResponse(w, http.StatusBadRequest, APIResponse{
|
||||
Success: false,
|
||||
Message: "The new access policy does not allow your current source address " + decision.CurrentSource,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
previous := config.AppConfig.PanelAccessPolicy
|
||||
config.AppConfig.PanelAccessPolicy = normalized
|
||||
if err := config.SaveConfig(); err != nil {
|
||||
config.AppConfig.PanelAccessPolicy = previous
|
||||
jsonResponse(w, http.StatusInternalServerError, APIResponse{Success: false, Message: "Failed to save panel access policy"})
|
||||
return
|
||||
}
|
||||
detail := "enabled=" + strings.ToLower(strings.TrimSpace(boolText(normalized.Enabled))) +
|
||||
",allowed=" + strings.Join(normalized.AllowedSources, ",") +
|
||||
",trusted_proxies=" + strings.Join(normalized.TrustedProxies, ",")
|
||||
auditRequest(r, "settings.panel_access", "Panel access policy", detail, true, "")
|
||||
jsonResponse(w, http.StatusOK, APIResponse{
|
||||
Success: true,
|
||||
Message: "Panel access policy saved",
|
||||
Data: panelAccessPolicyStatus(r, normalized),
|
||||
})
|
||||
}
|
||||
|
||||
func panelAccessPolicyStatus(r *http.Request, policy config.PanelAccessPolicy) panelAccessPolicyResponse {
|
||||
decision := evaluatePanelRequest(r, policy)
|
||||
return panelAccessPolicyResponse{
|
||||
Enabled: policy.Enabled,
|
||||
AllowedSources: append([]string(nil), policy.AllowedSources...),
|
||||
TrustedProxies: append([]string(nil), policy.TrustedProxies...),
|
||||
CurrentSource: decision.CurrentSource,
|
||||
DirectSource: decision.DirectSource,
|
||||
UsingForwarded: decision.UsedForwarded,
|
||||
}
|
||||
}
|
||||
|
||||
func evaluatePanelRequest(r *http.Request, policy config.PanelAccessPolicy) config.PanelAccessDecision {
|
||||
return config.EvaluatePanelAccess(policy, r.RemoteAddr, config.ForwardedClientHeaders{
|
||||
ForwardedFor: r.Header.Get("X-Forwarded-For"),
|
||||
RealIP: r.Header.Get("X-Real-IP"),
|
||||
CFConnectingIP: r.Header.Get("CF-Connecting-IP"),
|
||||
})
|
||||
}
|
||||
|
||||
func boolText(value bool) string {
|
||||
if value {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
}
|
||||
Reference in New Issue
Block a user