diff --git a/client/web/qnap.go b/client/web/qnap.go index 5ccd76798..07145a77c 100644 --- a/client/web/qnap.go +++ b/client/web/qnap.go @@ -9,6 +9,7 @@ package web import ( "crypto/tls" "encoding/xml" + "errors" "fmt" "io" "log" @@ -18,21 +19,17 @@ import ( // authorizeQNAP authenticates the logged-in QNAP user and verifies that they // are authorized to use the web client. -// It reports true if the request is authorized to continue, and false otherwise. -// authorizeQNAP manages writing out any relevant authorization errors to the -// ResponseWriter itself. -func authorizeQNAP(w http.ResponseWriter, r *http.Request) (ok bool) { +// If the user is not authorized to use the client, an error is returned. +func authorizeQNAP(r *http.Request) (ar authResponse, err error) { _, resp, err := qnapAuthn(r) if err != nil { - http.Error(w, err.Error(), http.StatusUnauthorized) - return false + return ar, err } if resp.IsAdmin == 0 { - http.Error(w, "user is not an admin", http.StatusForbidden) - return false + return ar, errors.New("user is not an admin") } - return true + return authResponse{OK: true}, nil } type qnapAuthResponse struct { diff --git a/client/web/src/components/app.tsx b/client/web/src/components/app.tsx index 8b10ae475..edbd885aa 100644 --- a/client/web/src/components/app.tsx +++ b/client/web/src/components/app.tsx @@ -3,17 +3,36 @@ import React from "react" import LegacyClientView from "src/components/views/legacy-client-view" import LoginClientView from "src/components/views/login-client-view" import ReadonlyClientView from "src/components/views/readonly-client-view" -import useAuth from "src/hooks/auth" +import useAuth, { AuthResponse } from "src/hooks/auth" import useNodeData from "src/hooks/node-data" import ManagementClientView from "./views/management-client-view" export default function App() { - const { data, refreshData, updateNode } = useNodeData() const { data: auth, loading: loadingAuth, waitOnAuth } = useAuth() return (
- {!data || loadingAuth ? ( + {loadingAuth ? ( +
Loading...
// TODO(sonia): add a loading view + ) : ( + + )} +
+ ) +} + +function WebClient({ + auth, + waitOnAuth, +}: { + auth?: AuthResponse + waitOnAuth: () => Promise +}) { + const { data, refreshData, updateNode } = useNodeData() + + return ( + <> + {!data ? (
Loading...
// TODO(sonia): add a loading view ) : data?.Status === "NeedsLogin" || data?.Status === "NoState" ? ( // Client not on a tailnet, render login. @@ -35,8 +54,8 @@ export default function App() { updateNode={updateNode} /> )} - {data && !loadingAuth &&