honeyweb-core 2.0.2 → 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.
@@ -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(); // ip -> { reason, timestamp, expiry }
7
- this.banDuration = config.banDuration || 86400000; // 24 hours
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
- active++;
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; // Time to live in milliseconds
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
- // Remove if already exists
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
  }
@@ -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
- // Step 1: Reverse DNS lookup (IP -> hostname)
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
- // Step 3: Forward DNS lookup (hostname -> IP) to verify
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
- // Verification successful
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
  }
@@ -1,64 +1,32 @@
1
1
  // honeyweb-core/utils/event-emitter.js
2
- // Event system for extensibility
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); // Allow more listeners for extensibility
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
 
package/utils/logger.js CHANGED
@@ -1,12 +1,6 @@
1
1
  // honeyweb-core/utils/logger.js
2
- // Structured logging utility
3
2
 
4
- const LOG_LEVELS = {
5
- debug: 0,
6
- info: 1,
7
- warn: 2,
8
- error: 3
9
- };
3
+ const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
10
4
 
11
5
  class Logger {
12
6
  constructor(config = {}) {
@@ -23,48 +17,31 @@ class Logger {
23
17
  const timestamp = new Date().toISOString();
24
18
 
25
19
  if (this.format === 'json') {
26
- return JSON.stringify({
27
- timestamp,
28
- level: level.toUpperCase(),
29
- message,
30
- ...meta
31
- });
20
+ return JSON.stringify({ timestamp, level: level.toUpperCase(), message, ...meta });
32
21
  }
33
22
 
34
- // Pretty format
35
- const metaStr = Object.keys(meta).length > 0
36
- ? ' ' + JSON.stringify(meta)
37
- : '';
23
+ const metaStr = Object.keys(meta).length > 0 ? ' ' + JSON.stringify(meta) : '';
38
24
  return `${this.prefix} [${level.toUpperCase()}] ${message}${metaStr}`;
39
25
  }
40
26
 
41
27
  debug(message, meta) {
42
- if (this._shouldLog('debug')) {
43
- console.log(this._formatMessage('debug', message, meta));
44
- }
28
+ if (this._shouldLog('debug')) console.log(this._formatMessage('debug', message, meta));
45
29
  }
46
30
 
47
31
  info(message, meta) {
48
- if (this._shouldLog('info')) {
49
- console.log(this._formatMessage('info', message, meta));
50
- }
32
+ if (this._shouldLog('info')) console.log(this._formatMessage('info', message, meta));
51
33
  }
52
34
 
53
35
  warn(message, meta) {
54
- if (this._shouldLog('warn')) {
55
- console.warn(this._formatMessage('warn', message, meta));
56
- }
36
+ if (this._shouldLog('warn')) console.warn(this._formatMessage('warn', message, meta));
57
37
  }
58
38
 
59
39
  error(message, meta) {
60
- if (this._shouldLog('error')) {
61
- console.error(this._formatMessage('error', message, meta));
62
- }
40
+ if (this._shouldLog('error')) console.error(this._formatMessage('error', message, meta));
63
41
  }
64
42
 
65
- // Convenience methods for common HoneyWeb events
66
43
  trapTriggered(ip, path) {
67
- this.warn(`🚨 TRAP TRIGGERED by ${ip} on ${path}`, { ip, path, event: 'trap_triggered' });
44
+ this.warn(`TRAP TRIGGERED by ${ip} on ${path}`, { ip, path, event: 'trap_triggered' });
68
45
  }
69
46
 
70
47
  ipBanned(ip, reason) {
@@ -73,10 +50,7 @@ class Logger {
73
50
 
74
51
  threatDetected(ip, threats, level) {
75
52
  this.warn(`THREAT DETECTED from ${ip}: ${threats.join(', ')} (level: ${level})`, {
76
- ip,
77
- threats,
78
- threatLevel: level,
79
- event: 'threat_detected'
53
+ ip, threats, threatLevel: level, event: 'threat_detected'
80
54
  });
81
55
  }
82
56