Last active
January 19, 2025 10:54
-
-
Save warrenseine/31129f9206f5fd82861944d5ff1a6189 to your computer and use it in GitHub Desktop.
Remove Proofpoint redirections from Outlook
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Remove Proofpoint | |
| // @namespace http://tampermonkey.net/ | |
| // @version 2025-01-19 | |
| // @description Replace Proofpoint links with the target directly | |
| // @author Warren Seine | |
| // @match https://outlook.office.com/mail/* | |
| // @icon https://res.public.onecdn.static.microsoft/owamail/20241011003.19/resources/images/favicons/mail-seen.ico | |
| // @downloadURL https://gist.github.com/warrenseine/31129f9206f5fd82861944d5ff1a6189/raw/remove-proofpoint.user.js | |
| // @updateURL https://gist.github.com/warrenseine/31129f9206f5fd82861944d5ff1a6189/raw/remove-proofpoint.user.js | |
| // @grant none | |
| // ==/UserScript== | |
| // ChatGPT-transformed and edited version of https://help.proofpoint.com/@api/deki/files/2775/urldecoder.py | |
| class URLDefenseDecoder { | |
| constructor() { | |
| this.udPattern = /https:\/\/urldefense(?:\.proofpoint)?\.com\/(v[0-9])\//; | |
| this.v1Pattern = /u=(?<url>.+?)&k=/; | |
| this.v2Pattern = /u=(?<url>.+?)&[dc]=/; | |
| this.v3Pattern = /v3\/__(?<url>.+?)__;(?<encBytes>.*?)!/; | |
| this.v3TokenPattern = /\*(\*.)?/g; | |
| this.v3SingleSlash = /^([a-z0-9+.-]+:\/)([^/].+)/i; | |
| this.v3RunMapping = {}; | |
| const runValues = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | |
| let runLength = 2; | |
| for (const value of runValues) { | |
| this.v3RunMapping[value] = runLength++; | |
| } | |
| } | |
| decode(rewrittenUrl) { | |
| const match = this.udPattern.exec(rewrittenUrl); | |
| if (match) { | |
| switch (match[1]) { | |
| case "v1": | |
| return this.decodeV1(rewrittenUrl); | |
| case "v2": | |
| return this.decodeV2(rewrittenUrl); | |
| case "v3": | |
| return this.decodeV3(rewrittenUrl); | |
| default: | |
| throw new Error(`Unrecognized version in: ${rewrittenUrl}`); | |
| } | |
| } | |
| } | |
| decodeV1(rewrittenUrl) { | |
| const match = this.v1Pattern.exec(rewrittenUrl); | |
| if (match) { | |
| const urlEncodedUrl = match.groups.url; | |
| const htmlEncodedUrl = decodeURIComponent(urlEncodedUrl); | |
| return this.unescapeHtml(htmlEncodedUrl); | |
| } else { | |
| throw new Error("Error parsing URL"); | |
| } | |
| } | |
| decodeV2(rewrittenUrl) { | |
| const match = this.v2Pattern.exec(rewrittenUrl); | |
| if (match) { | |
| const specialEncodedUrl = match.groups.url; | |
| const urlEncodedUrl = specialEncodedUrl.replace(/-/g, '%').replace(/_/g, '/'); | |
| const htmlEncodedUrl = decodeURIComponent(urlEncodedUrl); | |
| return this.unescapeHtml(htmlEncodedUrl); | |
| } else { | |
| throw new Error("Error parsing URL"); | |
| } | |
| } | |
| decodeV3(rewrittenUrl) { | |
| const match = this.v3Pattern.exec(rewrittenUrl); | |
| if (match) { | |
| let url = match.groups.url; | |
| const singleSlash = this.v3SingleSlash.exec(url); | |
| if (singleSlash && singleSlash.length === 3) { | |
| url = `${singleSlash[1]}/${singleSlash[2]}`; | |
| } | |
| const encodedUrl = decodeURIComponent(url); | |
| if (!match.groups.encBytes) return encodedUrl; | |
| const encBytes = match.groups.encBytes; | |
| const decBytes = this.decodeBase64(encBytes.replace(/-/g, '+').replace(/_/g, '/')); | |
| let currentMarker = 0; | |
| const replaceToken = (token) => { | |
| if (token === '*') { | |
| return decBytes[currentMarker++]; | |
| } | |
| if (token.startsWith('**')) { | |
| const runLength = this.v3RunMapping[token[token.length - 1]]; | |
| const run = decBytes.substring(currentMarker, currentMarker + runLength); | |
| currentMarker += runLength; | |
| return run; | |
| } | |
| return token; | |
| }; | |
| const substituteTokens = (text) => { | |
| return text.replace(this.v3TokenPattern, (match) => replaceToken(match)); | |
| }; | |
| return substituteTokens(encodedUrl); | |
| } else { | |
| throw new Error("Error parsing URL"); | |
| } | |
| } | |
| decodeBase64(s) { | |
| try { | |
| return atob(s) | |
| } catch (e) { | |
| try { | |
| return atob(s + '=') | |
| } catch (e) { | |
| return atob(s + '==') | |
| } | |
| } | |
| } | |
| unescapeHtml(str) { | |
| const doc = new DOMParser().parseFromString(str, "text/html"); | |
| return doc.documentElement.textContent; | |
| } | |
| } | |
| (function() { | |
| 'use strict'; | |
| const decoder = new URLDefenseDecoder(); | |
| setInterval(() => { | |
| const links = document.querySelectorAll('a'); | |
| links.forEach(link => { | |
| // Example usage in the browser | |
| try { | |
| const url = decoder.decode(link.href); | |
| if (!url) return | |
| let newLink = link.cloneNode(true); | |
| newLink.href = url; | |
| newLink.title = url; | |
| link.replaceWith(newLink); | |
| } catch (err) { | |
| console.error(err); | |
| } | |
| }); | |
| }, 1000); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment