Sfoglia il codice sorgente

Merge pull request #12796 from nextcloud/bugfix/e2e-upload-by-alper

Fix Upload Problems For Encrypted Folder
Tobias Kaminsky 1 anno fa
parent
commit
4592c17df0

+ 3 - 2
app/src/main/java/com/nextcloud/client/jobs/upload/FileUploadWorker.kt

@@ -235,7 +235,7 @@ class FileUploadWorker(
     }
 
     private fun cleanupUploadProcess(result: RemoteOperationResult<Any?>, operation: UploadFileOperation) {
-        if (!(isStopped && result.isCancelled)) {
+        if (!isStopped || !result.isCancelled) {
             uploadsStorageManager.updateDatabaseUploadResult(result, operation)
             notifyUploadResult(operation, result)
             notificationManager.dismissWorkerNotifications()
@@ -288,17 +288,18 @@ class FileUploadWorker(
                 context.resources
             )
 
-            // FIXME SYNC_CONFLICT passes wrong OCFile, check ConflictsResolveActivity.createIntent usage
             val conflictResolveIntent = if (uploadResult.code == ResultCode.SYNC_CONFLICT) {
                 intents.conflictResolveActionIntents(context, uploadFileOperation)
             } else {
                 null
             }
+
             val credentialIntent: PendingIntent? = if (uploadResult.code == ResultCode.UNAUTHORIZED) {
                 intents.credentialIntent(uploadFileOperation)
             } else {
                 null
             }
+
             notifyForFailedResult(uploadResult.code, conflictResolveIntent, credentialIntent, errorMessage)
             showNewNotification(uploadFileOperation)
         }

+ 25 - 32
app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java

@@ -23,6 +23,7 @@ package com.owncloud.android.operations;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.content.Intent;
 import android.net.Uri;
 import android.text.TextUtils;
 
@@ -98,6 +99,9 @@ import javax.crypto.Cipher;
 
 import androidx.annotation.CheckResult;
 import androidx.annotation.Nullable;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import static com.owncloud.android.ui.activity.FileDisplayActivity.REFRESH_FOLDER_EVENT_RECEIVER;
 
 
 /**
@@ -455,6 +459,7 @@ public class UploadFileOperation extends SyncOperation {
 
         boolean metadataExists = false;
         String token = null;
+        Object object = null;
 
         ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(getContext());
         String publicKey = arbitraryDataProvider.getValue(user.getAccountName(), EncryptionUtils.PUBLIC_KEY);
@@ -466,6 +471,7 @@ public class UploadFileOperation extends SyncOperation {
             if (result != null) {
                 return result;
             }
+
             /***** E2E *****/
             // Only on V2+: whenever we change something, increase counter
             long counter = -1;
@@ -485,13 +491,7 @@ public class UploadFileOperation extends SyncOperation {
 
             // Update metadata
             EncryptionUtilsV2 encryptionUtilsV2 = new EncryptionUtilsV2();
-//            kotlin.Pair<Boolean, DecryptedFolderMetadataFile> metadataPair =
-//                encryptionUtilsV2.retrieveMetadata(parentFile,
-//                                                   client,
-//                                                   user,
-//                                                   mContext);
-
-            Object object = EncryptionUtils.downloadFolderMetadata(parentFile, client, mContext, user);
+            object = EncryptionUtils.downloadFolderMetadata(parentFile, client, mContext, user);
             if (object instanceof DecryptedFolderMetadataFileV1 decrypted && decrypted.getMetadata() != null) {
                 metadataExists = true;
             }
@@ -703,13 +703,6 @@ public class UploadFileOperation extends SyncOperation {
                                                    "",
                                                    arbitraryDataProvider,
                                                    user);
-
-                    // unlock
-                    result = EncryptionUtils.unlockFolderV1(parentFile, client, token);
-
-                    if (result.isSuccess()) {
-                        token = null;
-                    }
                 } else {
                     DecryptedFolderMetadataFile metadata = (DecryptedFolderMetadataFile) object;
                     encryptionUtilsV2.addFileToMetadata(
@@ -730,13 +723,6 @@ public class UploadFileOperation extends SyncOperation {
                                                                  mContext,
                                                                  user,
                                                                  getStorageManager());
-
-                    // unlock
-                    result = EncryptionUtils.unlockFolder(parentFile, client, token);
-
-                    if (result.isSuccess()) {
-                        token = null;
-                    }
                 }
 
                 encryptedTempFile.delete();
@@ -751,6 +737,7 @@ public class UploadFileOperation extends SyncOperation {
             result = new RemoteOperationResult(e);
         } finally {
             mUploadStarted.set(false);
+            sendRefreshFolderEventBroadcast();
 
             if (fileLock != null) {
                 try {
@@ -768,6 +755,18 @@ public class UploadFileOperation extends SyncOperation {
             }
 
             logResult(result, mFile.getStoragePath(), mFile.getRemotePath());
+
+            // Unlock must be done otherwise folder stays locked and user can't upload any file
+            RemoteOperationResult<Void> unlockFolderResult;
+            if (object instanceof DecryptedFolderMetadataFileV1) {
+                unlockFolderResult = EncryptionUtils.unlockFolderV1(parentFile, client, token);
+            } else {
+                unlockFolderResult = EncryptionUtils.unlockFolder(parentFile, client, token);
+            }
+
+            if (unlockFolderResult != null && !unlockFolderResult.isSuccess()) {
+                result = unlockFolderResult;
+            }
         }
 
         if (result.isSuccess()) {
@@ -776,17 +775,6 @@ public class UploadFileOperation extends SyncOperation {
             getStorageManager().saveConflict(mFile, mFile.getEtagInConflict());
         }
 
-        // unlock must be done always
-        if (token != null) {
-            RemoteOperationResult unlockFolderResult = EncryptionUtils.unlockFolder(parentFile,
-                                                                                    client,
-                                                                                    token);
-
-            if (!unlockFolderResult.isSuccess()) {
-                return unlockFolderResult;
-            }
-        }
-
         // delete temporal file
         if (temporalFile != null && temporalFile.exists() && !temporalFile.delete()) {
             Log_OC.e(TAG, "Could not delete temporal file " + temporalFile.getAbsolutePath());
@@ -795,6 +783,11 @@ public class UploadFileOperation extends SyncOperation {
         return result;
     }
 
+    private void sendRefreshFolderEventBroadcast() {
+        Intent intent = new Intent(REFRESH_FOLDER_EVENT_RECEIVER);
+        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
+    }
+
     private RemoteOperationResult checkConditions(File originalFile) {
         RemoteOperationResult remoteOperationResult = null;
 

+ 23 - 0
app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -69,6 +69,7 @@ import com.nextcloud.client.jobs.download.FileDownloadHelper;
 import com.nextcloud.client.jobs.download.FileDownloadWorker;
 import com.nextcloud.client.jobs.upload.FileUploadHelper;
 import com.nextcloud.client.jobs.upload.FileUploadWorker;
+import com.nextcloud.client.jobs.upload.UploadNotificationManager;
 import com.nextcloud.client.media.PlayerServiceConnection;
 import com.nextcloud.client.network.ClientFactory;
 import com.nextcloud.client.network.ConnectivityService;
@@ -229,6 +230,8 @@ public class FileDisplayActivity extends FileActivity
     public static final String KEY_IS_SEARCH_OPEN = "IS_SEARCH_OPEN";
     public static final String KEY_SEARCH_QUERY = "SEARCH_QUERY";
 
+    public static final String REFRESH_FOLDER_EVENT_RECEIVER = "REFRESH_FOLDER_EVENT";
+
     private String searchQuery = "";
     private boolean searchOpen;
 
@@ -236,6 +239,7 @@ public class FileDisplayActivity extends FileActivity
     private PlayerServiceConnection mPlayerConnection;
     private Optional<User> lastDisplayedUser = Optional.empty();
     private int menuItemId = -1;
+
     @Inject AppPreferences preferences;
 
     @Inject AppInfo appInfo;
@@ -283,6 +287,7 @@ public class FileDisplayActivity extends FileActivity
 
         initSyncBroadcastReceiver();
         observeWorkerState();
+        registerRefreshFolderEventReceiver();
     }
 
     @SuppressWarnings("unchecked")
@@ -2296,6 +2301,24 @@ public class FileDisplayActivity extends FileActivity
         checkForNewDevVersionNecessary(getApplicationContext());
     }
 
+    private void registerRefreshFolderEventReceiver() {
+        IntentFilter filter = new IntentFilter(REFRESH_FOLDER_EVENT_RECEIVER);
+        LocalBroadcastManager.getInstance(this).registerReceiver(refreshFolderEventReceiver, filter);
+    }
+
+    private final BroadcastReceiver refreshFolderEventReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            syncAndUpdateFolder(true);
+        }
+    };
+
+    @Override
+    protected void onDestroy() {
+        LocalBroadcastManager.getInstance(this).unregisterReceiver(refreshFolderEventReceiver);
+        super.onDestroy();
+    }
+
     @Override
     protected void onRestart() {
         super.onRestart();

+ 8 - 10
app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java

@@ -22,13 +22,11 @@
 package com.owncloud.android.utils;
 
 import android.content.Context;
-import android.os.Build;
 import android.text.TextUtils;
 import android.util.Base64;
 import android.util.Pair;
 
 import com.google.common.collect.Lists;
-import com.google.common.primitives.Bytes;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.reflect.TypeToken;
@@ -73,17 +71,14 @@ import org.apache.commons.httpclient.HttpStatus;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.RandomAccessFile;
 import java.math.BigInteger;
 import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.Key;
@@ -114,7 +109,6 @@ import java.util.UUID;
 
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
-import javax.crypto.CipherInputStream;
 import javax.crypto.CipherOutputStream;
 import javax.crypto.IllegalBlockSizeException;
 import javax.crypto.KeyGenerator;
@@ -127,7 +121,6 @@ import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.SecretKeySpec;
 
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -516,8 +509,12 @@ public final class EncryptionUtils {
                 new TypeToken<>() {
                 });
 
-            if ("2.0".equals(v2.getVersion()) || "2".equals(v2.getVersion())) {
-                return E2EVersion.V2_0;
+            if (v2 != null) {
+                if ("2.0".equals(v2.getVersion()) || "2".equals(v2.getVersion())) {
+                    return E2EVersion.V2_0;
+                }
+            } else {
+                return E2EVersion.UNKNOWN;
             }
         }
 
@@ -565,7 +562,8 @@ public final class EncryptionUtils {
     }
 
     public static EncryptedFile encryptFile(File file, Cipher cipher) throws InvalidParameterSpecException {
-        File encryptedFile = new File(file.getAbsolutePath() + ".enc");
+        // FIXME this won't work on low or write-protected storage
+        File encryptedFile = new File(file.getAbsolutePath() + ".enc.jpg");
         encryptFileWithGivenCipher(file, encryptedFile, cipher);
         String authenticationTagString = getAuthenticationTag(cipher);
         return new EncryptedFile(encryptedFile, authenticationTagString);