Impede acesso ao portal para máquinas desativadas
This commit is contained in:
parent
0e97e4c0d6
commit
e5085962e9
5 changed files with 195 additions and 18 deletions
|
|
@ -7,6 +7,7 @@ import { appLocalDataDir, executableDir, join } from "@tauri-apps/api/path"
|
|||
import { ExternalLink, Eye, EyeOff, GalleryVerticalEnd, Loader2, RefreshCw } from "lucide-react"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./components/ui/tabs"
|
||||
import { cn } from "./lib/utils"
|
||||
import { DeactivationScreen } from "./components/DeactivationScreen"
|
||||
|
||||
type MachineOs = {
|
||||
name: string
|
||||
|
|
@ -137,14 +138,54 @@ function bytes(n?: number) {
|
|||
|
||||
function pct(p?: number) { return !p && p !== 0 ? "—" : `${p.toFixed(0)}%` }
|
||||
|
||||
type MachineStatePayload = {
|
||||
isActive?: boolean | null
|
||||
metadata?: Record<string, unknown> | null
|
||||
}
|
||||
|
||||
function extractActiveFromMetadata(metadata: unknown): boolean {
|
||||
if (!metadata || typeof metadata !== "object") return true
|
||||
const record = metadata as Record<string, unknown>
|
||||
const direct = record["isActive"]
|
||||
if (typeof direct === "boolean") return direct
|
||||
const state = record["state"]
|
||||
if (state && typeof state === "object") {
|
||||
const nested = state as Record<string, unknown>
|
||||
const active = nested["isActive"] ?? nested["active"] ?? nested["enabled"]
|
||||
if (typeof active === "boolean") return active
|
||||
}
|
||||
const flags = record["flags"]
|
||||
if (flags && typeof flags === "object") {
|
||||
const nested = flags as Record<string, unknown>
|
||||
const active = nested["isActive"] ?? nested["active"]
|
||||
if (typeof active === "boolean") return active
|
||||
}
|
||||
const status = record["status"]
|
||||
if (typeof status === "string") {
|
||||
const normalized = status.trim().toLowerCase()
|
||||
if (["deactivated", "desativada", "desativado", "inactive", "inativo", "disabled"].includes(normalized)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function resolveMachineActive(machine?: MachineStatePayload | null): boolean {
|
||||
if (!machine) return true
|
||||
if (typeof machine.isActive === "boolean") return machine.isActive
|
||||
return extractActiveFromMetadata(machine.metadata)
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [store, setStore] = useState<Store | null>(null)
|
||||
const [token, setToken] = useState<string | null>(null)
|
||||
const [config, setConfig] = useState<AgentConfig | null>(null)
|
||||
const [profile, setProfile] = useState<MachineProfile | null>(null)
|
||||
const [logoSrc, setLogoSrc] = useState<string>(() => `${appUrl}/logo-raven.png`)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [busy, setBusy] = useState(false)
|
||||
const [status, setStatus] = useState<string | null>(null)
|
||||
const [isMachineActive, setIsMachineActive] = useState(true)
|
||||
const [showSecret, setShowSecret] = useState(false)
|
||||
const [isLaunchingSystem, setIsLaunchingSystem] = useState(false)
|
||||
const [, setIsValidatingToken] = useState(false)
|
||||
|
|
@ -164,6 +205,7 @@ function App() {
|
|||
})
|
||||
const autoLaunchRef = useRef(false)
|
||||
const autoUpdateRef = useRef(false)
|
||||
const logoFallbackRef = useRef(false)
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
|
|
@ -214,6 +256,14 @@ function App() {
|
|||
} catch (err) {
|
||||
console.error("Falha ao iniciar heartbeat em segundo plano", err)
|
||||
}
|
||||
const payload = await res.clone().json().catch(() => null)
|
||||
if (payload && typeof payload === "object" && "machine" in payload) {
|
||||
const machineData = (payload as { machine?: MachineStatePayload }).machine
|
||||
if (machineData) {
|
||||
const currentActive = resolveMachineActive(machineData)
|
||||
setIsMachineActive(currentActive)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
const text = await res.text()
|
||||
|
|
@ -231,6 +281,7 @@ function App() {
|
|||
setToken(null)
|
||||
setConfig(null)
|
||||
setStatus(null)
|
||||
setIsMachineActive(true)
|
||||
setError("Este dispositivo precisa ser reprovisionado. Informe o código de provisionamento.")
|
||||
try {
|
||||
const p = await invoke<MachineProfile>("collect_machine_profile")
|
||||
|
|
@ -493,13 +544,41 @@ function App() {
|
|||
setIsLaunchingSystem(true)
|
||||
try {
|
||||
// Tenta criar a sessão via API (evita dependência de redirecionamento + cookies em 3xx)
|
||||
const res = await fetch(`${apiBaseUrl}/api/machines/sessions`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ machineToken: token, rememberMe: true }),
|
||||
})
|
||||
if (!res.ok) {
|
||||
const res = await fetch(`${apiBaseUrl}/api/machines/sessions`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ machineToken: token, rememberMe: true }),
|
||||
})
|
||||
if (res.ok) {
|
||||
const payload = await res.clone().json().catch(() => null)
|
||||
if (payload && typeof payload === "object" && "machine" in payload) {
|
||||
const machineData = (payload as { machine?: MachineStatePayload }).machine
|
||||
if (machineData) {
|
||||
const currentActive = resolveMachineActive(machineData)
|
||||
setIsMachineActive(currentActive)
|
||||
if (currentActive) {
|
||||
setError(null)
|
||||
}
|
||||
if (!currentActive) {
|
||||
setError("Esta máquina está desativada. Entre em contato com o suporte da Rever para reativar o acesso.")
|
||||
setIsLaunchingSystem(false)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (res.status === 423) {
|
||||
const payload = await res.clone().json().catch(() => null)
|
||||
const message =
|
||||
payload && typeof payload === "object" && typeof (payload as { error?: unknown }).error === "string"
|
||||
? ((payload as { error?: string }).error ?? "").trim()
|
||||
: ""
|
||||
setIsMachineActive(false)
|
||||
setIsLaunchingSystem(false)
|
||||
setError(message.length > 0 ? message : "Esta máquina está desativada. Entre em contato com o suporte da Rever.")
|
||||
return
|
||||
}
|
||||
// Se sessão falhar, tenta identificar token inválido/expirado
|
||||
try {
|
||||
const hb = await fetch(`${apiBaseUrl}/api/machines/heartbeat`, {
|
||||
|
|
@ -522,6 +601,7 @@ function App() {
|
|||
setToken(null)
|
||||
setConfig(null)
|
||||
setStatus(null)
|
||||
setIsMachineActive(true)
|
||||
setError("Sessão expirada. Reprovisione a máquina para continuar.")
|
||||
setIsLaunchingSystem(false)
|
||||
const p = await invoke<MachineProfile>("collect_machine_profile")
|
||||
|
|
@ -667,7 +747,24 @@ function App() {
|
|||
|
||||
return (
|
||||
<div className="min-h-screen grid place-items-center p-6">
|
||||
{token && !isMachineActive ? (
|
||||
<DeactivationScreen companyName={companyName} />
|
||||
) : (
|
||||
<div className="w-full max-w-[720px] rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
|
||||
<div className="mb-4 flex justify-center">
|
||||
<img
|
||||
src={logoSrc}
|
||||
alt="Logotipo Raven"
|
||||
width={160}
|
||||
height={160}
|
||||
className="h-16 w-auto md:h-20"
|
||||
onError={() => {
|
||||
if (logoFallbackRef.current) return
|
||||
logoFallbackRef.current = true
|
||||
setLogoSrc(`${appUrl}/raven.png`)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-2 flex items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="flex size-8 items-center justify-center rounded-lg bg-neutral-900 text-white"><GalleryVerticalEnd className="size-4" /></span>
|
||||
|
|
@ -869,9 +966,7 @@ function App() {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-6 flex justify-center">
|
||||
<img src={`${appUrl}/raven.png`} alt="Logotipo Raven" width={110} height={110} className="h-[3.45rem] w-auto" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue