Add checks for move or copy

Signed-off-by: alperozturk <alper_ozturk@proton.me>
This commit is contained in:
alperozturk 2024-07-03 16:38:08 +02:00 committed by Alper Öztürk
parent 7e85d80d8e
commit b6a732cdfd
5 changed files with 121 additions and 1 deletions

View file

@ -84,4 +84,76 @@ class FileNameValidatorTests : AbstractIT() {
assertTrue(FileNameValidator.isFileNameAlreadyExist("existingFile", existingFiles)) assertTrue(FileNameValidator.isFileNameAlreadyExist("existingFile", existingFiles))
assertFalse(FileNameValidator.isFileNameAlreadyExist("newFile", existingFiles)) assertFalse(FileNameValidator.isFileNameAlreadyExist("newFile", existingFiles))
} }
@Test
fun testValidFolderAndFilePaths() {
val folderPath = "validFolder"
val filePaths = listOf("file1.txt", "file2.doc", "file3.jpg")
val result = FileNameValidator.checkPath(folderPath, filePaths, capability, targetContext)
assertTrue(result)
}
@Test
fun testFolderPathWithReservedName() {
val folderPath = "CON"
val filePaths = listOf("file1.txt", "file2.doc", "file3.jpg")
val result = FileNameValidator.checkPath(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFilePathWithReservedName() {
val folderPath = "validFolder"
val filePaths = listOf("file1.txt", "PRN.doc", "file3.jpg")
val result = FileNameValidator.checkPath(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFolderPathWithInvalidCharacter() {
val folderPath = "invalid<Folder"
val filePaths = listOf("file1.txt", "file2.doc", "file3.jpg")
val result = FileNameValidator.checkPath(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFilePathWithInvalidCharacter() {
val folderPath = "validFolder"
val filePaths = listOf("file1.txt", "file|2.doc", "file3.jpg")
val result = FileNameValidator.checkPath(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFolderPathEndingWithSpace() {
val folderPath = "folderWithSpace "
val filePaths = listOf("file1.txt", "file2.doc", "file3.jpg")
val result = FileNameValidator.checkPath(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFilePathEndingWithPeriod() {
val folderPath = "validFolder"
val filePaths = listOf("file1.txt", "file2.doc", "file3.")
val result = FileNameValidator.checkPath(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
@Test
fun testFilePathWithNestedFolder() {
val folderPath = "validFolder\\secondValidFolder\\CON"
val filePaths = listOf("file1.txt", "file2.doc", "file3.")
val result = FileNameValidator.checkPath(folderPath, filePaths, capability, targetContext)
assertFalse(result)
}
} }

View file

@ -15,3 +15,12 @@ fun String.getRandomString(length: Int): String {
return this + result return this + result
} }
fun String.removeFileExtension(): String {
val dotIndex = lastIndexOf('.')
return if (dotIndex != -1) {
substring(0, dotIndex)
} else {
this
}
}

View file

@ -9,6 +9,7 @@ package com.nextcloud.utils.fileNameValidator
import android.content.Context import android.content.Context
import android.text.TextUtils import android.text.TextUtils
import com.nextcloud.utils.extensions.removeFileExtension
import com.owncloud.android.R import com.owncloud.android.R
import com.owncloud.android.lib.resources.status.OCCapability import com.owncloud.android.lib.resources.status.OCCapability
@ -46,7 +47,9 @@ object FileNameValidator {
return it return it
} }
if (capability.forbiddenFilenames.isTrue && reservedWindowsNames.contains(name.uppercase())) { if (capability.forbiddenFilenames.isTrue &&
(reservedWindowsNames.contains(name.uppercase()) || reservedWindowsNames.contains(name.removeFileExtension().uppercase()))
) {
return context.getString(R.string.file_name_validator_error_reserved_names) return context.getString(R.string.file_name_validator_error_reserved_names)
} }
@ -57,6 +60,24 @@ object FileNameValidator {
return null return null
} }
fun checkPath(folderPath: String, filePaths: List<String>, capability: OCCapability, context: Context): Boolean {
val folderPaths = folderPath.split("/", "\\")
for (item in folderPaths) {
if (isValid(item, capability, context) != null) {
return false
}
}
for (item in filePaths) {
if (isValid(item, capability, context) != null) {
return false
}
}
return true
}
private fun checkInvalidCharacters(name: String, capability: OCCapability, context: Context): String? { private fun checkInvalidCharacters(name: String, capability: OCCapability, context: Context): String? {
if (capability.forbiddenFilenameCharacters.isFalse) return null if (capability.forbiddenFilenameCharacters.isFalse) return null

View file

@ -15,6 +15,8 @@ import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.res.Resources import android.content.res.Resources
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Parcelable import android.os.Parcelable
import android.view.ActionMode import android.view.ActionMode
import android.view.Menu import android.view.Menu
@ -23,6 +25,7 @@ import android.view.View
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.nextcloud.client.di.Injectable import com.nextcloud.client.di.Injectable
import com.nextcloud.utils.fileNameValidator.FileNameValidator
import com.owncloud.android.R import com.owncloud.android.R
import com.owncloud.android.databinding.FilesFolderPickerBinding import com.owncloud.android.databinding.FilesFolderPickerBinding
import com.owncloud.android.databinding.FilesPickerBinding import com.owncloud.android.databinding.FilesPickerBinding
@ -441,6 +444,7 @@ open class FolderPickerActivity :
} }
} }
@Suppress("MagicNumber")
private fun processOperation(action: String?) { private fun processOperation(action: String?) {
val i = intent val i = intent
val resultData = Intent() val resultData = Intent()
@ -451,6 +455,18 @@ open class FolderPickerActivity :
} }
targetFilePaths?.let { filePaths -> targetFilePaths?.let { filePaths ->
val isPathValid = FileNameValidator.checkPath(file.remotePath, filePaths, capabilities, this)
if (!isPathValid) {
DisplayUtils.showSnackMessage(this, R.string.file_name_validator_error_copy_or_move)
Handler(Looper.getMainLooper()).postDelayed({
setResult(RESULT_CANCELED, resultData)
finish()
}, 1000L)
return
}
action?.let { action -> action?.let { action ->
fileOperationsHelper.moveOrCopyFiles(action, filePaths, file) fileOperationsHelper.moveOrCopyFiles(action, filePaths, file)
} }

View file

@ -1219,6 +1219,8 @@
<string name="unified_search_fragment_contact_not_found">Contact not found, you can always sync to update. Redirecting to web…</string> <string name="unified_search_fragment_contact_not_found">Contact not found, you can always sync to update. Redirecting to web…</string>
<string name="unified_search_fragment_permission_needed">Permissions are required to open search result otherwise it will redirected to web…</string> <string name="unified_search_fragment_permission_needed">Permissions are required to open search result otherwise it will redirected to web…</string>
<string name="file_name_validator_error_copy_or_move">Folder path contains reserved names or invalid character</string>
<string name="file_name_validator_error_invalid_character">File name contains invalid characters: %s</string> <string name="file_name_validator_error_invalid_character">File name contains invalid characters: %s</string>
<string name="file_name_validator_error_reserved_names">File name is a reserved name</string> <string name="file_name_validator_error_reserved_names">File name is a reserved name</string>
<string name="file_name_validator_error_ends_with_space_period">File name ends with a space or a period</string> <string name="file_name_validator_error_ends_with_space_period">File name ends with a space or a period</string>