UNPKG

@ahmedhegazee/nestjs-telescope

Version:

Advanced observability and monitoring solution for NestJS applications with ML-powered analytics, enterprise features, and production-ready scaling

713 lines 26.6 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 __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var EnterpriseSecurityService_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.EnterpriseSecurityService = void 0; const common_1 = require("@nestjs/common"); const rxjs_1 = require("rxjs"); const common_2 = require("@nestjs/common"); const crypto = __importStar(require("crypto")); const jwt = __importStar(require("jsonwebtoken")); let EnterpriseSecurityService = EnterpriseSecurityService_1 = class EnterpriseSecurityService { constructor(telescopeConfig) { this.telescopeConfig = telescopeConfig; this.logger = new common_1.Logger(EnterpriseSecurityService_1.name); this.users = new Map(); this.policies = new Map(); this.auditEvents = []; this.encryptionKeys = new Map(); this.auditSubject = new rxjs_1.Subject(); this.authSubject = new rxjs_1.Subject(); this.complianceSubject = new rxjs_1.Subject(); this.keyRotationInterval = null; this.config = this.telescopeConfig.enterpriseSecurity || this.getDefaultSecurityConfig(); } async onModuleInit() { if (!this.config.enabled) { this.logger.log('Enterprise security disabled'); return; } await this.initializeSecurity(); this.startKeyRotation(); this.logger.log('Enterprise security service initialized'); } getDefaultSecurityConfig() { return { enabled: true, authentication: { enabled: true, methods: ['jwt'], jwt: { secret: process.env.JWT_SECRET || 'your-secret-key', expiresIn: '1h', refreshExpiresIn: '7d', }, oauth2: { providers: { google: undefined, github: undefined, azure: undefined, okta: undefined, }, }, saml: { enabled: false, entryPoint: '', issuer: '', cert: '', }, ldap: { enabled: false, url: '', bindDN: '', bindCredentials: '', searchBase: '', searchFilter: '', }, }, authorization: { enabled: true, rbac: true, abac: true, policies: [], }, encryption: { enabled: true, algorithm: 'aes-256-gcm', keyRotation: true, keyRotationInterval: 30, }, audit: { enabled: true, logLevel: 'detailed', retention: 90, compliance: ['gdpr', 'sox'], }, compliance: { gdpr: { enabled: true, dataRetention: 2555, rightToBeForgotten: true, dataPortability: true, }, sox: { enabled: true, auditTrail: true, accessControls: true, }, hipaa: { enabled: false, phiProtection: false, accessLogging: false, }, pci: { enabled: false, cardDataEncryption: false, tokenization: false, }, }, }; } async initializeSecurity() { await this.initializeEncryptionKeys(); await this.initializeDefaultPolicies(); await this.initializeDefaultUsers(); if (this.config.audit.enabled) { await this.initializeComplianceMonitoring(); } } async initializeEncryptionKeys() { if (!this.config.encryption.enabled) return; const masterKey = crypto.randomBytes(32); this.encryptionKeys.set('master', { key: masterKey, createdAt: new Date(), }); this.logger.log('Encryption keys initialized'); } async initializeDefaultPolicies() { if (!this.config.authorization.enabled) return; const defaultPolicies = [ { id: 'admin-full-access', name: 'Administrator Full Access', description: 'Full access for administrators', type: 'allow', resources: ['*'], actions: ['*'], conditions: [{ field: 'roles', operator: 'contains', value: 'admin' }], priority: 100, }, { id: 'user-read-only', name: 'User Read Only', description: 'Read-only access for regular users', type: 'allow', resources: ['telescope:read', 'telescope:metrics'], actions: ['read', 'view'], conditions: [{ field: 'roles', operator: 'contains', value: 'user' }], priority: 50, }, { id: 'deny-sensitive-data', name: 'Deny Sensitive Data Access', description: 'Deny access to sensitive data for non-admin users', type: 'deny', resources: ['telescope:admin', 'telescope:security'], actions: ['*'], conditions: [{ field: 'roles', operator: 'not_in', value: ['admin'] }], priority: 75, }, ]; for (const policy of defaultPolicies) { this.policies.set(policy.id, policy); } this.logger.log('Default security policies initialized'); } async initializeDefaultUsers() { const defaultUsers = [ { id: 'admin-1', username: 'admin', email: 'admin@telescope.com', firstName: 'System', lastName: 'Administrator', roles: ['admin'], permissions: ['*'], groups: ['administrators'], lastLogin: new Date(), isActive: true, metadata: {}, }, { id: 'user-1', username: 'user', email: 'user@telescope.com', firstName: 'Regular', lastName: 'User', roles: ['user'], permissions: ['telescope:read', 'telescope:metrics'], groups: ['users'], lastLogin: new Date(), isActive: true, metadata: {}, }, ]; for (const user of defaultUsers) { this.users.set(user.id, user); } this.logger.log('Default users initialized'); } async initializeComplianceMonitoring() { if (this.config.compliance.gdpr.enabled) { this.logger.log('GDPR compliance monitoring initialized'); } if (this.config.compliance.sox.enabled) { this.logger.log('SOX compliance monitoring initialized'); } if (this.config.compliance.hipaa.enabled) { this.logger.log('HIPAA compliance monitoring initialized'); } if (this.config.compliance.pci.enabled) { this.logger.log('PCI compliance monitoring initialized'); } } startKeyRotation() { if (!this.config.encryption.keyRotation) return; this.keyRotationInterval = (0, rxjs_1.interval)(this.config.encryption.keyRotationInterval * 24 * 60 * 60 * 1000).subscribe(async () => { await this.rotateEncryptionKeys(); }); } async authenticate(credentials) { const startTime = Date.now(); try { let result; switch (credentials.method) { case 'jwt': result = await this.authenticateJwt(credentials.token); break; case 'oauth2': result = await this.authenticateOAuth2(credentials.code); break; case 'saml': result = await this.authenticateSaml(credentials.token); break; case 'ldap': result = await this.authenticateLdap(credentials.username, credentials.password); break; default: result = { success: false, error: 'Unsupported authentication method', method: credentials.method, }; } await this.logAuditEvent({ userId: result.user?.id || 'unknown', action: 'authentication', resource: 'auth', result: result.success ? 'success' : 'failure', ipAddress: 'unknown', userAgent: 'unknown', metadata: { method: credentials.method, duration: Date.now() - startTime, }, }); this.authSubject.next(result); return result; } catch (error) { const result = { success: false, error: error.message, method: credentials.method, }; await this.logAuditEvent({ userId: 'unknown', action: 'authentication', resource: 'auth', result: 'failure', ipAddress: 'unknown', userAgent: 'unknown', metadata: { method: credentials.method, error: error.message }, }); this.authSubject.next(result); return result; } } async authenticateJwt(token) { try { const decoded = jwt.verify(token, this.config.authentication.jwt.secret); const user = this.users.get(decoded.userId); if (!user || !user.isActive) { return { success: false, error: 'Invalid or inactive user', method: 'jwt', }; } const newToken = jwt.sign({ userId: user.id, roles: user.roles }, this.config.authentication.jwt.secret, { expiresIn: this.config.authentication.jwt.expiresIn }); return { success: true, user, token: newToken, expiresAt: new Date(Date.now() + 60 * 60 * 1000), method: 'jwt', }; } catch (error) { return { success: false, error: 'Invalid JWT token', method: 'jwt', }; } } async authenticateOAuth2(code) { return { success: false, error: 'OAuth2 authentication not implemented', method: 'oauth2', }; } async authenticateSaml(token) { return { success: false, error: 'SAML authentication not implemented', method: 'saml', }; } async authenticateLdap(username, password) { return { success: false, error: 'LDAP authentication not implemented', method: 'ldap', }; } async authorize(userId, action, resource, context = {}) { const user = this.users.get(userId); if (!user || !user.isActive) { return { allowed: false, reason: 'User not found or inactive', policies: [], conditions: [], }; } const applicablePolicies = this.getApplicablePolicies(user, action, resource, context); const allowPolicies = applicablePolicies.filter((p) => p.type === 'allow'); const denyPolicies = applicablePolicies.filter((p) => p.type === 'deny'); for (const policy of denyPolicies) { if (this.evaluatePolicy(policy, user, context)) { await this.logAuditEvent({ userId, action, resource, result: 'denied', ipAddress: context.ipAddress || 'unknown', userAgent: context.userAgent || 'unknown', metadata: { policy: policy.id, reason: 'Policy denied access' }, }); return { allowed: false, reason: `Access denied by policy: ${policy.name}`, policies: [policy.id], conditions: policy.conditions, }; } } for (const policy of allowPolicies) { if (this.evaluatePolicy(policy, user, context)) { await this.logAuditEvent({ userId, action, resource, result: 'success', ipAddress: context.ipAddress || 'unknown', userAgent: context.userAgent || 'unknown', metadata: { policy: policy.id }, }); return { allowed: true, policies: [policy.id], conditions: policy.conditions, }; } } await this.logAuditEvent({ userId, action, resource, result: 'denied', ipAddress: context.ipAddress || 'unknown', userAgent: context.userAgent || 'unknown', metadata: { reason: 'No applicable allow policy' }, }); return { allowed: false, reason: 'No applicable allow policy found', policies: [], conditions: [], }; } getApplicablePolicies(user, action, resource, context) { return Array.from(this.policies.values()) .filter((policy) => { const resourceMatch = policy.resources.includes('*') || policy.resources.includes(resource) || policy.resources.some((r) => resource.startsWith(r)); const actionMatch = policy.actions.includes('*') || policy.actions.includes(action); return resourceMatch && actionMatch; }) .sort((a, b) => b.priority - a.priority); } evaluatePolicy(policy, user, context) { for (const condition of policy.conditions) { if (!this.evaluateCondition(condition, user, context)) { return false; } } return true; } evaluateCondition(condition, user, context) { let fieldValue; if (condition.field === 'roles') { fieldValue = user.roles; } else if (condition.field === 'permissions') { fieldValue = user.permissions; } else if (condition.field === 'groups') { fieldValue = user.groups; } else if (condition.field === 'tenantId') { fieldValue = user.tenantId; } else { fieldValue = context[condition.field]; } switch (condition.operator) { case 'equals': return fieldValue === condition.value; case 'not_equals': return fieldValue !== condition.value; case 'contains': return Array.isArray(fieldValue) ? fieldValue.includes(condition.value) : fieldValue?.includes(condition.value); case 'regex': return new RegExp(condition.value).test(fieldValue); case 'in': return Array.isArray(condition.value) ? condition.value.includes(fieldValue) : false; case 'not_in': return Array.isArray(condition.value) ? !condition.value.includes(fieldValue) : true; default: return false; } } async encrypt(data, keyId = 'master') { if (!this.config.encryption.enabled) { return data; } const keyData = this.encryptionKeys.get(keyId); if (!keyData) { throw new Error(`Encryption key not found: ${keyId}`); } const iv = crypto.randomBytes(16); const cipher = crypto.createCipher(this.config.encryption.algorithm, keyData.key); let encrypted = cipher.update(data, 'utf8', 'hex'); encrypted += cipher.final('hex'); return `${keyId}:${iv.toString('hex')}:${encrypted}`; } async decrypt(encryptedData) { if (!this.config.encryption.enabled) { return encryptedData; } const [keyId, ivHex, encrypted] = encryptedData.split(':'); const keyData = this.encryptionKeys.get(keyId); if (!keyData) { throw new Error(`Encryption key not found: ${keyId}`); } const iv = Buffer.from(ivHex, 'hex'); const decipher = crypto.createDecipher(this.config.encryption.algorithm, keyData.key); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } async rotateEncryptionKeys() { this.logger.log('Rotating encryption keys'); const newKey = crypto.randomBytes(32); this.encryptionKeys.set('master', { key: newKey, createdAt: new Date(), }); this.logger.log('Encryption keys rotated successfully'); } async logAuditEvent(event) { if (!this.config.audit.enabled) return; const auditEvent = { id: crypto.randomUUID(), timestamp: new Date(), ...event, compliance: { gdpr: this.config.compliance.gdpr.enabled, sox: this.config.compliance.sox.enabled, hipaa: this.config.compliance.hipaa.enabled, pci: this.config.compliance.pci.enabled, }, }; this.auditEvents.push(auditEvent); const cutoffDate = new Date(Date.now() - this.config.audit.retention * 24 * 60 * 60 * 1000); const recentEvents = this.auditEvents.filter((event) => event.timestamp > cutoffDate); this.auditEvents.length = 0; this.auditEvents.push(...recentEvents); this.auditSubject.next(auditEvent); } async generateComplianceReport() { const report = { gdpr: { compliant: true, issues: [], dataRetention: this.config.compliance.gdpr.dataRetention, dataSubjects: this.users.size, }, sox: { compliant: true, issues: [], auditTrail: this.config.compliance.sox.auditTrail, accessControls: this.config.compliance.sox.accessControls, }, hipaa: { compliant: true, issues: [], phiProtected: this.config.compliance.hipaa.phiProtection, accessLogged: this.config.compliance.hipaa.accessLogging, }, pci: { compliant: true, issues: [], cardDataEncrypted: this.config.compliance.pci.cardDataEncryption, tokenized: this.config.compliance.pci.tokenization, }, }; if (this.config.compliance.gdpr.enabled) { const gdprIssues = await this.checkGDPRCompliance(); report.gdpr.issues = gdprIssues; report.gdpr.compliant = gdprIssues.length === 0; } if (this.config.compliance.sox.enabled) { const soxIssues = await this.checkSOXCompliance(); report.sox.issues = soxIssues; report.sox.compliant = soxIssues.length === 0; } if (this.config.compliance.hipaa.enabled) { const hipaaIssues = await this.checkHIPAACompliance(); report.hipaa.issues = hipaaIssues; report.hipaa.compliant = hipaaIssues.length === 0; } if (this.config.compliance.pci.enabled) { const pciIssues = await this.checkPCICompliance(); report.pci.issues = pciIssues; report.pci.compliant = pciIssues.length === 0; } this.complianceSubject.next(report); return report; } async checkGDPRCompliance() { const issues = []; if (this.config.compliance.gdpr.dataRetention > 2555) { issues.push('Data retention period exceeds GDPR requirements'); } if (!this.config.compliance.gdpr.rightToBeForgotten) { issues.push('Right to be forgotten not implemented'); } if (!this.config.compliance.gdpr.dataPortability) { issues.push('Data portability not implemented'); } return issues; } async checkSOXCompliance() { const issues = []; if (!this.config.compliance.sox.auditTrail) { issues.push('Audit trail not enabled'); } if (!this.config.compliance.sox.accessControls) { issues.push('Access controls not properly configured'); } return issues; } async checkHIPAACompliance() { const issues = []; if (!this.config.compliance.hipaa.phiProtection) { issues.push('PHI protection not enabled'); } if (!this.config.compliance.hipaa.accessLogging) { issues.push('Access logging not enabled'); } return issues; } async checkPCICompliance() { const issues = []; if (!this.config.compliance.pci.cardDataEncryption) { issues.push('Card data encryption not enabled'); } if (!this.config.compliance.pci.tokenization) { issues.push('Tokenization not enabled'); } return issues; } getUsers() { return Array.from(this.users.values()); } getUserById(userId) { return this.users.get(userId); } async createUser(userData) { const user = { ...userData, id: crypto.randomUUID(), lastLogin: new Date(), }; this.users.set(user.id, user); return user; } async updateUser(userId, updates) { const user = this.users.get(userId); if (!user) return null; const updatedUser = { ...user, ...updates }; this.users.set(userId, updatedUser); return updatedUser; } async deleteUser(userId) { return this.users.delete(userId); } getPolicies() { return Array.from(this.policies.values()); } async createPolicy(policy) { const newPolicy = { ...policy, id: crypto.randomUUID(), }; this.policies.set(newPolicy.id, newPolicy); return newPolicy; } async updatePolicy(policyId, updates) { const policy = this.policies.get(policyId); if (!policy) return null; const updatedPolicy = { ...policy, ...updates }; this.policies.set(policyId, updatedPolicy); return updatedPolicy; } async deletePolicy(policyId) { return this.policies.delete(policyId); } getAuditEvents() { return [...this.auditEvents]; } getAuthenticationUpdates() { return this.authSubject.asObservable(); } getAuditUpdates() { return this.auditSubject.asObservable(); } getComplianceUpdates() { return this.complianceSubject.asObservable(); } async shutdown() { if (this.keyRotationInterval) { clearInterval(this.keyRotationInterval); } this.logger.log('Enterprise security service shutdown'); } }; exports.EnterpriseSecurityService = EnterpriseSecurityService; exports.EnterpriseSecurityService = EnterpriseSecurityService = EnterpriseSecurityService_1 = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_2.Inject)('TELESCOPE_CONFIG')), __metadata("design:paramtypes", [Object]) ], EnterpriseSecurityService); //# sourceMappingURL=enterprise-security.service.js.map