Adds csrf protection and hooks up an initial POST request from the React web client. Updates tailscale/corp#13775 Signed-off-by: Sonia Appasamy <sonia@tailscale.com>main
parent
77ff705545
commit
077bbb8403
@ -0,0 +1,41 @@ |
||||
// 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)) |
||||
user, err := authorize(w, r) |
||||
if err != nil { |
||||
return |
||||
} |
||||
path := strings.TrimPrefix(r.URL.Path, "/api") |
||||
switch path { |
||||
case "/data": |
||||
switch r.Method { |
||||
case httpm.GET: |
||||
a.s.serveGetNodeDataJSON(w, r, user) |
||||
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) |
||||
} |
||||
@ -0,0 +1,32 @@ |
||||
let csrfToken: string |
||||
|
||||
// apiFetch wraps the standard JS fetch function
|
||||
// with csrf header management.
|
||||
export function apiFetch( |
||||
input: RequestInfo | URL, |
||||
init?: RequestInit | undefined |
||||
): Promise<Response> { |
||||
return fetch(input, { |
||||
...init, |
||||
headers: withCsrfToken(init?.headers), |
||||
}).then((r) => { |
||||
updateCsrfToken(r) |
||||
if (!r.ok) { |
||||
return r.text().then((err) => { |
||||
throw new Error(err) |
||||
}) |
||||
} |
||||
return r |
||||
}) |
||||
} |
||||
|
||||
function withCsrfToken(h?: HeadersInit): HeadersInit { |
||||
return { ...h, "X-CSRF-Token": csrfToken } |
||||
} |
||||
|
||||
function updateCsrfToken(r: Response) { |
||||
const tok = r.headers.get("X-CSRF-Token") |
||||
if (tok) { |
||||
csrfToken = tok |
||||
} |
||||
} |
||||
Loading…
Reference in new issue