feat: Enhance Enterprise App Protection extension with monitoring and UI improvements

- Introduce error reporting and performance monitoring in background.js to track API calls and processing times.
- Implement health check system to ensure the extension's operational status and log issues.
- Add caching and encryption utilities in content.js for improved link analysis and data validation.
- Refactor link analysis to process in batches, enhancing performance and user experience.
- Update UI in domains_management.html and options.html for better usability and aesthetics, including responsive design and improved layout.
- Enhance popup.html to display suspicious links with better styling and functionality.
- Modify manifest.json to include new permissions and host access for Safe Browsing API.
This commit is contained in:
becarta
2025-05-10 03:31:18 +02:00
parent ba83c95914
commit 13d9821b8d
6 changed files with 1220 additions and 396 deletions

View File

@@ -3,6 +3,136 @@
console.log("Background service worker loaded");
let domainsDB = {};
let SAFE_BROWSING_API_KEY = "";
const API_CALL_LIMIT = 100; // Maximum number of API calls per minute
let apiCallCount = 0;
let lastResetTime = Date.now();
// Error reporting service
const errorReporter = {
errors: [],
maxErrors: 100,
log(error, context = {}) {
const errorEntry = {
timestamp: Date.now(),
error: error.message || error,
stack: error.stack,
context
};
this.errors.push(errorEntry);
if (this.errors.length > this.maxErrors) {
this.errors.shift();
}
// Send to monitoring service if configured
if (this.monitoringEndpoint) {
this.sendToMonitoring(errorEntry);
}
console.error('Error logged:', errorEntry);
},
async sendToMonitoring(errorEntry) {
try {
await fetch(this.monitoringEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(errorEntry)
});
} catch (e) {
console.error('Failed to send error to monitoring:', e);
}
},
getErrors() {
return [...this.errors];
},
clearErrors() {
this.errors = [];
}
};
// Performance monitoring
const performanceMonitor = {
metrics: {
apiCalls: 0,
processingTime: 0,
errors: 0
},
startTimer() {
return performance.now();
},
endTimer(startTime) {
return performance.now() - startTime;
},
logMetric(name, value) {
this.metrics[name] = (this.metrics[name] || 0) + value;
},
getMetrics() {
return { ...this.metrics };
},
reset() {
this.metrics = {
apiCalls: 0,
processingTime: 0,
errors: 0
};
}
};
// Health check system
const healthCheck = {
lastCheck: Date.now(),
status: 'healthy',
issues: [],
async check() {
const startTime = performanceMonitor.startTimer();
try {
// Check storage access
await chrome.storage.local.get(['domainsDB']);
// Check API key
if (!SAFE_BROWSING_API_KEY) {
throw new Error('API key not configured');
}
// Check domains database
if (!domainsDB || Object.keys(domainsDB).length === 0) {
throw new Error('Domains database is empty');
}
this.status = 'healthy';
this.issues = [];
} catch (error) {
this.status = 'unhealthy';
this.issues.push({
timestamp: Date.now(),
error: error.message
});
errorReporter.log(error, { component: 'healthCheck' });
}
performanceMonitor.logMetric('processingTime', performanceMonitor.endTimer(startTime));
this.lastCheck = Date.now();
},
getStatus() {
return {
status: this.status,
lastCheck: this.lastCheck,
issues: [...this.issues]
};
}
};
async function updateDomainsDB() {
chrome.storage.local.get(["domainsDBURL"], async function (result) {
@@ -85,6 +215,29 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
});
return true; // Keep message channel open for async response
}
if (message.action === "checkSafeBrowsing") {
checkSafeBrowsing(message.url)
.then(result => sendResponse(result))
.catch(error => {
console.error("Safe Browsing API error:", error);
sendResponse({ isUnsafe: false });
});
return true; // Required for async response
}
if (message.action === "getHealthStatus") {
sendResponse(healthCheck.getStatus());
return true;
}
if (message.action === "getMetrics") {
sendResponse({
performance: performanceMonitor.getMetrics(),
errors: errorReporter.getErrors()
});
return true;
}
});
// Debug Mode: Keep-alive mechanism for testing
@@ -97,4 +250,78 @@ if (DEBUG_MODE) {
console.log("keepAlive alarm triggered, service worker is active");
}
});
}
}
// Reset API call count every minute
setInterval(() => {
apiCallCount = 0;
lastResetTime = Date.now();
}, 60000);
// Check URL against Google Safe Browsing API
async function checkSafeBrowsing(url) {
const startTime = performanceMonitor.startTimer();
try {
// Check rate limit
if (apiCallCount >= API_CALL_LIMIT) {
throw new Error('API call limit reached');
}
// Get API key from storage
if (!SAFE_BROWSING_API_KEY) {
const result = await chrome.storage.local.get(["safeBrowsingApiKey"]);
SAFE_BROWSING_API_KEY = result.safeBrowsingApiKey;
if (!SAFE_BROWSING_API_KEY) {
throw new Error('Safe Browsing API key not set');
}
}
apiCallCount++;
performanceMonitor.logMetric('apiCalls', 1);
const response = await fetch(
`https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${SAFE_BROWSING_API_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
client: {
clientId: "enterprise-app-protection",
clientVersion: "1.0"
},
threatInfo: {
threatTypes: ["MALWARE", "SOCIAL_ENGINEERING"],
platformTypes: ["ANY_PLATFORM"],
threatEntryTypes: ["URL"],
threatEntries: [{ url }]
}
})
}
);
if (!response.ok) {
throw new Error(`API responded with status: ${response.status}`);
}
const data = await response.json();
performanceMonitor.logMetric('processingTime', performanceMonitor.endTimer(startTime));
return { isUnsafe: data.matches ? true : false };
} catch (error) {
performanceMonitor.logMetric('errors', 1);
errorReporter.log(error, { url, apiCallCount });
return { isUnsafe: false };
}
}
// Listen for storage changes to update API key
chrome.storage.onChanged.addListener((changes, namespace) => {
if (namespace === "local" && changes.safeBrowsingApiKey) {
SAFE_BROWSING_API_KEY = changes.safeBrowsingApiKey.newValue;
}
});
// Add periodic health checks
setInterval(() => {
healthCheck.check();
}, 300000); // Every 5 minutes