Browse Source

Merge pull request #6479 from nextcloud/encUpdate

Fixed create folder due to new system (write on server is only performed upon unlock)
Andy Scherzinger 4 years ago
parent
commit
ed94dfb139

+ 66 - 0
src/androidTest/java/com/nextcloud/client/EndToEndRandomIT.java

@@ -32,10 +32,13 @@ import com.owncloud.android.lib.common.accounts.AccountUtils;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.e2ee.ToggleEncryptionRemoteOperation;
+import com.owncloud.android.lib.resources.status.OCCapability;
+import com.owncloud.android.lib.resources.status.OwnCloudVersion;
 import com.owncloud.android.lib.resources.users.GetPrivateKeyOperation;
 import com.owncloud.android.lib.resources.users.GetPublicKeyOperation;
 import com.owncloud.android.lib.resources.users.SendCSROperation;
 import com.owncloud.android.lib.resources.users.StorePrivateKeyOperation;
+import com.owncloud.android.operations.GetCapabilitiesOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.utils.CsrHelper;
 import com.owncloud.android.utils.EncryptionUtils;
@@ -52,9 +55,11 @@ import java.io.IOException;
 import java.security.KeyPair;
 import java.security.PrivateKey;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Random;
 
 import static com.owncloud.android.lib.resources.status.OwnCloudVersion.nextcloud_19;
