From c02f7c9c859b23b87ab0296157085392a17de542 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 8 Jun 2024 10:54:55 -0400 Subject: [PATCH] Remove `gist.github.com`, `gitlab.com` from default CSP (#7008) --- package.json | 1 + server/routes/embeds.ts | 121 ++++++++++++++++++++ server/routes/index.ts | 4 + server/services/web.ts | 15 +-- shared/editor/components/Frame.tsx | 18 +-- shared/editor/embeds/Gist.tsx | 12 +- shared/editor/embeds/GitLabSnippet.tsx | 23 ++-- yarn.lock | 149 +++---------------------- 8 files changed, 156 insertions(+), 187 deletions(-) create mode 100644 server/routes/embeds.ts diff --git a/package.json b/package.json index 529b7d0d8..48358d833 100644 --- a/package.json +++ b/package.json @@ -259,6 +259,7 @@ "@types/diff": "^5.0.9", "@types/dotenv": "^8.2.0", "@types/emoji-regex": "^9.2.0", + "@types/escape-html": "^1.0.4", "@types/express-useragent": "^1.0.2", "@types/formidable": "^2.0.6", "@types/fs-extra": "^11.0.4", diff --git a/server/routes/embeds.ts b/server/routes/embeds.ts new file mode 100644 index 000000000..6a175d751 --- /dev/null +++ b/server/routes/embeds.ts @@ -0,0 +1,121 @@ +import escape from "escape-html"; +import { Context, Next } from "koa"; + +/** + * Resize observer script that sends a message to the parent window when content is resized. Inject + * this script into the iframe to receive resize events. + */ +const resizeObserverScript = ( + ctx: Context +) => ``; + +/** + * Script that checks if the iframe is being loaded in an iframe. If it is not, it redirects to the + * origin URL. + */ +const iframeCheckScript = ( + ctx: Context +) => ``; + +/** + * Render an embed for a GitLab or GitHub snippet, injecting the necessary scripts to handle resizing + * and iframe checks. + * + * @param ctx The koa context + * @param next The next middleware in the stack + * @returns The response body + */ +export const renderEmbed = async (ctx: Context, next: Next) => { + const url = escape(String(ctx.query.url)); + + if (!url) { + ctx.throw(400, "url is required"); + } + + let parsed; + try { + parsed = new URL(url); + } catch (err) { + ctx.throw(400, "Invalid URL provided"); + } + + if ( + parsed.host === "gitlab.com" && + parsed.protocol === "https:" && + ctx.path === "/embeds/gitlab" + ) { + const snippetLink = `${url}.js`; + const csp = ctx.response.get("Content-Security-Policy"); + + // Inject gitlab.com into the script-src and style-src directives + ctx.set( + "Content-Security-Policy", + csp + .replace("script-src", "script-src gitlab.com") + .replace("style-src", "style-src gitlab.com") + ); + ctx.set("X-Frame-Options", "sameorigin"); + + ctx.type = "html"; + ctx.body = ` + + + + +${iframeCheckScript(ctx)} + + + +${resizeObserverScript(ctx)} + +`; + return; + } + + if ( + parsed.host === "gist.github.com" && + parsed.protocol === "https:" && + ctx.path === "/embeds/github" + ) { + const id = parsed.pathname.split("/")[2]; + const gistLink = `https://gist.github.com/${id}.js`; + const csp = ctx.response.get("Content-Security-Policy"); + + // Inject GitHub domains into the script-src and style-src directives + ctx.set( + "Content-Security-Policy", + csp + .replace("script-src", "script-src gist.github.com") + .replace("style-src", "style-src github.githubassets.com") + ); + ctx.set("X-Frame-Options", "sameorigin"); + + ctx.type = "html"; + ctx.body = ` + + + + +${iframeCheckScript(ctx)} + + + +${resizeObserverScript(ctx)} + +`; + return; + } + + return next(); +}; diff --git a/server/routes/index.ts b/server/routes/index.ts index 50b0f1011..0a3d8f865 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -18,6 +18,7 @@ import { getTeamFromContext } from "@server/utils/passport"; import { robotsResponse } from "@server/utils/robots"; import apexRedirect from "../middlewares/apexRedirect"; import { renderApp, renderShare } from "./app"; +import { renderEmbed } from "./embeds"; import errors from "./errors"; const koa = new Koa(); @@ -128,6 +129,9 @@ router.get("/s/:shareId", shareDomains(), renderShare); router.get("/s/:shareId/doc/:documentSlug", shareDomains(), renderShare); router.get("/s/:shareId/*", shareDomains(), renderShare); +router.get("/embeds/gitlab", renderEmbed); +router.get("/embeds/github", renderEmbed); + // catch all for application router.get("*", shareDomains(), async (ctx, next) => { if (ctx.state?.rootShare) { diff --git a/server/services/web.ts b/server/services/web.ts index 76adabea4..d596e0d45 100644 --- a/server/services/web.ts +++ b/server/services/web.ts @@ -24,19 +24,8 @@ import auth from "../routes/auth"; // Construct scripts CSP based on services in use by this installation const defaultSrc = ["'self'"]; -const scriptSrc = [ - "'self'", - "gist.github.com", - "www.googletagmanager.com", - "gitlab.com", -]; - -const styleSrc = [ - "'self'", - "'unsafe-inline'", - "github.githubassets.com", - "gitlab.com", -]; +const scriptSrc = ["'self'", "www.googletagmanager.com"]; +const styleSrc = ["'self'", "'unsafe-inline'"]; if (env.isCloudHosted) { scriptSrc.push("cdn.zapier.com"); diff --git a/shared/editor/components/Frame.tsx b/shared/editor/components/Frame.tsx index dccb65cb4..91ee0ea25 100644 --- a/shared/editor/components/Frame.tsx +++ b/shared/editor/components/Frame.tsx @@ -26,8 +26,6 @@ type Props = Omit, "children"> & { height?: string; /** The allow policy of the frame */ allow?: string; - /** Whether to skip sanitization of the `src` prop */ - dangerouslySkipSanitizeSrc?: boolean; }; type PropsWithRef = Props & { @@ -69,7 +67,6 @@ class Frame extends React.Component { isSelected, referrerPolicy, className = "", - dangerouslySkipSanitizeSrc, src, } = this.props; const withBar = !!(icon || canonicalUrl); @@ -94,7 +91,7 @@ class Frame extends React.Component { frameBorder="0" title="embed" loading="lazy" - src={dangerouslySkipSanitizeSrc ? src : sanitizeUrl(src)} + src={sanitizeUrl(src)} referrerPolicy={referrerPolicy} allowFullScreen /> @@ -167,19 +164,6 @@ const Bar = styled.div` position: relative; `; -/** - * Resize observer script that sends a message to the parent window when content is resized. Inject - * this script into the iframe to receive resize events. - */ -export const resizeObserverScript = ``; - export default React.forwardRef((props, ref) => ( )); diff --git a/shared/editor/embeds/Gist.tsx b/shared/editor/embeds/Gist.tsx index 2592fb758..a8bf0c376 100644 --- a/shared/editor/embeds/Gist.tsx +++ b/shared/editor/embeds/Gist.tsx @@ -3,23 +3,13 @@ import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; function Gist(props: Props) { - const gistUrl = new URL(props.attrs.href); - const id = gistUrl.pathname.split("/")[2]; - const gistLink = `https://gist.github.com/${id}.js`; - const gistScript = ``; - const styles = - ""; - const iframeHtml = `${styles}${gistScript}`; - return ( ); } diff --git a/shared/editor/embeds/GitLabSnippet.tsx b/shared/editor/embeds/GitLabSnippet.tsx index 12031e290..fd967eeb0 100644 --- a/shared/editor/embeds/GitLabSnippet.tsx +++ b/shared/editor/embeds/GitLabSnippet.tsx @@ -1,21 +1,20 @@ import * as React from "react"; -import Frame, { resizeObserverScript } from "../components/Frame"; +import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; function GitLabSnippet(props: Props) { - const frame = React.useRef(null); + const frame = React.useRef(null); const [height, setHeight] = React.useState(400); - const snippetUrl = new URL(props.attrs.href); - const id = snippetUrl.pathname.split("/").pop(); - const snippetLink = `${snippetUrl}.js`; - const snippetScript = `${resizeObserverScript}`; - const styles = - ""; - const iframeHtml = `${styles}${snippetScript}`; React.useEffect(() => { const handler = (event: MessageEvent<{ type: string; value: number }>) => { - if (event.data.type === "frame-resized") { + const contentWindow = + frame.current?.contentWindow || + frame.current?.contentDocument?.defaultView; + if ( + event.data.type === "frame-resized" && + event.source === contentWindow + ) { setHeight(event.data.value); } }; @@ -27,13 +26,11 @@ function GitLabSnippet(props: Props) { return ( ); } diff --git a/yarn.lock b/yarn.lock index d2be8f3ee..217cc4984 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4082,18 +4082,7 @@ dependencies: tslib "^2.6.2" -"@smithy/config-resolver@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-3.0.0.tgz#d37b31e3202c5ce54d9bd2406dcde7c7b5073cbd" - integrity sha512-2GzOfADwYLQugYkKQhIyZyQlM05K+tMKvRnc6eFfZcpJGRfKoMUMYdPlBKmqHwQFXQKBrGV6cxL9oymWgDzvFw== - dependencies: - "@smithy/node-config-provider" "^3.0.0" - "@smithy/types" "^3.0.0" - "@smithy/util-config-provider" "^3.0.0" - "@smithy/util-middleware" "^3.0.0" - tslib "^2.6.2" - -"@smithy/config-resolver@^3.0.1": +"@smithy/config-resolver@^3.0.0", "@smithy/config-resolver@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-3.0.1.tgz#4e0917e5a02139ef978a1ed470543ab41dd3626b" integrity sha512-hbkYJc20SBDz2qqLzttjI/EqXemtmWk0ooRznLsiXp3066KQRTvuKHa7U4jCZCJq6Dozqvy0R1/vNESC9inPJg== @@ -4104,21 +4093,7 @@ "@smithy/util-middleware" "^3.0.0" tslib "^2.6.2" -"@smithy/core@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@smithy/core/-/core-2.0.1.tgz#8a7ac8faa0227912ce260bc3f976a5e254323920" - integrity sha512-rcMkjvwxH/bER+oZUPR0yTA0ELD6m3A+d92+CFkdF6HJFCBB1bXo7P5pm21L66XwTN01B6bUhSCQ7cymWRD8zg== - dependencies: - "@smithy/middleware-endpoint" "^3.0.0" - "@smithy/middleware-retry" "^3.0.1" - "@smithy/middleware-serde" "^3.0.0" - "@smithy/protocol-http" "^4.0.0" - "@smithy/smithy-client" "^3.0.1" - "@smithy/types" "^3.0.0" - "@smithy/util-middleware" "^3.0.0" - tslib "^2.6.2" - -"@smithy/core@^2.1.1": +"@smithy/core@^2.0.0", "@smithy/core@^2.1.1": version "2.1.1" resolved "https://registry.yarnpkg.com/@smithy/core/-/core-2.1.1.tgz#c5e50785f9f61cad85fbefafa402b1a87eff095a" integrity sha512-0vbIwwUcg0FMhTVJgMhbsRSAFL0rwduy/OQz7Xq1pJXJOyaGv+PGjj1iGawRlzBUPA5BkJv7S6q+YU2U8gk/WA== @@ -4132,18 +4107,7 @@ "@smithy/util-middleware" "^3.0.0" tslib "^2.6.2" -"@smithy/credential-provider-imds@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-3.0.0.tgz#a290eb0224ef045742e5c806685cf63d44a084f3" - integrity sha512-lfmBiFQcA3FsDAPxNfY0L7CawcWtbyWsBOHo34nF095728JLkBX4Y9q/VPPE2r7fqMVK+drmDigqE2/SSQeVRA== - dependencies: - "@smithy/node-config-provider" "^3.0.0" - "@smithy/property-provider" "^3.0.0" - "@smithy/types" "^3.0.0" - "@smithy/url-parser" "^3.0.0" - tslib "^2.6.2" - -"@smithy/credential-provider-imds@^3.1.0": +"@smithy/credential-provider-imds@^3.0.0", "@smithy/credential-provider-imds@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.0.tgz#7e58b78aa8de13dd04e94829241cd1cbde59b6d3" integrity sha512-q4A4d38v8pYYmseu/jTS3Z5I3zXlEOe5Obi+EJreVKgSVyWUHOd7/yaVCinC60QG4MRyCs98tcxBH1IMC0bu7Q== @@ -4285,22 +4249,7 @@ "@smithy/util-middleware" "^3.0.0" tslib "^2.6.2" -"@smithy/middleware-retry@^3.0.0", "@smithy/middleware-retry@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-3.0.1.tgz#167b75e9b79395f11a799f22030eaaf7d40da410" - integrity sha512-hBhSEuL841FhJBK/19WpaGk5YWSzFk/P2UaVjANGKRv3eYNO8Y1lANWgqnuPWjOyCEWMPr58vELFDWpxvRKANw== - dependencies: - "@smithy/node-config-provider" "^3.0.0" - "@smithy/protocol-http" "^4.0.0" - "@smithy/service-error-classification" "^3.0.0" - "@smithy/smithy-client" "^3.0.1" - "@smithy/types" "^3.0.0" - "@smithy/util-middleware" "^3.0.0" - "@smithy/util-retry" "^3.0.0" - tslib "^2.6.2" - uuid "^9.0.1" - -"@smithy/middleware-retry@^3.0.3": +"@smithy/middleware-retry@^3.0.0", "@smithy/middleware-retry@^3.0.1", "@smithy/middleware-retry@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-3.0.3.tgz#8e9af1c9db4bc8904d73126225211b42b562f961" integrity sha512-Wve1qzJb83VEU/6q+/I0cQdAkDnuzELC6IvIBwDzUEiGpKqXgX1v10FUuZGbRS6Ov/P+HHthcAoHOJZQvZNAkA== @@ -4331,17 +4280,7 @@ "@smithy/types" "^3.0.0" tslib "^2.6.2" -"@smithy/node-config-provider@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-3.0.0.tgz#4cd5dcf6132c75d6a582fcd6243482dac703865a" - integrity sha512-buqfaSdDh0zo62EPLf8rGDvcpKwGpO5ho4bXS2cdFhlOta7tBkWJt+O5uiaAeICfIOfPclNOndshDNSanX2X9g== - dependencies: - "@smithy/property-provider" "^3.0.0" - "@smithy/shared-ini-file-loader" "^3.0.0" - "@smithy/types" "^3.0.0" - tslib "^2.6.2" - -"@smithy/node-config-provider@^3.1.0": +"@smithy/node-config-provider@^3.0.0", "@smithy/node-config-provider@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-3.1.0.tgz#e962987c4e2e2b8b50397de5f4745eb21ee7bdbb" integrity sha512-ngfB8QItUfTFTfHMvKuc2g1W60V1urIgZHqD1JNFZC2tTWXahqf2XvKXqcBS7yZqR7GqkQQZy11y/lNOUWzq7Q== @@ -4362,15 +4301,7 @@ "@smithy/types" "^3.0.0" tslib "^2.6.2" -"@smithy/property-provider@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-3.0.0.tgz#ef7a26557c855cc1471b9aa0e05529183e99b978" - integrity sha512-LmbPgHBswdXCrkWWuUwBm9w72S2iLWyC/5jet9/Y9cGHtzqxi+GVjfCfahkvNV4KXEwgnH8EMpcrD9RUYe0eLQ== - dependencies: - "@smithy/types" "^3.0.0" - tslib "^2.6.2" - -"@smithy/property-provider@^3.1.0": +"@smithy/property-provider@^3.0.0", "@smithy/property-provider@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-3.1.0.tgz#b78d4964a1016b90331cc0c770b472160361fde7" integrity sha512-Tj3+oVhqdZgemjCiWjFlADfhvLF4C/uKDuKo7/tlEsRQ9+3emCreR2xndj970QSRSsiCEU8hZW3/8JQu+n5w4Q== @@ -4410,15 +4341,7 @@ dependencies: "@smithy/types" "^3.0.0" -"@smithy/shared-ini-file-loader@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.0.0.tgz#8739b7cd24f55fb4e276a74f00f0c2bb4e3f25d8" - integrity sha512-REVw6XauXk8xE4zo5aGL7Rz4ywA8qNMUn8RtWeTRQsgAlmlvbJ7CEPBcaXU2NDC3AYBgYAXrGyWD8XrN8UGDog== - dependencies: - "@smithy/types" "^3.0.0" - tslib "^2.6.2" - -"@smithy/shared-ini-file-loader@^3.1.0": +"@smithy/shared-ini-file-loader@^3.0.0", "@smithy/shared-ini-file-loader@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.0.tgz#a4cb9304c3be1c232ec661132ca88d177ac7a5b1" integrity sha512-dAM7wSX0NR3qTNyGVN/nwwpEDzfV9T/3AN2eABExWmda5VqZKSsjlINqomO5hjQWGv+IIkoXfs3u2vGSNz8+Rg== @@ -4439,19 +4362,7 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" -"@smithy/smithy-client@^3.0.0", "@smithy/smithy-client@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-3.0.1.tgz#c440473f6fb5dfbe86eaf015565fc56f66533bb4" - integrity sha512-KAiFY4Y4jdHxR+4zerH/VBhaFKM8pbaVmJZ/CWJRwtM/CmwzTfXfvYwf6GoUwiHepdv+lwiOXCuOl6UBDUEINw== - dependencies: - "@smithy/middleware-endpoint" "^3.0.0" - "@smithy/middleware-stack" "^3.0.0" - "@smithy/protocol-http" "^4.0.0" - "@smithy/types" "^3.0.0" - "@smithy/util-stream" "^3.0.1" - tslib "^2.6.2" - -"@smithy/smithy-client@^3.1.1": +"@smithy/smithy-client@^3.0.0", "@smithy/smithy-client@^3.0.1", "@smithy/smithy-client@^3.1.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-3.1.1.tgz#9aa770edd9b6277dc4124c924c617a436cdb670e" integrity sha512-tj4Ku7MpzZR8cmVuPcSbrLFVxmptWktmJMwST/uIEq4sarabEdF8CbmQdYB7uJ/X51Qq2EYwnRsoS7hdR4B7rA== @@ -4517,18 +4428,7 @@ dependencies: tslib "^2.6.2" -"@smithy/util-defaults-mode-browser@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.1.tgz#0ba33ec90f6dd311599bed3a3dd604f3adba9acd" - integrity sha512-nW5kEzdJn1Bn5TF+gOPHh2rcPli8JU9vSSXLbfg7uPnfR1TMRQqs9zlYRhIb87NeSxIbpdXOI94tvXSy+fvDYg== - dependencies: - "@smithy/property-provider" "^3.0.0" - "@smithy/smithy-client" "^3.0.1" - "@smithy/types" "^3.0.0" - bowser "^2.11.0" - tslib "^2.6.2" - -"@smithy/util-defaults-mode-browser@^3.0.3": +"@smithy/util-defaults-mode-browser@^3.0.0", "@smithy/util-defaults-mode-browser@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.3.tgz#6fff11a6c407ca1d5a1dc009768bd09271b199c2" integrity sha512-3DFON2bvXJAukJe+qFgPV/rorG7ZD3m4gjCXHD1V5z/tgKQp5MCTCLntrd686tX6tj8Uli3lefWXJudNg5WmCA== @@ -4539,20 +4439,7 @@ bowser "^2.11.0" tslib "^2.6.2" -"@smithy/util-defaults-mode-node@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.1.tgz#71242a6978240a6f559445d4cc26f2cce91c90e1" - integrity sha512-TFk+Qb+elLc/MOhtSp+50fstyfZ6avQbgH2d96xUBpeScu+Al9elxv+UFAjaTHe0HQe5n+wem8ZLpXvU8lwV6Q== - dependencies: - "@smithy/config-resolver" "^3.0.0" - "@smithy/credential-provider-imds" "^3.0.0" - "@smithy/node-config-provider" "^3.0.0" - "@smithy/property-provider" "^3.0.0" - "@smithy/smithy-client" "^3.0.1" - "@smithy/types" "^3.0.0" - tslib "^2.6.2" - -"@smithy/util-defaults-mode-node@^3.0.3": +"@smithy/util-defaults-mode-node@^3.0.0", "@smithy/util-defaults-mode-node@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.3.tgz#0b52ba9cb1138ee9076feba9a733462b2e2e6093" integrity sha512-D0b8GJXecT00baoSQ3Iieu3k3mZ7GY8w1zmg8pdogYrGvWJeLcIclqk2gbkG4K0DaBGWrO6v6r20iwIFfDYrmA== @@ -4565,16 +4452,7 @@ "@smithy/types" "^3.0.0" tslib "^2.6.2" -"@smithy/util-endpoints@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-2.0.0.tgz#5a16a723c1220f536a9b1b3e01787e69e77b6f12" - integrity sha512-+exaXzEY3DNt2qtA2OtRNSDlVrE4p32j1JSsQkzA5AdP0YtJNjkYbYhJxkFmPYcjI1abuwopOZCwUmv682QkiQ== - dependencies: - "@smithy/node-config-provider" "^3.0.0" - "@smithy/types" "^3.0.0" - tslib "^2.6.2" - -"@smithy/util-endpoints@^2.0.1": +"@smithy/util-endpoints@^2.0.0", "@smithy/util-endpoints@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-2.0.1.tgz#4ea8069bfbf3ebbcbe106b5156ff59a7a627b7dd" integrity sha512-ZRT0VCOnKlVohfoABMc8lWeQo/JEFuPWctfNRXgTHbyOVssMOLYFUNWukxxiHRGVAhV+n3c0kPW+zUqckjVPEA== @@ -4870,6 +4748,11 @@ dependencies: emoji-regex "*" +"@types/escape-html@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-1.0.4.tgz#dc7c166b76c7b03b27e32f80edf01d91eb5d9af2" + integrity sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg== + "@types/estree@0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"