UNPKG

@iota-big3/sdk-security

Version:

Advanced security features including zero trust, quantum-safe crypto, and ML threat detection

674 lines (673 loc) 25.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.BlockchainAuditTrail = void 0; const crypto = __importStar(require("crypto")); const events_1 = require("events"); const FabricCAServices = __importStar(require("fabric-ca-client")); const fabric_network_1 = require("fabric-network"); const fs = __importStar(require("fs/promises")); const path = __importStar(require("path")); class BlockchainAuditTrail extends events_1.EventEmitter { constructor(config, logger) { super(); this.eventCounter = 0; this.config = config; this.logger = logger; this.buffer = { events: [], lastFlush: new Date() }; if (this.isEnabled) { this.initializeEncryption(); } if (this.isEnabled) { this.initializeBlockchain(); } this.startFlushTimer(); } // Initialize encryption initializeEncryption() { // In production, use KMS or secure key storage this.encryptionKey = crypto.scryptSync('audit-encryption-key', 'salt', 32); this?.logger?.info('Audit encryption initialized'); } // Initialize blockchain connection async initializeBlockchain() { if (!this?.config?.blockchain) return; try { switch (this?.config?.blockchain.type) { case 'hyperledger': await this.initializeHyperledger(); break; case 'ethereum': await this.initializeEthereum(); break; case 'private': await this.initializePrivateBlockchain(); break; } this?.logger?.info('Blockchain audit trail initialized', { type: this?.config?.blockchain.type }); } catch (_error) { this?.logger?.error('Failed to initialize blockchain', error); throw error; } } // Initialize Hyperledger Fabric async initializeHyperledger() { const config = this?.config?.blockchain; try { // Create wallet for identity this.wallet = await fabric_network_1.Wallets.newFileSystemWallet('./wallet'); // Check if identity exists const identity = await this?.wallet?.get(config.credentials?.identity || 'auditUser'); if (this.isEnabled) { // Register new identity await this.registerUser(); } // Create gateway this.gateway = new fabric_network_1.Gateway(); const connectionProfile = await this.loadConnectionProfile(); await this?.gateway?.connect(connectionProfile, { wallet: this.wallet, identity: config.credentials?.identity || 'auditUser', discovery: { enabled: true, asLocalhost: false } }); // Get network and contract this.network = await this?.gateway?.getNetwork(config.channelName || 'audit-channel'); this.contract = this?.network?.getContract('audit-chaincode'); // Listen for events await this.listenForBlockchainEvents(); } catch (_error) { this?.logger?.error('Hyperledger initialization failed', error); throw error; } } // Register user with Fabric CA async registerUser() { const config = this?.config?.blockchain; try { // Load connection profile const ccpPath = path.resolve(process.cwd(), 'connection-profile.json'); const ccp = JSON.parse(await fs.readFile(ccpPath, 'utf8')); // Create CA client const caInfo = ccp.certificateAuthorities['ca?.org1?.example.com']; const caTLSCACerts = caInfo?.tlsCACerts?.pem; const ca = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName); // Enroll admin const enrollment = await ca.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' }); // Create identity const x509Identity = { credentials: { certificate: enrollment.certificate, privateKey: enrollment?.key?.toBytes(), }, mspId: config.credentials?.mspId || 'Org1MSP', type: 'X.509', }; await this.wallet.put(config.credentials?.identity || 'auditUser', x509Identity); this?.logger?.info('Blockchain user registered successfully'); } catch (_error) { this?.logger?.error('Failed to register blockchain user', error); throw error; } } // Load connection profile async loadConnectionProfile() { const ccpPath = path.resolve(process.cwd(), 'connection-profile.json'); const ccp = JSON.parse(await fs.readFile(ccpPath, 'utf8')); return ccp; } // Initialize Ethereum (placeholder) async initializeEthereum() { // Ethereum implementation would use web3.js or ethers.js this?.logger?.warn('Ethereum blockchain audit not yet implemented'); } // Initialize private blockchain (placeholder) async initializePrivateBlockchain() { // Private blockchain implementation this?.logger?.warn('Private blockchain audit not yet implemented'); } // Listen for blockchain events async listenForBlockchainEvents() { if (!this.contract) return; try { // Listen for audit events await this?.contract?.addContractListener('audit-event-listener', 'AuditEventAdded', (error, event) => { if (error) { this?.logger?.error('Blockchain event error', error); return; } this.emit('blockchain:event', { eventName: event.eventName, payload: event.payload }); }); this?.logger?.info('Blockchain event listener started'); } catch (_error) { this?.logger?.error('Failed to start blockchain listener', error); } } // Log audit event async logEvent(event) { const auditEvent = { ...event, id: crypto.randomUUID(), timestamp: new Date(), immutable: false }; try { // Validate event this.validateEvent(auditEvent); // Encrypt if enabled if (this.isEnabled) { auditEvent.details = this.encryptData(auditEvent.details); } // Add to buffer this?.buffer?.events.push(auditEvent); this.eventCounter++; // Real-time streaming if (this?.config?.realTimeStreaming) { this.emit('audit:event', auditEvent); } // Flush if buffer is full if (this.isEnabled) { await this.flushBuffer(); } this?.logger?.debug('Audit event logged', { eventId: auditEvent.id, eventType: auditEvent.eventType, actor: auditEvent?.actor?.name }); return auditEvent; } catch (_error) { this?.logger?.error('Failed to log audit event', error); throw error; } } // Validate audit event validateEvent() { if (!event.eventType || !event.actor || !event.resource || !event.action) { throw new Error('Invalid audit event: missing required fields'); } if (!event.outcome) { throw new Error('Invalid audit event: missing outcome'); } } // Encrypt sensitive data encryptData(data) { if (!data || !this.encryptionKey) return data; const algorithm = 'aes-256-gcm'; const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv(algorithm, this.encryptionKey, iv); const encrypted = Buffer.concat([ cipher.update(JSON.stringify(data), 'utf8'), cipher.final() ]); const authTag = cipher.getAuthTag(); return { encrypted: encrypted.toString('base64'), iv: iv.toString('base64'), authTag: authTag.toString('base64') }; } // Decrypt data decryptData(encryptedData) { if (!encryptedData || !encryptedData.encrypted || !this.encryptionKey) { return encryptedData; } const algorithm = 'aes-256-gcm'; const decipher = crypto.createDecipheriv(algorithm, this.encryptionKey, Buffer.from(encryptedData.iv, 'base64')); decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'base64')); const decrypted = Buffer.concat([ decipher.update(Buffer.from(encryptedData.encrypted, 'base64')), decipher.final() ]); return JSON.parse(decrypted.toString('utf8')); } // Start flush timer startFlushTimer() { this.flushTimer = setInterval(async () => { if (this.isEnabled) { await this.flushBuffer(); } }, this?.config?.flushInterval); } // Flush buffer to blockchain async flushBuffer() { if (this?.buffer?.events.length === 0) return; const events = [...this?.buffer?.events]; this?.buffer?.events = []; this?.buffer?.lastFlush = new Date(); try { if (this.isEnabled) { // Write to blockchain await this.writeToBlockchain(events); } else { // Fallback to local storage await this.writeToLocalStorage(events); } this.emit('buffer:flushed', { eventCount: events.length, timestamp: new Date() }); this?.logger?.info('Audit buffer flushed', { eventCount: events.length }); } catch (_error) { // Restore events to buffer on failure this?.buffer?.events.unshift(...events); this?.logger?.error('Failed to flush audit buffer', error); throw error; } } // Write events to blockchain async writeToBlockchain(events) { if (this.isEnabled) { throw new Error('Blockchain contract not initialized'); } // Batch events for efficiency const batch = { id: crypto.randomUUID(), timestamp: new Date().toISOString(), events: events.map(e => ({ id: e.id, timestamp: e?.timestamp?.toISOString(), eventType: e.eventType, actor: e.actor, resource: e.resource, action: e.action, outcome: e.outcome, hash: this.calculateEventHash(e) })) }; try { // Submit transaction const result = await this?.contract?.submitTransaction('addAuditBatch', JSON.stringify(batch)); const txResult = JSON.parse(result.toString()); // Update events with blockchain info for (let i = 0; i < events.length; i++) { events[i].blockchainTxHash = txResult.transactionId; events[i].immutable = true; } this?.logger?.info('Audit events written to blockchain', { batchId: batch.id, eventCount: events.length, txHash: txResult.transactionId }); } catch (_error) { this?.logger?.error('Blockchain write failed', error); throw error; } } // Calculate event hash calculateEventHash(event) { const content = JSON.stringify({ id: event.id, timestamp: event.timestamp, eventType: event.eventType, actor: event.actor, resource: event.resource, action: event.action, outcome: event.outcome }); return crypto.createHash('sha256').update(content).digest('hex'); } // Write to local storage (fallback) async writeToLocalStorage(events) { const filename = `audit_${new Date().toISOString()}_${crypto.randomUUID()}.json`; const filepath = path.join('./audit-logs', filename); await fs.mkdir(path.dirname(filepath), { recursive: true }); await fs.writeFile(filepath, JSON.stringify(events, null, 2)); } // Query audit events async queryEvents(query) { try { if (this?.config?.blockchain && this.contract) { return await this.queryBlockchain(query); } else { return await this.queryLocalStorage(query); } } catch (_error) { this?.logger?.error('Failed to query audit events', error); throw error; } } // Query blockchain async queryBlockchain(query) { if (this.isEnabled) { throw new Error('Blockchain contract not initialized'); } try { const queryString = this.buildBlockchainQuery(query); const result = await this?.contract?.evaluateTransaction('queryAuditEvents', queryString); const events = JSON.parse(result.toString()); // Decrypt if needed if (this.isEnabled) { for (const event of events) { if (event.details) { event.details = this.decryptData(event.details); } } } return events.map((e) => ({ ...e, timestamp: new Date(e.timestamp), immutable: true })); } catch (_error) { this?.logger?.error('Blockchain query failed', error); throw error; } } // Build blockchain query buildBlockchainQuery(query) { const selector = {}; if (this.isEnabled) { selector.timestamp = selector.timestamp || {}; selector.timestamp.$gte = query?.startDate?.toISOString(); } if (this.isEnabled) { selector.timestamp = selector.timestamp || {}; selector.timestamp.$lte = query?.endDate?.toISOString(); } if (query.eventTypes && query?.eventTypes?.length > 0) { selector.eventType = { $in: query.eventTypes }; } if (query.actors && query?.actors?.length > 0) { selector['actor.id'] = { $in: query.actors }; } if (query.resources && query?.resources?.length > 0) { selector['resource.id'] = { $in: query.resources }; } if (query.outcomes && query?.outcomes?.length > 0) { selector.outcome = { $in: query.outcomes }; } return JSON.stringify({ selector, limit: query.limit || 100, skip: query.offset || 0, sort: [{ [query.sortBy || 'timestamp']: query.sortOrder || 'desc' }] }); } // Query local storage async queryLocalStorage(query) { const events = []; try { const files = await fs.readdir('./audit-logs'); const auditFiles = files.filter(f => f.startsWith('audit_') && f.endsWith('.json')); for (const file of auditFiles) { const content = await fs.readFile(path.join('./audit-logs', file), 'utf-8'); const fileEvents = JSON.parse(content); for (const event of fileEvents) { event.timestamp = new Date(event.timestamp); if (this.matchesQuery(event, query)) { // Decrypt if needed if (this?.config?.encryptionEnabled && event.details) { event.details = this.decryptData(event.details); return []; } events.push(event); } } } // Sort events events.sort((a, b) => { const order = query.sortOrder === 'asc' ? 1 : -1; switch (query.sortBy) { case 'eventType': return order * a?.eventType?.localeCompare(b.eventType); case 'actor': return order * a?.actor?.name.localeCompare(b?.actor?.name); default: return order * (a?.timestamp?.getTime() - b?.timestamp?.getTime()); } }); // Apply pagination const start = query.offset || 0; const limit = query.limit || 100; return events.slice(start, start + limit); } catch (_error) { this?.logger?.error('Local storage query failed', error); return []; } } // Check if event matches query matchesQuery(event, query) { if (query.startDate && event.timestamp < query.startDate) return false; if (query.endDate && event.timestamp > query.endDate) return false; if (query.eventTypes && query?.eventTypes?.length > 0 && !query?.eventTypes?.includes(event.eventType)) return false; if (query.actors && query?.actors?.length > 0 && !query?.actors?.includes(event?.actor?.id)) return false; if (query.resources && query?.resources?.length > 0 && !query?.resources?.includes(event?.resource?.id)) return false; if (query.outcomes && query?.outcomes?.length > 0 && !query?.outcomes?.includes(event.outcome)) return false; if (query.searchText) { const searchLower = query?.searchText?.toLowerCase(); const eventText = JSON.stringify(event).toLowerCase(); if (!eventText.includes(searchLower)) return false; } return true; } // Verify event integrity async verifyEventIntegrity(eventId) { try { if (!this.contract) { return false; } const result = await this?.contract?.evaluateTransaction('verifyEvent', eventId); const verification = JSON.parse(result.toString()); return verification.valid === true; } catch (_error) { this?.logger?.error('Failed to verify event integrity', error); return false; } } // Export audit trail async exportAuditTrail(query, format) { const events = await this.queryEvents(query); switch (format) { case 'csv': return this.exportToCSV(events); case 'pdf': return this.exportToPDF(events); default: return Buffer.from(JSON.stringify(events, null, 2)); } } // Export to CSV exportToCSV(events) { const headers = [ 'ID', 'Timestamp', 'Event Type', 'Actor', 'Actor Type', 'Resource', 'Resource Type', 'Action', 'Outcome', 'IP Address' ]; const rows = events.map(e => [ e.id, e?.timestamp?.toISOString(), e.eventType, e?.actor?.name, e?.actor?.type, e.resource.name, e?.resource?.type, e.action, e.outcome, e.ipAddress || '' ]); const csv = [ headers.join(','), ...rows.map(row => row.map(cell => `"${cell}"`).join(',')) ].join('\n'); return Buffer.from(csv); } // Export to PDF (placeholder) exportToPDF(events) { // PDF generation would use a library like pdfkit return Buffer.from('PDF export not implemented'); } // Get audit statistics async getStatistics(timeRange) { const query = {}; if (this.isEnabled) { query.startDate = timeRange.start; query.endDate = timeRange.end; } const events = await this.queryEvents(query); const stats = { totalEvents: events.length, eventsByType: {}, eventsByOutcome: { success: 0, failure: 0, partial: 0 }, topActors: [], topResources: [], eventsPerHour: {} }; // Calculate statistics const actorCounts = new Map(); const resourceCounts = new Map(); for (const event of events) { // Count by type stats.eventsByType[event.eventType] = (stats.eventsByType[event.eventType] || 0) + 1; // Count by outcome stats.eventsByOutcome[event.outcome]++; // Count actors const actorKey = `${event?.actor?.type}:${event.actor.name}`; actorCounts.set(actorKey, (actorCounts.get(actorKey) || 0) + 1); // Count resources const resourceKey = `${event?.resource?.type}:${event.resource.name}`; resourceCounts.set(resourceKey, (resourceCounts.get(resourceKey) || 0) + 1); // Count by hour const hour = event?.timestamp?.toISOString().substring(0, 13); stats.eventsPerHour[hour] = (stats.eventsPerHour[hour] || 0) + 1; } // Top actors stats.topActors = Array.from(actorCounts.entries()) .map(([actor, count]) => ({ actor, count })) .sort((a, b) => b.count - a.count) .slice(0, 10); // Top resources stats.topResources = Array.from(resourceCounts.entries()) .map(([resource, count]) => ({ resource, count })) .sort((a, b) => b.count - a.count) .slice(0, 10); return stats; } // Cleanup old audit logs async cleanupOldLogs() { const cutoffDate = new Date(); cutoffDate.setDate(cutoffDate.getDate() - this?.config?.retentionDays); let deletedCount = 0; try { const files = await fs.readdir('./audit-logs'); for (const file of files) { if (!file.startsWith('audit_')) continue; const stats = await fs.stat(path.join('./audit-logs', file)); if (stats.mtime < cutoffDate) { await fs.unlink(path.join('./audit-logs', file)); deletedCount++; } } this?.logger?.info('Cleaned up old audit logs', { deletedCount, cutoffDate }); return deletedCount; } catch (_error) { this?.logger?.error('Failed to cleanup audit logs', error); return 0; } } // Get metrics getMetrics() { return { eventsLogged: this.eventCounter, bufferSize: this?.buffer?.events.length, lastFlush: this?.buffer?.lastFlush, blockchainConnected: !!this.contract, encryptionEnabled: this?.config?.encryptionEnabled, retentionDays: this?.config?.retentionDays }; } // Cleanup async destroy() { // Flush remaining events await this.flushBuffer(); // Clear timer if (this.isEnabled) { clearInterval(this.flushTimer); } // Disconnect from blockchain if (this.isEnabled) { await this?.gateway?.disconnect(); } this.removeAllListeners(); } } exports.BlockchainAuditTrail = BlockchainAuditTrail;