diff --git a/background.js b/background.js
index 6a107ff..b8d7d50 100644
--- a/background.js
+++ b/background.js
@@ -134,27 +134,59 @@ const healthCheck = {
}
};
+// Default configuration
+const DEFAULT_CONFIG = {
+ apiKey: '',
+ domainsDBURL: 'https://git.365devnet.eu/365DevNet/EnterpriseAppProtection/raw/branch/main/domains.json',
+ updateInterval: 24, // hours
+ warningTemplate: 'Warning: This link claims to be {app} but goes to an unofficial domain.',
+ lastUpdate: null,
+ suspiciousCount: 0,
+ suspiciousLinks: []
+};
+
+// Function to get configuration
+async function getConfig() {
+ return new Promise((resolve) => {
+ chrome.storage.local.get([
+ "safeBrowsingApiKey",
+ "domainsDBURL",
+ "updateInterval",
+ "warningTemplate"
+ ], (result) => {
+ resolve({
+ apiKey: result.safeBrowsingApiKey || DEFAULT_CONFIG.apiKey,
+ domainsDBURL: result.domainsDBURL || DEFAULT_CONFIG.domainsDBURL,
+ updateInterval: result.updateInterval || DEFAULT_CONFIG.updateInterval,
+ warningTemplate: result.warningTemplate || DEFAULT_CONFIG.warningTemplate
+ });
+ });
+ });
+}
+
+// Function to update last update timestamp
+async function updateLastUpdate() {
+ await chrome.storage.local.set({ lastUpdate: Date.now() });
+}
+
+// Function to update domains database
async function updateDomainsDB() {
- chrome.storage.local.get(["domainsDBURL"], async function (result) {
- const domainsDBURL = result.domainsDBURL || "https://raw.githubusercontent.com/rrpbergsma/EnterpriseAppProtection/refs/heads/main/domains.json";
- console.log("updateDomainsDB: Starting update from URL:", domainsDBURL);
try {
- const response = await fetch(domainsDBURL);
- if (!response.ok) {
- console.error("updateDomainsDB: Fetch failed with status", response.status, response.statusText);
- return;
- }
- domainsDB = await response.json();
- chrome.storage.local.set({
- domainsDB: domainsDB,
- lastUpdate: Date.now()
- }, () => {
- console.log("updateDomainsDB: Database updated successfully at", new Date().toLocaleString());
- });
+ const config = await getConfig();
+ console.log("Updating domains database from:", config.domainsDBURL);
+ const response = await fetch(config.domainsDBURL);
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ const data = await response.json();
+ await chrome.storage.local.set({ domainsDB: data });
+ await updateLastUpdate();
+ console.log('Domains database updated successfully');
+ return true;
} catch (error) {
- console.error("updateDomainsDB: Failed to update domains database:", error);
+ console.error('Failed to update domains database:', error);
+ return false;
}
- });
}
// Run updates when the extension is installed or started
diff --git a/config.js b/config.js
index 70c80dd..77d21ad 100644
--- a/config.js
+++ b/config.js
@@ -1,7 +1,7 @@
// config.js
const CONFIG = {
// URL to fetch the approved enterprise domains list
- DOMAINS_DB_URL: 'https://raw.githubusercontent.com/rrpbergsma/EnterpriseAppProtection/refs/heads/main/domains.json',
+ DOMAINS_DB_URL: 'https://git.365devnet.eu/365DevNet/EnterpriseAppProtection/raw/branch/main/domains.json',
// Update interval in hours
UPDATE_INTERVAL: 24,
// Warning message template for suspicious links
diff --git a/domains_management.js b/domains_management.js
index 855671f..d0c2c63 100644
--- a/domains_management.js
+++ b/domains_management.js
@@ -1,39 +1,204 @@
document.addEventListener("DOMContentLoaded", function () {
- const saveButton = document.getElementById("save");
- const trustedInput = document.getElementById("trusted");
- const blockedInput = document.getElementById("blocked");
+ // Get UI elements
+ const addTrustedBtn = document.getElementById("addTrustedDomain");
+ const addBlockedBtn = document.getElementById("addBlockedDomain");
+ const domainModal = document.getElementById("domainModal");
+ const modalTitle = document.getElementById("modalTitle");
+ const domainNameInput = document.getElementById("domainName");
+ const domainTypeSelect = document.getElementById("domainType");
+ const saveDomainBtn = document.getElementById("saveDomain");
+ const cancelDomainBtn = document.getElementById("cancelDomain");
+ const trustedSearch = document.getElementById("trustedSearch");
+ const blockedSearch = document.getElementById("blockedSearch");
+ const trustedDomainsList = document.getElementById("trustedDomainsList");
+ const blockedDomainsList = document.getElementById("blockedDomainsList");
+ const statusMessage = document.getElementById("statusMessage");
+
+ let currentDomainType = 'trusted';
+ let editingDomain = null;
// Load saved domains
- chrome.storage.local.get(["trustedDomains", "blockedDomains"], function (data) {
- if (data.trustedDomains) trustedInput.value = data.trustedDomains.join("\n");
- if (data.blockedDomains) blockedInput.value = data.blockedDomains.join("\n");
- });
+ loadDomains();
- // Save button event
- saveButton.addEventListener("click", function () {
- // Retrieve domains from input fields
- const trustedDomains = trustedInput.value.split("\n").map(d => d.trim()).filter(d => d);
- const blockedDomains = blockedInput.value.split("\n").map(d => d.trim()).filter(d => d);
+ // Add domain buttons
+ if (addTrustedBtn) {
+ addTrustedBtn.addEventListener("click", () => openAddModal('trusted'));
+ }
+ if (addBlockedBtn) {
+ addBlockedBtn.addEventListener("click", () => openAddModal('blocked'));
+ }
- // Save to Chrome storage
- chrome.storage.local.set({ trustedDomains, blockedDomains }, function () {
- showPopup("✅ Changes saved successfully!");
- });
- });
+ // Modal buttons
+ if (saveDomainBtn) {
+ saveDomainBtn.addEventListener("click", saveDomain);
+ }
+ if (cancelDomainBtn) {
+ cancelDomainBtn.addEventListener("click", closeModal);
+ }
- // Function to show styled popup message
- function showPopup(message) {
- const popup = document.getElementById("popupMessage");
- const popupText = document.getElementById("popupText");
- const popupClose = document.getElementById("popupClose");
+ // Search functionality
+ if (trustedSearch) {
+ trustedSearch.addEventListener("input", (e) => filterDomains('trusted', e.target.value));
+ }
+ if (blockedSearch) {
+ blockedSearch.addEventListener("input", (e) => filterDomains('blocked', e.target.value));
+ }
- popupText.innerText = message;
- popup.classList.remove("hidden");
- popup.classList.add("visible");
-
- popupClose.addEventListener("click", function () {
- popup.classList.remove("visible");
- popup.classList.add("hidden");
+ // Functions
+ function loadDomains() {
+ chrome.storage.local.get(["trustedDomains", "blockedDomains"], function (data) {
+ renderDomainList('trusted', data.trustedDomains || []);
+ renderDomainList('blocked', data.blockedDomains || []);
});
}
+
+ function renderDomainList(type, domains) {
+ const list = type === 'trusted' ? trustedDomainsList : blockedDomainsList;
+ if (!list) return;
+
+ list.innerHTML = '';
+ domains.forEach(domain => {
+ const item = createDomainItem(domain, type);
+ list.appendChild(item);
+ });
+ }
+
+ function createDomainItem(domain, type) {
+ const div = document.createElement('div');
+ div.className = 'domain-item';
+ div.innerHTML = `
+
+ ${domain}
+ ${type}
+
+
+
+
+
+ `;
+ return div;
+ }
+
+ function openAddModal(type) {
+ currentDomainType = type;
+ editingDomain = null;
+ modalTitle.textContent = `Add ${type === 'trusted' ? 'Trusted' : 'Blocked'} Domain`;
+ domainNameInput.value = '';
+ domainTypeSelect.value = type;
+ domainModal.classList.add('active');
+ }
+
+ function closeModal() {
+ domainModal.classList.remove('active');
+ editingDomain = null;
+ }
+
+ function saveDomain() {
+ const domain = domainNameInput.value.trim();
+ if (!domain) {
+ showStatus('Please enter a domain name', 'error');
+ return;
+ }
+
+ chrome.storage.local.get(["trustedDomains", "blockedDomains"], function (data) {
+ const trustedDomains = data.trustedDomains || [];
+ const blockedDomains = data.blockedDomains || [];
+ const type = domainTypeSelect.value;
+
+ // Remove from both lists if editing
+ if (editingDomain) {
+ const oldType = currentDomainType;
+ if (oldType === 'trusted') {
+ const index = trustedDomains.indexOf(editingDomain);
+ if (index > -1) trustedDomains.splice(index, 1);
+ } else {
+ const index = blockedDomains.indexOf(editingDomain);
+ if (index > -1) blockedDomains.splice(index, 1);
+ }
+ }
+
+ // Add to appropriate list
+ if (type === 'trusted' && !trustedDomains.includes(domain)) {
+ trustedDomains.push(domain);
+ } else if (type === 'blocked' && !blockedDomains.includes(domain)) {
+ blockedDomains.push(domain);
+ }
+
+ // Save to storage
+ chrome.storage.local.set({
+ trustedDomains: trustedDomains,
+ blockedDomains: blockedDomains
+ }, function () {
+ loadDomains();
+ closeModal();
+ showStatus(`Domain ${editingDomain ? 'updated' : 'added'} successfully`, 'success');
+ });
+ });
+ }
+
+ function editDomain(domain, type) {
+ currentDomainType = type;
+ editingDomain = domain;
+ modalTitle.textContent = `Edit ${type === 'trusted' ? 'Trusted' : 'Blocked'} Domain`;
+ domainNameInput.value = domain;
+ domainTypeSelect.value = type;
+ domainModal.classList.add('active');
+ }
+
+ function removeDomain(domain, type) {
+ if (confirm(`Are you sure you want to remove ${domain}?`)) {
+ chrome.storage.local.get(["trustedDomains", "blockedDomains"], function (data) {
+ const trustedDomains = data.trustedDomains || [];
+ const blockedDomains = data.blockedDomains || [];
+
+ if (type === 'trusted') {
+ const index = trustedDomains.indexOf(domain);
+ if (index > -1) trustedDomains.splice(index, 1);
+ } else {
+ const index = blockedDomains.indexOf(domain);
+ if (index > -1) blockedDomains.splice(index, 1);
+ }
+
+ chrome.storage.local.set({
+ trustedDomains: trustedDomains,
+ blockedDomains: blockedDomains
+ }, function () {
+ loadDomains();
+ showStatus('Domain removed successfully', 'success');
+ });
+ });
+ }
+ }
+
+ function filterDomains(type, searchTerm) {
+ const list = type === 'trusted' ? trustedDomainsList : blockedDomainsList;
+ if (!list) return;
+
+ const items = list.getElementsByClassName('domain-item');
+ searchTerm = searchTerm.toLowerCase();
+
+ Array.from(items).forEach(item => {
+ const domainName = item.querySelector('.domain-name').textContent.toLowerCase();
+ item.style.display = domainName.includes(searchTerm) ? '' : 'none';
+ });
+ }
+
+ function showStatus(message, type) {
+ statusMessage.textContent = message;
+ statusMessage.className = `status-message ${type}`;
+ statusMessage.style.display = 'block';
+ setTimeout(() => {
+ statusMessage.style.display = 'none';
+ }, 3000);
+ }
+
+ // Make functions available globally for onclick handlers
+ window.editDomain = editDomain;
+ window.removeDomain = removeDomain;
});
\ No newline at end of file
diff --git a/manifest.json b/manifest.json
index f76fdb6..516a2b9 100644
--- a/manifest.json
+++ b/manifest.json
@@ -43,7 +43,7 @@
},
"options_page": "options.html",
"content_security_policy": {
- "extension_pages": "script-src 'self'; object-src 'self'; connect-src 'self' https://raw.githubusercontent.com/ https://safebrowsing.googleapis.com/",
+ "extension_pages": "script-src 'self'; object-src 'self'; connect-src 'self' https://git.365devnet.eu/ https://safebrowsing.googleapis.com/",
"sandbox": "sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self'"
},
"web_accessible_resources": [{
diff --git a/options.html b/options.html
index 2ab1963..0d51385 100644
--- a/options.html
+++ b/options.html
@@ -225,7 +225,7 @@
diff --git a/options.js b/options.js
index 4b0c2c8..1155b56 100644
--- a/options.js
+++ b/options.js
@@ -11,35 +11,35 @@ document.addEventListener("DOMContentLoaded", function () {
console.error("⚠️ Element with ID 'warningTemplate' not found in options.html!");
}
- // Default values
- const defaultValues = {
- safeBrowsingApiKey: "",
- domainsDBURL: "https://raw.githubusercontent.com/rrpbergsma/EnterpriseAppProtection/refs/heads/main/domains.json",
+ // Default configuration
+ const DEFAULT_CONFIG = {
+ apiKey: '',
+ domainsDBURL: 'https://git.365devnet.eu/365DevNet/EnterpriseAppProtection/raw/branch/main/domains.json',
updateInterval: 24,
- warningTemplate: "Warning: This link claims to be {app} but goes to an unofficial domain."
+ warningTemplate: 'Warning: This link claims to be {app} but goes to an unofficial domain.'
};
// Load stored settings and apply defaults where needed
chrome.storage.local.get(["safeBrowsingApiKey", "domainsDBURL", "updateInterval", "warningTemplate"], function (data) {
- if (apiKeyElement) apiKeyElement.value = data.safeBrowsingApiKey || defaultValues.safeBrowsingApiKey;
- if (domainsDBURLElement) domainsDBURLElement.value = data.domainsDBURL || defaultValues.domainsDBURL;
- if (updateIntervalElement) updateIntervalElement.value = data.updateInterval || defaultValues.updateInterval;
+ if (apiKeyElement) apiKeyElement.value = data.safeBrowsingApiKey || DEFAULT_CONFIG.apiKey;
+ if (domainsDBURLElement) domainsDBURLElement.value = data.domainsDBURL || DEFAULT_CONFIG.domainsDBURL;
+ if (updateIntervalElement) updateIntervalElement.value = data.updateInterval || DEFAULT_CONFIG.updateInterval;
if (warningTemplateElement) {
- warningTemplateElement.value = data.warningTemplate || defaultValues.warningTemplate;
+ warningTemplateElement.value = data.warningTemplate || DEFAULT_CONFIG.warningTemplate;
}
});
// Save settings when clicking "Save"
if (saveButton) {
saveButton.addEventListener("click", function () {
- const apiKey = apiKeyElement && apiKeyElement.value.trim() ? apiKeyElement.value.trim() : defaultValues.safeBrowsingApiKey;
- const domainsDBURL = domainsDBURLElement && domainsDBURLElement.value.trim() ? domainsDBURLElement.value.trim() : defaultValues.domainsDBURL;
+ const apiKey = apiKeyElement && apiKeyElement.value.trim() ? apiKeyElement.value.trim() : DEFAULT_CONFIG.apiKey;
+ const domainsDBURL = domainsDBURLElement && domainsDBURLElement.value.trim() ? domainsDBURLElement.value.trim() : DEFAULT_CONFIG.domainsDBURL;
const updateInterval = updateIntervalElement && updateIntervalElement.value.trim()
- ? parseInt(updateIntervalElement.value.trim()) || defaultValues.updateInterval
- : defaultValues.updateInterval;
+ ? parseInt(updateIntervalElement.value.trim()) || DEFAULT_CONFIG.updateInterval
+ : DEFAULT_CONFIG.updateInterval;
const warningTemplate = warningTemplateElement && warningTemplateElement.value.trim()
? warningTemplateElement.value.trim()
- : defaultValues.warningTemplate;
+ : DEFAULT_CONFIG.warningTemplate;
chrome.storage.local.set({
safeBrowsingApiKey: apiKey,