tailcfg, localapi: plumb device token to server

Updates tailscale/corp#8940

Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
This commit is contained in:
David Crawshaw
2023-01-29 14:04:40 -08:00
committed by David Crawshaw
parent 38b32be926
commit 8cf2805cca
9 changed files with 130 additions and 27 deletions

View File

@@ -1811,6 +1811,21 @@ func (b *LocalBackend) readPoller() {
}
}
// ResendHostinfoIfNeeded is called to recompute the Hostinfo and send
// the new version to the control server.
func (b *LocalBackend) ResendHostinfoIfNeeded() {
hi := hostinfo.New()
b.mu.Lock()
if b.hostinfo != nil {
hi.Services = b.hostinfo.Services
}
b.hostinfo = hi
b.mu.Unlock()
b.doSetHostinfoFilterServices(hi)
}
// WatchNotifications subscribes to the ipn.Notify message bus notification
// messages.
//

View File

@@ -70,6 +70,7 @@ var handler = map[string]localAPIHandler{
"debug-packet-filter-rules": (*Handler).serveDebugPacketFilterRules,
"derpmap": (*Handler).serveDERPMap,
"dev-set-state-store": (*Handler).serveDevSetStateStore,
"set-push-device-token": (*Handler).serveSetPushDeviceToken,
"dial": (*Handler).serveDial,
"file-targets": (*Handler).serveFileTargets,
"goroutines": (*Handler).serveGoroutines,
@@ -1205,6 +1206,25 @@ func (h *Handler) serveDial(w http.ResponseWriter, r *http.Request) {
<-errc
}
func (h *Handler) serveSetPushDeviceToken(w http.ResponseWriter, r *http.Request) {
if !h.PermitWrite {
http.Error(w, "set push device token access denied", http.StatusForbidden)
return
}
if r.Method != "POST" {
http.Error(w, "unsupported method", http.StatusMethodNotAllowed)
return
}
var params apitype.SetPushDeviceTokenRequest
if err := json.NewDecoder(r.Body).Decode(&params); err != nil {
http.Error(w, "invalid JSON body", 400)
return
}
hostinfo.SetPushDeviceToken(params.PushDeviceToken)
h.b.ResendHostinfoIfNeeded()
w.WriteHeader(http.StatusOK)
}
func (h *Handler) serveUploadClientMetrics(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "unsupported method", http.StatusMethodNotAllowed)

View File

@@ -4,9 +4,16 @@
package localapi
import (
"bytes"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"testing"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/hostinfo"
"tailscale.com/ipn/ipnlocal"
)
func TestValidHost(t *testing.T) {
@@ -32,3 +39,43 @@ func TestValidHost(t *testing.T) {
})
}
}
func TestSetPushDeviceToken(t *testing.T) {
origValidLocalHost := validLocalHost
validLocalHost = true
defer func() {
validLocalHost = origValidLocalHost
}()
h := &Handler{
PermitWrite: true,
b: &ipnlocal.LocalBackend{},
}
s := httptest.NewServer(h)
defer s.Close()
c := s.Client()
want := "my-test-device-token"
body, err := json.Marshal(apitype.SetPushDeviceTokenRequest{PushDeviceToken: want})
if err != nil {
t.Fatal(err)
}
req, err := http.NewRequest("POST", s.URL+"/localapi/v0/set-push-device-token", bytes.NewReader(body))
if err != nil {
t.Fatal(err)
}
res, err := c.Do(req)
if err != nil {
t.Fatal(err)
}
body, err = io.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if res.StatusCode != 200 {
t.Errorf("res.StatusCode=%d, want 200. body: %s", res.StatusCode, body)
}
if got := hostinfo.New().PushDeviceToken; got != want {
t.Errorf("hostinfo.PushDeviceToken=%q, want %q", got, want)
}
}