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.
- package/README.md +73 -0
- package/bin/validate.js +489 -0
- 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
|
+
[](https://www.npmjs.com/package/dotenv-validator-pro)
|
|
6
|
+
[](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
|
package/bin/validate.js
ADDED
|
@@ -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
|
+
}
|