mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-20 05:31:40 +00:00
client/web: check content-type on PATCH requests
Updates #10261 Fixes tailscale/corp#16267 Signed-off-by: Will Norris <will@tailscale.com>
This commit is contained in:
parent
c615fe2296
commit
69b56462fc
client/web
@ -965,6 +965,13 @@ func (s *Server) proxyRequestToLocalAPI(w http.ResponseWriter, r *http.Request)
|
|||||||
http.Error(w, "invalid request", http.StatusBadRequest)
|
http.Error(w, "invalid request", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if r.Method == httpm.PATCH {
|
||||||
|
// enforce that PATCH requests are always application/json
|
||||||
|
if ct := r.Header.Get("Content-Type"); ct != "application/json" {
|
||||||
|
http.Error(w, "invalid request", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
if !slices.Contains(localapiAllowlist, path) {
|
if !slices.Contains(localapiAllowlist, path) {
|
||||||
http.Error(w, fmt.Sprintf("%s not allowed from localapi proxy", path), http.StatusForbidden)
|
http.Error(w, fmt.Sprintf("%s not allowed from localapi proxy", path), http.StatusForbidden)
|
||||||
return
|
return
|
||||||
|
@ -100,29 +100,44 @@ func TestServeAPI(t *testing.T) {
|
|||||||
s := &Server{lc: &tailscale.LocalClient{Dial: lal.Dial}}
|
s := &Server{lc: &tailscale.LocalClient{Dial: lal.Dial}}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
reqPath string
|
reqMethod string
|
||||||
wantResp string
|
reqPath string
|
||||||
wantStatus int
|
reqContentType string
|
||||||
|
wantResp string
|
||||||
|
wantStatus int
|
||||||
}{{
|
}{{
|
||||||
name: "invalid_endpoint",
|
name: "invalid_endpoint",
|
||||||
|
reqMethod: httpm.POST,
|
||||||
reqPath: "/not-an-endpoint",
|
reqPath: "/not-an-endpoint",
|
||||||
wantResp: "invalid endpoint",
|
wantResp: "invalid endpoint",
|
||||||
wantStatus: http.StatusNotFound,
|
wantStatus: http.StatusNotFound,
|
||||||
}, {
|
}, {
|
||||||
name: "not_in_localapi_allowlist",
|
name: "not_in_localapi_allowlist",
|
||||||
|
reqMethod: httpm.POST,
|
||||||
reqPath: "/local/v0/not-allowlisted",
|
reqPath: "/local/v0/not-allowlisted",
|
||||||
wantResp: "/v0/not-allowlisted not allowed from localapi proxy",
|
wantResp: "/v0/not-allowlisted not allowed from localapi proxy",
|
||||||
wantStatus: http.StatusForbidden,
|
wantStatus: http.StatusForbidden,
|
||||||
}, {
|
}, {
|
||||||
name: "in_localapi_allowlist",
|
name: "in_localapi_allowlist",
|
||||||
|
reqMethod: httpm.POST,
|
||||||
reqPath: "/local/v0/logout",
|
reqPath: "/local/v0/logout",
|
||||||
wantResp: "success", // Successfully allowed to hit localapi.
|
wantResp: "success", // Successfully allowed to hit localapi.
|
||||||
wantStatus: http.StatusOK,
|
wantStatus: http.StatusOK,
|
||||||
|
}, {
|
||||||
|
name: "patch_bad_contenttype",
|
||||||
|
reqMethod: httpm.PATCH,
|
||||||
|
reqPath: "/local/v0/prefs",
|
||||||
|
reqContentType: "multipart/form-data",
|
||||||
|
wantResp: "invalid request",
|
||||||
|
wantStatus: http.StatusBadRequest,
|
||||||
}}
|
}}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := httptest.NewRequest("POST", "/api"+tt.reqPath, nil)
|
r := httptest.NewRequest(tt.reqMethod, "/api"+tt.reqPath, nil)
|
||||||
|
if tt.reqContentType != "" {
|
||||||
|
r.Header.Add("Content-Type", tt.reqContentType)
|
||||||
|
}
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
s.serveAPI(w, r)
|
s.serveAPI(w, r)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user