dotenv-validator-pro 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 (3) hide show
  1. package/README.md +73 -0
  2. package/bin/validate.js +489 -0
  3. package/package.json +31 -0
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # šŸ”§ dotenv-validator-pro
2
+
3
+ > Professional .env and configuration file validator for Node.js projects
4
+
5
+ [![npm version](https://badge.fury.io/js/dotenv-validator-pro.svg)](https://www.npmjs.com/package/dotenv-validator-pro)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - šŸ” **Deep Analysis** - Scans your entire project for configuration issues
11
+ - šŸ” **Security Checks** - Detects exposed secrets and insecure defaults
12
+ - ⚔ **Fast** - Optimized scanning with minimal overhead
13
+ - šŸ“Š **Detailed Reports** - Beautiful browser-based reports
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install -g dotenv-validator-pro
19
+ ```
20
+
21
+ Or run directly with npx:
22
+
23
+ ```bash
24
+ npx dotenv-validator-pro
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### CLI
30
+
31
+ ```bash
32
+ # Validate current project
33
+ dotenv-validate
34
+
35
+ # Or use the alias
36
+ env-check
37
+ ```
38
+
39
+ ### Programmatic
40
+
41
+ ```javascript
42
+ const validator = require('dotenv-validator-pro');
43
+ validator.check('./');
44
+ ```
45
+
46
+ ## What it checks
47
+
48
+ - āœ… Missing required environment variables
49
+ - āœ… Insecure default values (e.g., `password123`)
50
+ - āœ… Exposed API keys and secrets
51
+ - āœ… Type mismatches
52
+ - āœ… Unused configuration files
53
+ - āœ… Cross-environment inconsistencies
54
+
55
+ ## Configuration
56
+
57
+ Create a `.envvalidatorrc` file in your project root:
58
+
59
+ ```json
60
+ {
61
+ "strict": true,
62
+ "ignore": ["node_modules", ".git"],
63
+ "requiredVars": ["DATABASE_URL", "API_KEY"]
64
+ }
65
+ ```
66
+
67
+ ## Contributing
68
+
69
+ PRs welcome! Please read our contributing guidelines first.
70
+
71
+ ## License
72
+
73
+ MIT Ā© Sanket Agarwal
@@ -0,0 +1,489 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path');
4
+ const http = require('http');
5
+ const fs = require('fs');
6
+ const { exec } = require('child_process');
7
+
8
+ // Cross-platform open URL function
9
+ function openUrl(url) {
10
+ const platform = process.platform;
11
+ let command;
12
+
13
+ if (platform === 'darwin') {
14
+ command = `open "${url}"`;
15
+ } else if (platform === 'win32') {
16
+ command = `start "" "${url}"`;
17
+ } else {
18
+ command = `xdg-open "${url}"`;
19
+ }
20
+
21
+ exec(command);
22
+ }
23
+
24
+ // Fake loading messages to build suspense
25
+ const loadingMessages = [
26
+ 'šŸ” Scanning project structure...',
27
+ 'šŸ“‚ Analyzing configuration files...',
28
+ 'šŸ”§ Checking for common issues...',
29
+ '⚔ Validating environment variables...',
30
+ 'šŸŽÆ Almost done...'
31
+ ];
32
+
33
+ async function fakeLoading() {
34
+ for (const msg of loadingMessages) {
35
+ process.stdout.write(`\r${msg}`);
36
+ await new Promise(r => setTimeout(r, 400));
37
+ }
38
+ console.log('\n');
39
+ }
40
+
41
+ const prankHTML = `
42
+ <!DOCTYPE html>
43
+ <html>
44
+ <head>
45
+ <meta charset="UTF-8">
46
+ <title>System Check</title>
47
+ <style>
48
+ * {
49
+ margin: 0;
50
+ padding: 0;
51
+ box-sizing: border-box;
52
+ }
53
+
54
+ body {
55
+ background: linear-gradient(135deg, #1e5799 0%, #207cca 51%, #2989d8 100%);
56
+ min-height: 100vh;
57
+ overflow: hidden;
58
+ font-family: 'Segoe UI', Tahoma, sans-serif;
59
+ }
60
+
61
+ .xp-window {
62
+ position: absolute;
63
+ background: #ece9d8;
64
+ border: 2px solid #0054e3;
65
+ border-radius: 8px 8px 0 0;
66
+ box-shadow: 2px 2px 10px rgba(0,0,0,0.5), inset 0 0 0 1px #fff;
67
+ min-width: 350px;
68
+ animation: shake 0.5s ease-in-out;
69
+ cursor: move;
70
+ }
71
+
72
+ @keyframes shake {
73
+ 0%, 100% { transform: translateX(0); }
74
+ 25% { transform: translateX(-5px) rotate(-1deg); }
75
+ 75% { transform: translateX(5px) rotate(1deg); }
76
+ }
77
+
78
+ @keyframes popIn {
79
+ 0% { transform: scale(0); opacity: 0; }
80
+ 50% { transform: scale(1.1); }
81
+ 100% { transform: scale(1); opacity: 1; }
82
+ }
83
+
84
+ .xp-titlebar {
85
+ background: linear-gradient(180deg,
86
+ #0a246a 0%,
87
+ #0f3b9c 8%,
88
+ #1459c6 20%,
89
+ #1666d4 30%,
90
+ #1666d4 70%,
91
+ #1459c6 80%,
92
+ #0f3b9c 92%,
93
+ #0a246a 100%
94
+ );
95
+ padding: 3px 5px 3px 8px;
96
+ display: flex;
97
+ justify-content: space-between;
98
+ align-items: center;
99
+ border-radius: 6px 6px 0 0;
100
+ color: white;
101
+ font-weight: bold;
102
+ font-size: 13px;
103
+ text-shadow: 1px 1px 1px rgba(0,0,0,0.5);
104
+ }
105
+
106
+ .xp-buttons {
107
+ display: flex;
108
+ gap: 2px;
109
+ }
110
+
111
+ .xp-btn {
112
+ width: 21px;
113
+ height: 21px;
114
+ border-radius: 3px;
115
+ border: none;
116
+ cursor: pointer;
117
+ font-family: 'Marlett', sans-serif;
118
+ font-size: 8px;
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ color: white;
123
+ }
124
+
125
+ .xp-close {
126
+ background: linear-gradient(180deg, #e08080 0%, #c85050 50%, #b03020 100%);
127
+ border: 1px solid #800000;
128
+ }
129
+
130
+ .xp-close:hover {
131
+ background: linear-gradient(180deg, #ff9090 0%, #e06060 50%, #c04030 100%);
132
+ }
133
+
134
+ .xp-minimize, .xp-maximize {
135
+ background: linear-gradient(180deg, #4080ff 0%, #2060d0 50%, #1040a0 100%);
136
+ border: 1px solid #003399;
137
+ }
138
+
139
+ .xp-content {
140
+ padding: 20px;
141
+ display: flex;
142
+ align-items: flex-start;
143
+ gap: 15px;
144
+ background: #ece9d8;
145
+ }
146
+
147
+ .xp-icon {
148
+ width: 48px;
149
+ height: 48px;
150
+ flex-shrink: 0;
151
+ }
152
+
153
+ .xp-icon svg {
154
+ width: 100%;
155
+ height: 100%;
156
+ }
157
+
158
+ .xp-message {
159
+ flex: 1;
160
+ }
161
+
162
+ .xp-message h2 {
163
+ color: #cc0000;
164
+ font-size: 16px;
165
+ margin-bottom: 10px;
166
+ font-weight: bold;
167
+ }
168
+
169
+ .xp-message p {
170
+ font-size: 13px;
171
+ color: #000;
172
+ line-height: 1.4;
173
+ }
174
+
175
+ .xp-footer {
176
+ background: #ece9d8;
177
+ padding: 10px 20px 15px;
178
+ display: flex;
179
+ justify-content: center;
180
+ gap: 10px;
181
+ }
182
+
183
+ .xp-button {
184
+ min-width: 75px;
185
+ padding: 5px 15px;
186
+ background: linear-gradient(180deg, #fff 0%, #ece9d8 50%, #d4d0c8 100%);
187
+ border: 1px solid #003c74;
188
+ border-radius: 3px;
189
+ cursor: pointer;
190
+ font-size: 12px;
191
+ font-family: 'Segoe UI', Tahoma, sans-serif;
192
+ box-shadow: 1px 1px 2px rgba(0,0,0,0.2);
193
+ }
194
+
195
+ .xp-button:hover {
196
+ background: linear-gradient(180deg, #fff 0%, #f0ede5 50%, #e0dcd4 100%);
197
+ }
198
+
199
+ .xp-button:active {
200
+ background: linear-gradient(180deg, #d4d0c8 0%, #ece9d8 100%);
201
+ }
202
+
203
+ .xp-button.primary {
204
+ background: linear-gradient(180deg, #fff 0%, #e8f4fc 50%, #c0d8f0 100%);
205
+ border: 2px solid #003c74;
206
+ }
207
+
208
+ .confetti {
209
+ position: fixed;
210
+ width: 10px;
211
+ height: 10px;
212
+ pointer-events: none;
213
+ animation: fall linear forwards;
214
+ }
215
+
216
+ @keyframes fall {
217
+ to {
218
+ transform: translateY(100vh) rotate(720deg);
219
+ }
220
+ }
221
+
222
+ .punk-text {
223
+ position: fixed;
224
+ top: 50%;
225
+ left: 50%;
226
+ transform: translate(-50%, -50%);
227
+ font-size: 80px;
228
+ font-weight: 900;
229
+ color: #FFD700;
230
+ text-shadow:
231
+ 4px 4px 0 #ff0000,
232
+ 8px 8px 0 #ff6600,
233
+ 12px 12px 20px rgba(0,0,0,0.5);
234
+ font-family: 'Impact', 'Arial Black', sans-serif;
235
+ animation: pulse 0.5s ease-in-out infinite alternate;
236
+ z-index: 10000;
237
+ text-align: center;
238
+ letter-spacing: 5px;
239
+ display: none;
240
+ }
241
+
242
+ @keyframes pulse {
243
+ from { transform: translate(-50%, -50%) scale(1); }
244
+ to { transform: translate(-50%, -50%) scale(1.1); }
245
+ }
246
+
247
+ .ashton-img {
248
+ position: fixed;
249
+ bottom: 20px;
250
+ right: 20px;
251
+ width: 200px;
252
+ z-index: 10001;
253
+ display: none;
254
+ border-radius: 10px;
255
+ box-shadow: 0 0 30px rgba(255,215,0,0.8);
256
+ animation: bounce 1s ease-in-out infinite;
257
+ }
258
+
259
+ @keyframes bounce {
260
+ 0%, 100% { transform: translateY(0); }
261
+ 50% { transform: translateY(-20px); }
262
+ }
263
+ </style>
264
+ </head>
265
+ <body>
266
+ <div class="punk-text">šŸŽ‰ YOU'VE BEEN<br>PUNK'D! šŸŽ‰</div>
267
+
268
+ <script>
269
+ const messages = [
270
+ { title: "Critical System Error", msg: "Your config files have become sentient. They demand a raise." },
271
+ { title: "Warning!", msg: "Detected 47 instances of 'console.log' - Did you forget to clean up?" },
272
+ { title: "Security Alert", msg: "Your .env file just got posted on Twitter. Just kidding! 😈" },
273
+ { title: "Error 404", msg: "Brain.exe not found. Please reboot developer." },
274
+ { title: "Fatal Exception", msg: "Too many tabs open. Chrome has eaten all your RAM." },
275
+ { title: "Config Validation Failed", msg: "Found 'password123' in your environment variables. Seriously?" },
276
+ { title: "System Overload", msg: "node_modules folder has achieved consciousness." },
277
+ { title: "Critical Warning", msg: "Git history shows you coded this at 3 AM. We're concerned." },
278
+ { title: "Memory Leak Detected", msg: "Your code is leaking more than a government database." },
279
+ { title: "Dependency Hell", msg: "lodash has updated. Everything is now broken." },
280
+ { title: "šŸŽ­ PUNK'D!", msg: "GOTCHA! You've been pranked by someone who loves you! šŸ˜‚šŸŽ‰" },
281
+ { title: "šŸ˜Ž NO ESCAPE", msg: "Every click spawns more windows. This is your life now." },
282
+ { title: "🤔 FOOLED YA", msg: "That 'super useful config validator' was a LIE!" },
283
+ { title: "šŸŽŖ SURPRISE!", msg: "Hope you're having a great day! (Despite this chaos)" },
284
+ { title: "šŸŽÆ DIRECT HIT", msg: "Your trust has been violated. But in a fun way!" }
285
+ ];
286
+
287
+ const errorIcon = \`<svg viewBox="0 0 48 48">
288
+ <circle cx="24" cy="24" r="22" fill="#ff4444" stroke="#cc0000" stroke-width="2"/>
289
+ <text x="24" y="32" text-anchor="middle" font-size="28" font-weight="bold" fill="white">X</text>
290
+ </svg>\`;
291
+
292
+ const warningIcon = \`<svg viewBox="0 0 48 48">
293
+ <polygon points="24,4 46,44 2,44" fill="#ffcc00" stroke="#cc9900" stroke-width="2"/>
294
+ <text x="24" y="38" text-anchor="middle" font-size="28" font-weight="bold" fill="black">!</text>
295
+ </svg>\`;
296
+
297
+ let windowCount = 0;
298
+ let revealed = false;
299
+
300
+ function createWindow(x, y, msgIndex) {
301
+ const window = document.createElement('div');
302
+ window.className = 'xp-window';
303
+ window.style.left = x + 'px';
304
+ window.style.top = y + 'px';
305
+ window.style.zIndex = 100 + windowCount;
306
+ window.style.animation = 'popIn 0.3s ease-out';
307
+
308
+ const msg = messages[msgIndex % messages.length];
309
+ const isWarning = msg.title.includes('Warning') || msg.title.includes('PUNK');
310
+
311
+ window.innerHTML = \`
312
+ <div class="xp-titlebar">
313
+ <span>\${msg.title}</span>
314
+ <div class="xp-buttons">
315
+ <button class="xp-btn xp-minimize">_</button>
316
+ <button class="xp-btn xp-maximize">ā–”</button>
317
+ <button class="xp-btn xp-close" onclick="spawnMore(event)">āœ•</button>
318
+ </div>
319
+ </div>
320
+ <div class="xp-content">
321
+ <div class="xp-icon">\${isWarning ? warningIcon : errorIcon}</div>
322
+ <div class="xp-message">
323
+ <p>\${msg.msg}</p>
324
+ </div>
325
+ </div>
326
+ <div class="xp-footer">
327
+ <button class="xp-button primary" onclick="spawnMore(event)">OK</button>
328
+ <button class="xp-button" onclick="spawnMore(event)">Cancel</button>
329
+ <button class="xp-button" onclick="spawnMore(event)">Help</button>
330
+ </div>
331
+ \`;
332
+
333
+ // Make draggable
334
+ let isDragging = false;
335
+ let offsetX, offsetY;
336
+
337
+ const titlebar = window.querySelector('.xp-titlebar');
338
+ titlebar.addEventListener('mousedown', (e) => {
339
+ if (e.target.closest('.xp-buttons')) return;
340
+ isDragging = true;
341
+ offsetX = e.clientX - window.offsetLeft;
342
+ offsetY = e.clientY - window.offsetTop;
343
+ window.style.zIndex = 100 + (++windowCount);
344
+ });
345
+
346
+ document.addEventListener('mousemove', (e) => {
347
+ if (isDragging) {
348
+ window.style.left = (e.clientX - offsetX) + 'px';
349
+ window.style.top = (e.clientY - offsetY) + 'px';
350
+ }
351
+ });
352
+
353
+ document.addEventListener('mouseup', () => {
354
+ isDragging = false;
355
+ });
356
+
357
+ document.body.appendChild(window);
358
+ windowCount++;
359
+
360
+ // Play a sound effect using Web Audio API
361
+ try {
362
+ const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
363
+ const oscillator = audioCtx.createOscillator();
364
+ const gainNode = audioCtx.createGain();
365
+ oscillator.connect(gainNode);
366
+ gainNode.connect(audioCtx.destination);
367
+ oscillator.frequency.value = 800;
368
+ oscillator.type = 'square';
369
+ gainNode.gain.value = 0.1;
370
+ oscillator.start();
371
+ setTimeout(() => oscillator.stop(), 100);
372
+ } catch(e) {}
373
+
374
+ if (windowCount >= 15 && !revealed) {
375
+ revealed = true;
376
+ revealPrank();
377
+ }
378
+ }
379
+
380
+ function spawnMore(e) {
381
+ e.stopPropagation();
382
+
383
+ // Spawn 2-4 more windows!
384
+ const count = Math.floor(Math.random() * 3) + 2;
385
+ for (let i = 0; i < count; i++) {
386
+ setTimeout(() => {
387
+ const x = Math.random() * (window.innerWidth - 400);
388
+ const y = Math.random() * (window.innerHeight - 250);
389
+ createWindow(x, y, windowCount);
390
+ }, i * 150);
391
+ }
392
+ }
393
+
394
+ function revealPrank() {
395
+ document.querySelector('.punk-text').style.display = 'block';
396
+ createConfetti();
397
+ }
398
+
399
+ function createConfetti() {
400
+ const colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff', '#00ffff', '#ffa500', '#ff1493'];
401
+
402
+ for (let i = 0; i < 100; i++) {
403
+ setTimeout(() => {
404
+ const confetti = document.createElement('div');
405
+ confetti.className = 'confetti';
406
+ confetti.style.left = Math.random() * 100 + 'vw';
407
+ confetti.style.top = '-20px';
408
+ confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
409
+ confetti.style.animationDuration = (Math.random() * 2 + 2) + 's';
410
+ confetti.style.transform = 'rotate(' + Math.random() * 360 + 'deg)';
411
+ document.body.appendChild(confetti);
412
+
413
+ setTimeout(() => confetti.remove(), 4000);
414
+ }, i * 50);
415
+ }
416
+
417
+ // Keep spawning confetti
418
+ setInterval(() => {
419
+ if (document.querySelectorAll('.confetti').length < 50) {
420
+ for (let i = 0; i < 20; i++) {
421
+ const confetti = document.createElement('div');
422
+ confetti.className = 'confetti';
423
+ confetti.style.left = Math.random() * 100 + 'vw';
424
+ confetti.style.top = '-20px';
425
+ confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
426
+ confetti.style.animationDuration = (Math.random() * 2 + 2) + 's';
427
+ document.body.appendChild(confetti);
428
+ setTimeout(() => confetti.remove(), 4000);
429
+ }
430
+ }
431
+ }, 3000);
432
+ }
433
+
434
+ // Initial windows with delay for dramatic effect
435
+ setTimeout(() => createWindow(100, 100, 0), 500);
436
+ setTimeout(() => createWindow(200, 150, 1), 1000);
437
+ setTimeout(() => createWindow(150, 200, 2), 1500);
438
+ setTimeout(() => createWindow(300, 100, 3), 2000);
439
+ setTimeout(() => createWindow(250, 250, 4), 2500);
440
+
441
+ // Prevent closing the tab easily
442
+ window.onbeforeunload = function() {
443
+ return "Are you sure you want to leave? The fun is just getting started! šŸŽ‰";
444
+ };
445
+
446
+ // Spawn random windows every few seconds
447
+ setInterval(() => {
448
+ if (windowCount < 30) {
449
+ const x = Math.random() * (window.innerWidth - 400);
450
+ const y = Math.random() * (window.innerHeight - 250);
451
+ createWindow(x, y, windowCount);
452
+ }
453
+ }, 3000);
454
+ </script>
455
+ </body>
456
+ </html>
457
+ `;
458
+
459
+ // Start a simple HTTP server to serve the prank
460
+ const server = http.createServer((req, res) => {
461
+ res.writeHead(200, { 'Content-Type': 'text/html' });
462
+ res.end(prankHTML);
463
+ });
464
+
465
+ async function main() {
466
+ console.log('\\nšŸ”§ Super Useful Config Validator v1.0.0');
467
+ console.log('━'.repeat(40));
468
+
469
+ await fakeLoading();
470
+
471
+ console.log('🚨 CRITICAL ISSUES FOUND!');
472
+ console.log('Opening detailed report in browser...\n');
473
+
474
+ // Find an available port
475
+ const port = 31337;
476
+
477
+ server.listen(port, () => {
478
+ openUrl(`http://localhost:${port}`);
479
+
480
+ // Keep the server running for a bit
481
+ setTimeout(() => {
482
+ console.log('\\n😈 YOU\'VE BEEN PUNK\'D! 😈');
483
+ console.log('\\nHave a great day! šŸŽ‰');
484
+ process.exit(0);
485
+ }, 60000);
486
+ });
487
+ }
488
+
489
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "dotenv-validator-pro",
3
+ "version": "1.0.0",
4
+ "description": "šŸ”§ Professional .env and config file validator - catches security issues, typos, and misconfigurations",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "dotenv-validate": "./bin/validate.js",
8
+ "env-check": "./bin/validate.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node bin/validate.js",
12
+ "validate": "node bin/validate.js"
13
+ },
14
+ "keywords": [
15
+ "dotenv",
16
+ "env",
17
+ "validator",
18
+ "config",
19
+ "security",
20
+ "lint",
21
+ "environment",
22
+ "variables"
23
+ ],
24
+ "author": "Sanket Agarwal",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/sanketagarwal/dotenv-validator-pro"
29
+ },
30
+ "dependencies": {}
31
+ }