yusufkhon-guard 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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +734 -0
  3. package/bin/cli.js +39 -0
  4. package/bin/renew.js +149 -0
  5. package/bin/scan.js +124 -0
  6. package/bin/ssl.js +181 -0
  7. package/package.json +80 -0
  8. package/src/index.js +206 -0
  9. package/src/modules/acme/client.js +240 -0
  10. package/src/modules/acme/csr.js +172 -0
  11. package/src/modules/acme/detectDomains.js +132 -0
  12. package/src/modules/acme/index.js +211 -0
  13. package/src/modules/acme/jose.js +125 -0
  14. package/src/modules/acme/renew.js +89 -0
  15. package/src/modules/adaptiveRateLimiter.js +154 -0
  16. package/src/modules/alerts.js +168 -0
  17. package/src/modules/bodyLimit.js +106 -0
  18. package/src/modules/botDetector.js +144 -0
  19. package/src/modules/connectionGuard.js +128 -0
  20. package/src/modules/csrf.js +130 -0
  21. package/src/modules/dashboard.js +257 -0
  22. package/src/modules/dashboardHtml.js +235 -0
  23. package/src/modules/datacenterRanges.js +121 -0
  24. package/src/modules/ddosGuard.js +323 -0
  25. package/src/modules/firewall.js +239 -0
  26. package/src/modules/geoBlock.js +169 -0
  27. package/src/modules/headers.js +130 -0
  28. package/src/modules/honeypot.js +149 -0
  29. package/src/modules/httpsRedirect.js +67 -0
  30. package/src/modules/integrity.js +164 -0
  31. package/src/modules/ipBlocker.js +372 -0
  32. package/src/modules/ja3.js +155 -0
  33. package/src/modules/logExport.js +134 -0
  34. package/src/modules/nosqlGuard.js +143 -0
  35. package/src/modules/osFirewall.js +182 -0
  36. package/src/modules/rateLimiter.js +196 -0
  37. package/src/modules/sanitizer.js +253 -0
  38. package/src/modules/threatDetector.js +202 -0
  39. package/src/scanner/checks/dependencies.js +125 -0
  40. package/src/scanner/checks/environment.js +118 -0
  41. package/src/scanner/checks/exposure.js +99 -0
  42. package/src/scanner/checks/headers.js +119 -0
  43. package/src/scanner/checks/ssl.js +151 -0
  44. package/src/scanner/index.js +209 -0
  45. package/src/utils/cidr.js +140 -0
  46. package/src/utils/logger.js +194 -0
  47. package/src/utils/privilege.js +212 -0
