web/client: update synology token from /api/auth call

When the /api/auth response indicates that synology auth is needed,
fetch the SynoToken and store it for future API calls.  This doesn't yet
update the server-side code to set the new SynoAuth field.

Updates tailscale/corp#14335

Signed-off-by: Will Norris <will@tailscale.com>
pull/10038/head
Will Norris 1 year ago committed by Will Norris
parent b1a0caf056
commit e5fbe57908

@ -1,4 +1,5 @@
let csrfToken: string let csrfToken: string
let synoToken: string | undefined // required for synology API requests
let unraidCsrfToken: string | undefined // required for unraid POST requests (#8062) let unraidCsrfToken: string | undefined // required for unraid POST requests (#8062)
// apiFetch wraps the standard JS fetch function with csrf header // apiFetch wraps the standard JS fetch function with csrf header
@ -15,9 +16,13 @@ export function apiFetch(
): Promise<Response> { ): Promise<Response> {
const urlParams = new URLSearchParams(window.location.search) const urlParams = new URLSearchParams(window.location.search)
const nextParams = new URLSearchParams(params) const nextParams = new URLSearchParams(params)
const token = urlParams.get("SynoToken") if (synoToken) {
if (token) { nextParams.set("SynoToken", synoToken)
nextParams.set("SynoToken", token) } else {
const token = urlParams.get("SynoToken")
if (token) {
nextParams.set("SynoToken", token)
}
} }
const search = nextParams.toString() const search = nextParams.toString()
const url = `api${endpoint}${search ? `?${search}` : ""}` const url = `api${endpoint}${search ? `?${search}` : ""}`
@ -62,6 +67,10 @@ function updateCsrfToken(r: Response) {
} }
} }
export function setSynoToken(token?: string) {
synoToken = token
}
export function setUnraidCsrfToken(token?: string) { export function setUnraidCsrfToken(token?: string) {
unraidCsrfToken = token unraidCsrfToken = token
} }

@ -1,9 +1,15 @@
import { useCallback, useEffect, useState } from "react" import { useCallback, useEffect, useState } from "react"
import { apiFetch } from "src/api" import { apiFetch, setSynoToken } from "src/api"
export enum AuthType {
synology = "synology",
tailscale = "tailscale",
}
export type AuthResponse = { export type AuthResponse = {
ok: boolean ok: boolean
authUrl?: string authUrl?: string
authNeeded?: AuthType
} }
// useAuth reports and refreshes Tailscale auth status // useAuth reports and refreshes Tailscale auth status
@ -18,6 +24,14 @@ export default function useAuth() {
return apiFetch(url, "GET") return apiFetch(url, "GET")
.then((r) => r.json()) .then((r) => r.json())
.then((d) => { .then((d) => {
if ((d as AuthResponse).authNeeded == AuthType.synology) {
fetch("/webman/login.cgi")
.then((r) => r.json())
.then((data) => {
setSynoToken(data.SynoToken)
})
}
setLoading(false) setLoading(false)
setData(d) setData(d)
}) })

@ -269,9 +269,17 @@ func (s *Server) serveLoginAPI(w http.ResponseWriter, r *http.Request) {
return return
} }
type authType string
var (
synoAuth authType = "synology" // user needs a SynoToken for subsequent API calls
tailscaleAuth authType = "tailscale" // user needs to complete Tailscale check mode
)
type authResponse struct { type authResponse struct {
OK bool `json:"ok"` // true when user has valid auth session OK bool `json:"ok"` // true when user has valid auth session
AuthURL string `json:"authUrl,omitempty"` // filled when user has control auth action to take AuthURL string `json:"authUrl,omitempty"` // filled when user has control auth action to take
AuthNeeded authType `json:"authNeeded,omitempty"` // filled when user needs to complete a specific type of auth
} }
func (s *Server) serveTailscaleAuth(w http.ResponseWriter, r *http.Request) { func (s *Server) serveTailscaleAuth(w http.ResponseWriter, r *http.Request) {

Loading…
Cancel
Save