mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-04-14 16:40:58 -04:00
fix: Gist embed allowing unsafe html (#7883)
This commit is contained in:
parent
f597bd3e01
commit
0ae9b383d6
3 changed files with 27 additions and 46 deletions
|
@ -1212,7 +1212,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
title="Excalidraw Embedded Content"
|
title="Excalidraw Embedded Content"
|
||||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||||
allowFullScreen={true}
|
allowFullScreen={true}
|
||||||
sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads"
|
sandbox={`${
|
||||||
|
src?.sandbox?.allowSameOrigin ? "allow-same-origin" : ""
|
||||||
|
} allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -18,20 +18,20 @@ const RE_YOUTUBE =
|
||||||
/^(?:http(?:s)?:\/\/)?(?:www\.)?youtu(?:be\.com|\.be)\/(embed\/|watch\?v=|shorts\/|playlist\?list=|embed\/videoseries\?list=)?([a-zA-Z0-9_-]+)(?:\?t=|&t=|\?start=|&start=)?([a-zA-Z0-9_-]+)?[^\s]*$/;
|
/^(?:http(?:s)?:\/\/)?(?:www\.)?youtu(?:be\.com|\.be)\/(embed\/|watch\?v=|shorts\/|playlist\?list=|embed\/videoseries\?list=)?([a-zA-Z0-9_-]+)(?:\?t=|&t=|\?start=|&start=)?([a-zA-Z0-9_-]+)?[^\s]*$/;
|
||||||
|
|
||||||
const RE_VIMEO =
|
const RE_VIMEO =
|
||||||
/^(?:http(?:s)?:\/\/)?(?:(?:w){3}.)?(?:player\.)?vimeo\.com\/(?:video\/)?([^?\s]+)(?:\?.*)?$/;
|
/^(?:http(?:s)?:\/\/)?(?:(?:w){3}\.)?(?:player\.)?vimeo\.com\/(?:video\/)?([^?\s]+)(?:\?.*)?$/;
|
||||||
const RE_FIGMA = /^https:\/\/(?:www\.)?figma\.com/;
|
const RE_FIGMA = /^https:\/\/(?:www\.)?figma\.com/;
|
||||||
|
|
||||||
const RE_GH_GIST = /^https:\/\/gist\.github\.com/;
|
const RE_GH_GIST = /^https:\/\/gist\.github\.com/;
|
||||||
const RE_GH_GIST_EMBED =
|
const RE_GH_GIST_EMBED =
|
||||||
/^<script[\s\S]*?\ssrc=["'](https:\/\/gist.github.com\/.*?)\.js["']/i;
|
/https?:\/\/gist\.github\.com\/([\w_-]+)\/([\w_-]+)\.js["']/i;
|
||||||
|
|
||||||
// not anchored to start to allow <blockquote> twitter embeds
|
// not anchored to start to allow <blockquote> twitter embeds
|
||||||
const RE_TWITTER = /(?:http(?:s)?:\/\/)?(?:(?:w){3}.)?(?:twitter|x).com/;
|
const RE_TWITTER = /(?:https?:\/\/)?(?:(?:w){3}\.)?(?:twitter|x)\.com/;
|
||||||
const RE_TWITTER_EMBED =
|
const RE_TWITTER_EMBED =
|
||||||
/^<blockquote[\s\S]*?\shref=["'](https:\/\/(?:twitter|x).com\/[^"']*)/i;
|
/^<blockquote[\s\S]*?\shref=["'](https?:\/\/(?:twitter|x)\.com\/[^"']*)/i;
|
||||||
|
|
||||||
const RE_VALTOWN =
|
const RE_VALTOWN =
|
||||||
/^https:\/\/(?:www\.)?val.town\/(v|embed)\/[a-zA-Z_$][0-9a-zA-Z_$]+\.[a-zA-Z_$][0-9a-zA-Z_$]+/;
|
/^https:\/\/(?:www\.)?val\.town\/(v|embed)\/[a-zA-Z_$][0-9a-zA-Z_$]+\.[a-zA-Z_$][0-9a-zA-Z_$]+/;
|
||||||
|
|
||||||
const RE_GENERIC_EMBED =
|
const RE_GENERIC_EMBED =
|
||||||
/^<(?:iframe|blockquote)[\s\S]*?\s(?:src|href)=["']([^"']*)["'][\s\S]*?>$/i;
|
/^<(?:iframe|blockquote)[\s\S]*?\s(?:src|href)=["']([^"']*)["'][\s\S]*?>$/i;
|
||||||
|
@ -153,43 +153,21 @@ export const getEmbedLink = (
|
||||||
// the embed srcdoc still supports twitter.com domain only
|
// the embed srcdoc still supports twitter.com domain only
|
||||||
link = link.replace(/\bx.com\b/, "twitter.com");
|
link = link.replace(/\bx.com\b/, "twitter.com");
|
||||||
|
|
||||||
let ret: IframeData;
|
const ret: IframeData = {
|
||||||
// assume embed code
|
|
||||||
if (/<blockquote/.test(link)) {
|
|
||||||
const srcDoc = createSrcDoc(link);
|
|
||||||
ret = {
|
|
||||||
type: "document",
|
|
||||||
srcdoc: () => srcDoc,
|
|
||||||
intrinsicSize: { w: 480, h: 480 },
|
|
||||||
};
|
|
||||||
// assume regular tweet url
|
|
||||||
} else {
|
|
||||||
ret = {
|
|
||||||
type: "document",
|
type: "document",
|
||||||
srcdoc: (theme: string) =>
|
srcdoc: (theme: string) =>
|
||||||
createSrcDoc(
|
createSrcDoc(
|
||||||
`<blockquote class="twitter-tweet" data-dnt="true" data-theme="${theme}"><a href="${link}"></a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>`,
|
`<blockquote class="twitter-tweet" data-dnt="true" data-theme="${theme}"><a href="${link}"></a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>`,
|
||||||
),
|
),
|
||||||
intrinsicSize: { w: 480, h: 480 },
|
intrinsicSize: { w: 480, h: 480 },
|
||||||
|
sandbox: { allowSameOrigin: true },
|
||||||
};
|
};
|
||||||
}
|
|
||||||
embeddedLinkCache.set(originalLink, ret);
|
embeddedLinkCache.set(originalLink, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RE_GH_GIST.test(link)) {
|
if (RE_GH_GIST.test(link)) {
|
||||||
let ret: IframeData;
|
const ret: IframeData = {
|
||||||
// assume embed code
|
|
||||||
if (/<script>/.test(link)) {
|
|
||||||
const srcDoc = createSrcDoc(link);
|
|
||||||
ret = {
|
|
||||||
type: "document",
|
|
||||||
srcdoc: () => srcDoc,
|
|
||||||
intrinsicSize: { w: 550, h: 720 },
|
|
||||||
};
|
|
||||||
// assume regular url
|
|
||||||
} else {
|
|
||||||
ret = {
|
|
||||||
type: "document",
|
type: "document",
|
||||||
srcdoc: () =>
|
srcdoc: () =>
|
||||||
createSrcDoc(`
|
createSrcDoc(`
|
||||||
|
@ -202,7 +180,6 @@ export const getEmbedLink = (
|
||||||
`),
|
`),
|
||||||
intrinsicSize: { w: 550, h: 720 },
|
intrinsicSize: { w: 550, h: 720 },
|
||||||
};
|
};
|
||||||
}
|
|
||||||
embeddedLinkCache.set(link, ret);
|
embeddedLinkCache.set(link, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -313,8 +290,8 @@ export const maybeParseEmbedSrc = (str: string): string => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const gistMatch = str.match(RE_GH_GIST_EMBED);
|
const gistMatch = str.match(RE_GH_GIST_EMBED);
|
||||||
if (gistMatch && gistMatch.length === 2) {
|
if (gistMatch && gistMatch.length === 3) {
|
||||||
return gistMatch[1];
|
return `https://gist.github.com/${gistMatch[1]}/${gistMatch[2]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RE_GIPHY.test(str)) {
|
if (RE_GIPHY.test(str)) {
|
||||||
|
@ -325,6 +302,7 @@ export const maybeParseEmbedSrc = (str: string): string => {
|
||||||
if (match && match.length === 2) {
|
if (match && match.length === 2) {
|
||||||
return match[1];
|
return match[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,7 @@ export type IframeData =
|
||||||
| {
|
| {
|
||||||
intrinsicSize: { w: number; h: number };
|
intrinsicSize: { w: number; h: number };
|
||||||
error?: Error;
|
error?: Error;
|
||||||
|
sandbox?: { allowSameOrigin?: boolean };
|
||||||
} & (
|
} & (
|
||||||
| { type: "video" | "generic"; link: string }
|
| { type: "video" | "generic"; link: string }
|
||||||
| { type: "document"; srcdoc: (theme: Theme) => string }
|
| { type: "document"; srcdoc: (theme: Theme) => string }
|
||||||
|
|
Loading…
Add table
Reference in a new issue