package/bin/cli.js ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * @file bin/cli.js
6
+ * @description `yusufkhon-guard` CLI kirish nuqtasi (dispatcher). Birinchi
7
+ * argumentga qarab kichik buyruqni tanlaydi:
8
+ * yusufkhon-guard scan ... -> xavfsizlik auditi
9
+ * yusufkhon-guard ssl ... -> Let's Encrypt SSL sertifikati
10
+ * Kichik buyruq berilmasa yoki `--...` bilan boshlansa — `scan`
11
+ * (orqaga moslik uchun).
12
+ * @module bin/cli
13
+ */
14
+
15
+ const sub = process.argv[2];
16
+
17
+ if (sub === 'ssl') {
18
+ require('./ssl').main();
19
+ } else if (sub === 'renew') {
20
+ require('./renew').main();
21
+ } else if (sub === '--help' || sub === '-h' || sub === 'help') {
22
+ console.log(`
23
+ šŸ›”ļø yusufkhon-guard CLI
24
+
25
+ Buyruqlar:
26
+ scan Serverni xavfsizlik jihatidan tekshiradi (SSL, sarlavhalar, oshkorlik...)
27
+ ssl Let's Encrypt orqali SSL sertifikatini avtomat oladi (domenni o'zi aniqlaydi)
28
+ renew Sertifikatni tekshiradi/yangilaydi; --install bilan avtomat yangilash
29
+
30
+ Batafsil:
31
+ npx yusufkhon-guard scan --help
32
+ npx yusufkhon-guard ssl --help
33
+ npx yusufkhon-guard renew --help
34
+ `);
35
+ process.exit(0);
36
+ } else {
37
+ // Standart: scan ('scan', undefined yoki `--domain ...` kabi eski chaqiruvlar).
38
+ require('./scan').run();
39
+ }
package/bin/renew.js ADDED
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * @file bin/renew.js
6
+ * @description `yusufkhon-guard renew` — mavjud sertifikatni tekshiradi va
7
+ * `<N kun` qolgan bo'lsa AVTOMAT yangilaydi. `--install` bilan
8
+ * har kunlik avtomat yangilashni (cron/systemd/schtasks) rozilik
9
+ * qatlami orqali o'rnatadi.
10
+ *
11
+ * Misollar:
12
+ * npx yusufkhon-guard renew # kerak bo'lsa yangilaydi
13
+ * npx yusufkhon-guard renew --force # majburan yangilaydi
14
+ * sudo npx yusufkhon-guard renew --install # avtomat yangilashni o'rnatadi
15
+ * @module bin/renew
16
+ */
17
+
18
+ const path = require('path');
19
+ const acme = require('../src/modules/acme');
20
+ const privilege = require('../src/utils/privilege');
21
+ const { createChallengeServer, parseArgs } = require('./ssl');
22
+
23
+ /**
24
+ * Avtomat yangilash (auto-renew) buyrug'ini platformaga mos tuzadi.
25
+ * @param {string} certDir
26
+ * @param {string} cwd
27
+ * @returns {{ command: string, args: string[] }}
28
+ */
29
+ function buildAutoRenewCommand(certDir, cwd) {
30
+ if (process.platform === 'win32') {
31
+ const tr = `cmd /c cd /d "${cwd}" && npx yusufkhon-guard renew --cert-dir "${certDir}" --yes`;
32
+ return { command: 'schtasks', args: ['/create', '/tn', 'yusufkhon-guard-renew', '/tr', tr, '/sc', 'daily', '/st', '03:00', '/f'] };
33
+ }
34
+ const line = `0 3 * * * cd ${cwd} && npx yusufkhon-guard renew --cert-dir ${certDir} --yes >> ${certDir}/renew.log 2>&1 # yusufkhon-guard-renew`;
35
+ const pipeline = `(crontab -l 2>/dev/null | grep -v 'yusufkhon-guard-renew'; echo '${line}') | crontab -`;
36
+ return { command: 'sh', args: ['-c', pipeline] };
37
+ }
38
+
39
+ /**
40
+ * Avtomat yangilashni rozilik qatlami orqali o'rnatadi.
41
+ * @param {Object} params
42
+ * @param {string} params.certDir
43
+ * @param {boolean} [params.autoApprove]
44
+ * @param {boolean} [params.dryRun]
45
+ * @returns {Promise<import('../src/utils/privilege').PrivilegedResult>}
46
+ */
47
+ function installAutoRenew({ certDir, autoApprove, dryRun }) {
48
+ const cmd = buildAutoRenewCommand(path.resolve(certDir), process.cwd());
49
+ return privilege.runPrivileged(cmd.command, cmd.args, {
50
+ description: 'Har kuni 03:00 da sertifikatni avtomat yangilash (auto-renew) o\'rnatish',
51
+ autoApprove,
52
+ dryRun,
53
+ });
54
+ }
55
+
56
+ /** Yordam matni. @returns {void} */
57
+ function printHelp() {
58
+ console.log(`
59
+ šŸ”„ yusufkhon-guard renew — sertifikatni tekshiradi va kerak bo'lsa yangilaydi
60
+
61
+ Foydalanish:
62
+ npx yusufkhon-guard renew [parametrlar]
63
+
64
+ Parametrlar:
65
+ --cert-dir <yo'l> Sertifikat papkasi (standart: ./certs)
66
+ --days <n> Shu kundan kam qolsa yangilanadi (standart: 30)
67
+ --force Muddatidan qat'i nazar yangilaydi
68
+ --domain <d> Domen(lar)ni qo'lda ko'rsatish (aks holda cert SAN'idan olinadi)
69
+ --production Jonli muhit (standart: staging)
70
+ --port <n> Challenge porti (standart: 80)
71
+ --install Avtomat (har kunlik) yangilashni o'rnatadi (root/admin rozilik)
72
+ --yes Rozilikni so'ramasdan tasdiqlash
73
+ --dry-run O'rnatish buyrug'ini faqat ko'rsatadi (bajarmaydi)
74
+ --help Ushbu yordam
75
+ `);
76
+ }
77
+
78
+ /**
79
+ * CLI kirish nuqtasi.
80
+ * @returns {Promise<void>}
81
+ */
82
+ async function main() {
83
+ const raw = process.argv.slice(2).filter((a) => a !== 'renew');
84
+ const args = parseArgs(raw);
85
+ if (args.help) { printHelp(); process.exit(0); }
86
+
87
+ const certDir = typeof args['cert-dir'] === 'string' ? args['cert-dir'] : './certs';
88
+
89
+ // 1) Avtomat yangilashni o'rnatish.
90
+ if (args.install) {
91
+ await installAutoRenew({ certDir, autoApprove: Boolean(args.yes), dryRun: Boolean(args['dry-run']) });
92
+ process.exit(0);
93
+ }
94
+
95
+ // 2) Holatni tekshirish.
96
+ const days = Number(args.days) || 30;
97
+ const certPath = path.join(certDir, 'fullchain.pem');
98
+ const status = acme.checkCert(certPath, days);
99
+
100
+ console.log(`šŸ“œ Sertifikat: ${certPath}`);
101
+ console.log(` Holat: ${status.reason}`);
102
+
103
+ if (!status.exists && !args.domain) {
104
+ console.error('āŒ Sertifikat topilmadi. Avval oling: npx yusufkhon-guard ssl');
105
+ process.exit(1);
106
+ }
107
+
108
+ const domains = args.domain
109
+ ? String(args.domain).split(',').map((s) => s.trim()).filter(Boolean)
110
+ : (status.domains || []);
111
+ if (!domains.length) {
112
+ console.error('āŒ Yangilanadigan domen aniqlanmadi (--domain bering).');
113
+ process.exit(1);
114
+ }
115
+
116
+ if (!status.needsRenewal && !args.force) {
117
+ console.log(`āœ… Hali yangi — yangilash shart emas (${status.daysLeft} kun qoldi). Majburlash uchun: --force`);
118
+ process.exit(0);
119
+ }
120
+
121
+ // 3) Yangilash.
122
+ console.log(`šŸ”„ Yangilanyapti: ${domains.join(', ')}`);
123
+ const environment = args.production ? 'production' : 'staging';
124
+ const port = Number(args.port) || 80;
125
+ const accountKeyPath = typeof args['account-key'] === 'string' ? args['account-key'] : path.join(certDir, 'account.pem');
126
+
127
+ const store = new acme.ChallengeStore();
128
+ const server = createChallengeServer(store);
129
+ try {
130
+ await new Promise((resolve, reject) => { server.once('error', reject); server.listen(port, resolve); });
131
+ } catch (err) {
132
+ console.error(`āŒ ${port}-portni ochib bo'lmadi (${err && err.code}). sudo yoki --port bering.`);
133
+ process.exit(1);
134
+ }
135
+ try {
136
+ const result = await acme.obtainCertificate({ domains, email: typeof args.email === 'string' ? args.email : undefined, challengeStore: store, environment, certDir, accountKeyPath });
137
+ console.log(`āœ… Sertifikat yangilandi: ${result.paths.fullchain}`);
138
+ process.exit(0);
139
+ } catch (err) {
140
+ console.error(`āŒ Yangilash muvaffaqiyatsiz: ${err && err.message}`);
141
+ process.exit(1);
142
+ } finally {
143
+ server.close();
144
+ }
145
+ }
146
+
147
+ if (require.main === module) main();
148
+
149
+ module.exports = { main, buildAutoRenewCommand, installAutoRenew };
package/bin/scan.js ADDED
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * @file bin/scan.js
6
+ * @description `yusufkhon-guard` ning buyruq qatori (CLI) skaneri.
7
+ * Foydalanuvchi kutubxonani o'rnatgach, terminalda quyidagicha
8
+ * ishga tushiradi:
9
+ *
10
+ * npx yusufkhon-guard scan --domain example.com --target http://localhost:3000 --fix
11
+ *
12
+ * yoki loyihada: npm run scan
13
+ * @module bin/scan
14
+ */
15
+
16
+ const { scan, formatReport } = require('../src/scanner');
17
+
18
+ /**
19
+ * `--kalit qiymat` va `--bayroq` ko'rinishidagi argumentlarni tahlil qiladi.
20
+ * @param {string[]} argv - process.argv.slice(2).
21
+ * @returns {Record<string, string|boolean>}
22
+ */
23
+ function parseArgs(argv) {
24
+ /** @type {Record<string, string|boolean>} */
25
+ const args = {};
26
+ for (let i = 0; i < argv.length; i++) {
27
+ const token = argv[i];
28
+ if (token.startsWith('--')) {
29
+ const key = token.slice(2);
30
+ const next = argv[i + 1];
31
+ if (next && !next.startsWith('--')) {
32
+ args[key] = next;
33
+ i++;
34
+ } else {
35
+ args[key] = true;
36
+ }
37
+ }
38
+ }
39
+ return args;
40
+ }
41
+
42
+ /**
43
+ * Yordam matnini chiqaradi.
44
+ * @returns {void}
45
+ */
46
+ function printHelp() {
47
+ console.log(`
48
+ šŸ›”ļø yusufkhon-guard — Xavfsizlik skaneri
49
+
50
+ Foydalanish:
51
+ npx yusufkhon-guard scan [parametrlar]
52
+
53
+ Parametrlar:
54
+ --domain <domen> SSL/sertifikat tekshiruvi uchun domen (misol: example.com)
55
+ --target <url> Xavfsizlik sarlavhalarini tekshirish uchun server URL'i
56
+ (misol: http://localhost:3000)
57
+ --cwd <yo'l> Loyiha ildiz papkasi (standart: joriy papka)
58
+ --fix Muammolarni tuzatish (xavfsizlari avtomat; root talab
59
+ qiladiganlari rozilik so'rab, sudo/UAC bilan)
60
+ --yes Privilegiyali tuzatishlarga so'ramasdan rozilik berish
61
+ --dry-run Privilegiyali buyruqlarni bajarmasdan faqat ko'rsatish
62
+ --json Natijani JSON ko'rinishida chiqarish
63
+ --help Ushbu yordamni ko'rsatish
64
+
65
+ Misollar:
66
+ npx yusufkhon-guard scan --domain mysite.uz --target http://localhost:3000
67
+ npx yusufkhon-guard scan --fix
68
+ sudo npx yusufkhon-guard scan --domain mysite.uz --fix --yes
69
+ npx yusufkhon-guard scan --domain mysite.uz --fix --dry-run
70
+ `);
71
+ }
72
+
73
+ /**
74
+ * CLI kirish nuqtasi.
75
+ * @returns {Promise<void>}
76
+ */
77
+ async function main() {
78
+ // "scan" buyrug'ini (agar berilgan bo'lsa) tashlab yuboramiz.
79
+ const raw = process.argv.slice(2).filter((a) => a !== 'scan');
80
+ const args = parseArgs(raw);
81
+
82
+ if (args.help) {
83
+ printHelp();
84
+ process.exit(0);
85
+ }
86
+
87
+ const result = await scan({
88
+ domain: typeof args.domain === 'string' ? args.domain : undefined,
89
+ target: typeof args.target === 'string' ? args.target : undefined,
90
+ cwd: typeof args.cwd === 'string' ? args.cwd : process.cwd(),
91
+ autoFix: Boolean(args.fix),
92
+ autoApprove: Boolean(args.yes),
93
+ dryRun: Boolean(args['dry-run']),
94
+ });
95
+
96
+ if (args.json) {
97
+ // Ichki (_fix / _privileged) maydonlarni JSON'ga chiqarmaymiz.
98
+ const clean = {
99
+ ...result,
100
+ findings: result.findings.map(({ _fix, _privileged, ...rest }) => rest),
101
+ };
102
+ console.log(JSON.stringify(clean, null, 2));
103
+ } else {
104
+ console.log(formatReport(result));
105
+ }
106
+
107
+ // Kritik yoki yuqori darajadagi muammo bo'lsa — nol bo'lmagan chiqish kodi
108
+ // (CI/CD quvurlarida to'xtatish uchun foydali).
109
+ const failing = result.summary.critical + result.summary.high;
110
+ process.exit(failing > 0 ? 1 : 0);
111
+ }
112
+
113
+ /** Skaner CLI'ni ishga tushiradi (dispatcher yoki to'g'ridan-to'g'ri chaqiradi). */
114
+ function run() {
115
+ return main().catch((err) => {
116
+ console.error('Skaner xatosi:', err);
117
+ process.exit(2);
118
+ });
119
+ }
120
+
121
+ // To'g'ridan-to'g'ri (`node bin/scan.js`) chaqirilgandagina avtomat ishga tushadi.
122
+ if (require.main === module) run();
123
+
124
+ module.exports = { run, main, parseArgs };
package/bin/ssl.js ADDED
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * @file bin/ssl.js
6
+ * @description `yusufkhon-guard ssl` — Let's Encrypt (ACME) orqali SSL sertifikatini
7
+ * KOD YOZMASDAN, bitta buyruq bilan oladi ("standalone" rejim, certbot
8
+ * kabi). O'zi vaqtinchalik HTTP server ochib, HTTP-01 challenge'ni
9
+ * bajaradi va sertifikatni saqlaydi.
10
+ *
11
+ * Misol:
12
+ * npx yusufkhon-guard ssl --domain sayt.uz --email admin@sayt.uz
13
+ * npx yusufkhon-guard ssl --domain sayt.uz,www.sayt.uz --production
14
+ * @module bin/ssl
15
+ */
16
+
17
+ const http = require('http');
18
+ const acme = require('../src/modules/acme');
19
+ const privilege = require('../src/utils/privilege');
20
+
21
+ /**
22
+ * Sertifikat uchun domenlarni aniqlaydi: agar `--domain` berilgan bo'lsa o'shani,
23
+ * aks holda VPS konfiguratsiyasidan (nginx/apache/hostname) AVTOMAT topib, admin'dan
24
+ * tasdiq so'raydi.
25
+ * @param {Record<string,string|boolean>} args
26
+ * @param {Object} [deps] - Test uchun: { detect, confirm }.
27
+ * @returns {Promise<{ domains: string[], detected: Array, source: string, confirmed?: boolean }>}
28
+ */
29
+ async function resolveDomains(args, deps = {}) {
30
+ const detectFn = deps.detect || (() => acme.detectDomains());
31
+ const confirmFn = deps.confirm || ((msg) => privilege.confirm(msg, { autoApprove: Boolean(args.yes), defaultYes: true }));
32
+
33
+ // 1) Aniq --domain berilgan bo'lsa — o'shani ishlatamiz.
34
+ if (args.domain) {
35
+ const domains = String(args.domain).split(',').map((s) => s.trim()).filter(Boolean);
36
+ return { domains, detected: [], source: 'flag' };
37
+ }
38
+
39
+ // 2) Avtomat aniqlash (nginx / apache / hostname).
40
+ const detected = detectFn();
41
+ if (!detected.length) return { domains: [], detected: [], source: 'none' };
42
+
43
+ const list = detected.map((d) => `${d.domain} (${d.source})`).join(', ');
44
+ const ok = await confirmFn(` šŸ”Ž Aniqlangan domen(lar): ${list}\n ā“ Shu domen(lar) uchun SSL sertifikati olinsinmi?`);
45
+ return { domains: ok ? detected.map((d) => d.domain) : [], detected, source: 'detected', confirmed: ok };
46
+ }
47
+
48
+ /**
49
+ * `--kalit qiymat` va `--bayroq` argumentlarini tahlil qiladi.
50
+ * @param {string[]} argv - process.argv.slice(2) ('ssl' tokeni chiqarilgan holda).
51
+ * @returns {Record<string, string|boolean>}
52
+ */
53
+ function parseArgs(argv) {
54
+ /** @type {Record<string, string|boolean>} */
55
+ const args = {};
56
+ for (let i = 0; i < argv.length; i++) {
57
+ const token = argv[i];
58
+ if (token.startsWith('--')) {
59
+ const key = token.slice(2);
60
+ const next = argv[i + 1];
61
+ if (next && !next.startsWith('--')) { args[key] = next; i++; }
62
+ else args[key] = true;
63
+ }
64
+ }
65
+ return args;
66
+ }
67
+
68
+ /**
69
+ * Challenge'ni beruvchi vaqtinchalik HTTP serverni yaratadi (express'siz).
70
+ * `/.well-known/acme-challenge/<token>` so'roviga keyAuth qaytaradi, qolganiga 404.
71
+ * @param {acme.ChallengeStore} store
72
+ * @returns {import('http').Server}
73
+ */
74
+ function createChallengeServer(store) {
75
+ const chal = acme.challengeMiddleware(store);
76
+ return http.createServer((req, res) => {
77
+ chal(req, res, () => { res.statusCode = 404; res.end('Not found'); });
78
+ });
79
+ }
80
+
81
+ /** Yordam matnini chiqaradi. @returns {void} */
82
+ function printHelp() {
83
+ console.log(`
84
+ šŸ” yusufkhon-guard ssl — Let's Encrypt SSL sertifikatini avtomat oladi
85
+
86
+ Foydalanish:
87
+ npx yusufkhon-guard ssl # domenni AVTOMAT aniqlab, tasdiq so'raydi
88
+ npx yusufkhon-guard ssl --domain <domen> # domenni qo'lda ko'rsatib
89
+
90
+ Parametrlar:
91
+ --domain <d> Domen(lar). Berilmasa — nginx/apache/hostname'dan avtomat topiladi
92
+ --email <e> Bog'lanish uchun email (tavsiya etiladi)
93
+ --yes Aniqlangan domenni so'ramasdan tasdiqlash (non-interactive)
94
+ --staging Sinov muhiti (STANDART) — soxta, lekin xavfsiz cert
95
+ --production Jonli muhit — HAQIQIY cert (limitlarga e'tibor bering!)
96
+ --cert-dir <yo'l> Sertifikat saqlanadigan papka (standart: ./certs)
97
+ --account-key <f> ACME hisob kaliti fayli (standart: ./certs/account.pem)
98
+ --port <n> Challenge HTTP porti (standart: 80)
99
+ --help Ushbu yordam
100
+
101
+ Shartlar: real ommaviy domen, DNS domenni shu serverga yo'naltirgan, 80-port ochiq.
102
+
103
+ Misollar:
104
+ npx yusufkhon-guard ssl --domain sayt.uz --email admin@sayt.uz
105
+ npx yusufkhon-guard ssl --domain sayt.uz,www.sayt.uz --production
106
+ `);
107
+ }
108
+
109
+ /**
110
+ * CLI kirish nuqtasi.
111
+ * @returns {Promise<void>}
112
+ */
113
+ async function main() {
114
+ const raw = process.argv.slice(2).filter((a) => a !== 'ssl');
115
+ const args = parseArgs(raw);
116
+
117
+ if (args.help) { printHelp(); process.exit(0); }
118
+
119
+ // Domenni aniqlaymiz (--domain yoki avtomat aniqlash + admin tasdiqi).
120
+ const resolved = await resolveDomains(args);
121
+ const domains = resolved.domains;
122
+ if (!domains.length) {
123
+ if (resolved.source === 'none') {
124
+ console.error('āŒ Domen avtomat aniqlanmadi (nginx/apache/hostname topilmadi).');
125
+ console.error(' --domain bilan qo\'lda ko\'rsating: npx yusufkhon-guard ssl --domain sayt.uz');
126
+ } else if (resolved.source === 'detected' && resolved.confirmed === false) {
127
+ console.error('🚫 Bekor qilindi (admin tasdiqlamadi).');
128
+ }
129
+ process.exit(1);
130
+ }
131
+ if (resolved.source === 'detected') console.log(`āœ”ļø Tasdiqlangan domen(lar): ${domains.join(', ')}`);
132
+
133
+ const environment = args.production ? 'production' : 'staging';
134
+ const port = Number(args.port) || 80;
135
+ const certDir = typeof args['cert-dir'] === 'string' ? args['cert-dir'] : './certs';
136
+ const accountKeyPath = typeof args['account-key'] === 'string' ? args['account-key'] : './certs/account.pem';
137
+
138
+ const store = new acme.ChallengeStore();
139
+ const server = createChallengeServer(store);
140
+
141
+ // Challenge serverni ishga tushiramiz (80-port ruxsat talab qilishi mumkin).
142
+ try {
143
+ await new Promise((resolve, reject) => {
144
+ server.once('error', reject);
145
+ server.listen(port, resolve);
146
+ });
147
+ } catch (err) {
148
+ if (err && err.code === 'EACCES') {
149
+ console.error(`āŒ ${port}-portni ochib bo'lmadi (ruxsat yo'q). Root bilan ishlating (sudo) yoki --port 8080 bering (reverse-proxy orqasida).`);
150
+ } else if (err && err.code === 'EADDRINUSE') {
151
+ console.error(`āŒ ${port}-port band. Boshqa xizmatni to'xtating yoki --port bilan boshqa port bering.`);
152
+ } else {
153
+ console.error(`āŒ Server xatosi: ${err && err.message}`);
154
+ }
155
+ process.exit(1);
156
+ }
157
+
158
+ console.log(`🌐 Challenge server ${port}-portda. Sertifikat olinyapti [${environment}]: ${domains.join(', ')}`);
159
+ if (environment === 'staging') console.log('ā„¹ļø Sinov (staging) rejimi — cert soxta. Jonli cert uchun --production bering.');
160
+
161
+ try {
162
+ const result = await acme.obtainCertificate({ domains, email: typeof args.email === 'string' ? args.email : undefined, challengeStore: store, environment, certDir, accountKeyPath });
163
+ console.log('\nāœ… Sertifikat muvaffaqiyatli olindi!');
164
+ console.log(` Zanjir : ${result.paths.fullchain}`);
165
+ console.log(` Kalit : ${result.paths.privkey}`);
166
+ console.log('\n HTTPS serverda ishlatish:');
167
+ console.log(` https.createServer({ cert: fs.readFileSync('${result.paths.fullchain}'), key: fs.readFileSync('${result.paths.privkey}') }, app)`);
168
+ process.exit(0);
169
+ } catch (err) {
170
+ console.error(`\nāŒ Sertifikat olinmadi: ${err && err.message}`);
171
+ console.error(' Tekshiring: domen DNS shu serverga yo\'naltirilganmi, 80-port internetdan ochiqmi.');
172
+ process.exit(1);
173
+ } finally {
174
+ server.close();
175
+ }
176
+ }
177
+
178
+ // To'g'ridan-to'g'ri chaqirilgandagina ishga tushadi (require qilinganda emas).
179
+ if (require.main === module) main();
180
+
181
+ module.exports = { main, parseArgs, createChallengeServer, resolveDomains };
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "yusufkhon-guard",
3
+ "version": "1.0.0",
4
+ "description": "Express.js va Node.js uchun yengil, mustaqil (zero-dependency) xavfsizlik middleware: aktiv himoya (blue team firewall), auto IP-ban, security headers, rate-limiting, input sanitization va audit-skaner.",
5
+ "main": "src/index.js",
6
+ "types": "src/index.js",
7
+ "bin": {
8
+ "yusufkhon-guard": "bin/cli.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node test.js",
12
+ "demo": "node test.js",
13
+ "test": "jest --runInBand",
14
+ "test:watch": "jest --watch",
15
+ "test:coverage": "jest --coverage --runInBand",
16
+ "scan": "node bin/scan.js",
17
+ "ssl": "node bin/ssl.js",
18
+ "renew": "node bin/renew.js",
19
+ "prepublishOnly": "npm test"
20
+ },
21
+ "jest": {
22
+ "testEnvironment": "node",
23
+ "setupFiles": [
24
+ "<rootDir>/tests/jest.setup.js"
25
+ ],
26
+ "testMatch": [
27
+ "**/tests/**/*.test.js"
28
+ ],
29
+ "testPathIgnorePatterns": [
30
+ "/node_modules/",
31
+ "/tests/legacy-manual/"
32
+ ],
33
+ "testTimeout": 15000
34
+ },
35
+ "keywords": [
36
+ "express",
37
+ "security",
38
+ "middleware",
39
+ "rate-limit",
40
+ "rate-limiter",
41
+ "helmet",
42
+ "sanitizer",
43
+ "xss",
44
+ "sqli",
45
+ "security-headers",
46
+ "csp",
47
+ "hsts",
48
+ "firewall",
49
+ "waf",
50
+ "blue-team",
51
+ "ip-ban",
52
+ "auto-block",
53
+ "intrusion-detection",
54
+ "ssl-check",
55
+ "security-scanner",
56
+ "yusufkhon-guard"
57
+ ],
58
+ "author": "Yusufkhon",
59
+ "license": "MIT",
60
+ "engines": {
61
+ "node": ">=14.0.0"
62
+ },
63
+ "peerDependencies": {
64
+ "express": ">=4.0.0"
65
+ },
66
+ "peerDependenciesMeta": {
67
+ "express": {
68
+ "optional": true
69
+ }
70
+ },
71
+ "files": [
72
+ "src",
73
+ "bin",
74
+ "README.md"
75
+ ],
76
+ "devDependencies": {
77
+ "jest": "^30.4.2",
78
+ "supertest": "^7.2.2"
79
+ }
80
+ }