feat: per-link IP whitelist, clipboard fallback, and link editing
Build and Push to GHCR / build-and-push (push) Has been cancelled
Build and Push to GHCR / build-and-push (push) Has been cancelled
- Add `allowed_ips` to Link model with IPv4/IPv6 and CIDR support - Validate client IP in proxy auth middleware against link whitelist - Extract client IP from X-Forwarded-For / X-Real-Ip headers - Fix copy button for non-HTTPS contexts via execCommand fallback - Allow editing existing links (name, type, auth mode, rate limit, IPs) - Add dedicated IP whitelist modal for quick editing via [HAPI](https://hapi.run) Co-Authored-By: HAPI <[email protected]>
This commit is contained in:
+34
-17
@@ -14,6 +14,17 @@ import (
|
||||
"mirror-proxy/internal/config"
|
||||
)
|
||||
|
||||
func normalizeIPs(ips []string) []string {
|
||||
var out []string
|
||||
for _, ip := range ips {
|
||||
ip = strings.TrimSpace(ip)
|
||||
if ip != "" {
|
||||
out = append(out, ip)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
cfg *config.Config
|
||||
onRestart func()
|
||||
@@ -192,10 +203,11 @@ func (h *Handler) GetLinks(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (h *Handler) CreateLink(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
RateLimit int `json:"rate_limit"`
|
||||
AuthMode string `json:"auth_mode"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
RateLimit int `json:"rate_limit"`
|
||||
AuthMode string `json:"auth_mode"`
|
||||
AllowedIPs []string `json:"allowed_ips"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
@@ -214,14 +226,15 @@ func (h *Handler) CreateLink(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
link := &config.Link{
|
||||
ID: generateID(),
|
||||
Name: req.Name,
|
||||
Token: auth.GenerateToken(),
|
||||
Type: req.Type,
|
||||
AuthMode: req.AuthMode,
|
||||
Enabled: true,
|
||||
RateLimit: req.RateLimit,
|
||||
CreatedAt: time.Now().Unix(),
|
||||
ID: generateID(),
|
||||
Name: req.Name,
|
||||
Token: auth.GenerateToken(),
|
||||
Type: req.Type,
|
||||
AuthMode: req.AuthMode,
|
||||
Enabled: true,
|
||||
RateLimit: req.RateLimit,
|
||||
AllowedIPs: normalizeIPs(req.AllowedIPs),
|
||||
CreatedAt: time.Now().Unix(),
|
||||
}
|
||||
|
||||
h.cfg.SetLink(link)
|
||||
@@ -244,11 +257,12 @@ func (h *Handler) UpdateLink(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
RateLimit int `json:"rate_limit"`
|
||||
AuthMode string `json:"auth_mode"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
RateLimit int `json:"rate_limit"`
|
||||
AuthMode string `json:"auth_mode"`
|
||||
AllowedIPs []string `json:"allowed_ips,omitempty"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
@@ -271,6 +285,9 @@ func (h *Handler) UpdateLink(w http.ResponseWriter, r *http.Request) {
|
||||
if req.AuthMode != "" {
|
||||
link.AuthMode = req.AuthMode
|
||||
}
|
||||
if req.AllowedIPs != nil {
|
||||
link.AllowedIPs = normalizeIPs(req.AllowedIPs)
|
||||
}
|
||||
|
||||
h.cfg.SetLink(link)
|
||||
if err := h.cfg.Save(config.GetConfigFilePath()); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user