Skip to content

Commit

Permalink
Merge pull request #6492 from nextcloud/backport/6486/stable29
Browse files Browse the repository at this point in the history
[stable29] Check link protocol
  • Loading branch information
max-nextcloud authored Oct 2, 2024
2 parents aaa6b39 + 82301a1 commit 5281af4
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 69 deletions.
6 changes: 2 additions & 4 deletions cypress/e2e/directediting.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ function enterContentAndClose() {
cy.intercept({ method: 'POST', url: '**/session/*/close' }).as('closeRequest')
cy.intercept({ method: 'POST', url: '**/session/*/push' }).as('push')
cy.intercept({ method: 'POST', url: '**/session/*/sync' }).as('sync')
cy.getContent().type('# This is a headline')
cy.getContent().type('{enter}')
cy.getContent().type('Some text')
cy.getContent().type('{enter}')
cy.insertLine('# This is a headline')
cy.insertLine('Some text')
cy.getContent().type('{ctrl+s}')
cy.wait('@push')
cy.wait('@sync')
Expand Down
6 changes: 3 additions & 3 deletions cypress/e2e/nodes/CodeBlock.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe('Front matter support', function() {
cy.isolateTest({ sourceFile: 'codeblock.md' })
cy.openFile('codeblock.md').then(() => {
cy.clearContent()
cy.getContent().type('{enter}```javascript{enter}')
cy.insertLine('```javascript')
cy.getContent().type('const foo = "bar"{enter}{enter}{enter}')
cy.getContent().find('.hljs-keyword').first().contains('const')
})
Expand All @@ -123,7 +123,7 @@ describe('Front matter support', function() {
it('Add an invalid mermaid block', function() {
cy.isolateTest()
cy.openFile('empty.md').then(() => {
cy.getContent().type('```mermaid{enter}')
cy.insertLine('```mermaid')
cy.getContent().find('code').should('exist')
cy.getContent().get('.split-view__preview').should('be.visible')
// eslint-disable-next-line cypress/no-unnecessary-waiting
Expand All @@ -138,7 +138,7 @@ describe('Front matter support', function() {
it('Add a valid mermaid block', function() {
cy.isolateTest()
cy.openFile('empty.md').then(() => {
cy.getContent().type('```mermaid{enter}')
cy.insertLine('```mermaid')
cy.getContent().find('code').should('exist')
cy.getContent().get('.split-view__preview').should('be.visible')
// eslint-disable-next-line cypress/no-unnecessary-waiting
Expand Down
91 changes: 50 additions & 41 deletions cypress/e2e/nodes/Links.spec.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { initUserAndFiles, randUser } from '../../utils/index.js'
import { randUser } from '../../utils/index.js'

const user = randUser()
const fileName = 'empty.md'

describe('test link marks', function() {
before(function() {
initUserAndFiles(user)
cy.createUser(user)
})

beforeEach(function() {
Expand All @@ -21,14 +21,17 @@ describe('test link marks', function() {
})

describe('link bubble', function() {
it('shows a link preview in the bubble after clicking link', () => {
const link = 'https://nextcloud.com/'
cy.getContent()
.type(`${link}{enter}`)

function clickLink(link, options = {}) {
cy.getContent()
.find(`a[href*="${link}"]`)
.click()
.click(options)
}

it('shows a link preview in the bubble after clicking link', () => {
const link = 'https://nextcloud.com/'
cy.insertLine(link)
clickLink(link)

cy.get('.link-view-bubble .widget-default', { timeout: 10000 })
.find('.widget-default--name')
Expand All @@ -38,8 +41,7 @@ describe('test link marks', function() {

it('shows a link preview in the bubble after browsing to link', () => {
const link = 'https://nextcloud.com/'
cy.getContent()
.type(`${link}{enter}`)
cy.insertLine(link)
cy.getContent()
.find(`a[href*="${link}"]`)

Expand All @@ -53,12 +55,9 @@ describe('test link marks', function() {

it('closes the link bubble when clicking elsewhere', () => {
const link = 'https://nextcloud.com/'
cy.getContent()
.type(`${link}{enter}`)
cy.getContent()
.find(`a[href*="${link}"]`)
cy.getContent()
.type('{upArrow}')
cy.insertLine(link)
clickLink(link)

cy.get('.link-view-bubble .widget-default', { timeout: 10000 })
.find('.widget-default--name')
.contains('Nextcloud')
Expand All @@ -69,32 +68,47 @@ describe('test link marks', function() {
.should('not.exist')
})

it('allows to edit a link in the bubble', () => {
cy.getContent()
.type('https://example.org{enter}')
cy.getContent()
.type('{upArrow}{rightArrow}')

const changeLink = target => {
cy.get('.link-view-bubble button[title="Edit link"]')
.click()

cy.get('.link-view-bubble input')
.type('{selectAll}https://nextcloud.com')

cy.get('.link-view-bubble button[title="Save changes"]')
.click()
.type(`{selectAll}${target}{enter}`)
}

it('allows to edit a link in the bubble', () => {
cy.insertLine('https://example.org')
clickLink('https://example.org')
changeLink('https://nextcloud.com')
cy.getContent()
.find('a[href*="https://nextcloud.com"]')
})

it('does not link to other protocols', () => {
cy.insertLine('https://example.org')
clickLink('https://example.org')
cy.get('.link-view-bubble .widget-default')
.should('exist')
changeLink('mailto:test@my.example')
cy.getContent()
.find('a[href*="mailto:test@my.example"]')
.should('exist')
cy.get('.link-view-bubble .widget-default')
.should('not.exist')
changeLink('unknown:protocol')
cy.getContent()
.find('a[href*="unknown:protocol"]')
.should('not.exist')
cy.getContent()
.find('a[href*="#"]')
.should('exist')
cy.get('.link-view-bubble .widget-default')
.should('not.exist')
})

it('allows to remove a link in the bubble', () => {
const link = 'https://nextcloud.com'
cy.getContent()
.type(`${link}{enter}`)
cy.getContent()
.type('{upArrow}{rightArrow}')
cy.insertLine(link)
clickLink(link)

cy.get('.link-view-bubble button[title="Remove link"]')
.click()
Expand All @@ -107,17 +121,15 @@ describe('test link marks', function() {

it('Ctrl-click on a link opens a new tab', () => {
const link = 'https://nextcloud.com/'
cy.getContent()
.type(`${link}{enter}`)
cy.insertLine(link)

cy.getContent()
.find(`a[href*="${link}"]`)
.click({ ctrlKey: true })
clickLink(link, { ctrlKey: true })

cy.get('@winOpen')
.should('have.been.calledOnce')
.should('have.been.calledWith', link)
})

})

describe('autolink', function() {
Expand All @@ -128,8 +140,7 @@ describe('test link marks', function() {

const link = `${Cypress.env('baseUrl')}/apps/files/?dir=/&openfile=${id}#relPath=/${fileName}`
cy.clearContent()
cy.getContent()
.type(`${link}{enter}`)
cy.insertLine(link)

cy.getContent()
.find(`a[href*="${Cypress.env('baseUrl')}"]`)
Expand All @@ -138,16 +149,14 @@ describe('test link marks', function() {

it('without protocol', () => {
cy.clearContent()
cy.getContent()
.type('google.com{enter}')
cy.insertLine('google.com')
cy.getContent()
.find('a[href*="google.com"]')
.should('not.exist')
})

it('with protocol but without space', () => {
cy.getContent()
.type('https://nextcloud.com')
cy.getContent().type('https://nextcloud.com')

cy.getContent()
.find('a[href*="nextcloud.com"]')
Expand Down
5 changes: 2 additions & 3 deletions cypress/e2e/sections.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('Content Sections', () => {
it('Anchor ID is updated', () => {
cy.visitTestFolder()
cy.openFile(fileName, { force: true })
cy.getContent().type('# Heading 1{enter}')
cy.insertLine('# Heading 1')
cy.getContent()
.find('h1 > a')
.should('have.attr', 'id')
Expand Down Expand Up @@ -84,8 +84,7 @@ describe('Content Sections', () => {
cy.visitTestFolder()
cy.openFile(fileName, { force: true })
// Issue #2868
cy.getContent()
.type('# Heading 1{enter}')
cy.insertLine('# Heading 1')
cy.getContent()
.find('h1 > a')
.should('have.attr', 'id')
Expand Down
6 changes: 3 additions & 3 deletions cypress/e2e/sync.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('Sync', () => {
cy.openTestFile()
cy.wait('@sync', { timeout: 10000 })
cy.getContent().find('h2').should('contain', 'Hello world')
cy.getContent().type('{moveToEnd}* Saving the doc saves the doc state{enter}')
cy.insertLine('{moveToEnd}* Saving the doc saves the doc state')
cy.wait('@sync', { timeout: 10000 })
})

Expand Down Expand Up @@ -77,7 +77,7 @@ describe('Sync', () => {
.should('not.contain', 'Document could not be loaded.')
// FIXME: There seems to be a bug where typed words maybe lost if not waiting for the new session
cy.wait('@syncAfterRecovery', { timeout: 10000 })
cy.getContent().type('* more content added after the lost connection{enter}')
cy.insertLine('* more content added after the lost connection')
cy.wait('@syncAfterRecovery', { timeout: 10000 })
cy.closeFile()
cy.testName()
Expand Down Expand Up @@ -137,7 +137,7 @@ describe('Sync', () => {
.should('not.contain', 'Document could not be loaded.')
// FIXME: There seems to be a bug where typed words maybe lost if not waiting for the new session
cy.wait('@syncAfterRecovery', { timeout: 10000 })
cy.getContent().type('* more content added after the lost connection{enter}')
cy.insertLine('* more content added after the lost connection')
cy.wait('@syncAfterRecovery', { timeout: 10000 })
cy.closeFile()
cy.testName()
Expand Down
3 changes: 1 addition & 2 deletions cypress/e2e/viewer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ describe('Open test.md in viewer', function() {
// This used to break with the focus trap that the viewer modal has
cy.openFile('empty.md')

cy.getContent()
.type('- test{enter}')
cy.insertLine('- test')

// Cypress does not have native tab key support, though this seems to work
// for triggering the key handler of tiptap
Expand Down
5 changes: 5 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ Cypress.Commands.add('clearContent', () => {
cy.getContent()
})

Cypress.Commands.add('insertLine', (line = '') => {
cy.getContent()
.type(`${line}{enter}`)
})

Cypress.Commands.add('openWorkspace', () => {
cy.createDescription()
cy.get('#rich-workspace .editor__content').click({ force: true })
Expand Down
9 changes: 8 additions & 1 deletion src/components/Link/LinkBubbleView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
</div>

<!-- link preview -->
<NcReferenceList v-else-if="href"
<NcReferenceList v-else-if="showPreview"
ref="referencelist"
:text="sanitizedHref"
:limit="1"
Expand All @@ -92,6 +92,8 @@ import PencilIcon from 'vue-material-design-icons/Pencil.vue'
import CopyToClipboardMixin from '../../mixins/CopyToClipboardMixin.js'
const PROTOCOLS_WITH_PREVIEW = ['http:', 'https:']
export default {
name: 'LinkBubbleView',
Expand Down Expand Up @@ -157,6 +159,11 @@ export default {
title() {
return this.referenceTitle ? this.referenceTitle : this.sanitizedHref
},
showPreview() {
const url = new URL(this.href, window.location)
return this.href && PROTOCOLS_WITH_PREVIEW.includes(url.protocol)
},
},
watch: {
Expand Down
8 changes: 7 additions & 1 deletion src/marks/Link.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import TipTapLink from '@tiptap/extension-link'
import { domHref, parseHref } from './../helpers/links.js'
import { linkClicking } from '../plugins/links.js'

const PROTOCOLS_TO_LINK_TO = ['http:', 'https:', 'mailto:', 'tel:']

const Link = TipTapLink.extend({

addOptions() {
Expand Down Expand Up @@ -58,9 +60,13 @@ const Link = TipTapLink.extend({

renderHTML(options) {
const { mark } = options
const url = new URL(mark.attrs.href, window.location)
const href = PROTOCOLS_TO_LINK_TO.includes(url.protocol)
? domHref(mark, this.options.relativePath)
: '#'
return ['a', {
...mark.attrs,
href: domHref(mark, this.options.relativePath),
href,
'data-md-href': mark.attrs.href,
rel: 'noopener noreferrer nofollow',
}, 0]
Expand Down
Loading

0 comments on commit 5281af4

Please sign in to comment.