mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-19 05:09:06 +02:00
ReverseProxyClustersAPI.Delete and ReverseProxyTokensAPI.Delete passed
the path parameter into url.PathEscape without an empty check.
PathEscape("") returns "" which collapses the request onto the
collection endpoint ("/api/reverse-proxies/clusters/" /
"/api/reverse-proxies/proxy-tokens/"), so a caller bug delete with no
id reached a routable URL with surprising semantics (typically 405).
Short-circuit with a typed error before the request is built. Tests
mount a handler on the collection path that fails the test if hit, so
the regression is impossible to reintroduce silently.
52 lines
1.7 KiB
Go
52 lines
1.7 KiB
Go
package rest
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/url"
|
|
|
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
|
)
|
|
|
|
// ReverseProxyClustersAPI APIs for Reverse Proxy Clusters, do not use directly
|
|
type ReverseProxyClustersAPI struct {
|
|
c *Client
|
|
}
|
|
|
|
// List lists all available proxy clusters. Each cluster is enriched with the
|
|
// capability flags reported by its connected proxies (supports_custom_ports,
|
|
// supports_crowdsec, private, etc.), so callers can render UX gates without
|
|
// a follow-up round-trip.
|
|
func (a *ReverseProxyClustersAPI) List(ctx context.Context) ([]api.ProxyCluster, error) {
|
|
resp, err := a.c.NewRequest(ctx, "GET", "/api/reverse-proxies/clusters", nil, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Body != nil {
|
|
defer resp.Body.Close()
|
|
}
|
|
ret, err := parseResponse[[]api.ProxyCluster](resp)
|
|
return ret, err
|
|
}
|
|
|
|
// Delete removes every self-hosted (BYOP) proxy registration for the given
|
|
// cluster address owned by the calling account. Shared clusters operated by
|
|
// NetBird cannot be deleted via this endpoint; the server returns 404 / 400
|
|
// for cluster addresses the account does not own.
|
|
func (a *ReverseProxyClustersAPI) Delete(ctx context.Context, clusterAddress string) error {
|
|
// Guard against the empty input: url.PathEscape("") returns "" which
|
|
// would collapse the request URL onto the collection endpoint and
|
|
// silently delete nothing (or 405 depending on routing).
|
|
if clusterAddress == "" {
|
|
return errors.New("clusterAddress is required")
|
|
}
|
|
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/reverse-proxies/clusters/"+url.PathEscape(clusterAddress), nil, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp.Body != nil {
|
|
defer resp.Body.Close()
|
|
}
|
|
return nil
|
|
}
|