summary refs log tree commit diff
diff options
context:
space:
mode:
authorV <v@anomalous.eu>2020-08-14 23:43:30 +0200
committerV <v@anomalous.eu>2020-08-14 23:43:30 +0200
commitfb021e2cf43da42bfef11ebaa781388f1bb7613f (patch)
tree46c7d2daa3b761e14618c634259433693391d2a7
downloademail-protected-fb021e2cf43da42bfef11ebaa781388f1bb7613f.tar.zst
Initial release (from .xpi) v0.1
-rw-r--r--content.js52
-rw-r--r--icon.svg4
-rw-r--r--manifest.json21
3 files changed, 77 insertions, 0 deletions
diff --git a/content.js b/content.js
new file mode 100644
index 0000000..2329ae5
--- /dev/null
+++ b/content.js
@@ -0,0 +1,52 @@
+// shibboleth. decodes UTF-8 with an unholy combination of specific behaviour
+// https://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html
+function decodeUtf8(str) {
+  return decodeURIComponent(escape(str))
+}
+
+// decodes a string containing HTML entities
+function decodeHtml(str) {
+  let doc = new DOMParser().parseFromString(str, 'text/html')
+  return doc.documentElement.textContent
+}
+
+// decodes a "protected" "email"
+function decode(data) {
+  const [key, ...encoded] = data.match(/.{2}/g).map(e => parseInt(e, 16))
+  let bytes = encoded.map(e => String.fromCharCode(e ^ key)).join("")
+
+  // not sure why the proprietary code decodes entities, but I'm not changing it
+  return decodeHtml(decodeUtf8(bytes))
+}
+
+// processes a document fragment for "protected" "emails"
+function process(root) {
+  // mailto links
+  // format: <a href="/cdn-cgi/l/email-protection#{encrypted data}">...</a>
+  for (const node of root.querySelectorAll('a')) {
+    const url = new URL(node.href)
+    if (url.pathname === '/cdn-cgi/l/email-protection' && url.hash !== '')
+      node.href = `mailto:${decode(url.hash.slice(1))}`
+  }
+
+  // everything else Cloudflare thinks is an email
+  // format: <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="{encrypted data}">[email&#160;protected]</a>
+  for (const node of root.querySelectorAll('.__cf_email__'))
+    node.replaceWith(decode(node.getAttribute('data-cfemail')))
+
+  // <template> contents are not considered children of the element itself, so we
+  // need to recurse into them. I highly doubt this will ever come up in the wild,
+  // but since the proprietary code takes care of this edge-case, so should we.
+  for (const node of root.querySelectorAll('template'))
+    process(node.content)
+}
+
+// check for the presence of the Cloudflare deobfuscation script.
+// it doesn't make sense to run our stuff if this isn't in the page
+// format: <script data-cfasync="false" src="/cdn-cgi/scripts/71a88165/cloudflare-static/email-decode.min.js"></script>
+// (the hexadecimal part can change)
+let scripts = document.querySelectorAll('script[src$="/cloudflare-static/email-decode.min.js"]')
+if (scripts !== null) {
+  scripts.forEach(e => e.remove())
+  process(document)
+}
diff --git a/icon.svg b/icon.svg
new file mode 100644
index 0000000..984ac72
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 48 48" width="48" height="48">
+  <rect x="0" y="0" width="48" height="48" fill="black" />
+  <path d="m 20.8,9.2400001 h 3.28 q 3.24,0 3.56,0.04 2.24,0.36 3.8,1.9199999 0.6,0.6 0.96,1.2 0.72,1.16 0.96,2.6 l 0.08,0.28 v 9.08 L 33.4,33.8 q -0.28,2 -1.72,3.4 -1.28,1.24 -3.12,1.56 H 27.04 26.96 Q 25.4,38.52 24.28,37.6 24.04,37.44 24,37.4 l -0.24,0.16 q -1.16,0.92 -2.72,1.2 h -1.52 q -0.08,0 -0.12,0 -1.8,-0.32 -3.12,-1.56 -1.44,-1.4 -1.68,-3.4 -0.04,-0.36 -0.04,-4.16 0,-3.8 0.04,-4.16 0.24,-1.92 1.56,-3.28 1.32,-1.36 3.24,-1.64 0.28,-0.08 2.6,-0.08 h 2.36 l 0.2,0.08 q 0.96,0.32 1.28,1.32 l 0.04,0.2 v 5.68 l 0.04,5.72 0.08,0.2 q 0.12,0.36 0.32,0.6 0.24,0.32 0.64,0.48 0.36,0.2 0.8,0.2 0.44,0 0.8,-0.2 0.68,-0.32 0.96,-1.08 l 0.08,-0.2 V 24.64 15.6 Q 29.4,14 27.92,13.32 L 27.64,13.2 Q 27.2,13.04 24.56,13.04 h -0.44 l -3.16,0.04 q -1.44,0.16 -2.52,1.64 -0.08,0.16 -0.2,0.32 -0.28,0.48 -0.44,0.68 -0.4,0.4 -0.96,0.52 L 16.04,16.2 Q 15,15.96 14.64,14.96 14.56,14.72 14.56,14.44 l 0.08,-0.72 q 0.04,-0.12 0.12,-0.28 0.32,-0.64 0.88,-1.32 0.6,-0.76 1.32,-1.32 1.72,-1.3599999 3.84,-1.5599999 z M 22.04,28.88 22.08,24.32 h -1.04 q -1,0 -1.12,0.04 -0.12,0 -0.32,0.08 -0.88,0.28 -1.16,1.24 l -0.04,0.16 v 3.8 3.84 l 0.08,0.2 q 0.28,0.88 1.08,1.16 0.6,0.24 1.2,0.04 0.32,-0.12 0.6,-0.32 0.44,-0.32 0.64,-0.92 l 0.04,-0.16 z" fill="white" />
+</svg>
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..7411910
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,21 @@
+{
+	"manifest_version": 2,
+
+	"name": "[email protected]",
+	"version": "0.1",
+
+	"description": "Deobfuscate e-mail addresses \"protected\" by Cloudflare",
+
+	"icons": {
+		"48": "icon.svg",
+		"96": "icon.svg"
+	},
+
+	"content_scripts": [
+		{
+			"matches": [ "*://*/*" ],
+			"js": [ "content.js" ],
+			"run_at": "document_end"
+		}
+	]
+}