first commit
This commit is contained in:
commit
c9fb67e751
423 files changed
+53287
No files matched your search
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user