diff options
author | V <v@anomalous.eu> | 2020-08-14 23:43:30 +0200 |
---|---|---|
committer | V <v@anomalous.eu> | 2020-08-14 23:43:30 +0200 |
commit | fb021e2cf43da42bfef11ebaa781388f1bb7613f (patch) | |
tree | 46c7d2daa3b761e14618c634259433693391d2a7 /content.js | |
download | email-protected-fb021e2cf43da42bfef11ebaa781388f1bb7613f.tar.zst |
Initial release (from .xpi) v0.1
Diffstat (limited to 'content.js')
-rw-r--r-- | content.js | 52 |
1 files changed, 52 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 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) +} |