From fbf52fc4bf4df76914d8c4177355bceceffe1255 Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Thu, 15 May 2025 21:11:25 +0200 Subject: [PATCH 01/10] - - --- .../common/OwnCloudClientManagerFactory.java | 9 +++ .../ChunkedFileUploadRemoteOperation.java | 29 +++++++++ .../files/DownloadFileRemoteOperation.java | 60 ++++++++++++++++++- .../lib/resources/files/FileUtils.java | 23 +++++++ .../files/UploadFileRemoteOperation.java | 17 ++++++ 5 files changed, 136 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java index 71227d1569..10ee1df482 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java +++ b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -15,6 +15,7 @@ public class OwnCloudClientManagerFactory { private static String sUserAgent = "Mozilla/5.0 (Android) Nextcloud-android"; private static String proxyHost = ""; private static int proxyPort = -1; + private static boolean hash_check_enable = false; public static OwnCloudClientManager getDefaultSingleton() { if (sDefaultSingleton == null) { @@ -46,4 +47,12 @@ public static void setProxyPort(int port) { public static int getProxyPort() { return proxyPort; } + + public static void setHASHcheck(boolean status) { + hash_check_enable = status; + } + + public static boolean getHASHcheck() { + return hash_check_enable; + } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java index 818c4e0e4a..a68c8c09d2 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java @@ -9,6 +9,7 @@ import android.text.TextUtils; import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.network.ChunkFromFileChannelRequestEntity; import com.owncloud.android.lib.common.network.ProgressiveDataTransfer; import com.owncloud.android.lib.common.network.WebdavEntry; @@ -36,6 +37,11 @@ import androidx.annotation.VisibleForTesting; +import java.io.FileInputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.nio.ByteBuffer; +import java.math.BigInteger; public class ChunkedFileUploadRemoteOperation extends UploadFileRemoteOperation { @@ -216,6 +222,11 @@ protected RemoteOperationResult run(OwnCloudClient client) { moveMethod = new MoveMethod(originUri, destinationUri, true); moveMethod.addRequestHeader(OC_X_OC_MTIME_HEADER, String.valueOf(lastModificationTimestamp)); + String Hash = FileUtils.getHASHfromFile(this, new File(localPath), "SHA-256"); + if(Hash != null){ + putMethod.addRequestHeader("X-Content-Hash", Hash); + } + if (creationTimestamp != null && creationTimestamp > 0) { moveMethod.addRequestHeader(OC_X_OC_CTIME_HEADER, String.valueOf(creationTimestamp)); } @@ -291,6 +302,24 @@ private RemoteOperationResult uploadChunk(OwnCloudClient client, Chunk chunk) th putMethod.addRequestHeader(E2E_TOKEN, token); } + if (OwnCloudClientManagerFactory.getHASHcheck()) { + try (RandomAccessFile hashRaf = new RandomAccessFile(file, "r")) { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + + FileChannel hashChannel = hashRaf.getChannel(); + ByteBuffer buf = ByteBuffer.allocate((int) chunk.getLength()); + hashChannel.position(chunk.getStart()); + hashChannel.read(buf); + md.update(buf.array()); + + String chunkHash = String.format("%064x", new BigInteger(1, md.digest())); + + putMethod.addRequestHeader("X-Content-Hash", chunkHash); + } catch (Exception e) { + Log_OC.w(TAG, "Could not compute chunk hash"); + } + } + status = client.executeMethod(putMethod); result = new RemoteOperationResult(isSuccess(status), putMethod); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java index b5de6ebf99..32e0ee2640 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java @@ -7,6 +7,7 @@ package com.owncloud.android.lib.resources.files; import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.OperationCancelledException; @@ -28,6 +29,15 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.io.FileInputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.math.BigInteger; +import java.util.Locale; + +import androidx.annotation.NonNull; + + /** * Remote operation performing the download of a remote file in the ownCloud server. * @@ -135,8 +145,54 @@ private int downloadFile(OwnCloudClient client, File targetFile) throws IOExcept transferEncoding = "chunked".equals(transferEncodingHeader.getValue()); } - if (transferred == totalToTransfer || transferEncoding) { - savedFile = true; + if (transferred == totalToTransfer || transferEncoding) { + if (OwnCloudClientManagerFactory.getHASHcheck()){ + Header hashHeader = getMethod.getResponseHeader("X-Content-Hash"); + String expectedHash = hashHeader != null ? hashHeader.getValue() : null; + if (expectedHash != null) { + try { + String[] entries = expectedHash.split(","); + for (String entry : entries) { + String[] parts = entry.split(";", 2); + if (parts.length != 2) continue; + String Algorithm = parts[0].trim().toLowerCase(Locale.ROOT); + String hash = parts[1].trim(); + + String digestAlgorithm = null; + + switch (Algorithm) { + case "sha-256": + digestAlgorithm = "SHA-256"; + break; + default: + // Skip unknown algorithm + continue; + } + + String FileHash = FileUtils.getHASHfromFile(this, targetFile, digestAlgorithm); + + if (!hash.equalsIgnoreCase(FileHash)) { + // Hash is incorrect: delete file and abort + Log_OC.w(TAG, "Hash mismatch: expected="+ hash +" actual="+ FileHash); + status = 418; + savedFile = false; + }else{ + savedFile = true; + break; + } + } + } catch (Exception e) { + Log_OC.w(TAG, "Could not compute chunk hash"); + status = 418; + savedFile = false; + } + }else { + savedFile = true; + } + }else { + savedFile = true; + } + Header modificationTime = getMethod.getResponseHeader("Last-Modified"); if (modificationTime == null) { modificationTime = getMethod.getResponseHeader("last-modified"); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java b/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java index fa9f794603..53054958cd 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java @@ -7,19 +7,42 @@ package com.owncloud.android.lib.resources.files; import java.io.File; +import java.io.FileInputStream; import java.math.BigInteger; +import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; +import com.owncloud.android.lib.common.utils.Log_OC; + public class FileUtils { private static final String TAG = FileUtils.class.getSimpleName(); public static final String PATH_SEPARATOR = "/"; + public static String getHASHfromFile(Object thi, File f, String digestAlgorithm) { + if (OwnCloudClientManagerFactory.getHASHcheck()) { + try { + MessageDigest md = MessageDigest.getInstance(digestAlgorithm); + try (FileInputStream fis = new FileInputStream(f); + DigestInputStream dis = new DigestInputStream(fis, md)) { + byte[] buffer = new byte[8192]; + while (dis.read(buffer) != -1) { + // digest is updated by reading + } + } + return String.format("%064x", new BigInteger(1, md.digest())); + } catch (Exception e) { + Log_OC.w(thi, "Could not compute chunk hash"); + } + } + return null; + } public static String getParentPath(String remotePath) { String parentPath = new File(remotePath).getParent(); parentPath = parentPath.endsWith(PATH_SEPARATOR) ? parentPath : parentPath + PATH_SEPARATOR; diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java index 652e22f1f9..ac14940c2a 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java @@ -12,12 +12,14 @@ import androidx.annotation.VisibleForTesting; import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.network.FileRequestEntity; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.network.ProgressiveDataTransfer; import com.owncloud.android.lib.common.operations.OperationCancelledException; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; import org.apache.commons.httpclient.Header; @@ -32,6 +34,15 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.io.FileInputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.math.BigInteger; + + + + /** * Remote operation performing the upload of a remote file to the ownCloud server. * @@ -211,6 +222,12 @@ protected RemoteOperationResult uploadFile(OwnCloudClient client) throws } putMethod.setRequestEntity(entity); + + String Hash = FileUtils.getHASHfromFile(this, f, "SHA-256"); + if(Hash != null){ + putMethod.addRequestHeader("X-Content-Hash", Hash); + } + status = client.executeMethod(putMethod); result = new RemoteOperationResult<>(isSuccess(status), putMethod); From 012b77bd4dbc356916864b23a570b1686821b2db Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Thu, 15 May 2025 21:38:59 +0200 Subject: [PATCH 02/10] enhancement Signed-off-by: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> --- .../common/OwnCloudClientManagerFactory.java | 9 +++ .../ChunkedFileUploadRemoteOperation.java | 28 +++++++++ .../files/DownloadFileRemoteOperation.java | 60 ++++++++++++++++++- .../lib/resources/files/FileUtils.java | 23 +++++++ .../files/UploadFileRemoteOperation.java | 15 +++++ 5 files changed, 133 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java index 71227d1569..10ee1df482 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java +++ b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -15,6 +15,7 @@ public class OwnCloudClientManagerFactory { private static String sUserAgent = "Mozilla/5.0 (Android) Nextcloud-android"; private static String proxyHost = ""; private static int proxyPort = -1; + private static boolean hash_check_enable = false; public static OwnCloudClientManager getDefaultSingleton() { if (sDefaultSingleton == null) { @@ -46,4 +47,12 @@ public static void setProxyPort(int port) { public static int getProxyPort() { return proxyPort; } + + public static void setHASHcheck(boolean status) { + hash_check_enable = status; + } + + public static boolean getHASHcheck() { + return hash_check_enable; + } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java index 818c4e0e4a..ed601eba65 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java @@ -36,6 +36,11 @@ import androidx.annotation.VisibleForTesting; +import java.io.FileInputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.nio.ByteBuffer; +import java.math.BigInteger; public class ChunkedFileUploadRemoteOperation extends UploadFileRemoteOperation { @@ -216,6 +221,11 @@ protected RemoteOperationResult run(OwnCloudClient client) { moveMethod = new MoveMethod(originUri, destinationUri, true); moveMethod.addRequestHeader(OC_X_OC_MTIME_HEADER, String.valueOf(lastModificationTimestamp)); + String Hash = FileUtils.getHASHfromFile(this, new File(localPath), "SHA-256"); + if(Hash != null){ + putMethod.addRequestHeader("X-Content-Hash", Hash); + } + if (creationTimestamp != null && creationTimestamp > 0) { moveMethod.addRequestHeader(OC_X_OC_CTIME_HEADER, String.valueOf(creationTimestamp)); } @@ -291,6 +301,24 @@ private RemoteOperationResult uploadChunk(OwnCloudClient client, Chunk chunk) th putMethod.addRequestHeader(E2E_TOKEN, token); } + if (OwnCloudClientManagerFactory.getHASHcheck()) { + try (RandomAccessFile hashRaf = new RandomAccessFile(file, "r")) { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + + FileChannel hashChannel = hashRaf.getChannel(); + ByteBuffer buf = ByteBuffer.allocate((int) chunk.getLength()); + hashChannel.position(chunk.getStart()); + hashChannel.read(buf); + md.update(buf.array()); + + String chunkHash = String.format("%064x", new BigInteger(1, md.digest())); + + putMethod.addRequestHeader("X-Content-Hash", chunkHash); + } catch (Exception e) { + Log_OC.w(TAG, "Could not compute chunk hash"); + } + } + status = client.executeMethod(putMethod); result = new RemoteOperationResult(isSuccess(status), putMethod); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java index b5de6ebf99..07186c4628 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java @@ -7,6 +7,7 @@ package com.owncloud.android.lib.resources.files; import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.network.WebdavUtils; import com.owncloud.android.lib.common.operations.OperationCancelledException; @@ -28,6 +29,15 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.io.FileInputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.math.BigInteger; +import java.util.Locale; + +import androidx.annotation.NonNull; + + /** * Remote operation performing the download of a remote file in the ownCloud server. * @@ -135,8 +145,54 @@ private int downloadFile(OwnCloudClient client, File targetFile) throws IOExcept transferEncoding = "chunked".equals(transferEncodingHeader.getValue()); } - if (transferred == totalToTransfer || transferEncoding) { - savedFile = true; + if (transferred == totalToTransfer || transferEncoding) { + if (OwnCloudClientManagerFactory.getHASHcheck()){ + Header hashHeader = getMethod.getResponseHeader("X-Content-Hash"); + String expectedHash = hashHeader != null ? hashHeader.getValue() : null; + if (expectedHash != null) { + try { + String[] entries = expectedHash.split(","); + for (String entry : entries) { + String[] parts = entry.split(";", 2); + if (parts.length != 2) continue; + String Algorithm = parts[0].trim().toLowerCase(Locale.ROOT); + String hash = parts[1].trim(); + + String digestAlgorithm = null; + + switch (Algorithm) { + case "sha-256": + digestAlgorithm = "SHA-256"; + break; + default: + // Skip unknown algorithm + continue; + } + + String FileHash = FileUtils.getHASHfromFile(this, targetFile, digestAlgorithm); + + if (!hash.equalsIgnoreCase(FileHash)) { + // Hash is incorrect: delete file and abort + Log_OC.w(TAG, "Hash mismatch: expected="+ hash +" actual="+ FileHash); + status = 418; + savedFile = false; + }else{ + savedFile = true; + break; + } + } + } catch (Exception e) { + Log_OC.w(TAG, "Could not compute chunk hash"); + status = 418; + savedFile = false; + } + }else { + savedFile = true; + } + }else { + savedFile = true; + } + Header modificationTime = getMethod.getResponseHeader("Last-Modified"); if (modificationTime == null) { modificationTime = getMethod.getResponseHeader("last-modified"); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java b/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java index fa9f794603..53054958cd 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java @@ -7,19 +7,42 @@ package com.owncloud.android.lib.resources.files; import java.io.File; +import java.io.FileInputStream; import java.math.BigInteger; +import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; +import com.owncloud.android.lib.common.utils.Log_OC; + public class FileUtils { private static final String TAG = FileUtils.class.getSimpleName(); public static final String PATH_SEPARATOR = "/"; + public static String getHASHfromFile(Object thi, File f, String digestAlgorithm) { + if (OwnCloudClientManagerFactory.getHASHcheck()) { + try { + MessageDigest md = MessageDigest.getInstance(digestAlgorithm); + try (FileInputStream fis = new FileInputStream(f); + DigestInputStream dis = new DigestInputStream(fis, md)) { + byte[] buffer = new byte[8192]; + while (dis.read(buffer) != -1) { + // digest is updated by reading + } + } + return String.format("%064x", new BigInteger(1, md.digest())); + } catch (Exception e) { + Log_OC.w(thi, "Could not compute chunk hash"); + } + } + return null; + } public static String getParentPath(String remotePath) { String parentPath = new File(remotePath).getParent(); parentPath = parentPath.endsWith(PATH_SEPARATOR) ? parentPath : parentPath + PATH_SEPARATOR; diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java index 652e22f1f9..4a38614411 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java @@ -32,6 +32,15 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.io.FileInputStream; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.math.BigInteger; + + + + /** * Remote operation performing the upload of a remote file to the ownCloud server. * @@ -211,6 +220,12 @@ protected RemoteOperationResult uploadFile(OwnCloudClient client) throws } putMethod.setRequestEntity(entity); + + String Hash = FileUtils.getHASHfromFile(this, f, "SHA-256"); + if(Hash != null){ + putMethod.addRequestHeader("X-Content-Hash", Hash); + } + status = client.executeMethod(putMethod); result = new RemoteOperationResult<>(isSuccess(status), putMethod); From 05ff4d8c91f25c264dd1bea5a34d0560e79da92c Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Thu, 15 May 2025 21:53:09 +0200 Subject: [PATCH 03/10] remove unnecessary lines and add import OwnCloud Client Manager Factory Signed-off-by: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> --- .../files/ChunkedFileUploadRemoteOperation.java | 3 +-- .../lib/resources/files/DownloadFileRemoteOperation.java | 6 ------ .../lib/resources/files/UploadFileRemoteOperation.java | 9 --------- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java index ed601eba65..7d1ca75de4 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java @@ -9,6 +9,7 @@ import android.text.TextUtils; import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.network.ChunkFromFileChannelRequestEntity; import com.owncloud.android.lib.common.network.ProgressiveDataTransfer; import com.owncloud.android.lib.common.network.WebdavEntry; @@ -36,8 +37,6 @@ import androidx.annotation.VisibleForTesting; -import java.io.FileInputStream; -import java.security.DigestInputStream; import java.security.MessageDigest; import java.nio.ByteBuffer; import java.math.BigInteger; diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java index 07186c4628..3ec338d4fd 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java @@ -29,14 +29,8 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import java.io.FileInputStream; -import java.security.DigestInputStream; -import java.security.MessageDigest; -import java.math.BigInteger; import java.util.Locale; -import androidx.annotation.NonNull; - /** * Remote operation performing the download of a remote file in the ownCloud server. diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java index 4a38614411..aa6b38bc8c 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java @@ -32,15 +32,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import java.io.FileInputStream; -import java.security.DigestInputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.math.BigInteger; - - - - /** * Remote operation performing the upload of a remote file to the ownCloud server. * From 3342d51a8dd0adcf4a4166f1d4ed7a3a5050ac64 Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Thu, 15 May 2025 22:13:29 +0200 Subject: [PATCH 04/10] fix Signed-off-by: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> --- .../lib/resources/files/DownloadFileRemoteOperation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java index 3ec338d4fd..17bb7becc9 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java @@ -155,7 +155,7 @@ private int downloadFile(OwnCloudClient client, File targetFile) throws IOExcept String digestAlgorithm = null; switch (Algorithm) { - case "sha-256": + case "sha256": digestAlgorithm = "SHA-256"; break; default: From 37f53e7706070172321be9c8085ea9c84d394a8a Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Mon, 19 May 2025 16:07:23 +0200 Subject: [PATCH 05/10] Update UploadFileRemoteOperation.java Signed-off-by: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> --- .../lib/resources/files/UploadFileRemoteOperation.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java index 99daefac04..8c3d7f1df9 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java @@ -12,14 +12,12 @@ import androidx.annotation.VisibleForTesting; import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.network.FileRequestEntity; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.network.ProgressiveDataTransfer; import com.owncloud.android.lib.common.operations.OperationCancelledException; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; -import com.owncloud.android.lib.common.utils.Log_OC; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; import org.apache.commons.httpclient.Header; @@ -34,11 +32,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; -import java.io.FileInputStream; -import java.security.DigestInputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.math.BigInteger; + From e9dfa544edd97cd3d9ef5d67045c02c86d397329 Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Mon, 19 May 2025 16:07:44 +0200 Subject: [PATCH 06/10] Update UploadFileRemoteOperation.java Signed-off-by: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> --- .../lib/resources/files/UploadFileRemoteOperation.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java index 8c3d7f1df9..c00ecbfeb1 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java @@ -32,11 +32,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; - - - - - /** * Remote operation performing the upload of a remote file to the ownCloud server. * From e65b40b1b265c1a1103cf37c6bf507b06462c26f Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Tue, 27 May 2025 15:36:33 +0200 Subject: [PATCH 07/10] Update library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Co-authored-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> Signed-off-by: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> --- .../android/lib/common/OwnCloudClientManagerFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java index 10ee1df482..ba987329fa 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java +++ b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -15,7 +15,7 @@ public class OwnCloudClientManagerFactory { private static String sUserAgent = "Mozilla/5.0 (Android) Nextcloud-android"; private static String proxyHost = ""; private static int proxyPort = -1; - private static boolean hash_check_enable = false; + private static boolean hashCheckEnable = false; public static OwnCloudClientManager getDefaultSingleton() { if (sDefaultSingleton == null) { From b8841852904f00529c827de107485b4bc618833f Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Tue, 27 May 2025 15:39:40 +0200 Subject: [PATCH 08/10] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Co-authored-by: Alper Öztürk <67455295+alperozturk96@users.noreply.github.com> Signed-off-by: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> --- .../android/lib/common/OwnCloudClientManagerFactory.java | 8 ++++---- .../files/ChunkedFileUploadRemoteOperation.java | 9 +++++---- .../lib/resources/files/DownloadFileRemoteOperation.java | 4 ++-- .../owncloud/android/lib/resources/files/FileUtils.java | 2 +- .../lib/resources/files/UploadFileRemoteOperation.java | 4 ++-- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java index ba987329fa..b70786b295 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java +++ b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -48,11 +48,11 @@ public static int getProxyPort() { return proxyPort; } - public static void setHASHcheck(boolean status) { - hash_check_enable = status; + public static void setHashCheck(boolean status) { + hashCheckEnable = status; } - public static boolean getHASHcheck() { - return hash_check_enable; + public static boolean getHashCheck() { + return hashCheckEnable; } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java index 7d1ca75de4..29c6ad110a 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/ChunkedFileUploadRemoteOperation.java @@ -220,9 +220,10 @@ protected RemoteOperationResult run(OwnCloudClient client) { moveMethod = new MoveMethod(originUri, destinationUri, true); moveMethod.addRequestHeader(OC_X_OC_MTIME_HEADER, String.valueOf(lastModificationTimestamp)); - String Hash = FileUtils.getHASHfromFile(this, new File(localPath), "SHA-256"); - if(Hash != null){ - putMethod.addRequestHeader("X-Content-Hash", Hash); + File localFile = new File(localPath); + String hash = FileUtils.getHashFromFile(this, localFile, "SHA-256"); + if(hash != null) { + putMethod.addRequestHeader("X-Content-Hash", hash); } if (creationTimestamp != null && creationTimestamp > 0) { @@ -300,7 +301,7 @@ private RemoteOperationResult uploadChunk(OwnCloudClient client, Chunk chunk) th putMethod.addRequestHeader(E2E_TOKEN, token); } - if (OwnCloudClientManagerFactory.getHASHcheck()) { + if (OwnCloudClientManagerFactory.getHashCheck()) { try (RandomAccessFile hashRaf = new RandomAccessFile(file, "r")) { MessageDigest md = MessageDigest.getInstance("SHA-256"); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java index 243150e895..72982d0256 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java @@ -163,9 +163,9 @@ private int downloadFile(OwnCloudClient client, File targetFile) throws IOExcept continue; } - String FileHash = FileUtils.getHASHfromFile(this, targetFile, digestAlgorithm); + String fileHash = FileUtils.getHashFromFile(this, targetFile, digestAlgorithm); - if (!hash.equalsIgnoreCase(FileHash)) { + if (!hash.equalsIgnoreCase(fileHash)) { // Hash is incorrect: delete file and abort Log_OC.w(TAG, "Hash mismatch: expected="+ hash +" actual="+ FileHash); status = 418; diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java b/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java index 53054958cd..aadd9bb960 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java @@ -24,7 +24,7 @@ public class FileUtils { public static final String PATH_SEPARATOR = "/"; - public static String getHASHfromFile(Object thi, File f, String digestAlgorithm) { + public static String getHashFromFile(Object thi, File f, String digestAlgorithm) { if (OwnCloudClientManagerFactory.getHASHcheck()) { try { MessageDigest md = MessageDigest.getInstance(digestAlgorithm); diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java index c00ecbfeb1..c7ea0a2d9d 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java @@ -212,9 +212,9 @@ protected RemoteOperationResult uploadFile(OwnCloudClient client) throws putMethod.setRequestEntity(entity); - String Hash = FileUtils.getHASHfromFile(this, f, "SHA-256"); + String Hash = FileUtils.getHashFromFile(this, f, "SHA-256"); if(Hash != null){ - putMethod.addRequestHeader("X-Content-Hash", Hash); + putMethod.addRequestHeader("X-Content-Hash", hash); } status = client.executeMethod(putMethod); From 3051d795cbbfd334b5238474cc9709e876a38f04 Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Tue, 10 Jun 2025 20:39:10 +0200 Subject: [PATCH 09/10] - --- .../lib/common/OwnCloudClientManagerFactory.java | 8 ++++++++ .../files/DownloadFileRemoteOperation.java | 16 +++++++++++++--- .../android/lib/resources/files/FileUtils.java | 2 +- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java index b70786b295..a49de6ef18 100644 --- a/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java +++ b/library/src/main/java/com/owncloud/android/lib/common/OwnCloudClientManagerFactory.java @@ -16,6 +16,7 @@ public class OwnCloudClientManagerFactory { private static String proxyHost = ""; private static int proxyPort = -1; private static boolean hashCheckEnable = false; + private static boolean hashCheckDownloadEnable = false; public static OwnCloudClientManager getDefaultSingleton() { if (sDefaultSingleton == null) { @@ -55,4 +56,11 @@ public static void setHashCheck(boolean status) { public static boolean getHashCheck() { return hashCheckEnable; } + public static void setHashDownloadCheck(boolean status) { + hashCheckDownloadEnable = status; + } + + public static boolean getHashDownloadCheck() { + return hashCheckDownloadEnable; + } } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java index 72982d0256..0ea4b7d2c6 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java @@ -6,6 +6,8 @@ */ package com.owncloud.android.lib.resources.files; +import android.os.Build; + import com.owncloud.android.lib.common.OwnCloudClient; import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; @@ -31,6 +33,8 @@ import java.util.Locale; +import androidx.annotation.RequiresApi; + /** * Remote operation performing the download of a remote file in the ownCloud server. * @@ -85,6 +89,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } + @RequiresApi(api = Build.VERSION_CODES.GINGERBREAD) private int downloadFile(OwnCloudClient client, File targetFile) throws IOException, OperationCancelledException, CreateLocalFileException { int status; boolean savedFile = false; @@ -139,7 +144,7 @@ private int downloadFile(OwnCloudClient client, File targetFile) throws IOExcept } if (transferred == totalToTransfer || transferEncoding) { - if (OwnCloudClientManagerFactory.getHASHcheck()){ + if (OwnCloudClientManagerFactory.getHashFromFile()){ Header hashHeader = getMethod.getResponseHeader("X-Content-Hash"); String expectedHash = hashHeader != null ? hashHeader.getValue() : null; if (expectedHash != null) { @@ -155,9 +160,14 @@ private int downloadFile(OwnCloudClient client, File targetFile) throws IOExcept switch (Algorithm) { case "sha256": - digestAlgorithm = "SHA-256"; break; + case "sha1": + digestAlgorithm = "SHA-1"; + break; + case "md5": + digestAlgorithm = "MD5"; + break; default: // Skip unknown algorithm continue; @@ -167,7 +177,7 @@ private int downloadFile(OwnCloudClient client, File targetFile) throws IOExcept if (!hash.equalsIgnoreCase(fileHash)) { // Hash is incorrect: delete file and abort - Log_OC.w(TAG, "Hash mismatch: expected="+ hash +" actual="+ FileHash); + Log_OC.w(TAG, "Hash mismatch: expected="+ hash +" actual="+ fileHash); status = 418; savedFile = false; }else{ diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java b/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java index aadd9bb960..f2fc9b56df 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/FileUtils.java @@ -25,7 +25,7 @@ public class FileUtils { public static final String PATH_SEPARATOR = "/"; public static String getHashFromFile(Object thi, File f, String digestAlgorithm) { - if (OwnCloudClientManagerFactory.getHASHcheck()) { + if (OwnCloudClientManagerFactory.getHashCheck()) { try { MessageDigest md = MessageDigest.getInstance(digestAlgorithm); From a4583c4509b97da55a76428841fd4996ddd84d8d Mon Sep 17 00:00:00 2001 From: Alexander-Ger-Reich <50119493+Alexander-Ger-Reich@users.noreply.github.com> Date: Tue, 10 Jun 2025 21:16:28 +0200 Subject: [PATCH 10/10] f --- .../lib/resources/files/DownloadFileRemoteOperation.java | 2 +- .../android/lib/resources/files/UploadFileRemoteOperation.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java index 0ea4b7d2c6..79e9115cf7 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/DownloadFileRemoteOperation.java @@ -144,7 +144,7 @@ private int downloadFile(OwnCloudClient client, File targetFile) throws IOExcept } if (transferred == totalToTransfer || transferEncoding) { - if (OwnCloudClientManagerFactory.getHashFromFile()){ + if (OwnCloudClientManagerFactory.getHashDownloadCheck()){ Header hashHeader = getMethod.getResponseHeader("X-Content-Hash"); String expectedHash = hashHeader != null ? hashHeader.getValue() : null; if (expectedHash != null) { diff --git a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java index c7ea0a2d9d..5801c1b7d8 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/files/UploadFileRemoteOperation.java @@ -214,7 +214,7 @@ protected RemoteOperationResult uploadFile(OwnCloudClient client) throws String Hash = FileUtils.getHashFromFile(this, f, "SHA-256"); if(Hash != null){ - putMethod.addRequestHeader("X-Content-Hash", hash); + putMethod.addRequestHeader("X-Content-Hash", Hash); } status = client.executeMethod(putMethod);