Skip to content

Commit 4a94d0c

Browse files
authored
Add files via upload
bug fixes and some gui updates
1 parent 3bc064f commit 4a94d0c

11 files changed

Lines changed: 714 additions & 631 deletions

File tree

background.js

Lines changed: 95 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,120 @@
11
// Import IndexedDB storage module
22
importScripts('src/indexeddb.js');
33

4-
let attachedTabs = new Map();
5-
let collectedData = { jsFiles: {}, apiCalls: [], webSockets: [] };
6-
let windowModeActive = false; // Track if window mode is active
7-
let deletedWebSocketIds = new Set(); // Track deleted WebSocket IDs to prevent re-adding
4+
const attachedTabs = new Map();
5+
// REMOVED: large in-memory collectedData object. We rely on IndexedDB + small cache for active WebSocket control.
6+
let collectedData = { webSockets: [] }; // Only keep minimum needed for WS control
7+
let windowModeActive = false;
8+
let deletedWebSocketIds = new Set();
9+
// Optimized Tracking BlockList (Regex is faster than array.some + includes)
10+
const TRACKING_REGEX = new RegExp(
11+
[
12+
'google-analytics', 'googletagmanager', 'g\\.doubleclick', 'googleads', 'doubleclick', 'facebook\\.com/tr',
13+
'analytics', 'telemetry', 'pixel', 'tracker', 'tracking',
14+
'firebase', 'fcm\\.googleapis', 'onesignal', 'braze',
15+
'segment', 'mixpanel', 'amplitude', 'adjust', 'appsflyer', 'heapanalytics',
16+
'hotjar', 'clarity', 'sentry', 'newrelic', 'datadog',
17+
'collect', 'measure', 'beacon',
18+
'notifyvisitors', 'clevertap', 'heatmaps', 'event-api', 'google\\.com/xjs', 'gstatic\\.com/_/mss', 'connect\\.facebook\\.net/signals'
19+
].join('|'), 'i'
20+
);
21+
22+
// --- STATE RESTORATION FOR EXTENSION RESTARTS (Manfiest V3) ---
23+
async function restoreState() {
24+
try {
25+
const saved = await StorageDB.getSetting('activeSessions');
26+
if (saved && Array.isArray(saved)) {
27+
console.log('[Background] Restoring active sessions:', saved.length);
28+
for (const session of saved) {
29+
if (!attachedTabs.has(session.tabId)) {
30+
// Re-hydrate session object
31+
attachedTabs.set(session.tabId, {
32+
domain: session.domain,
33+
captureAllRequests: session.captureAllRequests,
34+
requests: new Map(), // Start fresh for in-memory requests map (ok since we store to DB)
35+
websockets: new Map()
36+
});
37+
38+
// Re-arm debugger if needed?
39+
// Usually debugger stays attached, we just lost our local map.
40+
// We can Verify attachment:
41+
chrome.debugger.getTargets((targets) => {
42+
const isAttached = targets.some(t => t.tabId === session.tabId && t.attached);
43+
if (!isAttached) {
44+
console.warn(`[Background] Tab ${session.tabId} was marked active but is not attached. Cleaning up.`);
45+
attachedTabs.delete(session.tabId);
46+
saveSessionState();
47+
}
48+
});
49+
}
50+
}
51+
}
52+
53+
// Restore window mode state
54+
const winState = await StorageDB.getSetting('windowModeActive');
55+
windowModeActive = !!winState;
56+
57+
} catch (e) {
58+
console.error('Failed to restore state:', e);
59+
}
60+
}
61+
62+
// Save current attachedTabs state to DB
63+
async function saveSessionState() {
64+
const sessions = [];
65+
for (const [tabId, data] of attachedTabs) {
66+
sessions.push({
67+
tabId,
68+
domain: data.domain,
69+
captureAllRequests: data.captureAllRequests
70+
});
71+
}
72+
await StorageDB.setSetting('activeSessions', sessions);
73+
await StorageDB.setSetting('windowModeActive', windowModeActive);
74+
}
75+
76+
// Init
77+
chrome.runtime.onStartup.addListener(restoreState);
78+
// Also run immediately in case of update/reload
79+
restoreState();
80+
881

