|
|
|
/** HTML escape */
|
|
|
|
function escapeHtml(unsafe) {
|
|
|
|
return unsafe
|
|
|
|
.replace(/&/g, "&")
|
|
|
|
.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
|
|
|
|
*
|
|
|
|
* Firefox doesn't allow these: |"*?:<>
|
|
|
|
*/
|
|
|
|
function cleanFilename(unsafe) {
|
|
|
|
return unsafe
|
|
|
|
.replace(/::/g, " - ") // common delimiter (e.g. My Cool Article :: Website.com)
|
|
|
|
.replace(/[?*]+/g, " ") // this is just noise, drop it
|
|
|
|
.replace(/[\<\[]/g, "(")
|
|
|
|
.replace(/[\>\]]/g, ")")
|
|
|
|
.replace(/ :/g, " -")
|
|
|
|
.replace(/: /g, " ")
|
|
|
|
.replace(/:/g, "_")
|
|
|
|
.replace(/"/g, "'") // firefox hates double quote
|
|
|
|
.replace(/[/\\|]/g, "-") // porobable delimiters that should be kept in some form
|
|
|
|
.replace(/-+/g, "-") // collapse multiple hyphen (may result from substitutions)
|
|
|
|
.replace(/[\+=]/g, "_") // other suspicious stuff
|
|
|
|
.replace(/\s+/g, " ") // collapse multiple whitespace
|
|
|
|
.replace(/[\._,-]+$/g, "") // the filename should not end on special chars
|
|
|
|
.replace(/^[\._,-]+/g, "") // nor start
|
|
|
|
.trim();
|
|
|
|
}
|
|
|
|
|
|
|
|
browser.browserAction.onClicked.addListener((tab) => {
|
|
|
|
const escapedUrl = escapeHtml(sanitizeUrl(tab.url));
|
|
|
|
const escapedTitle = escapeHtml(tab.title);
|
|
|
|
const filename = cleanFilename(tab.title);
|
|
|
|
|
|
|
|
console.log(`Escaped URL: "${escapedUrl}"`);
|
|
|
|
console.log(`Escaped title: "${escapedTitle}"`);
|
|
|
|
console.log(`Saving as: "${filename}"`);
|
|
|
|
|
|
|
|
const html = `<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
|
|
<title>${escapedTitle}</title>
|
|
|
|
<meta http-equiv="refresh" content="0; url=${escapedUrl}">
|
|
|
|
<style>
|
|
|
|
body {
|
|
|
|
padding: 1em;
|
|
|
|
text-align: center;
|
|
|
|
font-family: sans-serif;
|
|
|
|
color:#aaa;
|
|
|
|
}
|
|
|
|
a, a:visited, a:hover, a:link {
|
|
|
|
color:#888;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
Redirecting to: <a href="${escapedUrl}">${escapedUrl}</a>
|
|
|
|
</body>
|
|
|
|
</html>
|
|
|
|
`;
|
|
|
|
|
|
|
|
const content = new Blob([html]);
|
|
|
|
|
|
|
|
//console.log(`Generated HTML:\n${html}`);
|
|
|
|
|
|
|
|
browser.downloads.download({
|
|
|
|
filename: `${filename}.link.html`,
|
|
|
|
url: URL.createObjectURL(content)
|
|
|
|
});
|
|
|
|
});
|