ui: Add Privacy Panel

This commit is contained in:
Daniel
2023-10-23 22:16:02 +02:00
parent 6c8724f7ac
commit 1938eb100d
8 changed files with 430 additions and 113 deletions
+115 -33
View File
@@ -1,5 +1,8 @@
import App from "../../App";
import * as EVENTS from "./events";
import { analyzeService } from "./security";
import * as tiles from "./tiles"
export default class Settings {
constructor() {
@@ -10,69 +13,148 @@ export default class Settings {
init() {
this.checkLocalStorage()
this.initSecurityPanel()
this.initSettings()
this.initPager()
}
let darkMode = this.addOnOffTile(
initSettings() {
let darkMode = tiles.addOnOffTile(this.config,
"dark_mode", "Dark mode",
"Make the colors more appropriate for low-light environments",
"dark_mode", EVENTS.onThemeChange
)
document.getElementById("theme-switcher").addEventListener("click", () => {
darkMode.click()
})
this.addOnOffTile(
tiles.addOnOffTile(this.config,
"open_in_new", "Open in new tab",
"Clicking on application will open it in a new browser tab",
"open_new_tab", EVENTS.onNewTabChange
)
this.addOnOffTile(
tiles.addOnOffTile(this.config,
"blur_on", "Enable blur",
"Improves UI sweetness but may have a huge impact on performance",
"blur", EVENTS.onBlurChange
)
this.addOnOffTile(
tiles.addOnOffTile(this.config,
"animation", "Animations",
"Show nice and fancy page transitions for improved experience",
"animations", EVENTS.onAnimationChange
)
document.getElementById("theme-switcher").addEventListener("click", () => {
darkMode.click()
})
}
addOnOffTile(icon, name, desc, key, func) {
let item = document.createElement("div")
item.classList.add("setting")
item.innerHTML = `
<i>${icon}</i>
<div class="text">
<div class="name">${name}</div>
<div class="desc">${desc}</div>
</div>
<div class="switch"></div>`
initPager() {
let switcher = document.getElementById("switch")
let buttons = switcher.children
let subsettings = document.getElementById("subsettings")
let handleState = () => {
let c = item.classList
if (this.config.get(key)) c.add("checked")
else c.remove("checked")
for (let i = 0; i < buttons.length; i++) {
let button = buttons[i]
subsettings.children[i].setAttribute("style", `--n: ${i}`)
button.addEventListener("click", () => {
let calculatedHeight = subsettings.children[i].offsetHeight
subsettings.style.height = `${calculatedHeight}px`
subsettings.parentNode.setAttribute("style", `--id: ${i}`)
switcher.setAttribute("style", `--switches: ${buttons.length}`)
})
}
let write = () => {
let target_value = !this.config.get(key)
this.config.set(key, target_value)
buttons[0].click()
}
initSecurityPanel() {
let stats = {
total: 0,
secure: 0,
thirdParties: 0
}
for (let service of this.config.getServices()) {
let analysis = analyzeService(service.href)
stats.total++
stats.secure += analysis.isSecure
stats.thirdParties += analysis.isThirdParty
}
let f = () => {func(this.config)}
item.addEventListener("click", write)
item.addEventListener("click", handleState)
if (func) item.addEventListener("click", f)
let secure_pp = 100 * stats.secure / stats.total
let indepencence_pp = 100 * (stats.total - stats.thirdParties) / stats.total
let privacy_score = secure_pp * 0.5 + indepencence_pp * 0.5
handleState()
if (func && this.config.changed(key)) f()
document.getElementById("settings").appendChild(item)
return item
let privacy_report;
if (privacy_score == 100) {
privacy_report = "Data is sent securely and no third-party services are involved."
}
else if (privacy_score >= 85) {
privacy_report = "Great privacy overall, but at some point it could be better."
}
else if (privacy_score >= 40) {
privacy_report = "Decent privacy. You should pay attention what you're doing."
}
else privacy_report = "Transferring data is insecure and vulnerable to various threats."
document.getElementById("report-score").innerText = Math.round(privacy_score)
document.getElementById("report").innerText = privacy_report
const phrase = " of the listed services are using secure connections"
tiles.privacyBox(secure_pp, "icon-https", [
{
"from": 0,
"name": "No encryption",
"desc": "None" + phrase
},
{
"from": 0.1,
"name": "Poor encryption",
"desc": "Only some" + phrase
},
{
"from": 60,
"name": "Fair encryption",
"desc": "Most" + phrase
},
{
"from": 90,
"name": "Good encryption",
"desc": "Nearly all" + phrase
},
{
"from": 100,
"name": "Full encryption",
"desc": "All" + phrase
}
])
tiles.privacyBox(indepencence_pp, "icon-rocket", [
{
"from": 0,
"name": "Not independent",
"desc": "This server lists a lot of 3rd party services"
},
{
"from": 40,
"name": "Partially independent",
"desc": "This server lists many 3rd party services"
},
{
"from": 65,
"name": "Mostly independent",
"desc": "This server still lists some 3rd party services"
},
{
"from": 100,
"name": "Fully independent",
"desc": "This server is free of 3rd party services"
}
])
}
checkLocalStorage() {
let warn = document.getElementById("no-cookies").classList
if (this.config.storageAvailable) warn.add("hidden")
}
}
}
+32
View File
@@ -0,0 +1,32 @@
export function analyzeService(url) {
let isSiteSecure = (
window.location.protocol == "https:" ||
window.location.hostname == "localhost"
)
let domain_base = window.location.hostname
let isSecure = false
let isThirdParty = true
if (url.startsWith("https://")) {
isSecure = true
}
else if (!["http", "https"].includes(url.split("://")[0])) {
isSecure = isSiteSecure
}
if (isThirdParty) {
let domain = url.split("://")
if (domain.length > 1) {
domain = domain[1]
domain = domain.split("/")[0]
domain = domain.split(":")[0]
isThirdParty = !domain.includes(domain_base)
}
else {
isThirdParty = false
}
}
return {isSecure, isThirdParty}
}
+59
View File
@@ -0,0 +1,59 @@
export function addOnOffTile(conf, icon, name, desc, key, func) {
let item = document.createElement("div")
item.classList.add("setting")
item.innerHTML = `
<i>${icon}</i>
<div class="text">
<div class="name">${name}</div>
<div class="desc">${desc}</div>
</div>
<div class="switch"></div>`
let handleState = () => {
let c = item.classList
if (conf.get(key)) c.add("checked")
else c.remove("checked")
}
let write = () => {
let target_value = !conf.get(key)
conf.set(key, target_value)
}
let f = () => {func(conf)}
item.addEventListener("click", write)
item.addEventListener("click", handleState)
if (func) item.addEventListener("click", f)
handleState()
if (func && conf.changed(key)) f()
document.getElementById("settings").appendChild(item)
return item
}
export function privacyBox(privacyScore, icon_class, levels) {
let name, desc
levels = levels.reverse()
for (let i in levels) {
let item = levels[i]
if (item.from <= privacyScore) {
name = levels[i].name
desc = levels[i].desc
break
}
}
let item = document.createElement("div")
item.innerHTML = `<i class="${icon_class}"></i>
<div>
<div class="title">${name}</div>
<div class="subtitle">${desc}</div>
</div>`
if (privacyScore < 30) item.classList.add("error")
else if (privacyScore < 90) item.classList.add("warn")
else if (privacyScore < 100) item.classList.add("prewarn")
document.getElementById("report-boxes").appendChild(item)
return item
}