982
function isJavaScriptFile(type, url) {
1083
if (!url) return false;
11-
const urlLower = url.toLowerCase();
84+
// Fast path
1285
if (type === 'Script') return true;
13-
if (urlLower.endsWith('.js') || urlLower.endsWith('.mjs') || urlLower.endsWith('.jsx') || urlLower.includes('.js?') || urlLower.includes('.mjs?') || urlLower.includes('.jsx?')) return true;
14-
if (urlLower.includes('javascript') || urlLower.includes('/script') || urlLower.includes('type=script')) return true;
15-
return false;
86+
const u = url.split('?')[0].toLowerCase(); // ignore params for extension check
87+
return u.endsWith('.js') || u.endsWith('.mjs') || u.endsWith('.jsx') ||
88+
url.includes('javascript:') || url.includes('/script');
1689
}
1790

1891
function matchesDomainOrSubdomain(hostname, targetDomain) {
1992
if (!hostname || !targetDomain) return false;
20-
const hostnameLower = hostname.toLowerCase();
21-
const targetLower = targetDomain.toLowerCase();
22-
if (hostnameLower === targetLower) return true;
23-
if (hostnameLower.endsWith('.' + targetLower)) {
24-
const depth = hostnameLower.split('.').length - targetLower.split('.').length;
25-
if (depth > 0 && depth <= 10) return true;
26-
}
27-
if (targetLower.endsWith('.' + hostnameLower)) {
28-
const depth = targetLower.split('.').length - hostnameLower.split('.').length;
29-
if (depth > 0 && depth <= 10) return true;
30-
}
31-
return false;
93+
if (hostname === targetDomain) return true;
94+
return hostname.endsWith('.' + targetDomain); // Optimized simple suffix check
3295
}
3396

3497
chrome.runtime.onInstalled.addListener(async () => {
35-
// Initialize IndexedDB settings
3698
await StorageDB.setSettings({
3799
isRecording: false,
38100
lastError: null
39101
});
40-
// Data is now stored in IndexedDB object stores, not as a single 'collectedData' key
41102
console.log('[Background] Extension installed/updated, IndexedDB initialized');
42103
});
43104

44105
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
45-
console.log('[Background] Message received:', JSON.stringify(request));
46-
47-
const action = request.action ? request.action.trim() : '';
106+
const action = request.action || '';
48107

49108
if (action === 'startRecording') {
50109
doStartRecording(request.windowId, request.tabId, request.domain, request.captureAllRequests)
51110
.then(() => sendResponse({ success: true, status: 'started' }))
52-
.catch((error) => sendResponse({ success: false, error: error.message }));
111+
.catch((error) => sendResponse({ success: false, error: (error.message || error) }));
53112
return true;
54113
}
55114
if (action === 'stopRecording') {
56115
doStopRecording(request.tabId)
57116
.then(() => sendResponse({ success: true }))
58-
.catch((error) => sendResponse({ success: false, error: error.message }));
117+
.catch((error) => sendResponse({ success: false, error: (error.message || error) }));
59118
return true;
60119
}
61120
if (action === 'clearData') {
@@ -71,36 +130,12 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
71130
return true;
72131
}
73132

74-
// Catch-all for unknown actions to aid debugging
75-
console.warn('[Background] Unknown action received:', request.action);
76-
// Log char codes to detect hidden characters
77-
if (request.action) {
78-
console.warn('Action char codes:', request.action.split('').map(c => c.charCodeAt(0)));
79-
}
80-
sendResponse({ success: false, error: 'Unknown action: ' + request.action });
81-
return false;
133+
return false; // let other listeners handle if any
82134
});
83135

84-
85-
86136
async function updateStorage(entry) {
87-
// Use IndexedDB with automatic batching for optimal performance
88-
// The batching mechanism will automatically flush after 100ms or 10 items
137+
// Direct to IndexedDB, bypass memory cache
89138
await StorageDB.addApiCall(entry);
90-
91-
// Update in-memory cache for quick access
92-
if (!collectedData.apiCalls) collectedData.apiCalls = [];
93-
const index = collectedData.apiCalls.findIndex(req => req.id === entry.id);
94-
if (index !== -1) {
95-
collectedData.apiCalls[index] = entry;
96-
} else {
97-
collectedData.apiCalls.push(entry);
98-
}
99-
100-
// Optimize memory by keeping only last 2000 requests in memory
101-
if (collectedData.apiCalls.length > 2000) {
102-
collectedData.apiCalls.shift();
103-
}
104139
}
105140

