@dimzxzzx07/file-watcher 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/.env +13 -0
  2. package/.eslintrc.json +128 -0
  3. package/.prettierrc +18 -0
  4. package/Dimzxzzx07.png +0 -0
  5. package/README.md +1024 -0
  6. package/dist/core/BackupManager.d.ts +25 -0
  7. package/dist/core/BackupManager.d.ts.map +1 -0
  8. package/dist/core/BackupManager.js +290 -0
  9. package/dist/core/BackupManager.js.map +1 -0
  10. package/dist/core/IntegrityValidator.d.ts +18 -0
  11. package/dist/core/IntegrityValidator.d.ts.map +1 -0
  12. package/dist/core/IntegrityValidator.js +212 -0
  13. package/dist/core/IntegrityValidator.js.map +1 -0
  14. package/dist/core/SecurityManager.d.ts +40 -0
  15. package/dist/core/SecurityManager.d.ts.map +1 -0
  16. package/dist/core/SecurityManager.js +320 -0
  17. package/dist/core/SecurityManager.js.map +1 -0
  18. package/dist/core/WatcherEngine.d.ts +44 -0
  19. package/dist/core/WatcherEngine.d.ts.map +1 -0
  20. package/dist/core/WatcherEngine.js +470 -0
  21. package/dist/core/WatcherEngine.js.map +1 -0
  22. package/dist/crypto/HashGenerator.d.ts +26 -0
  23. package/dist/crypto/HashGenerator.d.ts.map +1 -0
  24. package/dist/crypto/HashGenerator.js +220 -0
  25. package/dist/crypto/HashGenerator.js.map +1 -0
  26. package/dist/crypto/KeyManager.d.ts +30 -0
  27. package/dist/crypto/KeyManager.d.ts.map +1 -0
  28. package/dist/crypto/KeyManager.js +235 -0
  29. package/dist/crypto/KeyManager.js.map +1 -0
  30. package/dist/crypto/SignatureValidator.d.ts +11 -0
  31. package/dist/crypto/SignatureValidator.d.ts.map +1 -0
  32. package/dist/crypto/SignatureValidator.js +102 -0
  33. package/dist/crypto/SignatureValidator.js.map +1 -0
  34. package/dist/detectors/AnomalyDetector.d.ts +24 -0
  35. package/dist/detectors/AnomalyDetector.d.ts.map +1 -0
  36. package/dist/detectors/AnomalyDetector.js +209 -0
  37. package/dist/detectors/AnomalyDetector.js.map +1 -0
  38. package/dist/detectors/InjectionDetector.d.ts +14 -0
  39. package/dist/detectors/InjectionDetector.d.ts.map +1 -0
  40. package/dist/detectors/InjectionDetector.js +204 -0
  41. package/dist/detectors/InjectionDetector.js.map +1 -0
  42. package/dist/detectors/PatternMatcher.d.ts +28 -0
  43. package/dist/detectors/PatternMatcher.d.ts.map +1 -0
  44. package/dist/detectors/PatternMatcher.js +283 -0
  45. package/dist/detectors/PatternMatcher.js.map +1 -0
  46. package/dist/guards/FileGuard.d.ts +35 -0
  47. package/dist/guards/FileGuard.d.ts.map +1 -0
  48. package/dist/guards/FileGuard.js +357 -0
  49. package/dist/guards/FileGuard.js.map +1 -0
  50. package/dist/guards/MemoryGuard.d.ts +28 -0
  51. package/dist/guards/MemoryGuard.d.ts.map +1 -0
  52. package/dist/guards/MemoryGuard.js +256 -0
  53. package/dist/guards/MemoryGuard.js.map +1 -0
  54. package/dist/guards/ProcessGuard.d.ts +25 -0
  55. package/dist/guards/ProcessGuard.d.ts.map +1 -0
  56. package/dist/guards/ProcessGuard.js +221 -0
  57. package/dist/guards/ProcessGuard.js.map +1 -0
  58. package/dist/index.d.ts +19 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +186 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/types/index.d.ts +69 -0
  63. package/dist/types/index.d.ts.map +1 -0
  64. package/dist/types/index.js +3 -0
  65. package/dist/types/index.js.map +1 -0
  66. package/dist/utils/Constants.d.ts +407 -0
  67. package/dist/utils/Constants.d.ts.map +1 -0
  68. package/dist/utils/Constants.js +505 -0
  69. package/dist/utils/Constants.js.map +1 -0
  70. package/dist/utils/Logger.d.ts +45 -0
  71. package/dist/utils/Logger.d.ts.map +1 -0
  72. package/dist/utils/Logger.js +285 -0
  73. package/dist/utils/Logger.js.map +1 -0
  74. package/dist/utils/Validator.d.ts +27 -0
  75. package/dist/utils/Validator.d.ts.map +1 -0
  76. package/dist/utils/Validator.js +245 -0
  77. package/dist/utils/Validator.js.map +1 -0
  78. package/favicon.png +0 -0
  79. package/jest.config.js +69 -0
  80. package/package.json +69 -0
  81. package/src/core/BackupManager.ts +305 -0
  82. package/src/core/IntegrityValidator.ts +200 -0
  83. package/src/core/SecurityManager.ts +348 -0
  84. package/src/core/WatcherEngine.ts +537 -0
  85. package/src/crypto/HashGenerator.ts +234 -0
  86. package/src/crypto/KeyManager.ts +249 -0
  87. package/src/crypto/SignatureValidator.ts +76 -0
  88. package/src/detectors/AnomalyDetector.ts +247 -0
  89. package/src/detectors/InjectionDetector.ts +233 -0
  90. package/src/detectors/PatternMatcher.ts +319 -0
  91. package/src/guards/FileGuard.ts +385 -0
  92. package/src/guards/MemoryGuard.ts +263 -0
  93. package/src/guards/ProcessGuard.ts +219 -0
  94. package/src/index.ts +189 -0
  95. package/src/types/index.ts +72 -0
  96. package/src/utils/Constants.ts +532 -0
  97. package/src/utils/Logger.ts +279 -0
  98. package/src/utils/Validator.ts +248 -0
  99. package/tests/setup.ts +80 -0
  100. package/tsconfig.json +42 -0
