From 7aea219a0fa652322d74a29894afc0433ff27553 Mon Sep 17 00:00:00 2001 From: Sonia Appasamy Date: Tue, 29 Aug 2023 13:20:25 -0400 Subject: [PATCH] client/web: pull SynoToken logic into apiFetch Updates tailscale/corp#13775 --- client/web/src/api.ts | 24 ++++++++++++---- client/web/src/hooks/node-data.ts | 47 +++++++++++-------------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/client/web/src/api.ts b/client/web/src/api.ts index 3009a1716..2d36186b3 100644 --- a/client/web/src/api.ts +++ b/client/web/src/api.ts @@ -1,12 +1,26 @@ let csrfToken: string -// apiFetch wraps the standard JS fetch function -// with csrf header management. +// apiFetch wraps the standard JS fetch function with csrf header +// management and param additions specific to the web client. +// +// apiFetch adds the `api` prefix to the request URL, +// so endpoint should be provided without the `api` prefix +// (i.e. provide `/data` rather than `api/data`). export function apiFetch( - input: RequestInfo | URL, - init?: RequestInit | undefined + endpoint: string, + init?: RequestInit | undefined, + addURLParams?: Record ): Promise { - return fetch(input, { + const urlParams = new URLSearchParams(window.location.search) + const nextParams = new URLSearchParams(addURLParams) + const token = urlParams.get("SynoToken") + if (token) { + nextParams.set("SynoToken", token) + } + const search = nextParams.toString() + const url = `api${endpoint}${search ? `?${search}` : ""}` + + return fetch(url, { ...init, headers: withCsrfToken(init?.headers), }).then((r) => { diff --git a/client/web/src/hooks/node-data.ts b/client/web/src/hooks/node-data.ts index 99c28421a..b7d4f6486 100644 --- a/client/web/src/hooks/node-data.ts +++ b/client/web/src/hooks/node-data.ts @@ -35,21 +35,14 @@ export default function useNodeData() { const [data, setData] = useState() const [isPosting, setIsPosting] = useState(false) - const fetchNodeData = useCallback(() => { - const urlParams = new URLSearchParams(window.location.search) - const nextParams = new URLSearchParams() - const token = urlParams.get("SynoToken") - if (token) { - nextParams.set("SynoToken", token) - } - const search = nextParams.toString() - const url = `api/data${search ? `?${search}` : ""}` - - apiFetch(url) - .then((r) => r.json()) - .then((d) => setData(d)) - .catch((error) => console.error(error)) - }, [setData]) + const fetchNodeData = useCallback( + () => + apiFetch("/data") + .then((r) => r.json()) + .then((d) => setData(d)) + .catch((error) => console.error(error)), + [setData] + ) const updateNode = useCallback( (update: NodeUpdate) => { @@ -77,17 +70,7 @@ export default function useNodeData() { : data.AdvertiseExitNode, } - const urlParams = new URLSearchParams(window.location.search) - const nextParams = new URLSearchParams({ up: "true" }) - const token = urlParams.get("SynoToken") - if (token) { - nextParams.set("SynoToken", token) - } - const search = nextParams.toString() - const url = `api/data${search ? `?${search}` : ""}` - var body, contentType: string - if (data.IsUnraid) { const params = new URLSearchParams() params.append("csrf_token", data.UnraidToken) @@ -99,11 +82,15 @@ export default function useNodeData() { contentType = "application/json" } - apiFetch(url, { - method: "POST", - headers: { Accept: "application/json", "Content-Type": contentType }, - body: body, - }) + apiFetch( + "/data", + { + method: "POST", + headers: { Accept: "application/json", "Content-Type": contentType }, + body: body, + }, + { up: "true" } + ) .then((r) => r.json()) .then((r) => { setIsPosting(false)