summaryrefslogtreecommitdiffhomepage
path: root/client/web/src/hooks/auth.ts
blob: 46b3dcdded25bea7c651c51d72cb34c943f5de25 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause

import { useCallback, useEffect, useState } from "react"
import { apiFetch, setSynoToken } from "src/api"

export enum AuthType {
  synology = "synology",
  tailscale = "tailscale",
}

export type AuthResponse = {
  authNeeded?: AuthType
  canManageNode: boolean
  serverMode: "login" | "readonly" | "manage"
  viewerIdentity?: {
    loginName: string
    nodeName: string
    nodeIP: string
    profilePicUrl?: string
  }
}

// useAuth reports and refreshes Tailscale auth status
// for the web client.
export default function useAuth() {
  const [data, setData] = useState<AuthResponse>()
  const [loading, setLoading] = useState<boolean>(true)
  const [ranSynoAuth, setRanSynoAuth] = useState<boolean>(false)

  const loadAuth = useCallback(() => {
    setLoading(true)
    return apiFetch<AuthResponse>("/auth", "GET")
      .then((d) => {
        setData(d)
        switch (d.authNeeded) {
          case AuthType.synology:
            fetch("/webman/login.cgi")
              .then((r) => r.json())
              .then((a) => {
                setSynoToken(a.SynoToken)
                setRanSynoAuth(true)
                setLoading(false)
              })
            break
          default:
            setLoading(false)
        }
        return d
      })
      .catch((error) => {
        setLoading(false)
        console.error(error)
      })
  }, [])

  const newSession = useCallback(() => {
    return apiFetch<{ authUrl?: string }>("/auth/session/new", "GET")
      .then((d) => {
        if (d.authUrl) {
          window.open(d.authUrl, "_blank")
          return apiFetch("/auth/session/wait", "GET")
        }
      })
      .then(() => {
        loadAuth()
      })
      .catch((error) => {
        console.error(error)
      })
  }, [loadAuth])

  useEffect(() => {
    loadAuth().then((d) => {
      if (
        !d?.canManageNode &&
        new URLSearchParams(window.location.search).get("check") === "now"
      ) {
        newSession()
      }
    })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  useEffect(() => {
    loadAuth() // Refresh auth state after syno auth runs
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [ranSynoAuth])

  return {
    data,
    loading,
    newSession,
  }
}