Browse Source

fix(files): Do not escape file names for filepicker buttons

The text is already escaped by Vue, so we should not escape or sanitize the filename.

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Ferdinand Thiessen 1 month ago
parent
commit
b9caf24228

+ 2 - 2
apps/files/src/actions/moveOrCopyAction.ts

@@ -212,7 +212,7 @@ const openFilePickerForAction = async (action: MoveCopyAction, dir = '/', nodes:
 
 			if (action === MoveCopyAction.COPY || action === MoveCopyAction.MOVE_OR_COPY) {
 				buttons.push({
-					label: target ? t('files', 'Copy to {target}', { target }) : t('files', 'Copy'),
+					label: target ? t('files', 'Copy to {target}', { target }, undefined, { escape: false, sanitize: false }) : t('files', 'Copy'),
 					type: 'primary',
 					icon: CopyIconSvg,
 					async callback(destination: Node[]) {
@@ -237,7 +237,7 @@ const openFilePickerForAction = async (action: MoveCopyAction, dir = '/', nodes:
 
 			if (action === MoveCopyAction.MOVE || action === MoveCopyAction.MOVE_OR_COPY) {
 				buttons.push({
-					label: target ? t('files', 'Move to {target}', { target }) : t('files', 'Move'),
+					label: target ? t('files', 'Move to {target}', { target }, undefined, { escape: false, sanitize: false }) : t('files', 'Move'),
 					type: action === MoveCopyAction.MOVE ? 'primary' : 'secondary',
 					icon: FolderMoveSvg,
 					async callback(destination: Node[]) {

+ 1 - 1
cypress/e2e/files/FilesUtils.ts

@@ -90,7 +90,7 @@ export const copyFile = (fileName: string, dirName: string) => {
 			cy.contains('button', 'Copy').should('be.visible').click()
 		} else {
 			// select folder
-			cy.get(`[data-filename="${dirName}"]`).should('be.visible').click()
+			cy.get(`[data-filename="${CSS.escape(dirName)}"]`).should('be.visible').click()
 			// click copy
 			cy.contains('button', `Copy to ${dirName}`).should('be.visible').click()
 		}

+ 38 - 0
cypress/e2e/files/files_copy-move.cy.ts

@@ -35,6 +35,7 @@ describe('Files: Move or copy files', { testIsolation: true }, () => {
 		cy.deleteUser(currentUser)
 	})
 
+
 	it('Can copy a file to new folder', () => {
 		// Prepare initial state
 		cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
@@ -136,4 +137,41 @@ describe('Files: Move or copy files', { testIsolation: true }, () => {
 		getRowForFile('original.txt').should('be.visible')
 		getRowForFile('original (copy 2).txt').should('be.visible')
 	})
+
+	/** Test for https://github.com/nextcloud/server/issues/43329 */
+	context.only('escaping file and folder names', () => {
+		it('Can handle files with special characters', () => {
+			cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
+				.mkdir(currentUser, '/can\'t say')
+			cy.login(currentUser)
+			cy.visit('/apps/files')
+
+			copyFile('original.txt', 'can\'t say')
+
+			navigateToFolder('can\'t say')
+
+			cy.url().should('contain', 'dir=/can%27t%20say')
+			getRowForFile('original.txt').should('be.visible')
+			getRowForFile('can\'t say').should('not.exist')
+		})
+
+		/**
+		 * If escape is set to false (required for test above) then "<a>foo" would result in "<a>foo</a>" if sanitizing is not disabled
+		 * We should disable it as vue already escapes the text when using v-text
+		 */
+		it('does not incorrectly sanitize file names', () => {
+			cy.uploadContent(currentUser, new Blob(), 'text/plain', '/original.txt')
+				.mkdir(currentUser, '/<a href="#">foo')
+			cy.login(currentUser)
+			cy.visit('/apps/files')
+
+			copyFile('original.txt', '<a href="#">foo')
+
+			navigateToFolder('<a href="#">foo')
+
+			cy.url().should('contain', 'dir=/%3Ca%20href%3D%22%23%22%3Efoo')
+			getRowForFile('original.txt').should('be.visible')
+			getRowForFile('<a href="#">foo').should('not.exist')
+		})
+	})
 })