mirror of
https://github.com/Synzvato/decentraleyes.git
synced 2026-02-23 10:15:31 -05:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d6a7b68ad | ||
|
|
74e6c6fa98 | ||
|
|
440def810d | ||
|
|
cd0c06c5bc | ||
|
|
be533e8953 | ||
|
|
7ec143efbf | ||
|
|
bce5e9f58e | ||
|
|
3b941ed077 | ||
|
|
449bf8c064 | ||
|
|
861ba95dee | ||
|
|
b3931febc2 | ||
|
|
391eb4e6d2 | ||
|
|
91f32afa59 | ||
|
|
7883d5f2c7 | ||
|
|
62bd811bbf |
@@ -17,7 +17,8 @@
|
||||
"Setting": true,
|
||||
"stateManager": true,
|
||||
"WebRequest": true,
|
||||
"Whitelist": true
|
||||
"Whitelist": true,
|
||||
"wrappers": true
|
||||
},
|
||||
"overrides": {
|
||||
"files": [
|
||||
|
||||
@@ -44,15 +44,15 @@
|
||||
"description": "Disable prefetch title."
|
||||
},
|
||||
"disablePrefetchDescription": {
|
||||
"message": "Prevent disallowed requests from leaking out to delivery networks.",
|
||||
"message": "配信ネットワークに許可されていないリクエストの漏れから予防する。",
|
||||
"description": "Disable prefetch description."
|
||||
},
|
||||
"stripMetadataTitle": {
|
||||
"message": "Strip metadata from allowed requests",
|
||||
"message": "許可されていたるリクエストからメタデータを取り除く",
|
||||
"description": "Strip metadata title."
|
||||
},
|
||||
"stripMetadataDescription": {
|
||||
"message": "Erase sensitive data from allowed CDN requests for improved privacy.",
|
||||
"message": "プライバシー向上のために許可されたCDNリクエストから機密データを消去する。",
|
||||
"description": "Strip metadata description."
|
||||
},
|
||||
"whitelistedDomainsTitle": {
|
||||
|
||||
70
_locales/ko/messages.json
Normal file
70
_locales/ko/messages.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"extensionDescription": {
|
||||
"message": "\"무료\"라는 미끼로 당신을 추적하는 대규모 CDN을 사용하지 않음으로써 개인 정보를 지킵니다.",
|
||||
"description": "Extension description."
|
||||
},
|
||||
"disableProtectionTitle": {
|
||||
"message": "이 사이트의 보호 비활성화",
|
||||
"description": "Disable protection title."
|
||||
},
|
||||
"enableProtectionTitle": {
|
||||
"message": "보호 활성화",
|
||||
"description": "Enable protection title."
|
||||
},
|
||||
"amountInjectedTitle": {
|
||||
"message": "로컬 리소스로 대체한 요청 횟수",
|
||||
"description": "Amount injected title."
|
||||
},
|
||||
"amountInjectedDescription": {
|
||||
"message": "Decentraleyes를 설치한 뒤, CDN에서 다운로드 하는 대신 로컬 자원을 사용한 횟수입니다.",
|
||||
"description": "Amount injected description."
|
||||
},
|
||||
"optionsTitle": {
|
||||
"message": "옵션",
|
||||
"description": "Options title."
|
||||
},
|
||||
"showIconBadgeTitle": {
|
||||
"message": "차단한 횟수를 아이콘에 표시",
|
||||
"description": "Show icon badge title."
|
||||
},
|
||||
"showIconBadgeDescription": {
|
||||
"message": "로컬 리소스로 대체한 요청 수를 확장 기능 아이콘에 표시합니다.",
|
||||
"description": "Show icon badge description."
|
||||
},
|
||||
"blockMissingTitle": {
|
||||
"message": "존재하지 않는 리소스에 대한 요청을 차단",
|
||||
"description": "Block requests for missing resources title."
|
||||
},
|
||||
"blockMissingDescription": {
|
||||
"message": "리소스를 로컬에서 가져올 수 없다면 리소스 요청을 취소합니다.",
|
||||
"description": "Block requests for missing resources description."
|
||||
},
|
||||
"disablePrefetchTitle": {
|
||||
"message": "링크 프리페치를 비활성화",
|
||||
"description": "Disable prefetch title."
|
||||
},
|
||||
"disablePrefetchDescription": {
|
||||
"message": "허가되지 않은 요청이 전달 네트워크(DN)로 전송되는 것을 차단합니다.",
|
||||
"description": "Disable prefetch description."
|
||||
},
|
||||
"stripMetadataTitle": {
|
||||
"message": "허용된 요청에서 메타데이터를 제거",
|
||||
"description": "Strip metadata title."
|
||||
},
|
||||
"stripMetadataDescription": {
|
||||
"message": "프라이버시 보호를 위해 허가된 CDN 요청에서 민감한 데이터를 지웁니다.",
|
||||
"description": "Strip metadata description."
|
||||
},
|
||||
"whitelistedDomainsTitle": {
|
||||
"message": "Decentraleyes를 사용하지 않을 도메인",
|
||||
"description": "Whitelisted domains title."
|
||||
},
|
||||
"whitelistedDomainsDescription": {
|
||||
"message": "화이트 리스트에 등록할 도메인을 입력하세요. 여러 개를 입력할 경우 세미콜론 (;) 을 이용해 구분합니다.",
|
||||
"description": "Whitelisted domains description."
|
||||
},
|
||||
"advancedLabel": {
|
||||
"message": "고급",
|
||||
"description": "Advanced label."
|
||||
}
|
||||
}
|
||||
@@ -1,70 +1,70 @@
|
||||
{
|
||||
"extensionDescription":{
|
||||
"message":"Beschermt tegen tracking via het \"gratis\", gecentraliseerd, verzorgen van content.",
|
||||
"description":"Extension description."
|
||||
"extensionDescription": {
|
||||
"message": "Beschermt tegen tracking via het \"gratis\", gecentraliseerd, verzorgen van content.",
|
||||
"description": "Extension description."
|
||||
},
|
||||
"disableProtectionTitle":{
|
||||
"message":"Bescherming voor deze website uitschakelen",
|
||||
"description":"Disable protection title."
|
||||
"disableProtectionTitle": {
|
||||
"message": "Bescherming voor deze website uitschakelen",
|
||||
"description": "Disable protection title."
|
||||
},
|
||||
"enableProtectionTitle":{
|
||||
"message":"Bescherming inschakelen",
|
||||
"description":"Enable protection title."
|
||||
"enableProtectionTitle": {
|
||||
"message": "Bescherming inschakelen",
|
||||
"description": "Enable protection title."
|
||||
},
|
||||
"amountInjectedTitle":{
|
||||
"message":"Teller voor lokaal geïnjecteerde bestanden",
|
||||
"description":"Amount injected title."
|
||||
"amountInjectedTitle": {
|
||||
"message": "Teller voor lokaal geïnjecteerde bestanden",
|
||||
"description": "Amount injected title."
|
||||
},
|
||||
"amountInjectedDescription":{
|
||||
"message":"Aantal lokale Content Delivery Network-bestandsinjecties sinds installatie.",
|
||||
"description":"Amount injected description."
|
||||
"amountInjectedDescription": {
|
||||
"message": "Aantal lokale Content Delivery Network-bestandsinjecties sinds installatie.",
|
||||
"description": "Amount injected description."
|
||||
},
|
||||
"optionsTitle":{
|
||||
"message":"Opties",
|
||||
"description":"Options title."
|
||||
"optionsTitle": {
|
||||
"message": "Opties",
|
||||
"description": "Options title."
|
||||
},
|
||||
"showIconBadgeTitle":{
|
||||
"message":"Getelde injecties op icoon weergeven",
|
||||
"description":"Show icon badge title."
|
||||
"showIconBadgeTitle": {
|
||||
"message": "Getelde injecties op icoon weergeven",
|
||||
"description": "Show icon badge title."
|
||||
},
|
||||
"showIconBadgeDescription":{
|
||||
"message":"Toon het aantal geïnjecteerde bestanden op het extensie-icoon.",
|
||||
"description":"Show icon badge description."
|
||||
"showIconBadgeDescription": {
|
||||
"message": "Toon het aantal geïnjecteerde bestanden op het extensie-icoon.",
|
||||
"description": "Show icon badge description."
|
||||
},
|
||||
"blockMissingTitle":{
|
||||
"message":"Verzoeken voor ontbrekende items blokkeren",
|
||||
"description":"Block requests for missing resources title."
|
||||
"blockMissingTitle": {
|
||||
"message": "Verzoeken voor ontbrekende items blokkeren",
|
||||
"description": "Block requests for missing resources title."
|
||||
},
|
||||
"blockMissingDescription":{
|
||||
"message":"Annuleer een onderschept verzoek wanneer het bestand niet lokaal beschikbaar is.",
|
||||
"description":"Block requests for missing resources description."
|
||||
"blockMissingDescription": {
|
||||
"message": "Annuleer een onderschept verzoek wanneer het bestand niet lokaal beschikbaar is.",
|
||||
"description": "Block requests for missing resources description."
|
||||
},
|
||||
"disablePrefetchTitle":{
|
||||
"message":"Link prefetching uitschakelen",
|
||||
"description":"Disable prefetch title."
|
||||
"disablePrefetchTitle": {
|
||||
"message": "Link prefetching uitschakelen",
|
||||
"description": "Disable prefetch title."
|
||||
},
|
||||
"disablePrefetchDescription":{
|
||||
"message":"Voorkom dat geweigerde verzoeken naar afleveringsnetwerken uitlekken.",
|
||||
"description":"Disable prefetch description."
|
||||
"disablePrefetchDescription": {
|
||||
"message": "Voorkom dat geweigerde verzoeken naar afleveringsnetwerken uitlekken.",
|
||||
"description": "Disable prefetch description."
|
||||
},
|
||||
"stripMetadataTitle":{
|
||||
"message":"Metadata uit toegestane verzoeken verwijderen",
|
||||
"description":"Strip metadata title."
|
||||
"stripMetadataTitle": {
|
||||
"message": "Metadata uit toegestane verzoeken verwijderen",
|
||||
"description": "Strip metadata title."
|
||||
},
|
||||
"stripMetadataDescription":{
|
||||
"message":"Wis gevoelige gegevens uit toegestane CDN-verzoeken voor verbeterde privacy.",
|
||||
"description":"Strip metadata description."
|
||||
"stripMetadataDescription": {
|
||||
"message": "Wis gevoelige gegevens uit toegestane CDN-verzoeken voor verbeterde privacy.",
|
||||
"description": "Strip metadata description."
|
||||
},
|
||||
"whitelistedDomainsTitle":{
|
||||
"message":"Sluit domeinen uit van inspecties",
|
||||
"description":"Whitelisted domains title."
|
||||
"whitelistedDomainsTitle": {
|
||||
"message": "Sluit domeinen uit van inspecties",
|
||||
"description": "Whitelisted domains title."
|
||||
},
|
||||
"whitelistedDomainsDescription":{
|
||||
"message":"Voer de te negeren domeinen in. Scheid de waarden met puntkomma's (;).",
|
||||
"description":"Whitelisted domains description."
|
||||
"whitelistedDomainsDescription": {
|
||||
"message": "Voer de te negeren domeinen in. Scheid de waarden met puntkomma's (;).",
|
||||
"description": "Whitelisted domains description."
|
||||
},
|
||||
"advancedLabel":{
|
||||
"message":"Geavanceerd",
|
||||
"description":"Advanced label."
|
||||
"advancedLabel": {
|
||||
"message": "Geavanceerd",
|
||||
"description": "Advanced label."
|
||||
}
|
||||
}
|
||||
@@ -1,70 +1,70 @@
|
||||
{
|
||||
"extensionDescription":{
|
||||
"message":"保護您不受「免費」、中心化的內容傳遞網路(CDN)的追蹤。",
|
||||
"description":"Extension description."
|
||||
"extensionDescription": {
|
||||
"message": "保護您不受「免費」、中心化的內容傳遞網路(CDN)的追蹤。",
|
||||
"description": "Extension description."
|
||||
},
|
||||
"disableProtectionTitle":{
|
||||
"message":"為此網站停用保護",
|
||||
"description":"Disable protection title."
|
||||
"disableProtectionTitle": {
|
||||
"message": "為此網站停用保護",
|
||||
"description": "Disable protection title."
|
||||
},
|
||||
"enableProtectionTitle":{
|
||||
"message":"啟用保護",
|
||||
"description":"Enable protection title."
|
||||
"enableProtectionTitle": {
|
||||
"message": "啟用保護",
|
||||
"description": "Enable protection title."
|
||||
},
|
||||
"amountInjectedTitle":{
|
||||
"message":"由本機提供的資源計數器",
|
||||
"description":"Amount injected title."
|
||||
"amountInjectedTitle": {
|
||||
"message": "由本機提供的資源計數器",
|
||||
"description": "Amount injected title."
|
||||
},
|
||||
"amountInjectedDescription":{
|
||||
"message":"安裝以來,由本機檔案所取代的 CDN 資源數量。",
|
||||
"description":"Amount injected description."
|
||||
"amountInjectedDescription": {
|
||||
"message": "安裝以來,由本機檔案所取代的 CDN 資源數量。",
|
||||
"description": "Amount injected description."
|
||||
},
|
||||
"optionsTitle":{
|
||||
"message":"選項",
|
||||
"description":"Options title."
|
||||
"optionsTitle": {
|
||||
"message": "選項",
|
||||
"description": "Options title."
|
||||
},
|
||||
"showIconBadgeTitle":{
|
||||
"message":"在圖示上顯示被取代的資源數量",
|
||||
"description":"Show icon badge title."
|
||||
"showIconBadgeTitle": {
|
||||
"message": "在圖示上顯示被取代的資源數量",
|
||||
"description": "Show icon badge title."
|
||||
},
|
||||
"showIconBadgeDescription":{
|
||||
"message":"在擴充套件圖示上,顯示被取代的資源數量。",
|
||||
"description":"Show icon badge description."
|
||||
"showIconBadgeDescription": {
|
||||
"message": "在擴充套件圖示上,顯示被取代的資源數量。",
|
||||
"description": "Show icon badge description."
|
||||
},
|
||||
"blockMissingTitle":{
|
||||
"message":"封鎖缺少資源時的連線請求",
|
||||
"description":"Block requests for missing resources title."
|
||||
"blockMissingTitle": {
|
||||
"message": "封鎖缺少資源時的連線請求",
|
||||
"description": "Block requests for missing resources title."
|
||||
},
|
||||
"blockMissingDescription":{
|
||||
"message":"若本機沒有所請求的資源,就取消該請求。",
|
||||
"description":"Block requests for missing resources description."
|
||||
"blockMissingDescription": {
|
||||
"message": "若本機沒有所請求的資源,就取消該請求。",
|
||||
"description": "Block requests for missing resources description."
|
||||
},
|
||||
"disablePrefetchTitle":{
|
||||
"message":"停用連結預讀功能",
|
||||
"description":"Disable prefetch title."
|
||||
"disablePrefetchTitle": {
|
||||
"message": "停用連結預讀功能",
|
||||
"description": "Disable prefetch title."
|
||||
},
|
||||
"disablePrefetchDescription":{
|
||||
"message":"防止發出不被允許的請求到 CDN 網路。",
|
||||
"description":"Disable prefetch description."
|
||||
"disablePrefetchDescription": {
|
||||
"message": "防止發出不被允許的請求到 CDN 網路。",
|
||||
"description": "Disable prefetch description."
|
||||
},
|
||||
"stripMetadataTitle":{
|
||||
"message":"移除放行請求當中的後設資料",
|
||||
"description":"Strip metadata title."
|
||||
"stripMetadataTitle": {
|
||||
"message": "移除放行請求當中的後設資料",
|
||||
"description": "Strip metadata title."
|
||||
},
|
||||
"stripMetadataDescription":{
|
||||
"message":"清除放行的 CDN 請求當中的敏感資料,以保護隱私權。",
|
||||
"description":"Strip metadata description."
|
||||
"stripMetadataDescription": {
|
||||
"message": "清除放行的 CDN 請求當中的敏感資料,以保護隱私權。",
|
||||
"description": "Strip metadata description."
|
||||
},
|
||||
"whitelistedDomainsTitle":{
|
||||
"message":"要排除檢查的網域",
|
||||
"description":"Whitelisted domains title."
|
||||
"whitelistedDomainsTitle": {
|
||||
"message": "要排除檢查的網域",
|
||||
"description": "Whitelisted domains title."
|
||||
},
|
||||
"whitelistedDomainsDescription":{
|
||||
"message":"輸入網域即可將其加入白名單。使用分號(;)分隔多個網域。",
|
||||
"description":"Whitelisted domains description."
|
||||
"whitelistedDomainsDescription": {
|
||||
"message": "輸入網域即可將其加入白名單。使用分號(;)分隔多個網域。",
|
||||
"description": "Whitelisted domains description."
|
||||
},
|
||||
"advancedLabel":{
|
||||
"message":"進階",
|
||||
"description":"Advanced label."
|
||||
"advancedLabel": {
|
||||
"message": "進階",
|
||||
"description": "Advanced label."
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,10 @@ const Address = {
|
||||
'ANY': '*://*/*',
|
||||
'ANY_PATH': '/*',
|
||||
'ANY_PROTOCOL': '*://',
|
||||
'DOMAIN_EXPRESSION': /:\/\/(.[^/]+)(.*)/,
|
||||
'EXAMPLE': 'example.org',
|
||||
'HTTP_EXPRESSION': /^http?:\/\//,
|
||||
'HTTPS': 'https://',
|
||||
'WWW_PREFIX': 'www.',
|
||||
'WWW_PREFIX_LENGTH': 4
|
||||
'HTTP': 'http:',
|
||||
'HTTPS': 'https:',
|
||||
'WWW_PREFIX': 'www.'
|
||||
};
|
||||
|
||||
const Resource = {
|
||||
|
||||
@@ -36,19 +36,21 @@ interceptor.handleRequest = function (requestDetails, tabIdentifier, tab) {
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
tabDomain = tab.url.match(Address.DOMAIN_EXPRESSION)[1];
|
||||
tabDomain = requestAnalyzer._normalizeDomain(tabDomain);
|
||||
} catch (exception) {
|
||||
tabDomain = helpers.extractDomainFromUrl(tab.url, true);
|
||||
|
||||
if (tabDomain === null) {
|
||||
tabDomain = Address.EXAMPLE;
|
||||
}
|
||||
|
||||
// Temporary list of undetectable tainted domains.
|
||||
let undetectableTaintedDomains = {
|
||||
'10fastfingers.com': true,
|
||||
'cdnjs.com': true,
|
||||
'dropbox.com': true,
|
||||
'glowing-bear.org': true,
|
||||
'minigames.mail.ru': true,
|
||||
'miniquadtestbench.com': true,
|
||||
'qwertee.com': true,
|
||||
'report-uri.io': true,
|
||||
'scotthelme.co.uk': true,
|
||||
'securityheaders.io': true,
|
||||
@@ -98,12 +100,15 @@ interceptor._handleMissingCandidate = function (requestUrl) {
|
||||
};
|
||||
}
|
||||
|
||||
if (requestUrl.match(Address.HTTP_EXPRESSION)) {
|
||||
let requestUrlSegments = new URL(requestUrl);
|
||||
|
||||
let secureRequestUrl = requestUrl.replace(Address.HTTP_EXPRESSION, Address.HTTPS);
|
||||
if (requestUrlSegments.protocol === Address.HTTP) {
|
||||
|
||||
requestUrlSegments.protocol = Address.HTTPS;
|
||||
requestUrl = requestUrlSegments.toString();
|
||||
|
||||
return {
|
||||
'redirectUrl': secureRequestUrl
|
||||
'redirectUrl': requestUrl
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
20
core/main.js
20
core/main.js
@@ -90,24 +90,6 @@ main._showReleaseNotes = function (details) {
|
||||
chrome.runtime.onInstalled.addListener(main._showReleaseNotes);
|
||||
main._initializeOptions();
|
||||
|
||||
chrome.runtime.getPlatformInfo(function (information) {
|
||||
main.operatingSystem = information.os;
|
||||
});
|
||||
|
||||
if (typeof chrome.browserAction.setBadgeBackgroundColor !== 'function') {
|
||||
|
||||
chrome.browserAction.setBadgeBackgroundColor = function () {};
|
||||
chrome.browserAction.setBadgeText = function () {};
|
||||
|
||||
chrome.browserAction.onClicked.addListener(function () {
|
||||
|
||||
chrome.tabs.create({
|
||||
'url': chrome.extension.getURL('pages/popup/popup.html'),
|
||||
'active': false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
chrome.browserAction.setBadgeBackgroundColor({
|
||||
wrappers.setBadgeBackgroundColor({
|
||||
'color': [74, 130, 108, 255]
|
||||
});
|
||||
|
||||
@@ -25,15 +25,17 @@ var requestAnalyzer = {};
|
||||
|
||||
requestAnalyzer.isValidCandidate = function (requestDetails, tabDetails) {
|
||||
|
||||
let initiatorHost;
|
||||
let initiatorDomain, isWhitelisted;
|
||||
|
||||
try {
|
||||
initiatorHost = tabDetails.url.match(Address.DOMAIN_EXPRESSION)[1];
|
||||
} catch (exception) {
|
||||
initiatorHost = Address.EXAMPLE;
|
||||
initiatorDomain = helpers.extractDomainFromUrl(tabDetails.url, true);
|
||||
|
||||
if (initiatorDomain === null) {
|
||||
initiatorDomain = Address.EXAMPLE;
|
||||
}
|
||||
|
||||
if (initiatorHost && requestAnalyzer.whitelistedDomains[requestAnalyzer._normalizeDomain(initiatorHost)]) {
|
||||
isWhitelisted = requestAnalyzer.whitelistedDomains[initiatorDomain];
|
||||
|
||||
if (isWhitelisted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -43,10 +45,12 @@ requestAnalyzer.isValidCandidate = function (requestDetails, tabDetails) {
|
||||
|
||||
requestAnalyzer.getLocalTarget = function (requestDetails) {
|
||||
|
||||
let destinationHost, destinationPath, hostMappings, basePath, resourceMappings;
|
||||
let destinationUrl, destinationHost, destinationPath, hostMappings, basePath, resourceMappings;
|
||||
|
||||
destinationHost = requestDetails.url.match(Address.DOMAIN_EXPRESSION)[1];
|
||||
destinationPath = requestDetails.url.match(Address.DOMAIN_EXPRESSION)[2];
|
||||
destinationUrl = new URL(requestDetails.url);
|
||||
|
||||
destinationHost = destinationUrl.host;
|
||||
destinationPath = destinationUrl.pathname;
|
||||
|
||||
// Use the proper mappings for the targeted host.
|
||||
hostMappings = mappings[destinationHost];
|
||||
@@ -122,17 +126,6 @@ requestAnalyzer._applyWhitelistedDomains = function () {
|
||||
});
|
||||
};
|
||||
|
||||
requestAnalyzer._normalizeDomain = function (domain) {
|
||||
|
||||
domain = domain.toLowerCase().trim();
|
||||
|
||||
if (domain.startsWith(Address.WWW_PREFIX)) {
|
||||
domain = domain.slice(Address.WWW_PREFIX_LENGTH);
|
||||
}
|
||||
|
||||
return domain;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializations
|
||||
*/
|
||||
|
||||
@@ -37,14 +37,14 @@ stateManager.registerInjection = function (tabIdentifier, injection) {
|
||||
|
||||
if (injectionCount > 0) {
|
||||
|
||||
chrome.browserAction.setBadgeText({
|
||||
wrappers.setBadgeText({
|
||||
'tabId': tabIdentifier,
|
||||
'text': injectionCount.toString()
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
chrome.browserAction.setBadgeText({
|
||||
wrappers.setBadgeText({
|
||||
'tabId': tabIdentifier,
|
||||
'text': ''
|
||||
});
|
||||
@@ -114,12 +114,8 @@ stateManager._createTab = function (tab) {
|
||||
|
||||
chrome.webRequest.onBeforeRequest.addListener(function (requestDetails) {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
browser.tabs.get(tabIdentifier).then(function (tab) {
|
||||
resolve(interceptor.handleRequest(requestDetails, tabIdentifier, tab));
|
||||
});
|
||||
});
|
||||
let tab = stateManager.tabs[tabIdentifier].details || {};
|
||||
return interceptor.handleRequest(requestDetails, tabIdentifier, tab);
|
||||
|
||||
}, requestFilters, [WebRequest.BLOCKING]);
|
||||
};
|
||||
@@ -141,7 +137,7 @@ stateManager._updateTab = function (details) {
|
||||
|
||||
if (stateManager.showIconBadge === true) {
|
||||
|
||||
chrome.browserAction.setBadgeText({
|
||||
wrappers.setBadgeText({
|
||||
'tabId': tabIdentifier,
|
||||
'text': ''
|
||||
});
|
||||
@@ -203,7 +199,7 @@ stateManager._handleStorageChanged = function (changes) {
|
||||
|
||||
stateManager._removeIconBadgeFromTab = function (tab) {
|
||||
|
||||
chrome.browserAction.setBadgeText({
|
||||
wrappers.setBadgeText({
|
||||
'tabId': tab.id,
|
||||
'text': ''
|
||||
});
|
||||
@@ -238,6 +234,17 @@ chrome.storage.local.get('showIconBadge', function (items) {
|
||||
chrome.tabs.onCreated.addListener(stateManager._createTab);
|
||||
chrome.tabs.onRemoved.addListener(stateManager._removeTab);
|
||||
|
||||
chrome.webRequest.onBeforeRequest.addListener(function (requestDetails) {
|
||||
|
||||
if (requestDetails.tabId !== -1) {
|
||||
|
||||
stateManager.tabs[requestDetails.tabId].details = {
|
||||
'url': requestDetails.url
|
||||
};
|
||||
}
|
||||
|
||||
}, {'types': ['main_frame'], 'urls': [Address.ANY]});
|
||||
|
||||
chrome.webNavigation.onCommitted.addListener(stateManager._updateTab, {
|
||||
'url': [{'urlContains': ':'}]
|
||||
});
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"is": "is"
|
||||
"it": "it"
|
||||
"ja": "ja"
|
||||
"ko": "ko"
|
||||
"nl": "nl"
|
||||
"pl": "pl"
|
||||
"ro": "ro"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Decentraleyes",
|
||||
"version": "2.0.1",
|
||||
"version": "2.0.2",
|
||||
|
||||
"author": "Thomas Rientjes",
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
"38": "icons/action/icon38.png",
|
||||
"64": "icons/action/icon64.png"
|
||||
},
|
||||
"default_popup": "pages/popup/popup.html",
|
||||
"browser_style": false
|
||||
"default_popup": "pages/popup/popup.html",
|
||||
"browser_style": false
|
||||
},
|
||||
|
||||
"options_ui": {
|
||||
@@ -49,8 +49,8 @@
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "jid1-BoFifL9Vbdl2zQ@jetpack",
|
||||
"strict_min_version": "56.0a1"
|
||||
"id": "jid1-BoFifL9Vbdl2zQ@jetpack",
|
||||
"strict_min_version": "56.0a1"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
5
modules/fontawesome/fontawesome.min.js
vendored
Normal file
5
modules/fontawesome/fontawesome.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5
modules/fontawesome/icon-bundle.min.js
vendored
Normal file
5
modules/fontawesome/icon-bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -20,7 +20,7 @@
|
||||
var helpers = {};
|
||||
|
||||
/**
|
||||
* Public Functions
|
||||
* Public Methods
|
||||
*/
|
||||
|
||||
helpers.insertI18nContentIntoDocument = function (document) {
|
||||
@@ -62,8 +62,8 @@ helpers.languageIsFullySupported = function (language) {
|
||||
languageSupported = false;
|
||||
|
||||
supportedLanguages = [
|
||||
'ar', 'bg', 'zh-CN', 'zh-TW', 'da', 'nl', 'en', 'et', 'fi', 'fr', 'de',
|
||||
'el', 'is', 'id', 'pl', 'pt-PT', 'ro', 'ru', 'es', 'sv', 'tr'
|
||||
'ar', 'bg', 'zh', 'da', 'nl', 'en', 'et', 'fi', 'fr', 'de', 'el', 'is',
|
||||
'id', 'it', 'ja', 'ko', 'pl', 'pt', 'ro', 'ru', 'es', 'sv', 'tr'
|
||||
];
|
||||
|
||||
for (let supportedLanguage of supportedLanguages) {
|
||||
@@ -76,6 +76,48 @@ helpers.languageIsFullySupported = function (language) {
|
||||
return languageSupported;
|
||||
};
|
||||
|
||||
helpers.normalizeDomain = function (domain) {
|
||||
|
||||
domain = domain.toLowerCase().trim();
|
||||
|
||||
if (domain.startsWith(Address.WWW_PREFIX)) {
|
||||
domain = domain.slice(Address.WWW_PREFIX.length);
|
||||
}
|
||||
|
||||
return domain;
|
||||
};
|
||||
|
||||
helpers.extractDomainFromUrl = function (url, normalize) {
|
||||
|
||||
let extractedDomain;
|
||||
|
||||
try {
|
||||
extractedDomain = new URL(url).host;
|
||||
} catch (exception) {
|
||||
extractedDomain = null;
|
||||
}
|
||||
|
||||
if (extractedDomain === '') {
|
||||
extractedDomain = null;
|
||||
}
|
||||
|
||||
if (extractedDomain !== null && normalize === true) {
|
||||
extractedDomain = helpers.normalizeDomain(extractedDomain);
|
||||
}
|
||||
|
||||
return extractedDomain;
|
||||
};
|
||||
|
||||
helpers.extractFilenameFromPath = function (path) {
|
||||
|
||||
let pathSegments, filename;
|
||||
|
||||
pathSegments = path.split('/');
|
||||
filename = pathSegments[pathSegments.length - 1];
|
||||
|
||||
return filename;
|
||||
};
|
||||
|
||||
helpers.determineCdnName = function (domainName) {
|
||||
|
||||
switch (domainName) {
|
||||
|
||||
38
modules/internal/wrappers.js
Normal file
38
modules/internal/wrappers.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Internal API Wrapper Module
|
||||
* Belongs to Decentraleyes.
|
||||
*
|
||||
* @author Thomas Rientjes
|
||||
* @since 2017-12-03
|
||||
* @license MPL 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Wrappers
|
||||
*/
|
||||
|
||||
var wrappers = {};
|
||||
|
||||
/**
|
||||
* Public Methods
|
||||
*/
|
||||
|
||||
wrappers.setBadgeBackgroundColor = function (details) {
|
||||
|
||||
if (chrome.browserAction.setBadgeBackgroundColor !== undefined) {
|
||||
chrome.browserAction.setBadgeBackgroundColor(details);
|
||||
}
|
||||
};
|
||||
|
||||
wrappers.setBadgeText = function (details) {
|
||||
|
||||
if (chrome.browserAction.setBadgeText !== undefined) {
|
||||
chrome.browserAction.setBadgeText(details);
|
||||
}
|
||||
};
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<body>
|
||||
|
||||
<script src="../../modules/internal/wrappers.js"></script>
|
||||
<script src="../../modules/internal/helpers.js"></script>
|
||||
|
||||
<script src="../../core/constants.js"></script>
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="options.css">
|
||||
|
||||
<script defer src="../../modules/fontawesome/packs/solid.js"></script>
|
||||
<script defer src="../../modules/fontawesome/fontawesome.js"></script>
|
||||
<script defer src="../../modules/fontawesome/icon-bundle.min.js"></script>
|
||||
<script defer src="../../modules/fontawesome/fontawesome.min.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
<div class="notice-body" dir="ltr">
|
||||
|
||||
<i class="fas fa-exclamation-triangle icon"></i>
|
||||
<i class="fai fa-exclamation-triangle icon"></i>
|
||||
Your preferred language is not yet fully supported.
|
||||
<a class="link-text" href="https://crowdin.com/project/decentraleyes" target="_blank">
|
||||
Help Translate
|
||||
|
||||
@@ -23,43 +23,73 @@ var options = {};
|
||||
* Private Methods
|
||||
*/
|
||||
|
||||
options._renderContents = function () {
|
||||
|
||||
document.body.setAttribute('dir', options._scriptDirection);
|
||||
helpers.insertI18nContentIntoDocument(document);
|
||||
|
||||
options._determineOptionValues()
|
||||
.then(options._renderOptionsPanel);
|
||||
};
|
||||
|
||||
options._renderOptionsPanel = function () {
|
||||
|
||||
let whitelistedDomains, domainWhitelist, elements;
|
||||
|
||||
whitelistedDomains = options._optionValues.whitelistedDomains;
|
||||
domainWhitelist = options._serializeWhitelistedDomains(whitelistedDomains);
|
||||
|
||||
elements = options._optionElements;
|
||||
|
||||
elements.showIconBadge.checked = options._optionValues.showIconBadge;
|
||||
elements.blockMissing.checked = options._optionValues.blockMissing;
|
||||
elements.disablePrefetch.checked = options._optionValues.disablePrefetch;
|
||||
elements.stripMetadata.checked = options._optionValues.stripMetadata;
|
||||
elements.whitelistedDomains.value = domainWhitelist;
|
||||
|
||||
options._registerOptionChangedEventListeners(elements);
|
||||
|
||||
if (options._languageSupported === false) {
|
||||
options._renderLocaleNotice();
|
||||
}
|
||||
};
|
||||
|
||||
options._renderLocaleNotice = function () {
|
||||
|
||||
let localeNoticeElement = document.getElementById('notice-locale');
|
||||
localeNoticeElement.setAttribute('class', 'notice');
|
||||
};
|
||||
|
||||
options._registerOptionChangedEventListeners = function (elements) {
|
||||
|
||||
elements.showIconBadge.addEventListener('change', options._onOptionChanged);
|
||||
elements.blockMissing.addEventListener('change', options._onOptionChanged);
|
||||
elements.disablePrefetch.addEventListener('change', options._onOptionChanged);
|
||||
elements.stripMetadata.addEventListener('change', options._onOptionChanged);
|
||||
elements.whitelistedDomains.addEventListener('keyup', options._onOptionChanged);
|
||||
};
|
||||
|
||||
options._determineOptionValues = function () {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
let optionKeys = Object.keys(options._optionElements);
|
||||
|
||||
chrome.storage.local.get(optionKeys, function (items) {
|
||||
|
||||
options._optionValues = items;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
options._getOptionElement = function (optionKey) {
|
||||
return document.querySelector(`[data-option=${optionKey}]`);
|
||||
};
|
||||
|
||||
function _normalizeDomain (domain) {
|
||||
options._getOptionElements = function () {
|
||||
|
||||
domain = domain.toLowerCase().trim();
|
||||
|
||||
if (domain.startsWith(Address.WWW_PREFIX)) {
|
||||
domain = domain.slice(Address.WWW_PREFIX_LENGTH);
|
||||
}
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializations
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
let scriptDirection, languageSupported, optionElements;
|
||||
|
||||
scriptDirection = helpers.determineScriptDirection(navigator.language);
|
||||
document.body.setAttribute('dir', scriptDirection);
|
||||
|
||||
languageSupported = helpers.languageIsFullySupported(navigator.language);
|
||||
|
||||
if (languageSupported === false) {
|
||||
|
||||
let localeNoticeElement = document.getElementById('notice-locale');
|
||||
localeNoticeElement.setAttribute('class', 'notice');
|
||||
}
|
||||
|
||||
helpers.insertI18nContentIntoDocument(document);
|
||||
|
||||
optionElements = {
|
||||
let optionElements = {
|
||||
'showIconBadge': options._getOptionElement(Setting.SHOW_ICON_BADGE),
|
||||
'blockMissing': options._getOptionElement(Setting.BLOCK_MISSING),
|
||||
'disablePrefetch': options._getOptionElement(Setting.DISABLE_PREFETCH),
|
||||
@@ -67,76 +97,97 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
'whitelistedDomains': options._getOptionElement(Setting.WHITELISTED_DOMAINS)
|
||||
};
|
||||
|
||||
chrome.storage.local.get(Object.keys(optionElements), function (items) {
|
||||
return optionElements;
|
||||
};
|
||||
|
||||
let whitelistedDomains, domainWhitelist;
|
||||
options._configureLinkPrefetching = function (value) {
|
||||
|
||||
whitelistedDomains = items.whitelistedDomains;
|
||||
domainWhitelist = '';
|
||||
if (value === false) {
|
||||
|
||||
Object.keys(whitelistedDomains).forEach(function (domain) {
|
||||
domainWhitelist = `${domainWhitelist}${domain};`;
|
||||
// Restore default values of related preference values.
|
||||
chrome.privacy.network.networkPredictionEnabled.clear({});
|
||||
|
||||
} else {
|
||||
|
||||
chrome.privacy.network.networkPredictionEnabled.set({
|
||||
'value': false
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
domainWhitelist = domainWhitelist.slice(0, -1);
|
||||
domainWhitelist = domainWhitelist.replace(Whitelist.TRIM_EXPRESSION, '');
|
||||
options._serializeWhitelistedDomains = function (whitelistedDomains) {
|
||||
|
||||
optionElements.showIconBadge.checked = items.showIconBadge;
|
||||
optionElements.blockMissing.checked = items.blockMissing;
|
||||
optionElements.disablePrefetch.checked = items.disablePrefetch;
|
||||
optionElements.stripMetadata.checked = items.stripMetadata;
|
||||
optionElements.whitelistedDomains.value = domainWhitelist;
|
||||
let domainWhitelist, whitelistedDomainKeys;
|
||||
|
||||
whitelistedDomainKeys = Object.keys(whitelistedDomains);
|
||||
domainWhitelist = '';
|
||||
|
||||
whitelistedDomainKeys.forEach(function (domain) {
|
||||
domainWhitelist = `${domainWhitelist}${domain};`;
|
||||
});
|
||||
|
||||
let optionChangedHandler = function ({target}) {
|
||||
domainWhitelist = domainWhitelist.slice(0, -1);
|
||||
domainWhitelist = domainWhitelist.replace(Whitelist.TRIM_EXPRESSION, '');
|
||||
|
||||
let optionKey, optionType, optionValue;
|
||||
return domainWhitelist;
|
||||
};
|
||||
|
||||
optionKey = target.getAttribute('data-option');
|
||||
optionType = target.getAttribute('type');
|
||||
options._parseDomainWhitelist = function (domainWhitelist) {
|
||||
|
||||
switch (optionType) {
|
||||
case 'checkbox':
|
||||
optionValue = target.checked;
|
||||
break;
|
||||
default:
|
||||
optionValue = target.value;
|
||||
}
|
||||
let whitelistedDomains = {};
|
||||
|
||||
if (optionKey === Setting.DISABLE_PREFETCH) {
|
||||
domainWhitelist.split(Whitelist.VALUE_SEPARATOR).forEach(function (domain) {
|
||||
whitelistedDomains[helpers.normalizeDomain(domain)] = true;
|
||||
});
|
||||
|
||||
if (optionValue === false) {
|
||||
return whitelistedDomains;
|
||||
};
|
||||
|
||||
// Restore default values of related preference values.
|
||||
chrome.privacy.network.networkPredictionEnabled.clear({});
|
||||
/**
|
||||
* Event Handlers
|
||||
*/
|
||||
|
||||
} else {
|
||||
options._onDocumentLoaded = function () {
|
||||
|
||||
chrome.privacy.network.networkPredictionEnabled.set({
|
||||
'value': false
|
||||
});
|
||||
}
|
||||
}
|
||||
let language = navigator.language;
|
||||
|
||||
if (optionKey === Setting.WHITELISTED_DOMAINS) {
|
||||
options._optionElements = options._getOptionElements();
|
||||
options._languageSupported = helpers.languageIsFullySupported(language);
|
||||
options._scriptDirection = helpers.determineScriptDirection(language);
|
||||
|
||||
let domainWhitelist = optionValue;
|
||||
options._renderContents();
|
||||
};
|
||||
|
||||
optionValue = {};
|
||||
options._onOptionChanged = function ({target}) {
|
||||
|
||||
domainWhitelist.split(Whitelist.VALUE_SEPARATOR).forEach(function (domain) {
|
||||
optionValue[_normalizeDomain(domain)] = true;
|
||||
});
|
||||
}
|
||||
let optionKey, optionType, optionValue;
|
||||
|
||||
chrome.storage.local.set({
|
||||
[optionKey]: optionValue
|
||||
});
|
||||
};
|
||||
optionKey = target.getAttribute('data-option');
|
||||
optionType = target.getAttribute('type');
|
||||
|
||||
optionElements.showIconBadge.addEventListener('change', optionChangedHandler);
|
||||
optionElements.blockMissing.addEventListener('change', optionChangedHandler);
|
||||
optionElements.disablePrefetch.addEventListener('change', optionChangedHandler);
|
||||
optionElements.stripMetadata.addEventListener('change', optionChangedHandler);
|
||||
optionElements.whitelistedDomains.addEventListener('keyup', optionChangedHandler);
|
||||
});
|
||||
switch (optionType) {
|
||||
case 'checkbox':
|
||||
optionValue = target.checked;
|
||||
break;
|
||||
default:
|
||||
optionValue = target.value;
|
||||
}
|
||||
|
||||
if (optionKey === Setting.DISABLE_PREFETCH) {
|
||||
options._configureLinkPrefetching(optionValue);
|
||||
}
|
||||
|
||||
if (optionKey === Setting.WHITELISTED_DOMAINS) {
|
||||
optionValue = options._parseDomainWhitelist(optionValue);
|
||||
}
|
||||
|
||||
chrome.storage.local.set({
|
||||
[optionKey]: optionValue
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializations
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', options._onDocumentLoaded);
|
||||
|
||||
@@ -247,3 +247,14 @@ footer {
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatibility
|
||||
*/
|
||||
|
||||
@media screen and (-webkit-min-device-pixel-ratio: 0) {
|
||||
|
||||
body {
|
||||
width: 348px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,74 +2,74 @@
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<head>
|
||||
|
||||
<title>Decentraleyes Popup</title>
|
||||
<title>Decentraleyes Popup</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="popup.css">
|
||||
<link rel="stylesheet" type="text/css" href="popup.css">
|
||||
|
||||
<script defer src="../../modules/fontawesome/packs/solid.js"></script>
|
||||
<script defer src="../../modules/fontawesome/fontawesome.js"></script>
|
||||
<script defer src="../../modules/fontawesome/icon-bundle.min.js"></script>
|
||||
<script defer src="../../modules/fontawesome/fontawesome.min.js"></script>
|
||||
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body>
|
||||
|
||||
<script src="../../core/constants.js"></script>
|
||||
<script src="../../modules/internal/helpers.js"></script>
|
||||
<script src="../../core/constants.js"></script>
|
||||
<script src="../../modules/internal/helpers.js"></script>
|
||||
|
||||
<script src="popup.js"></script>
|
||||
<script src="popup.js"></script>
|
||||
|
||||
<header>
|
||||
<header>
|
||||
|
||||
<img class="icon-logo" src="icon.svg" alt="Extension Icon">
|
||||
<div class="heading">Decentraleyes <sup id="version-label" class="label-version"></sup></div>
|
||||
<img class="icon-logo" src="icon.svg" alt="Extension Icon">
|
||||
<div class="heading">Decentraleyes <sup id="version-label" class="label-version"></sup></div>
|
||||
|
||||
</header>
|
||||
</header>
|
||||
|
||||
<section class="content">
|
||||
<section class="content">
|
||||
|
||||
<div id="website-context" class="panel hidden">
|
||||
<div id="website-context" class="panel hidden">
|
||||
|
||||
<div class="subpanel">
|
||||
<div class="subpanel">
|
||||
|
||||
<div id="protection-toggle-button" class="button button-toggle active">
|
||||
<i class="fas fa-power-off" data-fa-transform="grow-2"></i>
|
||||
</div>
|
||||
<div id="protection-toggle-button" class="button button-toggle active">
|
||||
<i class="fai fa-power-off" data-fa-transform="grow-2 down-.5"></i>
|
||||
</div>
|
||||
|
||||
<div class="label-domain">
|
||||
<i class="icon fai fa-globe fa-lg" data-fa-transform="down-1"></i>
|
||||
<span id="domain-indicator"></span>
|
||||
</div>
|
||||
|
||||
<div class="label-domain">
|
||||
<i class="icon fas fa-globe fa-lg" data-fa-transform="down-1"></i>
|
||||
<span id="domain-indicator"></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="extension-context" class="panel">
|
||||
|
||||
<div id="extension-context" class="panel">
|
||||
<div id="injection-counter" class="counter">0</div>
|
||||
|
||||
<div id="injection-counter" class="counter">0</div>
|
||||
<div class="subheading" data-i18n-content="amountInjectedTitle"></div>
|
||||
<div class="description" data-i18n-content="amountInjectedDescription"></div>
|
||||
|
||||
<div class="subheading" data-i18n-content="amountInjectedTitle"></div>
|
||||
<div class="description" data-i18n-content="amountInjectedDescription"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
<footer>
|
||||
|
||||
<footer>
|
||||
<span id="testing-utility-link" class="link-text">decentraleyes.org/test</span>
|
||||
|
||||
<span id="testing-utility-link" class="link-text">decentraleyes.org/test</span>
|
||||
<div id="options-button" class="button" data-i18n-title="optionsTitle">
|
||||
<i class="fai fa-cog" data-fa-transform="grow-2 down-.5"></i>
|
||||
</div>
|
||||
|
||||
<div id="options-button" class="button" data-i18n-title="optionsTitle">
|
||||
<i class="fas fa-cog" data-fa-transform="grow-2"></i>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -20,237 +20,314 @@
|
||||
var popup = {};
|
||||
|
||||
/**
|
||||
* Initializations
|
||||
* Private Methods
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
let version, optionsButtonElement, scriptDirection;
|
||||
|
||||
version = helpers.formatVersion(chrome.runtime.getManifest().version);
|
||||
document.getElementById('version-label').innerText = version;
|
||||
|
||||
scriptDirection = helpers.determineScriptDirection(navigator.language);
|
||||
optionsButtonElement = document.getElementById('options-button');
|
||||
popup._renderContents = function () {
|
||||
|
||||
helpers.insertI18nContentIntoDocument(document);
|
||||
helpers.insertI18nTitlesIntoDocument(document);
|
||||
|
||||
chrome.storage.local.get('amountInjected', function (items) {
|
||||
popup._renderNonContextualContents();
|
||||
|
||||
let amountInjected = items.amountInjected || 0;
|
||||
document.getElementById('injection-counter').innerText = amountInjected;
|
||||
if (popup._backgroundPage !== null) {
|
||||
|
||||
popup._determineTargetTab()
|
||||
.then(popup._renderContextualContents);
|
||||
}
|
||||
};
|
||||
|
||||
popup._renderNonContextualContents = function () {
|
||||
|
||||
let versionLabelElement, counterElement, testingUtilityLinkElement, optionsButtonElement;
|
||||
|
||||
versionLabelElement = document.getElementById('version-label');
|
||||
counterElement = document.getElementById('injection-counter');
|
||||
testingUtilityLinkElement = document.getElementById('testing-utility-link');
|
||||
optionsButtonElement = document.getElementById('options-button');
|
||||
|
||||
versionLabelElement.innerText = popup._version;
|
||||
counterElement.innerText = popup._amountInjected;
|
||||
|
||||
testingUtilityLinkElement.addEventListener('mouseup', popup._onTestingUtilityLinkClicked);
|
||||
optionsButtonElement.addEventListener('mouseup', popup._onOptionsButtonClicked);
|
||||
};
|
||||
|
||||
popup._renderContextualContents = function () {
|
||||
|
||||
let injections, groupedInjections;
|
||||
|
||||
popup._domain = helpers.extractDomainFromUrl(popup._targetTab.url);
|
||||
|
||||
popup._requestAnalyzer = popup._backgroundPage.requestAnalyzer;
|
||||
popup._stateManager = popup._backgroundPage.stateManager;
|
||||
|
||||
if (popup._domain !== null) {
|
||||
|
||||
popup._domain = helpers.normalizeDomain(popup._domain);
|
||||
popup._renderDomainWhitelistPanel();
|
||||
}
|
||||
|
||||
injections = popup._stateManager.tabs[popup._targetTab.id].injections;
|
||||
groupedInjections = popup._groupResourceInjections(injections);
|
||||
|
||||
if (Object.keys(groupedInjections).length > 0) {
|
||||
popup._renderInjectionPanel(groupedInjections);
|
||||
}
|
||||
};
|
||||
|
||||
popup._renderDomainWhitelistPanel = function () {
|
||||
|
||||
let websiteContextElement, protectionToggleElement, domainIndicatorElement;
|
||||
|
||||
websiteContextElement = document.getElementById('website-context');
|
||||
protectionToggleElement = document.getElementById('protection-toggle-button');
|
||||
domainIndicatorElement = document.getElementById('domain-indicator');
|
||||
|
||||
protectionToggleElement.setAttribute('dir', popup._scriptDirection);
|
||||
domainIndicatorElement.innerText = popup._domain;
|
||||
|
||||
if (popup._requestAnalyzer.whitelistedDomains[popup._domain]) {
|
||||
|
||||
let enableProtectionTitle = chrome.i18n.getMessage('enableProtectionTitle');
|
||||
|
||||
protectionToggleElement.setAttribute('class', 'button button-toggle');
|
||||
protectionToggleElement.addEventListener('click', popup._enableProtection);
|
||||
protectionToggleElement.setAttribute('title', enableProtectionTitle);
|
||||
|
||||
} else {
|
||||
|
||||
let disableProtectionTitle = chrome.i18n.getMessage('disableProtectionTitle');
|
||||
|
||||
protectionToggleElement.setAttribute('class', 'button button-toggle active');
|
||||
protectionToggleElement.addEventListener('click', popup._disableProtection);
|
||||
protectionToggleElement.setAttribute('title', disableProtectionTitle);
|
||||
}
|
||||
|
||||
websiteContextElement.setAttribute('class', 'panel');
|
||||
};
|
||||
|
||||
popup._renderInjectionPanel = function (groupedInjections) {
|
||||
|
||||
let websiteContextElement, injectionOverviewElement;
|
||||
|
||||
websiteContextElement = document.getElementById('website-context');
|
||||
injectionOverviewElement = popup._createInjectionOverviewElement(groupedInjections);
|
||||
|
||||
websiteContextElement.append(injectionOverviewElement);
|
||||
};
|
||||
|
||||
popup._enableProtection = function () {
|
||||
|
||||
popup._stateManager.deleteDomainFromWhitelist(popup._domain)
|
||||
.then(popup._onProtectionToggled);
|
||||
};
|
||||
|
||||
popup._disableProtection = function () {
|
||||
|
||||
popup._stateManager.addDomainToWhitelist(popup._domain)
|
||||
.then(popup._onProtectionToggled);
|
||||
};
|
||||
|
||||
popup._determineBackgroundPage = function () {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
chrome.runtime.getBackgroundPage(function (backgroundPage) {
|
||||
|
||||
popup._backgroundPage = backgroundPage;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
popup._determineTargetTab = function () {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
chrome.tabs.query({'active': true, 'currentWindow': true}, function (tabs) {
|
||||
|
||||
chrome.runtime.getBackgroundPage(function (backgroundPage) {
|
||||
|
||||
if (backgroundPage === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
popup.backgroundPage = backgroundPage;
|
||||
|
||||
if (backgroundPage.main.operatingSystem === chrome.runtime.PlatformOs.ANDROID) {
|
||||
|
||||
browser.tabs.getCurrent().then(function (tab) {
|
||||
|
||||
browser.tabs.update(tab.id, {
|
||||
'active': true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let injections, injectionOverview, domain;
|
||||
|
||||
injections = backgroundPage.stateManager.tabs[tabs[0].id].injections;
|
||||
injectionOverview = {};
|
||||
|
||||
try {
|
||||
domain = tabs[0].url.match(Address.DOMAIN_EXPRESSION)[1];
|
||||
} catch (exception) {
|
||||
domain = null;
|
||||
}
|
||||
|
||||
if (domain !== null) {
|
||||
|
||||
let websiteContextElement, protectionToggleElement, domainIndicatorElement;
|
||||
|
||||
websiteContextElement = document.getElementById('website-context');
|
||||
protectionToggleElement = document.getElementById('protection-toggle-button');
|
||||
domainIndicatorElement = document.getElementById('domain-indicator');
|
||||
|
||||
if (domain.startsWith(Address.WWW_PREFIX)) {
|
||||
domain = domain.slice(Address.WWW_PREFIX_LENGTH);
|
||||
}
|
||||
|
||||
domainIndicatorElement.innerText = domain;
|
||||
|
||||
if (backgroundPage.requestAnalyzer.whitelistedDomains[domain]) {
|
||||
|
||||
protectionToggleElement.setAttribute('class', 'button button-toggle');
|
||||
|
||||
let enableProtectionTitle = chrome.i18n.getMessage('enableProtectionTitle');
|
||||
protectionToggleElement.setAttribute('title', enableProtectionTitle);
|
||||
|
||||
protectionToggleElement.addEventListener('click', function () {
|
||||
|
||||
backgroundPage.stateManager.deleteDomainFromWhitelist(domain).then(function () {
|
||||
|
||||
chrome.tabs.reload(tabs[0].id);
|
||||
|
||||
if (backgroundPage.main.operatingSystem === chrome.runtime.PlatformOs.ANDROID) {
|
||||
|
||||
return browser.tabs.getCurrent().then(function (tab) {
|
||||
browser.tabs.remove(tab.id);
|
||||
});
|
||||
}
|
||||
|
||||
return window.close();
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
protectionToggleElement.setAttribute('class', 'button button-toggle active');
|
||||
|
||||
let disableProtectionTitle = chrome.i18n.getMessage('disableProtectionTitle');
|
||||
|
||||
protectionToggleElement.setAttribute('title', disableProtectionTitle);
|
||||
protectionToggleElement.setAttribute('dir', scriptDirection);
|
||||
|
||||
protectionToggleElement.addEventListener('click', function () {
|
||||
|
||||
backgroundPage.stateManager.addDomainToWhitelist(domain).then(function () {
|
||||
|
||||
chrome.tabs.reload(tabs[0].id);
|
||||
|
||||
if (backgroundPage.main.operatingSystem === chrome.runtime.PlatformOs.ANDROID) {
|
||||
|
||||
return browser.tabs.getCurrent().then(function (tab) {
|
||||
browser.tabs.remove(tab.id);
|
||||
});
|
||||
}
|
||||
|
||||
return window.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
websiteContextElement.setAttribute('class', 'panel');
|
||||
}
|
||||
|
||||
for (let injection in injections) {
|
||||
|
||||
injection = injections[injection];
|
||||
|
||||
let injectionSource = injection.source;
|
||||
injectionOverview[injectionSource] = injectionOverview[injectionSource] || [];
|
||||
|
||||
injectionOverview[injectionSource].push({
|
||||
'path': injection.path,
|
||||
'version': injection.version,
|
||||
'source': injection.source
|
||||
});
|
||||
}
|
||||
|
||||
let listElement = document.createElement('ul');
|
||||
listElement.setAttribute('class', 'list');
|
||||
|
||||
for (let injectionSource in injectionOverview) {
|
||||
|
||||
let cdn, listItemElement, badgeElement, badgeTextNode, cdnName, cdnNameTextNode, subListElement;
|
||||
|
||||
cdn = injectionOverview[injectionSource];
|
||||
|
||||
listItemElement = document.createElement('li');
|
||||
listItemElement.setAttribute('class', 'list-item');
|
||||
|
||||
badgeElement = document.createElement('span');
|
||||
badgeElement.setAttribute('class', 'badge');
|
||||
|
||||
badgeTextNode = document.createTextNode(cdn.length);
|
||||
badgeElement.appendChild(badgeTextNode);
|
||||
|
||||
cdnName = helpers.determineCdnName(injectionSource);
|
||||
|
||||
cdnNameTextNode = document.createTextNode(cdnName);
|
||||
|
||||
listItemElement.appendChild(badgeElement);
|
||||
listItemElement.appendChild(cdnNameTextNode);
|
||||
|
||||
listElement.appendChild(listItemElement);
|
||||
|
||||
subListElement = document.createElement('ul');
|
||||
subListElement.setAttribute('class', 'sublist');
|
||||
|
||||
listElement.appendChild(subListElement);
|
||||
|
||||
for (let injection of cdn) {
|
||||
|
||||
let subListItemElement, resourcePathDetails, resourceFilename, resourceName,
|
||||
resourceNameTextNode, sideNoteElement, sideNoteTextNode;
|
||||
|
||||
subListItemElement = document.createElement('li');
|
||||
subListItemElement.setAttribute('class', 'sublist-item');
|
||||
|
||||
resourcePathDetails = injection.path.split('/');
|
||||
resourceFilename = resourcePathDetails[resourcePathDetails.length - 1];
|
||||
|
||||
resourceName = helpers.determineResourceName(resourceFilename);
|
||||
|
||||
resourceNameTextNode = document.createTextNode(`- ${resourceName}`);
|
||||
subListItemElement.appendChild(resourceNameTextNode);
|
||||
|
||||
sideNoteElement = document.createElement('span');
|
||||
sideNoteElement.setAttribute('class', 'side-note');
|
||||
|
||||
sideNoteTextNode = document.createTextNode(` v${injection.version}`);
|
||||
|
||||
sideNoteElement.appendChild(sideNoteTextNode);
|
||||
subListItemElement.appendChild(sideNoteElement);
|
||||
|
||||
subListElement.appendChild(subListItemElement);
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(injectionOverview).length > 0) {
|
||||
|
||||
let websiteContextElement = document.getElementById('website-context');
|
||||
websiteContextElement.append(listElement);
|
||||
}
|
||||
});
|
||||
popup._targetTab = tabs[0];
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
popup._determineAmountInjected = function () {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
|
||||
chrome.storage.local.get('amountInjected', function (items) {
|
||||
|
||||
popup._amountInjected = items.amountInjected || 0;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
popup._groupResourceInjections = function (injections) {
|
||||
|
||||
let groupedInjections = {};
|
||||
|
||||
for (let index in injections) {
|
||||
|
||||
let {source} = injections[index];
|
||||
|
||||
groupedInjections[source] = groupedInjections[source] || [];
|
||||
groupedInjections[source].push(injections[index]);
|
||||
}
|
||||
|
||||
return groupedInjections;
|
||||
};
|
||||
|
||||
popup._createInjectionOverviewElement = function (groupedInjections) {
|
||||
|
||||
let injectionOverviewElement = document.createElement('ul');
|
||||
injectionOverviewElement.setAttribute('class', 'list');
|
||||
|
||||
for (let source in groupedInjections) {
|
||||
|
||||
let injectionGroupHeaderElement, injectionGroupElement, cdn;
|
||||
|
||||
cdn = groupedInjections[source];
|
||||
|
||||
injectionGroupHeaderElement = popup._createInjectionGroupHeaderElement(source, cdn);
|
||||
injectionGroupElement = popup._createInjectionGroupElement(source, cdn);
|
||||
|
||||
injectionOverviewElement.appendChild(injectionGroupHeaderElement);
|
||||
injectionOverviewElement.appendChild(injectionGroupElement);
|
||||
}
|
||||
|
||||
return injectionOverviewElement;
|
||||
};
|
||||
|
||||
popup._createInjectionGroupHeaderElement = function (source, cdn) {
|
||||
|
||||
let injectionGroupHeaderElement, badgeElement, badgeTextNode, cdnNameTextNode;
|
||||
|
||||
injectionGroupHeaderElement = document.createElement('li');
|
||||
injectionGroupHeaderElement.setAttribute('class', 'list-item');
|
||||
|
||||
badgeElement = document.createElement('span');
|
||||
badgeElement.setAttribute('class', 'badge');
|
||||
|
||||
badgeTextNode = document.createTextNode(cdn.length);
|
||||
badgeElement.appendChild(badgeTextNode);
|
||||
|
||||
cdnNameTextNode = document.createTextNode(helpers.determineCdnName(source));
|
||||
|
||||
injectionGroupHeaderElement.appendChild(badgeElement);
|
||||
injectionGroupHeaderElement.appendChild(cdnNameTextNode);
|
||||
|
||||
return injectionGroupHeaderElement;
|
||||
};
|
||||
|
||||
popup._createInjectionGroupElement = function (source, cdn) {
|
||||
|
||||
let injectionGroupElement;
|
||||
|
||||
injectionGroupElement = document.createElement('ul');
|
||||
injectionGroupElement.setAttribute('class', 'sublist');
|
||||
|
||||
for (let injection of cdn) {
|
||||
|
||||
let injectionElement = popup._createInjectionElement(injection);
|
||||
injectionGroupElement.appendChild(injectionElement);
|
||||
}
|
||||
|
||||
return injectionGroupElement;
|
||||
};
|
||||
|
||||
popup._createInjectionElement = function (injection) {
|
||||
|
||||
let injectionElement, filename, name, nameTextNode, noteElement, noteTextNode;
|
||||
|
||||
injectionElement = document.createElement('li');
|
||||
injectionElement.setAttribute('class', 'sublist-item');
|
||||
|
||||
filename = helpers.extractFilenameFromPath(injection.path);
|
||||
name = helpers.determineResourceName(filename);
|
||||
|
||||
nameTextNode = document.createTextNode(`- ${name}`);
|
||||
injectionElement.appendChild(nameTextNode);
|
||||
|
||||
noteElement = document.createElement('span');
|
||||
noteElement.setAttribute('class', 'side-note');
|
||||
|
||||
noteTextNode = document.createTextNode(` v${injection.version}`);
|
||||
|
||||
noteElement.appendChild(noteTextNode);
|
||||
injectionElement.appendChild(noteElement);
|
||||
|
||||
return injectionElement;
|
||||
};
|
||||
|
||||
popup._close = function () {
|
||||
|
||||
chrome.runtime.getPlatformInfo(function (information) {
|
||||
|
||||
optionsButtonElement.addEventListener('mouseup', function () {
|
||||
if (information.os === chrome.runtime.PlatformOs.ANDROID) {
|
||||
|
||||
if (information.os === chrome.runtime.PlatformOs.ANDROID) {
|
||||
|
||||
return chrome.tabs.create({
|
||||
'url': chrome.extension.getURL('pages/options/options.html')
|
||||
});
|
||||
}
|
||||
|
||||
chrome.runtime.openOptionsPage();
|
||||
return window.close();
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('testing-utility-link').addEventListener('mouseup', function (event) {
|
||||
|
||||
if (event.button === 0 || event.button === 1) {
|
||||
|
||||
chrome.tabs.create({
|
||||
'url': 'https://decentraleyes.org/test',
|
||||
'active': (event.button === 0)
|
||||
chrome.tabs.getCurrent(function (tab) {
|
||||
chrome.tabs.remove(tab.id);
|
||||
});
|
||||
}
|
||||
|
||||
if (event.button === 0) {
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Event Handlers
|
||||
*/
|
||||
|
||||
popup._onDocumentLoaded = function () {
|
||||
|
||||
let manifest, language;
|
||||
|
||||
manifest = chrome.runtime.getManifest();
|
||||
language = navigator.language;
|
||||
|
||||
popup._version = helpers.formatVersion(manifest.version);
|
||||
popup._scriptDirection = helpers.determineScriptDirection(language);
|
||||
|
||||
popup._determineBackgroundPage()
|
||||
.then(popup._determineAmountInjected)
|
||||
.then(popup._renderContents);
|
||||
};
|
||||
|
||||
popup._onTestingUtilityLinkClicked = function (event) {
|
||||
|
||||
if (event.button === 0 || event.button === 1) {
|
||||
|
||||
chrome.tabs.create({
|
||||
'url': 'https://decentraleyes.org/test',
|
||||
'active': (event.button === 0)
|
||||
});
|
||||
}
|
||||
|
||||
if (event.button === 0) {
|
||||
window.close();
|
||||
}
|
||||
};
|
||||
|
||||
popup._onOptionsButtonClicked = function () {
|
||||
|
||||
chrome.runtime.openOptionsPage();
|
||||
return window.close();
|
||||
};
|
||||
|
||||
popup._onProtectionToggled = function () {
|
||||
|
||||
let bypassCache = (typeof browser === 'undefined');
|
||||
|
||||
chrome.tabs.reload(popup._targetTab.id, {bypassCache});
|
||||
popup._close();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializations
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', popup._onDocumentLoaded);
|
||||
|
||||
@@ -2,79 +2,79 @@
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<head>
|
||||
|
||||
<title>2.0 Says Hello - Decentraleyes</title>
|
||||
<title>2.0 Says Hello - Decentraleyes</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="welcome.css">
|
||||
<link rel="stylesheet" type="text/css" href="welcome.css">
|
||||
|
||||
<script defer src="../../modules/fontawesome/packs/solid.js"></script>
|
||||
<script defer src="../../modules/fontawesome/fontawesome.js"></script>
|
||||
<script defer src="../../modules/fontawesome/icon-bundle.min.js"></script>
|
||||
<script defer src="../../modules/fontawesome/fontawesome.min.js"></script>
|
||||
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||
|
||||
</head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body>
|
||||
|
||||
<img src="logo.svg" alt="Decentraleyes" class="logo"/>
|
||||
<img src="logo.svg" alt="Decentraleyes" class="logo"/>
|
||||
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
|
||||
<h1>What's new in version 2.0?</h1>
|
||||
<h1>What's new in version 2.0?</h1>
|
||||
|
||||
<div class="notice">
|
||||
<div class="notice">
|
||||
|
||||
<span class="subtle-hint"><span class="topic-label">A Completely New Foundation</span><br>Decentraleyes has been fully rebuilt, on top of cutting-edge web technologies. As a result, it's even faster, more capable, and ready for upcoming versions of Firefox.</span>
|
||||
<span class="subtle-hint"><span class="topic-label">A Completely New Foundation</span><br>Decentraleyes has been fully rebuilt, on top of cutting-edge web technologies. As a result, it's even faster, more capable, and ready for upcoming versions of Firefox.</span>
|
||||
|
||||
<div class="topic-badge"><i class="fas fa-cube"></i></div>
|
||||
<div class="topic-badge"><i class="fai fa-cube"></i></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="notice">
|
||||
|
||||
<div class="topic-badge color-purple"><i class="fai fa-window-restore fa-flip-horizontal"></i></div>
|
||||
|
||||
<span class="subtle-hint"><span class="topic-label color-purple">A Clear User Interface</span><br>The extension is finally less shy about what it does to protect you. It shows you what exactly it injects into given pages, and puts all available features right at your fingertips.</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="notice">
|
||||
|
||||
<span class="subtle-hint"><span class="topic-label">Improved Configurability</span><br>The options screen has been updated to give you more control over the extension. Settings that impact privacy, or website functionality, are now explicitly labeled as advanced.</span>
|
||||
|
||||
<div class="topic-badge"><i class="fai fa-cog"></i></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="notice">
|
||||
|
||||
<div class="topic-badge color-purple"><i class="fai fa-power-off"></i></div>
|
||||
|
||||
<span class="subtle-hint"><span class="topic-label color-purple">Simplified Whitelist Management</span><br>Excluding the domain you're visiting from inspections is now easier than ever. Just open up the popup panel, and use the dedicated button, to disable protection for said site.</span>
|
||||
|
||||
</div>
|
||||
|
||||
<h1>Learn more, or contribute</h1>
|
||||
|
||||
<div class="btn-panel">
|
||||
|
||||
<a class="btn btn-website" href="https://decentraleyes.org" target="_blank"><i class="btn-icon fai fa-globe" data-fa-transform="grow-2"></i><span class="btn-text">Website</span></a>
|
||||
|
||||
<a class="btn btn-github" href="https://github.com/Synzvato/decentraleyes" target="_blank"><i class="btn-icon fai fa-github-alt" data-fa-transform="grow-2"></i><span class="btn-text">GitHub</span></a>
|
||||
|
||||
<a class="btn btn-bitcoin" href="https://decentraleyes.org/donate/bitcoin/" target="_blank"><i class="btn-icon fai fa-btc" data-fa-transform="grow-2"></i><span class="btn-text">Bitcoin</span></a>
|
||||
|
||||
<a class="btn btn-monero" href="https://decentraleyes.org/donate/monero/" target="_blank"><i class="btn-icon fai fa-monero" data-fa-transform="grow-2"></i><span class="btn-text">Monero</span></a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="notice">
|
||||
|
||||
<div class="topic-badge color-purple"><i class="fas fa-browser fa-flip-horizontal"></i></div>
|
||||
|
||||
<span class="subtle-hint"><span class="topic-label color-purple">A Clear User Interface</span><br>The extension is finally less shy about what it does to protect you. It shows you what exactly it injects into given pages, and puts all available features right at your fingertips.</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="notice">
|
||||
|
||||
<span class="subtle-hint"><span class="topic-label">Improved Configurability</span><br>The options screen has been updated to give you more control over the extension. Settings that impact privacy, or website functionality, are now explicitly labeled as advanced.</span>
|
||||
|
||||
<div class="topic-badge"><i class="fas fa-cog"></i></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="notice">
|
||||
|
||||
<div class="topic-badge color-purple"><i class="fas fa-power-off"></i></div>
|
||||
|
||||
<span class="subtle-hint"><span class="topic-label color-purple">Simplified Whitelist Management</span><br>Excluding the domain you're visiting from inspections is now easier than ever. Just open up the popup panel, and use the dedicated button, to disable protection for said site.</span>
|
||||
|
||||
</div>
|
||||
|
||||
<h1>Learn more, or contribute</h1>
|
||||
|
||||
<div class="btn-panel">
|
||||
|
||||
<a class="btn btn-website" href="https://decentraleyes.org" target="_blank"><i class="btn-icon fas fa-globe" data-fa-transform="grow-2"></i><span class="btn-text">Website</span></a>
|
||||
|
||||
<a class="btn btn-github" href="https://github.com/Synzvato/decentraleyes" target="_blank"><i class="btn-icon fas fa-github-alt" data-fa-transform="grow-2"></i><span class="btn-text">GitHub</span></a>
|
||||
|
||||
<a class="btn btn-bitcoin" href="https://decentraleyes.org/donate/bitcoin/" target="_blank"><i class="btn-icon fas fa-btc" data-fa-transform="grow-2"></i><span class="btn-text">Bitcoin</span></a>
|
||||
|
||||
<a class="btn btn-monero" href="https://decentraleyes.org/donate/monero/" target="_blank"><i class="btn-icon fas fa-monero" data-fa-transform="grow-2"></i><span class="btn-text">Monero</span></a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user