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.
@@ -1,5 +1,4 @@
1
1
  // honeyweb-core/middleware/dashboard.js
2
- // Dashboard middleware with cookie-based auth (no credentials in URL)
3
2
 
4
3
  const crypto = require('crypto');
5
4
 
@@ -67,7 +66,6 @@ function createDashboard(config, storage, botTracker, detector, events) {
67
66
  return async function dashboard(req, res, next) {
68
67
  if (req.path !== dashboardPath) return next();
69
68
 
70
- // POST login
71
69
  if (req.method === 'POST') {
72
70
  const submitted = req.body && req.body.secret;
73
71
  if (submitted === dashboardSecret) {
@@ -77,7 +75,6 @@ function createDashboard(config, storage, botTracker, detector, events) {
77
75
  return renderLoginPage(res, 'Invalid secret. Try again.');
78
76
  }
79
77
 
80
- // Legacy ?key= support (redirect to clean URL)
81
78
  if (req.query.key) {
82
79
  if (req.query.key === dashboardSecret) {
83
80
  res.setHeader('Set-Cookie', `honeyweb_session=${sessionToken}; HttpOnly; Path=${dashboardPath}; SameSite=Strict; Max-Age=3600`);
@@ -109,14 +106,12 @@ function createDashboard(config, storage, botTracker, detector, events) {
109
106
  code{font-family:'Cascadia Code','Fira Code',Consolas,monospace;background:#0d1117;padding:2px 6px;border-radius:4px;font-size:0.88em;color:#e6edf3}
110
107
  pre{font-family:'Cascadia Code','Fira Code',Consolas,monospace}
111
108
 
112
- /* Layout */
113
109
  .wrap{max-width:1100px;margin:0 auto;padding:32px 24px 48px}
114
110
  .top-bar{display:flex;align-items:center;justify-content:space-between;margin-bottom:32px;flex-wrap:wrap;gap:12px}
115
111
  .top-bar h1{font-size:1.6em;color:#e6edf3}
116
112
  .top-bar h1 span{color:#58a6ff}
117
113
  .top-bar .meta{color:#484f58;font-size:0.78em}
118
114
 
119
- /* Stat cards */
120
115
  .stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:36px}
121
116
  .stat{background:#161b22;border:1px solid #21262d;border-radius:8px;padding:20px}
122
117
  .stat .label{font-size:0.75em;text-transform:uppercase;letter-spacing:.5px;color:#8b949e;margin-bottom:8px;font-weight:600}
@@ -124,13 +119,10 @@ function createDashboard(config, storage, botTracker, detector, events) {
124
119
  .stat .val.green{color:#238636}
125
120
  .stat .val.blue{color:#58a6ff}
126
121
 
127
- /* Section headers */
128
122
  .section-hdr{font-size:1.15em;color:#e6edf3;margin:32px 0 16px;padding-bottom:8px;border-bottom:1px solid #21262d;display:flex;align-items:center;gap:10px}
129
123
 
130
- /* Card generic */
131
124
  .card{background:#161b22;border:1px solid #21262d;border-radius:8px;padding:20px 24px;margin-bottom:14px}
132
125
 
133
- /* Bot cards */
134
126
  .bot-hdr{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:8px}
135
127
  .bot-hdr h3{color:#e6edf3;font-size:1em;margin:0}
136
128
  .badge{padding:3px 8px;border-radius:12px;font-size:0.7em;font-weight:700;text-transform:uppercase;letter-spacing:.3px}
@@ -143,14 +135,12 @@ function createDashboard(config, storage, botTracker, detector, events) {
143
135
  details summary{cursor:pointer;color:#58a6ff;font-size:0.88em;margin-top:4px}
144
136
  details summary:hover{text-decoration:underline}
145
137
 
146
- /* AI reports */
147
138
  .ai-card{background:#161b22;border:1px solid #21262d;border-radius:8px;padding:20px 24px;margin-bottom:14px}
148
139
  .ai-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;flex-wrap:wrap;gap:8px}
149
140
  .ai-header .ip-tag{background:rgba(248,81,73,0.1);color:#f85149;padding:4px 10px;border-radius:12px;font-size:0.78em;font-weight:600}
150
141
  .ai-header .ts{color:#484f58;font-size:0.78em}
151
142
  .ai-body{background:#0d1117;border:1px solid #21262d;border-radius:6px;padding:16px;white-space:pre-wrap;word-wrap:break-word;font-size:0.85em;line-height:1.6;color:#c9d1d9}
152
143
 
153
- /* Banned table */
154
144
  .ban-table{width:100%;border-collapse:collapse;background:#161b22;border:1px solid #21262d;border-radius:8px;overflow:hidden}
155
145
  .ban-table th{background:#1a2332;color:#8b949e;font-size:0.75em;text-transform:uppercase;letter-spacing:.5px;font-weight:600;padding:12px 16px;text-align:left;border-bottom:1px solid #21262d}
156
146
  .ban-table td{padding:12px 16px;border-bottom:1px solid #21262d;font-size:0.9em}
@@ -159,15 +149,12 @@ function createDashboard(config, storage, botTracker, detector, events) {
159
149
  .ban-table .reason{color:#f85149;font-weight:500}
160
150
  .ban-table .ts{color:#484f58;font-size:0.8em}
161
151
 
162
- /* Empty states */
163
152
  .empty{text-align:center;padding:36px;color:#484f58;background:#161b22;border:1px solid #21262d;border-radius:8px}
164
153
  .empty p:first-child{font-size:0.95em;color:#8b949e}
165
154
  .empty p.hint{font-size:0.78em;margin-top:8px}
166
155
 
167
- /* Footer */
168
156
  .dash-footer{text-align:center;color:#484f58;font-size:0.75em;margin-top:40px;padding-top:16px;border-top:1px solid #21262d}
169
157
 
170
- /* Logout */
171
158
  .logout-btn{background:none;border:1px solid #30363d;color:#8b949e;padding:6px 14px;border-radius:6px;font-size:0.8em;cursor:pointer;transition:all .2s}
172
159
  .logout-btn:hover{border-color:#f85149;color:#f85149}
173
160
  </style>
@@ -186,7 +173,6 @@ function createDashboard(config, storage, botTracker, detector, events) {
186
173
  </div>
187
174
  </div>
188
175
 
189
- <!-- Stats -->
190
176
  <div class="stats">
191
177
  <div class="stat">
192
178
  <div class="label">Banned IPs (Total)</div>
@@ -211,7 +197,6 @@ function createDashboard(config, storage, botTracker, detector, events) {
211
197
  </div>` : ''}
212
198
  </div>
213
199
 
214
- <!-- Legitimate Bots -->
215
200
  <div class="section-hdr">Legitimate Bot Activity</div>
216
201
  ${Object.keys(botVisits).length === 0 ? `
217
202
  <div class="empty">
@@ -238,7 +223,6 @@ function createDashboard(config, storage, botTracker, detector, events) {
238
223
  </div>
239
224
  `).join('')}
240
225
 
241
- <!-- AI Analysis -->
242
226
  <div class="section-hdr">AI Threat Analysis</div>
243
227
  ${aiReports.length === 0 ? `
244
228
  <div class="empty">
@@ -255,7 +239,6 @@ function createDashboard(config, storage, botTracker, detector, events) {
255
239
  </div>
256
240
  `).join('')}
257
241
 
258
- <!-- Banned IPs -->
259
242
  <div class="section-hdr">Banned IP Addresses</div>
260
243
  ${bannedIPs.length === 0 ? `
261
244
  <div class="empty"><p>No banned IPs yet.</p></div>
@@ -1,24 +1,9 @@
1
- // honeyweb-core/middleware/index.js
2
- // Middleware factory - orchestrates all middleware components
3
-
4
1
  const createBlocklistChecker = require('./blocklist-checker');
5
2
  const createRequestAnalyzer = require('./request-analyzer');
6
3
  const createTrapInjector = require('./trap-injector');
7
4
  const createDashboard = require('./dashboard');
8
5
 
9
- /**
10
- * Create HoneyWeb middleware stack
11
- * @param {Object} config - Configuration
12
- * @param {Object} storage - Storage instance
13
- * @param {Object} botTracker - Bot tracker instance
14
- * @param {Object} detector - Detection engine
15
- * @param {Object} aiAnalyzer - AI analyzer
16
- * @param {Object} logger - Logger instance
17
- * @param {Object} events - Event emitter
18
- * @returns {Function} - Express middleware function
19
- */
20
6
  function createMiddleware(config, storage, botTracker, detector, aiAnalyzer, logger, events) {
21
- // Create individual middleware components
22
7
  const blocklistChecker = createBlocklistChecker(storage, logger, events);
23
8
  const requestAnalyzer = createRequestAnalyzer(config, storage, botTracker, detector, aiAnalyzer, logger, events);
24
9
  const trapInjector = createTrapInjector(config);
@@ -27,56 +12,35 @@ function createMiddleware(config, storage, botTracker, detector, aiAnalyzer, log
27
12
  ? createDashboard(config, storage, botTracker, detector, events)
28
13
  : null;
29
14
 
30
- // Return combined middleware function
31
15
  return async function honeyWebMiddleware(req, res, next) {
32
16
  try {
33
- // 1. Dashboard (if enabled and path matches)
17
+ // Dashboard route
34
18
  if (dashboard && req.path === config.dashboard.path) {
35
19
  return dashboard(req, res, next);
36
20
  }
37
21
 
38
- // 2. If this is a trap path, ALWAYS run the analyzer first
39
- // so trap triggers are logged + AI-analyzed even for banned IPs
22
+ // Trap paths: always analyze first
40
23
  if (trapPaths.includes(req.path)) {
41
24
  await new Promise((resolve, reject) => {
42
- requestAnalyzer(req, res, (err) => {
43
- if (err) reject(err);
44
- else resolve();
45
- });
25
+ requestAnalyzer(req, res, (err) => err ? reject(err) : resolve());
46
26
  });
47
- // Analyzer already sent 403 for traps
48
27
  if (res.headersSent) return;
49
28
  }
50
29
 
51
- // 3. Check blocklist (non-trap requests)
30
+ // Blocklist check
52
31
  await new Promise((resolve, reject) => {
53
- blocklistChecker(req, res, (err) => {
54
- if (err) reject(err);
55
- else resolve();
56
- });
32
+ blocklistChecker(req, res, (err) => err ? reject(err) : resolve());
57
33
  });
34
+ if (res.headersSent) return;
58
35
 
59
- // If response was sent (blocked), stop here
60
- if (res.headersSent) {
61
- return;
62
- }
63
-
64
- // 4. Analyze request (patterns, rate limiting, behavioral)
36
+ // Full request analysis
65
37
  await new Promise((resolve, reject) => {
66
- requestAnalyzer(req, res, (err) => {
67
- if (err) reject(err);
68
- else resolve();
69
- });
38
+ requestAnalyzer(req, res, (err) => err ? reject(err) : resolve());
70
39
  });
40
+ if (res.headersSent) return;
71
41
 
72
- // If response was sent (blocked), stop here
73
- if (res.headersSent) {
74
- return;
75
- }
76
-
77
- // 5. Inject traps into HTML responses
42
+ // Inject traps into HTML responses
78
43
  trapInjector(req, res, next);
79
-
80
44
  } catch (err) {
81
45
  logger.error('Middleware error', { error: err.message });
82
46
  next(err);
@@ -1,29 +1,12 @@
1
- // honeyweb-core/middleware/request-analyzer.js
2
- // Request analysis middleware
3
-
4
- /**
5
- * Create request analyzer middleware
6
- * @param {Object} config - Configuration
7
- * @param {Object} storage - Storage instance
8
- * @param {Object} botTracker - Bot tracker instance
9
- * @param {Object} detector - Detection engine
10
- * @param {Object} aiAnalyzer - AI analyzer
11
- * @param {Object} logger - Logger instance
12
- * @param {Object} events - Event emitter
13
- * @returns {Function} - Middleware function
14
- */
15
1
  function createRequestAnalyzer(config, storage, botTracker, detector, aiAnalyzer, logger, events) {
16
2
  const trapPaths = config.traps.paths;
17
3
 
18
4
  return async function analyzeRequest(req, res, next) {
19
5
  const clientIP = req.ip || req.connection.remoteAddress;
20
-
21
- // 1. THREAT DETECTION (whitelist check happens FIRST to protect legit bots)
22
6
  const analysis = await detector.analyze(req, clientIP);
23
7
 
24
- // Skip ALL checks if legitimate bot (even trap paths!)
8
+ // Legitimate bots skip all checks
25
9
  if (analysis.legitimateBot) {
26
- // Record legitimate bot visit for dashboard
27
10
  botTracker.recordVisit({
28
11
  botName: analysis.whitelist.botName,
29
12
  ip: clientIP,
@@ -32,22 +15,18 @@ function createRequestAnalyzer(config, storage, botTracker, detector, aiAnalyzer
32
15
  verified: analysis.whitelist.verified,
33
16
  timestamp: Date.now()
34
17
  });
35
-
36
18
  logger.info('Legitimate bot detected', {
37
- ip: clientIP,
38
- botName: analysis.whitelist.botName,
39
- verified: analysis.whitelist.verified,
40
- path: req.path
19
+ ip: clientIP, botName: analysis.whitelist.botName,
20
+ verified: analysis.whitelist.verified, path: req.path
41
21
  });
42
22
  return next();
43
23
  }
44
24
 
45
- // 2. CHECK IF TRAP ACCESSED (only after confirming not a legit bot)
25
+ // Trap access immediate ban
46
26
  if (trapPaths.includes(req.path)) {
47
27
  logger.trapTriggered(clientIP, req.path);
48
28
  events.emitTrapTriggered(clientIP, req.path);
49
29
 
50
- // Ban the IP immediately
51
30
  try {
52
31
  await storage.ban(clientIP, `Trap triggered: ${req.path}`);
53
32
  events.emitIpBanned(clientIP, `Trap triggered: ${req.path}`);
@@ -55,71 +34,47 @@ function createRequestAnalyzer(config, storage, botTracker, detector, aiAnalyzer
55
34
  logger.error('Error banning IP', { error: err.message });
56
35
  }
57
36
 
58
- // AI analysis for trap trigger
59
37
  if (aiAnalyzer.isEnabled()) {
60
38
  aiAnalyzer.analyzeTrap({
61
- ip: clientIP,
62
- path: req.path,
63
- userAgent: req.headers['user-agent'],
64
- timestamp: Date.now()
39
+ ip: clientIP, path: req.path,
40
+ userAgent: req.headers['user-agent'], timestamp: Date.now()
65
41
  }).then(report => {
66
42
  if (report) {
67
43
  logger.info('AI Trap Analysis', { ip: clientIP, report });
68
44
  events.emitAiAnalysis(clientIP, report);
69
- } else {
70
- logger.warn('AI returned empty report for trap', { ip: clientIP, path: req.path });
71
45
  }
72
- }).catch(err => {
73
- logger.error('AI trap analysis failed', { error: err.message });
74
- });
75
- } else {
76
- logger.info('AI is disabled, skipping trap analysis');
46
+ }).catch(err => logger.error('AI trap analysis failed', { error: err.message }));
77
47
  }
78
48
 
79
- return res.status(403).send(
80
- '<h1>403 Forbidden</h1><p>You have accessed a restricted area.</p>'
81
- );
49
+ return res.status(403).send('<h1>403 Forbidden</h1><p>You have accessed a restricted area.</p>');
82
50
  }
83
51
 
84
- // 3. OTHER THREAT DETECTION (patterns, rate limiting, behavioral)
85
-
86
- if (analysis.detected) {
52
+ // Pattern/rate/behavioral/bot threats
53
+ if (analysis.detected && analysis.threatLevel >= 50) {
87
54
  logger.threatDetected(clientIP, analysis.threats, analysis.threatLevel);
88
55
  events.emitThreatDetected(clientIP, analysis.threats, analysis.threatLevel);
89
56
 
90
- // Ban if threat level is high
91
- if (analysis.threatLevel >= 50) {
92
- try {
93
- await storage.ban(clientIP, `Threat detected: ${analysis.threats[0]}`);
94
- events.emitIpBanned(clientIP, `Threat detected: ${analysis.threats[0]}`);
95
- } catch (err) {
96
- logger.error('Error banning IP', { error: err.message });
97
- }
98
-
99
- // AI analysis for threat
100
- if (aiAnalyzer.isEnabled()) {
101
- aiAnalyzer.analyzeThreat({
102
- ip: clientIP,
103
- path: req.path,
104
- method: req.method,
105
- threats: analysis.threats,
106
- userAgent: req.headers['user-agent'],
107
- referer: req.headers['referer'],
108
- timestamp: Date.now()
109
- }).then(report => {
110
- if (report) {
111
- logger.info('AI Threat Analysis', { ip: clientIP, report });
112
- events.emitAiAnalysis(clientIP, report);
113
- }
114
- }).catch(err => {
115
- logger.error('AI analysis failed', { error: err.message });
116
- });
117
- }
57
+ try {
58
+ await storage.ban(clientIP, `Threat detected: ${analysis.threats[0]}`);
59
+ events.emitIpBanned(clientIP, `Threat detected: ${analysis.threats[0]}`);
60
+ } catch (err) {
61
+ logger.error('Error banning IP', { error: err.message });
62
+ }
118
63
 
119
- return res.status(403).send(
120
- '<h1>403 Forbidden</h1><p>Malicious activity detected.</p>'
121
- );
64
+ if (aiAnalyzer.isEnabled()) {
65
+ aiAnalyzer.analyzeThreat({
66
+ ip: clientIP, path: req.path, method: req.method,
67
+ threats: analysis.threats, userAgent: req.headers['user-agent'],
68
+ referer: req.headers['referer'], timestamp: Date.now()
69
+ }).then(report => {
70
+ if (report) {
71
+ logger.info('AI Threat Analysis', { ip: clientIP, report });
72
+ events.emitAiAnalysis(clientIP, report);
73
+ }
74
+ }).catch(err => logger.error('AI analysis failed', { error: err.message }));
122
75
  }
76
+
77
+ return res.status(403).send('<h1>403 Forbidden</h1><p>Malicious activity detected.</p>');
123
78
  }
124
79
 
125
80
  next();
@@ -1,50 +1,25 @@
1
- // honeyweb-core/middleware/trap-injector.js
2
- // Trap injection middleware (extracted from main index.js)
3
-
4
1
  const cheerio = require('cheerio');
5
2
 
6
- /**
7
- * Create trap injector middleware
8
- * @param {Object} config - Trap configuration
9
- * @returns {Function} - Middleware function
10
- */
11
3
  function createTrapInjector(config) {
12
4
  const trapPaths = config.traps.paths;
13
5
 
14
6
  return function injectTraps(req, res, next) {
15
- // Only inject if trap injection is enabled
16
- if (!config.traps.injection.enabled) {
17
- return next();
18
- }
7
+ if (!config.traps.injection.enabled) return next();
19
8
 
20
- // Intercept res.send to inject traps
21
9
  const originalSend = res.send;
22
-
23
10
  res.send = function (body) {
24
- // Only inject if the content is HTML
25
11
  if (typeof body === 'string' && (body.includes('<html') || body.includes('<body'))) {
26
12
  try {
27
13
  const $ = cheerio.load(body);
28
-
29
- // Pick a random trap
30
14
  const trapUrl = trapPaths[Math.floor(Math.random() * trapPaths.length)];
31
-
32
- // Create invisible link (Hidden by CSS)
33
- const trapLink = `<a href="${trapUrl}" style="opacity:0; position:absolute; z-index:-999; left:-9999px;">Admin Panel</a>`;
34
-
35
- // Inject into body
36
- $('body').append(trapLink);
37
-
15
+ $('body').append(`<a href="${trapUrl}" style="opacity:0;position:absolute;z-index:-999;left:-9999px;">Admin Panel</a>`);
38
16
  body = $.html();
39
17
  } catch (err) {
40
- // If cheerio fails, just send original body
41
- console.error('[TrapInjector] Failed to inject trap:', err.message);
18
+ // If injection fails, send original body
42
19
  }
43
20
  }
44
-
45
21
  originalSend.call(this, body);
46
22
  };
47
-
48
23
  next();
49
24
  };
50
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "honeyweb-core",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "Production-ready honeypot middleware with behavioral analysis, bot fingerprinting, and AI threat intelligence",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,16 +1,11 @@
1
1
  // honeyweb-core/storage/bot-tracker.js
2
- // Track legitimate bot visits for dashboard display
3
2
 
4
3
  class BotTracker {
5
4
  constructor() {
6
- this.botVisits = new Map(); // botName -> array of visits
7
- this.maxVisitsPerBot = 50; // Keep last 50 visits per bot
5
+ this.botVisits = new Map();
6
+ this.maxVisitsPerBot = 50;
8
7
  }
9
8
 
10
- /**
11
- * Record a legitimate bot visit
12
- * @param {Object} visit - Visit data
13
- */
14
9
  recordVisit(visit) {
15
10
  const { botName, ip, path, userAgent, verified, timestamp } = visit;
16
11
 
@@ -19,49 +14,23 @@ class BotTracker {
19
14
  }
20
15
 
21
16
  const visits = this.botVisits.get(botName);
17
+ visits.unshift({ ip, path, userAgent, verified, timestamp: timestamp || Date.now() });
22
18
 
23
- // Add new visit at the beginning (most recent first)
24
- visits.unshift({
25
- ip,
26
- path,
27
- userAgent,
28
- verified,
29
- timestamp: timestamp || Date.now()
30
- });
31
-
32
- // Keep only last N visits
33
- if (visits.length > this.maxVisitsPerBot) {
34
- visits.pop();
35
- }
19
+ if (visits.length > this.maxVisitsPerBot) visits.pop();
36
20
  }
37
21
 
38
- /**
39
- * Get all bot visits grouped by bot name
40
- * @returns {Object} - Bot visits grouped by name
41
- */
42
22
  getAllVisits() {
43
23
  const result = {};
44
-
45
24
  for (const [botName, visits] of this.botVisits.entries()) {
46
25
  result[botName] = visits;
47
26
  }
48
-
49
27
  return result;
50
28
  }
51
29
 
52
- /**
53
- * Get visits for a specific bot
54
- * @param {string} botName - Bot name
55
- * @returns {Array} - Array of visits
56
- */
57
30
  getVisitsByBot(botName) {
58
31
  return this.botVisits.get(botName) || [];
59
32
  }
60
33
 
61
- /**
62
- * Get statistics
63
- * @returns {Object} - Statistics
64
- */
65
34
  getStats() {
66
35
  let totalVisits = 0;
67
36
  const botCounts = {};
@@ -71,37 +40,21 @@ class BotTracker {
71
40
  botCounts[botName] = visits.length;
72
41
  }
73
42
 
74
- return {
75
- totalBots: this.botVisits.size,
76
- totalVisits,
77
- botCounts
78
- };
43
+ return { totalBots: this.botVisits.size, totalVisits, botCounts };
79
44
  }
80
45
 
81
- /**
82
- * Clear all bot visits
83
- */
84
46
  clear() {
85
47
  this.botVisits.clear();
86
48
  }
87
49
 
88
- /**
89
- * Cleanup old visits (older than 7 days)
90
- */
91
50
  cleanup() {
92
- const maxAge = 7 * 24 * 60 * 60 * 1000; // 7 days
51
+ const maxAge = 7 * 24 * 60 * 60 * 1000;
93
52
  const now = Date.now();
94
53
 
95
54
  for (const [botName, visits] of this.botVisits.entries()) {
96
- const filtered = visits.filter(visit => {
97
- return (now - visit.timestamp) < maxAge;
98
- });
99
-
100
- if (filtered.length === 0) {
101
- this.botVisits.delete(botName);
102
- } else {
103
- this.botVisits.set(botName, filtered);
104
- }
55
+ const filtered = visits.filter(v => (now - v.timestamp) < maxAge);
56
+ if (filtered.length === 0) this.botVisits.delete(botName);
57
+ else this.botVisits.set(botName, filtered);
105
58
  }
106
59
  }
107
60
  }
package/storage/index.js CHANGED
@@ -1,24 +1,15 @@
1
1
  // honeyweb-core/storage/index.js
2
- // Storage factory
3
2
 
4
3
  const JsonStore = require('./json-store');
5
4
  const MemoryStore = require('./memory-store');
6
5
 
7
- /**
8
- * Create storage instance based on configuration
9
- * @param {Object} config - Storage configuration
10
- * @returns {JsonStore|MemoryStore}
11
- */
12
6
  function createStorage(config) {
13
7
  const type = config.type || 'json';
14
8
 
15
9
  switch (type) {
16
- case 'json':
17
- return new JsonStore(config);
18
- case 'memory':
19
- return new MemoryStore(config);
20
- default:
21
- throw new Error(`[HoneyWeb] Unknown storage type: ${type}`);
10
+ case 'json': return new JsonStore(config);
11
+ case 'memory': return new MemoryStore(config);
12
+ default: throw new Error(`[HoneyWeb] Unknown storage type: ${type}`);
22
13
  }
23
14
  }
24
15