summaryrefslogtreecommitdiffhomepage
path: root/ipn/localapi
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@tailscale.com>2025-01-21 12:34:15 -0800
committerBrad Fitzpatrick <bradfitz@tailscale.com>2025-01-21 14:34:19 -0800
commit3116dbefacba11586b99acd1dc0891adf40d76ca (patch)
treee04f0f450d3b8cd24e440016211f1b8174ce879a /ipn/localapi
parentb50d32059f1b33311dbba96a57c82d33a28f0e1f (diff)
downloadtailscale-bradfitz/syspolicy_key.tar.xz
tailscale-bradfitz/syspolicy_key.zip
util/syspolicy/policyclient: add Client interface to the syspolicy universebradfitz/syspolicy_key
This removes the dependency on syspolicy/... from LocalBackend and tailscaled when ts_omit_syspolicy is true. Updates #12614 Change-Id: I309deb0f50f8e7d6bc11454e4210bb3b358abc77 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Diffstat (limited to 'ipn/localapi')
-rw-r--r--ipn/localapi/localapi.go50
-rw-r--r--ipn/localapi/syspolicy_api.go67
2 files changed, 67 insertions, 50 deletions
diff --git a/ipn/localapi/localapi.go b/ipn/localapi/localapi.go
index 157f72a65..072ad6b4a 100644
--- a/ipn/localapi/localapi.go
+++ b/ipn/localapi/localapi.go
@@ -62,8 +62,6 @@ import (
"tailscale.com/util/osdiag"
"tailscale.com/util/progresstracking"
"tailscale.com/util/rands"
- "tailscale.com/util/syspolicy/rsop"
- "tailscale.com/util/syspolicy/setting"
"tailscale.com/version"
"tailscale.com/wgengine/magicsock"
)
@@ -78,7 +76,6 @@ var handler = map[string]localAPIHandler{
"cert/": (*Handler).serveCert,
"file-put/": (*Handler).serveFilePut,
"files/": (*Handler).serveFiles,
- "policy/": (*Handler).servePolicy,
"profiles/": (*Handler).serveProfiles,
// The other /localapi/v0/NAME handlers are exact matches and contain only NAME
@@ -1389,53 +1386,6 @@ func (h *Handler) servePrefs(w http.ResponseWriter, r *http.Request) {
e.Encode(prefs)
}
-func (h *Handler) servePolicy(w http.ResponseWriter, r *http.Request) {
- if !h.PermitRead {
- http.Error(w, "policy access denied", http.StatusForbidden)
- return
- }
-
- suffix, ok := strings.CutPrefix(r.URL.EscapedPath(), "/localapi/v0/policy/")
- if !ok {
- http.Error(w, "misconfigured", http.StatusInternalServerError)
- return
- }
-
- var scope setting.PolicyScope
- if suffix == "" {
- scope = setting.DefaultScope()
- } else if err := scope.UnmarshalText([]byte(suffix)); err != nil {
- http.Error(w, fmt.Sprintf("%q is not a valid scope", suffix), http.StatusBadRequest)
- return
- }
-
- policy, err := rsop.PolicyFor(scope)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- var effectivePolicy *setting.Snapshot
- switch r.Method {
- case "GET":
- effectivePolicy = policy.Get()
- case "POST":
- effectivePolicy, err = policy.Reload()
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- default:
- http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
- return
- }
-
- w.Header().Set("Content-Type", "application/json")
- e := json.NewEncoder(w)
- e.SetIndent("", "\t")
- e.Encode(effectivePolicy)
-}
-
type resJSON struct {
Error string `json:",omitempty"`
}
diff --git a/ipn/localapi/syspolicy_api.go b/ipn/localapi/syspolicy_api.go
new file mode 100644
index 000000000..366045de3
--- /dev/null
+++ b/ipn/localapi/syspolicy_api.go
@@ -0,0 +1,67 @@
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build !ts_omit_syspolicy
+
+package localapi
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "tailscale.com/util/syspolicy/rsop"
+ "tailscale.com/util/syspolicy/setting"
+)
+
+func init() {
+ handler["policy/"] = (*Handler).servePolicy
+}
+
+func (h *Handler) servePolicy(w http.ResponseWriter, r *http.Request) {
+ if !h.PermitRead {
+ http.Error(w, "policy access denied", http.StatusForbidden)
+ return
+ }
+
+ suffix, ok := strings.CutPrefix(r.URL.EscapedPath(), "/localapi/v0/policy/")
+ if !ok {
+ http.Error(w, "misconfigured", http.StatusInternalServerError)
+ return
+ }
+
+ var scope setting.PolicyScope
+ if suffix == "" {
+ scope = setting.DefaultScope()
+ } else if err := scope.UnmarshalText([]byte(suffix)); err != nil {
+ http.Error(w, fmt.Sprintf("%q is not a valid scope", suffix), http.StatusBadRequest)
+ return
+ }
+
+ policy, err := rsop.PolicyFor(scope)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ var effectivePolicy *setting.Snapshot
+ switch r.Method {
+ case "GET":
+ effectivePolicy = policy.Get()
+ case "POST":
+ effectivePolicy, err = policy.Reload()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ default:
+ http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ e := json.NewEncoder(w)
+ e.SetIndent("", "\t")
+ e.Encode(effectivePolicy)
+}