106141
// Helper to get hostname safely
@@ -222,6 +257,7 @@ async function attachToTab(tabId, domain, captureAllRequests) {
222257
websockets: new Map()
223258
};
224259
attachedTabs.set(tabId, session);
260+
await saveSessionState(); // Persist state
225261
}
226262

227263
// Listen for new tabs in window mode
@@ -283,6 +319,7 @@ async function doStopRecording(tabId) {
283319
attachedTabs.delete(tid);
284320
}
285321

322+
await saveSessionState(); // Update state
286323
await StorageDB.setSetting('isRecording', false);
287324
}
288325

@@ -336,6 +373,8 @@ chrome.debugger.onDetach.addListener((source, reason) => {
336373
}
337374

338375
attachedTabs.delete(source.tabId);
376+
saveSessionState(); // Update state
377+
339378
// Only stop recording if no tabs are attached and not in window mode
340379
if (attachedTabs.size === 0 && !windowModeActive) {
341380
StorageDB.setSetting('isRecording', false);
@@ -376,21 +415,9 @@ async function handleRequest(tabId, params, session) {
376415
// Filters control display only, not capture
377416

378417
// Layer 4: Block Analytics, Tracking, and Push Notifications
379-
// Blocks common services: Google Analytics, GTM, Firebase, OneSignal, Segment, Mixpanel, etc.
380-
// Blocks keywords: analytics, tracking, telemetry, pixel, metric, etc.
381-
const trackingPatterns = [
382-
'google-analytics', 'googletagmanager', 'g.doubleclick', 'googleads', 'doubleclick', 'facebook.com/tr',
383-
'analytics', 'telemetry', 'pixel', 'tracker', 'tracking',
384-
'firebase', 'fcm.googleapis', 'onesignal', 'braze', 'push', 'notification',
385-
'segment', 'mixpanel', 'amplitude', 'adjust', 'appsflyer', 'heapanalytics',
386-
'hotjar', 'clarity', 'sentry', 'newrelic', 'datadog',
387-
'collect', 'measure', 'beacon',
388-
// Added based on user feedback:
389-
'notifyvisitors', 'clevertap', 'heatmaps', 'event-api', 'google.com/xjs', 'gstatic.com/_/mss', 'connect.facebook.net/signals'
390-
];
391-
392-
if (trackingPatterns.some(p => urlLower.includes(p))) {
393-
console.log(`[API Inspector] ❌ Blocked tracking/analytics: ${url}`);
418+
// Optimized: Use pre-compiled Regex
419+
if (TRACKING_REGEX.test(urlLower)) {
420+
// console.log(`[API Inspector] ❌ Blocked tracking/analytics: ${url}`);
394421
return;
395422
}
396423

content.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,15 @@ function interceptWebSockets() {
4747
if (!window.__capturedWebSockets) window.__capturedWebSockets = {};
4848
window.__capturedWebSockets[url] = ws;
4949

50-
// Cleanup on close
51-
ws.addEventListener('close', function () {
50+
// Cleanup on close or error
51+
const cleanup = () => {
5252
if (window.__capturedWebSockets && window.__capturedWebSockets[url] === ws) {
5353
delete window.__capturedWebSockets[url];
5454
}
55-
});
55+
};
56+
57+
ws.addEventListener('close', cleanup);
58+
ws.addEventListener('error', cleanup);
5659

5760
return ws;
5861
};

dashboard/css/common.css

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,35 @@
11
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Outfit:wght@500;600;700&display=swap');
22

33
:root {
4-
/* Premium Dark Theme Palette - "Midnight & Neon" */
5-
--bg-app: #09090b;
6-
/* Zinc 950 - Deeper black */
7-
--bg-sidebar: #0f1218;
8-
/* Slightly lighter/bluer dark */
9-
--bg-panel: #11141d;
10-
--bg-hover: #1f2536;
11-
--bg-active: #272e42;
12-
--bg-input: #050507;
13-
14-
--border-color: #232836;
15-
--border-light: #32394d;
16-
17-
--text-primary: #f8fafc;
18-
/* Slate 50 */
19-
--text-secondary: #94a3b8;
20-
/* Slate 400 */
21-
--text-muted: #64748b;
22-
/* Slate 500 */
4+
/* Premium Dark Theme Palette - "Midnight & Gold" */
5+
--bg-app: #050505;
6+
--bg-sidebar: #0a0a0a;
7+
--bg-panel: #141414;
8+
--bg-hover: #1f1f22;
9+
--bg-active: #27272a;
10+
--bg-input: #000000;
11+
12+
--border-color: #27272a;
13+
--border-light: #3f3f46;
14+
15+
--text-primary: #ffffff;
16+
--text-secondary: #a1a1aa;
17+
--text-muted: #52525b;
2318

2419
/* Vibrant Accents */
25-
--accent-primary: #6366f1;
26-
/* Indigo 500 - More modern than basic blue */
27-
--accent-hover: #818cf8;
28-
/* Indigo 400 */
29-
--accent-dim: rgba(99, 102, 241, 0.15);
20+
--accent-primary: #FFD600;
21+
--accent-hover: #FFEA00;
22+
--accent-dim: rgba(255, 214, 0, 0.12);
3023

3124
/* Gradient Accents */
32-
--gradient-primary: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
33-
--gradient-text: linear-gradient(135deg, #fff 0%, #cbd5e1 100%);
25+
--gradient-primary: linear-gradient(135deg, #FFD600 0%, #FFAB00 100%);
26+
--gradient-text: linear-gradient(135deg, #fff 0%, #e4e4e7 100%);
3427

3528
/* Status Colors */
3629
--success: #10b981;
37-
/* Emerald 500 */
3830
--warning: #f59e0b;
39-
/* Amber 500 */
4031
--danger: #ef4444;
41-
/* Red 500 */
4232
--info: #3b82f6;
43-
/* Blue 500 */
4433

4534
/* Typography */
4635
--font-heading: 'Outfit', sans-serif;
@@ -52,23 +41,23 @@
5241
--sidebar-width: 280px;
5342

5443
/* Effects */
55-
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
56-
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
57-
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
58-
--glass-bg: rgba(15, 18, 24, 0.7);
59-
--glass-border: 1px solid rgba(255, 255, 255, 0.05);
44+
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
45+
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.3);
46+
--shadow-lg: 0 12px 24px rgba(0, 0, 0, 0.4);
47+
--glass-bg: rgba(10, 10, 10, 0.8);
48+
--glass-border: 1px solid rgba(255, 255, 255, 0.08);
6049

6150
/* Highlight Colors */
6251
--highlight-red: rgba(239, 68, 68, 0.15);
6352
--highlight-green: rgba(16, 185, 129, 0.15);
6453
--highlight-blue: rgba(59, 130, 246, 0.15);
65-
--highlight-yellow: rgba(245, 158, 11, 0.15);
54+
--highlight-yellow: rgba(255, 214, 0, 0.2);
6655
--highlight-purple: rgba(168, 85, 247, 0.15);
6756

6857
/* Material Design Colors for Search Bar */
69-
--accent: #44a2ff;
70-
--accent-surface: #253145;
71-
--neutral: #5e5e5e;
58+
--accent: #FFD600;
59+
--accent-surface: #18181b;
60+
--neutral: #71717a;
7261
}
7362

7463
* {
@@ -143,7 +132,7 @@ body {
143132

144133
.logo-icon {
145134
font-size: 24px;
146-
filter: drop-shadow(0 0 12px rgba(99, 102, 241, 0.5));
135+
filter: drop-shadow(0 0 12px rgba(255, 214, 0, 0.4));
147136
}
148137

149138
.logo-text {
@@ -194,7 +183,7 @@ body {
194183
.nav-item.active {
195184
background: var(--gradient-primary);
196185
color: white;
197-
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
186+
box-shadow: 0 4px 12px rgba(255, 214, 0, 0.4);
198187
}
199188

200189
.nav-badge {
@@ -293,7 +282,7 @@ body {
293282
overflow: hidden;
294283
position: relative;
295284
/* subtle pattern overlay */
296-
background-image: radial-gradient(circle at top right, rgba(99, 102, 241, 0.08), transparent 400px);
285+
background-image: radial-gradient(circle at top right, rgba(255, 214, 0, 0.08), transparent 400px);
297286
}
298287

299288
/* Top Bar */

0 commit comments

Comments
 (0)