diff options
| author | kari-ts <kari@tailscale.com> | 2025-03-19 11:28:04 -0700 |
|---|---|---|
| committer | kari-ts <kari@tailscale.com> | 2025-04-04 14:24:56 -0700 |
| commit | 6d5c7b11913e09b061e863411ad488dc44a13870 (patch) | |
| tree | 9e1789b5080ae4a92523611e49920dcb1102604b /client/web/web.go | |
| parent | ca50599c95e0a4cb7b4aab179e866e202f10c0c4 (diff) | |
| parent | 3a2c92f08eac8cd8f50356ff288e40a28636ee42 (diff) | |
| download | tailscale-kari/taildropsaf.tar.xz tailscale-kari/taildropsaf.zip | |
TO DO:kari/taildropsaf
-check if Context.getExternalFilesDirs works as is for private dir
Diffstat (limited to 'client/web/web.go')
| -rw-r--r-- | client/web/web.go | 56 |
1 files changed, 32 insertions, 24 deletions
diff --git a/client/web/web.go b/client/web/web.go index 6203b4c18..6eccdadcf 100644 --- a/client/web/web.go +++ b/client/web/web.go @@ -203,15 +203,25 @@ func NewServer(opts ServerOpts) (s *Server, err error) { } s.assetsHandler, s.assetsCleanup = assetsHandler(s.devMode) - var metric string // clientmetric to report on startup + var metric string + s.apiHandler, metric = s.modeAPIHandler(s.mode) + s.apiHandler = s.withCSRF(s.apiHandler) - // Create handler for "/api" requests with CSRF protection. - // We don't require secure cookies, since the web client is regularly used - // on network appliances that are served on local non-https URLs. - // The client is secured by limiting the interface it listens on, - // or by authenticating requests before they reach the web client. + // Don't block startup on reporting metric. + // Report in separate go routine with 5 second timeout. + go func() { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + s.lc.IncrementCounter(ctx, metric, 1) + }() + + return s, nil +} + +func (s *Server) withCSRF(h http.Handler) http.Handler { csrfProtect := csrf.Protect(s.csrfKey(), csrf.Secure(false)) + // ref https://github.com/tailscale/tailscale/pull/14822 // signal to the CSRF middleware that the request is being served over // plaintext HTTP to skip TLS-only header checks. withSetPlaintext := func(h http.Handler) http.Handler { @@ -221,27 +231,24 @@ func NewServer(opts ServerOpts) (s *Server, err error) { }) } - switch s.mode { + // NB: the order of the withSetPlaintext and csrfProtect calls is important + // to ensure that we signal to the CSRF middleware that the request is being + // served over plaintext HTTP and not over TLS as it presumes by default. + return withSetPlaintext(csrfProtect(h)) +} + +func (s *Server) modeAPIHandler(mode ServerMode) (http.Handler, string) { + switch mode { case LoginServerMode: - s.apiHandler = csrfProtect(withSetPlaintext(http.HandlerFunc(s.serveLoginAPI))) - metric = "web_login_client_initialization" + return http.HandlerFunc(s.serveLoginAPI), "web_login_client_initialization" case ReadOnlyServerMode: - s.apiHandler = csrfProtect(withSetPlaintext(http.HandlerFunc(s.serveLoginAPI))) - metric = "web_readonly_client_initialization" + return http.HandlerFunc(s.serveLoginAPI), "web_readonly_client_initialization" case ManageServerMode: - s.apiHandler = csrfProtect(withSetPlaintext(http.HandlerFunc(s.serveAPI))) - metric = "web_client_initialization" + return http.HandlerFunc(s.serveAPI), "web_client_initialization" + default: // invalid mode + log.Fatalf("invalid mode: %v", mode) } - - // Don't block startup on reporting metric. - // Report in separate go routine with 5 second timeout. - go func() { - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - s.lc.IncrementCounter(ctx, metric, 1) - }() - - return s, nil + return nil, "" } func (s *Server) Shutdown() { @@ -328,7 +335,8 @@ func (s *Server) requireTailscaleIP(w http.ResponseWriter, r *http.Request) (han ipv6ServiceHost = "[" + tsaddr.TailscaleServiceIPv6String + "]" ) // allow requests on quad-100 (or ipv6 equivalent) - if r.Host == ipv4ServiceHost || r.Host == ipv6ServiceHost { + host := strings.TrimSuffix(r.Host, ":80") + if host == ipv4ServiceHost || host == ipv6ServiceHost { return false } |
