@dynamicu/chromedebug-mcp 2.2.0
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/CLAUDE.md +344 -0
- package/LICENSE +21 -0
- package/README.md +250 -0
- package/chrome-extension/README.md +41 -0
- package/chrome-extension/background.js +3917 -0
- package/chrome-extension/chrome-session-manager.js +706 -0
- package/chrome-extension/content.css +181 -0
- package/chrome-extension/content.js +3022 -0
- package/chrome-extension/data-buffer.js +435 -0
- package/chrome-extension/dom-tracker.js +411 -0
- package/chrome-extension/extension-config.js +78 -0
- package/chrome-extension/firebase-client.js +278 -0
- package/chrome-extension/firebase-config.js +32 -0
- package/chrome-extension/firebase-config.module.js +22 -0
- package/chrome-extension/firebase-config.module.template.js +27 -0
- package/chrome-extension/firebase-config.template.js +36 -0
- package/chrome-extension/frame-capture.js +407 -0
- package/chrome-extension/icon128.png +1 -0
- package/chrome-extension/icon16.png +1 -0
- package/chrome-extension/icon48.png +1 -0
- package/chrome-extension/license-helper.js +181 -0
- package/chrome-extension/logger.js +23 -0
- package/chrome-extension/manifest.json +73 -0
- package/chrome-extension/network-tracker.js +510 -0
- package/chrome-extension/offscreen.html +10 -0
- package/chrome-extension/options.html +203 -0
- package/chrome-extension/options.js +282 -0
- package/chrome-extension/pako.min.js +2 -0
- package/chrome-extension/performance-monitor.js +533 -0
- package/chrome-extension/pii-redactor.js +405 -0
- package/chrome-extension/popup.html +532 -0
- package/chrome-extension/popup.js +2446 -0
- package/chrome-extension/upload-manager.js +323 -0
- package/chrome-extension/web-vitals.iife.js +1 -0
- package/config/api-keys.json +11 -0
- package/config/chrome-pilot-config.json +45 -0
- package/package.json +126 -0
- package/scripts/cleanup-processes.js +109 -0
- package/scripts/config-manager.js +280 -0
- package/scripts/generate-extension-config.js +53 -0
- package/scripts/setup-security.js +64 -0
- package/src/capture/architecture.js +426 -0
- package/src/capture/error-handling-tests.md +38 -0
- package/src/capture/error-handling-types.ts +360 -0
- package/src/capture/index.js +508 -0
- package/src/capture/interfaces.js +625 -0
- package/src/capture/memory-manager.js +713 -0
- package/src/capture/types.js +342 -0
- package/src/chrome-controller.js +2658 -0
- package/src/cli.js +19 -0
- package/src/config-loader.js +303 -0
- package/src/database.js +2178 -0
- package/src/firebase-license-manager.js +462 -0
- package/src/firebase-privacy-guard.js +397 -0
- package/src/http-server.js +1516 -0
- package/src/index-direct.js +157 -0
- package/src/index-modular.js +219 -0
- package/src/index-monolithic-backup.js +2230 -0
- package/src/index.js +305 -0
- package/src/legacy/chrome-controller-old.js +1406 -0
- package/src/legacy/index-express.js +625 -0
- package/src/legacy/index-old.js +977 -0
- package/src/legacy/routes.js +260 -0
- package/src/legacy/shared-storage.js +101 -0
- package/src/logger.js +10 -0
- package/src/mcp/handlers/chrome-tool-handler.js +306 -0
- package/src/mcp/handlers/element-tool-handler.js +51 -0
- package/src/mcp/handlers/frame-tool-handler.js +957 -0
- package/src/mcp/handlers/request-handler.js +104 -0
- package/src/mcp/handlers/workflow-tool-handler.js +636 -0
- package/src/mcp/server.js +68 -0
- package/src/mcp/tools/index.js +701 -0
- package/src/middleware/auth.js +371 -0
- package/src/middleware/security.js +267 -0
- package/src/port-discovery.js +258 -0
- package/src/routes/admin.js +182 -0
- package/src/services/browser-daemon.js +494 -0
- package/src/services/chrome-service.js +375 -0
- package/src/services/failover-manager.js +412 -0
- package/src/services/git-safety-service.js +675 -0
- package/src/services/heartbeat-manager.js +200 -0
- package/src/services/http-client.js +195 -0
- package/src/services/process-manager.js +318 -0
- package/src/services/process-tracker.js +574 -0
- package/src/services/profile-manager.js +449 -0
- package/src/services/project-manager.js +415 -0
- package/src/services/session-manager.js +497 -0
- package/src/services/session-registry.js +491 -0
- package/src/services/unified-session-manager.js +678 -0
- package/src/shared-storage-old.js +267 -0
- package/src/standalone-server.js +53 -0
- package/src/utils/extension-path.js +145 -0
- package/src/utils.js +187 -0
- package/src/validation/log-transformer.js +125 -0
- package/src/validation/schemas.js +391 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// Port discovery utilities for Chrome Debug
|
|
2
|
+
// This helps Chrome extension and MCP clients find the running HTTP server
|
|
3
|
+
//
|
|
4
|
+
// Note: Claude Code (MCP client) may create .chromedebug-port-[UUID] files
|
|
5
|
+
// to track multiple sessions. Our code only uses .chromedebug-port (no UUID).
|
|
6
|
+
// We don't clean these files as we didn't create them.
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import crypto from 'crypto';
|
|
12
|
+
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
|
|
15
|
+
// Session management for port discovery
|
|
16
|
+
let currentSessionId = null;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get or generate a session ID for port discovery
|
|
20
|
+
*/
|
|
21
|
+
function getSessionId() {
|
|
22
|
+
if (!currentSessionId) {
|
|
23
|
+
currentSessionId = crypto.randomBytes(8).toString('hex');
|
|
24
|
+
}
|
|
25
|
+
return currentSessionId;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Set a custom session ID for port discovery
|
|
30
|
+
*/
|
|
31
|
+
export function setPortDiscoverySessionId(sessionId) {
|
|
32
|
+
if (typeof sessionId === 'string' && sessionId.match(/^[a-zA-Z0-9_-]+$/)) {
|
|
33
|
+
currentSessionId = sessionId;
|
|
34
|
+
console.log(`Port discovery session ID set to: ${sessionId}`);
|
|
35
|
+
} else {
|
|
36
|
+
throw new Error('Session ID must be alphanumeric with dashes/underscores only');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the session-specific port file path
|
|
42
|
+
*/
|
|
43
|
+
function getPortFilePath() {
|
|
44
|
+
const sessionId = getSessionId();
|
|
45
|
+
return path.join(__dirname, `../.chromedebug-port-${sessionId}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get the legacy port file path (for backward compatibility)
|
|
50
|
+
*/
|
|
51
|
+
function getLegacyPortFilePath() {
|
|
52
|
+
return path.join(__dirname, '../.chromedebug-port');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Write the current port to a session-specific file for discovery
|
|
57
|
+
*/
|
|
58
|
+
export function writePortFile(port, options = {}) {
|
|
59
|
+
const { sessionId, writeLegacy = true } = options;
|
|
60
|
+
|
|
61
|
+
// Set session ID if provided
|
|
62
|
+
if (sessionId) {
|
|
63
|
+
setPortDiscoverySessionId(sessionId);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const portFilePath = getPortFilePath();
|
|
67
|
+
const legacyPortFilePath = getLegacyPortFilePath();
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
// Write to session-specific file
|
|
71
|
+
fs.writeFileSync(portFilePath, port.toString());
|
|
72
|
+
console.log(`Port ${port} written to ${portFilePath} [Session: ${getSessionId()}]`);
|
|
73
|
+
|
|
74
|
+
// Optionally write to legacy file for backward compatibility
|
|
75
|
+
if (writeLegacy) {
|
|
76
|
+
try {
|
|
77
|
+
fs.writeFileSync(legacyPortFilePath, port.toString());
|
|
78
|
+
} catch (legacyError) {
|
|
79
|
+
console.warn(`Could not write legacy port file: ${legacyError.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error('Failed to write port file:', error);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Read the port from session-specific or legacy file
|
|
89
|
+
*/
|
|
90
|
+
export function readPortFile(sessionId = null) {
|
|
91
|
+
// If session ID provided, use that specific session
|
|
92
|
+
if (sessionId) {
|
|
93
|
+
try {
|
|
94
|
+
const sessionPortFile = path.join(__dirname, `../.chromedebug-port-${sessionId}`);
|
|
95
|
+
if (fs.existsSync(sessionPortFile)) {
|
|
96
|
+
const port = parseInt(fs.readFileSync(sessionPortFile, 'utf8').trim());
|
|
97
|
+
if (!isNaN(port)) {
|
|
98
|
+
return port;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error(`Failed to read session port file for ${sessionId}:`, error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Try current session file
|
|
107
|
+
const portFilePath = getPortFilePath();
|
|
108
|
+
try {
|
|
109
|
+
if (fs.existsSync(portFilePath)) {
|
|
110
|
+
const port = parseInt(fs.readFileSync(portFilePath, 'utf8').trim());
|
|
111
|
+
if (!isNaN(port)) {
|
|
112
|
+
return port;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.error('Failed to read session port file:', error);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Fall back to legacy file
|
|
120
|
+
const legacyPortFilePath = getLegacyPortFilePath();
|
|
121
|
+
try {
|
|
122
|
+
if (fs.existsSync(legacyPortFilePath)) {
|
|
123
|
+
const port = parseInt(fs.readFileSync(legacyPortFilePath, 'utf8').trim());
|
|
124
|
+
if (!isNaN(port)) {
|
|
125
|
+
return port;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error('Failed to read legacy port file:', error);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Remove the port files on shutdown
|
|
137
|
+
*/
|
|
138
|
+
export function removePortFile() {
|
|
139
|
+
const portFilePath = getPortFilePath();
|
|
140
|
+
const legacyPortFilePath = getLegacyPortFilePath();
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
if (fs.existsSync(portFilePath)) {
|
|
144
|
+
fs.unlinkSync(portFilePath);
|
|
145
|
+
console.log(`Removed session port file: ${portFilePath}`);
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('Failed to remove session port file:', error);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Only remove legacy file if no other sessions are using it
|
|
152
|
+
try {
|
|
153
|
+
if (fs.existsSync(legacyPortFilePath)) {
|
|
154
|
+
// Check if there are other session port files
|
|
155
|
+
const portFiles = fs.readdirSync(__dirname + '/..')
|
|
156
|
+
.filter(f => f.startsWith('.chromedebug-port-') && f !== `.chromedebug-port-${getSessionId()}`);
|
|
157
|
+
|
|
158
|
+
if (portFiles.length === 0) {
|
|
159
|
+
fs.unlinkSync(legacyPortFilePath);
|
|
160
|
+
console.log('Removed legacy port file (no other sessions)');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error('Failed to remove legacy port file:', error);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Try to discover the Chrome Debug server by checking multiple ports
|
|
170
|
+
*/
|
|
171
|
+
export async function discoverServer(preferredPorts = [3000, 3001, 3002, 3028], options = {}) {
|
|
172
|
+
const { sessionId, extendedRange = true } = options;
|
|
173
|
+
|
|
174
|
+
// Extend port range to reduce conflicts in multi-session environments
|
|
175
|
+
if (extendedRange) {
|
|
176
|
+
preferredPorts = [
|
|
177
|
+
...preferredPorts,
|
|
178
|
+
// Original extended range (maintain backward compatibility)
|
|
179
|
+
3029, 3030, 3031, 3032, 3033, 3034, 3035, 3036,
|
|
180
|
+
// Safer fallback ranges (avoid common service conflicts)
|
|
181
|
+
8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090,
|
|
182
|
+
9000, 9001, 9002, 9003, 9004, 9005, 9006, 9007, 9008, 9009, 9010
|
|
183
|
+
];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// First check session-specific port file
|
|
187
|
+
const filePort = readPortFile(sessionId);
|
|
188
|
+
if (filePort) {
|
|
189
|
+
preferredPorts.unshift(filePort);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Try each port with exponential backoff
|
|
193
|
+
for (let i = 0; i < preferredPorts.length; i++) {
|
|
194
|
+
const port = preferredPorts[i];
|
|
195
|
+
try {
|
|
196
|
+
const response = await fetch(`http://localhost:${port}/chromedebug/status`, {
|
|
197
|
+
method: 'GET',
|
|
198
|
+
signal: AbortSignal.timeout(1000) // 1 second timeout
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
if (response.ok) {
|
|
202
|
+
const data = await response.json();
|
|
203
|
+
if (data.status === 'online') {
|
|
204
|
+
console.log(`Discovered ChromeDebug server on port ${port}`);
|
|
205
|
+
return port;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
} catch (error) {
|
|
209
|
+
// Port not available or wrong server, continue
|
|
210
|
+
// Add small delay for later ports to avoid overwhelming the system
|
|
211
|
+
if (i > 3) {
|
|
212
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get session information for port discovery
|
|
222
|
+
*/
|
|
223
|
+
export function getPortDiscoveryInfo() {
|
|
224
|
+
return {
|
|
225
|
+
sessionId: getSessionId(),
|
|
226
|
+
portFile: getPortFilePath(),
|
|
227
|
+
legacyPortFile: getLegacyPortFilePath(),
|
|
228
|
+
currentPort: readPortFile()
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Find all active ChromeDebug sessions by scanning port files
|
|
234
|
+
*/
|
|
235
|
+
export function findActiveSessions() {
|
|
236
|
+
const sessions = [];
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
const files = fs.readdirSync(__dirname + '/..');
|
|
240
|
+
const portFiles = files.filter(f => f.startsWith('.chromedebug-port-'));
|
|
241
|
+
|
|
242
|
+
for (const file of portFiles) {
|
|
243
|
+
const sessionId = file.replace('.chromedebug-port-', '');
|
|
244
|
+
try {
|
|
245
|
+
const port = parseInt(fs.readFileSync(path.join(__dirname, '..', file), 'utf8').trim());
|
|
246
|
+
if (!isNaN(port)) {
|
|
247
|
+
sessions.push({ sessionId, port, portFile: file });
|
|
248
|
+
}
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.warn(`Could not read port file ${file}: ${error.message}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
} catch (error) {
|
|
254
|
+
console.error('Failed to scan for active sessions:', error);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return sessions;
|
|
258
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import {
|
|
3
|
+
generateApiKey,
|
|
4
|
+
listApiKeys,
|
|
5
|
+
revokeApiKey,
|
|
6
|
+
activateApiKey,
|
|
7
|
+
deleteApiKey,
|
|
8
|
+
requireAdmin,
|
|
9
|
+
ROLES
|
|
10
|
+
} from '../middleware/auth.js';
|
|
11
|
+
import { createValidator } from '../validation/schemas.js';
|
|
12
|
+
import { createApiKeySchema, updateApiKeySchema } from '../validation/schemas.js';
|
|
13
|
+
import { rateLimits } from '../middleware/security.js';
|
|
14
|
+
|
|
15
|
+
const router = express.Router();
|
|
16
|
+
|
|
17
|
+
// Apply admin authentication and rate limiting to all admin routes
|
|
18
|
+
router.use(requireAdmin);
|
|
19
|
+
router.use(rateLimits.auth);
|
|
20
|
+
|
|
21
|
+
// Generate new API key
|
|
22
|
+
router.post('/api-keys', createValidator(createApiKeySchema), (req, res) => {
|
|
23
|
+
try {
|
|
24
|
+
const { name, role } = req.body;
|
|
25
|
+
|
|
26
|
+
// Validate role
|
|
27
|
+
if (!Object.values(ROLES).includes(role)) {
|
|
28
|
+
return res.status(400).json({
|
|
29
|
+
error: 'Invalid role',
|
|
30
|
+
validRoles: Object.values(ROLES)
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const result = generateApiKey(name, role);
|
|
35
|
+
|
|
36
|
+
res.status(201).json({
|
|
37
|
+
success: true,
|
|
38
|
+
message: 'API key created successfully',
|
|
39
|
+
apiKey: result.apiKey,
|
|
40
|
+
keyInfo: result.keyData
|
|
41
|
+
});
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error('Error creating API key:', error);
|
|
44
|
+
res.status(500).json({
|
|
45
|
+
error: 'Failed to create API key',
|
|
46
|
+
details: error.message
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// List all API keys
|
|
52
|
+
router.get('/api-keys', (req, res) => {
|
|
53
|
+
try {
|
|
54
|
+
const keys = listApiKeys();
|
|
55
|
+
res.json({
|
|
56
|
+
success: true,
|
|
57
|
+
keys,
|
|
58
|
+
total: keys.length
|
|
59
|
+
});
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('Error listing API keys:', error);
|
|
62
|
+
res.status(500).json({
|
|
63
|
+
error: 'Failed to list API keys',
|
|
64
|
+
details: error.message
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Update API key (revoke/activate)
|
|
70
|
+
router.patch('/api-keys/:keyId', createValidator(updateApiKeySchema), (req, res) => {
|
|
71
|
+
try {
|
|
72
|
+
const { keyId } = req.params;
|
|
73
|
+
const { active } = req.body;
|
|
74
|
+
|
|
75
|
+
if (typeof active === 'boolean') {
|
|
76
|
+
const success = active ?
|
|
77
|
+
activateApiKey(keyId) :
|
|
78
|
+
revokeApiKey(keyId);
|
|
79
|
+
|
|
80
|
+
if (success) {
|
|
81
|
+
res.json({
|
|
82
|
+
success: true,
|
|
83
|
+
message: active ? 'API key activated' : 'API key revoked'
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
res.status(404).json({
|
|
87
|
+
error: 'API key not found'
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
res.status(400).json({
|
|
92
|
+
error: 'Invalid update data'
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('Error updating API key:', error);
|
|
97
|
+
res.status(500).json({
|
|
98
|
+
error: 'Failed to update API key',
|
|
99
|
+
details: error.message
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Delete API key permanently
|
|
105
|
+
router.delete('/api-keys/:keyId', (req, res) => {
|
|
106
|
+
try {
|
|
107
|
+
const { keyId } = req.params;
|
|
108
|
+
const success = deleteApiKey(keyId);
|
|
109
|
+
|
|
110
|
+
if (success) {
|
|
111
|
+
res.json({
|
|
112
|
+
success: true,
|
|
113
|
+
message: 'API key deleted successfully'
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
res.status(404).json({
|
|
117
|
+
error: 'API key not found'
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error('Error deleting API key:', error);
|
|
122
|
+
res.status(500).json({
|
|
123
|
+
error: 'Failed to delete API key',
|
|
124
|
+
details: error.message
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// System status and security info
|
|
130
|
+
router.get('/status', (req, res) => {
|
|
131
|
+
try {
|
|
132
|
+
const keys = listApiKeys();
|
|
133
|
+
const activeKeys = keys.filter(k => k.active);
|
|
134
|
+
|
|
135
|
+
res.json({
|
|
136
|
+
success: true,
|
|
137
|
+
system: {
|
|
138
|
+
totalApiKeys: keys.length,
|
|
139
|
+
activeApiKeys: activeKeys.length,
|
|
140
|
+
roles: Object.values(ROLES),
|
|
141
|
+
securityFeatures: [
|
|
142
|
+
'API Key Authentication',
|
|
143
|
+
'JWT Bearer Tokens',
|
|
144
|
+
'Role-based Access Control',
|
|
145
|
+
'Rate Limiting',
|
|
146
|
+
'CORS Protection',
|
|
147
|
+
'Security Headers',
|
|
148
|
+
'Request Validation',
|
|
149
|
+
'Audit Logging'
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
timestamp: new Date().toISOString()
|
|
153
|
+
});
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error('Error getting admin status:', error);
|
|
156
|
+
res.status(500).json({
|
|
157
|
+
error: 'Failed to get status',
|
|
158
|
+
details: error.message
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Security audit log
|
|
164
|
+
router.get('/audit-log', (req, res) => {
|
|
165
|
+
try {
|
|
166
|
+
// This would typically come from a proper audit log database
|
|
167
|
+
// For now, return a placeholder response
|
|
168
|
+
res.json({
|
|
169
|
+
success: true,
|
|
170
|
+
message: 'Audit logging not yet implemented',
|
|
171
|
+
note: 'Security events are currently logged to console'
|
|
172
|
+
});
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error('Error getting audit log:', error);
|
|
175
|
+
res.status(500).json({
|
|
176
|
+
error: 'Failed to get audit log',
|
|
177
|
+
details: error.message
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
export default router;
|