diff options
author | Mark H Weaver <mhw@netris.org> | 2023-12-24 03:17:17 -0500 |
---|---|---|
committer | Mark H Weaver <mhw@netris.org> | 2023-12-24 05:43:25 -0500 |
commit | f889514426e512e5602c71e1b411ae0332a33366 (patch) | |
tree | 3b82853563494d606da665ea407b30ef9b60d2b2 /data/extensions/jsr@javascriptrestrictor/fp_report.js | |
parent | 6a76a10682b6e63f562e4b9f26f3ef12f88bd839 (diff) |
Update the JShelter extension to 0.17.0.
Diffstat (limited to 'data/extensions/jsr@javascriptrestrictor/fp_report.js')
-rw-r--r-- | data/extensions/jsr@javascriptrestrictor/fp_report.js | 436 |
1 files changed, 253 insertions, 183 deletions
diff --git a/data/extensions/jsr@javascriptrestrictor/fp_report.js b/data/extensions/jsr@javascriptrestrictor/fp_report.js index 2606dc9..f9f44e3 100644 --- a/data/extensions/jsr@javascriptrestrictor/fp_report.js +++ b/data/extensions/jsr@javascriptrestrictor/fp_report.js @@ -21,18 +21,20 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. // +let hiddenTraces = {}; + /** * Event listener that listens for a load of FPD report page. If the page is loaded, fetch FPD data from background. * * \param callback Function that initializes FPD report creation from fetched data. */ window.addEventListener('load', () => { - browser.runtime.sendMessage({ - purpose: "fpd-get-report-data", - tabId: new URLSearchParams(window.location.search).get("id") - }).then((result) => { - createReport(result); - }); + browser.runtime.sendMessage({ + purpose: "fpd-get-report-data", + tabId: new URLSearchParams(window.location.search).get("id") + }).then((result) => { + createReport(result); + }); }); /** @@ -41,182 +43,250 @@ window.addEventListener('load', () => { * \param data Information about latest fingerprinting evaluation consisting of all essential FPD objects. */ function createReport(data) { - var {tabObj, groups, latestEvals, fpDb, exceptionWrappers} = data; + var {tabObj, groups, latestEvals, fpDb, exceptionWrappers} = data; + var reportContainer = document.getElementById("fpd-report-container"); + if (!tabObj || !groups || !groups.root || !groups.all || !fpDb || !latestEvals) { + report.innerHTML =`<div class="alert">${browser.i18n.getMessage("FPDReportMissingData")}</div>`; + return; + } + + // parse latestEvals to create more useful representation for FPD report generation + var processedEvals = {}; + for (let item of latestEvals.evalStats) { + processedEvals[item.title] = processedEvals[item.title] || {}; + processedEvals[item.title].type = item.type; + let total = 0; + if (fpDb[item.title]) { + for (let stat of Object.values(fpDb[item.title])) { + total += stat.total; + } + } + processedEvals[item.title].total = total; + } + + // add page URL and FavIcon to header section of the report + if (tabObj) { + let urlObj = new URL(tabObj.url); + var url = urlObj.hostname + (urlObj.pathname.length > 1 ? urlObj.pathname : ""); + document.getElementById("report-url").innerHTML = url; + let img = document.getElementById("pageFavicon"); + img.src = tabObj.favIconUrl; + } + + var html = ""; + + // generate html code for evaluated group + let generateGroup = (group) => { + if (processedEvals[group]) { + if (groups.all[group].description) { + html += "<div id=\"" + group + "\" class=\"fpd-group access\">"; + html += "<h2>" + group + "</h2>"; + html += `<button class="help" id="expand${group}" >⤵</button>`; + html += "<section>"; + html += "<p>" + groups.all[group].description + "</p>"; + } + for (let [item, type] of Object.entries(groups.all[group].items)) { + if (type == "group") { + generateGroup(item); + } + else { + generateResource(item) + } + } + if (groups.all[group].description) { + html += "</section></div>"; + } + } + } + + // generate html code for evaluated resource (get,set,call) + let generateResource = (resource) => { + if (processedEvals[resource]) { + let callers = ""; + if (fpDb[resource]) { + for (let t of Object.values(fpDb[resource])) { + let traces = Object.keys(t.callers); + for (trace of traces) { + if (trace !== "" && !(trace in hiddenTraces)) { + callers += "<p>" + trace.replace(/\n/g, '<br>') + "</p>"; + } + } + } + } + let accessRaw = processedEvals[resource].total; + let accessCount = accessRaw >= 1000 ? "1000+" : accessRaw; + html += `<div class="details ${accessRaw > 0 ? "access" : "no-access"}"><h4><span class="dot">-</span> ` + + `${resource} (${exceptionWrappers.includes(resource) ? "n/a" : accessCount})</h4>\n${callers}</div>`; + } + } + + // start generating FPD report from the first group (root group) + generateGroup(groups.root); var report = document.getElementById("fpd-report"); - if (!tabObj || !groups || !groups.root || !groups.all || !fpDb || !latestEvals) { - report.innerHTML = browser.i18n.getMessage("FPDReportMissingData"); - return; - } - - // parse latestEvals to create more useful representation for FPD report generation - var processedEvals = {}; - for (let item of latestEvals.evalStats) { - processedEvals[item.title] = processedEvals[item.title] || {}; - processedEvals[item.title].type = item.type; - let total = 0; - if (fpDb[item.title]) { - for (let stat of Object.values(fpDb[item.title])) { - total += stat.total; - } - } - processedEvals[item.title].total = total; - } - - // add page URL and FavIcon to header section of the report - if (tabObj) { - let urlObj = new URL(tabObj.url); - var url = urlObj.hostname + (urlObj.pathname.length > 1 ? urlObj.pathname : ""); - document.getElementById("report-url").innerHTML = url; - let img = document.getElementById("pageFavicon"); - img.src = tabObj.favIconUrl; - } - - var html = ""; - - // generate html code for evaluated group - let generateGroup = (group) => { - if (processedEvals[group]) { - if (groups.all[group].description) { - html += "<div id=\"" + group + "\" class=\"fpd-group access\">"; - html += "<h2>" + group + "</h2>"; - html += "<p>" + groups.all[group].description + "</p>"; - } - for (let [item, type] of Object.entries(groups.all[group].items)) { - if (type == "group") { - generateGroup(item); - } - else { - generateResource(item) - } - } - if (groups.all[group].description) { - html += "</div>"; - } - } - } - - // generate html code for evaluated resource (get,set,call) - let generateResource = (resource) => { - if (processedEvals[resource]) { - let accessRaw = processedEvals[resource].total; - let accessCount = accessRaw >= 1000 ? "1000+" : accessRaw; - html += `<h4 class="hidden ${accessRaw > 0 ? "access" : "no-access"}"><span class="dot">-</span> ` + - `${resource} (${exceptionWrappers.includes(resource) ? "n/a" : accessCount})</h4>`; - } - } - - // start generating FPD report from the first group (root group) - generateGroup(groups.root); - report.innerHTML += html; - - // process generated document - let groupElements = document.querySelectorAll(".fpd-group.access"); - for (let i = groupElements.length; i > 0; i--) { - // remove duplicit entries from groups - let duplicitArray = []; - let elements = groupElements[i-1].querySelectorAll(":scope > h4"); - elements.forEach((d) => { - if (duplicitArray.indexOf(d.innerHTML) > -1) { - d.remove(); - } - else { - duplicitArray.push(d.innerHTML); - } - }); - - // hide groups with no relevant entries - if (!document.querySelectorAll(`#${groupElements[i-1].id} > .access`).length) { - groupElements[i-1].classList.replace("access", "no-access"); - } - } - - // function that enables to show accessed resources of the group - let toggleResources = (event) => { - let parent = event.target.parentElement; - for (let i = 0; i < parent.children.length; i++) { - let child = parent.children[i]; - if (child.tagName == "H4") { - child.classList.toggle("hidden"); - } - } - } - - // make group name clickable only if it makes sense - groups with resources - let makeClickableTitles = () => { - for (let element of document.querySelectorAll(".fpd-group")) { - let button; - let haveChild = false; - - for (let i = 0; i < element.children.length; i++) { - let child = element.children[i]; - if (child.tagName == "H2") { - button = child; - } - if (child.tagName == "H4" && !child.classList.contains("no-access")) { - haveChild = true; - } - } - - if (button && haveChild) { - button.classList.add("clickable"); - button.addEventListener("click", toggleResources); - } - } - } - makeClickableTitles(); - - // show resources for every group in FPD report - let showAll = (event) => { - for (let element of document.querySelectorAll(".fpd-group > h4")) { - element.classList.remove("hidden"); - } - showBtn.classList.add("hidden"); - hideBtn.classList.remove("hidden"); - } - - // hide resources for every group in FPD report - let hideDetails = (event) => { - for (let element of document.querySelectorAll(".fpd-group > h4")) { - element.classList.add("hidden"); - } - showBtn.classList.remove("hidden"); - hideBtn.classList.add("hidden"); - } - - // show description/help for the report - let showDescription = () => { - for (let element of document.querySelectorAll(".description")) { - element.classList.toggle("hidden"); - } - } - - // show all groups/resources even if not accessed - let showNotAccessed = () => { - for (let element of document.querySelectorAll(".no-access")) { - element.classList.remove("no-access"); - } - makeClickableTitles(); - } - - // create on-site JSON representation of FPD evaluation data and download it - function exportReport(filename) { - let element = document.createElement("a"); - let obj = { - fpd_evaluation_statistics: latestEvals.evalStats, - fpd_access_logs: fpDb - } - element.setAttribute("href", "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj))); - element.setAttribute("download", filename); - element.style.display = "none"; - document.body.appendChild(element); - element.click(); - document.body.removeChild(element); - } - - document.getElementById("showBtn").addEventListener("click", showAll); - document.getElementById("hideBtn").addEventListener("click", hideDetails); - document.getElementById("exportBtn").addEventListener("click", exportReport.bind(null, `fpd_report_${url}.json`)) - document.getElementById("titletext").innerHTML += '<button id="help" class="help">?</button>'; - document.getElementById("help").addEventListener("click", showDescription); - document.getElementById("unhideAll").addEventListener("click", showNotAccessed); + report.innerHTML = html; + + // process generated document + let groupElements = document.querySelectorAll(".fpd-group.access"); + for (let i = groupElements.length; i > 0; i--) { + // remove duplicit entries from groups + let duplicitArray = []; + let elements = groupElements[i-1].querySelectorAll(":scope > section > div.details > h4"); + elements.forEach((d) => { + if (duplicitArray.indexOf(d.innerHTML) > -1) { + d.remove(); + } + else { + duplicitArray.push(d.innerHTML); + } + }); + + // hide groups with no relevant entries + if (!document.querySelectorAll(`#${groupElements[i-1].id} > section > .access`).length) { + groupElements[i-1].classList.replace("access", "no-access"); + } + } + + // function that enables to show accessed resources of the group + function toggleResources(event) { + let parent = event.target.parentElement; + for (let i = 0; i < parent.children.length; i++) { + let child = parent.children[i]; + if (child.tagName == "SECTION") { + child.classList.toggle("hidden"); + } + } + } + + // make group name clickable only if it makes sense - groups with resources + function makeGroupExpansionsClickable() { + for (let element of document.querySelectorAll(".fpd-group")) { + let button; + + for (let i = 0; i < element.children.length; i++) { + let child = element.children[i]; + if (child.tagName == "BUTTON") { + button = child; + } + } + + if (button) { + button.classList.add("clickable"); + button.addEventListener("click", toggleResources); + } + } + } + makeGroupExpansionsClickable(); + + // show resources for every group in FPD report + let showAll = (event) => { + for (let element of document.querySelectorAll(".fpd-group div.details")) { + element.classList.remove("hidden"); + } + showBtn.classList.add("hidden"); + hideBtn.classList.remove("hidden"); + } + + // hide resources for every group in FPD report + let hideDetails = (event) => { + for (let element of document.querySelectorAll(".fpd-group div.details")) { + element.classList.add("hidden"); + } + showBtn.classList.remove("hidden"); + hideBtn.classList.add("hidden"); + } + hideDetails(); + + // refresh data in the report + function refreshReport() { + browser.runtime.sendMessage({ + purpose: "fpd-get-report-data", + tabId: tabId + }).then((result) => { + createReport(result); + showAll(); + }); + browser.runtime.sendMessage({purpose: "fpd-track-callers-stop"}); + document.getElementById("updateReportBtn").classList.remove("hidden"); + document.getElementById("forgetCurrentBtn").classList.remove("hidden"); + let trackCallersBtn = document.getElementById("trackCallersBtn"); + trackCallersBtn.innerText = browser.i18n.getMessage("FPDReportTrackCallersRestart"); + trackCallersBtn.classList.remove("hidden"); + } + + // Reload the report with data on the identity of the calling scripts + function trackCallers() { + tabId = new URLSearchParams(window.location.search).get("id"); + function onReloaded() { + setTimeout(refreshReport, 5000); + report.innerHTML = browser.i18n.getMessage("FPDReportTrackCallersWaiting"); + document.getElementById("trackCallersBtn").classList.add("hidden"); + document.getElementById("updateReportBtn").classList.add("hidden"); + document.getElementById("forgetCurrentBtn").classList.add("hidden"); + } + function onError(error) { + document.getElementById("fpdError").innerHTML = browser.i18n.getMessage("FPDReportTrackCallersFailed", error); + browser.runtime.sendMessage({purpose: "fpd-track-callers-stop"}); + } + browser.runtime.sendMessage({ + purpose: "fpd-track-callers", + tabId: tabId + }).then(onReloaded, onError); + } + + function updateReport() { + } + + // show all groups/resources even if not accessed + let showNotAccessed = () => { + for (let element of document.querySelectorAll(".no-access")) { + element.classList.remove("no-access"); + } + makeGroupExpansionsClickable(); + } + + function forgetTraces() { + for (resource of Object.values(fpDb)) { + for (type of Object.values(resource)) { + for (trace of Object.keys(type.callers)) { + hiddenTraces[trace] = true; + } + } + } + createReport(data); + } + + // create on-site JSON representation of FPD evaluation data and download it + function exportReport(filename) { + let element = document.createElement("a"); + let obj = { + fpd_evaluation_statistics: latestEvals.evalStats, + fpd_access_logs: fpDb + } + element.setAttribute("href", "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(obj))); + element.setAttribute("download", filename); + element.style.display = "none"; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); + } + + document.getElementById("showBtn").onclick = showAll; + document.getElementById("hideBtn").onclick = hideDetails; + document.getElementById("exportBtn").onclick = exportReport.bind(null, `fpd_report_${url}.json`); + document.getElementById("trackCallersBtn").onclick = trackCallers; + document.getElementById("forgetCurrentBtn").onclick = forgetTraces; + document.getElementById("updateReportBtn").onclick = refreshReport; + document.getElementById("unhideAll").onclick = showNotAccessed; +} + +// show description/help for the report +let showDescription = () => { + for (let element of document.querySelectorAll(".description")) { + element.classList.toggle("hidden"); + } } + +window.addEventListener("DOMContentLoaded", function() { + document.getElementById("titletext").innerHTML += '<button id="help" class="help">?</button>'; + document.getElementById("help").addEventListener("click", showDescription); +}); |