From 00d641d9fc69557fdac6500eb889088520010705 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 11 Apr 2021 16:10:31 -0700 Subject: [PATCH] ipn/localapi: move EditPrefs to localapi Follow-up/revision to recent 53cfff109b01baa3d219697a1a9e2ea16c4b0d3d which added EditPrefs. Signed-off-by: Brad Fitzpatrick --- client/tailscale/tailscale.go | 19 ++++++++++++++++++- cmd/tailscale/cli/down.go | 28 ++-------------------------- ipn/backend.go | 2 -- ipn/fake_test.go | 7 ------- ipn/ipnlocal/local.go | 5 +++-- ipn/localapi/localapi.go | 19 ++++++++++++++++++- ipn/message.go | 8 -------- 7 files changed, 41 insertions(+), 47 deletions(-) diff --git a/client/tailscale/tailscale.go b/client/tailscale/tailscale.go index 2a3e0ba74..fb191141a 100644 --- a/client/tailscale/tailscale.go +++ b/client/tailscale/tailscale.go @@ -6,6 +6,7 @@ package tailscale import ( + "bytes" "context" "encoding/json" "errors" @@ -208,7 +209,23 @@ func GetPrefs(ctx context.Context) (*ipn.Prefs, error) { } var p ipn.Prefs if err := json.Unmarshal(body, &p); err != nil { - return nil, fmt.Errorf("invalid JSON from check-ip-forwarding: %w", err) + return nil, fmt.Errorf("invalid prefs JSON: %w", err) + } + return &p, nil +} + +func EditPrefs(ctx context.Context, mp *ipn.MaskedPrefs) (*ipn.Prefs, error) { + mpj, err := json.Marshal(mp) + if err != nil { + return nil, err + } + body, err := send(ctx, "POST", "/localapi/v0/prefs", http.StatusOK, bytes.NewReader(mpj)) + if err != nil { + return nil, err + } + var p ipn.Prefs + if err := json.Unmarshal(body, &p); err != nil { + return nil, fmt.Errorf("invalid prefs JSON: %w", err) } return &p, nil } diff --git a/cmd/tailscale/cli/down.go b/cmd/tailscale/cli/down.go index 0bbdad2be..c0a9034fe 100644 --- a/cmd/tailscale/cli/down.go +++ b/cmd/tailscale/cli/down.go @@ -9,7 +9,6 @@ "fmt" "log" "os" - "time" "github.com/peterbourgon/ff/v2/ffcli" "tailscale.com/client/tailscale" @@ -37,34 +36,11 @@ func runDown(ctx context.Context, args []string) error { fmt.Fprintf(os.Stderr, "Tailscale was already stopped.\n") return nil } - - c, bc, ctx, cancel := connect(ctx) - defer cancel() - - timer := time.AfterFunc(5*time.Second, func() { - log.Fatalf("timeout running stop") - }) - defer timer.Stop() - - bc.SetNotifyCallback(func(n ipn.Notify) { - if n.ErrMessage != nil { - log.Fatal(*n.ErrMessage) - } - if n.State != nil { - if *n.State == ipn.Stopped { - cancel() - } - return - } - }) - - bc.EditPrefs(&ipn.MaskedPrefs{ + _, err = tailscale.EditPrefs(ctx, &ipn.MaskedPrefs{ Prefs: ipn.Prefs{ WantRunning: false, }, WantRunningSet: true, }) - pump(ctx, bc, c) - - return nil + return err } diff --git a/ipn/backend.go b/ipn/backend.go index 64dd7ccd8..8b07d5953 100644 --- a/ipn/backend.go +++ b/ipn/backend.go @@ -158,8 +158,6 @@ type Backend interface { // WantRunning. This may cause the wireguard engine to // reconfigure or stop. SetPrefs(*Prefs) - // EditPrefs is like SetPrefs but only sets the specified fields. - EditPrefs(*MaskedPrefs) // RequestEngineStatus polls for an update from the wireguard // engine. Only needed if you want to display byte // counts. Connection events are emitted automatically without diff --git a/ipn/fake_test.go b/ipn/fake_test.go index c1e0b50da..cacb13caa 100644 --- a/ipn/fake_test.go +++ b/ipn/fake_test.go @@ -96,13 +96,6 @@ func (b *FakeBackend) SetPrefs(new *Prefs) { } } -func (b *FakeBackend) EditPrefs(mp *MaskedPrefs) { - // This fake implementation only cares about this one pref. - if mp.WantRunningSet { - b.SetPrefs(&mp.Prefs) - } -} - func (b *FakeBackend) RequestEngineStatus() { if b.notify != nil { b.notify(Notify{Engine: &EngineStatus{}}) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 55d4f0baa..817bf04be 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -1302,17 +1302,18 @@ func (b *LocalBackend) SetCurrentUserID(uid string) { b.mu.Unlock() } -func (b *LocalBackend) EditPrefs(mp *ipn.MaskedPrefs) { +func (b *LocalBackend) EditPrefs(mp *ipn.MaskedPrefs) (*ipn.Prefs, error) { b.mu.Lock() p0 := b.prefs.Clone() p1 := b.prefs.Clone() p1.ApplyEdits(mp) if p1.Equals(p0) { b.mu.Unlock() - return + return p1, nil } b.logf("EditPrefs: %v", mp.Pretty()) b.setPrefsLockedOnEntry("EditPrefs", p1) + return p1, nil } // SetPrefs saves new user preferences and propagates them throughout diff --git a/ipn/localapi/localapi.go b/ipn/localapi/localapi.go index bbdf28351..0e76e4504 100644 --- a/ipn/localapi/localapi.go +++ b/ipn/localapi/localapi.go @@ -23,6 +23,7 @@ "time" "inet.af/netaddr" + "tailscale.com/ipn" "tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnstate" "tailscale.com/tailcfg" @@ -224,10 +225,26 @@ func (h *Handler) servePrefs(w http.ResponseWriter, r *http.Request) { http.Error(w, "prefs access denied", http.StatusForbidden) return } + var prefs *ipn.Prefs + if r.Method == "POST" { + mp := new(ipn.MaskedPrefs) + if err := json.NewDecoder(r.Body).Decode(mp); err != nil { + http.Error(w, err.Error(), 400) + return + } + var err error + prefs, err = h.b.EditPrefs(mp) + if err != nil { + http.Error(w, err.Error(), 400) + return + } + } else { + prefs = h.b.Prefs() + } w.Header().Set("Content-Type", "application/json") e := json.NewEncoder(w) e.SetIndent("", "\t") - e.Encode(h.b.Prefs()) + e.Encode(prefs) } func (h *Handler) serveFiles(w http.ResponseWriter, r *http.Request) { diff --git a/ipn/message.go b/ipn/message.go index 8628b6f84..5db11d8cd 100644 --- a/ipn/message.go +++ b/ipn/message.go @@ -80,7 +80,6 @@ type Command struct { Login *tailcfg.Oauth2Token Logout *NoArgs SetPrefs *SetPrefsArgs - EditPrefs *MaskedPrefs RequestEngineStatus *NoArgs RequestStatus *NoArgs FakeExpireAfter *FakeExpireAfterArgs @@ -204,9 +203,6 @@ func (bs *BackendServer) GotCommand(ctx context.Context, cmd *Command) error { } else if c := cmd.SetPrefs; c != nil { bs.b.SetPrefs(c.New) return nil - } else if c := cmd.EditPrefs; c != nil { - bs.b.EditPrefs(c) - return nil } else if c := cmd.FakeExpireAfter; c != nil { bs.b.FakeExpireAfter(c.Duration) return nil @@ -307,10 +303,6 @@ func (bc *BackendClient) SetPrefs(new *Prefs) { bc.send(Command{SetPrefs: &SetPrefsArgs{New: new}}) } -func (bc *BackendClient) EditPrefs(mp *MaskedPrefs) { - bc.send(Command{EditPrefs: mp}) -} - func (bc *BackendClient) RequestEngineStatus() { bc.send(Command{RequestEngineStatus: &NoArgs{}}) }