Files
outline/shared/utils/urls.ts
Fawzi E. Abdulfattah eb5126335c Improving the urls to not break protocols and adding tests (#3995)
* Improving the urls utils to not break dynamic protocols and testing the utils

Signed-off-by: iifawzi <iifawzie@gmail.com>

* Adding a list of blocked protocols

Signed-off-by: iifawzi <iifawzie@gmail.com>

* Update the way of sanitizing blocked protocols

Signed-off-by: iifawzi <iifawzie@gmail.com>

* Update shared/utils/urls.ts

Javascript pseudo protocol does not require the //

Co-authored-by: Tom Moor <tom.moor@gmail.com>

* updating the javascript protocol sanitizing tests

Signed-off-by: iifawzi <iifawzie@gmail.com>

* Update shared/utils/urls.test.ts

Co-authored-by: Apoorv Mishra <apoorvmishra101092@gmail.com>

* Update shared/utils/urls.ts

Co-authored-by: Apoorv Mishra <apoorvmishra101092@gmail.com>

* Using toBe instead of toEqual in tests

Signed-off-by: iifawzi <iifawzie@gmail.com>

* Sanitizing data: and vbscript:

Signed-off-by: iifawzi <iifawzie@gmail.com>

* Using toBeUndefined instead of toEqual in tests

Signed-off-by: iifawzi <iifawzie@gmail.com>

* Using URL to check the protocols

Signed-off-by: iifawzi <iifawzie@gmail.com>

* Allowing sms, fax, and tel protocols

Signed-off-by: iifawzi <iifawzie@gmail.com>

* Update shared/utils/urls.ts

inlining the protocols in the same file

Co-authored-by: Tom Moor <tom.moor@gmail.com>

* removing unused protocols constant

Signed-off-by: iifawzi <iifawzie@gmail.com>

Signed-off-by: iifawzi <iifawzie@gmail.com>
Co-authored-by: Tom Moor <tom.moor@gmail.com>
Co-authored-by: Apoorv Mishra <apoorvmishra101092@gmail.com>
2022-09-07 16:51:56 +05:30

111 lines
2.7 KiB
TypeScript

import { escapeRegExp } from "lodash";
import env from "../env";
import { parseDomain } from "./domains";
/**
* Prepends the CDN url to the given path (If a CDN is configured).
*
* @param path The path to prepend the CDN url to.
* @returns The path with the CDN url prepended.
*/
export function cdnPath(path: string): string {
return `${env.CDN_URL}${path}`;
}
/**
* Returns true if the given string is a link to inside the application.
*
* Important Note: If this is called server-side, it will always return false.
* The reason this is in a shared util is because it's used in an editor plugin
* which is also in the shared code
*
* @param url The url to check.
* @returns True if the url is internal, false otherwise.
*/
export function isInternalUrl(href: string) {
// empty strings are never internal
if (href === "") {
return false;
}
// relative paths are always internal
if (href[0] === "/") {
return true;
}
const outline =
typeof window !== "undefined"
? parseDomain(window.location.href)
: undefined;
const domain = parseDomain(href);
return outline?.host === domain.host;
}
/**
* Returns true if the given string is a url.
*
* @param url The url to check.
* @returns True if a url, false otherwise.
*/
export function isUrl(text: string) {
if (text.match(/\n/)) {
return false;
}
try {
const url = new URL(text);
const blockedProtocols = ["javascript:", "file:", "vbscript:", "data:"];
return url.hostname !== "" && !blockedProtocols.includes(url.protocol);
} catch (err) {
return false;
}
}
/**
* Returns true if the given string is a link to outside the application.
*
* @param url The url to check.
* @returns True if the url is external, false otherwise.
*/
export function isExternalUrl(url: string) {
return !!url && !isInternalUrl(url);
}
/**
* For use in the editor, this function will ensure that a url is
* potentially valid, and filter out unsupported and malicious protocols.
*
* @param url The url to sanitize
* @returns The sanitized href
*/
export function sanitizeUrl(url: string | null | undefined) {
if (!url) {
return undefined;
}
if (
!isUrl(url) &&
!url.startsWith("/") &&
!url.startsWith("#") &&
!url.startsWith("mailto:") &&
!url.startsWith("sms:") &&
!url.startsWith("fax:") &&
!url.startsWith("tel:")
) {
return `https://${url}`;
}
return url;
}
export function urlRegex(url: string | null | undefined): RegExp | undefined {
if (!url || !isUrl(url)) {
return undefined;
}
const urlObj = new URL(sanitizeUrl(url) as string);
return new RegExp(escapeRegExp(`${urlObj.protocol}//${urlObj.host}`));
}