@@ -0,0 +1,537 @@
1
+ import * as chokidar from 'chokidar';
2
+ import * as fs from 'fs/promises';
3
+ import * as path from 'path';
4
+ import { EventEmitter } from 'events';
5
+ import { SecurityConfig, FileMetadata, IntegrityViolation } from '../types';
6
+ import { IntegrityValidator } from './IntegrityValidator';
7
+ import { SecurityManager } from './SecurityManager';
8
+ import { BackupManager } from './BackupManager';
9
+ import { Logger } from '../utils/Logger';
10
+ import { ProcessGuard } from '../guards/ProcessGuard';
11
+
12
+ export class WatcherEngine extends EventEmitter {
13
+ private watcher: chokidar.FSWatcher | null = null;
14
+ private readonly config: SecurityConfig;
15
+ private readonly validator: IntegrityValidator;
16
+ private readonly securityManager: SecurityManager;
17
+ private readonly backupManager: BackupManager;
18
+ private readonly logger: Logger;
19
+ private readonly processGuard: ProcessGuard;
20
+ private readonly fileCache: Map<string, FileMetadata>;
21
+ private readonly watchState: Map<string, boolean>;
22
+ private isShuttingDown: boolean = false;
23
+ private scanInterval: NodeJS.Timeout | null = null;
24
+
25
+ constructor(config: SecurityConfig) {
26
+ super();
27
+ this.config = config;
28
+ this.fileCache = new Map();
29
+ this.watchState = new Map();
30
+ this.logger = Logger.getInstance();
31
+ this.validator = new IntegrityValidator(config);
32
+ this.securityManager = SecurityManager.getInstance(config);
33
+ this.backupManager = new BackupManager(config);
34
+ this.processGuard = ProcessGuard.getInstance();
35
+
36
+ this.initialize();
37
+ }
38
+
39
+ private async initialize(): Promise<void> {
40
+ try {
41
+ await this.verifyEnvironment();
42
+ await this.initializeDirectories();
43
+ await this.loadExistingFiles();
44
+ await this.establishSecureConnection();
45
+ this.startSelfProtection();
46
+
47
+ this.logger.info('WatcherEngine initialized successfully', {
48
+ watchDir: this.config.watchDir,
49
+ integrityLevel: this.config.integrityLevel
50
+ });
51
+ } catch (error) {
52
+ this.logger.error('Failed to initialize WatcherEngine', { error });
53
+ throw error;
54
+ }
55
+ }
56
+
57
+ private async verifyEnvironment(): Promise<void> {
58
+ if (process.version < 'v18.0.0') {
59
+ throw new Error('Node.js version 18+ required');
60
+ }
61
+
62
+ if (process.execArgv.some(arg => arg.includes('--inspect'))) {
63
+ this.logger.warning('Debugger detected - running in secure mode');
64
+ this.securityManager.setDebugMode(true);
65
+ }
66
+
67
+ try {
68
+ await fs.access(this.config.watchDir, fs.constants.R_OK | fs.constants.W_OK);
69
+ } catch {
70
+ throw new Error(`Insufficient permissions for ${this.config.watchDir}`);
71
+ }
72
+ }
73
+
74
+ private async initializeDirectories(): Promise<void> {
75
+ const dirs = [
76
+ this.config.backupDir,
77
+ this.config.quarantineDir,
78
+ path.join(this.config.watchDir, '.secure')
79
+ ];
80
+
81
+ for (const dir of dirs) {
82
+ try {
83
+ await fs.mkdir(dir, { recursive: true, mode: 0o700 });
84
+ } catch (error) {
85
+ this.logger.error(`Failed to create directory: ${dir}`, { error });
86
+ }
87
+ }
88
+ }
89
+
90
+ private async loadExistingFiles(): Promise<void> {
91
+ const files = await this.scanDirectory(this.config.watchDir);
92
+
93
+ for (const file of files) {
94
+ try {
95
+ const metadata = await this.validator.generateFileMetadata(file);
96
+ this.fileCache.set(file, metadata);
97
+
98
+ await this.backupManager.createBackup(file, metadata);
99
+
100
+ const isValid = await this.validator.validateFile(file, metadata);
101
+ if (!isValid) {
102
+ this.handleIntegrityViolation({
103
+ id: crypto.randomUUID(),
104
+ timestamp: new Date(),
105
+ filePath: file,
106
+ violationType: 'hash_mismatch',
107
+ severity: 'high',
108
+ details: { initialValidation: false },
109
+ actionTaken: 'alert'
110
+ });
111
+ }
112
+ } catch (error) {
113
+ this.logger.error(`Failed to load file: ${file}`, { error });
114
+ }
115
+ }
116
+
117
+ this.logger.info(`Loaded ${this.fileCache.size} files into cache`);
118
+ }
119
+
120
+ private async scanDirectory(dir: string): Promise<string[]> {
121
+ const files: string[] = [];
122
+
123
+ try {
124
+ const entries = await fs.readdir(dir, { withFileTypes: true });
125
+
126
+ for (const entry of entries) {
127
+ const fullPath = path.join(dir, entry.name);
128
+
129
+ if (this.shouldIgnore(fullPath)) {
130
+ continue;
131
+ }
132
+
133
+ if (entry.isDirectory()) {
134
+ files.push(...await this.scanDirectory(fullPath));
135
+ } else if (entry.isFile()) {
136
+ files.push(fullPath);
137
+ }
138
+ }
139
+ } catch (error) {
140
+ this.logger.error(`Error scanning directory: ${dir}`, { error });
141
+ }
142
+
143
+ return files;
144
+ }
145
+
146
+ private shouldIgnore(filePath: string): boolean {
147
+ const ignorePatterns = [
148
+ /node_modules/,
149
+ /\.git/,
150
+ /\.secure/,
151
+ /\.backup/,
152
+ /\.quarantine/,
153
+ /\.DS_Store/,
154
+ /Thumbs\.db/,
155
+ /\.tmp$/,
156
+ /\.temp$/,
157
+ /\.log$/
158
+ ];
159
+
160
+ return ignorePatterns.some(pattern => pattern.test(filePath));
161
+ }
162
+
163
+ private async establishSecureConnection(): Promise<void> {
164
+ const secureChannel = await this.securityManager.createSecureChannel();
165
+ this.emit('secure:connected', secureChannel);
166
+ }
167
+
168
+ private startSelfProtection(): void {
169
+ this.processGuard.protectProcess();
170
+
171
+ setInterval(() => {
172
+ this.securityManager.validateMemoryIntegrity();
173
+ }, 5000);
174
+
175
+ setInterval(() => {
176
+ if (this.processGuard.detectDebugger()) {
177
+ this.emit('security:debugger-detected');
178
+ }
179
+ }, 1000);
180
+ }
181
+
182
+ public startWatching(): void {
183
+ if (this.watcher) {
184
+ return;
185
+ }
186
+
187
+ const watchOptions: chokidar.WatchOptions = {
188
+ ignored: (file: string) => this.shouldIgnore(file),
189
+ persistent: true,
190
+ ignoreInitial: true,
191
+ followSymlinks: false,
192
+ usePolling: true,
193
+ interval: 100,
194
+ binaryInterval: 300,
195
+ awaitWriteFinish: {
196
+ stabilityThreshold: 200,
197
+ pollInterval: 50
198
+ }
199
+ };
200
+
201
+ this.watcher = chokidar.watch(this.config.watchDir, watchOptions);
202
+
203
+ this.watcher
204
+ .on('add', (filePath: string) => this.handleFileAdd(filePath))
205
+ .on('change', (filePath: string) => this.handleFileChange(filePath))
206
+ .on('unlink', (filePath: string) => this.handleFileDelete(filePath))
207
+ .on('error', (error: Error) => this.handleWatcherError(error));
208
+
209
+ if (this.config.scanInterval > 0) {
210
+ this.scanInterval = setInterval(
211
+ () => this.performSecurityScan(),
212
+ this.config.scanInterval * 1000
213
+ );
214
+ }
215
+
216
+ this.logger.info('File watcher started successfully');
217
+ }
218
+
219
+ private async handleFileAdd(filePath: string): Promise<void> {
220
+ this.logger.info(`New file detected: ${filePath}`);
221
+
222
+ try {
223
+ if (!this.isAllowedFileType(filePath)) {
224
+ await this.handleDisallowedFile(filePath);
225
+ return;
226
+ }
227
+
228
+ const metadata = await this.validator.generateFileMetadata(filePath);
229
+
230
+ const isClean = await this.securityManager.scanFile(filePath);
231
+ if (!isClean) {
232
+ await this.handleInfectedFile(filePath);
233
+ return;
234
+ }
235
+
236
+ await this.backupManager.createBackup(filePath, metadata);
237
+
238
+ this.fileCache.set(filePath, metadata);
239
+
240
+ if (this.config.signatureVerification) {
241
+ const isValid = await this.validator.verifySignature(filePath, metadata);
242
+ if (!isValid) {
243
+ throw new Error('Invalid file signature');
244
+ }
245
+ }
246
+
247
+ this.emit('file:added', { filePath, metadata });
248
+
249
+ } catch (error) {
250
+ this.logger.error(`Error handling new file: ${filePath}`, { error });
251
+ await this.handleSuspiciousFile(filePath, error);
252
+ }
253
+ }
254
+
255
+ private async handleFileChange(filePath: string): Promise<void> {
256
+ this.logger.info(`File modified: ${filePath}`);
257
+
258
+ try {
259
+ const oldMetadata = this.fileCache.get(filePath);
260
+
261
+ if (!oldMetadata) {
262
+ await this.handleFileAdd(filePath);
263
+ return;
264
+ }
265
+
266
+ const newMetadata = await this.validator.generateFileMetadata(filePath);
267
+
268
+ const isAuthorized = await this.securityManager.isAuthorizedChange(
269
+ filePath,
270
+ oldMetadata,
271
+ newMetadata
272
+ );
273
+
274
+ if (!isAuthorized) {
275
+ throw new Error('Unauthorized file modification');
276
+ }
277
+
278
+ const isValid = await this.validator.validateFile(filePath, newMetadata);
279
+
280
+ if (!isValid) {
281
+ if (this.config.autoRollback) {
282
+ await this.backupManager.rollbackFile(filePath);
283
+ this.logger.info(`File rolled back: ${filePath}`);
284
+ } else {
285
+ throw new Error('Integrity check failed');
286
+ }
287
+ } else {
288
+ this.fileCache.set(filePath, newMetadata);
289
+
290
+ await this.backupManager.updateBackup(filePath, newMetadata);
291
+
292
+ this.emit('file:changed', { filePath, oldMetadata, newMetadata });
293
+ }
294
+
295
+ } catch (error) {
296
+ this.logger.error(`Error handling file change: ${filePath}`, { error });
297
+ await this.handleIntegrityViolation({
298
+ id: crypto.randomUUID(),
299
+ timestamp: new Date(),
300
+ filePath,
301
+ violationType: 'hash_mismatch',
302
+ severity: 'high',
303
+ details: { error },
304
+ actionTaken: this.config.autoRollback ? 'rollback' : 'alert'
305
+ });
306
+ }
307
+ }
308
+
309
+ private async handleFileDelete(filePath: string): Promise<void> {
310
+ this.logger.warning(`File deleted: ${filePath}`);
311
+
312
+ try {
313
+ const metadata = this.fileCache.get(filePath);
314
+
315
+ if (metadata) {
316
+ const restored = await this.backupManager.restoreFile(filePath);
317
+
318
+ if (restored) {
319
+ this.logger.info(`File restored from backup: ${filePath}`);
320
+
321
+ const restoredMetadata = await this.validator.generateFileMetadata(filePath);
322
+ this.fileCache.set(filePath, restoredMetadata);
323
+
324
+ this.emit('file:restored', { filePath, metadata: restoredMetadata });
325
+ } else {
326
+ this.fileCache.delete(filePath);
327
+ this.emit('file:deleted', { filePath, metadata });
328
+ }
329
+ }
330
+
331
+ } catch (error) {
332
+ this.logger.error(`Error handling file deletion: ${filePath}`, { error });
333
+ }
334
+ }
335
+
336
+ private async handleIntegrityViolation(violation: IntegrityViolation): Promise<void> {
337
+ this.logger.critical('Integrity violation detected', violation);
338
+
339
+ if (violation.severity === 'critical' || violation.severity === 'high') {
340
+ await this.quarantineFile(violation.filePath);
341
+ }
342
+
343
+ this.emit('integrity:violation', violation);
344
+
345
+ switch (violation.severity) {
346
+ case 'critical':
347
+ await this.handleCriticalViolation(violation);
348
+ break;
349
+ case 'high':
350
+ await this.handleHighSeverityViolation(violation);
351
+ break;
352
+ default:
353
+ await this.handleLowSeverityViolation(violation);
354
+ }
355
+ }
356
+
357
+ private async quarantineFile(filePath: string): Promise<void> {
358
+ try {
359
+ const quarantinePath = path.join(
360
+ this.config.quarantineDir,
361
+ path.basename(filePath) + '.quarantined'
362
+ );
363
+
364
+ await fs.copyFile(filePath, quarantinePath);
365
+
366
+ await this.securityManager.encryptFile(quarantinePath);
367
+
368
+ this.logger.info(`File quarantined: ${filePath} -> ${quarantinePath}`);
369
+
370
+ if (this.config.integrityLevel === 'paranoid') {
371
+ await fs.unlink(filePath);
372
+ }
373
+
374
+ } catch (error) {
375
+ this.logger.error(`Failed to quarantine file: ${filePath}`, { error });
376
+ }
377
+ }
378
+
379
+ private async handleCriticalViolation(violation: IntegrityViolation): Promise<void> {
380
+ this.logger.emergency('Critical security violation - initiating shutdown');
381
+
382
+ this.stopWatching();
383
+
384
+ this.emit('security:critical', violation);
385
+
386
+ await this.performSecureShutdown();
387
+
388
+ process.exit(1);
389
+ }
390
+
391
+ private async handleHighSeverityViolation(violation: IntegrityViolation): Promise<void> {
392
+ this.watchState.set(violation.filePath, false);
393
+
394
+ if (this.config.autoRollback) {
395
+ const restored = await this.backupManager.rollbackFile(violation.filePath);
396
+ if (restored) {
397
+ this.logger.info(`File rolled back successfully: ${violation.filePath}`);
398
+ this.watchState.delete(violation.filePath);
399
+ }
400
+ }
401
+
402
+ this.emit('security:alert', violation);
403
+ }
404
+
405
+ private async handleLowSeverityViolation(violation: IntegrityViolation): Promise<void> {
406
+ this.logger.warning('Low severity violation', violation);
407
+ this.emit('security:warning', violation);
408
+ }
409
+
410
+ private async handleSuspiciousFile(filePath: string, error: any): Promise<void> {
411
+ this.logger.warning(`Suspicious file detected: ${filePath}`, { error });
412
+
413
+ await this.quarantineFile(filePath);
414
+
415
+ this.emit('file:suspicious', { filePath, error });
416
+ }
417
+
418
+ private async handleInfectedFile(filePath: string): Promise<void> {
419
+ this.logger.critical(`Infected file detected: ${filePath}`);
420
+
421
+ await this.quarantineFile(filePath);
422
+
423
+ this.emit('security:infected', { filePath });
424
+ }
425
+
426
+ private async handleDisallowedFile(filePath: string): Promise<void> {
427
+ this.logger.warning(`Disallowed file type: ${filePath}`);
428
+
429
+ if (this.config.integrityLevel === 'paranoid') {
430
+ await fs.unlink(filePath);
431
+ this.logger.info(`Disallowed file deleted: ${filePath}`);
432
+ }
433
+
434
+ this.emit('file:disallowed', { filePath });
435
+ }
436
+
437
+ private isAllowedFileType(filePath: string): boolean {
438
+ const ext = path.extname(filePath).toLowerCase();
439
+ return this.config.allowedExtensions.includes(ext);
440
+ }
441
+
442
+ private handleWatcherError(error: Error): void {
443
+ this.logger.error('Watcher error', { error });
444
+ this.emit('watcher:error', error);
445
+ }
446
+
447
+ private async performSecurityScan(): Promise<void> {
448
+ this.logger.debug('Performing security scan...');
449
+
450
+ for (const [filePath, metadata] of this.fileCache.entries()) {
451
+ try {
452
+ const isValid = await this.validator.validateFile(filePath, metadata);
453
+
454
+ if (!isValid) {
455
+ await this.handleIntegrityViolation({
456
+ id: crypto.randomUUID(),
457
+ timestamp: new Date(),
458
+ filePath,
459
+ violationType: 'hash_mismatch',
460
+ severity: 'high',
461
+ details: { scan: 'periodic' },
462
+ actionTaken: 'alert'
463
+ });
464
+ }
465
+
466
+ if (!await this.fileExists(filePath)) {
467
+ await this.handleFileDelete(filePath);
468
+ }
469
+
470
+ } catch (error) {
471
+ this.logger.error(`Scan error for ${filePath}`, { error });
472
+ }
473
+ }
474
+
475
+ const allFiles = await this.scanDirectory(this.config.watchDir);
476
+ for (const file of allFiles) {
477
+ if (!this.fileCache.has(file)) {
478
+ await this.handleFileAdd(file);
479
+ }
480
+ }
481
+
482
+ this.logger.debug('Security scan completed');
483
+ }
484
+
485
+ private async fileExists(filePath: string): Promise<boolean> {
486
+ try {
487
+ await fs.access(filePath);
488
+ return true;
489
+ } catch {
490
+ return false;
491
+ }
492
+ }
493
+
494
+ private async performSecureShutdown(): Promise<void> {
495
+ this.isShuttingDown = true;
496
+
497
+ this.logger.info('Performing secure shutdown...');
498
+
499
+ this.stopWatching();
500
+
501
+ await this.securityManager.encryptSensitiveData();
502
+
503
+ this.fileCache.clear();
504
+ this.watchState.clear();
505
+
506
+ await this.backupManager.performFinalBackup();
507
+
508
+ this.logger.info('Secure shutdown completed');
509
+ }
510
+
511
+ public stopWatching(): void {
512
+ if (this.scanInterval) {
513
+ clearInterval(this.scanInterval);
514
+ this.scanInterval = null;
515
+ }
516
+
517
+ if (this.watcher) {
518
+ this.watcher.close();
519
+ this.watcher = null;
520
+ }
521
+
522
+ this.logger.info('File watcher stopped');
523
+ }
524
+
525
+ public getStatus(): any {
526
+ return {
527
+ watching: this.watcher !== null,
528
+ filesWatched: this.fileCache.size,
529
+ cacheSize: this.fileCache.size,
530
+ scanInterval: this.config.scanInterval,
531
+ integrityLevel: this.config.integrityLevel,
532
+ uptime: process.uptime(),
533
+ memoryUsage: process.memoryUsage(),
534
+ isShuttingDown: this.isShuttingDown
535
+ };
536
+ }
537
+ }