diff --git a/app/src/androidTest/assets/invalid_certs.json b/app/src/androidTest/assets/invalid_certs.json new file mode 100644 index 000000000000..e21885f10c80 --- /dev/null +++ b/app/src/androidTest/assets/invalid_certs.json @@ -0,0 +1,4 @@ +{ +"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Fujuh6usrHcIrIV1Dqb\nZ5JZ4ddl0ux/GW4SSMdfxXaL2HU6C/SzmrHVBwEoZYdK+1P0VnJqBgLPHEdvbf79\nazaJpR2Ll3VMN7GPYbreBcImyKezAOSzZaf1pIxOVAjRd+hMdT//6p+kYyxvS1q8\nNwbEp/bRwx8qa1+zaZ8rJPuriQEl/qd3ozUuG2P6jNlDaJYcFWKJJJsNFRYowhY7\nm4qnF8q3pgFPadY/HokE0T/pYUJ/jdUkeu/Nzl2F2oMoRpnYgyB9ZqjVB599bhKc\nmv9ey8nsFgo4u39dKTqXqIJRkvMMkG92g86qChYln3RCqHzDS+pzGJNVyUX51QPo\nYwIDAQAB\n-----END PUBLIC KEY-----\n", +"certificate": "-----BEGIN CERTIFICATE-----\nMIIDFDCCAfygAwIBAgIBADANBgkqhkiG9w0BAQUFADAjMSEwHwYDVQQDDBgxMjAw\nNDkwMTAwMDAwMDAzMTIzNjcyODMwHhcNMjQwMzA3MTQxNTA2WhcNNDQwMzAyMTQx\nNTA2WjAjMSEwHwYDVQQDDBgxMjAwNDkwMTAwMDAwMDAzMTIzNjcyODMwggEiMA0G\nCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCoQKjjsyhGZbnYM6+tv7HVNTw6P+xq\n0U+247wzdLfVPzyDOw41F2+UvL6hPY7GYQSpEGHVFUMlaJCP3TOBYxtbqYhj23ew\nL6oeIZia7DZbMNV9NvKHtFvyPzPPusFpKJuhFhcjULEsQ4RmsMvam3fJpPEm+Ngh\nDbUkNB1oEdEhB8qtqDI3QY3KGOH8SPeeMad38ALmsnxRrxqZtLGSRGBuMFFfo1HM\n+KEVlCIirwxcmciGThR0w9lsOe1Sjfi+3pj3BOjRAUxA7TTC1ec2BYCfk0TWXvVp\n7GT4SWeIEIQVgEY261hTdLywDeMUkoQAwZwvLKYyDLTuRgbcqjE/m1ILAgMBAAGj\nUzBRMB0GA1UdDgQWBBTokFvhPZPUAUPgGwFwSnzNpig6dTAfBgNVHSMEGDAWgBTo\nkFvhPZPUAUPgGwFwSnzNpig6dTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB\nBQUAA4IBAQC8al3bczyOTdMLflrjsY6Su7HEDzemtwgMhtAO++IIfqNoddemk4xM\n+gRjwJrk9W6UjwtUagaSQlFFnGn8SEZsBfrcJcTuxB+BSNw7mU1YmIGE0GnYzJ6U\n/OgM6XLzTCrxtpzVGCtnbTgFWZDE7oLdnv8ALD0AByz8EGGLyQPBiVCD+8Lk/Hic\nSOv+cl/6zkbW4pMgqMYlmPR5JNhx9vG9TEgM9V++W8qZGzdYxEkOLlIq2AV4z1Uz\nl/HLHmqU9o9+6kG3Jq/bhxmSb5IsDuzBFsL/ejogLcRx2l7aPn4Q7/9eFdz/dh6E\nWA0ZtxVcBbrQKKdzTMkazJHqOQ3AZwzL\n-----END CERTIFICATE-----" +} diff --git a/app/src/androidTest/java/com/nextcloud/utils/CertificateValidatorTests.kt b/app/src/androidTest/java/com/nextcloud/utils/CertificateValidatorTests.kt index 127858586a22..66583e0744fb 100644 --- a/app/src/androidTest/java/com/nextcloud/utils/CertificateValidatorTests.kt +++ b/app/src/androidTest/java/com/nextcloud/utils/CertificateValidatorTests.kt @@ -19,6 +19,7 @@ import java.io.InputStreamReader class CertificateValidatorTests { private var sut: CertificateValidator? = null + private val gson = Gson() @Before fun setup() { @@ -32,14 +33,24 @@ class CertificateValidatorTests { @Test fun testValidateWhenGivenValidServerKeyAndCertificateShouldReturnTrue() { + val isCertificateValid = validateCertificate("credentials.json") + assert(isCertificateValid) + } + + @Test + fun testValidateWhenGivenAnotherValidServerKeyAndCertificateShouldReturnTrue() { + val isCertificateValid = validateCertificate("invalid_certs.json") + assert(isCertificateValid) + } + + private fun validateCertificate(filename: String): Boolean { val inputStream = - InstrumentationRegistry.getInstrumentation().context.assets.open("credentials.json") + InstrumentationRegistry.getInstrumentation().context.assets.open(filename) val credentials = InputStreamReader(inputStream).use { reader -> - Gson().fromJson(reader, Credentials::class.java) + gson.fromJson(reader, Credentials::class.java) } - val isCertificateValid = sut?.validate(credentials.publicKey, credentials.certificate) ?: false - assert(isCertificateValid) + return sut?.validate(credentials.publicKey, credentials.certificate) ?: false } } diff --git a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java index f006888799f0..519ec7370ada 100644 --- a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java @@ -267,7 +267,7 @@ private RemoteOperationResult encryptedCreateV2(OCFile parent, OwnCloudClient cl // check if filename already exists if (isFileExisting(metadata, filename)) { - return new RemoteOperationResult(RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS); + return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS); } // generate new random file name, check if it exists in metadata @@ -279,9 +279,9 @@ private RemoteOperationResult encryptedCreateV2(OCFile parent, OwnCloudClient cl token) .execute(client); - String remoteId = result.getResultData(); - if (result.isSuccess()) { + String remoteId = result.getResultData(); + DecryptedFolderMetadataFile subFolderMetadata = encryptionUtilsV2.createDecryptedFolderMetadataFile(); // upload metadata @@ -294,9 +294,7 @@ private RemoteOperationResult encryptedCreateV2(OCFile parent, OwnCloudClient cl user, parent, getStorageManager()); - } - if (result.isSuccess()) { // update metadata DecryptedFolderMetadataFile updatedMetadataFile = encryptionUtilsV2.addFolderToMetadata(encryptedFileName, filename, @@ -314,48 +312,43 @@ private RemoteOperationResult encryptedCreateV2(OCFile parent, OwnCloudClient cl user, getStorageManager()); - // unlock folder - RemoteOperationResult unlockFolderResult = EncryptionUtils.unlockFolder(parent, client, token); - - if (unlockFolderResult.isSuccess()) { - token = null; - } else { - // TODO E2E: do better - throw new RuntimeException("Could not unlock folder!"); - } - - RemoteOperationResult remoteFolderOperationResult = new ReadFolderRemoteOperation(encryptedRemotePath) + final var remoteFolderOperationResult = new ReadFolderRemoteOperation(encryptedRemotePath) .execute(client); - createdRemoteFolder = (RemoteFile) remoteFolderOperationResult.getData().get(0); - OCFile newDir = createRemoteFolderOcFile(parent, filename, createdRemoteFolder); - getStorageManager().saveFile(newDir); + if (remoteFolderOperationResult.isSuccess()) { + createdRemoteFolder = (RemoteFile) remoteFolderOperationResult.getData().get(0); + OCFile newDir = createRemoteFolderOcFile(parent, filename, createdRemoteFolder); + getStorageManager().saveFile(newDir); - RemoteOperationResult encryptionOperationResult = new ToggleEncryptionRemoteOperation( - newDir.getLocalId(), - newDir.getRemotePath(), - true) - .execute(client); + final var encryptionOperationResult = new ToggleEncryptionRemoteOperation( + newDir.getLocalId(), + newDir.getRemotePath(), + true) + .execute(client); - if (!encryptionOperationResult.isSuccess()) { - throw new RuntimeException("Error creating encrypted subfolder!"); + 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"); } return result; } catch (Exception e) { - // TODO remove folder + if (token != null) { + final var unlockFolderResult = EncryptionUtils.unlockFolder(parent, client, token); - if (!EncryptionUtils.unlockFolder(parent, client, token).isSuccess()) { - throw new RuntimeException("Could not clean up after failing folder creation!", e); + if (!unlockFolderResult.isSuccess()) { + throw new RuntimeException("Could not unlock folder!"); + } else { + token = null; + } } // remove folder if (encryptedRemotePath != null) { - RemoteOperationResult removeResult = new RemoveRemoteEncryptedFileOperation(encryptedRemotePath, + final var removeResult = new RemoveRemoteEncryptedFileOperation(encryptedRemotePath, user, context, filename, @@ -367,16 +360,13 @@ private RemoteOperationResult encryptedCreateV2(OCFile parent, OwnCloudClient cl } } - // TODO E2E: do better - return new RemoteOperationResult(e); + return new RemoteOperationResult<>(e); } finally { - // unlock folder if (token != null) { - RemoteOperationResult unlockFolderResult = EncryptionUtils.unlockFolder(parent, client, token); + final var unlockFolderResult = EncryptionUtils.unlockFolder(parent, client, token); if (!unlockFolderResult.isSuccess()) { - // TODO E2E: do better - throw new RuntimeException("Could not unlock folder!"); + Log_OC.d(TAG, "Could not unlock folder!"); } } } diff --git a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java index 086006d40559..507a7d594a25 100644 --- a/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java @@ -495,7 +495,8 @@ private void synchronizeData(List folderAndFiles) { if (CapabilityUtils.getCapability(mContext).getEndToEndEncryptionApiVersion().compareTo(E2EVersion.V2_0) >= 0) { if (encryptedAncestor && object == null) { - throw new IllegalStateException("metadata is null!"); + Log_OC.d(TAG,"metadata is null!"); + return; } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 2b64bce92d3a..60f1607a2d2c 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1708,6 +1708,7 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe onSynchronizeFileOperationFinish((SynchronizeFileOperation) operation, result); } else if (operation instanceof CreateFolderOperation) { onCreateFolderOperationFinish((CreateFolderOperation) operation, result); + syncAndUpdateFolder(true); } else if (operation instanceof MoveFileOperation) { onMoveFileOperationFinish((MoveFileOperation) operation, result); } else if (operation instanceof CopyFileOperation) { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/setupEncryption/SetupEncryptionDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/setupEncryption/SetupEncryptionDialogFragment.kt index becfda347fa9..f12fb254e65e 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/setupEncryption/SetupEncryptionDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/setupEncryption/SetupEncryptionDialogFragment.kt @@ -307,11 +307,6 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable { if (isCertificateValid == false) { Log_OC.d(TAG, "Could not save certificate, certificate is not valid") - return null - } - - if (arbitraryDataProvider == null) { - return null } arbitraryDataProvider?.storeOrUpdateKeyValue( diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index d6725c51d7ef..81c35bc23585 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1820,7 +1820,7 @@ private void encryptFolder(OCFile folder, Log_OC.d(TAG, "encrypt folder " + folder.getRemoteId()); User user = accountManager.getUser(); OwnCloudClient client = clientFactory.create(user); - RemoteOperationResult remoteOperationResult = new ToggleEncryptionRemoteOperation(localId, + final var remoteOperationResult = new ToggleEncryptionRemoteOperation(localId, remotePath, shouldBeEncrypted) .execute(client); diff --git a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java index e22eef012c55..2dc6bb8bd9d8 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -17,6 +17,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.nextcloud.client.account.User; +import com.nextcloud.common.SessionTimeOut; import com.owncloud.android.R; import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; @@ -408,9 +409,9 @@ public static DecryptedFolderMetadataFileV1 decryptFolderMetaData(EncryptedFolde downloadFolderMetadata(OCFile folder, OwnCloudClient client, Context context, - User user - ) { - RemoteOperationResult getMetadataOperationResult = new GetMetadataRemoteOperation(folder.getLocalId()) + User user) { + + RemoteOperationResult getMetadataOperationResult = new GetMetadataRemoteOperation(folder.getLocalId(), longSessionTimeOut) .execute(client); if (!getMetadataOperationResult.isSuccess()) { @@ -1320,7 +1321,8 @@ public static String lockFolder(ServerFileInterface parentFile, OwnCloudClient c public static String lockFolder(ServerFileInterface parentFile, OwnCloudClient client, long counter) throws UploadException { // Lock folder LockFileRemoteOperation lockFileOperation = new LockFileRemoteOperation(parentFile.getLocalId(), - counter); + counter, + longSessionTimeOut); RemoteOperationResult lockFileOperationResult = lockFileOperation.execute(client); if (lockFileOperationResult.isSuccess() && @@ -1507,9 +1509,11 @@ public static void uploadMetadata(ServerFileInterface parentFile, } } + private static SessionTimeOut longSessionTimeOut = new SessionTimeOut(60000, 60000); + public static RemoteOperationResult unlockFolder(ServerFileInterface parentFolder, OwnCloudClient client, String token) { if (token != null) { - return new UnlockFileRemoteOperation(parentFolder.getLocalId(), token).execute(client); + return new UnlockFileRemoteOperation(parentFolder.getLocalId(), token, longSessionTimeOut).execute(client); } else { return new RemoteOperationResult<>(new Exception("No token available")); } diff --git a/build.gradle b/build.gradle index d3775f409b03..587df8208b80 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ */ buildscript { ext { - androidLibraryVersion ="a4d86ef9d1" + androidLibraryVersion ="5f21c760d4" androidPluginVersion = '8.5.2' androidxMediaVersion = '1.4.0' androidxTestVersion = "1.6.1" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 63a157d6e9aa..4296f0967d52 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -293,7 +293,10 @@ - + + + +