Initial commit
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 traktofon, (c) 2024 MassiveBox.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
53
README.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
Detect CloudFlare (Chromium port)
|
||||
===============================
|
||||
|
||||
An extension for Chromium-based browsers which aims to detect whether the current page uses CloudFlare.
|
||||
It adds an icon to the browser toolbar which indicates the detection status.
|
||||
|
||||
This is intended to help users detect which of the sites they visit is using CloudFlare, so that they can take the appropriate actions (e.g. changing their password) if they are worried that they are affected by the [cloudbleed bug](https://bugs.chromium.org/p/project-zero/issues/detail?id=1139).
|
||||
|
||||
**Note**: This extension detects whether the page _currently_ uses CloudFlare. It cannot detect whether the page might have used CloudFlare in the past, especially during the time period where it was affected by cloudbleed (i.e. 2016-09-22 thru 2017-02-18). For this, you may check [this list](https://github.com/pirate/sites-using-cloudflare).
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
The extension is not available (yet) on Chrome's WebStore. To install the extension from source:
|
||||
|
||||
* Clone or download this repository
|
||||
* In your browser, go to [chrome://extensions](chrome://extensions)
|
||||
* Enable "developer mode" - there should be a toggle on the top right for it
|
||||
* Click "load unpacked extension" and choose the folder where you cloned or downloaded the repository
|
||||
* The extension will be loaded. Note that it won't have automatic updates. You might have to pin it to keep it always visible.
|
||||
|
||||
|
||||
How it Works
|
||||
------------
|
||||
|
||||
The extension analyzes all HTTP(S) requests and checks whether any of them are served by CloudFlare proxies, as identified by certain headers in the HTTP(S) response. Based on the result of this analysis, the icon changes color:
|
||||
|
||||
![green](icons/cf-green-32.png) No requests were served by CloudFlare.
|
||||
|
||||
![orange](icons/cf-orange-32.png) Extenal resources were served by CloudFlare.
|
||||
|
||||
![red](icons/cf-red-32.png) The page itself was served by CloudFlare.
|
||||
|
||||
Clicking on the icon will show a popup with detailed information about the domains which use CloudFlare.
|
||||
Because the extension only uses the headers provided by the server to determine whether a website uses CloudFlare or not, it doesn't make any additional connection to other servers, APIs or DNS resolvers.
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
* This extension analyzes **all** requests made by the browser, though other extensions (e.g. adblockers) may block some requests before they are made.
|
||||
* When navigating forward/backward inside a tab, the detection status will reset to neutral. To get the correct status, the page needs to be reloaded. (Though nowadays the reload happens automatically for many webpages.)
|
||||
|
||||
## Fork information and donations
|
||||
|
||||
This is a fork of [cf-detect](https://github.com/traktofon/cf-detect), which is for Firefox-based browsers. Thanks to [traktofon](https://github.com/traktofon) for the base code.
|
||||
Right now, the extension is a simple port of the original, with the same features being supported. I plan on working more on this project to port it to Manifest V3 and add some improvements.
|
||||
|
||||
Copyright (c) 2017 traktofon, (c) 2024 MassiveBox.
|
||||
The software is distributed under the MIT license. Consult the LICENSE file to learn more.
|
||||
|
||||
If you like this fork, consider supporting its creator with a small [donation](https://massivebox.net/pages/donate.html).
|
189
background.js
Normal file
|
@ -0,0 +1,189 @@
|
|||
const iconColorAndDesc = {
|
||||
0: { color: "grey", desc: "Detect Cloudflare" },
|
||||
1: { color: "green", desc: "This page doesn't seem to use Cloudflare." },
|
||||
2: { color: "orange", desc: "External resources on this page use Cloudflare." },
|
||||
3: { color: "red", desc: "This page uses Cloudflare!" }
|
||||
};
|
||||
|
||||
function Counter() {
|
||||
this.counts = new Map();
|
||||
this.setCount = function(key,val) {
|
||||
this.counts.set(key, val);
|
||||
};
|
||||
this.getCount = function(key) {
|
||||
if (!this.counts.has(key)) { return 0; }
|
||||
else { return this.counts.get(key); }
|
||||
};
|
||||
this.incCount = function(key) {
|
||||
if (!this.counts.has(key)) { this.counts.set(key,1); }
|
||||
else { this.counts.set(key, this.counts.get(key)+1); }
|
||||
};
|
||||
this.delCount = function(key) {
|
||||
this.counts.delete(key);
|
||||
};
|
||||
}
|
||||
|
||||
function mapToObject( map ) {
|
||||
obj = {};
|
||||
map.forEach( function(val,key) { obj[key]=val; } );
|
||||
return obj;
|
||||
}
|
||||
|
||||
function CFInfo() {
|
||||
this.domainCounter = new Counter();
|
||||
this.result = 0;
|
||||
// maybe more in the future
|
||||
}
|
||||
|
||||
function CFInfoByTab() {
|
||||
this.info = new Map();
|
||||
this.getInfo = function(id) {
|
||||
return this.info.get(id);
|
||||
}
|
||||
this.getOrCreate = function(id) {
|
||||
if (!this.info.has(id)) { this.info.set(id, new CFInfo()); }
|
||||
return this.info.get(id);
|
||||
};
|
||||
this.delInfo = function(id) {
|
||||
this.info.delete(id);
|
||||
};
|
||||
}
|
||||
|
||||
var cfInfo = new CFInfoByTab();
|
||||
|
||||
function onError(e) {
|
||||
console.log(`CF-Detect-Background: ${e}`);
|
||||
}
|
||||
|
||||
function getDomainFromURL( urltxt ) {
|
||||
try {
|
||||
var url = new URL(urltxt);
|
||||
return url.hostname;
|
||||
} catch(err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function updateStatus( tabId ) {
|
||||
var info = cfInfo.getInfo(tabId);
|
||||
if (info) {
|
||||
if (info.result >= 3) return; // no need for further updates
|
||||
var counts = info.domainCounter.counts;
|
||||
if (counts.size == 0) {
|
||||
info.result = 1;
|
||||
updateIcon( tabId, 1 );
|
||||
} else {
|
||||
chrome.tabs.get(tabId, function(tab) {
|
||||
try {
|
||||
var domain = getDomainFromURL(tab.url);
|
||||
if (counts.has(domain)) {
|
||||
info.result = 3;
|
||||
updateIcon( tabId, 3 );
|
||||
} else {
|
||||
info.result = 2;
|
||||
updateIcon( tabId, 2 );
|
||||
}
|
||||
} catch (error) {
|
||||
onError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
updateIcon( tabId, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
function updateIcon( tabId, result ) {
|
||||
var cd = iconColorAndDesc[result];
|
||||
var color = cd.color;
|
||||
var title = cd.desc;
|
||||
chrome.browserAction.setTitle({
|
||||
tabId: tabId,
|
||||
title: title
|
||||
});
|
||||
chrome.browserAction.setIcon({
|
||||
tabId: tabId,
|
||||
path: {
|
||||
16: `icons/cf-${color}-16.png` ,
|
||||
32: `icons/cf-${color}-32.png` ,
|
||||
64: `icons/cf-${color}-64.png`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cfdetect( details ) {
|
||||
var headers = details.responseHeaders;
|
||||
var cf = false;
|
||||
for (var i=0; i<headers.length; i++) {
|
||||
var h = headers[i];
|
||||
var hname = h.name.toLowerCase();
|
||||
if ((hname === "cf-ray") ||
|
||||
(hname === "server" && h.value === "cloudflare-nginx")) {
|
||||
cf = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var tabId = details.tabId;
|
||||
if (tabId == -1) return;
|
||||
var info = cfInfo.getOrCreate(tabId);
|
||||
if (cf) {
|
||||
var ctr = info.domainCounter;
|
||||
var domain = getDomainFromURL( details.url );
|
||||
ctr.incCount(domain);
|
||||
}
|
||||
updateStatus(tabId);
|
||||
}
|
||||
|
||||
function handleBeforeNavigate( details ) {
|
||||
if (details.frameId == 0) {
|
||||
cfInfo.delInfo( details.tabId );
|
||||
updateStatus( details.tabId );
|
||||
}
|
||||
}
|
||||
|
||||
function handleTabUpdate( tabId, changeInfo, tabInfo ) {
|
||||
if ("url" in changeInfo) {
|
||||
updateStatus( tabId );
|
||||
}
|
||||
}
|
||||
|
||||
function handleTabClose( tabId, removeInfo ) {
|
||||
cfInfo.delInfo(tabId);
|
||||
}
|
||||
|
||||
function handleTabReplace( newId, oldId ) {
|
||||
cfInfo.delInfo(oldId);
|
||||
}
|
||||
|
||||
// triggered by popup script
|
||||
function handleConnect(port) {
|
||||
port.onMessage.addListener( function(tabId) {
|
||||
var info = cfInfo.getInfo(tabId);
|
||||
var msg;
|
||||
if (info) {
|
||||
msg = {
|
||||
result: info.result,
|
||||
counts: mapToObject(info.domainCounter.counts)
|
||||
};
|
||||
} else {
|
||||
msg = null;
|
||||
}
|
||||
port.postMessage(msg);
|
||||
});
|
||||
}
|
||||
|
||||
chrome.webRequest.onHeadersReceived.addListener(
|
||||
cfdetect,
|
||||
{ urls: [ "<all_urls>" ] },
|
||||
[ "responseHeaders" ]
|
||||
);
|
||||
|
||||
chrome.webNavigation.onBeforeNavigate.addListener( handleBeforeNavigate );
|
||||
|
||||
chrome.tabs.onUpdated.addListener( handleTabUpdate );
|
||||
chrome.tabs.onRemoved.addListener( handleTabClose );
|
||||
chrome.tabs.onReplaced.addListener( handleTabReplace );
|
||||
|
||||
chrome.runtime.onConnect.addListener( handleConnect );
|
||||
|
||||
// vim: set expandtab ts=4 sw=4 :
|
5
icons/LICENSE
Normal file
|
@ -0,0 +1,5 @@
|
|||
The drawing in "cf.svg" is derived from the "cloud" icon in
|
||||
Font Awesome by Dave Gandy - http://fontawesome.io .
|
||||
|
||||
It is licensed under the SIL Open Font License 1.1,
|
||||
http://scripts.sil.org/OFL .
|
BIN
icons/cf-green-16.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
icons/cf-green-32.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
icons/cf-green-64.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
icons/cf-grey-16.png
Normal file
After Width: | Height: | Size: 835 B |
BIN
icons/cf-grey-32.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
icons/cf-grey-64.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
icons/cf-orange-16.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
icons/cf-orange-32.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
icons/cf-orange-64.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
icons/cf-red-16.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
icons/cf-red-32.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
icons/cf-red-64.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
167
icons/cf.svg
Normal file
|
@ -0,0 +1,167 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 -256 1920 1920"
|
||||
id="svg2989"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
width="100%"
|
||||
height="100%"
|
||||
sodipodi:docname="cloudflare-grey.svg">
|
||||
<metadata
|
||||
id="metadata2999">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<cc:license
|
||||
rdf:resource="http://scripts.sil.org/OFL" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://scripts.sil.org/OFL">
|
||||
<cc:permits
|
||||
rdf:resource="http://scripts.sil.org/pub/OFL/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://scripts.sil.org/pub/OFL/Distribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://scripts.sil.org/pub/OFL/Embedding" />
|
||||
<cc:permits
|
||||
rdf:resource="http://scripts.sil.org/pub/OFL/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://scripts.sil.org/pub/OFL/Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://scripts.sil.org/pub/OFL/Attribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://scripts.sil.org/pub/OFL/ShareAlike" />
|
||||
<cc:requires
|
||||
rdf:resource="http://scripts.sil.org/pub/OFL/DerivativeRenaming" />
|
||||
<cc:requires
|
||||
rdf:resource="http://scripts.sil.org/pub/OFL/BundlingWhenSelling" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs2997" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1551"
|
||||
inkscape:window-height="878"
|
||||
id="namedview2995"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.35833333"
|
||||
inkscape:cx="960"
|
||||
inkscape:cy="960"
|
||||
inkscape:window-x="49"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2989"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true">
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="691.56977,1638.2267"
|
||||
id="guide3752" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="475.45422,1047.9833"
|
||||
id="guide3754" />
|
||||
</sodipodi:namedview>
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path2993"
|
||||
d="m 0,990.205 q 0,159 112.5,271.5 112.5,112.5 271.5,112.5 h 1088 q 185,0 316.5,-131.5 131.5,-131.5 131.5,-316.5 0,-132 -71,-241.5 -71,-109.5 -187,-163.5 2,-28 2,-43 0,-212 -150,-362 -150,-149.999997 -362,-149.999997 -158.00002,0 -286.5,88.000001 Q 737,142.205 678,284.205 q -70,-62 -166,-62 -106,0 -181,75 -75,75 -75,181 0,75 41,138 -129,30 -212.999998,134.5 Q 0,855.205 0,990.205 z" />
|
||||
<g
|
||||
id="g3901"
|
||||
transform="translate(-23.203018,-30)">
|
||||
<path
|
||||
transform="translate(0,-256)"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3758"
|
||||
d="m 691.56977,902.0167 0,-510.88298"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:40;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3758-3"
|
||||
d="m 691.39826,1157.3339 0,-510.88294"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:40;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3758-5"
|
||||
d="m 689.46328,646.15278 -510.88298,0"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:40;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3758-5-3"
|
||||
d="m 1203.847,646.31395 -510.88296,0"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:40;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
<path
|
||||
sodipodi:open="true"
|
||||
sodipodi:end="3.1415927"
|
||||
sodipodi:start="1.5707963"
|
||||
transform="translate(-73.498961,-181.39926)"
|
||||
d="m 877.21656,827.61626 c -61.83101,0 -111.95495,-50.12393 -111.95495,-111.95494 0,0 0,-1e-5 0,-1e-5"
|
||||
sodipodi:ry="111.95494"
|
||||
sodipodi:rx="111.95494"
|
||||
sodipodi:cy="715.66132"
|
||||
sodipodi:cx="877.21655"
|
||||
id="path3845"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:40;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:open="true"
|
||||
sodipodi:end="3.1415927"
|
||||
sodipodi:start="1.5707963"
|
||||
transform="matrix(-1,0,0,1,1456.8026,-181.52326)"
|
||||
d="m 877.21656,827.61626 c -61.83101,0 -111.95495,-50.12393 -111.95495,-111.95494 0,0 0,-1e-5 0,-1e-5"
|
||||
sodipodi:ry="111.95494"
|
||||
sodipodi:rx="111.95494"
|
||||
sodipodi:cy="715.66132"
|
||||
sodipodi:cx="877.21655"
|
||||
id="path3845-5"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:40;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:open="true"
|
||||
sodipodi:end="3.1415927"
|
||||
sodipodi:start="1.5707963"
|
||||
transform="matrix(-1,0,0,-1,1456.4916,1473.8323)"
|
||||
d="m 877.21656,827.61626 c -61.83101,0 -111.95495,-50.12393 -111.95495,-111.95494 0,0 0,-1e-5 0,-1e-5"
|
||||
sodipodi:ry="111.95494"
|
||||
sodipodi:rx="111.95494"
|
||||
sodipodi:cy="715.66132"
|
||||
sodipodi:cx="877.21655"
|
||||
id="path3845-5-6"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:40;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:open="true"
|
||||
sodipodi:end="3.1415927"
|
||||
sodipodi:start="1.5707963"
|
||||
transform="matrix(0,1,-1,0,1518.9723,-118.89156)"
|
||||
d="m 877.21656,827.61626 c -61.83101,0 -111.95495,-50.12393 -111.95495,-111.95494 0,0 0,-1e-5 0,-1e-5"
|
||||
sodipodi:ry="111.95494"
|
||||
sodipodi:rx="111.95494"
|
||||
sodipodi:cy="715.66132"
|
||||
sodipodi:cx="877.21655"
|
||||
id="path3845-5-6-2"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:40;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
sodipodi:type="arc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.7 KiB |
17
icons/make.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
colors="red:#cc0000 green:#00cc00 orange:#ddaa00 grey:#cccccc"
|
||||
|
||||
for res in 16 32 64; do
|
||||
for color in ${colors}; do
|
||||
colname=${color%:*}
|
||||
colspec=${color#*:}
|
||||
convert -background none cf.svg \
|
||||
+level-colors "${colspec}," \
|
||||
-colorspace RGB \
|
||||
-resize "${res}" \
|
||||
-colorspace sRGB \
|
||||
"cf-${colname}-${res}.png"
|
||||
done
|
||||
done
|
||||
|
31
manifest.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Detect Cloudflare",
|
||||
"homepage_url": "https://git.massivebox.net/massivebox/cf-detect-chrome",
|
||||
"description": "Adds an icon to the toolbar which indicates whether the current page uses Cloudflare. If it does, the icon changes color. Detection is performed by analyzing the response headers of all requests.",
|
||||
"version": "0.7",
|
||||
"icons": {
|
||||
"16": "icons/cf-grey-16.png",
|
||||
"32": "icons/cf-grey-32.png",
|
||||
"64": "icons/cf-grey-64.png"
|
||||
},
|
||||
"permissions": [
|
||||
"webRequest",
|
||||
"webNavigation",
|
||||
"tabs",
|
||||
"<all_urls>"
|
||||
],
|
||||
"background": {
|
||||
"scripts": [ "background.js" ]
|
||||
},
|
||||
"browser_action": {
|
||||
"browser_style": true,
|
||||
"default_title": "Indicates whether this page uses Cloudflare",
|
||||
"default_icon": {
|
||||
"16": "icons/cf-grey-16.png",
|
||||
"32": "icons/cf-grey-32.png",
|
||||
"64": "icons/cf-grey-64.png"
|
||||
},
|
||||
"default_popup": "popup.html"
|
||||
}
|
||||
}
|
16
popup.css
Normal file
|
@ -0,0 +1,16 @@
|
|||
body {
|
||||
padding: 0em 1em;
|
||||
}
|
||||
|
||||
p#status {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin-top: -1ex;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.count {
|
||||
color: #cc0000;
|
||||
}
|
13
popup.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="popup.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="top">
|
||||
<p id="status">Detection Status.</p>
|
||||
</div>
|
||||
<script src="popup.js"></script>
|
||||
</body>
|
||||
</html>
|
54
popup.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
const statusText = {
|
||||
0: "No requests have been processed yet.",
|
||||
1: "No requests were served by Cloudflare.",
|
||||
2: "Requests for these domains were served by Cloudflare:",
|
||||
3: "Requests for these domains were served by Cloudflare:",
|
||||
99: "Detection result unavailable."
|
||||
};
|
||||
|
||||
var getTab = chrome.tabs.query( { active:true, currentWindow:true }, function(tabs){
|
||||
try {
|
||||
var tab = tabs[0];
|
||||
var port = chrome.runtime.connect();
|
||||
port.postMessage(tab.id);
|
||||
port.onMessage.addListener( function(msg) {
|
||||
port.disconnect();
|
||||
if (msg) {
|
||||
writeStatus(msg.result);
|
||||
populatePopup(msg.counts);
|
||||
} else {
|
||||
writeStatus(0);
|
||||
}
|
||||
});
|
||||
}catch (error){
|
||||
writeStatus(99);
|
||||
console.log(`CF-Detect-Popup: ${error}`);
|
||||
}
|
||||
});
|
||||
|
||||
function writeStatus( st ) {
|
||||
var p = document.getElementById("status");
|
||||
p.textContent = statusText[st];
|
||||
}
|
||||
|
||||
function populatePopup( domainCounts ) {
|
||||
var ndomain = 0;
|
||||
var div = document.getElementById("top");
|
||||
var ul = document.createElement("ul");
|
||||
for (var domain in domainCounts) {
|
||||
if (!domainCounts.hasOwnProperty(domain)) continue;
|
||||
++ndomain;
|
||||
var count = domainCounts[domain];
|
||||
var li = document.createElement("li");
|
||||
var text = document.createTextNode(`${domain}: `);
|
||||
var span = document.createElement("span");
|
||||
span.setAttribute("class", "count");
|
||||
span.textContent = `${count}`;
|
||||
li.appendChild(text);
|
||||
li.appendChild(span);
|
||||
ul.appendChild(li);
|
||||
}
|
||||
if (ndomain>0) div.appendChild(ul);
|
||||
}
|
||||
|
||||
// vim: set expandtab ts=4 sw=4 :
|