handmade-revolt/src/lib/links.ts

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" };
}