honeyweb-core 2.0.3 → 2.0.4
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/ai/gemini.js +9 -34
- package/ai/index.js +4 -27
- package/config/defaults.js +13 -36
- package/config/index.js +7 -35
- package/config/schema.js +1 -17
- package/detection/behavioral.js +26 -118
- package/detection/bot-detector.js +11 -62
- package/detection/index.js +19 -35
- package/detection/patterns.js +14 -51
- package/detection/rate-limiter.js +15 -86
- package/detection/traversal.js +42 -0
- package/index.js +1 -13
- package/middleware/blocklist-checker.js +1 -15
- package/middleware/dashboard.js +0 -17
- package/middleware/index.js +10 -46
- package/middleware/request-analyzer.js +29 -74
- package/middleware/trap-injector.js +3 -28
- package/package.json +1 -1
- package/storage/bot-tracker.js +9 -56
- package/storage/index.js +3 -12
- package/storage/json-store.js +15 -89
- package/storage/memory-store.js +9 -61
- package/utils/cache.js +5 -48
- package/utils/dns-verify.js +8 -45
- package/utils/event-emitter.js +7 -39
- package/utils/logger.js +9 -35
package/storage/json-store.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// honeyweb-core/storage/json-store.js
|
|
2
|
-
// Async JSON storage with in-memory cache
|
|
3
2
|
|
|
4
3
|
const fs = require('fs-extra');
|
|
5
4
|
const path = require('path');
|
|
@@ -8,18 +7,14 @@ const LRUCache = require('../utils/cache');
|
|
|
8
7
|
class JsonStore {
|
|
9
8
|
constructor(config) {
|
|
10
9
|
this.filePath = path.resolve(config.path || './blocked-ips.json');
|
|
11
|
-
this.banDuration = config.banDuration || 86400000;
|
|
10
|
+
this.banDuration = config.banDuration || 86400000;
|
|
12
11
|
this.autoCleanup = config.autoCleanup !== false;
|
|
13
|
-
this.cache = config.cache ? new LRUCache(1000, 60000) : null;
|
|
12
|
+
this.cache = config.cache ? new LRUCache(1000, 60000) : null;
|
|
14
13
|
|
|
15
|
-
// Initialize file
|
|
16
14
|
this._initFile();
|
|
17
15
|
|
|
18
|
-
// Start auto-cleanup if enabled
|
|
19
16
|
if (this.autoCleanup) {
|
|
20
|
-
this.cleanupInterval = setInterval(() =>
|
|
21
|
-
this._cleanupExpired();
|
|
22
|
-
}, 300000); // Clean up every 5 minutes
|
|
17
|
+
this.cleanupInterval = setInterval(() => this._cleanupExpired(), 300000);
|
|
23
18
|
}
|
|
24
19
|
}
|
|
25
20
|
|
|
@@ -33,24 +28,12 @@ class JsonStore {
|
|
|
33
28
|
}
|
|
34
29
|
}
|
|
35
30
|
|
|
36
|
-
/**
|
|
37
|
-
* Get all banned IPs
|
|
38
|
-
* @returns {Promise<Array>} - Array of banned IP objects
|
|
39
|
-
*/
|
|
40
31
|
async getAll() {
|
|
41
|
-
|
|
42
|
-
if (this.cache && this.cache.has('all')) {
|
|
43
|
-
return this.cache.get('all');
|
|
44
|
-
}
|
|
32
|
+
if (this.cache && this.cache.has('all')) return this.cache.get('all');
|
|
45
33
|
|
|
46
34
|
try {
|
|
47
35
|
const data = await fs.readJson(this.filePath);
|
|
48
|
-
|
|
49
|
-
// Cache the result
|
|
50
|
-
if (this.cache) {
|
|
51
|
-
this.cache.set('all', data);
|
|
52
|
-
}
|
|
53
|
-
|
|
36
|
+
if (this.cache) this.cache.set('all', data);
|
|
54
37
|
return data;
|
|
55
38
|
} catch (err) {
|
|
56
39
|
console.error('[JsonStore] Error reading file:', err);
|
|
@@ -58,24 +41,16 @@ class JsonStore {
|
|
|
58
41
|
}
|
|
59
42
|
}
|
|
60
43
|
|
|
61
|
-
/**
|
|
62
|
-
* Check if IP is banned
|
|
63
|
-
* @param {string} ip
|
|
64
|
-
* @returns {Promise<boolean>}
|
|
65
|
-
*/
|
|
66
44
|
async isBanned(ip) {
|
|
67
45
|
const bannedIPs = await this.getAll();
|
|
68
46
|
|
|
69
|
-
// Support both simple array format and object format
|
|
70
47
|
if (bannedIPs.length > 0 && typeof bannedIPs[0] === 'string') {
|
|
71
48
|
return bannedIPs.includes(ip);
|
|
72
49
|
}
|
|
73
50
|
|
|
74
|
-
// Object format with expiry
|
|
75
51
|
const entry = bannedIPs.find(entry => entry.ip === ip);
|
|
76
52
|
if (!entry) return false;
|
|
77
53
|
|
|
78
|
-
// Check if expired
|
|
79
54
|
if (entry.expiry && Date.now() > entry.expiry) {
|
|
80
55
|
await this.unban(ip);
|
|
81
56
|
return false;
|
|
@@ -84,79 +59,47 @@ class JsonStore {
|
|
|
84
59
|
return true;
|
|
85
60
|
}
|
|
86
61
|
|
|
87
|
-
/**
|
|
88
|
-
* Ban an IP
|
|
89
|
-
* @param {string} ip
|
|
90
|
-
* @param {string} reason
|
|
91
|
-
* @returns {Promise<void>}
|
|
92
|
-
*/
|
|
93
62
|
async ban(ip, reason = 'Suspicious activity') {
|
|
94
63
|
const bannedIPs = await this.getAll();
|
|
95
64
|
|
|
96
|
-
|
|
97
|
-
const existingIndex = bannedIPs.findIndex(entry =>
|
|
65
|
+
const exists = bannedIPs.some(entry =>
|
|
98
66
|
typeof entry === 'string' ? entry === ip : entry.ip === ip
|
|
99
67
|
);
|
|
68
|
+
if (exists) return;
|
|
100
69
|
|
|
101
|
-
|
|
102
|
-
return; // Already banned
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Add new ban with expiry
|
|
106
|
-
const banEntry = {
|
|
70
|
+
bannedIPs.push({
|
|
107
71
|
ip,
|
|
108
72
|
reason,
|
|
109
73
|
timestamp: Date.now(),
|
|
110
74
|
expiry: Date.now() + this.banDuration
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
bannedIPs.push(banEntry);
|
|
75
|
+
});
|
|
114
76
|
|
|
115
77
|
await this._save(bannedIPs);
|
|
116
78
|
}
|
|
117
79
|
|
|
118
|
-
/**
|
|
119
|
-
* Unban an IP
|
|
120
|
-
* @param {string} ip
|
|
121
|
-
* @returns {Promise<void>}
|
|
122
|
-
*/
|
|
123
80
|
async unban(ip) {
|
|
124
81
|
const bannedIPs = await this.getAll();
|
|
125
|
-
|
|
126
82
|
const filtered = bannedIPs.filter(entry =>
|
|
127
83
|
typeof entry === 'string' ? entry !== ip : entry.ip !== ip
|
|
128
84
|
);
|
|
129
|
-
|
|
130
85
|
await this._save(filtered);
|
|
131
86
|
}
|
|
132
87
|
|
|
133
|
-
/**
|
|
134
|
-
* Save data to file and invalidate cache
|
|
135
|
-
* @private
|
|
136
|
-
*/
|
|
137
88
|
async _save(data) {
|
|
138
89
|
try {
|
|
139
90
|
await fs.writeJson(this.filePath, data, { spaces: 2 });
|
|
140
|
-
|
|
141
|
-
// Invalidate cache
|
|
142
|
-
if (this.cache) {
|
|
143
|
-
this.cache.delete('all');
|
|
144
|
-
}
|
|
91
|
+
if (this.cache) this.cache.delete('all');
|
|
145
92
|
} catch (err) {
|
|
146
93
|
console.error('[JsonStore] Error writing file:', err);
|
|
147
94
|
}
|
|
148
95
|
}
|
|
149
96
|
|
|
150
|
-
/**
|
|
151
|
-
* Clean up expired bans
|
|
152
|
-
* @private
|
|
153
|
-
*/
|
|
154
97
|
async _cleanupExpired() {
|
|
155
98
|
const bannedIPs = await this.getAll();
|
|
156
99
|
const now = Date.now();
|
|
157
100
|
|
|
158
101
|
const active = bannedIPs.filter(entry => {
|
|
159
|
-
if (typeof entry === 'string') return true;
|
|
102
|
+
if (typeof entry === 'string') return true;
|
|
160
103
|
return !entry.expiry || now <= entry.expiry;
|
|
161
104
|
});
|
|
162
105
|
|
|
@@ -165,41 +108,24 @@ class JsonStore {
|
|
|
165
108
|
}
|
|
166
109
|
}
|
|
167
110
|
|
|
168
|
-
/**
|
|
169
|
-
* Get statistics
|
|
170
|
-
* @returns {Promise<Object>}
|
|
171
|
-
*/
|
|
172
111
|
async getStats() {
|
|
173
112
|
const bannedIPs = await this.getAll();
|
|
174
113
|
const now = Date.now();
|
|
175
|
-
|
|
176
|
-
let active = 0;
|
|
177
|
-
let expired = 0;
|
|
114
|
+
let active = 0, expired = 0;
|
|
178
115
|
|
|
179
116
|
bannedIPs.forEach(entry => {
|
|
180
|
-
if (typeof entry === 'string') {
|
|
181
|
-
active++;
|
|
182
|
-
} else if (!entry.expiry || now <= entry.expiry) {
|
|
117
|
+
if (typeof entry === 'string' || !entry.expiry || now <= entry.expiry) {
|
|
183
118
|
active++;
|
|
184
119
|
} else {
|
|
185
120
|
expired++;
|
|
186
121
|
}
|
|
187
122
|
});
|
|
188
123
|
|
|
189
|
-
return {
|
|
190
|
-
total: bannedIPs.length,
|
|
191
|
-
active,
|
|
192
|
-
expired
|
|
193
|
-
};
|
|
124
|
+
return { total: bannedIPs.length, active, expired };
|
|
194
125
|
}
|
|
195
126
|
|
|
196
|
-
/**
|
|
197
|
-
* Cleanup and stop intervals
|
|
198
|
-
*/
|
|
199
127
|
destroy() {
|
|
200
|
-
if (this.cleanupInterval)
|
|
201
|
-
clearInterval(this.cleanupInterval);
|
|
202
|
-
}
|
|
128
|
+
if (this.cleanupInterval) clearInterval(this.cleanupInterval);
|
|
203
129
|
}
|
|
204
130
|
}
|
|
205
131
|
|
package/storage/memory-store.js
CHANGED
|
@@ -1,45 +1,28 @@
|
|
|
1
1
|
// honeyweb-core/storage/memory-store.js
|
|
2
|
-
// In-memory storage for testing
|
|
3
2
|
|
|
4
3
|
class MemoryStore {
|
|
5
4
|
constructor(config) {
|
|
6
|
-
this.bannedIPs = new Map();
|
|
7
|
-
this.banDuration = config.banDuration || 86400000;
|
|
5
|
+
this.bannedIPs = new Map();
|
|
6
|
+
this.banDuration = config.banDuration || 86400000;
|
|
8
7
|
this.autoCleanup = config.autoCleanup !== false;
|
|
9
8
|
|
|
10
|
-
// Start auto-cleanup if enabled
|
|
11
9
|
if (this.autoCleanup) {
|
|
12
|
-
this.cleanupInterval = setInterval(() =>
|
|
13
|
-
this._cleanupExpired();
|
|
14
|
-
}, 60000); // Clean up every minute
|
|
10
|
+
this.cleanupInterval = setInterval(() => this._cleanupExpired(), 60000);
|
|
15
11
|
}
|
|
16
12
|
}
|
|
17
13
|
|
|
18
|
-
/**
|
|
19
|
-
* Get all banned IPs
|
|
20
|
-
* @returns {Promise<Array>}
|
|
21
|
-
*/
|
|
22
14
|
async getAll() {
|
|
23
15
|
const result = [];
|
|
24
16
|
for (const [ip, data] of this.bannedIPs.entries()) {
|
|
25
|
-
result.push({
|
|
26
|
-
ip,
|
|
27
|
-
...data
|
|
28
|
-
});
|
|
17
|
+
result.push({ ip, ...data });
|
|
29
18
|
}
|
|
30
19
|
return result;
|
|
31
20
|
}
|
|
32
21
|
|
|
33
|
-
/**
|
|
34
|
-
* Check if IP is banned
|
|
35
|
-
* @param {string} ip
|
|
36
|
-
* @returns {Promise<boolean>}
|
|
37
|
-
*/
|
|
38
22
|
async isBanned(ip) {
|
|
39
23
|
const entry = this.bannedIPs.get(ip);
|
|
40
24
|
if (!entry) return false;
|
|
41
25
|
|
|
42
|
-
// Check if expired
|
|
43
26
|
if (entry.expiry && Date.now() > entry.expiry) {
|
|
44
27
|
this.bannedIPs.delete(ip);
|
|
45
28
|
return false;
|
|
@@ -48,12 +31,6 @@ class MemoryStore {
|
|
|
48
31
|
return true;
|
|
49
32
|
}
|
|
50
33
|
|
|
51
|
-
/**
|
|
52
|
-
* Ban an IP
|
|
53
|
-
* @param {string} ip
|
|
54
|
-
* @param {string} reason
|
|
55
|
-
* @returns {Promise<void>}
|
|
56
|
-
*/
|
|
57
34
|
async ban(ip, reason = 'Suspicious activity') {
|
|
58
35
|
this.bannedIPs.set(ip, {
|
|
59
36
|
reason,
|
|
@@ -62,19 +39,10 @@ class MemoryStore {
|
|
|
62
39
|
});
|
|
63
40
|
}
|
|
64
41
|
|
|
65
|
-
/**
|
|
66
|
-
* Unban an IP
|
|
67
|
-
* @param {string} ip
|
|
68
|
-
* @returns {Promise<void>}
|
|
69
|
-
*/
|
|
70
42
|
async unban(ip) {
|
|
71
43
|
this.bannedIPs.delete(ip);
|
|
72
44
|
}
|
|
73
45
|
|
|
74
|
-
/**
|
|
75
|
-
* Clean up expired bans
|
|
76
|
-
* @private
|
|
77
|
-
*/
|
|
78
46
|
_cleanupExpired() {
|
|
79
47
|
const now = Date.now();
|
|
80
48
|
for (const [ip, entry] of this.bannedIPs.entries()) {
|
|
@@ -84,44 +52,24 @@ class MemoryStore {
|
|
|
84
52
|
}
|
|
85
53
|
}
|
|
86
54
|
|
|
87
|
-
/**
|
|
88
|
-
* Get statistics
|
|
89
|
-
* @returns {Promise<Object>}
|
|
90
|
-
*/
|
|
91
55
|
async getStats() {
|
|
92
56
|
const now = Date.now();
|
|
93
|
-
let active = 0;
|
|
94
|
-
let expired = 0;
|
|
57
|
+
let active = 0, expired = 0;
|
|
95
58
|
|
|
96
59
|
for (const entry of this.bannedIPs.values()) {
|
|
97
|
-
if (!entry.expiry || now <= entry.expiry)
|
|
98
|
-
|
|
99
|
-
} else {
|
|
100
|
-
expired++;
|
|
101
|
-
}
|
|
60
|
+
if (!entry.expiry || now <= entry.expiry) active++;
|
|
61
|
+
else expired++;
|
|
102
62
|
}
|
|
103
63
|
|
|
104
|
-
return {
|
|
105
|
-
total: this.bannedIPs.size,
|
|
106
|
-
active,
|
|
107
|
-
expired
|
|
108
|
-
};
|
|
64
|
+
return { total: this.bannedIPs.size, active, expired };
|
|
109
65
|
}
|
|
110
66
|
|
|
111
|
-
/**
|
|
112
|
-
* Clear all bans
|
|
113
|
-
*/
|
|
114
67
|
clear() {
|
|
115
68
|
this.bannedIPs.clear();
|
|
116
69
|
}
|
|
117
70
|
|
|
118
|
-
/**
|
|
119
|
-
* Cleanup and stop intervals
|
|
120
|
-
*/
|
|
121
71
|
destroy() {
|
|
122
|
-
if (this.cleanupInterval)
|
|
123
|
-
clearInterval(this.cleanupInterval);
|
|
124
|
-
}
|
|
72
|
+
if (this.cleanupInterval) clearInterval(this.cleanupInterval);
|
|
125
73
|
}
|
|
126
74
|
}
|
|
127
75
|
|
package/utils/cache.js
CHANGED
|
@@ -1,26 +1,16 @@
|
|
|
1
1
|
// honeyweb-core/utils/cache.js
|
|
2
|
-
// LRU cache implementation for DNS verification and blocklist
|
|
3
2
|
|
|
4
3
|
class LRUCache {
|
|
5
4
|
constructor(maxSize = 1000, ttl = 3600000) {
|
|
6
5
|
this.maxSize = maxSize;
|
|
7
|
-
this.ttl = ttl;
|
|
6
|
+
this.ttl = ttl;
|
|
8
7
|
this.cache = new Map();
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
/**
|
|
12
|
-
* Get value from cache
|
|
13
|
-
* @param {string} key
|
|
14
|
-
* @returns {*} - Value or undefined if not found/expired
|
|
15
|
-
*/
|
|
16
10
|
get(key) {
|
|
17
11
|
const item = this.cache.get(key);
|
|
12
|
+
if (!item) return undefined;
|
|
18
13
|
|
|
19
|
-
if (!item) {
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Check if expired
|
|
24
14
|
if (Date.now() > item.expiry) {
|
|
25
15
|
this.cache.delete(key);
|
|
26
16
|
return undefined;
|
|
@@ -29,76 +19,43 @@ class LRUCache {
|
|
|
29
19
|
// Move to end (most recently used)
|
|
30
20
|
this.cache.delete(key);
|
|
31
21
|
this.cache.set(key, item);
|
|
32
|
-
|
|
33
22
|
return item.value;
|
|
34
23
|
}
|
|
35
24
|
|
|
36
|
-
/**
|
|
37
|
-
* Set value in cache
|
|
38
|
-
* @param {string} key
|
|
39
|
-
* @param {*} value
|
|
40
|
-
* @param {number} customTTL - Optional custom TTL for this entry
|
|
41
|
-
*/
|
|
42
25
|
set(key, value, customTTL) {
|
|
43
|
-
|
|
44
|
-
if (this.cache.has(key)) {
|
|
45
|
-
this.cache.delete(key);
|
|
46
|
-
}
|
|
26
|
+
if (this.cache.has(key)) this.cache.delete(key);
|
|
47
27
|
|
|
48
|
-
// Evict oldest if at capacity
|
|
49
28
|
if (this.cache.size >= this.maxSize) {
|
|
50
29
|
const firstKey = this.cache.keys().next().value;
|
|
51
30
|
this.cache.delete(firstKey);
|
|
52
31
|
}
|
|
53
32
|
|
|
54
|
-
const ttl = customTTL || this.ttl;
|
|
55
33
|
this.cache.set(key, {
|
|
56
34
|
value,
|
|
57
|
-
expiry: Date.now() + ttl
|
|
35
|
+
expiry: Date.now() + (customTTL || this.ttl)
|
|
58
36
|
});
|
|
59
37
|
}
|
|
60
38
|
|
|
61
|
-
/**
|
|
62
|
-
* Check if key exists and is not expired
|
|
63
|
-
* @param {string} key
|
|
64
|
-
* @returns {boolean}
|
|
65
|
-
*/
|
|
66
39
|
has(key) {
|
|
67
40
|
return this.get(key) !== undefined;
|
|
68
41
|
}
|
|
69
42
|
|
|
70
|
-
/**
|
|
71
|
-
* Delete key from cache
|
|
72
|
-
* @param {string} key
|
|
73
|
-
*/
|
|
74
43
|
delete(key) {
|
|
75
44
|
this.cache.delete(key);
|
|
76
45
|
}
|
|
77
46
|
|
|
78
|
-
/**
|
|
79
|
-
* Clear all entries
|
|
80
|
-
*/
|
|
81
47
|
clear() {
|
|
82
48
|
this.cache.clear();
|
|
83
49
|
}
|
|
84
50
|
|
|
85
|
-
/**
|
|
86
|
-
* Get cache size
|
|
87
|
-
* @returns {number}
|
|
88
|
-
*/
|
|
89
51
|
size() {
|
|
90
52
|
return this.cache.size;
|
|
91
53
|
}
|
|
92
54
|
|
|
93
|
-
/**
|
|
94
|
-
* Clean up expired entries
|
|
95
|
-
*/
|
|
96
55
|
cleanup() {
|
|
97
56
|
const now = Date.now();
|
|
98
57
|
for (const [key, item] of this.cache.entries()) {
|
|
99
|
-
if (now > item.expiry)
|
|
100
|
-
this.cache.delete(key);
|
|
101
|
-
}
|
|
58
|
+
if (now > item.expiry) this.cache.delete(key);
|
|
102
59
|
}
|
|
103
60
|
}
|
|
104
61
|
}
|
package/utils/dns-verify.js
CHANGED
|
@@ -1,92 +1,55 @@
|
|
|
1
1
|
// honeyweb-core/utils/dns-verify.js
|
|
2
|
-
// DNS verification utilities for bot whitelist
|
|
3
2
|
|
|
4
3
|
const dns = require('dns').promises;
|
|
5
4
|
const LRUCache = require('./cache');
|
|
6
5
|
|
|
7
6
|
class DNSVerifier {
|
|
8
7
|
constructor(cacheTTL = 86400000) {
|
|
9
|
-
// Cache DNS results for 24 hours by default
|
|
10
8
|
this.cache = new LRUCache(500, cacheTTL);
|
|
11
9
|
}
|
|
12
10
|
|
|
13
|
-
/**
|
|
14
|
-
* Verify if IP belongs to claimed bot domain
|
|
15
|
-
* @param {string} ip - IP address to verify
|
|
16
|
-
* @param {string} expectedDomain - Expected domain pattern (e.g., 'googlebot.com')
|
|
17
|
-
* @returns {Promise<Object>} - { verified: boolean, hostname: string, error: string }
|
|
18
|
-
*/
|
|
19
11
|
async verify(ip, expectedDomain) {
|
|
20
|
-
// Check cache first
|
|
21
12
|
const cacheKey = `${ip}:${expectedDomain}`;
|
|
22
|
-
if (this.cache.has(cacheKey))
|
|
23
|
-
return this.cache.get(cacheKey);
|
|
24
|
-
}
|
|
13
|
+
if (this.cache.has(cacheKey)) return this.cache.get(cacheKey);
|
|
25
14
|
|
|
26
15
|
try {
|
|
27
|
-
//
|
|
16
|
+
// Reverse DNS: IP -> hostname
|
|
28
17
|
const hostnames = await dns.reverse(ip);
|
|
29
18
|
|
|
30
19
|
if (!hostnames || hostnames.length === 0) {
|
|
31
|
-
const result = {
|
|
32
|
-
verified: false,
|
|
33
|
-
hostname: null,
|
|
34
|
-
error: 'No reverse DNS record found'
|
|
35
|
-
};
|
|
20
|
+
const result = { verified: false, hostname: null, error: 'No reverse DNS record found' };
|
|
36
21
|
this.cache.set(cacheKey, result);
|
|
37
22
|
return result;
|
|
38
23
|
}
|
|
39
24
|
|
|
40
25
|
const hostname = hostnames[0];
|
|
41
26
|
|
|
42
|
-
// Step 2: Check if hostname matches expected domain
|
|
43
27
|
if (!hostname.endsWith(expectedDomain)) {
|
|
44
|
-
const result = {
|
|
45
|
-
verified: false,
|
|
46
|
-
hostname,
|
|
47
|
-
error: `Hostname ${hostname} does not match expected domain ${expectedDomain}`
|
|
48
|
-
};
|
|
28
|
+
const result = { verified: false, hostname, error: `Hostname ${hostname} does not match ${expectedDomain}` };
|
|
49
29
|
this.cache.set(cacheKey, result);
|
|
50
30
|
return result;
|
|
51
31
|
}
|
|
52
32
|
|
|
53
|
-
//
|
|
33
|
+
// Forward DNS: hostname -> IP (verification)
|
|
54
34
|
const addresses = await dns.resolve4(hostname);
|
|
55
35
|
|
|
56
36
|
if (!addresses.includes(ip)) {
|
|
57
|
-
const result = {
|
|
58
|
-
verified: false,
|
|
59
|
-
hostname,
|
|
60
|
-
error: 'Forward DNS lookup does not match original IP'
|
|
61
|
-
};
|
|
37
|
+
const result = { verified: false, hostname, error: 'Forward DNS does not match original IP' };
|
|
62
38
|
this.cache.set(cacheKey, result);
|
|
63
39
|
return result;
|
|
64
40
|
}
|
|
65
41
|
|
|
66
|
-
|
|
67
|
-
const result = {
|
|
68
|
-
verified: true,
|
|
69
|
-
hostname,
|
|
70
|
-
error: null
|
|
71
|
-
};
|
|
42
|
+
const result = { verified: true, hostname, error: null };
|
|
72
43
|
this.cache.set(cacheKey, result);
|
|
73
44
|
return result;
|
|
74
45
|
|
|
75
46
|
} catch (err) {
|
|
76
|
-
const result = {
|
|
77
|
-
verified: false,
|
|
78
|
-
hostname: null,
|
|
79
|
-
error: err.message
|
|
80
|
-
};
|
|
81
|
-
// Cache failures for shorter time (5 minutes)
|
|
47
|
+
const result = { verified: false, hostname: null, error: err.message };
|
|
82
48
|
this.cache.set(cacheKey, result, 300000);
|
|
83
49
|
return result;
|
|
84
50
|
}
|
|
85
51
|
}
|
|
86
52
|
|
|
87
|
-
/**
|
|
88
|
-
* Clear DNS cache
|
|
89
|
-
*/
|
|
90
53
|
clearCache() {
|
|
91
54
|
this.cache.clear();
|
|
92
55
|
}
|
package/utils/event-emitter.js
CHANGED
|
@@ -1,64 +1,32 @@
|
|
|
1
1
|
// honeyweb-core/utils/event-emitter.js
|
|
2
|
-
//
|
|
2
|
+
// Events: trap:triggered, threat:detected, ip:banned, request:blocked, ai:analysis
|
|
3
3
|
|
|
4
4
|
const { EventEmitter } = require('events');
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* HoneyWeb Event Emitter
|
|
8
|
-
* Provides a centralized event system for middleware extensibility
|
|
9
|
-
*
|
|
10
|
-
* Events:
|
|
11
|
-
* - 'trap:triggered' - { ip, path, timestamp }
|
|
12
|
-
* - 'threat:detected' - { ip, threats, threatLevel, timestamp }
|
|
13
|
-
* - 'ip:banned' - { ip, reason, timestamp }
|
|
14
|
-
* - 'request:blocked' - { ip, reason, timestamp }
|
|
15
|
-
* - 'ai:analysis' - { ip, report, timestamp }
|
|
16
|
-
*/
|
|
17
6
|
class HoneyWebEvents extends EventEmitter {
|
|
18
7
|
constructor() {
|
|
19
8
|
super();
|
|
20
|
-
this.setMaxListeners(20);
|
|
9
|
+
this.setMaxListeners(20);
|
|
21
10
|
}
|
|
22
11
|
|
|
23
12
|
emitTrapTriggered(ip, path) {
|
|
24
|
-
this.emit('trap:triggered', {
|
|
25
|
-
ip,
|
|
26
|
-
path,
|
|
27
|
-
timestamp: Date.now()
|
|
28
|
-
});
|
|
13
|
+
this.emit('trap:triggered', { ip, path, timestamp: Date.now() });
|
|
29
14
|
}
|
|
30
15
|
|
|
31
16
|
emitThreatDetected(ip, threats, threatLevel) {
|
|
32
|
-
this.emit('threat:detected', {
|
|
33
|
-
ip,
|
|
34
|
-
threats,
|
|
35
|
-
threatLevel,
|
|
36
|
-
timestamp: Date.now()
|
|
37
|
-
});
|
|
17
|
+
this.emit('threat:detected', { ip, threats, threatLevel, timestamp: Date.now() });
|
|
38
18
|
}
|
|
39
19
|
|
|
40
20
|
emitIpBanned(ip, reason) {
|
|
41
|
-
this.emit('ip:banned', {
|
|
42
|
-
ip,
|
|
43
|
-
reason,
|
|
44
|
-
timestamp: Date.now()
|
|
45
|
-
});
|
|
21
|
+
this.emit('ip:banned', { ip, reason, timestamp: Date.now() });
|
|
46
22
|
}
|
|
47
23
|
|
|
48
24
|
emitRequestBlocked(ip, reason) {
|
|
49
|
-
this.emit('request:blocked', {
|
|
50
|
-
ip,
|
|
51
|
-
reason,
|
|
52
|
-
timestamp: Date.now()
|
|
53
|
-
});
|
|
25
|
+
this.emit('request:blocked', { ip, reason, timestamp: Date.now() });
|
|
54
26
|
}
|
|
55
27
|
|
|
56
28
|
emitAiAnalysis(ip, report) {
|
|
57
|
-
this.emit('ai:analysis', {
|
|
58
|
-
ip,
|
|
59
|
-
report,
|
|
60
|
-
timestamp: Date.now()
|
|
61
|
-
});
|
|
29
|
+
this.emit('ai:analysis', { ip, report, timestamp: Date.now() });
|
|
62
30
|
}
|
|
63
31
|
}
|
|
64
32
|
|