@openade/fe
Version:
Fatturazione Elettronica - Electronic Invoicing for Sistema di Interscambio (SDI)
275 lines • 9.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuditTrailManager = void 0;
exports.createAuditTrailManager = createAuditTrailManager;
exports.logAuditEvent = logAuditEvent;
exports.queryAuditEvents = queryAuditEvents;
const fs_1 = require("fs");
const path_1 = require("path");
class AuditTrailManager {
constructor(config) {
this.currentLogFile = null;
this.config = {
maxLogSize: 10 * 1024 * 1024,
retentionDays: 2555,
detailedLogging: true,
includeSensitiveData: false,
format: 'json',
compression: true,
...config,
};
this.ensureLogDirectory();
}
async logEvent(event) {
const auditEvent = {
id: this.generateEventId(),
timestamp: new Date().toISOString(),
...event,
};
if (!this.config.includeSensitiveData) {
auditEvent.details = this.sanitizeSensitiveData(auditEvent.details);
}
await this.writeToLog(auditEvent);
await this.rotateLogIfNeeded();
}
async queryEvents(query = {}) {
try {
const logFiles = this.getLogFiles();
const events = [];
for (const logFile of logFiles) {
const fileEvents = await this.readLogFile(logFile);
events.push(...fileEvents);
}
return this.filterEvents(events, query);
}
catch {
return [];
}
}
async getAuditStats(query = {}) {
const events = await this.queryEvents(query);
return this.calculateStats(events);
}
async exportEvents(query = {}, format = 'json') {
const events = await this.queryEvents(query);
if (format === 'csv') {
return this.exportToCSV(events);
}
else {
return JSON.stringify(events, null, 2);
}
}
async cleanupOldLogs() {
try {
const logFiles = this.getLogFiles();
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - this.config.retentionDays);
let deletedCount = 0;
for (const logFile of logFiles) {
const filePath = (0, path_1.join)(this.config.logDir, logFile);
const stats = (0, fs_1.statSync)(filePath);
if (stats.mtime < cutoffDate) {
(0, fs_1.unlinkSync)(filePath);
deletedCount++;
}
}
return deletedCount;
}
catch {
return 0;
}
}
generateEventId() {
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2, 8);
return `EVT_${timestamp}_${random}`;
}
ensureLogDirectory() {
if (!(0, fs_1.existsSync)(this.config.logDir)) {
(0, fs_1.mkdirSync)(this.config.logDir, { recursive: true });
}
}
getCurrentLogFile() {
if (!this.currentLogFile) {
const date = new Date().toISOString().split('T')[0];
this.currentLogFile = (0, path_1.join)(this.config.logDir, `audit_${date}.log`);
}
return this.currentLogFile;
}
async writeToLog(event) {
const logFile = this.getCurrentLogFile();
const logEntry = this.formatLogEntry(event);
(0, fs_1.writeFileSync)(logFile, logEntry + '\n', { flag: 'a' });
}
formatLogEntry(event) {
if (this.config.format === 'json') {
return JSON.stringify(event);
}
else {
return `${event.timestamp} [${event.type}] ${event.description} - ${event.success ? 'SUCCESS' : 'FAILED'}`;
}
}
async rotateLogIfNeeded() {
const logFile = this.getCurrentLogFile();
if ((0, fs_1.existsSync)(logFile)) {
const stats = (0, fs_1.statSync)(logFile);
if (stats.size >= this.config.maxLogSize) {
this.currentLogFile = null;
}
}
}
getLogFiles() {
try {
if (!(0, fs_1.existsSync)(this.config.logDir)) {
return [];
}
return (0, fs_1.readdirSync)(this.config.logDir)
.filter((file) => file.startsWith('audit_') && file.endsWith('.log'))
.sort();
}
catch {
return [];
}
}
async readLogFile(filename) {
try {
const filePath = (0, path_1.join)(this.config.logDir, filename);
const content = (0, fs_1.readFileSync)(filePath, 'utf8');
const lines = content.trim().split('\n');
return lines
.map((line) => {
try {
return JSON.parse(line);
}
catch {
return null;
}
})
.filter((event) => event !== null);
}
catch {
return [];
}
}
filterEvents(events, query) {
let filtered = events;
if (query.types && query.types.length > 0) {
filtered = filtered.filter((event) => query.types.includes(event.type));
}
if (query.startDate) {
filtered = filtered.filter((event) => event.timestamp >= query.startDate);
}
if (query.endDate) {
filtered = filtered.filter((event) => event.timestamp <= query.endDate);
}
if (query.userId) {
filtered = filtered.filter((event) => event.userId === query.userId);
}
if (query.success !== undefined) {
filtered = filtered.filter((event) => event.success === query.success);
}
if (query.invoiceId) {
filtered = filtered.filter((event) => event.invoiceId === query.invoiceId);
}
filtered.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
if (query.offset) {
filtered = filtered.slice(query.offset);
}
if (query.limit) {
filtered = filtered.slice(0, query.limit);
}
return filtered;
}
calculateStats(events) {
const eventsByType = {};
const eventsByUser = {};
const errors = {};
let totalDuration = 0;
let durationCount = 0;
for (const event of events) {
eventsByType[event.type] = (eventsByType[event.type] || 0) + 1;
if (event.userId) {
eventsByUser[event.userId] = (eventsByUser[event.userId] || 0) + 1;
}
if (!event.success && event.error) {
errors[event.error] = (errors[event.error] || 0) + 1;
}
if (event.duration) {
totalDuration += event.duration;
durationCount++;
}
}
const commonErrors = Object.entries(errors)
.map(([error, count]) => ({ error, count }))
.sort((a, b) => b.count - a.count)
.slice(0, 10);
const successCount = events.filter((e) => e.success).length;
const successRate = events.length > 0 ? (successCount / events.length) * 100 : 0;
const averageDuration = durationCount > 0 ? totalDuration / durationCount : 0;
const timestamps = events.map((e) => e.timestamp).sort();
const timeRange = {
start: timestamps[0] || '',
end: timestamps[timestamps.length - 1] || '',
};
return {
totalEvents: events.length,
eventsByType,
eventsByUser,
successRate,
averageDuration,
commonErrors,
timeRange,
};
}
exportToCSV(events) {
if (events.length === 0) {
return '';
}
const headers = [
'ID',
'Type',
'Timestamp',
'User ID',
'Description',
'Success',
'Error',
'Duration',
'Invoice ID',
];
const rows = events.map((event) => [
event.id,
event.type,
event.timestamp,
event.userId || '',
event.description,
event.success ? 'TRUE' : 'FALSE',
event.error || '',
event.duration || '',
event.invoiceId || '',
]);
return [headers, ...rows].map((row) => row.join(',')).join('\n');
}
sanitizeSensitiveData(details) {
const sensitiveKeys = ['password', 'token', 'key', 'secret', 'certificate', 'privateKey'];
const sanitized = { ...details };
for (const key of Object.keys(sanitized)) {
if (sensitiveKeys.some((sensitive) => key.toLowerCase().includes(sensitive))) {
sanitized[key] = '[REDACTED]';
}
}
return sanitized;
}
}
exports.AuditTrailManager = AuditTrailManager;
function createAuditTrailManager(config) {
return new AuditTrailManager(config);
}
async function logAuditEvent(event, config) {
const manager = createAuditTrailManager(config);
await manager.logEvent(event);
}
async function queryAuditEvents(query = {}, config) {
const manager = createAuditTrailManager(config);
return await manager.queryEvents(query);
}
//# sourceMappingURL=audit.manager.js.map