From 1ff1ececb42c67a280c1723bd15fb092500da739 Mon Sep 17 00:00:00 2001 From: Dominik Date: Thu, 13 Nov 2025 20:12:28 +0100 Subject: [PATCH] moved files for structure --- .gitignore | 1 + extension/manifest.json | 50 ++++++++++++ extension/popup/css/styles.css | 71 ++++++++++++++++ extension/popup/html/main.html | 32 ++++++++ extension/popup/js/background.js | 129 ++++++++++++++++++++++++++++++ extension/popup/js/visual.js | 89 +++++++++++++++++++++ extension/static/icons/icon32.png | Bin 0 -> 662 bytes extension/static/icons/icon48.png | Bin 0 -> 869 bytes makefile | 5 ++ package.json | 2 +- 10 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 extension/manifest.json create mode 100644 extension/popup/css/styles.css create mode 100644 extension/popup/html/main.html create mode 100644 extension/popup/js/background.js create mode 100644 extension/popup/js/visual.js create mode 100644 extension/static/icons/icon32.png create mode 100644 extension/static/icons/icon48.png diff --git a/.gitignore b/.gitignore index c2658d7..72aae85 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +out/ diff --git a/extension/manifest.json b/extension/manifest.json new file mode 100644 index 0000000..d07d557 --- /dev/null +++ b/extension/manifest.json @@ -0,0 +1,50 @@ +{ + "manifest_version": 2, + "name": "File-Leak", + "version": "1.0", + + "description": "Find hidden files on websites you visit which are not supposed to be there", + "homepage_url": "https://agres.online", + + "icons": { + "32": "static/icons/icon32.png", + "48": "static/icons/icon48.png" + }, + + "permissions": [ + "webNavigation", + "storage", + "", + "http://*/*", + "https://*/*" + ], + + "browser_action": { + "default_icon": "static/icons/icon48.png", + "default_title": "File-leak", + "default_popup": "popup/html/main.html" + }, + + "background": { + "scripts": ["popup/js/background.js"], + "persistent": false + }, + + "content_scripts": [ + { + "matches": [""], + "js": ["popup/js/visual.js"] + } + ], + "browser_specific_settings": { + "gecko": { + "id": "dominik@agres.online", + "strict_min_version": "120.0", + "data_collection_permissions": { + "collects_diagnostic_data": false, + "collects_usage_data": false, + "required": ["none"] + } + } + } +} diff --git a/extension/popup/css/styles.css b/extension/popup/css/styles.css new file mode 100644 index 0000000..78a25bb --- /dev/null +++ b/extension/popup/css/styles.css @@ -0,0 +1,71 @@ +body { + margin: 0; + padding: 0; + font-family: sans-serif; + background: #1e2430; + color: #e4e7ec; +} + +#popup-content { + padding: 12px; + width: 260px; +} + +h1 { + margin-top: 0; + font-size: 18px; + color: #f0f3f8; +} + +label, button { + display: block; + margin: 8px 0; +} + +button { + padding: 6px 10px; + background: #2d3441; + border: 1px solid #3a4253; + color: #e4e7ec; + border-radius: 4px; + cursor: pointer; +} + +button:hover { + background: #3a4253; +} + +#entry-box { + margin-top: 10px; + background: #252b36; + border: 1px solid #333b49; + border-radius: 4px; + max-height: 250px; + overflow-y: auto; + padding: 6px; +} + +.entry { + display: grid; + grid-template-columns: 1.2fr 1fr auto auto; + align-items: center; + gap: 6px; + padding: 6px; + background: #2b3240; + border-radius: 3px; + margin-bottom: 6px; + font-size: 12px; +} + +.entry span { + font-size: 12px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + min-width: 0; +} + +.entry button { + padding: 4px 6px; + font-size: 12px; +} diff --git a/extension/popup/html/main.html b/extension/popup/html/main.html new file mode 100644 index 0000000..87fa62b --- /dev/null +++ b/extension/popup/html/main.html @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + diff --git a/extension/popup/js/background.js b/extension/popup/js/background.js new file mode 100644 index 0000000..fe73008 --- /dev/null +++ b/extension/popup/js/background.js @@ -0,0 +1,129 @@ +// function to scan the url the tab is on for hidden files + +async function onTabUpdate(tabId, changeInfo, tab) { + if (changeInfo.status !== "complete") return; + + const url = new URL(tab.url); + const hostname = url.hostname; + + const stored = await browser.storage.local.get("entries"); + const existingEntries = stored.entries || []; + + const alreadyDone = existingEntries.some(e => e.domainField === hostname); + if (alreadyDone) return; + + async function tryFetch(pathname) { + const target = url.origin + pathname; + let response; + try { + response = await fetch(target, { redirect: "manual" }); + } catch { + return null; + } + return response.status === 200 ? target : null; + } + + const results = { + env: await tryFetch("/.env"), + git: await tryFetch("/.git"), + dsstore: await tryFetch("/.DS_Store"), + config: await tryFetch("/.config"), + svn: await tryFetch("/.svn"), + npm: await tryFetch("/.npm"), + hg: await tryFetch("/.hg"), + docker: await tryFetch("/.docker"), + }; + + const newEntries = [...existingEntries]; + + for (const [key, foundPath] of Object.entries(results)) { + if (!foundPath) continue; + + const entry = { + domainField: hostname, + pathField: foundPath, + type: key + }; + + newEntries.push(entry); + + } + + await browser.storage.local.set({ entries: newEntries }); + +} + +// Enable, Idsable automatic listener and the message listener for it + +function enableListener() { + if (!browser.tabs.onUpdated.hasListener(onTabUpdate)) { + browser.tabs.onUpdated.addListener(onTabUpdate); + } +} + +function disableListener() { + if (browser.tabs.onUpdated.hasListener(onTabUpdate)) { + browser.tabs.onUpdated.removeListener(onTabUpdate); + } +} + +browser.runtime.onMessage.addListener((msg) => { + if (msg.type === "toggleListener") { + if (msg.enabled) enableListener(); + else disableListener(); + } +}); + +// Singe run, can be merged with onTabUpdate function + +async function runSingleScan() { + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + if (!tabs.length) return; + const tab = tabs[0]; + const url = new URL(tab.url); + const hostname = url.hostname; + + async function tryFetch(path) { + const target = url.origin + path; + let response; + try { + response = await fetch(target, { redirect: "manual" }); + } catch { + return null; + } + return response.status === 200 ? target : null; + } + + const results = { + env: await tryFetch("/.env"), + git: await tryFetch("/.git"), + dsstore: await tryFetch("/.DS_Store"), + config: await tryFetch("/.config"), + svn: await tryFetch("/.svn"), + npm: await tryFetch("/.npm"), + hg: await tryFetch("/.hg"), + docker: await tryFetch("/.docker"), + }; + + const stored = await browser.storage.local.get("entries"); + const entries = stored.entries || []; + + for (const [key, foundPath] of Object.entries(results)) { + if (!foundPath) continue; + + entries.push({ + domainField: hostname, + pathField: foundPath, + type: key + }); + + } + + await browser.storage.local.set({ entries }); +} + +browser.runtime.onMessage.addListener((msg) => { + if (msg.type === "runOnce") { + runSingleScan(); + } +}); diff --git a/extension/popup/js/visual.js b/extension/popup/js/visual.js new file mode 100644 index 0000000..fb0bf3d --- /dev/null +++ b/extension/popup/js/visual.js @@ -0,0 +1,89 @@ +// Handling of adding saving and loading list entries + +function addEntry(domain, path) { + + const list = document.getElementById("entry-list"); + + const entry = document.createElement("div"); + entry.className = "entry"; + + const domainField = document.createElement("span"); + domainField.textContent = domain; + + const pathField = document.createElement("span"); + pathField.textContent = path; + + const deleteButton = document.createElement("button"); + deleteButton.textContent = "Delete"; + deleteButton.addEventListener("click", function () { + entry.remove(); + saveAllEntries(); + }) + + const openButton = document.createElement("button"); + openButton.textContent = "Open"; + openButton.addEventListener("click", function () { + const url = pathField.textContent; + if (url) { + window.open(url, "_blank"); + } + }); + + entry.appendChild(domainField); + entry.appendChild(pathField); + entry.appendChild(deleteButton); + entry.appendChild(openButton); + + list.appendChild(entry); + + saveAllEntries(); +} + +function saveAllEntries() { + const entries = []; + + document.querySelectorAll(".entry").forEach(entry => { + const spans = entry.querySelectorAll("span"); + entries.push({ + domainField: spans[0].textContent, + pathField: spans[1].textContent + }); + }); + + browser.storage.local.set({ entries }); +} + +async function loadEntries() { + const stored = await browser.storage.local.get("entries"); + if (!stored.entries) return; + + for (const data of stored.entries) { + addEntry(data.domainField, data.pathField); + } +} + +// Load entries when popup starts + +document.addEventListener("DOMContentLoaded", () => { + loadEntries(); +}); + +// Handle persistance for toggle button + +const toggle = document.getElementById("listenerToggle"); + +browser.storage.local.get("listenerEnabled").then(({ listenerEnabled }) => { + toggle.checked = !!listenerEnabled; +}); + +toggle.addEventListener("change", (e) => { + const enabled = e.target.checked; + browser.storage.local.set({ listenerEnabled: enabled }); + browser.runtime.sendMessage({ type: "toggleListener", enabled }); +}); + +// Run one scan on button press + +document.getElementById("runOnceBtn").addEventListener("click", () => { + browser.runtime.sendMessage({ type: "runOnce" }); +}); diff --git a/extension/static/icons/icon32.png b/extension/static/icons/icon32.png new file mode 100644 index 0000000000000000000000000000000000000000..3094d6a8c1a3aa395e4029c0f1d654685949f2c9 GIT binary patch literal 662 zcmV;H0%`q;P)&uPm#dEA@5jcD8?02>f4 zvg)b6`Y#~(iU3v0dvBYa*80y{?YG1<>r6jp$-aaJtped4M3{|}SO1Bi1xRb;;bZ4Z z_0u$+i2zK~JccucN9=To4df+`BV=3#^NiY!hmPa?jj|C5z%=JAoXNdG#LI_D27h{q za1hZ)YIhbKXQwu5U<|*rCWR7wm*brhXDAIAI)!y zoyU0{`L96GzI!8_i2;D#ouAq2r9DBqrJ3-r)7{V2 z6{YM0P^D%VuoGsxFrY*LSjqJ~m{%q011MURmk4-2skL~$@o)&})oyM30s0+|PJEX( znRsV13DvBc_~#rJOIPlqVZ4^9r7K0AcMmU=?dQyd#dJ*ztr5IHX8$`*|23gXs$zT% z@3Cmvb*4xm4a>Tf!;Pt-0JyA}O9Oze4F=Hpw*X>N5&%f;3KC?1uOMp@j+db>l}6*% zc*y)R%(@Y!)r!@uq+$C|B!DBS(Io4%#ARon`aCZ7~!_Tpwg)9dW zKMO-6*_8Mri$q>Iy$LyDB8p2&xzM_L%yCL032@~syod(;s5{u07*qoM6N<$f)7h6mH+?% literal 0 HcmV?d00001 diff --git a/extension/static/icons/icon48.png b/extension/static/icons/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..bde8f4339ea549d68be371bfc53446a9fa3344a8 GIT binary patch literal 869 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-s3dtTpz6=aiY77hwEes65fI&vMa$g2X8p@M>gtcrn* zioUM4p^mnptg@l3l7Wnpft<2|f|h}jmVum#p_aCxf|jnV5>VC%s2Hdh6Uiv*$$^c< zltLB(YKPb^r)r2S{{R2~RMAgmKqnfP1o;I6X>5Scv|!2cN1y*NX%y{wuHXMqtj2oZ zKWpYV*20fpPvu=N1?pi;@^*JIS-J7$Um%CQ#M9T6{UtZA5F;b!?E3dW=>$&~#}JR> zbHiRnH5&-rIdqIox5@SCzJ)PPnVyqskuF`oRHf>JwoF$QRoyv=ByeCUo#{YYo%`?BdNcmqvu$cadE!qFPj<4G1 zXz%fgD?WUBjmep1Z;!~9yuCiV@%bOqZ_WyG3KCT@^K0d|KlZaZl6U9P#$%^m9N#vZ$+scLI7L}G zTJ>(v)3^WrIxDlCdS0*GE!XvVv8iyE~TbY_z8Cz%@7+4t? z)Wv=0N70a*pOTqYiK4*_tib@H;bGN{K%fQ