+import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNotNull;
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assume.assumeTrue;
@@ -80,6 +85,12 @@ public class EndToEndRandomIT extends AbstractOnServerIT {
 
     @Before
     public void before() {
+        OCCapability capability = getStorageManager().getCapability(account.name);
+
+        if (capability.getVersion().equals(new OwnCloudVersion("0.0.0"))) {
+            // fetch new one
+            assertTrue(new GetCapabilitiesOperation().execute(client, getStorageManager()).isSuccess());
+        }
         // tests only for NC19+
         assumeTrue(getStorageManager()
                        .getCapability(account.name)
@@ -282,6 +293,7 @@ public class EndToEndRandomIT extends AbstractOnServerIT {
         }
 
         OCFile fileToDelete = files.get(new Random().nextInt(files.size()));
+        assertNotNull(fileToDelete.getRemoteId());
 
         Log_OC.d(this,
                  "[" + i + "/" + actionCount + "] " +
@@ -395,4 +407,58 @@ public class EndToEndRandomIT extends AbstractOnServerIT {
     private String generateMnemonicString() {
         return "1 2 3 4 5 6";
     }
+
+    public void after() {
+        // remove all encrypted files
+        OCFile root = fileDataStorageManager.getFileByDecryptedRemotePath("/");
+        removeFolder(root);
+
+//        List<OCFile> files = fileDataStorageManager.getFolderContent(root, false);
+//
+//        for (OCFile child : files) {
+//            removeFolder(child);
+//        }
+
+        assertEquals(0, fileDataStorageManager.getFolderContent(root, false).size());
+
+        super.after();
+    }
+
+    private void removeFolder(OCFile folder) {
+        Log_OC.d(this, "Start removing content of folder: " + folder.getDecryptedRemotePath());
+
+        List<OCFile> children = fileDataStorageManager.getFolderContent(folder, false);
+
+        // remove children
+        for (OCFile child : children) {
+            if (child.isFolder()) {
+                removeFolder(child);
+
+                // remove folder
+                Log_OC.d(this, "Remove folder: " + child.getDecryptedRemotePath());
+                if (!folder.isEncrypted() && child.isEncrypted()) {
+                    assertTrue(new ToggleEncryptionRemoteOperation(child.getLocalId(),
+                                                                   child.getRemotePath(),
+                                                                   false)
+                                   .execute(client)
+                                   .isSuccess());
+
+                    OCFile f = getStorageManager().getFileByEncryptedRemotePath(child.getRemotePath());
+                    f.setEncrypted(false);
+                    getStorageManager().saveFile(f);
+
+                    child.setEncrypted(false);
+                }
+            } else {
+                Log_OC.d(this, "Remove file: " + child.getDecryptedRemotePath());
+            }
+
+            assertTrue(new RemoveFileOperation(child, false, account, false, targetContext)
+                           .execute(client, getStorageManager())
+                           .isSuccess()
+                      );
+        }
+
+        Log_OC.d(this, "Finished removing content of folder: " + folder.getDecryptedRemotePath());
+    }
 }

+ 1 - 3
src/androidTest/java/com/owncloud/android/AbstractIT.java

@@ -9,7 +9,6 @@ import android.content.ActivityNotFoundException;
 import android.content.Context;
 
 import com.facebook.testing.screenshot.Screenshot;
-import com.nextcloud.client.RetryTestRule;
 import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
 import com.nextcloud.client.account.UserAccountManagerImpl;
@@ -35,7 +34,6 @@ import junit.framework.TestCase;
 
 import org.apache.commons.io.FileUtils;
 import org.junit.BeforeClass;
-import org.junit.Rule;
 
 import java.io.File;
 import java.io.FileWriter;
@@ -61,7 +59,7 @@ import static org.junit.Assert.assertTrue;
  */
 
 public abstract class AbstractIT {
-    @Rule public RetryTestRule retryTestRule = new RetryTestRule();
+    //@Rule public RetryTestRule retryTestRule = new RetryTestRule();
 
     protected static OwnCloudClient client;
     protected static Account account;

+ 5 - 0
src/androidTest/java/com/owncloud/android/AbstractOnServerIT.java

@@ -236,5 +236,10 @@ public abstract class AbstractOnServerIT extends AbstractIT {
 
         RemoteOperationResult result = newUpload.execute(client, getStorageManager());
         assertTrue(result.getLogMessage(), result.isSuccess());
+//
+//        shortSleep();
+//        shortSleep();
+//
+//        assertNotNull(getStorageManager().getFileByDecryptedRemotePath(ocUpload.getRemotePath()).getRemoteId());
     }
 }

+ 2 - 0
src/androidTest/java/com/owncloud/android/datamodel/FileDataStorageManagerContentResolverTest.java

@@ -26,5 +26,7 @@ public class FileDataStorageManagerContentResolverTest extends FileDataStorageMa
     @Override
     public void before() {
         sut = new FileDataStorageManager(account, targetContext.getContentResolver());
+
+        super.before();
     }
 }

+ 7 - 1
src/androidTest/java/com/owncloud/android/datamodel/FileDataStorageManagerTest.java

@@ -55,7 +55,13 @@ abstract public class FileDataStorageManagerTest extends AbstractOnServerIT {
     protected FileDataStorageManager sut;
 
     @Before
-    abstract public void before();
+    public void before() {
+        // make sure everything is removed
+        sut.deleteAllFiles();
+        sut.deleteVirtuals(VirtualFolderType.PHOTOS);
+
+        assertEquals(0, sut.getAllFiles().size());
+    }
 
     @After
     public void after() {

+ 98 - 0
src/androidTest/java/com/owncloud/android/operations/RemoveFileOperationIT.java

@@ -0,0 +1,98 @@
+/*
+ *
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2020 Tobias Kaminsky
+ * Copyright (C) 2020 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package com.owncloud.android.operations;
+
+import com.owncloud.android.AbstractOnServerIT;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.db.OCUpload;
+import com.owncloud.android.utils.FileStorageUtils;
+
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+
+public class RemoveFileOperationIT extends AbstractOnServerIT {
+    @Test
+    public void deleteFolder() {
+        String parent = "/test/";
+        String path = parent + "folder1/";
+        assertTrue(new CreateFolderOperation(path, user, targetContext).execute(client, getStorageManager())
+                       .isSuccess());
+
+        OCFile folder = getStorageManager().getFileByPath(path);
+
+        assertNotNull(folder);
+
+        assertTrue(new RemoveFileOperation(folder,
+                                           false,
+                                           account,
+                                           false,
+                                           targetContext)
+                       .execute(client, getStorageManager())
+                       .isSuccess());
+
+        OCFile parentFolder = getStorageManager().getFileByPath(parent);
+
+        assertNotNull(parentFolder);
+        assertTrue(new RemoveFileOperation(parentFolder,
+                                           false,
+                                           account,
+                                           false,
+                                           targetContext)
+                       .execute(client, getStorageManager())
+                       .isSuccess());
+    }
+
+    @Test
+    public void deleteFile() {
+        String parent = "/test/";
+        String path = parent + "empty.txt";
+        OCUpload ocUpload = new OCUpload(FileStorageUtils.getSavePath(account.name) + "/empty.txt", path, account.name);
+
+        uploadOCUpload(ocUpload);
+
+        OCFile file = getStorageManager().getFileByPath(path);
+
+        assertNotNull(file);
+
+        assertTrue(new RemoveFileOperation(file,
+                                           false,
+                                           account,
+                                           false,
+                                           targetContext)
+                       .execute(client, getStorageManager())
+                       .isSuccess());
+
+        OCFile parentFolder = getStorageManager().getFileByPath(parent);
+
+        assertNotNull(parentFolder);
+        assertTrue(new RemoveFileOperation(parentFolder,
+                                           false,
+                                           account,
+                                           false,
+                                           targetContext)
+                       .execute(client, getStorageManager())
+                       .isSuccess());
+    }
+}

+ 37 - 27
src/main/java/com/owncloud/android/operations/CreateFolderOperation.java

@@ -21,7 +21,6 @@
 
 package com.owncloud.android.operations;
 
-import android.accounts.Account;
 import android.content.Context;
 import android.os.Build;
 import android.util.Pair;
@@ -159,31 +158,6 @@ public class CreateFolderOperation extends SyncOperation implements OnRemoteOper
                 .execute(client);
 
             if (result.isSuccess()) {
-                RemoteOperationResult remoteFolderOperationResult = new ReadFolderRemoteOperation(encryptedRemotePath)
-                    .execute(client);
-
-                createdRemoteFolder = (RemoteFile) remoteFolderOperationResult.getData().get(0);
-                OCFile newDir = new OCFile(createdRemoteFolder.getRemotePath());
-                newDir.setMimeType(MimeType.DIRECTORY);
-
-                newDir.setParentId(parent.getFileId());
-                newDir.setRemoteId(createdRemoteFolder.getRemoteId());
-                newDir.setModificationTimestamp(System.currentTimeMillis());
-                newDir.setEncrypted(true);
-                newDir.setPermissions(createdRemoteFolder.getPermissions());
-                newDir.setDecryptedRemotePath(parent.getDecryptedRemotePath() + filename + "/");
-                getStorageManager().saveFile(newDir);
-
-                RemoteOperationResult encryptionOperationResult = new ToggleEncryptionRemoteOperation(
-                    newDir.getLocalId(),
-                    newDir.getRemotePath(),
-                    true)
-                    .execute(client);
-
-                if (!encryptionOperationResult.isSuccess()) {
-                    throw new RuntimeException("Error creating encrypted subfolder!");
-                }
-
                 // Key, always generate new one
                 byte[] key = EncryptionUtils.generateKey();
 
@@ -212,6 +186,43 @@ public class CreateFolderOperation extends SyncOperation implements OnRemoteOper
                                                token,
                                                client,
                                                metadataExists);
+
+                // unlock folder
+                if (token != null) {
+                    RemoteOperationResult unlockFolderResult = EncryptionUtils.unlockFolder(parent, client, token);
+
+                    if (unlockFolderResult.isSuccess()) {
+                        token = null;
+                    } else {
+                        // TODO do better
+                        throw new RuntimeException("Could not unlock folder!");
+                    }
+                }
+
+                RemoteOperationResult remoteFolderOperationResult = new ReadFolderRemoteOperation(encryptedRemotePath)
+                    .execute(client);
+
+                createdRemoteFolder = (RemoteFile) remoteFolderOperationResult.getData().get(0);
+                OCFile newDir = new OCFile(createdRemoteFolder.getRemotePath());
+                newDir.setMimeType(MimeType.DIRECTORY);
+
+                newDir.setParentId(parent.getFileId());
+                newDir.setRemoteId(createdRemoteFolder.getRemoteId());
+                newDir.setModificationTimestamp(System.currentTimeMillis());
+                newDir.setEncrypted(true);
+                newDir.setPermissions(createdRemoteFolder.getPermissions());
+                newDir.setDecryptedRemotePath(parent.getDecryptedRemotePath() + filename + "/");
+                getStorageManager().saveFile(newDir);
+
+                RemoteOperationResult encryptionOperationResult = new ToggleEncryptionRemoteOperation(
+                    newDir.getLocalId(),
+                    newDir.getRemotePath(),
+                    true)
+                    .execute(client);
+
+                if (!encryptionOperationResult.isSuccess()) {
+                    throw new RuntimeException("Error creating encrypted subfolder!");
+                }
             } else {
                 // revert to sane state in case of any error
                 Log_OC.e(TAG, remotePath + " hasn't been created");
@@ -249,7 +260,6 @@ public class CreateFolderOperation extends SyncOperation implements OnRemoteOper
             // TODO do better
             return new RemoteOperationResult(e);
         } finally {
-
             // unlock folder
             if (token != null) {
                 RemoteOperationResult unlockFolderResult = EncryptionUtils.unlockFolder(parent, client, token);

+ 1 - 1
src/main/java/com/owncloud/android/operations/RemoveFileOperation.java

@@ -106,7 +106,7 @@ public class RemoveFileOperation extends SyncOperation {
                                                                    context,
                                                                    fileToRemove.getEncryptedFileName());
             } else {
-                operation = new RemoveFileRemoteOperation(fileToRemove.getDecryptedRemotePath());
+                operation = new RemoveFileRemoteOperation(fileToRemove.getRemotePath());
             }
             result = operation.execute(client);
             if (result.isSuccess() || result.getCode() == ResultCode.FILE_NOT_FOUND) {

+ 15 - 7
src/main/java/com/owncloud/android/operations/UploadFileOperation.java

@@ -604,7 +604,7 @@ public class UploadFileOperation extends SyncOperation {
                 metadata.getFiles().put(encryptedFileName, decryptedFile);
 
                 EncryptedFolderMetadata encryptedFolderMetadata = EncryptionUtils.encryptFolderMetadata(metadata,
-                        privateKey);
+                                                                                                        privateKey);
                 String serializedFolderMetadata = EncryptionUtils.serializeJSON(encryptedFolderMetadata);
 
                 // upload metadata
@@ -613,6 +613,13 @@ public class UploadFileOperation extends SyncOperation {
                                                token,
                                                client,
                                                metadataExists);
+
+                // unlock
+                result = EncryptionUtils.unlockFolder(parentFile, client, token);
+
+                if (result.isSuccess()) {
+                    token = null;
+                }
             }
         } catch (FileNotFoundException e) {
             Log_OC.d(TAG, mFile.getStoragePath() + " not exists anymore");
@@ -650,13 +657,14 @@ public class UploadFileOperation extends SyncOperation {
         }
 
         // unlock must be done always
-        // TODO check if in good state
-        RemoteOperationResult unlockFolderResult = EncryptionUtils.unlockFolder(parentFile,
-                                                                                client,
-                                                                                token);
+        if (token != null) {
+            RemoteOperationResult unlockFolderResult = EncryptionUtils.unlockFolder(parentFile,
+                                                                                    client,
+                                                                                    token);
 
-        if (!unlockFolderResult.isSuccess()) {
-            return unlockFolderResult;
+            if (!unlockFolderResult.isSuccess()) {
+                return unlockFolderResult;
+            }
         }
 
         // delete temporal file