mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-25 04:37:42 +00:00
client/web: add localapi proxy
Adds proxy to the localapi from /api/local/ web client endpoint. The localapi proxy is restricted to an allowlist of those actually used by the web client frontend. Updates tailscale/corp#13775 Signed-off-by: Sonia Appasamy <sonia@tailscale.com>
This commit is contained in:

committed by
Sonia Appasamy

parent
c919ff540f
commit
da6eb076aa
@@ -5,7 +5,7 @@ import useNodeData from "src/hooks/node-data"
|
||||
export default function App() {
|
||||
// TODO(sonia): use isPosting value from useNodeData
|
||||
// to fill loading states.
|
||||
const { data, updateNode } = useNodeData()
|
||||
const { data, refreshData, updateNode } = useNodeData()
|
||||
|
||||
return (
|
||||
<div className="py-14">
|
||||
@@ -15,7 +15,11 @@ export default function App() {
|
||||
) : (
|
||||
<>
|
||||
<main className="container max-w-lg mx-auto mb-8 py-6 px-8 bg-white rounded-md shadow-2xl">
|
||||
<Header data={data} updateNode={updateNode} />
|
||||
<Header
|
||||
data={data}
|
||||
refreshData={refreshData}
|
||||
updateNode={updateNode}
|
||||
/>
|
||||
<IP data={data} />
|
||||
<State data={data} updateNode={updateNode} />
|
||||
</main>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import cx from "classnames"
|
||||
import React from "react"
|
||||
import { apiFetch } from "src/api"
|
||||
import { NodeData, NodeUpdate } from "src/hooks/node-data"
|
||||
|
||||
// TODO(tailscale/corp#13775): legacy.tsx contains a set of components
|
||||
@@ -9,9 +10,11 @@ import { NodeData, NodeUpdate } from "src/hooks/node-data"
|
||||
|
||||
export function Header({
|
||||
data,
|
||||
refreshData,
|
||||
updateNode,
|
||||
}: {
|
||||
data: NodeData
|
||||
refreshData: () => void
|
||||
updateNode: (update: NodeUpdate) => void
|
||||
}) {
|
||||
return (
|
||||
@@ -89,7 +92,11 @@ export function Header({
|
||||
</button>{" "}
|
||||
|{" "}
|
||||
<button
|
||||
onClick={() => updateNode({ ForceLogout: true })}
|
||||
onClick={() =>
|
||||
apiFetch("/local/v0/logout", { method: "POST" })
|
||||
.then(refreshData)
|
||||
.catch((err) => alert("Logout failed: " + err.message))
|
||||
}
|
||||
className="hover:text-gray-700"
|
||||
>
|
||||
Logout
|
||||
|
@@ -35,7 +35,7 @@ export default function useNodeData() {
|
||||
const [data, setData] = useState<NodeData>()
|
||||
const [isPosting, setIsPosting] = useState<boolean>(false)
|
||||
|
||||
const fetchNodeData = useCallback(
|
||||
const refreshData = useCallback(
|
||||
() =>
|
||||
apiFetch("/data")
|
||||
.then((r) => r.json())
|
||||
@@ -102,7 +102,7 @@ export default function useNodeData() {
|
||||
if (url) {
|
||||
window.open(url, "_blank")
|
||||
}
|
||||
fetchNodeData()
|
||||
refreshData()
|
||||
})
|
||||
.catch((err) => alert("Failed operation: " + err.message))
|
||||
},
|
||||
@@ -112,11 +112,11 @@ export default function useNodeData() {
|
||||
useEffect(
|
||||
() => {
|
||||
// Initial data load.
|
||||
fetchNodeData()
|
||||
refreshData()
|
||||
|
||||
// Refresh on browser tab focus.
|
||||
const onVisibilityChange = () => {
|
||||
document.visibilityState === "visible" && fetchNodeData()
|
||||
document.visibilityState === "visible" && refreshData()
|
||||
}
|
||||
window.addEventListener("visibilitychange", onVisibilityChange)
|
||||
return () => {
|
||||
@@ -128,5 +128,5 @@ export default function useNodeData() {
|
||||
[]
|
||||
)
|
||||
|
||||
return { data, updateNode, isPosting }
|
||||
return { data, refreshData, updateNode, isPosting }
|
||||
}
|
||||
|
Reference in New Issue
Block a user