From 294521f1624fdc4617150d4fa128146e7057013b Mon Sep 17 00:00:00 2001 From: Apoorv Mishra Date: Tue, 2 Aug 2022 14:10:11 +0530 Subject: [PATCH] fix: Escape regex for embeds (#3907) Fixes #3899 --- shared/editor/embeds/Abstract.test.ts | 4 ++++ shared/editor/embeds/Abstract.tsx | 4 ++-- shared/editor/embeds/ClickUp.test.ts | 2 ++ shared/editor/embeds/ClickUp.tsx | 2 +- shared/editor/embeds/Descript.test.ts | 10 ++++++++++ shared/editor/embeds/Descript.tsx | 2 +- shared/editor/embeds/Figma.test.ts | 6 ++++++ shared/editor/embeds/Figma.tsx | 2 +- shared/editor/embeds/Gist.test.ts | 10 ++++++++++ shared/editor/embeds/Gist.tsx | 2 +- shared/editor/embeds/Gliffy.test.ts | 14 ++++++++++++++ shared/editor/embeds/Gliffy.tsx | 2 +- shared/editor/embeds/GoogleCalendar.test.ts | 10 ++++++++++ shared/editor/embeds/GoogleCalendar.tsx | 2 +- shared/editor/embeds/GoogleDataStudio.test.ts | 10 ++++++++++ shared/editor/embeds/GoogleDataStudio.tsx | 2 +- shared/editor/embeds/GoogleDocs.test.ts | 10 ++++++++++ shared/editor/embeds/GoogleDocs.tsx | 2 +- shared/editor/embeds/GoogleDrawings.test.ts | 10 ++++++++++ shared/editor/embeds/GoogleDrawings.tsx | 2 +- shared/editor/embeds/GoogleDrive.test.ts | 10 ++++++++++ shared/editor/embeds/GoogleDrive.tsx | 2 +- shared/editor/embeds/GoogleSheets.test.ts | 10 ++++++++++ shared/editor/embeds/GoogleSheets.tsx | 4 +++- shared/editor/embeds/GoogleSlides.test.ts | 10 ++++++++++ shared/editor/embeds/GoogleSlides.tsx | 4 +++- shared/editor/embeds/JSFiddle.test.ts | 11 +++++++++++ shared/editor/embeds/JSFiddle.tsx | 2 +- shared/editor/embeds/Loom.test.ts | 3 +++ shared/editor/embeds/Loom.tsx | 2 +- shared/editor/embeds/Marvel.test.ts | 1 + shared/editor/embeds/Marvel.tsx | 2 +- shared/editor/embeds/Mindmeister.test.ts | 12 ++++++++++++ shared/editor/embeds/Mindmeister.tsx | 2 +- shared/editor/embeds/Miro.test.ts | 3 +++ shared/editor/embeds/Miro.tsx | 2 +- shared/editor/embeds/ModeAnalytics.test.ts | 6 ++++++ shared/editor/embeds/ModeAnalytics.tsx | 2 +- shared/editor/embeds/Otter.test.ts | 9 +++++++++ shared/editor/embeds/Otter.tsx | 2 +- shared/editor/embeds/Pitch.test.ts | 18 ++++++++++++++++++ shared/editor/embeds/Pitch.tsx | 2 +- shared/editor/embeds/Prezi.test.ts | 3 +++ shared/editor/embeds/Prezi.tsx | 2 +- shared/editor/embeds/Spotify.test.ts | 10 ++++++++++ shared/editor/embeds/Spotify.tsx | 2 +- shared/editor/embeds/Tldraw.test.ts | 10 ++++++++++ shared/editor/embeds/Tldraw.tsx | 2 +- shared/editor/embeds/Trello.test.ts | 9 +++++++++ shared/editor/embeds/Trello.tsx | 2 +- shared/editor/embeds/Typeform.test.ts | 2 ++ shared/editor/embeds/Typeform.tsx | 2 +- shared/editor/embeds/Vimeo.test.ts | 1 + shared/editor/embeds/Vimeo.tsx | 2 +- shared/editor/embeds/Whimsical.test.ts | 9 +++++++++ shared/editor/embeds/Whimsical.tsx | 2 +- 56 files changed, 256 insertions(+), 29 deletions(-) create mode 100644 shared/editor/embeds/Descript.test.ts create mode 100644 shared/editor/embeds/Gliffy.test.ts create mode 100644 shared/editor/embeds/JSFiddle.test.ts create mode 100644 shared/editor/embeds/Otter.test.ts create mode 100644 shared/editor/embeds/Pitch.test.ts create mode 100644 shared/editor/embeds/Tldraw.test.ts create mode 100644 shared/editor/embeds/Trello.test.ts create mode 100644 shared/editor/embeds/Whimsical.test.ts diff --git a/shared/editor/embeds/Abstract.test.ts b/shared/editor/embeds/Abstract.test.ts index 84dc2459f..e70d352d1 100644 --- a/shared/editor/embeds/Abstract.test.ts +++ b/shared/editor/embeds/Abstract.test.ts @@ -44,6 +44,10 @@ describe("Abstract", () => { }); test("to not be enabled elsewhere", () => { + expect("https://sharedgoabstract.com/f473".match(match)).toBe(null); + expect("https://share.goabstractacom/f473".match(match)).toBe(null); + expect("https://app1goabstract.com/share/f473".match(match2)).toBe(null); + expect("https://app.goabstractacom/share/f473".match(match2)).toBe(null); expect("https://abstract.com".match(match)).toBe(null); expect("https://goabstract.com".match(match)).toBe(null); expect("https://app.goabstract.com".match(match)).toBe(null); diff --git a/shared/editor/embeds/Abstract.tsx b/shared/editor/embeds/Abstract.tsx index 28f01a850..100858443 100644 --- a/shared/editor/embeds/Abstract.tsx +++ b/shared/editor/embeds/Abstract.tsx @@ -4,8 +4,8 @@ import { EmbedProps as Props } from "."; export default class Abstract extends React.Component { static ENABLED = [ - new RegExp("https?://share.(?:go)?abstract.com/(.*)$"), - new RegExp("https?://app.(?:go)?abstract.com/(?:share|embed)/(.*)$"), + new RegExp("https?://share\\.(?:go)?abstract\\.com/(.*)$"), + new RegExp("https?://app\\.(?:go)?abstract\\.com/(?:share|embed)/(.*)$"), ]; render() { diff --git a/shared/editor/embeds/ClickUp.test.ts b/shared/editor/embeds/ClickUp.test.ts index afd6416e7..6b5f3645b 100644 --- a/shared/editor/embeds/ClickUp.test.ts +++ b/shared/editor/embeds/ClickUp.test.ts @@ -11,6 +11,8 @@ describe("ClickUp", () => { test("to not be enabled elsewhere", () => { expect("https://share.clickup.com".match(match)).toBe(null); + expect("https://sharedclickup.com/a/b/c/d".match(match)).toBe(null); + expect("https://share.clickupdcom/a/b/c/d".match(match)).toBe(null); expect("https://clickup.com/".match(match)).toBe(null); expect("https://clickup.com/features".match(match)).toBe(null); }); diff --git a/shared/editor/embeds/ClickUp.tsx b/shared/editor/embeds/ClickUp.tsx index a5b71daab..385e8e3bd 100644 --- a/shared/editor/embeds/ClickUp.tsx +++ b/shared/editor/embeds/ClickUp.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "^https?://share.clickup.com/[a-z]/[a-z]/(.*)/(.*)$" + "^https?://share\\.clickup\\.com/[a-z]/[a-z]/(.*)/(.*)$" ); export default class ClickUp extends React.Component { diff --git a/shared/editor/embeds/Descript.test.ts b/shared/editor/embeds/Descript.test.ts new file mode 100644 index 000000000..0bf1610c8 --- /dev/null +++ b/shared/editor/embeds/Descript.test.ts @@ -0,0 +1,10 @@ +import Descript from "./Descript"; + +describe("Descript", () => { + const match = Descript.ENABLED[0]; + + test("to not be enabled elsewhere", () => { + expect("https://shareddescript.com/view/c9d8".match(match)).toBe(null); + expect("https://share.descriptdcom/view/c9d8".match(match)).toBe(null); + }); +}); diff --git a/shared/editor/embeds/Descript.tsx b/shared/editor/embeds/Descript.tsx index 32a0de8c8..aef9c4f13 100644 --- a/shared/editor/embeds/Descript.tsx +++ b/shared/editor/embeds/Descript.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; export default class Descript extends React.Component { - static ENABLED = [new RegExp("https?://share.descript.com/view/(\\w+)$")]; + static ENABLED = [new RegExp("https?://share\\.descript\\.com/view/(\\w+)$")]; render() { const { matches } = this.props.attrs; diff --git a/shared/editor/embeds/Figma.test.ts b/shared/editor/embeds/Figma.test.ts index 629245ab1..1e915d6cd 100644 --- a/shared/editor/embeds/Figma.test.ts +++ b/shared/editor/embeds/Figma.test.ts @@ -18,5 +18,11 @@ describe("Figma", () => { test("to not be enabled elsewhere", () => { expect("https://www.figma.com".match(match)).toBe(null); expect("https://www.figma.com/features".match(match)).toBe(null); + expect( + "https://wwww.figmaacom/file/LKQ4FJ4bTnCSjedbRpk931".match(match) + ).toBe(null); + expect( + "https://wwwwfigma.com/file/LKQ4FJ4bTnCSjedbRpk931".match(match) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/Figma.tsx b/shared/editor/embeds/Figma.tsx index 355bfc1c8..84cc23330 100644 --- a/shared/editor/embeds/Figma.tsx +++ b/shared/editor/embeds/Figma.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "https://([w.-]+.)?figma.com/(file|proto)/([0-9a-zA-Z]{22,128})(?:/.*)?$" + "https://([w.-]+\\.)?figma\\.com/(file|proto)/([0-9a-zA-Z]{22,128})(?:/.*)?$" ); export default class Figma extends React.Component { diff --git a/shared/editor/embeds/Gist.test.ts b/shared/editor/embeds/Gist.test.ts index 3208c0e18..314d3f941 100644 --- a/shared/editor/embeds/Gist.test.ts +++ b/shared/editor/embeds/Gist.test.ts @@ -22,6 +22,16 @@ describe("Gist", () => { }); test("to not be enabled elsewhere", () => { + expect( + "https://gistigithub.com/n3n/eb51ada6308b539d388c8ff97711adfa".match( + match + ) + ).toBe(null); + expect( + "https://gist.githubbcom/n3n/eb51ada6308b539d388c8ff97711adfa".match( + match + ) + ).toBe(null); expect("https://gist.github.com/tommoor".match(match)).toBe(null); }); }); diff --git a/shared/editor/embeds/Gist.tsx b/shared/editor/embeds/Gist.tsx index edf56a943..8c333c165 100644 --- a/shared/editor/embeds/Gist.tsx +++ b/shared/editor/embeds/Gist.tsx @@ -3,7 +3,7 @@ import styled from "styled-components"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "^https://gist.github.com/([a-zA-Z\\d](?:[a-zA-Z\\d]|-(?=[a-zA-Z\\d])){0,38})/(.*)$" + "^https://gist\\.github\\.com/([a-zA-Z\\d](?:[a-zA-Z\\d]|-(?=[a-zA-Z\\d])){0,38})/(.*)$" ); class Gist extends React.Component { diff --git a/shared/editor/embeds/Gliffy.test.ts b/shared/editor/embeds/Gliffy.test.ts new file mode 100644 index 000000000..fe72fc4ff --- /dev/null +++ b/shared/editor/embeds/Gliffy.test.ts @@ -0,0 +1,14 @@ +import Gliffy from "./Gliffy"; + +describe("Gliffy", () => { + const match = Gliffy.ENABLED[0]; + + test("to not be enabled elsewhere", () => { + expect("https://gotgliffy.com/go/share/c9d837d74182317".match(match)).toBe( + null + ); + expect("https://go.gliffyycom/go/share/c9d837d74182317".match(match)).toBe( + null + ); + }); +}); diff --git a/shared/editor/embeds/Gliffy.tsx b/shared/editor/embeds/Gliffy.tsx index e0330ffe5..56e9132d1 100644 --- a/shared/editor/embeds/Gliffy.tsx +++ b/shared/editor/embeds/Gliffy.tsx @@ -8,6 +8,6 @@ function Gliffy(props: Props) { ); } -Gliffy.ENABLED = [new RegExp("https?://go.gliffy.com/go/share/(.*)$")]; +Gliffy.ENABLED = [new RegExp("https?://go\\.gliffy\\.com/go/share/(.*)$")]; export default Gliffy; diff --git a/shared/editor/embeds/GoogleCalendar.test.ts b/shared/editor/embeds/GoogleCalendar.test.ts index 7e2e814ca..2d981a4c2 100644 --- a/shared/editor/embeds/GoogleCalendar.test.ts +++ b/shared/editor/embeds/GoogleCalendar.test.ts @@ -15,5 +15,15 @@ describe("GoogleCalendar", () => { expect("https://calendar.google.com/calendar".match(match)).toBe(null); expect("https://calendar.google.com".match(match)).toBe(null); expect("https://www.google.com".match(match)).toBe(null); + expect( + "https://calendarrgoogle.com/calendar/embed?src=tom%40outline.com&ctz=America%2FSao_Paulo".match( + match + ) + ).toBe(null); + expect( + "https://calendar.googleecom/calendar/embed?src=tom%40outline.com&ctz=America%2FSao_Paulo".match( + match + ) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/GoogleCalendar.tsx b/shared/editor/embeds/GoogleCalendar.tsx index 8dc6e185a..5f3b1fc11 100644 --- a/shared/editor/embeds/GoogleCalendar.tsx +++ b/shared/editor/embeds/GoogleCalendar.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "^https?://calendar.google.com/calendar/embed\\?src=(.*)$" + "^https?://calendar\\.google\\.com/calendar/embed\\?src=(.*)$" ); export default class GoogleCalendar extends React.Component { diff --git a/shared/editor/embeds/GoogleDataStudio.test.ts b/shared/editor/embeds/GoogleDataStudio.test.ts index 13e4944a2..c190ad573 100644 --- a/shared/editor/embeds/GoogleDataStudio.test.ts +++ b/shared/editor/embeds/GoogleDataStudio.test.ts @@ -15,5 +15,15 @@ describe("GoogleDataStudio", () => { expect("https://datastudio.google.com/u/0/".match(match)).toBe(null); expect("https://datastudio.google.com".match(match)).toBe(null); expect("https://www.google.com".match(match)).toBe(null); + expect( + "https://datastudioogoogle.com/embed/reporting/aab01789-f3a2-4ff3-9cba-c4c94c4a92e8/page/7zFD".match( + match + ) + ).toBe(null); + expect( + "https://datastudio.googleecom/embed/reporting/aab01789-f3a2-4ff3-9cba-c4c94c4a92e8/page/7zFD".match( + match + ) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/GoogleDataStudio.tsx b/shared/editor/embeds/GoogleDataStudio.tsx index 1a65c6933..0e90828df 100644 --- a/shared/editor/embeds/GoogleDataStudio.tsx +++ b/shared/editor/embeds/GoogleDataStudio.tsx @@ -4,7 +4,7 @@ import Image from "../components/Image"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "^https?://datastudio.google.com/(embed|u/0)/reporting/(.*)/page/(.*)(/edit)?$" + "^https?://datastudio\\.google\\.com/(embed|u/0)/reporting/(.*)/page/(.*)(/edit)?$" ); export default class GoogleDataStudio extends React.Component { diff --git a/shared/editor/embeds/GoogleDocs.test.ts b/shared/editor/embeds/GoogleDocs.test.ts index 5400a38a4..ba1cd758b 100644 --- a/shared/editor/embeds/GoogleDocs.test.ts +++ b/shared/editor/embeds/GoogleDocs.test.ts @@ -30,5 +30,15 @@ describe("GoogleDocs", () => { expect("https://docs.google.com/document".match(match)).toBe(null); expect("https://docs.google.com".match(match)).toBe(null); expect("https://www.google.com".match(match)).toBe(null); + expect( + "https://docssgoogle.com/document/d/e/2PACX-1vTdddHPoZ5M_47wmSHCoigRIt2cj_Pd-kgtaNQY6H0Jzn0_CVGbxC1GcK5IoNzU615lzguexFwxasAW/pubhtml".match( + match + ) + ).toBe(null); + expect( + "https://docs.googleecom/document/d/e/2PACX-1vTdddHPoZ5M_47wmSHCoigRIt2cj_Pd-kgtaNQY6H0Jzn0_CVGbxC1GcK5IoNzU615lzguexFwxasAW/pubhtml".match( + match + ) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/GoogleDocs.tsx b/shared/editor/embeds/GoogleDocs.tsx index 7d86db401..e23d540ac 100644 --- a/shared/editor/embeds/GoogleDocs.tsx +++ b/shared/editor/embeds/GoogleDocs.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import Image from "../components/Image"; import { EmbedProps as Props } from "."; -const URL_REGEX = new RegExp("^https?://docs.google.com/document/(.*)$"); +const URL_REGEX = new RegExp("^https?://docs\\.google\\.com/document/(.*)$"); export default class GoogleDocs extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/GoogleDrawings.test.ts b/shared/editor/embeds/GoogleDrawings.test.ts index d3e772c2d..68abc2ee8 100644 --- a/shared/editor/embeds/GoogleDrawings.test.ts +++ b/shared/editor/embeds/GoogleDrawings.test.ts @@ -25,5 +25,15 @@ describe("GoogleDrawings", () => { expect("https://docs.google.com/drawings".match(match)).toBe(null); expect("https://docs.google.com".match(match)).toBe(null); expect("https://www.google.com".match(match)).toBe(null); + expect( + "https://docssgoogle.com/drawings/d/1zDLtJ4HSCnjGCGSoCgqGe3F8p6o7R8Vjk8MDR6dKf-U/edit".match( + match + ) + ).toBe(null); + expect( + "https://docs.googleecom/drawings/d/1zDLtJ4HSCnjGCGSoCgqGe3F8p6o7R8Vjk8MDR6dKf-U/edit".match( + match + ) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/GoogleDrawings.tsx b/shared/editor/embeds/GoogleDrawings.tsx index a86c21ada..bccb892bf 100644 --- a/shared/editor/embeds/GoogleDrawings.tsx +++ b/shared/editor/embeds/GoogleDrawings.tsx @@ -4,7 +4,7 @@ import Image from "../components/Image"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "^https://docs.google.com/drawings/d/(.*)/(edit|preview)(.*)$" + "^https://docs\\.google\\.com/drawings/d/(.*)/(edit|preview)(.*)$" ); export default class GoogleDrawings extends React.Component { diff --git a/shared/editor/embeds/GoogleDrive.test.ts b/shared/editor/embeds/GoogleDrive.test.ts index 5d2e93ead..4cc4d1c1b 100644 --- a/shared/editor/embeds/GoogleDrive.test.ts +++ b/shared/editor/embeds/GoogleDrive.test.ts @@ -25,5 +25,15 @@ describe("GoogleDrive", () => { expect("https://drive.google.com/file".match(match)).toBe(null); expect("https://drive.google.com".match(match)).toBe(null); expect("https://www.google.com".match(match)).toBe(null); + expect( + "https://driveegoogle.com/file/d/1ohkOgmE8MiNx68u6ynBfYkgjeKu_x3ZK/view?usp=sharing".match( + match + ) + ).toBe(null); + expect( + "https://drive.googleecom/file/d/1ohkOgmE8MiNx68u6ynBfYkgjeKu_x3ZK/view?usp=sharing".match( + match + ) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/GoogleDrive.tsx b/shared/editor/embeds/GoogleDrive.tsx index 916dab23c..0c7cdcc84 100644 --- a/shared/editor/embeds/GoogleDrive.tsx +++ b/shared/editor/embeds/GoogleDrive.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import Image from "../components/Image"; import { EmbedProps as Props } from "."; -const URL_REGEX = new RegExp("^https?://drive.google.com/file/d/(.*)$"); +const URL_REGEX = new RegExp("^https?://drive\\.google\\.com/file/d/(.*)$"); export default class GoogleDrive extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/GoogleSheets.test.ts b/shared/editor/embeds/GoogleSheets.test.ts index a3a3e8e10..e929fc56d 100644 --- a/shared/editor/embeds/GoogleSheets.test.ts +++ b/shared/editor/embeds/GoogleSheets.test.ts @@ -20,5 +20,15 @@ describe("GoogleSheets", () => { expect("https://docs.google.com/spreadsheets".match(match)).toBe(null); expect("https://docs.google.com".match(match)).toBe(null); expect("https://www.google.com".match(match)).toBe(null); + expect( + "https://docssgoogle.com/spreadsheets/d/e/2PACX-1vTdddHPoZ5M_47wmSHCoigRIt2cj_Pd-kgtaNQY6H0Jzn0_CVGbxC1GcK5IoNzU615lzguexFwxasAW/pub".match( + match + ) + ).toBe(null); + expect( + "https://docs.googleecom/spreadsheets/d/e/2PACX-1vTdddHPoZ5M_47wmSHCoigRIt2cj_Pd-kgtaNQY6H0Jzn0_CVGbxC1GcK5IoNzU615lzguexFwxasAW/pub".match( + match + ) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/GoogleSheets.tsx b/shared/editor/embeds/GoogleSheets.tsx index 7416bb6a9..1376124a8 100644 --- a/shared/editor/embeds/GoogleSheets.tsx +++ b/shared/editor/embeds/GoogleSheets.tsx @@ -3,7 +3,9 @@ import Frame from "../components/Frame"; import Image from "../components/Image"; import { EmbedProps as Props } from "."; -const URL_REGEX = new RegExp("^https?://docs.google.com/spreadsheets/d/(.*)$"); +const URL_REGEX = new RegExp( + "^https?://docs\\.google\\.com/spreadsheets/d/(.*)$" +); export default class GoogleSheets extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/GoogleSlides.test.ts b/shared/editor/embeds/GoogleSlides.test.ts index 77263e9ea..4295a1751 100644 --- a/shared/editor/embeds/GoogleSlides.test.ts +++ b/shared/editor/embeds/GoogleSlides.test.ts @@ -25,5 +25,15 @@ describe("GoogleSlides", () => { expect("https://docs.google.com/presentation".match(match)).toBe(null); expect("https://docs.google.com".match(match)).toBe(null); expect("https://www.google.com".match(match)).toBe(null); + expect( + "https://docssgoogle.com/presentation/d/e/2PACX-1vTdddHPoZ5M_47wmSHCoigRIt2cj_Pd-kgtaNQY6H0Jzn0_CVGbxC1GcK5IoNzU615lzguexFwxasAW/pub?start=false&loop=false&delayms=3000".match( + match + ) + ).toBe(null); + expect( + "https://docs.googleecom/presentation/d/e/2PACX-1vTdddHPoZ5M_47wmSHCoigRIt2cj_Pd-kgtaNQY6H0Jzn0_CVGbxC1GcK5IoNzU615lzguexFwxasAW/pub?start=false&loop=false&delayms=3000".match( + match + ) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/GoogleSlides.tsx b/shared/editor/embeds/GoogleSlides.tsx index 9bc99e95b..78d4c02d7 100644 --- a/shared/editor/embeds/GoogleSlides.tsx +++ b/shared/editor/embeds/GoogleSlides.tsx @@ -3,7 +3,9 @@ import Frame from "../components/Frame"; import Image from "../components/Image"; import { EmbedProps as Props } from "."; -const URL_REGEX = new RegExp("^https?://docs.google.com/presentation/d/(.*)$"); +const URL_REGEX = new RegExp( + "^https?://docs\\.google\\.com/presentation/d/(.*)$" +); export default class GoogleSlides extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/JSFiddle.test.ts b/shared/editor/embeds/JSFiddle.test.ts new file mode 100644 index 000000000..9917d78e1 --- /dev/null +++ b/shared/editor/embeds/JSFiddle.test.ts @@ -0,0 +1,11 @@ +import JSFiddle from "./JSFiddle"; + +describe("JSFiddle", () => { + const match = JSFiddle.ENABLED[0]; + + test("to not be enabled for invalid urls", () => { + expect("https://jsfiddleenet/go/share/c9d837d74182317".match(match)).toBe( + null + ); + }); +}); diff --git a/shared/editor/embeds/JSFiddle.tsx b/shared/editor/embeds/JSFiddle.tsx index 49249ef7c..fcc2067ad 100644 --- a/shared/editor/embeds/JSFiddle.tsx +++ b/shared/editor/embeds/JSFiddle.tsx @@ -20,6 +20,6 @@ function JSFiddle(props: Props) { ); } -JSFiddle.ENABLED = [new RegExp("https?://jsfiddle.net/(.*)/(.*)$")]; +JSFiddle.ENABLED = [new RegExp("https?://jsfiddle\\.net/(.*)/(.*)$")]; export default JSFiddle; diff --git a/shared/editor/embeds/Loom.test.ts b/shared/editor/embeds/Loom.test.ts index 618a8f099..5441b804e 100644 --- a/shared/editor/embeds/Loom.test.ts +++ b/shared/editor/embeds/Loom.test.ts @@ -28,5 +28,8 @@ describe("Loom", () => { test("to not be enabled elsewhere", () => { expect("https://www.useloom.com".match(match)).toBe(null); expect("https://www.useloom.com/features".match(match)).toBe(null); + expect( + "https://www.loommcom/share/55327cbb265743f39c2c442c029277e0".match(match) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/Loom.tsx b/shared/editor/embeds/Loom.tsx index ee9fbfe9c..0222a7b06 100644 --- a/shared/editor/embeds/Loom.tsx +++ b/shared/editor/embeds/Loom.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; -const URL_REGEX = /^https:\/\/(www\.)?(use)?loom.com\/(embed|share)\/(.*)$/; +const URL_REGEX = /^https:\/\/(www\.)?(use)?loom\.com\/(embed|share)\/(.*)$/; export default class Loom extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/Marvel.test.ts b/shared/editor/embeds/Marvel.test.ts index a1a5c09a2..bd7690625 100644 --- a/shared/editor/embeds/Marvel.test.ts +++ b/shared/editor/embeds/Marvel.test.ts @@ -10,5 +10,6 @@ describe("Marvel", () => { test("to not be enabled elsewhere", () => { expect("https://marvelapp.com".match(match)).toBe(null); expect("https://marvelapp.com/features".match(match)).toBe(null); + expect("https://marvelapppcom/75hj91".match(match)).toBe(null); }); }); diff --git a/shared/editor/embeds/Marvel.tsx b/shared/editor/embeds/Marvel.tsx index 0fb8b54ca..e35be6b2f 100644 --- a/shared/editor/embeds/Marvel.tsx +++ b/shared/editor/embeds/Marvel.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; -const URL_REGEX = new RegExp("^https://marvelapp.com/([A-Za-z0-9-]{6})/?$"); +const URL_REGEX = new RegExp("^https://marvelapp\\.com/([A-Za-z0-9-]{6})/?$"); export default class Marvel extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/Mindmeister.test.ts b/shared/editor/embeds/Mindmeister.test.ts index 4590afd47..6faa19242 100644 --- a/shared/editor/embeds/Mindmeister.test.ts +++ b/shared/editor/embeds/Mindmeister.test.ts @@ -42,5 +42,17 @@ describe("Mindmeister", () => { test("to not be enabled elsewhere", () => { expect("https://mindmeister.com".match(match)).toBe(null); expect("https://www.mindmeister.com/pricing".match(match)).toBe(null); + expect("https://www.mmttt/326377934".match(match)).toBe(null); + expect( + "https://www.mindmeisterrcom/maps/public_map_shell/326377934/paper-digital-or-online-mind-mapping".match( + match + ) + ).toBe(null); + expect("https://wwwwmm.tt/326377934".match(match)).toBe(null); + expect( + "https://wwwwmindmeister.com/maps/public_map_shell/326377934/paper-digital-or-online-mind-mapping".match( + match + ) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/Mindmeister.tsx b/shared/editor/embeds/Mindmeister.tsx index 823caaeaf..035a4d905 100644 --- a/shared/editor/embeds/Mindmeister.tsx +++ b/shared/editor/embeds/Mindmeister.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "^https://([w.-]+.)?(mindmeister.com|mm.tt)(/maps/public_map_shell)?/(\\d+)(\\?t=.*)?(/.*)?$" + "^https://([w.-]+\\.)?(mindmeister\\.com|mm\\.tt)(/maps/public_map_shell)?/(\\d+)(\\?t=.*)?(/.*)?$" ); export default class Mindmeister extends React.Component { diff --git a/shared/editor/embeds/Miro.test.ts b/shared/editor/embeds/Miro.test.ts index 5c3d60ada..fb6800623 100644 --- a/shared/editor/embeds/Miro.test.ts +++ b/shared/editor/embeds/Miro.test.ts @@ -23,5 +23,8 @@ describe("Miro", () => { expect("https://miro.com".match(match)).toBe(null); expect("https://realtimeboard.com".match(match)).toBe(null); expect("https://realtimeboard.com/features".match(match)).toBe(null); + expect( + "https://realtimeboarddcom/app/board/o9J_k0fwiss=".match(match) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/Miro.tsx b/shared/editor/embeds/Miro.tsx index d0df3a222..61da3e6dc 100644 --- a/shared/editor/embeds/Miro.tsx +++ b/shared/editor/embeds/Miro.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; -const URL_REGEX = /^https:\/\/(realtimeboard|miro).com\/app\/board\/(.*)$/; +const URL_REGEX = /^https:\/\/(realtimeboard|miro)\.com\/app\/board\/(.*)$/; export default class RealtimeBoard extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/ModeAnalytics.test.ts b/shared/editor/embeds/ModeAnalytics.test.ts index f3ea83984..76ab839b1 100644 --- a/shared/editor/embeds/ModeAnalytics.test.ts +++ b/shared/editor/embeds/ModeAnalytics.test.ts @@ -13,5 +13,11 @@ describe("ModeAnalytics", () => { expect("https://modeanalytics.com".match(match)).toBe(null); expect("https://modeanalytics.com/outline".match(match)).toBe(null); expect("https://modeanalytics.com/outline/reports".match(match)).toBe(null); + expect( + "https://modeanalyticsscom/outline/reports/5aca06064f56".match(match) + ).toBe(null); + expect( + "https://wwwwmodeanalytics.com/outline/reports/5aca06064f56".match(match) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/ModeAnalytics.tsx b/shared/editor/embeds/ModeAnalytics.tsx index 1b61ee6fc..e82431b6e 100644 --- a/shared/editor/embeds/ModeAnalytics.tsx +++ b/shared/editor/embeds/ModeAnalytics.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "^https://([w.-]+.)?modeanalytics.com/(.*)/reports/(.*)$" + "^https://([w.-]+\\.)?modeanalytics\\.com/(.*)/reports/(.*)$" ); export default class ModeAnalytics extends React.Component { diff --git a/shared/editor/embeds/Otter.test.ts b/shared/editor/embeds/Otter.test.ts new file mode 100644 index 000000000..72503d306 --- /dev/null +++ b/shared/editor/embeds/Otter.test.ts @@ -0,0 +1,9 @@ +import Otter from "./Otter"; + +describe("Otter", () => { + const match = Otter.ENABLED[0]; + + test("to not be enabled for invalid urls", () => { + expect("https://otterrai/s/c9d837d74182317".match(match)).toBe(null); + }); +}); diff --git a/shared/editor/embeds/Otter.tsx b/shared/editor/embeds/Otter.tsx index 51055e60c..5909ebb59 100644 --- a/shared/editor/embeds/Otter.tsx +++ b/shared/editor/embeds/Otter.tsx @@ -14,6 +14,6 @@ function Otter(props: Props) { ); } -Otter.ENABLED = [new RegExp("https?://otter.ai/[su]/(.*)$")]; +Otter.ENABLED = [new RegExp("https?://otter\\.ai/[su]/(.*)$")]; export default Otter; diff --git a/shared/editor/embeds/Pitch.test.ts b/shared/editor/embeds/Pitch.test.ts new file mode 100644 index 000000000..c07b62f2b --- /dev/null +++ b/shared/editor/embeds/Pitch.test.ts @@ -0,0 +1,18 @@ +import Pitch from "./Pitch"; + +describe("Pitch", () => { + const match = Pitch.ENABLED[0]; + + test("to not be enabled elsewhere", () => { + expect( + "https://appppitch.com/app/presentation/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/player/c9d837d74182317".match( + match + ) + ).toBe(null); + expect( + "https://app.pitchhcom/app/presentation/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/player/c9d837d74182317".match( + match + ) + ).toBe(null); + }); +}); diff --git a/shared/editor/embeds/Pitch.tsx b/shared/editor/embeds/Pitch.tsx index 23231584a..52de477d4 100644 --- a/shared/editor/embeds/Pitch.tsx +++ b/shared/editor/embeds/Pitch.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "^https?://app.pitch.com/app/(?:presentation/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|public/player)/(.*)$" + "^https?://app\\.pitch\\.com/app/(?:presentation/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|public/player)/(.*)$" ); export default class Pitch extends React.Component { diff --git a/shared/editor/embeds/Prezi.test.ts b/shared/editor/embeds/Prezi.test.ts index aad481ed7..fb304f057 100644 --- a/shared/editor/embeds/Prezi.test.ts +++ b/shared/editor/embeds/Prezi.test.ts @@ -18,5 +18,8 @@ describe("Prezi", () => { test("to not be enabled elsewhere", () => { expect("https://prezi.com".match(match)).toBe(null); expect("https://prezi.com/pricing".match(match)).toBe(null); + expect("https://preziicom/view/39mn8Rn1ZkoeEKQCgk5C".match(match)).toBe( + null + ); }); }); diff --git a/shared/editor/embeds/Prezi.tsx b/shared/editor/embeds/Prezi.tsx index 06193c008..22c4fba1e 100644 --- a/shared/editor/embeds/Prezi.tsx +++ b/shared/editor/embeds/Prezi.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; -const URL_REGEX = new RegExp("^https://prezi.com/view/(.*)$"); +const URL_REGEX = new RegExp("^https://prezi\\.com/view/(.*)$"); export default class Prezi extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/Spotify.test.ts b/shared/editor/embeds/Spotify.test.ts index 6c281919f..385e77ef8 100644 --- a/shared/editor/embeds/Spotify.test.ts +++ b/shared/editor/embeds/Spotify.test.ts @@ -23,5 +23,15 @@ describe("Spotify", () => { expect("https://spotify.com".match(match)).toBe(null); expect("https://open.spotify.com".match(match)).toBe(null); expect("https://www.spotify.com".match(match)).toBe(null); + expect( + "https://opennspotify.com/track/29G1ScCUhgjgI0H72qN4DE?si=DxjEUxV2Tjmk6pSVckPDRg".match( + match + ) + ).toBe(null); + expect( + "https://open.spotifyycom/track/29G1ScCUhgjgI0H72qN4DE?si=DxjEUxV2Tjmk6pSVckPDRg".match( + match + ) + ).toBe(null); }); }); diff --git a/shared/editor/embeds/Spotify.tsx b/shared/editor/embeds/Spotify.tsx index c366d63e1..82b024399 100644 --- a/shared/editor/embeds/Spotify.tsx +++ b/shared/editor/embeds/Spotify.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import Frame from "../components/Frame"; -const URL_REGEX = new RegExp("https?://open.spotify.com/(.*)$"); +const URL_REGEX = new RegExp("https?://open\\.spotify\\.com/(.*)$"); import { EmbedProps as Props } from "."; export default class Spotify extends React.Component { diff --git a/shared/editor/embeds/Tldraw.test.ts b/shared/editor/embeds/Tldraw.test.ts new file mode 100644 index 000000000..5c82bfa6c --- /dev/null +++ b/shared/editor/embeds/Tldraw.test.ts @@ -0,0 +1,10 @@ +import Tldraw from "./Tldraw"; + +describe("Tldraw", () => { + const match = Tldraw.ENABLED[0]; + + test("to not be enabled elsewhere", () => { + expect("https://wwwwtldraw.com/r/c9d837d74182317".match(match)).toBe(null); + expect("https://www.tldrawwcom/r/c9d837d74182317".match(match)).toBe(null); + }); +}); diff --git a/shared/editor/embeds/Tldraw.tsx b/shared/editor/embeds/Tldraw.tsx index f440aba12..cdbdcc365 100644 --- a/shared/editor/embeds/Tldraw.tsx +++ b/shared/editor/embeds/Tldraw.tsx @@ -14,6 +14,6 @@ function Tldraw(props: Props) { ); } -Tldraw.ENABLED = [new RegExp("https?://www.tldraw.com/r/(.*)$")]; +Tldraw.ENABLED = [new RegExp("https?://www\\.tldraw\\.com/r/(.*)$")]; export default Tldraw; diff --git a/shared/editor/embeds/Trello.test.ts b/shared/editor/embeds/Trello.test.ts new file mode 100644 index 000000000..b4fb26d6a --- /dev/null +++ b/shared/editor/embeds/Trello.test.ts @@ -0,0 +1,9 @@ +import Trello from "./Trello"; + +describe("Trello", () => { + const match = Trello.ENABLED[0]; + + test("to not be enabled for invalid urls", () => { + expect("https://trelloocom/c/c9d837d74182317".match(match)).toBe(null); + }); +}); diff --git a/shared/editor/embeds/Trello.tsx b/shared/editor/embeds/Trello.tsx index 87829a4ff..fa784faa0 100644 --- a/shared/editor/embeds/Trello.tsx +++ b/shared/editor/embeds/Trello.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; -const URL_REGEX = /^https:\/\/trello.com\/(c|b)\/([^/]*)(.*)?$/; +const URL_REGEX = /^https:\/\/trello\.com\/(c|b)\/([^/]*)(.*)?$/; export default class Trello extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/Typeform.test.ts b/shared/editor/embeds/Typeform.test.ts index e23557ba9..7acaa570d 100644 --- a/shared/editor/embeds/Typeform.test.ts +++ b/shared/editor/embeds/Typeform.test.ts @@ -13,5 +13,7 @@ describe("Typeform", () => { expect("https://www.typeform.com".match(match)).toBe(null); expect("https://typeform.com/to/zvlr4L".match(match)).toBe(null); expect("https://typeform.com/features".match(match)).toBe(null); + expect("https://beardymanntypeform.com/to/zvlr4L".match(match)).toBe(null); + expect("https://beardyman.typeformmcom/to/zvlr4L".match(match)).toBe(null); }); }); diff --git a/shared/editor/embeds/Typeform.tsx b/shared/editor/embeds/Typeform.tsx index 4b7b96991..c477ad873 100644 --- a/shared/editor/embeds/Typeform.tsx +++ b/shared/editor/embeds/Typeform.tsx @@ -3,7 +3,7 @@ import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; const URL_REGEX = new RegExp( - "^https://([A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?).typeform.com/to/(.*)$" + "^https://([A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)\\.typeform\\.com/to/(.*)$" ); export default class Typeform extends React.Component { diff --git a/shared/editor/embeds/Vimeo.test.ts b/shared/editor/embeds/Vimeo.test.ts index f9c632d36..e314403c7 100644 --- a/shared/editor/embeds/Vimeo.test.ts +++ b/shared/editor/embeds/Vimeo.test.ts @@ -15,5 +15,6 @@ describe("Vimeo", () => { expect("https://vimeo.com/features/video-marketing".match(match)).toBe( null ); + expect("https://www.vimeoocom/265045525".match(match)).toBe(null); }); }); diff --git a/shared/editor/embeds/Vimeo.tsx b/shared/editor/embeds/Vimeo.tsx index f7f18607e..dcf39f466 100644 --- a/shared/editor/embeds/Vimeo.tsx +++ b/shared/editor/embeds/Vimeo.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; -const URL_REGEX = /(http|https)?:\/\/(www\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^/]*)\/videos\/|)(\d+)(?:\/|\?)?([\d\w]+)?/; +const URL_REGEX = /(http|https)?:\/\/(www\.)?vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^/]*)\/videos\/|)(\d+)(?:\/|\?)?([\d\w]+)?/; export default class Vimeo extends React.Component { static ENABLED = [URL_REGEX]; diff --git a/shared/editor/embeds/Whimsical.test.ts b/shared/editor/embeds/Whimsical.test.ts new file mode 100644 index 000000000..e9849042f --- /dev/null +++ b/shared/editor/embeds/Whimsical.test.ts @@ -0,0 +1,9 @@ +import Whimsical from "./Whimsical"; + +describe("Whimsical", () => { + const match = Whimsical.ENABLED[0]; + + test("to not be enabled for invalid urls", () => { + expect("https://whimsicallcom/a-c9d837d74182317".match(match)).toBe(null); + }); +}); diff --git a/shared/editor/embeds/Whimsical.tsx b/shared/editor/embeds/Whimsical.tsx index 7e68127ce..aefa8c7b2 100644 --- a/shared/editor/embeds/Whimsical.tsx +++ b/shared/editor/embeds/Whimsical.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import Frame from "../components/Frame"; import { EmbedProps as Props } from "."; -const URL_REGEX = /^https?:\/\/whimsical.com\/[0-9a-zA-Z-_~]*-([a-zA-Z0-9]+)\/?$/; +const URL_REGEX = /^https?:\/\/whimsical\.com\/[0-9a-zA-Z-_~]*-([a-zA-Z0-9]+)\/?$/; export default class Whimsical extends React.Component { static ENABLED = [URL_REGEX];