aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-09-05 01:34:48 +0200
committerFerdinand Thiessen <opensource@fthiessen.de>2024-09-06 03:38:48 +0200
commit018af2a2fef7ae9f4057ad4c111b995201ef6e0b (patch)
tree556eac309bbaf44b02ab9980b5c83b1b8b5b9d12 /apps/files
parentcb4c5694866926a4209cf2ba25d23c6840273f56 (diff)
downloadnextcloud-server-018af2a2fef7ae9f4057ad4c111b995201ef6e0b.tar.gz
nextcloud-server-018af2a2fef7ae9f4057ad4c111b995201ef6e0b.zip
fix(files): Do not add click listener if there is no default action on public shares
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/files')
-rw-r--r--apps/files/src/actions/downloadAction.ts22
-rw-r--r--apps/files/src/components/FileEntryMixin.ts25
-rw-r--r--apps/files/src/utils/permissions.ts30
3 files changed, 46 insertions, 31 deletions
diff --git a/apps/files/src/actions/downloadAction.ts b/apps/files/src/actions/downloadAction.ts
index bac5e4adf10..97d1cc773d4 100644
--- a/apps/files/src/actions/downloadAction.ts
+++ b/apps/files/src/actions/downloadAction.ts
@@ -2,13 +2,12 @@
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import type { ShareAttribute } from '../../../files_sharing/src/sharing'
-
-import { FileAction, Permission, Node, FileType, View, DefaultType } from '@nextcloud/files'
+import { FileAction, Node, FileType, View, DefaultType } from '@nextcloud/files'
import { t } from '@nextcloud/l10n'
import { generateUrl } from '@nextcloud/router'
import { getSharingToken, isPublicShare } from '@nextcloud/sharing/public'
import { basename } from 'path'
+import { isDownloadable } from '../utils/permissions'
import ArrowDownSvg from '@mdi/svg/svg/arrow-down.svg?raw'
@@ -40,23 +39,6 @@ const downloadNodes = function(dir: string, nodes: Node[]) {
triggerDownload(url)
}
-const isDownloadable = function(node: Node) {
- if ((node.permissions & Permission.READ) === 0) {
- return false
- }
-
- // If the mount type is a share, ensure it got download permissions.
- if (node.attributes['share-attributes']) {
- const shareAttributes = JSON.parse(node.attributes['share-attributes'] || '[]') as Array<ShareAttribute>
- const downloadAttribute = shareAttributes.find(({ scope, key }: ShareAttribute) => scope === 'permissions' && key === 'download')
- if (downloadAttribute) {
- return downloadAttribute.value === true
- }
- }
-
- return true
-}
-
export const action = new FileAction({
id: 'download',
default: DefaultType.DEFAULT,
diff --git a/apps/files/src/components/FileEntryMixin.ts b/apps/files/src/components/FileEntryMixin.ts
index 73c6ce19387..58f5c1e9474 100644
--- a/apps/files/src/components/FileEntryMixin.ts
+++ b/apps/files/src/components/FileEntryMixin.ts
@@ -20,6 +20,7 @@ import { getDragAndDropPreview } from '../utils/dragUtils.ts'
import { hashCode } from '../utils/hashUtils.ts'
import { dataTransferToFileTree, onDropExternalFiles, onDropInternalFiles } from '../services/DropService.ts'
import logger from '../logger.ts'
+import { isDownloadable } from '../utils/permissions.ts'
Vue.directive('onClickOutside', vOnClickOutside)
@@ -270,29 +271,31 @@ export default defineComponent({
event.stopPropagation()
},
- execDefaultAction(event) {
+ execDefaultAction(event: MouseEvent) {
// Ignore click if we are renaming
if (this.isRenaming) {
return
}
- // Ignore right click.
- if (event.button > 1) {
+ // Ignore right click (button & 2) and any auxillary button expect mouse-wheel (button & 4)
+ if (Boolean(event.button & 2) || event.button > 4) {
return
}
- // if ctrl+click or middle mouse button, open in new tab
+ // if ctrl+click / cmd+click (MacOS uses the meta key) or middle mouse button (button & 4), open in new tab
// also if there is no default action use this as a fallback
- const metaKeyPressed = event.ctrlKey || event.metaKey || event.button === 1
+ const metaKeyPressed = event.ctrlKey || event.metaKey || Boolean(event.button & 4)
if (metaKeyPressed || !this.defaultFileAction) {
+ // If no download permission, then we can not allow to download (direct link) the files
+ if (isPublicShare() && !isDownloadable(this.source)) {
+ return
+ }
+
+ const url = isPublicShare()
+ ? this.source.encodedSource
+ : generateUrl('/f/{fileId}', { fileId: this.fileid })
event.preventDefault()
event.stopPropagation()
- let url: string
- if (isPublicShare()) {
- url = this.source.encodedSource
- } else {
- url = generateUrl('/f/{fileId}', { fileId: this.fileid })
- }
window.open(url, metaKeyPressed ? '_self' : undefined)
return
}
diff --git a/apps/files/src/utils/permissions.ts b/apps/files/src/utils/permissions.ts
new file mode 100644
index 00000000000..2c85ede1659
--- /dev/null
+++ b/apps/files/src/utils/permissions.ts
@@ -0,0 +1,30 @@
+/*!
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+import type { Node } from '@nextcloud/files'
+import type { ShareAttribute } from '../../../files_sharing/src/sharing.ts'
+
+import { Permission } from '@nextcloud/files'
+
+/**
+ * Check permissions on the node if it can be downloaded
+ * @param node The node to check
+ * @return True if downloadable, false otherwise
+ */
+export function isDownloadable(node: Node): boolean {
+ if ((node.permissions & Permission.READ) === 0) {
+ return false
+ }
+
+ // If the mount type is a share, ensure it got download permissions.
+ if (node.attributes['share-attributes']) {
+ const shareAttributes = JSON.parse(node.attributes['share-attributes'] || '[]') as Array<ShareAttribute>
+ const downloadAttribute = shareAttributes.find(({ scope, key }: ShareAttribute) => scope === 'permissions' && key === 'download')
+ if (downloadAttribute !== undefined) {
+ return downloadAttribute.value === true
+ }
+ }
+
+ return true
+}