Skip to content

Commit

Permalink
fix(NcRichText): more strictly resolve vue router's path
Browse files Browse the repository at this point in the history
Signed-off-by: Grigorii K. Shartsev <me@shgk.me>
  • Loading branch information
ShGKme committed Apr 10, 2024
1 parent ef0d06f commit e2da973
Showing 1 changed file with 73 additions and 11 deletions.
84 changes: 73 additions & 11 deletions src/components/NcRichText/autolink.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
/**
* @copyright Copyright (c) 2022 Julius Härtl <jus@bitgrid.net>
*
* @author Julius Härtl <jus@bitgrid.net>
* @author Raimund Schlüßler <raimund.schluessler@mailbox.org>
* @author Maksim Sukharev <antreesy.web@gmail.com>
* @author Grigorii K. Shartsev <me@shgk.me>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import { URL_PATTERN_AUTOLINK } from './helpers.js'

import { visit, SKIP } from 'unist-util-visit'
import { u } from 'unist-builder'
import { getBaseUrl } from '@nextcloud/router'
import { getBaseUrl, getRootUrl } from '@nextcloud/router'

const NcLink = {
name: 'NcLink',
Expand Down Expand Up @@ -84,20 +109,57 @@ export const parseUrl = (text) => {
return text
}

/**
* Try to get path for router link from an absolute or relative URL.
*
* @param {import('vue-router').default} router - VueRouter instance of the router link
* @param {string} url - absolute URL to parse
* @return {string|null} a path that can be useed in the router link or null if this URL doesn't match this router config
* @example http://cloud.ltd/nextcloud/index.php/app/files/favorites?fileid=2#fragment => /files/favorites?fileid=2#fragment
*/
export const getRoute = (router, url) => {
// Skip if Router is not defined in app, or baseUrl does not match
if (!router || !url.includes(getBaseUrl())) {
/**
* http://cloud.ltd /nextcloud /index.php/app/files /favorites?fileid=2#fragment
* |_____origin____|__________router-base__________|_________router-path________|
* |__________base____________|
* |___root___|
*/

// Router is not defined in the app => not an app route
if (!router) {
return null
}

const regexArray = router.getRoutes()
// route.regex matches only complete string (^.$), need to remove these characters
.map(route => new RegExp(route.regex.source.slice(1, -1), route.regex.flags))
const isAbsoluteURL = /^https?:\/\//.test(url)

for (const regex of regexArray) {
const match = url.search(regex)
if (match !== -1) {
return url.slice(match)
}
// URL is not a link to this Nextcloud server instance => not an app route
if ((isAbsoluteURL && !url.startsWith(getBaseUrl())) || (!isAbsoluteURL && !url.startsWith(getRootUrl()))) {
return null
}

// Vue 3: router.options.history.base
const routerBase = router.history.base

const urlWithoutOrigin = isAbsoluteURL ? url.slice(new URL(url).origin.length) : url

// Remove index.php - it is optional in general case in both, VueRouter base and the URL
const urlWithoutOriginAndIndexPhp = url.startsWith((isAbsoluteURL ? getBaseUrl() : getRootUrl()) + '/index.php') ? urlWithoutOrigin.replace('/index.php', '') : urlWithoutOrigin
const routerBaseWithoutIndexPhp = routerBase.replace('/index.php', '')

// This URL is not a part of this router by base
if (!urlWithoutOriginAndIndexPhp.startsWith(routerBaseWithoutIndexPhp)) {
return null
}

// Root route may have an empty '' path, fallback to '/'
const routerPath = urlWithoutOriginAndIndexPhp.replace(routerBaseWithoutIndexPhp, '') || '/'

// Check if there is actually matching route in the router for this path
const route = router.resolve(routerPath).route

if (!route.matched.length) {
return null
}

return route.fullPath
}

0 comments on commit e2da973

Please sign in to comment.