fix: Disallow data: URI's for images
This commit is contained in:
@@ -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<Props, State> {
|
||||
};
|
||||
|
||||
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<Props, State> {
|
||||
|
||||
this.discardInputValue = true;
|
||||
const { from, to } = this.props;
|
||||
href = sanitizeHref(href) ?? "";
|
||||
href = sanitizeUrl(href) ?? "";
|
||||
|
||||
this.props.onSelectLink({ href, title, from, to });
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 = (
|
||||
</Button>
|
||||
<ImageZoom
|
||||
image={{
|
||||
src,
|
||||
src: sanitizeUrl(src) ?? "",
|
||||
alt,
|
||||
// @ts-expect-error type is incorrect, allows spreading all img props
|
||||
onLoad: (ev) => {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user