first commit

This commit is contained in:
rodrigo committed 2025-04-10 23:07:21 -03:00
commit c9fb67e751
423 files changed
+53287

No files matched your search

+246
View File
@@ -0,0 +1,246 @@
import axios from 'axios';
import { v4 as uuidv4 } from 'uuid';
import { createHash } from 'crypto';
// Tentativa de importar o UAParser com fallback para evitar quebra caso não esteja instalado
let UAParser;
try {
UAParser = require('ua-parser-js');
} catch (error) {
console.warn('Aviso: UAParser não está disponível. Usando método alternativo para analisar User-Agent.');
// Implementação simples de fallback para quando a biblioteca não está disponível
UAParser = class SimpleBrowserDetect {
constructor(userAgent) {
this.userAgent = userAgent;
}
getResult() {
const isMobile = /mobile|android|iphone|ipod|ipad/i.test(this.userAgent);
const isWindows = /windows/i.test(this.userAgent);
const isMac = /macintosh|mac os/i.test(this.userAgent);
const isLinux = /linux/i.test(this.userAgent);
const chromeMatch = this.userAgent.match(/chrome\/(\d+)/i);
const firefoxMatch = this.userAgent.match(/firefox\/(\d+)/i);
const safariMatch = this.userAgent.match(/safari\/(\d+)/i);
const edgeMatch = this.userAgent.match(/edge\/(\d+)|edg\/(\d+)/i);
return {
browser: {
name: edgeMatch ? 'Edge' :
chromeMatch ? 'Chrome' :
firefoxMatch ? 'Firefox' :
safariMatch ? 'Safari' : 'Desconhecido',
version: (edgeMatch || chromeMatch || firefoxMatch || safariMatch || ['', '0'])[1],
major: (edgeMatch || chromeMatch || firefoxMatch || safariMatch || ['', '0'])[1],
},
engine: {
name: 'Desconhecido',
version: '',
},
os: {
name: isWindows ? 'Windows' :
isMac ? 'Mac OS' :
isLinux ? 'Linux' : 'Desconhecido',
version: '',
},
device: {
vendor: '',
model: '',
type: isMobile ? 'mobile' : 'desktop',
},
cpu: {
architecture: '',
}
};
}
};
}
/**
* Classe para coletar e validar metadados de arquivos conforme RFC 3227
* (Diretrizes para Coleta e Arquivamento de Evidências)
*/
export class MetadataCollector {
/**
* Coleta metadados avançados a partir dos dados fornecidos
*/
async collectMetadata(data: {
userAgent: string;
ipAddress: string;
timestamp: Date;
fileName: string;
fileModified?: Date;
fileSize: number;
viewportWidth?: string;
viewportHeight?: string;
language?: string;
referrer?: string;
latitude?: number;
longitude?: number;
}) {
try {
// Gerar identificador único para a coleta
const collectionId = uuidv4();
const collectionTimestamp = new Date();
// Parser para informações do navegador
const parser = new UAParser(data.userAgent);
const browserInfo = parser.getResult();
// Obter geolocalização a partir do IP se não fornecida diretamente
let geoInfo = null;
if (!data.latitude && !data.longitude) {
try {
geoInfo = await this.getGeolocationFromIP(data.ipAddress);
} catch (error) {
console.warn('Falha ao obter geolocalização:', error);
}
}
// Construir o objeto de metadados
return {
// Identificação da coleta
collectionId,
collectionTimestamp: collectionTimestamp.toISOString(),
// Dados do usuário
userInfo: {
ipAddress: data.ipAddress,
userAgent: data.userAgent,
language: data.language || 'não informado',
browser: {
name: browserInfo.browser.name || 'desconhecido',
version: browserInfo.browser.version || 'desconhecido',
major: browserInfo.browser.major || 'desconhecido',
},
engine: {
name: browserInfo.engine.name || 'desconhecido',
version: browserInfo.engine.version || 'desconhecido',
},
os: {
name: browserInfo.os.name || 'desconhecido',
version: browserInfo.os.version || 'desconhecido',
},
device: {
vendor: browserInfo.device.vendor || 'desconhecido',
model: browserInfo.device.model || 'desconhecido',
type: browserInfo.device.type || 'desconhecido',
},
cpu: {
architecture: browserInfo.cpu.architecture || 'desconhecido',
},
viewportSize: data.viewportWidth && data.viewportHeight
? `${data.viewportWidth}x${data.viewportHeight}`
: 'não informado',
referrer: data.referrer || 'não informado',
},
// Dados do arquivo
fileInfo: {
name: data.fileName,
size: data.fileSize,
sizeFormatted: this.formatFileSize(data.fileSize),
modifiedDate: data.fileModified ? data.fileModified.toISOString() : 'não informado',
},
// Dados de localização
locationInfo: geoInfo || {
latitude: data.latitude || null,
longitude: data.longitude || null,
city: 'não disponível',
region: 'não disponível',
country: 'não disponível',
timezone: 'não disponível'
},
// Timestamp oficial do sistema
timestamp: data.timestamp.toISOString(),
// Hash da coleta para garantir integridade
integrityHash: this.generateIntegrityHash(
data.ipAddress,
data.userAgent,
data.fileName,
data.fileSize.toString(),
collectionTimestamp.toISOString()
)
};
} catch (error) {
console.error('Erro ao coletar metadados:', error);
// Retornar metadados simplificados se algo der errado
return {
timestamp: new Date().toISOString(),
userAgent: data.userAgent,
ipAddress: data.ipAddress,
fileName: data.fileName,
fileSize: data.fileSize,
error: 'Falha na coleta completa de metadados'
};
}
}
/**
* Formata o tamanho do arquivo para exibição
*/
private formatFileSize(bytes: number): string {
if (bytes < 1024) return bytes + ' bytes';
else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
else return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
}
/**
* Gera um hash de integridade para os metadados coletados
*/
private generateIntegrityHash(...inputs: string[]): string {
try {
return createHash('sha256')
.update(inputs.join('|'))
.digest('hex');
} catch (error) {
console.error('Erro ao gerar hash de integridade:', error);
return 'hash-error-' + Date.now();
}
}
/**
* Obtém informações de geolocalização a partir do endereço IP
*/
private async getGeolocationFromIP(ipAddress: string) {
try {
// Apenas para endereços IP públicos, ignorar IPs locais
if (ipAddress === '127.0.0.1' || ipAddress === '::1' || ipAddress.startsWith('192.168.') || ipAddress.startsWith('10.')) {
return null;
}
// Usar API pública de geolocalização
const response = await axios.get(`https://ipinfo.io/${ipAddress}/json`);
const data = response.data;
// Extrair coordenadas (formato: "lat,long")
let latitude = null;
let longitude = null;
if (data.loc) {
const [lat, lng] = data.loc.split(',');
latitude = parseFloat(lat);
longitude = parseFloat(lng);
}
return {
latitude,
longitude,
city: data.city || 'não disponível',
region: data.region || 'não disponível',
country: data.country || 'não disponível',
timezone: data.timezone || 'não disponível',
provider: 'ipinfo.io'
};
} catch (error) {
console.error('Erro ao obter geolocalização:', error);
return null;
}
}
}