feat: implement panel domain verification for federation sharing

This commit is contained in:
sagit
2026-02-09 10:53:58 +00:00
parent bf88b0dd7e
commit a19e8d2bcb
9 changed files with 91 additions and 18 deletions
@@ -38,13 +38,16 @@ func NewFederationClient() *FederationClient {
}
}
func (c *FederationClient) Connect(url, token string) (*RemoteNodeInfo, error) {
func (c *FederationClient) Connect(url, token, localDomain string) (*RemoteNodeInfo, error) {
url = strings.TrimSuffix(url, "/")
req, err := http.NewRequest("POST", url+"/api/v1/federation/connect", nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+token)
if localDomain != "" {
req.Header.Set("X-Panel-Domain", localDomain)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
@@ -73,7 +76,7 @@ func (c *FederationClient) Connect(url, token string) (*RemoteNodeInfo, error) {
return &res.Data, nil
}
func (c *FederationClient) CreateTunnel(url, token string, protocol string, remotePort int, target string) (*RemoteTunnelResponse, error) {
func (c *FederationClient) CreateTunnel(url, token, localDomain, protocol string, remotePort int, target string) (*RemoteTunnelResponse, error) {
url = strings.TrimSuffix(url, "/")
payload := map[string]interface{}{
"protocol": protocol,
@@ -86,6 +89,9 @@ func (c *FederationClient) CreateTunnel(url, token string, protocol string, remo
return nil, err
}
req.Header.Set("Authorization", "Bearer "+token)
if localDomain != "" {
req.Header.Set("X-Panel-Domain", localDomain)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
+29 -1
View File
@@ -25,6 +25,7 @@ type createPeerShareRequest struct {
ExpiryTime int64 `json:"expiryTime"`
PortRangeStart int `json:"portRangeStart"`
PortRangeEnd int `json:"portRangeEnd"`
AllowedDomains string `json:"allowedDomains"`
}
type deletePeerShareRequest struct {
@@ -111,6 +112,7 @@ func (h *Handler) federationShareCreate(w http.ResponseWriter, r *http.Request)
IsActive: 1,
CreatedTime: now,
UpdatedTime: now,
AllowedDomains: req.AllowedDomains,
}
if err := h.repo.CreatePeerShare(share); err != nil {
@@ -158,8 +160,14 @@ func (h *Handler) nodeImport(w http.ResponseWriter, r *http.Request) {
return
}
domainCfg, _ := h.repo.GetConfigByName("panel_domain")
localDomain := ""
if domainCfg != nil {
localDomain = domainCfg.Value
}
fc := client.NewFederationClient()
info, err := fc.Connect(req.RemoteURL, req.Token)
info, err := fc.Connect(req.RemoteURL, req.Token, localDomain)
if err != nil {
response.WriteJSON(w, response.Err(-2, "Failed to connect: "+err.Error()))
return
@@ -242,6 +250,26 @@ func (h *Handler) authPeer(next http.HandlerFunc) http.HandlerFunc {
return
}
if share.AllowedDomains != "" {
clientDomain := r.Header.Get("X-Panel-Domain")
if clientDomain == "" {
response.WriteJSON(w, response.Err(403, "Domain verification required"))
return
}
allowed := false
domains := strings.Split(share.AllowedDomains, ",")
for _, d := range domains {
if strings.TrimSpace(d) == clientDomain {
allowed = true
break
}
}
if !allowed {
response.WriteJSON(w, response.Err(403, "Domain not allowed"))
return
}
}
next(w, r)
}
}
@@ -543,7 +543,12 @@ func (h *Handler) tunnelCreate(w http.ResponseWriter, r *http.Request) {
}
if targetPort > 0 && targetAddr != "" {
_, err := fc.CreateTunnel(rUrl.String, rToken.String, targetProto, targetPort, targetAddr)
domainCfg, _ := h.repo.GetConfigByName("panel_domain")
localDomain := ""
if domainCfg != nil {
localDomain = domainCfg.Value
}
_, err := fc.CreateTunnel(rUrl.String, rToken.String, localDomain, targetProto, targetPort, targetAddr)
if err != nil {
response.WriteJSON(w, response.ErrDefault("Remote tunnel creation failed: "+err.Error()))
return