mdefender-pro 1.2.4 → 1.2.5
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/auto.js +62 -0
- package/bin/mdefender.js +85 -34
- package/block-page.html +56 -210
- package/client.mjs +345 -237
- package/index.js +9 -1
- package/package.json +3 -2
- package/vite.js +45 -2
package/auto.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MDefender Pro Zero-Code Auto-Instrumentation Agent.
|
|
5
|
+
*
|
|
6
|
+
* Automatically hooks into Express and Node.js native http/https servers
|
|
7
|
+
* to provide full WAF protection without changing a single line of application code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const http = require('http');
|
|
11
|
+
const https = require('https');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
|
|
15
|
+
let isHooked = false;
|
|
16
|
+
|
|
17
|
+
function autoHook() {
|
|
18
|
+
if (isHooked) return;
|
|
19
|
+
isHooked = true;
|
|
20
|
+
|
|
21
|
+
const mdefender = require('./index');
|
|
22
|
+
|
|
23
|
+
// Load environment variables from .env if present
|
|
24
|
+
const envPath = path.resolve(process.cwd(), '.env');
|
|
25
|
+
if (fs.existsSync(envPath)) {
|
|
26
|
+
try {
|
|
27
|
+
const dotenv = require('dotenv');
|
|
28
|
+
dotenv.config({ path: envPath });
|
|
29
|
+
} catch (e) {}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const activeConfig = mdefender.loadConfig();
|
|
33
|
+
|
|
34
|
+
if (activeConfig.mode === 'off') {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log(`\x1b[36m\x1b[1m🛡️ [MDefender Pro] Zero-Code WAF Protection Active\x1b[0m`);
|
|
39
|
+
console.log(`\x1b[90m Inspection Endpoint: ${activeConfig.apiEndpoint}\x1b[0m`);
|
|
40
|
+
console.log(`\x1b[90m Protected Domain : ${activeConfig.domain || 'auto-detect'}\x1b[0m`);
|
|
41
|
+
console.log(`\x1b[90m Defense Mode : ${activeConfig.mode.toUpperCase()}\x1b[0m\n`);
|
|
42
|
+
|
|
43
|
+
// 1. Hook Express if loaded
|
|
44
|
+
try {
|
|
45
|
+
const express = require('express');
|
|
46
|
+
if (express && express.application && typeof express.application.lazyrouter === 'function') {
|
|
47
|
+
const origLazyRouter = express.application.lazyrouter;
|
|
48
|
+
express.application.lazyrouter = function () {
|
|
49
|
+
origLazyRouter.apply(this, arguments);
|
|
50
|
+
if (!this._mdefenderAttached && this._router) {
|
|
51
|
+
this._mdefenderAttached = true;
|
|
52
|
+
this._router.use(mdefender(activeConfig));
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
} catch (e) {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Automatically activate when loaded via -r / --require
|
|
60
|
+
autoHook();
|
|
61
|
+
|
|
62
|
+
module.exports = { autoHook };
|
package/bin/mdefender.js
CHANGED
|
@@ -3,15 +3,38 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const readline = require('readline');
|
|
6
|
+
const { spawn } = require('child_process');
|
|
6
7
|
|
|
7
8
|
const args = process.argv.slice(2);
|
|
8
|
-
const command = args[0] || '
|
|
9
|
+
const command = args[0] || 'help';
|
|
9
10
|
|
|
10
|
-
console.log(`\n\x1b[36m\x1b[1m
|
|
11
|
-
console.log(`\x1b[36m\x1b[1m
|
|
12
|
-
console.log(`\x1b[36m\x1b[1m
|
|
11
|
+
console.log(`\n\x1b[36m\x1b[1m====================================================\x1b[0m`);
|
|
12
|
+
console.log(`\x1b[36m\x1b[1m 🛡️ MDefender Pro — Zero-Code WAF CLI \x1b[0m`);
|
|
13
|
+
console.log(`\x1b[36m\x1b[1m====================================================\x1b[0m\n`);
|
|
13
14
|
|
|
14
|
-
if (command === '
|
|
15
|
+
if (command === 'run' || command === 'start') {
|
|
16
|
+
const targetScript = args[1] || 'index.js';
|
|
17
|
+
const scriptPath = path.resolve(process.cwd(), targetScript);
|
|
18
|
+
|
|
19
|
+
if (!fs.existsSync(scriptPath)) {
|
|
20
|
+
console.error(`\x1b[31m[!] Target file not found: ${targetScript}\x1b[0m`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log(`\x1b[32m[+] Launching "${targetScript}" with zero-code MDefender WAF protection...\x1b[0m\n`);
|
|
25
|
+
|
|
26
|
+
const preloadModule = path.resolve(__dirname, '..', 'auto.js');
|
|
27
|
+
const child = spawn(process.execPath, ['-r', preloadModule, scriptPath], {
|
|
28
|
+
stdio: 'inherit',
|
|
29
|
+
env: process.env,
|
|
30
|
+
cwd: process.cwd(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
child.on('exit', (code) => {
|
|
34
|
+
process.exit(code || 0);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
} else if (command === 'init' || command === 'setup') {
|
|
15
38
|
const targetConfig = path.join(process.cwd(), 'mdefender.config.js');
|
|
16
39
|
|
|
17
40
|
if (fs.existsSync(targetConfig)) {
|
|
@@ -25,56 +48,84 @@ if (command === 'init' || command === 'setup') {
|
|
|
25
48
|
});
|
|
26
49
|
|
|
27
50
|
rl.question('\x1b[32mEnter your MDefender Pro API Key (from Dashboard): \x1b[0m', (apiKey) => {
|
|
28
|
-
rl.question('\x1b[32mEnter your Website Domain (e.g.
|
|
29
|
-
|
|
30
|
-
|
|
51
|
+
rl.question('\x1b[32mEnter your Website Domain (e.g. localhost or mysite.com): \x1b[0m', (domain) => {
|
|
52
|
+
rl.question('\x1b[32mEnter MDefender API Endpoint (default http://localhost:8000): \x1b[0m', (endpoint) => {
|
|
53
|
+
const trimmedKey = (apiKey || 'YOUR_API_KEY_HERE').trim();
|
|
54
|
+
const trimmedDomain = (domain || 'localhost').trim();
|
|
55
|
+
const trimmedEndpoint = (endpoint || 'http://localhost:8000').trim();
|
|
31
56
|
|
|
32
|
-
|
|
57
|
+
const configTemplate = `/**
|
|
33
58
|
* MDefender Pro Web Application Firewall Configuration
|
|
34
|
-
* Generated automatically by @mdefender/pro CLI
|
|
35
59
|
*/
|
|
36
60
|
module.exports = {
|
|
37
61
|
// Your Secret Website API Key from MDefender Dashboard
|
|
38
62
|
apiKey: process.env.MDEFENDER_API_KEY || '${trimmedKey}',
|
|
39
63
|
|
|
40
64
|
// Domain registered in MDefender Pro
|
|
41
|
-
domain: '${trimmedDomain}',
|
|
65
|
+
domain: process.env.MDEFENDER_DOMAIN || '${trimmedDomain}',
|
|
42
66
|
|
|
43
|
-
//
|
|
44
|
-
apiEndpoint: process.env.MDEFENDER_API_ENDPOINT || '
|
|
67
|
+
// Inspection Backend Endpoint
|
|
68
|
+
apiEndpoint: process.env.MDEFENDER_API_ENDPOINT || '${trimmedEndpoint}',
|
|
45
69
|
|
|
46
|
-
// Mode: 'block' (active
|
|
70
|
+
// Defense Mode: 'block' (active protection), 'monitor' (log-only), or 'off'
|
|
47
71
|
mode: 'block',
|
|
48
72
|
|
|
49
|
-
// Request timeout
|
|
50
|
-
timeout:
|
|
73
|
+
// Request timeout in ms (fails open safely if cloud unreachable)
|
|
74
|
+
timeout: 5000,
|
|
51
75
|
|
|
52
|
-
// Paths to bypass from inspection
|
|
76
|
+
// Paths to bypass from inspection
|
|
53
77
|
skipPaths: ['/favicon.ico', '/robots.txt', '/static', '/assets', '/health'],
|
|
54
78
|
|
|
55
|
-
// HTTP methods to bypass
|
|
56
|
-
skipMethods: ['OPTIONS'],
|
|
57
|
-
|
|
58
79
|
// Log blocked attacks in console
|
|
59
80
|
logBlocked: true
|
|
60
81
|
};
|
|
61
82
|
`;
|
|
62
83
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
console.log(`\x1b[90m---------------------------------------------------\x1b[0m\n`);
|
|
74
|
-
rl.close();
|
|
84
|
+
fs.writeFileSync(targetConfig, configTemplate, 'utf8');
|
|
85
|
+
console.log(`\n\x1b[32m[+] Created mdefender.config.js successfully!\x1b[0m`);
|
|
86
|
+
console.log(`\n\x1b[36mZero-Code Run Command:\x1b[0m`);
|
|
87
|
+
console.log(`\x1b[90m---------------------------------------------------\x1b[0m`);
|
|
88
|
+
console.log(` npx mdefender-pro run index.js`);
|
|
89
|
+
console.log(` OR`);
|
|
90
|
+
console.log(` node -r mdefender-pro index.js`);
|
|
91
|
+
console.log(`\x1b[90m---------------------------------------------------\x1b[0m\n`);
|
|
92
|
+
rl.close();
|
|
93
|
+
});
|
|
75
94
|
});
|
|
76
95
|
});
|
|
96
|
+
|
|
97
|
+
} else if (command === 'test') {
|
|
98
|
+
const mdefender = require('../index');
|
|
99
|
+
const config = mdefender.loadConfig();
|
|
100
|
+
|
|
101
|
+
console.log(`\x1b[33mTesting WAF connection to ${config.apiEndpoint}...\x1b[0m`);
|
|
102
|
+
|
|
103
|
+
const testPayload = {
|
|
104
|
+
domain: config.domain || 'localhost',
|
|
105
|
+
request: {
|
|
106
|
+
method: 'GET',
|
|
107
|
+
url: '/test-probe?id=1%20UNION/**/SELECT%20password%20FROM%20users',
|
|
108
|
+
ip: '127.0.0.1',
|
|
109
|
+
headers: { 'User-Agent': 'MDefender-Test-Probe' },
|
|
110
|
+
body: ''
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
mdefender.sendAnalyzeRequest(config.apiEndpoint, config.apiKey, testPayload, 5000)
|
|
115
|
+
.then((res) => {
|
|
116
|
+
console.log(`\x1b[32m[+] WAF Connection Successful!\x1b[0m`);
|
|
117
|
+
console.log(` Status Code : ${res.statusCode}`);
|
|
118
|
+
console.log(` Decision : \x1b[31m${res.data?.decision || res.data?.status}\x1b[0m`);
|
|
119
|
+
console.log(` Attack Type : ${res.data?.attack_type || res.data?.reason}`);
|
|
120
|
+
console.log(` Reference ID: ${res.data?.reference_id}\n`);
|
|
121
|
+
})
|
|
122
|
+
.catch((err) => {
|
|
123
|
+
console.error(`\x1b[31m[-] WAF Connection Failed: ${err.message}\x1b[0m\n`);
|
|
124
|
+
});
|
|
125
|
+
|
|
77
126
|
} else {
|
|
78
|
-
console.log(`
|
|
79
|
-
|
|
127
|
+
console.log(`Commands:`);
|
|
128
|
+
console.log(` \x1b[32mnpx mdefender-pro run <file>\x1b[0m Run any Node.js server with ZERO code changes`);
|
|
129
|
+
console.log(` \x1b[32mnpx mdefender-pro init\x1b[0m Generate mdefender.config.js interactively`);
|
|
130
|
+
console.log(` \x1b[32mnpx mdefender-pro test\x1b[0m Test connection to MDefender inspection engine\n`);
|
|
80
131
|
}
|
package/block-page.html
CHANGED
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
box-shadow: 0 8px 25px -4px rgba(0, 0, 0, 0.04), 0 4px 6px -2px rgba(0, 0, 0, 0.02);
|
|
44
44
|
padding: 24px 28px;
|
|
45
45
|
text-align: center;
|
|
46
|
-
animation: fadeIn 0.
|
|
46
|
+
animation: fadeIn 0.2s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
|
47
47
|
}
|
|
48
48
|
@keyframes fadeIn {
|
|
49
|
-
from { opacity: 0; transform: translateY(
|
|
49
|
+
from { opacity: 0; transform: translateY(6px); }
|
|
50
50
|
to { opacity: 1; transform: translateY(0); }
|
|
51
51
|
}
|
|
52
52
|
.logo-wrap {
|
|
@@ -102,7 +102,6 @@
|
|
|
102
102
|
color: var(--text-secondary);
|
|
103
103
|
margin-bottom: 12px;
|
|
104
104
|
}
|
|
105
|
-
|
|
106
105
|
.table-container {
|
|
107
106
|
border: 1px solid var(--border-color);
|
|
108
107
|
border-radius: 7px;
|
|
@@ -140,7 +139,6 @@
|
|
|
140
139
|
padding: 7px 12px;
|
|
141
140
|
vertical-align: middle;
|
|
142
141
|
}
|
|
143
|
-
|
|
144
142
|
.threat-row td {
|
|
145
143
|
background-color: #fff5f5 !important;
|
|
146
144
|
color: #991b1b !important;
|
|
@@ -168,7 +166,6 @@
|
|
|
168
166
|
text-decoration: none;
|
|
169
167
|
white-space: nowrap;
|
|
170
168
|
}
|
|
171
|
-
|
|
172
169
|
.ip-wrap {
|
|
173
170
|
display: flex;
|
|
174
171
|
align-items: center;
|
|
@@ -178,138 +175,93 @@
|
|
|
178
175
|
border: 1px solid rgba(0, 0, 0, 0.08);
|
|
179
176
|
border-radius: 2px;
|
|
180
177
|
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
|
181
|
-
display: inline-block;
|
|
182
|
-
vertical-align: middle;
|
|
183
178
|
}
|
|
184
|
-
|
|
185
179
|
.why-header {
|
|
186
180
|
font-size: 12.5px;
|
|
187
181
|
font-weight: 700;
|
|
188
182
|
color: #0f172a;
|
|
189
|
-
|
|
190
|
-
margin-bottom:
|
|
183
|
+
text-align: left;
|
|
184
|
+
margin-bottom: 4px;
|
|
191
185
|
}
|
|
192
186
|
.why-desc {
|
|
193
|
-
font-size:
|
|
187
|
+
font-size: 11px;
|
|
194
188
|
color: var(--text-secondary);
|
|
195
189
|
line-height: 1.45;
|
|
196
|
-
|
|
197
|
-
margin:
|
|
190
|
+
text-align: left;
|
|
191
|
+
margin-bottom: 12px;
|
|
198
192
|
}
|
|
199
|
-
|
|
200
193
|
.ref-box {
|
|
201
|
-
background: #
|
|
194
|
+
background: #f1f5f9;
|
|
202
195
|
border: 1px dashed var(--border-color);
|
|
203
196
|
border-radius: 5px;
|
|
204
|
-
padding:
|
|
197
|
+
padding: 7px;
|
|
205
198
|
font-family: var(--font-mono);
|
|
206
|
-
font-size:
|
|
199
|
+
font-size: 11px;
|
|
207
200
|
font-weight: 700;
|
|
208
|
-
color: #
|
|
209
|
-
|
|
210
|
-
margin-bottom:
|
|
211
|
-
letter-spacing: 0.5px;
|
|
201
|
+
color: #334155;
|
|
202
|
+
letter-spacing: 0.6px;
|
|
203
|
+
margin-bottom: 14px;
|
|
212
204
|
cursor: pointer;
|
|
213
|
-
transition: all 0.2s
|
|
205
|
+
transition: all 0.2s;
|
|
214
206
|
}
|
|
215
207
|
.ref-box:hover {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
208
|
+
border-color: var(--brand-1);
|
|
209
|
+
color: var(--brand-1);
|
|
210
|
+
background: #eef2ff;
|
|
219
211
|
}
|
|
220
|
-
|
|
221
212
|
.actions {
|
|
222
213
|
display: flex;
|
|
214
|
+
align-items: center;
|
|
223
215
|
justify-content: center;
|
|
224
|
-
gap:
|
|
225
|
-
margin-bottom:
|
|
216
|
+
gap: 10px;
|
|
217
|
+
margin-bottom: 12px;
|
|
226
218
|
flex-wrap: wrap;
|
|
227
219
|
}
|
|
228
220
|
.btn {
|
|
229
221
|
display: inline-flex;
|
|
230
222
|
align-items: center;
|
|
231
223
|
justify-content: center;
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
font-size:
|
|
224
|
+
gap: 6px;
|
|
225
|
+
font-family: var(--font-main);
|
|
226
|
+
font-size: 11px;
|
|
235
227
|
font-weight: 600;
|
|
228
|
+
padding: 7px 14px;
|
|
229
|
+
border-radius: 5px;
|
|
236
230
|
text-decoration: none;
|
|
231
|
+
transition: all 0.15s ease;
|
|
237
232
|
cursor: pointer;
|
|
238
|
-
transition: all 0.2s ease;
|
|
239
|
-
gap: 6px;
|
|
240
|
-
box-shadow: 0 1px 3px rgba(0,0,0,0.02);
|
|
241
|
-
border: none;
|
|
242
233
|
}
|
|
243
234
|
.btn-primary {
|
|
244
|
-
background-color: #
|
|
235
|
+
background-color: #0f172a;
|
|
245
236
|
color: #ffffff;
|
|
237
|
+
border: 1px solid #0f172a;
|
|
246
238
|
}
|
|
247
239
|
.btn-primary:hover {
|
|
248
|
-
background-color: #
|
|
249
|
-
|
|
250
|
-
box-shadow: 0
|
|
251
|
-
color: #ffffff;
|
|
240
|
+
background-color: #1e293b;
|
|
241
|
+
border-color: #1e293b;
|
|
242
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
252
243
|
}
|
|
253
244
|
.btn-secondary {
|
|
254
245
|
background-color: #ffffff;
|
|
255
|
-
color: #
|
|
246
|
+
color: #334155;
|
|
256
247
|
border: 1px solid var(--border-color);
|
|
257
248
|
}
|
|
258
249
|
.btn-secondary:hover {
|
|
259
250
|
background-color: #f8fafc;
|
|
260
|
-
color: #0f172a;
|
|
261
251
|
border-color: #94a3b8;
|
|
262
|
-
|
|
263
|
-
box-shadow: 0 3px 5px rgba(0,0,0,0.04);
|
|
252
|
+
color: #0f172a;
|
|
264
253
|
}
|
|
265
|
-
|
|
266
254
|
.footer {
|
|
267
|
-
font-size:
|
|
255
|
+
font-size: 10px;
|
|
268
256
|
color: var(--text-muted);
|
|
269
|
-
border-top: 1px solid
|
|
270
|
-
padding-top:
|
|
271
|
-
margin-top: 10px;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
@media (max-width: 768px) {
|
|
275
|
-
.container { padding: 24px; }
|
|
276
|
-
.details-table th, .details-table td {
|
|
277
|
-
display: block;
|
|
278
|
-
width: 100%;
|
|
279
|
-
border-right: none;
|
|
280
|
-
}
|
|
281
|
-
.details-table th {
|
|
282
|
-
background-color: #f8fafc;
|
|
283
|
-
padding-bottom: 6px;
|
|
284
|
-
}
|
|
285
|
-
.details-table td {
|
|
286
|
-
padding-top: 6px;
|
|
287
|
-
border-bottom: none;
|
|
288
|
-
}
|
|
289
|
-
.details-table tr {
|
|
290
|
-
border-bottom: 1px solid var(--border-color);
|
|
291
|
-
display: block;
|
|
292
|
-
}
|
|
293
|
-
.threat-cell-content {
|
|
294
|
-
flex-direction: column;
|
|
295
|
-
align-items: flex-start;
|
|
296
|
-
gap: 8px;
|
|
297
|
-
}
|
|
298
|
-
.actions {
|
|
299
|
-
flex-direction: column;
|
|
300
|
-
width: 100%;
|
|
301
|
-
max-width: 400px;
|
|
302
|
-
margin: 0 auto 12px;
|
|
303
|
-
}
|
|
304
|
-
.btn {
|
|
305
|
-
width: 100%;
|
|
306
|
-
}
|
|
257
|
+
border-top: 1px solid #f1f5f9;
|
|
258
|
+
padding-top: 8px;
|
|
307
259
|
}
|
|
308
260
|
</style>
|
|
309
261
|
</head>
|
|
310
262
|
<body>
|
|
311
263
|
<div class="container">
|
|
312
|
-
<!-- Logo Header -->
|
|
264
|
+
<!-- Shield Logo Header -->
|
|
313
265
|
<div class="logo-wrap">
|
|
314
266
|
<svg class="logo-svg" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
|
|
315
267
|
<defs>
|
|
@@ -328,11 +280,8 @@
|
|
|
328
280
|
<stop offset="0%" stop-color="#1e293b" />
|
|
329
281
|
<stop offset="100%" stop-color="#0f172a" />
|
|
330
282
|
</linearGradient>
|
|
331
|
-
<filter id="dropShadow" x="-10%" y="-10%" width="120%" height="120%">
|
|
332
|
-
<feDropShadow dx="0" dy="4" stdDeviation="4" flood-color="#0f172a" flood-opacity="0.15" />
|
|
333
|
-
</filter>
|
|
334
283
|
</defs>
|
|
335
|
-
<path d="M60 10 C85 22 98 25 98 48 C98 75 75 98 60 108 C45 98 22 75 22 48 C22 25 35 22 60 10 Z" fill="url(#shieldBg)" stroke="url(#shieldBorder)" stroke-width="3"
|
|
284
|
+
<path d="M60 10 C85 22 98 25 98 48 C98 75 75 98 60 108 C45 98 22 75 22 48 C22 25 35 22 60 10 Z" fill="url(#shieldBg)" stroke="url(#shieldBorder)" stroke-width="3" />
|
|
336
285
|
<path d="M60 18 C80 28 90 30 90 48 C90 70 70 90 60 98 C50 90 30 70 30 48 C30 30 40 28 60 18 Z" fill="none" stroke="#ffffff" stroke-width="1.5" stroke-opacity="0.8" stroke-dasharray="3 2" />
|
|
337
286
|
<path d="M60 28 C58 35 52 38 48 38 C44 38 43 42 45 44 C47 46 51 44 51 48 C51 52 46 55 42 53 C38 51 36 54 38 58 C40 62 45 60 48 64 C50 66 48 70 44 72 C48 74 54 75 58 72 C58 68 55 65 57 62 C59 59 63 61 65 58 C67 55 66 52 62 50 C64 45 68 46 70 42 C72 38 67 36 65 32 C63 28 61 25 60 28 Z" fill="url(#dragonColor)" />
|
|
338
287
|
</svg>
|
|
@@ -363,18 +312,18 @@
|
|
|
363
312
|
<th>Origin Client IP</th>
|
|
364
313
|
<td>
|
|
365
314
|
<div class="ip-wrap">
|
|
366
|
-
<img id="flag-img" src="https://flagcdn.com/w40/bd.png"
|
|
367
|
-
<span><span id="client-ip-display" style="font-family: var(--font-mono); font-weight: 700;">{{CLIENT_IP}}</span><span id="geo-text" style="color: #64748b;"> (GeoIP:
|
|
315
|
+
<img id="flag-img" src="https://flagcdn.com/w40/bd.png" width="20" height="15" alt="Flag" class="flag-img" style="display: inline-block;">
|
|
316
|
+
<span><span id="client-ip-display" style="font-family: var(--font-mono); font-weight: 700;">{{CLIENT_IP}}</span><span id="geo-text" style="color: #64748b;"> (GeoIP: BD)</span></span>
|
|
368
317
|
</div>
|
|
369
318
|
</td>
|
|
370
319
|
</tr>
|
|
371
320
|
<tr>
|
|
372
321
|
<th>Event Timestamp</th>
|
|
373
|
-
<td><span id="utc-time">{{TIMESTAMP}}</span> (Ref: <span id="unix-ref">
|
|
322
|
+
<td><span id="utc-time">{{TIMESTAMP}}</span> (Ref: <span id="unix-ref">1788786632</span>)</td>
|
|
374
323
|
</tr>
|
|
375
324
|
<tr>
|
|
376
325
|
<th>Violation Reason</th>
|
|
377
|
-
<td>Request blocked by rule ID: <span id="rule-id-val">
|
|
326
|
+
<td>Request blocked by rule ID: <span id="rule-id-val">99236</span> (Ref: {{ATTACK_TYPE}})</td>
|
|
378
327
|
</tr>
|
|
379
328
|
<tr>
|
|
380
329
|
<th>Protocol Details</th>
|
|
@@ -387,7 +336,6 @@
|
|
|
387
336
|
</table>
|
|
388
337
|
</div>
|
|
389
338
|
|
|
390
|
-
<!-- Bottom Explanatory Section -->
|
|
391
339
|
<h3 class="why-header">Why did this happen?</h3>
|
|
392
340
|
<p class="why-desc">
|
|
393
341
|
To maintain system integrity, suspicious requests are automatically analyzed and filtered. If you believe this is a valid corporate action, please share the Reference ID below with your local IT/Security operations. Regular users should clear cache or contact support.
|
|
@@ -397,27 +345,14 @@
|
|
|
397
345
|
REFERENCE ID: {{REFERENCE_ID}}
|
|
398
346
|
</div>
|
|
399
347
|
|
|
400
|
-
<!-- Actions Button Section -->
|
|
401
348
|
<div class="actions">
|
|
402
|
-
<a
|
|
403
|
-
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
404
|
-
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
|
|
405
|
-
<polyline points="22,6 12,13 2,6"></polyline>
|
|
406
|
-
</svg>
|
|
349
|
+
<a href="#" class="btn btn-primary" onclick="alert('Reference ID: {{REFERENCE_ID}}\\nContact your IT security team.'); return false;">
|
|
407
350
|
Contact Security Operations
|
|
408
351
|
</a>
|
|
409
352
|
<a href="/" class="btn btn-secondary">
|
|
410
|
-
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
411
|
-
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
|
|
412
|
-
<polyline points="9 22 9 12 15 12 15 22"></polyline>
|
|
413
|
-
</svg>
|
|
414
353
|
Return to Homepage
|
|
415
354
|
</a>
|
|
416
355
|
<button type="button" class="btn btn-secondary" onclick="copyRef()">
|
|
417
|
-
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
418
|
-
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
|
419
|
-
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
|
420
|
-
</svg>
|
|
421
356
|
Copy Reference ID
|
|
422
357
|
</button>
|
|
423
358
|
</div>
|
|
@@ -428,112 +363,23 @@
|
|
|
428
363
|
</div>
|
|
429
364
|
|
|
430
365
|
<script>
|
|
431
|
-
// Fetch GeoIP and real IP details
|
|
432
|
-
const serverDetectedIp = "{{CLIENT_IP}}";
|
|
433
|
-
const ipSpan = document.getElementById('client-ip-display');
|
|
434
|
-
const flagImg = document.getElementById('flag-img');
|
|
435
|
-
const geoText = document.getElementById('geo-text');
|
|
436
|
-
|
|
437
|
-
function updateGeoDisplay(ip, countryCode, city, country) {
|
|
438
|
-
if (ipSpan && ip) {
|
|
439
|
-
ipSpan.innerText = ip;
|
|
440
|
-
}
|
|
441
|
-
if (flagImg && countryCode) {
|
|
442
|
-
const cc = countryCode.toLowerCase();
|
|
443
|
-
flagImg.src = `https://flagcdn.com/w40/${cc}.png`;
|
|
444
|
-
flagImg.srcset = `https://flagcdn.com/w80/${cc}.png 2x`;
|
|
445
|
-
flagImg.alt = countryCode.toUpperCase();
|
|
446
|
-
flagImg.style.display = 'inline-block';
|
|
447
|
-
}
|
|
448
|
-
if (geoText) {
|
|
449
|
-
let geoInfo = '';
|
|
450
|
-
if (city && country) geoInfo = ` (GeoIP: ${city}, ${country})`;
|
|
451
|
-
else if (country) geoInfo = ` (GeoIP: ${country})`;
|
|
452
|
-
geoText.innerText = geoInfo;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (serverDetectedIp && serverDetectedIp !== '127.0.0.1' && serverDetectedIp !== '::1' && serverDetectedIp !== 'localhost' && serverDetectedIp !== 'unknown') {
|
|
457
|
-
// Real public IP forwarded by server
|
|
458
|
-
fetch(`https://ip-api.com/json/${serverDetectedIp}?fields=status,country,city,countryCode,query`)
|
|
459
|
-
.then(r => r.json())
|
|
460
|
-
.then(data => {
|
|
461
|
-
if (data.status === 'success') {
|
|
462
|
-
updateGeoDisplay(data.query || serverDetectedIp, data.countryCode, data.city, data.country);
|
|
463
|
-
}
|
|
464
|
-
}).catch(err => {
|
|
465
|
-
updateGeoDisplay(serverDetectedIp, 'BD', 'Dhaka', 'Bangladesh');
|
|
466
|
-
});
|
|
467
|
-
} else {
|
|
468
|
-
// Local / private IP - discover visitor's public GeoIP from browser client
|
|
469
|
-
fetch('https://ipapi.co/json/')
|
|
470
|
-
.then(r => r.json())
|
|
471
|
-
.then(data => {
|
|
472
|
-
if (data && data.ip) {
|
|
473
|
-
updateGeoDisplay(data.ip, data.country_code, data.city, data.country_name);
|
|
474
|
-
}
|
|
475
|
-
})
|
|
476
|
-
.catch(() => {
|
|
477
|
-
fetch('https://api.country.is')
|
|
478
|
-
.then(r => r.json())
|
|
479
|
-
.then(cData => {
|
|
480
|
-
if (cData && cData.country) {
|
|
481
|
-
updateGeoDisplay(cData.ip || serverDetectedIp, cData.country, '', cData.country);
|
|
482
|
-
}
|
|
483
|
-
})
|
|
484
|
-
.catch(() => {});
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// Convert Timestamp to UTC format
|
|
489
|
-
const timestampStr = "{{TIMESTAMP}}";
|
|
490
|
-
try {
|
|
491
|
-
const dt = new Date(timestampStr.replace(' ', 'T'));
|
|
492
|
-
if (!isNaN(dt.getTime())) {
|
|
493
|
-
document.getElementById('utc-time').innerText = dt.toISOString().replace('T', ' ').slice(0, 19) + ' UTC';
|
|
494
|
-
document.getElementById('unix-ref').innerText = Math.floor(dt.getTime() / 1000);
|
|
495
|
-
}
|
|
496
|
-
} catch (e) {}
|
|
497
|
-
|
|
498
|
-
// Dynamically compute rule ID from attack type
|
|
499
|
-
const attackType = "{{ATTACK_TYPE}}";
|
|
500
|
-
let hash = 0;
|
|
501
|
-
for (let i = 0; i < attackType.length; i++) {
|
|
502
|
-
hash = attackType.charCodeAt(i) + ((hash << 5) - hash);
|
|
503
|
-
}
|
|
504
|
-
const ruleId = Math.abs(hash % 10000) + 90000;
|
|
505
|
-
const ruleEl = document.getElementById('rule-id-val');
|
|
506
|
-
if (ruleEl) ruleEl.innerText = ruleId;
|
|
507
|
-
|
|
508
|
-
// Server host lookup
|
|
509
|
-
const srvHost = document.getElementById('server-host');
|
|
510
|
-
if (srvHost && (!srvHost.innerText || srvHost.innerText === 'Protected Website' || srvHost.innerText.includes('{{'))) {
|
|
511
|
-
srvHost.innerText = window.location.hostname || "protected.local";
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// Setup email operations mailto link
|
|
515
366
|
const refId = "{{REFERENCE_ID}}";
|
|
516
|
-
const emailLink = document.getElementById('email-link');
|
|
517
|
-
if (emailLink) {
|
|
518
|
-
emailLink.href = `mailto:security@mdefender-pro.io?subject=WAF Block Reference: ${refId}&body=Hello Security Team,%0D%0A%0D%0AMy request was blocked by the corporate WAF. Details below:%0D%0A- Reference ID: ${refId}%0D%0A- IP: ${clientIp}%0D%0A- Host: ${window.location.host}%0D%0A- Reason: ${attackType}`;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
367
|
function copyRef() {
|
|
522
368
|
navigator.clipboard.writeText(refId).then(() => {
|
|
523
369
|
const refBox = document.getElementById('ref-id-box');
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
370
|
+
if (refBox) {
|
|
371
|
+
const originalHtml = refBox.innerHTML;
|
|
372
|
+
refBox.innerHTML = 'COPIED TO CLIPBOARD! ✅';
|
|
373
|
+
refBox.style.color = '#10b981';
|
|
374
|
+
refBox.style.borderColor = '#10b981';
|
|
375
|
+
refBox.style.background = '#ecfdf5';
|
|
376
|
+
setTimeout(() => {
|
|
377
|
+
refBox.innerHTML = originalHtml;
|
|
378
|
+
refBox.style.color = '';
|
|
379
|
+
refBox.style.borderColor = '';
|
|
380
|
+
refBox.style.background = '';
|
|
381
|
+
}, 2000);
|
|
382
|
+
}
|
|
537
383
|
});
|
|
538
384
|
}
|
|
539
385
|
</script>
|