frontend; backend: adiciona sistema novo de gravacao de provas
Signed-off-by: Rodrigo B. de Sousa Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
1 parent
0750b26208
commit
ece79775d8
13 files changed
+1510
-70
No files matched your search
@@ -0,0 +1,227 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useParams, Link } from 'react-router-dom';
|
||||
import { format } from 'date-fns';
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
|
||||
interface SessionData {
|
||||
id: string;
|
||||
startTime: string;
|
||||
endTime?: string;
|
||||
ipAddress: string;
|
||||
dnsInfo: string;
|
||||
userAgent: string;
|
||||
geolocation?: {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
};
|
||||
screenshots: string[];
|
||||
videoPath?: string;
|
||||
metadata: any;
|
||||
}
|
||||
|
||||
export const SessionReport: React.FC = () => {
|
||||
const { sessionId } = useParams<{ sessionId: string }>();
|
||||
const [session, setSession] = useState<SessionData | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSession = async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/sessions/${sessionId}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Sessão não encontrada');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
setSession(data.session);
|
||||
} catch (error) {
|
||||
console.error('Erro ao buscar sessão:', error);
|
||||
setError(error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (sessionId) {
|
||||
fetchSession();
|
||||
}
|
||||
}, [sessionId]);
|
||||
|
||||
const formatDuration = (start: string, end?: string) => {
|
||||
if (!end) return 'Em andamento';
|
||||
|
||||
const startTime = new Date(start);
|
||||
const endTime = new Date(end);
|
||||
const diffMs = endTime.getTime() - startTime.getTime();
|
||||
|
||||
const hours = Math.floor(diffMs / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((diffMs % (1000 * 60)) / 1000);
|
||||
|
||||
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="bg-white rounded-lg shadow p-6">
|
||||
<div className="animate-pulse">
|
||||
<div className="h-6 bg-gray-300 rounded w-3/4 mb-4"></div>
|
||||
<div className="h-4 bg-gray-300 rounded w-1/2 mb-2"></div>
|
||||
<div className="h-4 bg-gray-300 rounded w-2/3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !session) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="bg-white rounded-lg shadow p-6 text-center">
|
||||
<div className="text-red-600 text-xl font-bold mb-4">
|
||||
Erro ao carregar sessão
|
||||
</div>
|
||||
<p className="text-gray-600 mb-6">{error || 'Sessão não encontrada'}</p>
|
||||
<Link
|
||||
to="/sessions/new"
|
||||
className="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
|
||||
>
|
||||
Nova Sessão
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<div className="bg-white rounded-lg shadow overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="bg-green-600 text-white px-6 py-4">
|
||||
<h1 className="text-2xl font-bold">Relatório de Sessão de Coleta de Prova</h1>
|
||||
<p className="text-green-100">ID da Sessão: {session.id}</p>
|
||||
</div>
|
||||
|
||||
{/* Resumo da sessão */}
|
||||
<div className="p-6 border-b border-gray-200">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">Resumo da Sessão</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500">Data/Hora de Início</h3>
|
||||
<p className="text-lg text-gray-900">
|
||||
{format(new Date(session.startTime), 'dd/MM/yyyy HH:mm:ss', { locale: ptBR })}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{session.endTime && (
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500">Data/Hora de Fim</h3>
|
||||
<p className="text-lg text-gray-900">
|
||||
{format(new Date(session.endTime), 'dd/MM/yyyy HH:mm:ss', { locale: ptBR })}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500">Duração</h3>
|
||||
<p className="text-lg text-gray-900">
|
||||
{formatDuration(session.startTime, session.endTime)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500">Screenshots Capturados</h3>
|
||||
<p className="text-lg text-gray-900">{session.screenshots.length}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Informações de rede */}
|
||||
<div className="p-6 border-b border-gray-200">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">Informações de Rede</h2>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500">Endereço IP</h3>
|
||||
<p className="text-gray-900 font-mono">{session.ipAddress}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500">DNS Reverso</h3>
|
||||
<p className="text-gray-900 font-mono">{session.dnsInfo}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500">User-Agent</h3>
|
||||
<p className="text-gray-900 font-mono text-sm break-all">{session.userAgent}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Geolocalização */}
|
||||
{session.geolocation && (
|
||||
<div className="p-6 border-b border-gray-200">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">Geolocalização</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500">Latitude</h3>
|
||||
<p className="text-gray-900 font-mono">{session.geolocation.latitude}</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-sm font-medium text-gray-500">Longitude</h3>
|
||||
<p className="text-gray-900 font-mono">{session.geolocation.longitude}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Metadados adicionais */}
|
||||
<div className="p-6 border-b border-gray-200">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">Metadados do Sistema</h2>
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<pre className="text-sm text-gray-700 overflow-x-auto">
|
||||
{JSON.stringify(session.metadata, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Ações */}
|
||||
<div className="p-6 flex flex-col sm:flex-row gap-4">
|
||||
<a
|
||||
href={`/api/sessions/${session.id}/report`}
|
||||
className="inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700"
|
||||
>
|
||||
Baixar Relatório PDF
|
||||
</a>
|
||||
|
||||
{session.videoPath && (
|
||||
<button className="inline-flex items-center justify-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
|
||||
Visualizar Vídeo
|
||||
</button>
|
||||
)}
|
||||
|
||||
<Link
|
||||
to="/sessions/new"
|
||||
className="inline-flex items-center justify-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
|
||||
>
|
||||
Nova Sessão
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 text-center text-sm text-gray-500">
|
||||
Relatório gerado pelo sistema AdvX Provas - Coleta de Evidências Digitais
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SessionReport;
|
||||
Reference in new issue
Block a user