mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 08:17:26 +01:00
196 lines
5.2 KiB
JavaScript
196 lines
5.2 KiB
JavaScript
function loadFilterPrefs(key) {
|
|
try {
|
|
const raw = localStorage.getItem(key);
|
|
return raw ? JSON.parse(raw) : null;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function saveFilterPrefs(key, value) {
|
|
try {
|
|
localStorage.setItem(key, JSON.stringify(value));
|
|
} catch (e) {
|
|
/* localStorage unavailable or quota exceeded */
|
|
}
|
|
}
|
|
|
|
function encodePathForUrl(path) {
|
|
return String(path || "")
|
|
.split("/")
|
|
.map((segment) => encodeURIComponent(segment))
|
|
.join("/");
|
|
}
|
|
|
|
function humanFileSize(bytes, si = false, dp = 1) {
|
|
const thresh = si ? 1000 : 1024;
|
|
|
|
bytes = bytes / 8;
|
|
|
|
if (Math.abs(bytes) < thresh) {
|
|
return bytes + "B";
|
|
}
|
|
|
|
const units = si
|
|
? ["kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]
|
|
: ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
|
|
let u = -1;
|
|
const r = 10 ** dp;
|
|
|
|
do {
|
|
bytes /= thresh;
|
|
++u;
|
|
} while (
|
|
Math.round(Math.abs(bytes) * r) / r >= thresh &&
|
|
u < units.length - 1
|
|
);
|
|
|
|
return bytes.toFixed(dp) + "" + units[u];
|
|
}
|
|
|
|
function urlRel2abs(
|
|
url,
|
|
baseUrl = location.href.match(/^(.+)\/?(?:#.+)?$/)[0] + "/"
|
|
) {
|
|
/* Only accept commonly trusted protocols:
|
|
* Only data-image URLs are accepted, Exotic flavours (escaped slash,
|
|
* html-entitied characters) are not supported to keep the function fast.
|
|
* "javascript:" is intentionally NOT allowed — returning such a URL
|
|
* unchanged would let it reach an href attribute and execute on click
|
|
* (XSS, CWE-79). */
|
|
if (
|
|
/^(https?|file|ftps?|mailto|data:image\/[^;]{2,9};):/i.test(url)
|
|
) {
|
|
return url; //Url is already absolute
|
|
}
|
|
// Block any other explicit scheme (javascript:, vbscript:, data:text/html,
|
|
// …) so it can't slip through as an "absolute" URL via the relative-path
|
|
// handling below.
|
|
if (/^\s*[a-z][a-z0-9+.-]*:/i.test(url)) {
|
|
return "";
|
|
}
|
|
|
|
if (url.substring(0, 2) == "//") return location.protocol + url;
|
|
else if (url.charAt(0) == "/") return baseUrl + url;
|
|
// Strip the leading "./" so it concatenates cleanly with baseUrl. The old
|
|
// code prepended an extra "." here, which turned "./X" into "../X" and
|
|
// silently dropped one path segment — see #346.
|
|
else if (url.substring(0, 2) == "./") url = url.substring(2);
|
|
else if (/^\s*$/.test(url)) return "";
|
|
//Empty = Return nothing
|
|
|
|
url = baseUrl + url;
|
|
|
|
while (/\/\.\.\//.test((url = url.replace(/[^\/]+\/+\.\.\//g, ""))));
|
|
/* Escape certain characters to prevent XSS */
|
|
url = url
|
|
.replace(/\.$/, "")
|
|
.replace(/\/\.\//g, "")
|
|
.replace(/"/g, "%22")
|
|
.replace(/'/g, "%27")
|
|
.replace(/</g, "%3C")
|
|
.replace(/>/g, "%3E");
|
|
|
|
return url;
|
|
}
|
|
|
|
const charactersAttributes = "[^-a-z0-9:._]";
|
|
const allTagCharacters = "(?:[^>\"']*(?:\"[^\"]*\"|'[^']*'))*?[^>]*";
|
|
|
|
function by(baseUrl) {
|
|
return (match, group1, group2, group3) => {
|
|
/* Note that this function can also be used to remove links:
|
|
* return group1 + "javascript://" + group3; */
|
|
return group1 + urlRel2abs(group2, baseUrl) + group3;
|
|
};
|
|
}
|
|
|
|
function cr(html, selector, attribute, baseUrl) {
|
|
if (typeof selector == "string") selector = new RegExp(selector, "gi");
|
|
attribute = charactersAttributes + attribute;
|
|
const marker = "\\s*=\\s*";
|
|
const end = ")(";
|
|
var re1 = new RegExp("(" + attribute + marker + '")([^"]+)()', "gi");
|
|
var re2 = new RegExp("(" + attribute + marker + "')([^']+)()", "gi");
|
|
var re3 = new RegExp(
|
|
"(" + attribute + marker + ")([^\"'][^\\s>]*" + end + ")",
|
|
"gi"
|
|
);
|
|
html = html.replace(selector, function (match) {
|
|
return match
|
|
.replace(re1, by(baseUrl))
|
|
.replace(re2, by(baseUrl))
|
|
.replace(re3, by(baseUrl));
|
|
});
|
|
return html;
|
|
}
|
|
|
|
function contentAbs2Relative(content, baseUrl) {
|
|
if (!content) return content;
|
|
content = cr(
|
|
content,
|
|
"<" +
|
|
allTagCharacters +
|
|
charactersAttributes +
|
|
"href\\s*=" +
|
|
allTagCharacters +
|
|
">",
|
|
"href",
|
|
baseUrl
|
|
);
|
|
content = cr(
|
|
content,
|
|
"<" +
|
|
allTagCharacters +
|
|
charactersAttributes +
|
|
"src\\s*=" +
|
|
allTagCharacters +
|
|
">",
|
|
"src",
|
|
baseUrl
|
|
);
|
|
return content;
|
|
}
|
|
|
|
function generateRandomId(length) {
|
|
const alphabet = "ABCDEF0123456789";
|
|
let output = "";
|
|
for (let index = 0; index < length; index++) {
|
|
output += alphabet[Math.round(Math.random() * (alphabet.length - 1))];
|
|
}
|
|
return output;
|
|
}
|
|
|
|
function parseGithubUrl(url) {
|
|
if (!url) throw "Invalid url";
|
|
// Gist URLs: https://gist.github.com/<owner>/<gistId> or
|
|
// https://gist.github.com/<gistId>
|
|
const gistMatch = url.match(
|
|
/gist\.github\.com\/(?:(?<owner>[\w-\._]+)\/)?(?<gist>[a-fA-F0-9]+)/
|
|
);
|
|
if (gistMatch && gistMatch.groups.gist) {
|
|
return {
|
|
owner: gistMatch.groups.owner,
|
|
gistId: gistMatch.groups.gist,
|
|
};
|
|
}
|
|
const matches = url
|
|
.replace(/\.git(\/|$)/, "$1")
|
|
.match(
|
|
/.*?github.com\/(?<owner>[\w-\._]+)\/(?<repo>[\w-\._]+)(\/pull\/(?<PR>[0-9]+))?/
|
|
);
|
|
if (matches && matches.groups.owner && matches.groups.repo) {
|
|
return {
|
|
owner: matches.groups.owner,
|
|
repo: matches.groups.repo,
|
|
pullRequestId: matches.groups.PR,
|
|
};
|
|
} else {
|
|
throw "Invalid url";
|
|
}
|
|
}
|
|
|
|
function renderMD(md, baseUrlValue) {
|
|
return window.MarkdownRenderer.render(md || "", baseUrlValue);
|
|
}
|