From 71557b9b0b388ce45e31740e66c5f0e8cd7616ed Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 10 Oct 2023 09:47:15 +0200 Subject: [PATCH 1/5] Handle user disabled exception as its own result code Signed-off-by: tobiasKaminsky --- .../files/UploadFileRemoteOperationIT.kt | 34 +++++++++++++++++++ .../ChunkedFileUploadRemoteOperationIT.kt | 17 ++++++++++ .../common/operations/ExceptionParser.java | 6 ++++ .../operations/RemoteOperationResult.java | 12 +++++-- 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt index 8376af46c..2bd6e0881 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt @@ -9,9 +9,13 @@ package com.owncloud.android.lib.resources.files import android.os.Build import com.owncloud.android.AbstractIT +import com.owncloud.android.lib.common.OwnCloudBasicCredentials +import com.owncloud.android.lib.common.OwnCloudClientFactory +import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.model.RemoteFile import junit.framework.TestCase.assertEquals +import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Test @@ -22,6 +26,7 @@ import java.nio.file.attribute.BasicFileAttributes import java.util.concurrent.TimeUnit class UploadFileRemoteOperationIT : AbstractIT() { + @Throws(IOException::class) @Test fun creationTime() { val imageFile = getFile("imageFile.png") @@ -30,6 +35,7 @@ class UploadFileRemoteOperationIT : AbstractIT() { assertTrue(creationDate!! > (System.currentTimeMillis() / MILLI_TO_SECOND) - TIME_OFFSET) } + @Throws(IOException::class) @Test fun upload() { // create file @@ -80,6 +86,34 @@ class UploadFileRemoteOperationIT : AbstractIT() { ) } + @Throws(IOException::class) + @Test + fun uploadWithDisabledUser() { + // use disabled user + val client3 = OwnCloudClientFactory.createOwnCloudClient(url, context, true) + client3.credentials = OwnCloudBasicCredentials("disabled", "disabled") + + // create file + val filePath = createFile("text") + val remotePath = "/test.md" + + val creationTimestamp = getCreationTimestamp(File(filePath)) + val sut = + UploadFileRemoteOperation( + filePath, + remotePath, + "text/markdown", + "", + RANDOM_MTIME, + creationTimestamp, + true + ) + + val uploadResult = sut.execute(client3) + assertFalse(uploadResult.isSuccess) + assertEquals(RemoteOperationResult.ResultCode.USER_DISABLED, uploadResult.code) + } + private fun getCreationTimestamp(file: File): Long? { return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { return null diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt index 31f834e3d..786499870 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt @@ -8,12 +8,16 @@ package com.owncloud.android.lib.resources.files.webdav import com.owncloud.android.AbstractIT +import com.owncloud.android.lib.common.OwnCloudBasicCredentials +import com.owncloud.android.lib.common.OwnCloudClientFactory import com.owncloud.android.lib.common.network.WebdavEntry import com.owncloud.android.lib.common.network.WebdavUtils import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.resources.files.ChunkedFileUploadRemoteOperation import junit.framework.TestCase +import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertFalse import junit.framework.TestCase.assertNotNull import org.apache.jackrabbit.webdav.client.methods.PropFindMethod import org.junit.Test @@ -59,6 +63,19 @@ class ChunkedFileUploadRemoteOperationIT : AbstractIT() { TestCase.assertSame(ResultCode.CANCELLED, uploadResult?.code) } + @Test + fun uploadWithDisabledUser() { + // use disabled user + val client3 = OwnCloudClientFactory.createOwnCloudClient(url, context, true) + client3.credentials = OwnCloudBasicCredentials("disabled", "disabled") + + val sut = genLargeUpload(true) + val uploadResult = sut.execute(client3) + + assertFalse(uploadResult.isSuccess) + assertEquals(ResultCode.USER_DISABLED, uploadResult.code) + } + @Test fun resume() { val filePath = createFile("chunkedFile.txt", BIG_FILE_ITERATION * 2) diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/ExceptionParser.java b/library/src/main/java/com/owncloud/android/lib/common/operations/ExceptionParser.java index 623502062..b52c0745f 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/operations/ExceptionParser.java +++ b/library/src/main/java/com/owncloud/android/lib/common/operations/ExceptionParser.java @@ -30,6 +30,8 @@ public class ExceptionParser { private static final String INVALID_PATH_EXCEPTION_STRING = "OC\\Connector\\Sabre\\Exception\\InvalidPath"; private static final String INVALID_PATH_EXCEPTION_UPLOAD_STRING = "OCP\\Files\\InvalidPathException"; private static final String VIRUS_EXCEPTION_STRING = "OCA\\DAV\\Connector\\Sabre\\Exception\\UnsupportedMediaType"; + private static final String USER_DISABLED_MESSAGE = "OC\\User\\LoginException: Account disabled"; + private static final String SERVICE_UNAVAILABLE_STRING = "Sabre\\DAV\\Exception\\ServiceUnavailable"; // No namespaces private static final String ns = null; @@ -76,6 +78,10 @@ public boolean isVirusException() { return VIRUS_EXCEPTION_STRING.equalsIgnoreCase(exception) && message.startsWith("Virus"); } + public boolean isUserDisabledException() { + return SERVICE_UNAVAILABLE_STRING.equals(exception) && USER_DISABLED_MESSAGE.equalsIgnoreCase(message); + } + /** * Parse OCS node * diff --git a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java index 48453ee4f..72285a46a 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java +++ b/library/src/main/java/com/owncloud/android/lib/common/operations/RemoteOperationResult.java @@ -130,7 +130,8 @@ public enum ResultCode { VIRUS_DETECTED, FOLDER_ALREADY_EXISTS, CANNOT_CREATE_FILE, - LOCKED + LOCKED, + USER_DISABLED } private boolean mSuccess = false; @@ -324,7 +325,10 @@ public RemoteOperationResult(boolean success, OkHttpMethodBase httpMethod) { public RemoteOperationResult(boolean success, HttpMethod httpMethod) { this(success, httpMethod.getStatusCode(), httpMethod.getStatusText(), httpMethod.getResponseHeaders()); - if (mHttpCode == HttpStatus.SC_BAD_REQUEST || mHttpCode == HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE) { + if (mHttpCode == HttpStatus.SC_BAD_REQUEST || + mHttpCode == HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE || + mHttpCode == HttpStatus.SC_SERVICE_UNAVAILABLE || + mHttpCode == HttpStatus.SC_UNAUTHORIZED) { try { String bodyResponse = httpMethod.getResponseBodyAsString(); @@ -339,6 +343,10 @@ public RemoteOperationResult(boolean success, HttpMethod httpMethod) { mCode = ResultCode.VIRUS_DETECTED; } + if (xmlParser.isUserDisabledException()) { + mCode = ResultCode.USER_DISABLED; + } + mHttpPhrase = xmlParser.getMessage(); } } catch (Exception e) { From e31414e5b9b0a7367667a21484e3daccbd302727 Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 14 Jan 2025 08:18:18 +0100 Subject: [PATCH 2/5] disable bruteforce Signed-off-by: tobiasKaminsky --- .drone.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 30eec7f8c..f2bab4859 100644 --- a/.drone.yml +++ b/.drone.yml @@ -70,6 +70,7 @@ services: - su www-data -c "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash" - su www-data -c "source ~/.bashrc; nvm install node" - /usr/local/bin/initnc.sh + - sed -i "3i'auth.bruteforce.protection.enabled' => false," config/config.php - su www-data -c "php /var/www/html/occ log:manage --level warning" - su www-data -c "OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1" - su www-data -c "OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2" @@ -187,6 +188,7 @@ services: - su www-data -c "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash" - su www-data -c "source ~/.bashrc; nvm install node" - BRANCH="$SERVER_VERSION" /usr/local/bin/initnc.sh + - sed -i "3i'auth.bruteforce.protection.enabled' => false," config/config.php - su www-data -c "php /var/www/html/occ log:manage --level warning" - su www-data -c "OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1" - su www-data -c "OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2" @@ -235,6 +237,6 @@ trigger: - pull_request --- kind: signature -hmac: 3e71a44f6f57a4d4d853c586c0c322bf0b718d96627906b92864e12353e5a014 +hmac: 16bfb471ab277c0a835cec54323e774e681796a57a9b1bd623945e9e4ea602a2 ... From eb4c3bb5d3a93abc243bff095c5c6744218d38ac Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 14 Jan 2025 08:26:54 +0100 Subject: [PATCH 3/5] disable bruteforce Signed-off-by: tobiasKaminsky --- .drone.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.drone.yml b/.drone.yml index f2bab4859..76a139448 100644 --- a/.drone.yml +++ b/.drone.yml @@ -70,7 +70,7 @@ services: - su www-data -c "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash" - su www-data -c "source ~/.bashrc; nvm install node" - /usr/local/bin/initnc.sh - - sed -i "3i'auth.bruteforce.protection.enabled' => false," config/config.php + - sed -i "3i'auth.bruteforce.protection.enabled' => false," /var/www/html/config/config.php - su www-data -c "php /var/www/html/occ log:manage --level warning" - su www-data -c "OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1" - su www-data -c "OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2" @@ -188,7 +188,7 @@ services: - su www-data -c "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash" - su www-data -c "source ~/.bashrc; nvm install node" - BRANCH="$SERVER_VERSION" /usr/local/bin/initnc.sh - - sed -i "3i'auth.bruteforce.protection.enabled' => false," config/config.php + - sed -i "3i'auth.bruteforce.protection.enabled' => false," /var/www/html/config/config.php - su www-data -c "php /var/www/html/occ log:manage --level warning" - su www-data -c "OC_PASS=user1 php /var/www/html/occ user:add --password-from-env --display-name='User One' user1" - su www-data -c "OC_PASS=user2 php /var/www/html/occ user:add --password-from-env --display-name='User Two' user2" @@ -237,6 +237,6 @@ trigger: - pull_request --- kind: signature -hmac: 16bfb471ab277c0a835cec54323e774e681796a57a9b1bd623945e9e4ea602a2 +hmac: affd20484da7cefd212f5c6a389f9bb1801bceee8f5c93d08ac64c5f12a24eb0 ... From 7a08d74bc5c52d4dcc68229b600b6ae8204d594c Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 14 Jan 2025 10:28:21 +0100 Subject: [PATCH 4/5] add user "disabled" Signed-off-by: tobiasKaminsky --- .drone.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 76a139448..47430e712 100644 --- a/.drone.yml +++ b/.drone.yml @@ -77,6 +77,8 @@ services: - su www-data -c "OC_PASS=user3 php /var/www/html/occ user:add --password-from-env --display-name='User Three' user3" - su www-data -c "OC_PASS=test php /var/www/html/occ user:add --password-from-env --display-name='Test@Test' test@test" - su www-data -c "OC_PASS=test php /var/www/html/occ user:add --password-from-env --display-name='Test Spaces' 'test test'" + - su www-data -c "OC_PASS=disabled php /var/www/html/occ user:add --password-from-env --display-name='Disabled' 'disabled'" + - su www-data -c "php /var/www/html/occ user:disable disabled" - su www-data -c "php /var/www/html/occ user:setting user2 files quota 1G" - su www-data -c "php /var/www/html/occ group:add users" - su www-data -c "php /var/www/html/occ group:adduser users user1" @@ -195,6 +197,8 @@ services: - su www-data -c "OC_PASS=user3 php /var/www/html/occ user:add --password-from-env --display-name='User Three' user3" - su www-data -c "OC_PASS=test php /var/www/html/occ user:add --password-from-env --display-name='Test@Test' test@test" - su www-data -c "OC_PASS=test php /var/www/html/occ user:add --password-from-env --display-name='Test Spaces' 'test test'" + - su www-data -c "OC_PASS=disabled php /var/www/html/occ user:add --password-from-env --display-name='Disabled' 'disabled'" + - su www-data -c "php /var/www/html/occ user:disable disabled" - su www-data -c "php /var/www/html/occ user:setting user2 files quota 1G" - su www-data -c "php /var/www/html/occ group:add users" - su www-data -c "php /var/www/html/occ group:adduser users user1" @@ -237,6 +241,6 @@ trigger: - pull_request --- kind: signature -hmac: affd20484da7cefd212f5c6a389f9bb1801bceee8f5c93d08ac64c5f12a24eb0 +hmac: e1e69dd987460a8794e6923b226173da09dc90d855e1dd4d7a6cc0d4b1580ecf ... From da3cc4ddea4f02c3e10b235cd2a25d6d5626ceef Mon Sep 17 00:00:00 2001 From: tobiasKaminsky Date: Tue, 14 Jan 2025 12:26:18 +0100 Subject: [PATCH 5/5] test ony with NC31+ Signed-off-by: tobiasKaminsky --- .../android/lib/resources/files/UploadFileRemoteOperationIT.kt | 3 +++ .../files/webdav/ChunkedFileUploadRemoteOperationIT.kt | 3 +++ .../owncloud/android/lib/resources/status/NextcloudVersion.kt | 3 +++ 3 files changed, 9 insertions(+) diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt index 2bd6e0881..c2af7db95 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperationIT.kt @@ -14,6 +14,7 @@ import com.owncloud.android.lib.common.OwnCloudClientFactory import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.lib.resources.files.model.RemoteFile +import com.owncloud.android.lib.resources.status.NextcloudVersion import junit.framework.TestCase.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -89,6 +90,8 @@ class UploadFileRemoteOperationIT : AbstractIT() { @Throws(IOException::class) @Test fun uploadWithDisabledUser() { + testOnlyOnServer(NextcloudVersion.nextcloud_31) + // use disabled user val client3 = OwnCloudClientFactory.createOwnCloudClient(url, context, true) client3.credentials = OwnCloudBasicCredentials("disabled", "disabled") diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt index 786499870..e6f8ec5c3 100644 --- a/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt +++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/files/webdav/ChunkedFileUploadRemoteOperationIT.kt @@ -15,6 +15,7 @@ import com.owncloud.android.lib.common.network.WebdavUtils import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode import com.owncloud.android.lib.resources.files.ChunkedFileUploadRemoteOperation +import com.owncloud.android.lib.resources.status.NextcloudVersion import junit.framework.TestCase import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertFalse @@ -65,6 +66,8 @@ class ChunkedFileUploadRemoteOperationIT : AbstractIT() { @Test fun uploadWithDisabledUser() { + testOnlyOnServer(NextcloudVersion.nextcloud_31) + // use disabled user val client3 = OwnCloudClientFactory.createOwnCloudClient(url, context, true) client3.credentials = OwnCloudBasicCredentials("disabled", "disabled") diff --git a/library/src/main/java/com/owncloud/android/lib/resources/status/NextcloudVersion.kt b/library/src/main/java/com/owncloud/android/lib/resources/status/NextcloudVersion.kt index 5fc1d25cf..50ffa3608 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/status/NextcloudVersion.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/status/NextcloudVersion.kt @@ -38,6 +38,9 @@ class NextcloudVersion : OwnCloudVersion { @JvmField val nextcloud_30 = NextcloudVersion(0x1E000000) // 30.0 + + @JvmField + val nextcloud_31 = NextcloudVersion(0x1F000000) // 31.0 } constructor(string: String) : super(string)