diff --git a/app/editor/components/LinkEditor.tsx b/app/editor/components/LinkEditor.tsx index f444f6279..e848cf1f0 100644 --- a/app/editor/components/LinkEditor.tsx +++ b/app/editor/components/LinkEditor.tsx @@ -11,7 +11,7 @@ import { setTextSelection } from "prosemirror-utils"; import { EditorView } from "prosemirror-view"; import * as React from "react"; import styled from "styled-components"; -import { isInternalUrl, sanitizeHref } from "@shared/utils/urls"; +import { isInternalUrl, sanitizeUrl } from "@shared/utils/urls"; import Flex from "~/components/Flex"; import { Dictionary } from "~/hooks/useDictionary"; import { ToastOptions } from "~/types"; @@ -70,7 +70,7 @@ class LinkEditor extends React.Component { }; get href(): string { - return sanitizeHref(this.props.mark?.attrs.href) ?? ""; + return sanitizeUrl(this.props.mark?.attrs.href) ?? ""; } get suggestedLinkTitle(): string { @@ -113,7 +113,7 @@ class LinkEditor extends React.Component { this.discardInputValue = true; const { from, to } = this.props; - href = sanitizeHref(href) ?? ""; + href = sanitizeUrl(href) ?? ""; this.props.onSelectLink({ href, title, from, to }); }; diff --git a/shared/editor/marks/Link.tsx b/shared/editor/marks/Link.tsx index da95ddb83..0fa6e2ead 100644 --- a/shared/editor/marks/Link.tsx +++ b/shared/editor/marks/Link.tsx @@ -13,7 +13,7 @@ import { EditorState, Plugin } from "prosemirror-state"; import { Decoration, DecorationSet } from "prosemirror-view"; import * as React from "react"; import ReactDOM from "react-dom"; -import { isExternalUrl, sanitizeHref } from "../../utils/urls"; +import { isExternalUrl, sanitizeUrl } from "../../utils/urls"; import findLinkNodes from "../queries/findLinkNodes"; import { EventType, Dispatch } from "../types"; import Mark from "./Mark"; @@ -80,7 +80,7 @@ export default class Link extends Mark { "a", { ...node.attrs, - href: sanitizeHref(node.attrs.href), + href: sanitizeUrl(node.attrs.href), rel: "noopener noreferrer nofollow", }, 0, diff --git a/shared/editor/nodes/Attachment.tsx b/shared/editor/nodes/Attachment.tsx index a86bd1d12..a6df3a5e5 100644 --- a/shared/editor/nodes/Attachment.tsx +++ b/shared/editor/nodes/Attachment.tsx @@ -4,7 +4,7 @@ import { NodeSpec, NodeType, Node as ProsemirrorNode } from "prosemirror-model"; import * as React from "react"; import { Trans } from "react-i18next"; import { bytesToHumanReadable } from "../../utils/files"; -import { sanitizeHref } from "../../utils/urls"; +import { sanitizeUrl } from "../../utils/urls"; import toggleWrap from "../commands/toggleWrap"; import FileExtension from "../components/FileExtension"; import Widget from "../components/Widget"; @@ -57,7 +57,7 @@ export default class Attachment extends Node { { class: `attachment`, id: node.attrs.id, - href: sanitizeHref(node.attrs.href), + href: sanitizeUrl(node.attrs.href), download: node.attrs.title, "data-size": node.attrs.size, }, diff --git a/shared/editor/nodes/Embed.tsx b/shared/editor/nodes/Embed.tsx index daf297176..7bc391ee9 100644 --- a/shared/editor/nodes/Embed.tsx +++ b/shared/editor/nodes/Embed.tsx @@ -2,7 +2,7 @@ import Token from "markdown-it/lib/token"; import { NodeSpec, NodeType, Node as ProsemirrorNode } from "prosemirror-model"; import { EditorState } from "prosemirror-state"; import * as React from "react"; -import { sanitizeHref } from "../../utils/urls"; +import { sanitizeUrl } from "../../utils/urls"; import DisabledEmbed from "../components/DisabledEmbed"; import { MarkdownSerializerState } from "../lib/markdown/serializer"; import embedsRule from "../rules/embeds"; @@ -50,7 +50,7 @@ export default class Embed extends Node { "iframe", { class: "embed", - src: sanitizeHref(node.attrs.href), + src: sanitizeUrl(node.attrs.href), contentEditable: "false", }, 0, diff --git a/shared/editor/nodes/Image.tsx b/shared/editor/nodes/Image.tsx index b1e3949ce..a6923f12e 100644 --- a/shared/editor/nodes/Image.tsx +++ b/shared/editor/nodes/Image.tsx @@ -12,6 +12,7 @@ import * as React from "react"; import ImageZoom from "react-medium-image-zoom"; import styled from "styled-components"; import { getDataTransferFiles, getEventFiles } from "../../utils/files"; +import { sanitizeUrl } from "../../utils/urls"; import { AttachmentValidation } from "../../validations"; import insertFiles, { Options } from "../commands/insertFiles"; import { MarkdownSerializerState } from "../lib/markdown/serializer"; @@ -197,7 +198,14 @@ export default class Image extends Node { { class: className, }, - ["img", { ...node.attrs, contentEditable: "false" }], + [ + "img", + { + ...node.attrs, + src: sanitizeUrl(node.attrs.src), + contentEditable: "false", + }, + ], ["p", { class: "caption" }, 0], ]; }, @@ -507,7 +515,7 @@ const ImageComponent = ( { diff --git a/shared/utils/urls.ts b/shared/utils/urls.ts index 640991116..06e5bc5d1 100644 --- a/shared/utils/urls.ts +++ b/shared/utils/urls.ts @@ -71,24 +71,24 @@ export function isExternalUrl(url: string) { } /** - * For use in the editor, this function will ensure that a link href is + * For use in the editor, this function will ensure that a url is * potentially valid, and filter out unsupported and malicious protocols. * - * @param href The href to sanitize + * @param url The url to sanitize * @returns The sanitized href */ -export function sanitizeHref(href: string | null | undefined) { - if (!href) { +export function sanitizeUrl(url: string | null | undefined) { + if (!url) { return undefined; } if ( - !isUrl(href) && - !href.startsWith("/") && - !href.startsWith("#") && - !href.startsWith("mailto:") + !isUrl(url) && + !url.startsWith("/") && + !url.startsWith("#") && + !url.startsWith("mailto:") ) { - return `https://${href}`; + return `https://${url}`; } - return href; + return url; }