Validate URL protocol before opening from Visual Editor tooltip (#18393)

GitOrigin-RevId: 1da255d3e8ccd91e8c8774d140ec663906be948f
This commit is contained in:
Alf Eaton 2024-05-20 11:29:31 +01:00 committed by Copybot
parent e9d4d26fec
commit e7827fbd57
5 changed files with 23 additions and 10 deletions

View file

@ -17,6 +17,7 @@ import {
import { Button, ControlLabel, FormControl, FormGroup } from 'react-bootstrap' import { Button, ControlLabel, FormControl, FormGroup } from 'react-bootstrap'
import Icon from '../../../../shared/components/icon' import Icon from '../../../../shared/components/icon'
import { EditorState } from '@codemirror/state' import { EditorState } from '@codemirror/state'
import { openURL } from '@/features/source-editor/utils/url'
export const HrefTooltipContent: FC = () => { export const HrefTooltipContent: FC = () => {
const state = useCodeMirrorStateContext() const state = useCodeMirrorStateContext()
@ -108,7 +109,7 @@ export const HrefTooltipContent: FC = () => {
className="ol-cm-command-tooltip-link" className="ol-cm-command-tooltip-link"
onClick={() => { onClick={() => {
// TODO: unescape content // TODO: unescape content
window.open(url, '_blank') openURL(url)
}} }}
> >
<Icon type="external-link" fw /> <Icon type="external-link" fw />

View file

@ -9,6 +9,7 @@ import {
} from '../../lezer-latex/latex.terms.mjs' } from '../../lezer-latex/latex.terms.mjs'
import Icon from '../../../../shared/components/icon' import Icon from '../../../../shared/components/icon'
import { EditorState } from '@codemirror/state' import { EditorState } from '@codemirror/state'
import { openURL } from '@/features/source-editor/utils/url'
export const UrlTooltipContent: FC = () => { export const UrlTooltipContent: FC = () => {
const { t } = useTranslation() const { t } = useTranslation()
@ -23,7 +24,7 @@ export const UrlTooltipContent: FC = () => {
onClick={() => { onClick={() => {
const url = readUrl(state) const url = readUrl(state)
if (url) { if (url) {
window.open(url, '_blank') openURL(url)
} }
}} }}
> >

View file

@ -0,0 +1,11 @@
const ALLOWED_PROTOCOLS = ['https:', 'http:']
export const openURL = (content: string) => {
const url = new URL(content, document.location.href)
if (!ALLOWED_PROTOCOLS.includes(url.protocol)) {
throw new Error(`Not opening URL with protocol ${url.protocol}`)
}
window.open(url, '_blank')
}

View file

@ -54,8 +54,8 @@ describe('<CodeMirrorEditor/> command tooltip in Visual mode', function () {
// open the link // open the link
cy.findByRole('button', { name: 'Go to page' }).click() cy.findByRole('button', { name: 'Go to page' }).click()
cy.get('@window-open').should( cy.get('@window-open').should(
'have.been.calledOnceWithExactly', 'have.been.calledWithMatch',
'https://example.com', Cypress.sinon.match.has('href', 'https://example.com/'),
'_blank' '_blank'
) )
@ -112,8 +112,8 @@ describe('<CodeMirrorEditor/> command tooltip in Visual mode', function () {
// open the link // open the link
cy.findByRole('button', { name: 'Go to page' }).click() cy.findByRole('button', { name: 'Go to page' }).click()
cy.get('@window-open').should( cy.get('@window-open').should(
'have.been.calledOnceWithExactly', 'have.been.calledWithMatch',
'https://example.com', Cypress.sinon.match.has('href', 'https://example.com/'),
'_blank' '_blank'
) )
}) })

View file

@ -42,8 +42,8 @@ describe('<CodeMirrorEditor/> tooltips in Visual mode', function () {
}) })
cy.findByRole('button', { name: 'Go to page' }).click() cy.findByRole('button', { name: 'Go to page' }).click()
cy.get('@open-window').should( cy.get('@open-window').should(
'have.been.calledOnceWithExactly', 'have.been.calledWithMatch',
'https://example.com/foo', Cypress.sinon.match.has('href', 'https://example.com/foo'),
'_blank' '_blank'
) )
cy.findByRole('button', { name: 'Remove link' }).click() cy.findByRole('button', { name: 'Remove link' }).click()
@ -62,8 +62,8 @@ describe('<CodeMirrorEditor/> tooltips in Visual mode', function () {
}) })
cy.findByRole('button', { name: 'Go to page' }).click() cy.findByRole('button', { name: 'Go to page' }).click()
cy.get('@open-window').should( cy.get('@open-window').should(
'have.been.calledOnceWithExactly', 'have.been.calledWithMatch',
'https://example.com', Cypress.sinon.match.has('href', 'https://example.com/'),
'_blank' '_blank'
) )
}) })