mdefender-pro 1.2.3 → 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/index.js CHANGED
@@ -35,10 +35,10 @@ function getDefaultTemplate() {
35
35
  const DEFAULT_CONFIG = {
36
36
  apiKey: '',
37
37
  domain: '',
38
- apiEndpoint: 'https://mdefenderapi.onrender.com',
38
+ apiEndpoint: process.env.MDEFENDER_API_ENDPOINT || 'http://localhost:8000',
39
39
  mode: 'block', // 'block' | 'monitor' | 'off'
40
40
  blockStatusCode: 403,
41
- timeout: 5000,
41
+ timeout: 10000,
42
42
  maxBodySize: 1024 * 1024, // 1MB
43
43
  logBlocked: true,
44
44
  customBlockPage: null,
@@ -137,7 +137,11 @@ function extractBody(req) {
137
137
  function sendAnalyzeRequest(endpointUrl, apiKey, data, timeoutMs = 5000) {
138
138
  return new Promise((resolve, reject) => {
139
139
  try {
140
- const parsed = new URL('/api/analyze', endpointUrl);
140
+ let analyzePath = '/api/v1/waf/analyze';
141
+ if (endpointUrl.endsWith('/waf/analyze') || endpointUrl.endsWith('/analyze')) {
142
+ analyzePath = '';
143
+ }
144
+ const parsed = new URL(analyzePath, endpointUrl.replace(/\/+$/, '') + '/');
141
145
  const postData = JSON.stringify(data);
142
146
  const isHttps = parsed.protocol === 'https:';
143
147
  const transport = isHttps ? https : http;
@@ -154,7 +158,7 @@ function sendAnalyzeRequest(endpointUrl, apiKey, data, timeoutMs = 5000) {
154
158
  'Content-Type': 'application/json',
155
159
  'Content-Length': Buffer.byteLength(postData),
156
160
  'Authorization': `Bearer ${apiKey}`,
157
- 'X-MDefender-Version': '1.1.0'
161
+ 'X-MDefender-Version': '1.2.4'
158
162
  }
159
163
  };
160
164
 
@@ -165,7 +169,8 @@ function sendAnalyzeRequest(endpointUrl, apiKey, data, timeoutMs = 5000) {
165
169
  res.on('end', () => {
166
170
  try {
167
171
  const json = JSON.parse(body);
168
- resolve({ statusCode: res.statusCode, data: json });
172
+ const decisionData = json && json.data ? json.data : json;
173
+ resolve({ statusCode: res.statusCode, data: decisionData });
169
174
  } catch (e) {
170
175
  resolve({ statusCode: res.statusCode, data: { status: res.statusCode === 200 ? 'allowed' : 'error', raw: body } });
171
176
  }
@@ -271,7 +276,7 @@ function mdefender(overrides = {}) {
271
276
  domain: config.domain || host.split(':')[0],
272
277
  request: {
273
278
  method: req.method,
274
- url: parsedUrl.pathname,
279
+ url: req.originalUrl || req.url || parsedUrl.pathname,
275
280
  query_string: parsedUrl.search || '',
276
281
  query_params: Object.fromEntries(parsedUrl.searchParams),
277
282
  ip: clientIp,
@@ -287,11 +292,19 @@ function mdefender(overrides = {}) {
287
292
  };
288
293
 
289
294
  const resp = await sendAnalyzeRequest(config.apiEndpoint, config.apiKey, payload, config.timeout);
290
- const result = resp.data;
291
-
292
- if (result.status === 'blocked') {
295
+ const result = resp && resp.data ? resp.data : {};
296
+ const isBlocked = Boolean(
297
+ result && (
298
+ result.decision === 'BLOCK' ||
299
+ result.action === 'block' ||
300
+ result.status === 'blocked' ||
301
+ result.blocked === true
302
+ )
303
+ );
304
+
305
+ if (isBlocked) {
293
306
  if (config.logBlocked) {
294
- console.warn(`[MDefender] BLOCKED ${req.method} ${parsedUrl.pathname} - ${result.attack_type || 'Malicious Payload'} (${((result.confidence || 0.95) * 100).toFixed(0)}%) [IP: ${clientIp}]`);
307
+ console.warn(`[MDefender] BLOCKED ${req.method} ${parsedUrl.pathname} - ${result.attack_type || result.reason || 'Malicious Payload'} (${((result.confidence || 0.95) * 100).toFixed(0)}%) [IP: ${clientIp}]`);
295
308
  }
296
309
 
297
310
  const blockPage = result.block_page || renderBlockPage(config, result, req);
@@ -337,4 +350,11 @@ mdefender.DEFAULT_CONFIG = DEFAULT_CONFIG;
337
350
  mdefender.sendAnalyzeRequest = sendAnalyzeRequest;
338
351
 
339
352
  module.exports = mdefender;
353
+
354
+ try {
355
+ const { autoHook } = require('./auto');
356
+ mdefender.autoHook = autoHook;
357
+ } catch (e) {}
358
+
359
+
340
360
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdefender-pro",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "MDefender Pro - Web Application Firewall middleware for Node.js/Express. Protects against XSS, SQLi, CSRF, and other OWASP Top 10 attacks.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -32,6 +32,7 @@
32
32
  },
33
33
  "files": [
34
34
  "index.js",
35
+ "auto.js",
35
36
  "index.d.ts",
36
37
  "README.md",
37
38
  "config-loader.js",
@@ -43,6 +44,7 @@
43
44
  ],
44
45
  "exports": {
45
46
  ".": "./index.js",
47
+ "./auto": "./auto.js",
46
48
  "./client": "./client.mjs",
47
49
  "./vite": "./vite.mjs"
48
50
  },
@@ -50,7 +52,6 @@
50
52
  "type": "git",
51
53
  "url": "git+https://github.com/mdefender/mdefender.git"
52
54
  },
53
- "homepage": "https://mdefenderapi.onrender.com",
54
55
  "bugs": {
55
56
  "url": "https://github.com/mdefender/mdefender/issues"
56
57
  }
package/vite.js CHANGED
@@ -1,15 +1,58 @@
1
1
  // vite.js - Official MDefender Pro Vite Plugin (CJS)
2
+ 'use strict';
3
+
2
4
  const mdefender = require('./index.js');
3
5
 
4
6
  function mdefenderVite(options = {}) {
5
7
  const middleware = mdefender(options);
8
+
6
9
  return {
7
10
  name: 'mdefender-vite-plugin',
8
11
  configureServer(server) {
9
- server.middlewares.use(middleware);
12
+ if (server && server.middlewares) {
13
+ server.middlewares.use(middleware);
14
+ }
10
15
  },
11
16
  configurePreviewServer(server) {
12
- server.middlewares.use(middleware);
17
+ if (server && server.middlewares) {
18
+ server.middlewares.use(middleware);
19
+ }
20
+ },
21
+ transformIndexHtml(html) {
22
+ const inlineGuard = [
23
+ '<script>',
24
+ '(function(){',
25
+ ' try {',
26
+ ' var raw = (window.location.search || "") + " " + (window.location.hash || "");',
27
+ ' if (!raw.trim()) return;',
28
+ ' var norm = raw;',
29
+ ' try { norm = decodeURIComponent(norm); } catch(e){}',
30
+ ' try { norm = decodeURIComponent(norm); } catch(e){}',
31
+ ' var p = [',
32
+ ' /<\\s*(?:script|iframe|object|embed|svg|img|math)\\b/i,',
33
+ ' /\\bon(?:error|load|click|mouseover|focus|submit)\\s*=/i,',
34
+ ' /\\b(?:javascript|data\\s*:\\s*text\\/html)\\s*:/i,',
35
+ ' /\\b(?:alert|eval|confirm|prompt|document\\.cookie)\\s*\\(/i,',
36
+ ' /\\bUNION\\s+(?:ALL\\s+)?SELECT\\b/i,',
37
+ ' /(?:\'|"|\\b)\\s*(?:OR|AND)\\s+[\'"]?([a-zA-Z0-9_\\-]+)[\'"]?\\s*=\\s*[\'"]?\\1/i,',
38
+ ' /(?:--|#|\\/\\*).*?(?:DROP|ALTER|INSERT|DELETE|UPDATE|EXEC)/i,',
39
+ ' /(?:\\.\\.\\/|\\.\\.\\\\|etc\\/passwd|etc\\/shadow|win\\.ini|boot\\.ini)/i,',
40
+ ' /(?:169\\.254\\.169\\.254|metadata\\.google\\.internal|=(?:https?:\\/\\/)?(?:127\\.0\\.0\\.1|169\\.254|localhost|0\\.0\\.0\\.0))/i,',
41
+ ' /(?:;|\\||\\|\\||&&|`|\\$\\()\\s*(?:cat|ls|id|whoami|powershell|cmd|sh|bash|wget|curl)\\b/i,',
42
+ ' /(?:ignore\\s+all\\s+(?:previous|prior)\\s+instructions|system\\s+override|DAN\\s+mode)/i',
43
+ ' ];',
44
+ ' for (var i = 0; i < p.length; i++) {',
45
+ ' if (p[i].test(norm)) {',
46
+ ' try { window.stop(); } catch(e){}',
47
+ ' break;',
48
+ ' }',
49
+ ' }',
50
+ ' } catch(e){}',
51
+ '})();',
52
+ '</script>'
53
+ ].join('\\n');
54
+
55
+ return html.replace('<head>', '<head>\\n' + inlineGuard);
13
56
  }
14
57
  };
15
58
  }