cybersentinel-cli 1.0.1 → 1.0.4

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 (2) hide show
  1. package/bin/index.js +208 -3
  2. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -72,7 +72,21 @@ $ s*" .u@*"" '""\\dP"
72
72
  """"* RL d>
73
73
  "$u. .$
74
74
  ^"*bo@" tony
75
- `) + "\n" + chalk.green.bold(' CYBERSENTINEL - Audit Platform CLI\n');
75
+ `) + "\n" +
76
+ chalk.green.bold('================================================================================\n') +
77
+ chalk.green.bold(' CYBERSENTINEL - Audit Platform CLI\n') +
78
+ chalk.green.bold('================================================================================\n') +
79
+ chalk.green('INTRODUCTION & PURPOSE:\n') +
80
+ chalk.white(' CyberSentinel CLI is a secure, interactive terminal-based auditing gateway\n') +
81
+ chalk.white(' designed for white-hat penetration testers and compliance officers. It executes\n') +
82
+ chalk.white(' automated vulnerability assessments, facilitates manual control checkpoints, and\n') +
83
+ chalk.white(' synchronizes verified ratings and uploads directly to the management database.\n\n') +
84
+ chalk.green('CREATOR & LEAD DEVELOPER:\n') +
85
+ chalk.white(' Engr. Brian Perez\n\n') +
86
+ chalk.green('PROPRIETARY LICENSE & COPYRIGHT:\n') +
87
+ chalk.white(' This software package and its distribution binaries are exclusively owned by\n') +
88
+ chalk.white(' the Inspire Alliance Fund Group Incorporated. All rights reserved.\n') +
89
+ chalk.green.bold('================================================================================\n');
76
90
 
77
91
  const SNAKE_SPINNER = {
78
92
  interval: 100,
@@ -122,6 +136,36 @@ function getMtlsClient(config) {
122
136
  });
123
137
  }
124
138
 
139
+ // Wait for user to decide to quit by pressing Ctrl + C or /exit command
140
+ async function waitToExit() {
141
+ console.log(chalk.gray('\n=================================================='));
142
+ console.log(chalk.green('Task execution complete. Session remains active.'));
143
+ console.log(chalk.green('Type "/exit" or press Ctrl+C to close the connection and exit.'));
144
+ console.log(chalk.gray('==================================================\n'));
145
+
146
+ const readline = require('readline');
147
+ const rl = readline.createInterface({
148
+ input: process.stdin,
149
+ output: process.stdout
150
+ });
151
+
152
+ return new Promise((resolve) => {
153
+ const ask = () => {
154
+ rl.question(chalk.green('cybersentinel> '), (answer) => {
155
+ if (answer.trim() === '/exit') {
156
+ console.log(chalk.yellow('Closing session...'));
157
+ rl.close();
158
+ process.exit(0);
159
+ } else {
160
+ console.log(chalk.gray(`Unknown command "${answer.trim()}". Type "/exit" to quit.`));
161
+ ask();
162
+ }
163
+ });
164
+ };
165
+ ask();
166
+ });
167
+ }
168
+
125
169
  // Print startup banner
126
170
  console.log(VIPER_BANNER);
127
171
 
@@ -253,13 +297,25 @@ program
253
297
  console.log(chalk.green(`Files saved to: ${CONFIG_DIR}`));
254
298
  console.log(chalk.green(`PKCS12 Container: client.p12 (encrypted)\n`));
255
299
 
300
+ await waitToExit();
256
301
  } catch (error) {
257
302
  spinner.fail(chalk.red('Registration failed!'));
258
303
  if (error.response) {
259
- console.error(chalk.red(`Error: ${error.response.status} - ${error.response.data.message || error.response.data.error}`));
304
+ let msg = '';
305
+ if (typeof error.response.data === 'string') {
306
+ if (error.response.data.includes('The plain HTTP request was sent to HTTPS port')) {
307
+ msg = 'Plain HTTP request was sent to an HTTPS port. Please use "https://" instead of "http://".';
308
+ } else {
309
+ msg = error.response.data.substring(0, 150);
310
+ }
311
+ } else {
312
+ msg = error.response.data.message || error.response.data.error || JSON.stringify(error.response.data);
313
+ }
314
+ console.error(chalk.red(`Error: ${error.response.status} - ${msg}`));
260
315
  } else {
261
316
  console.error(chalk.red(`Error: ${error.message}`));
262
317
  }
318
+ await waitToExit();
263
319
  }
264
320
  });
265
321
 
@@ -267,7 +323,7 @@ program
267
323
  program
268
324
  .command('init')
269
325
  .description('Verify credential certificate files status')
270
- .action(() => {
326
+ .action(async () => {
271
327
  if (hasCertificates()) {
272
328
  try {
273
329
  const config = loadConfig();
@@ -282,6 +338,7 @@ program
282
338
  console.log(chalk.yellow('⚠ No active client certificate found. Please run:'));
283
339
  console.log(chalk.cyan(' cybersentinel register'));
284
340
  }
341
+ await waitToExit();
285
342
  });
286
343
 
287
344
  // Command: audit
@@ -293,6 +350,7 @@ program
293
350
  .action(async (options) => {
294
351
  if (!hasCertificates()) {
295
352
  console.error(chalk.red('Error: Local certificate files not found. Run "cybersentinel register" first.'));
353
+ await waitToExit();
296
354
  process.exit(1);
297
355
  }
298
356
 
@@ -301,6 +359,7 @@ program
301
359
  config = loadConfig();
302
360
  } catch (err) {
303
361
  console.error(chalk.red(err.message));
362
+ await waitToExit();
304
363
  process.exit(1);
305
364
  }
306
365
 
@@ -325,6 +384,7 @@ program
325
384
  } else {
326
385
  console.error(chalk.red(`Connection error: ${err.message}`));
327
386
  }
387
+ await waitToExit();
328
388
  process.exit(1);
329
389
  }
330
390
 
@@ -473,6 +533,29 @@ program
473
533
  console.log(chalk.gray(`Current: Rating: ${currentVal.rating} | Notes: ${currentVal.notes}`));
474
534
  }
475
535
 
536
+ const actionPrompt = await inquirer.prompt([
537
+ {
538
+ type: 'list',
539
+ name: 'action',
540
+ message: 'Choose action for this checkpoint:',
541
+ choices: [
542
+ { name: 'Audit / Rate this item', value: 'audit' },
543
+ { name: 'Skip this item', value: 'skip' },
544
+ { name: chalk.yellow('Exit & Save Session'), value: 'exit' }
545
+ ]
546
+ }
547
+ ]);
548
+
549
+ if (actionPrompt.action === 'exit') {
550
+ console.log(chalk.yellow('\n✔ Session progress saved. Exiting audit session. Goodbye!'));
551
+ process.exit(0);
552
+ }
553
+
554
+ if (actionPrompt.action === 'skip') {
555
+ console.log(chalk.gray(`Skipping item ${item.id}.`));
556
+ continue;
557
+ }
558
+
476
559
  const itemAnswers = await inquirer.prompt([
477
560
  {
478
561
  type: 'list',
@@ -554,6 +637,128 @@ program
554
637
  }
555
638
 
556
639
  console.log(chalk.green.bold(`\n✔ Completed Category ${selectedCategory.id} Audit!\n`));
640
+ await waitToExit();
641
+ });
642
+
643
+ function startProxyServer(port, targetFilter) {
644
+ const http = require('http');
645
+ const net = require('net');
646
+ const url = require('url');
647
+
648
+ const server = http.createServer((req, res) => {
649
+ try {
650
+ const parsedUrl = url.parse(req.url);
651
+ const host = req.headers.host || '';
652
+
653
+ const shouldLog = !targetFilter || host.includes(targetFilter);
654
+ if (shouldLog) {
655
+ console.log(chalk.green(`[HTTP Request] ${req.method} ${req.url}`));
656
+ }
657
+
658
+ const options = {
659
+ hostname: parsedUrl.hostname || host.split(':')[0],
660
+ port: parsedUrl.port || 80,
661
+ path: parsedUrl.path,
662
+ method: req.method,
663
+ headers: req.headers
664
+ };
665
+
666
+ const proxyReq = http.request(options, (proxyRes) => {
667
+ if (shouldLog) {
668
+ console.log(chalk.cyan(`[HTTP Response] ${req.method} ${req.url} -> Status: ${proxyRes.statusCode}`));
669
+ }
670
+ res.writeHead(proxyRes.statusCode, proxyRes.headers);
671
+ proxyRes.pipe(res);
672
+ });
673
+
674
+ proxyReq.on('error', (err) => {
675
+ if (shouldLog) {
676
+ console.error(chalk.red(`[HTTP Error] ${req.method} ${req.url} -> Error: ${err.message}`));
677
+ }
678
+ res.writeHead(502);
679
+ res.end(`Proxy Gateway Error: ${err.message}`);
680
+ });
681
+
682
+ req.pipe(proxyReq);
683
+ } catch (err) {
684
+ console.error(chalk.red(`Proxy Request Handler Error: ${err.message}`));
685
+ }
686
+ });
687
+
688
+ server.on('connect', (req, clientSocket, head) => {
689
+ try {
690
+ const parts = req.url.split(':');
691
+ const targetHost = parts[0];
692
+ const targetPort = parseInt(parts[1] || '443', 10);
693
+
694
+ const shouldLog = !targetFilter || targetHost.includes(targetFilter);
695
+ if (shouldLog) {
696
+ console.log(chalk.yellow(`[HTTPS CONNECT Tunnel] ${targetHost}:${targetPort}`));
697
+ }
698
+
699
+ const serverSocket = net.connect(targetPort, targetHost, () => {
700
+ clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n');
701
+ serverSocket.write(head);
702
+ serverSocket.pipe(clientSocket);
703
+ clientSocket.pipe(serverSocket);
704
+ });
705
+
706
+ serverSocket.on('error', (err) => {
707
+ if (shouldLog) {
708
+ console.error(chalk.red(`[HTTPS Tunnel Error] Tunnel to ${targetHost}:${targetPort} failed: ${err.message}`));
709
+ }
710
+ clientSocket.end('HTTP/1.1 502 Bad Gateway\r\n\r\n');
711
+ });
712
+
713
+ clientSocket.on('error', () => {
714
+ serverSocket.end();
715
+ });
716
+ } catch (err) {
717
+ console.error(chalk.red(`Proxy CONNECT Handler Error: ${err.message}`));
718
+ }
719
+ });
720
+
721
+ server.listen(port, () => {
722
+ console.log(chalk.green.bold(`\n⚡ CyberSentinel Interception Proxy Active!`));
723
+ console.log(chalk.green(`Listening on local port: ${port}`));
724
+ if (targetFilter) {
725
+ console.log(chalk.green(`Filtering target host: ${targetFilter}`));
726
+ }
727
+ console.log(chalk.gray(`Configure your browser (e.g. Chrome) to use HTTP/HTTPS proxy 127.0.0.1:${port}`));
728
+ console.log(chalk.gray(`Type "/exit" or press Ctrl+C to stop the proxy server.\n`));
729
+ });
730
+
731
+ const readline = require('readline');
732
+ const rl = readline.createInterface({
733
+ input: process.stdin,
734
+ output: process.stdout
735
+ });
736
+
737
+ const ask = () => {
738
+ rl.question('', (answer) => {
739
+ if (answer.trim() === '/exit') {
740
+ console.log(chalk.yellow('Stopping proxy server and closing session...'));
741
+ server.close();
742
+ rl.close();
743
+ process.exit(0);
744
+ } else {
745
+ ask();
746
+ }
747
+ });
748
+ };
749
+ ask();
750
+ }
751
+
752
+ // Command: proxy
753
+ program
754
+ .command('proxy')
755
+ .description('Start a local interception proxy server (like Burp Suite CLI)')
756
+ .option('-p, --port <port>', 'Port to listen on', '8088')
757
+ .option('-t, --target <host>', 'Filter logs by target host domain')
758
+ .action((options) => {
759
+ const port = parseInt(options.port, 10);
760
+ startProxyServer(port, options.target);
557
761
  });
558
762
 
559
763
  program.parse(process.argv);
764
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cybersentinel-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "description": "CyberSentinel Cybersecurity Auditor CLI Tool",
5
5
  "main": "bin/index.js",
6
6
  "type": "commonjs",