diff --git a/shared/utils/urls.test.ts b/shared/utils/urls.test.ts index 62de14b0c..6d40aa5c6 100644 --- a/shared/utils/urls.test.ts +++ b/shared/utils/urls.test.ts @@ -2,13 +2,19 @@ import * as urlsUtils from "./urls"; import { urlRegex } from "./urls"; describe("IsUrl Method", () => { - describe("invalid urls", () => { - it("should return false", () => { - expect(urlsUtils.isUrl("")).toBe(false); - expect(urlsUtils.isUrl("#invalidurl")).toBe(false); - expect(urlsUtils.isUrl("mailto:")).toBe(false); - expect(urlsUtils.isUrl("://")).toBe(false); - }); + it("should return false for invalid url", () => { + expect(urlsUtils.isUrl("")).toBe(false); + expect(urlsUtils.isUrl("#invalidurl")).toBe(false); + expect(urlsUtils.isUrl("mailto:")).toBe(false); + expect(urlsUtils.isUrl("sms:")).toBe(false); + expect(urlsUtils.isUrl("://")).toBe(false); + }); + + it("should return true for valid urls", () => { + expect(urlsUtils.isUrl("http://example.com")).toBe(true); + expect(urlsUtils.isUrl("https://www.example.com")).toBe(true); + expect(urlsUtils.isUrl("seafile://openfile")).toBe(true); + expect(urlsUtils.isUrl("figma://launch")).toBe(true); }); }); diff --git a/shared/utils/urls.ts b/shared/utils/urls.ts index 7981ae9d3..3c6e64f9c 100644 --- a/shared/utils/urls.ts +++ b/shared/utils/urls.ts @@ -45,10 +45,11 @@ export function isInternalUrl(href: string) { /** * Returns true if the given string is a url. * - * @param url The url to check. + * @param text The url to check. + * @param options Parsing options. * @returns True if a url, false otherwise. */ -export function isUrl(text: string) { +export function isUrl(text: string, options?: { requireHostname: boolean }) { if (text.match(/\n/)) { return false; } @@ -57,7 +58,18 @@ export function isUrl(text: string) { const url = new URL(text); const blockedProtocols = ["javascript:", "file:", "vbscript:", "data:"]; - return url.hostname !== "" && !blockedProtocols.includes(url.protocol); + if (blockedProtocols.includes(url.protocol)) { + return false; + } + if (url.hostname) { + return true; + } + + return ( + url.protocol !== "" && + url.pathname.startsWith("//") && + !options?.requireHostname + ); } catch (err) { return false; } @@ -86,7 +98,7 @@ export function sanitizeUrl(url: string | null | undefined) { } if ( - !isUrl(url) && + !isUrl(url, { requireHostname: false }) && !url.startsWith("/") && !url.startsWith("#") && !url.startsWith("mailto:") &&