Untitled
Anonymous
plain_text
02/24/2026 10:39 PM
13.2 KB
10
Indexable
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<title>set-cookie</title>
</head>
<body>
<script>
console.log("[set-cookie] script carregou, aguardando mensagem...");
window.addEventListener("message", (event) => {
try {
const origin = event.origin;
const originURL = new URL(origin);
const isHttps = originURL.protocol === "https:";
const isAuthorizedHost =
originURL.hostname.endsWith(".vrgente.com.br") ||
originURL.hostname.endsWith(".vr.com.br");
if (!isHttps || !isAuthorizedHost) {
console.warn("[set-cookie] Origem não autorizada:", origin);
return;
}
const payload = event.data && event.data.payload;
if (!payload) {
console.warn("[set-cookie] payload ausente");
return;
}
document.cookie =
`hcm-user=${payload}; ` +
`SameSite=None; Secure; ` +
`path=/; domain=.vrgente.com.br; ` +
`expires=Fri, 31 Dec 9999 23:59:59 GMT`;
// Verifica se o cookie foi realmente gravado
const cookieGravado = document.cookie.match(/(^|;)\s*hcm-user\s*=/);
if (!cookieGravado) {
console.error("[set-cookie] Cookie NÃO foi gravado. Verifique CSP/headers do servidor.");
} else {
console.log("[set-cookie] Cookie gravado com sucesso.");
}
// Responde de volta para o minisite
// event.source é a janela do shell/minisite — o targetOrigin deve ser o origin dele
event.source?.postMessage("COOKIE_SUCCESS", { targetOrigin: origin });
console.log("[set-cookie] ACK enviado para:", origin);
} catch (error) {
console.error("[set-cookie] erro:", error);
}
});
</script>
</body>
</html>
------------------------------
import Cookies from "js-cookie";
import { ReactNode, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import secureLocalStorage from "react-secure-storage";
import { UserData, UserResponse, zUserResponse } from "@config/schemas/user";
import { useAuthenticateHcmWithSpeToken } from "@hooks/useAuthenticateHcmWithSpeToken";
import { useFeatureFlagState } from "@hooks/useFeatureFlagState";
import { useToast } from "@hooks/useToast";
import { PageLoading, useLocalStorage } from "@vr-gente/hcm-components-lib";
import { setHcmUserCookie } from "@utilities/cookie";
import { useGlobalState } from "@vr-spe-toolkit/react";
import { getCookies } from "@vr-spe-toolkit/utils";
import { AuthenticationContext } from "./authentication-provider";
import { runtimeEnvironment } from "@helpers/env";
const NAVIGATE_EVENT_NAME = 'navigate_hcm';
// === Helpers ===
async function forceCleanSession() {
try {
secureLocalStorage.removeItem("user");
localStorage.removeItem("user");
Cookies.remove("access-token");
Cookies.remove("hcm-user");
document.cookie = "hcm-user=; SameSite=None; Secure; path=/; domain=.vrgente.com.br; expires=Thu, 01 Jan 1970 00:00:00 GMT";
} catch (e) {
console.error("Erro ao limpar sessão:", e);
}
}
function isEnvironmentClean() {
const token = Cookies.get("access-token");
const storage = secureLocalStorage.getItem("user");
const hcmUser = document.cookie.match(/(^|;)\s*hcm-user\s*=/);
return !token && !storage && !hcmUser;
}
type AuthStage =
| 'INITIAL_CLEANING'
| 'AUTHENTICATING'
| 'SETTING_SESSION'
| 'LOADING_FLAGS'
| 'READY';
export function SpeGedAuthenticationProvider({ children }: { children: ReactNode }) {
const toast = useToast();
const navigate = useNavigate();
const { set, remove } = useLocalStorage<UserData | null>("user");
const idToken = getCookies("spe-security/id-token");
const { user } = useGlobalState();
const [stage, setStage] = useState<AuthStage>('INITIAL_CLEANING');
const [sessionData, setSessionData] = useState<UserResponse["data"] | null>(null);
const { loadFeatureFlag, loading: isFeatureFlagLoading } = useFeatureFlagState();
const { mutate } = useAuthenticateHcmWithSpeToken({
onSuccess(res) {
const parsedRes = zUserResponse.parse(res.data);
setSessionData(parsedRes.data);
setStage('SETTING_SESSION');
},
onError() {
forceCleanSession();
remove();
toast?.current?.openToast({
message: "O serviço está temporariamente indisponível.",
type: "error",
});
navigate("/ged/sem-acesso");
},
});
// PASSO 1: Limpeza Inicial
useEffect(() => {
setStage('INITIAL_CLEANING');
console.log("[Auth] 1. Limpando ambiente...");
const cleanEnvironment = async () => {
remove();
await forceCleanSession();
if (isEnvironmentClean()) {
setStage('AUTHENTICATING');
} else {
console.error("[Auth] Falha ao limpar ambiente.");
window.location.href = '/';
window.location.reload();
}
};
cleanEnvironment();
// PASSO 6: Limpar ao desmontar
window.addEventListener('unmount_document_manager', async (res) => {
const customEvent = res as CustomEvent;
console.log("[Auth] Unmounting - Limpando tudo.");
remove();
setStage('INITIAL_CLEANING');
await forceCleanSession();
customEvent.detail.callback();
});
}, []);
// PASSO 2: Autenticação
useEffect(() => {
if (stage === 'AUTHENTICATING' && idToken && user?.cnpj) {
console.log("[Auth] 2. Autenticando...");
mutate({ idToken, cnpj: user?.cnpj });
}
}, [stage, idToken, user, mutate]);
// PASSO 3: Gravar Sessão via iframe cross-domain
useEffect(() => {
if (stage !== "SETTING_SESSION" || !sessionData) return;
console.log("[Auth] 3. Gravando Sessão...");
// Storage local
secureLocalStorage.setItem("user", sessionData);
set(sessionData);
// Cookies locais (domínio do shell)
Cookies.set("access-token", sessionData.access_token);
setHcmUserCookie({
access_token: sessionData.access_token,
refresh_token: sessionData.refresh_token,
});
const cookiePayload = {
access_token: sessionData.access_token,
refresh_token: sessionData.refresh_token,
};
const encoded = encodeURIComponent(JSON.stringify(cookiePayload));
const divRoot = document.getElementById("root") as HTMLDivElement | null;
if (!divRoot) {
console.error("[Auth] Root não encontrado.");
return;
}
const IFRAME_ID = "ged-set-cookie-iframe";
const portalOrigin = new URL(runtimeEnvironment.GED_SIGNATURE_PORTAL).origin;
const iframeUrl = `${portalOrigin}/assets/set-cookie.html`;
const sendMessage = (iframeEl: HTMLIFrameElement) => {
try {
console.log("[Auth] Enviando mensagem para o iframe...", { portalOrigin });
iframeEl.contentWindow?.postMessage(
{ origin: window.location.origin, payload: encoded },
portalOrigin
);
} catch (error) {
console.error("[Auth] Erro ao enviar mensagem para o iframe:", error);
}
};
const handleResponse = (event: MessageEvent) => {
if (event.origin !== portalOrigin) {
console.warn("[Auth] Origem não autorizada:", event.origin, "esperado:", portalOrigin);
return;
}
if (event.data === "COOKIE_SUCCESS") {
console.log("[Auth] Cookie configurado com sucesso pelo iframe.");
window.removeEventListener("message", handleResponse);
document.getElementById(IFRAME_ID)?.remove();
setStage("LOADING_FLAGS");
return;
}
console.error("[Auth] Resposta inesperada do iframe:", event.data);
};
window.addEventListener("message", handleResponse);
// Sempre recria o iframe para garantir que vai carregar a URL correta
// e disparar o evento onload — nunca confiamos em iframe reaproveitado cross-origin
document.getElementById(IFRAME_ID)?.remove();
const iframe = document.createElement("iframe");
iframe.id = IFRAME_ID;
iframe.src = iframeUrl;
iframe.style.width = "0";
iframe.style.height = "0";
iframe.style.border = "none";
iframe.style.position = "absolute";
// Só envia a mensagem depois que o iframe confirmou que carregou a URL correta
iframe.addEventListener("load", () => {
console.log("[Auth] Iframe carregou, enviando mensagem...");
sendMessage(iframe);
});
divRoot.appendChild(iframe);
// Fallback: se nunca responder em 5s, segue o fluxo
const timeout = window.setTimeout(() => {
console.error("[Auth] Timeout esperando COOKIE_SUCCESS do iframe.");
setStage("LOADING_FLAGS");
}, 5000);
return () => {
window.clearTimeout(timeout);
window.removeEventListener("message", handleResponse);
};
}, [stage, sessionData, set]);
// PASSO 4: Carregar Feature Flags
useEffect(() => {
if (stage === 'LOADING_FLAGS') {
console.log("[Auth] 4. Carregando Flags...");
loadFeatureFlag();
}
}, [stage, loadFeatureFlag]);
// PASSO 5: Monitorar Flags para liberar renderização
useEffect(() => {
if (stage === 'LOADING_FLAGS' && !isFeatureFlagLoading) {
console.log("[Auth] 5. Pronto.");
setStage('READY');
}
}, [stage, isFeatureFlagLoading]);
// Roteamento interno via evento customizado (minisite no SPE)
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const handleCustomEvent = (event: any) => {
const { detail } = event;
if (detail?.url) {
navigate(detail.url, { replace: true });
}
};
window.addEventListener(NAVIGATE_EVENT_NAME, handleCustomEvent);
return () => window.removeEventListener(NAVIGATE_EVENT_NAME, handleCustomEvent);
}, []);
if (stage !== 'READY') {
return <PageLoading />;
}
return (
<AuthenticationContext.Provider value={{ session: sessionData, isSuccess: true }}>
{children}
</AuthenticationContext.Provider>
);
}
Editor is loading...
Leave a Comment