client/web: add csrf protection to web client api

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>
This commit is contained in:
Sonia Appasamy
2023-08-16 18:52:31 -04:00
committed by Sonia Appasamy
parent 77ff705545
commit 077bbb8403
11 changed files with 245 additions and 47 deletions

View File

@@ -3,7 +3,9 @@ import { Footer, Header, IP, State } from "src/components/legacy"
import useNodeData from "src/hooks/node-data"
export default function App() {
const data = useNodeData()
// TODO(sonia): use isPosting value from useNodeData
// to fill loading states.
const { data, updateNode } = useNodeData()
return (
<div className="py-14">
@@ -15,7 +17,7 @@ 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} />
<IP data={data} />
<State data={data} />
<State data={data} updateNode={updateNode} />
</main>
<Footer data={data} />
</>

View File

@@ -1,5 +1,6 @@
import cx from "classnames"
import React from "react"
import { NodeData } from "src/hooks/node-data"
import { NodeData, NodeUpdate } from "src/hooks/node-data"
// TODO(tailscale/corp#13775): legacy.tsx contains a set of components
// that (crudely) implement the pre-2023 web client. These are implemented
@@ -162,9 +163,13 @@ export function IP(props: { data: NodeData }) {
)
}
export function State(props: { data: NodeData }) {
const { data } = props
export function State({
data,
updateNode,
}: {
data: NodeData
updateNode: (update: NodeUpdate) => void
}) {
switch (data.Status) {
case "NeedsLogin":
case "NoState":
@@ -232,25 +237,20 @@ export function State(props: { data: NodeData }) {
device name or IP address above.
</p>
</div>
<div className="mb-4">
<a href="#" className="mb-4 js-advertiseExitNode">
{data.AdvertiseExitNode ? (
<button
className="button button-red button-medium"
id="enabled"
>
Stop advertising Exit Node
</button>
) : (
<button
className="button button-blue button-medium"
id="enabled"
>
Advertise as Exit Node
</button>
)}
</a>
</div>
<button
className={cx("button button-medium mb-4", {
"button-red": data.AdvertiseExitNode,
"button-blue": !data.AdvertiseExitNode,
})}
id="enabled"
onClick={() =>
updateNode({ AdvertiseExitNode: !data.AdvertiseExitNode })
}
>
{data.AdvertiseExitNode
? "Stop advertising Exit Node"
: "Advertise as Exit Node"}
</button>
</>
)
}