Cleanup UriUploader a bit, and add tests for private paths

Signed-off-by: Álvaro Brey <alvaro.brey@nextcloud.com>
This commit is contained in:
Álvaro Brey 2022-07-20 16:15:04 +02:00
parent cd3bd0845a
commit 8f8274cab2
No known key found for this signature in database
GPG key ID: 2585783189A62105
2 changed files with 76 additions and 25 deletions

View file

@ -0,0 +1,52 @@
package com.owncloud.android.ui.helpers
import android.net.Uri
import androidx.test.core.app.launchActivity
import com.nextcloud.client.TestActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.files.services.FileUploader
import org.junit.Assert
import org.junit.Test
class UriUploaderIT : AbstractIT() {
@Test
fun testUploadPrivatePathSharedPreferences() {
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { activity ->
val packageName = activity.packageName
val path = "file:///data/data/$packageName/shared_prefs/com.nextcloud.client_preferences.xml"
testPrivatePath(activity, path)
}
}
}
@Test
fun testUploadPrivatePathUserFile() {
launchActivity<TestActivity>().use { scenario ->
scenario.onActivity { activity ->
val packageName = activity.packageName
val path = "file:///storage/emulated/0/Android/media/$packageName/nextcloud/test/welcome.txt"
testPrivatePath(activity, path)
}
}
}
private fun testPrivatePath(activity: TestActivity, path: String) {
val sut = UriUploader(
activity,
listOf(Uri.parse(path)),
"",
activity.user.orElseThrow(::RuntimeException),
FileUploader.LOCAL_BEHAVIOUR_MOVE,
false,
null
)
val uploadResult = sut.uploadUris()
Assert.assertEquals(
"Wrong result code",
UriUploader.UriUploaderResultCode.ERROR_SENSITIVE_PATH,
uploadResult
)
}
}

View file

@ -49,8 +49,7 @@ import com.owncloud.android.utils.UriUtils.getDisplayNameForUri
@Suppress( @Suppress(
"Detekt.LongParameterList", "Detekt.LongParameterList",
"Detekt.SpreadOperator", "Detekt.SpreadOperator",
"Detekt.TooGenericExceptionCaught", "Detekt.TooGenericExceptionCaught"
"Detekt.NestedBlockDepth"
) // legacy code ) // legacy code
class UriUploader( class UriUploader(
private val mActivity: FileActivity, private val mActivity: FileActivity,
@ -76,29 +75,23 @@ class UriUploader(
Log_OC.e(TAG, "Sensitive URI detected, aborting upload.") Log_OC.e(TAG, "Sensitive URI detected, aborting upload.")
code = UriUploaderResultCode.ERROR_SENSITIVE_PATH code = UriUploaderResultCode.ERROR_SENSITIVE_PATH
} else { } else {
val contentUris: MutableList<Uri> = ArrayList() val uris = mUrisToUpload.filterNotNull()
val contentRemotePaths: MutableList<String> = ArrayList() .map { it as Uri }
var schemeFileCounter = 0 .map { Pair(it, getRemotePathForUri(it)) }
for (sourceStream in mUrisToUpload) {
val sourceUri = sourceStream as Uri? val fileUris = uris
if (sourceUri != null) { .filter { it.first.scheme == ContentResolver.SCHEME_FILE }
val displayName = getDisplayNameForUri(sourceUri, mActivity) fileUris.forEach {
require(displayName != null) { "Display name cannot be null" } requestUpload(it.first.path, it.second)
val remotePath = mUploadPath + displayName
if (ContentResolver.SCHEME_CONTENT == sourceUri.scheme) {
contentUris.add(sourceUri)
contentRemotePaths.add(remotePath)
} else if (ContentResolver.SCHEME_FILE == sourceUri.scheme) {
// file: uris should point to a local file, should be safe let FileUploader handle them
requestUpload(sourceUri.path, remotePath)
schemeFileCounter++
} }
}
} val contentUrisNew = uris
if (contentUris.isNotEmpty()) { .filter { it.first.scheme == ContentResolver.SCHEME_CONTENT }
// content: uris will be copied to temporary files before calling {@link FileUploader}
copyThenUpload(contentUris.toTypedArray(), *contentRemotePaths.toTypedArray()) if (contentUrisNew.isNotEmpty()) {
} else if (schemeFileCounter == 0) { val (contentUris, contentRemotePaths) = contentUrisNew.unzip()
copyThenUpload(contentUris.toTypedArray(), contentRemotePaths.toTypedArray())
} else if (fileUris.isEmpty()) {
code = UriUploaderResultCode.ERROR_NO_FILE_TO_UPLOAD code = UriUploaderResultCode.ERROR_NO_FILE_TO_UPLOAD
} }
} }
@ -112,6 +105,12 @@ class UriUploader(
return code return code
} }
private fun getRemotePathForUri(sourceUri: Uri): String {
val displayName = getDisplayNameForUri(sourceUri, mActivity)
require(displayName != null) { "Display name cannot be null" }
return mUploadPath + displayName
}
private fun isSensitiveUri(uri: Uri): Boolean = uri.toString().contains(mActivity.packageName) private fun isSensitiveUri(uri: Uri): Boolean = uri.toString().contains(mActivity.packageName)
/** /**
@ -146,7 +145,7 @@ class UriUploader(
* @param sourceUris Array of content:// URIs to the files to upload * @param sourceUris Array of content:// URIs to the files to upload
* @param remotePaths Array of absolute paths to set to the uploaded files * @param remotePaths Array of absolute paths to set to the uploaded files
*/ */
private fun copyThenUpload(sourceUris: Array<Uri>, vararg remotePaths: String) { private fun copyThenUpload(sourceUris: Array<Uri>, remotePaths: Array<String>) {
if (mShowWaitingDialog) { if (mShowWaitingDialog) {
mActivity.showLoadingDialog(mActivity.resources.getString(R.string.wait_for_tmp_copy_from_private_storage)) mActivity.showLoadingDialog(mActivity.resources.getString(R.string.wait_for_tmp_copy_from_private_storage))
} }