forked from abner/for-legacy-web
75 lines
1.4 KiB
TypeScript
75 lines
1.4 KiB
TypeScript
/**
|
|
* Type of link
|
|
*/
|
|
type LinkType =
|
|
| {
|
|
type: "navigate";
|
|
path: string;
|
|
}
|
|
| { type: "external"; href: string; url: URL }
|
|
| { type: "none" };
|
|
|
|
/**
|
|
* Allowed origins for relative navigation
|
|
*/
|
|
const ALLOWED_ORIGINS = [
|
|
location.hostname,
|
|
"app.revolt.chat",
|
|
"nightly.revolt.chat",
|
|
"local.revolt.chat",
|
|
];
|
|
|
|
/**
|
|
* Permissible protocols in URLs
|
|
*/
|
|
const PROTOCOL_WHITELIST = [
|
|
"http:",
|
|
"https:",
|
|
"ftp:",
|
|
"ftps:",
|
|
"mailto:",
|
|
"news:",
|
|
"irc:",
|
|
"gopher:",
|
|
"nntp:",
|
|
"feed:",
|
|
"telnet:",
|
|
"mms:",
|
|
"rtsp:",
|
|
"svn:",
|
|
"git:",
|
|
"tel:",
|
|
"fax:",
|
|
"xmpp:",
|
|
"magnet:",
|
|
];
|
|
|
|
/**
|
|
* Determine what kind of link we are dealing with and sanitise any malicious input
|
|
* @param href Input URL
|
|
* @returns Link Type
|
|
*/
|
|
export function determineLink(href?: string): LinkType {
|
|
let internal,
|
|
url: URL | null = null;
|
|
|
|
if (href) {
|
|
try {
|
|
url = new URL(href, location.href);
|
|
|
|
if (ALLOWED_ORIGINS.includes(url.hostname)) {
|
|
const path = url.pathname.replace(/[^A-z0-9/]/g, "");
|
|
return { type: "navigate", path };
|
|
}
|
|
} catch (err) {}
|
|
|
|
if (!internal && url) {
|
|
if (PROTOCOL_WHITELIST.includes(url.protocol)) {
|
|
return { type: "external", href, url };
|
|
}
|
|
}
|
|
}
|
|
|
|
return { type: "none" };
|
|
}
|