From 4828e4c2db184d9ea48dd77aea2b33ca2c699761 Mon Sep 17 00:00:00 2001 From: Sonia Appasamy Date: Fri, 25 Aug 2023 11:27:22 -0400 Subject: [PATCH] client/web: move api handler into web.go Also uses `http.HandlerFunc` to pass the handler into `csrfProtect` so we can get rid of the extraneous `api` struct. Updates tailscale/corp#13775 Signed-off-by: Sonia Appasamy --- client/web/api.go | 37 ------------------------------------- client/web/web.go | 24 +++++++++++++++++++++++- 2 files changed, 23 insertions(+), 38 deletions(-) delete mode 100644 client/web/api.go diff --git a/client/web/api.go b/client/web/api.go deleted file mode 100644 index 1ee37980e..000000000 --- a/client/web/api.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Tailscale Inc & AUTHORS -// SPDX-License-Identifier: BSD-3-Clause - -package web - -import ( - "net/http" - "strings" - - "github.com/gorilla/csrf" - "tailscale.com/util/httpm" -) - -type api struct { - s *Server -} - -// ServeHTTP serves requests for the web client api. -// It should only be called by Server.ServeHTTP, via Server.apiHandler, -// which protects the handler using gorilla csrf. -func (a *api) ServeHTTP(w http.ResponseWriter, r *http.Request) { - w.Header().Set("X-CSRF-Token", csrf.Token(r)) - path := strings.TrimPrefix(r.URL.Path, "/api") - switch path { - case "/data": - switch r.Method { - case httpm.GET: - a.s.serveGetNodeDataJSON(w, r) - case httpm.POST: - a.s.servePostNodeUpdate(w, r) - default: - http.Error(w, "method not allowed", http.StatusMethodNotAllowed) - } - return - } - http.Error(w, "invalid endpoint", http.StatusNotFound) -} diff --git a/client/web/web.go b/client/web/web.go index 816890e2f..f18e83deb 100644 --- a/client/web/web.go +++ b/client/web/web.go @@ -30,6 +30,7 @@ import ( "tailscale.com/licenses" "tailscale.com/net/netutil" "tailscale.com/tailcfg" + "tailscale.com/util/httpm" "tailscale.com/version/distro" ) @@ -109,7 +110,7 @@ func NewServer(ctx context.Context, opts ServerOpts) (s *Server, cleanup func()) // The client is secured by limiting the interface it listens on, // or by authenticating requests before they reach the web client. csrfProtect := csrf.Protect(s.csrfKey(), csrf.Secure(false)) - s.apiHandler = csrfProtect(&api{s: s}) + s.apiHandler = csrfProtect(http.HandlerFunc(s.serveAPI)) } var wg sync.WaitGroup @@ -239,6 +240,27 @@ func (s *Server) serve(w http.ResponseWriter, r *http.Request) { } } +// serveAPI serves requests for the web client api. +// It should only be called by Server.ServeHTTP, via Server.apiHandler, +// which protects the handler using gorilla csrf. +func (s *Server) serveAPI(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-CSRF-Token", csrf.Token(r)) + path := strings.TrimPrefix(r.URL.Path, "/api") + switch path { + case "/data": + switch r.Method { + case httpm.GET: + s.serveGetNodeDataJSON(w, r) + case httpm.POST: + s.servePostNodeUpdate(w, r) + default: + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + } + return + } + http.Error(w, "invalid endpoint", http.StatusNotFound) +} + type nodeData struct { Profile tailcfg.UserProfile Status string