/** HTML escape */ function escapeHtml(unsafe) { return unsafe .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } /** Escape URL chars that could throw off the meta redirect tag */ function sanitizeUrl(unsafe) { return unsafe .replace(/;/g, "%3B"); } /** Remove the most risky characters from a filename string */ function cleanFilename(unsafe) { return unsafe .replace(/[/\\?*|"'<>:]+/g, " ") .replace(/\s+/g, " "); } browser.browserAction.onClicked.addListener((tab) => { const escapedUrl = escapeHtml(sanitizeUrl(tab.url)); const escapedTitle = escapeHtml(tab.title); const filename = cleanFilename(tab.title); const content = new Blob([ ` ${escapedTitle} Redirecting to: ${escapedUrl} `]); browser.downloads.download({ filename: `${filename}.link.html`, url: URL.createObjectURL(content) }); });