mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 21:27:31 +00:00
tailcfg,ipn/localapi,client/tailscale: add QueryFeature endpoint
Updates tailscale/corp#10577 Signed-off-by: Sonia Appasamy <sonia@tailscale.com>
This commit is contained in:

committed by
Sonia Appasamy

parent
ab7749aed7
commit
301e59f398
@@ -113,6 +113,7 @@ var handler = map[string]localAPIHandler{
|
||||
"upload-client-metrics": (*Handler).serveUploadClientMetrics,
|
||||
"watch-ipn-bus": (*Handler).serveWatchIPNBus,
|
||||
"whois": (*Handler).serveWhoIs,
|
||||
"query-feature": (*Handler).serveQueryFeature,
|
||||
}
|
||||
|
||||
func randHex(n int) string {
|
||||
@@ -1932,6 +1933,66 @@ func (h *Handler) serveProfiles(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// serveQueryFeature makes a request to the "/machine/feature/query"
|
||||
// Noise endpoint to get instructions on how to enable a feature, such as
|
||||
// Funnel, for the node's tailnet.
|
||||
//
|
||||
// This request itself does not directly enable the feature on behalf of
|
||||
// the node, but rather returns information that can be presented to the
|
||||
// acting user about where/how to enable the feature. If relevant, this
|
||||
// includes a control URL the user can visit to explicitly consent to
|
||||
// using the feature.
|
||||
//
|
||||
// See tailcfg.QueryFeatureResponse for full response structure.
|
||||
func (h *Handler) serveQueryFeature(w http.ResponseWriter, r *http.Request) {
|
||||
feature := r.FormValue("feature")
|
||||
switch {
|
||||
case !h.PermitRead:
|
||||
http.Error(w, "access denied", http.StatusForbidden)
|
||||
return
|
||||
case r.Method != httpm.POST:
|
||||
http.Error(w, "use POST", http.StatusMethodNotAllowed)
|
||||
return
|
||||
case feature == "":
|
||||
http.Error(w, "missing feature", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
nm := h.b.NetMap()
|
||||
if nm == nil {
|
||||
http.Error(w, "no netmap", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
b, err := json.Marshal(&tailcfg.QueryFeatureRequest{
|
||||
NodeKey: nm.NodeKey,
|
||||
Feature: feature,
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(r.Context(),
|
||||
"POST", "https://unused/machine/feature/query", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := h.b.DoNoiseRequest(req)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
if _, err := io.Copy(w, resp.Body); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func defBool(a string, def bool) bool {
|
||||
if a == "" {
|
||||
return def
|
||||
|
Reference in New Issue
Block a user