@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
JavaScript
"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;