mirror of
https://github.com/docmost/docmost.git
synced 2025-11-10 05:02:06 +10:00
fix xss in generic iframe embed (#1419)
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
import { Node, mergeAttributes } from '@tiptap/core';
|
||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||
import { sanitizeUrl } from './utils';
|
||||
|
||||
export interface EmbedOptions {
|
||||
HTMLAttributes: Record<string, any>;
|
||||
@ -40,9 +41,12 @@ export const Embed = Node.create<EmbedOptions>({
|
||||
return {
|
||||
src: {
|
||||
default: '',
|
||||
parseHTML: (element) => element.getAttribute('data-src'),
|
||||
parseHTML: (element) => {
|
||||
const src = element.getAttribute('data-src');
|
||||
return sanitizeUrl(src);
|
||||
},
|
||||
renderHTML: (attributes: EmbedAttributes) => ({
|
||||
'data-src': attributes.src,
|
||||
'data-src': sanitizeUrl(attributes.src),
|
||||
}),
|
||||
},
|
||||
provider: {
|
||||
@ -85,6 +89,9 @@ export const Embed = Node.create<EmbedOptions>({
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
const src = HTMLAttributes["data-src"];
|
||||
const safeHref = sanitizeUrl(src);
|
||||
|
||||
return [
|
||||
"div",
|
||||
mergeAttributes(
|
||||
@ -95,10 +102,10 @@ export const Embed = Node.create<EmbedOptions>({
|
||||
[
|
||||
"a",
|
||||
{
|
||||
href: HTMLAttributes["data-src"],
|
||||
href: safeHref,
|
||||
target: "blank",
|
||||
},
|
||||
`${HTMLAttributes["data-src"]}`,
|
||||
safeHref,
|
||||
],
|
||||
];
|
||||
},
|
||||
@ -108,9 +115,15 @@ export const Embed = Node.create<EmbedOptions>({
|
||||
setEmbed:
|
||||
(attrs: EmbedAttributes) =>
|
||||
({ commands }) => {
|
||||
// Validate the URL before inserting
|
||||
const validatedAttrs = {
|
||||
...attrs,
|
||||
src: sanitizeUrl(attrs.src),
|
||||
};
|
||||
|
||||
return commands.insertContent({
|
||||
type: 'embed',
|
||||
attrs: attrs,
|
||||
attrs: validatedAttrs,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@ -4,6 +4,7 @@ import { Selection, Transaction } from "@tiptap/pm/state";
|
||||
import { CellSelection, TableMap } from "@tiptap/pm/tables";
|
||||
import { Node, ResolvedPos } from "@tiptap/pm/model";
|
||||
import Table from "@tiptap/extension-table";
|
||||
import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url";
|
||||
|
||||
export const isRectSelected = (rect: any) => (selection: CellSelection) => {
|
||||
const map = TableMap.get(selection.$anchorCell.node(-1));
|
||||
@ -379,3 +380,12 @@ export function setAttributes(
|
||||
export function icon(name: string) {
|
||||
return `<span class="ProseMirror-icon ProseMirror-icon-${name}"></span>`;
|
||||
}
|
||||
|
||||
export function sanitizeUrl(url: string | undefined): string {
|
||||
if (!url) return "";
|
||||
|
||||
const sanitized = braintreeSanitizeUrl(url);
|
||||
|
||||
// Return empty string instead of "about:blank"
|
||||
return sanitized === "about:blank" ? "" : sanitized;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user