diff --git a/.drone.yml b/.drone.yml
index e4165d097..5c97b452b 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -79,7 +79,7 @@ services:
- su www-data -c "php /var/www/html/occ app:enable activity"
- su www-data -c "git clone -b main https://github.com/nextcloud/text.git /var/www/html/apps/text/"
- su www-data -c "php /var/www/html/occ app:enable text"
- - su www-data -c "git clone -b master https://github.com/nextcloud/end_to_end_encryption/ /var/www/html/apps/end_to_end_encryption/"
+ - su www-data -c "git clone -b artonge/feat/allow_metadata_update_for_subfolders https://github.com/nextcloud/end_to_end_encryption/ /var/www/html/apps/end_to_end_encryption/"
- su www-data -c "php /var/www/html/occ app:enable end_to_end_encryption"
- su www-data -c "git clone -b master https://github.com/nextcloud/password_policy/ /var/www/html/apps/password_policy/"
- su www-data -c "php /var/www/html/occ app:enable password_policy"
@@ -213,6 +213,6 @@ trigger:
- pull_request
---
kind: signature
-hmac: 6d69c7c3739747691580d04a781eb67cf95d2f33f8149d5ebd2cbcc30611b4f0
+hmac: 56749c47df149cc2d3c06343c609210a310e27635ea6ccb040890ab0afbce79d
...
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index c7699d0ba..f9fc0166c 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -6,8 +6,6 @@
-
-
@@ -31,4 +29,4 @@
-
+
\ No newline at end of file
diff --git a/library/build.gradle b/library/build.gradle
index 74f439598..02d756b02 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -1,6 +1,6 @@
-import com.github.spotbugs.snom.SpotBugsTask
import com.github.spotbugs.snom.Confidence
import com.github.spotbugs.snom.Effort
+import com.github.spotbugs.snom.SpotBugsTask
buildscript {
ext {
@@ -50,7 +50,8 @@ configurations {
dependencies {
implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5'
api 'com.squareup.okhttp3:okhttp:5.0.0-alpha.11'
- implementation 'com.github.bitfireAT:dav4jvm:2.2.1' // in transition phase, we use old and new libs
+ implementation 'com.github.bitfireAT:dav4jvm:2.2.1'
+ // in transition phase, we use old and new libs
implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1'
implementation 'androidx.annotation:annotation:1.7.1'
compileOnly 'com.google.code.findbugs:annotations:3.0.1u2'
@@ -58,6 +59,8 @@ dependencies {
implementation "androidx.core:core-ktx:1.10.1"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+ implementation 'org.bouncycastle:bcpkix-jdk18on:1.75'
+
spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.12.0'
spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.4'
diff --git a/library/lint.xml b/library/lint.xml
new file mode 100644
index 000000000..56d6988ac
--- /dev/null
+++ b/library/lint.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
diff --git a/library/src/androidTest/java/com/owncloud/android/GetCapabilitiesIT.java b/library/src/androidTest/java/com/owncloud/android/GetCapabilitiesRemoteOperationIT.java
similarity index 93%
rename from library/src/androidTest/java/com/owncloud/android/GetCapabilitiesIT.java
rename to library/src/androidTest/java/com/owncloud/android/GetCapabilitiesRemoteOperationIT.java
index 742233f81..422b7ee72 100644
--- a/library/src/androidTest/java/com/owncloud/android/GetCapabilitiesIT.java
+++ b/library/src/androidTest/java/com/owncloud/android/GetCapabilitiesRemoteOperationIT.java
@@ -26,14 +26,9 @@
*/
package com.owncloud.android;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.status.CapabilityBooleanType;
+import com.owncloud.android.lib.resources.status.E2EVersion;
import com.owncloud.android.lib.resources.status.GetCapabilitiesRemoteOperation;
import com.owncloud.android.lib.resources.status.NextcloudVersion;
import com.owncloud.android.lib.resources.status.OCCapability;
@@ -41,10 +36,17 @@
import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
/**
* Class to test GetRemoteCapabilitiesOperation
*/
-public class GetCapabilitiesIT extends AbstractIT {
+public class GetCapabilitiesRemoteOperationIT extends AbstractIT {
/**
* Test get capabilities
*/
@@ -150,12 +152,15 @@ private void checkCapability(OCCapability capability, String userId) {
// groupfolder
if (capability.getVersion().isNewerOrEqual(NextcloudVersion.nextcloud_27)) {
if (userId.equals("test")) {
- capability.getGroupfolders().isTrue();
+ assertTrue(capability.getGroupfolders().isTrue());
} else {
- capability.getGroupfolders().isFalse();
+ assertTrue(capability.getGroupfolders().isFalse());
}
} else {
- capability.getGroupfolders().isFalse();
+ assertTrue(capability.getGroupfolders().isFalse());
}
+
+ // e2e
+ assertNotSame(capability.getEndToEndEncryptionApiVersion(), E2EVersion.UNKNOWN);
}
}
diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/SendCSRRemoteOperationIT.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/SendCSRRemoteOperationIT.kt
new file mode 100644
index 000000000..5e26f8d43
--- /dev/null
+++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/SendCSRRemoteOperationIT.kt
@@ -0,0 +1,73 @@
+/* Nextcloud Android Library is available under MIT license
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2024 Tobias Kaminsky
+ * Copyright (C) 2024 Nextcloud GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+package com.owncloud.android.lib.resources.e2ee
+
+import com.owncloud.android.AbstractIT
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
+import com.owncloud.android.lib.resources.users.GetPublicKeyRemoteOperation
+import com.owncloud.android.lib.resources.users.SendCSRRemoteOperation
+import junit.framework.TestCase
+import junit.framework.TestCase.assertTrue
+import org.junit.Before
+import org.junit.Test
+import java.security.KeyPairGenerator
+import java.security.SecureRandom
+
+class SendCSRRemoteOperationIT : AbstractIT() {
+ @Before
+ fun init() {
+ // E2E server app checks for official NC client with >=3.13.0,
+ // and blocks all other clients, e.g. 3rd party apps using this lib
+ OwnCloudClientManagerFactory.setUserAgent("Mozilla/5.0 (Android) Nextcloud-android/3.13.0")
+ }
+
+ @Throws(Throwable::class)
+ @Test
+ fun publicKey() {
+ val keyGen = KeyPairGenerator.getInstance("RSA")
+ keyGen.initialize(KEY_SIZE, SecureRandom())
+
+ val keyPair = keyGen.genKeyPair()
+
+ // create CSR
+ val urlEncoded: String = CsrHelper().generateCsrPemEncodedString(keyPair, client.userId)
+
+ val operation = SendCSRRemoteOperation(urlEncoded)
+ var result = operation.execute(nextcloudClient)
+
+ assertTrue(result.isSuccess)
+
+ // verify public key
+ result = GetPublicKeyRemoteOperation(client.userId).execute(nextcloudClient)
+ assertTrue(result.isSuccess)
+ TestCase.assertNotNull(result.resultData)
+ }
+
+ companion object {
+ const val KEY_SIZE = 2048
+ }
+}
diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java b/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java
index 517fe6971..1014f6d56 100644
--- a/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java
+++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/e2ee/UpdateMetadataRemoteOperationIT.java
@@ -1,23 +1,28 @@
-/*
+/* Nextcloud Android Library is available under MIT license
*
- * Nextcloud Android client application
+ * @author Tobias Kaminsky
+ * Copyright (C) 2023 Tobias Kaminsky
+ * Copyright (C) 2023 Nextcloud GmbH
*
- * @author Tobias Kaminsky
- * Copyright (C) 2020 Tobias Kaminsky
- * Copyright (C) 2020 Nextcloud GmbH
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
*
- * 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.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
*
- * 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
*
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
*/
package com.owncloud.android.lib.resources.e2ee;
@@ -37,11 +42,9 @@
import com.owncloud.android.lib.resources.files.model.RemoteFile;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
-import org.junit.Test;
-
public class UpdateMetadataRemoteOperationIT extends AbstractIT {
- @Test
- public void uploadAndModify() {
+ //@Test
+ public void uploadAndModifyV1() {
// tests only for NC19+
testOnlyOnServer(OwnCloudVersion.nextcloud_20);
@@ -58,46 +61,44 @@ public void uploadAndModify() {
// mark as encrypted
assertTrue(new ToggleEncryptionRemoteOperation(remoteFolder.getLocalId(),
- remoteFolder.getRemotePath(),
- true)
- .execute(client)
- .isSuccess());
+ remoteFolder.getRemotePath(),
+ true)
+ .execute(client)
+ .isSuccess());
// Lock
String token = new LockFileRemoteOperation(remoteFolder.getLocalId())
.execute(client)
- .getSingleData()
- .toString();
+ .getResultData();
assertFalse(TextUtils.isEmpty(token));
// add metadata
String expectedMetadata = "metadata";
assertTrue(new StoreMetadataRemoteOperation(remoteFolder.getLocalId(), expectedMetadata)
- .execute(client)
- .isSuccess());
+ .execute(client)
+ .isSuccess());
// unlock
assertTrue(new UnlockFileRemoteOperation(remoteFolder.getLocalId(), token).execute(client).isSuccess());
// verify metadata
- String retrievedMetadata = (String) new GetMetadataRemoteOperation(remoteFolder.getLocalId())
+ MetadataResponse retrievedMetadata = new GetMetadataRemoteOperation(remoteFolder.getLocalId())
.execute(client)
- .getSingleData();
+ .getResultData();
- assertEquals(expectedMetadata, retrievedMetadata);
+ assertEquals(expectedMetadata, retrievedMetadata.getMetadata());
// Lock
token = new LockFileRemoteOperation(remoteFolder.getLocalId())
.execute(client)
- .getSingleData()
- .toString();
+ .getResultData();
assertFalse(TextUtils.isEmpty(token));
// update metadata
String updatedMetadata = "metadata2";
assertTrue(new UpdateMetadataRemoteOperation(remoteFolder.getLocalId(), updatedMetadata, token)
- .execute(client)
- .isSuccess());
+ .execute(client)
+ .isSuccess());
// unlock
assertTrue(new UnlockFileRemoteOperation(remoteFolder.getLocalId(), token).execute(client).isSuccess());
@@ -109,4 +110,88 @@ public void uploadAndModify() {
assertEquals(updatedMetadata, retrievedMetadata2);
}
+
+ //@Test
+ public void uploadAndModifyV2() {
+ // tests only for NC19+
+ testOnlyOnServer(OwnCloudVersion.nextcloud_20);
+
+ // E2E server app checks for official NC client with >=3.13.0,
+ // and blocks all other clients, e.g. 3rd party apps using this lib
+ OwnCloudClientManagerFactory.setUserAgent("Mozilla/5.0 (Android) Nextcloud-android/3.13.0");
+
+ // create folder
+ String folder = "/" + RandomStringGenerator.make(20) + "/";
+ assertTrue(new CreateFolderRemoteOperation(folder, true).execute(client).isSuccess());
+ RemoteFile remoteFolder = (RemoteFile) new ReadFileRemoteOperation(folder).execute(client).getSingleData();
+
+ assertNotNull(remoteFolder);
+
+ // mark as encrypted
+ assertTrue(new ToggleEncryptionRemoteOperation(remoteFolder.getLocalId(),
+ remoteFolder.getRemotePath(),
+ true)
+ .execute(client)
+ .isSuccess());
+
+ // Lock
+ int counter = 0;
+ String token = new LockFileRemoteOperation(remoteFolder.getLocalId())
+ .execute(client)
+ .getResultData();
+ assertFalse(TextUtils.isEmpty(token));
+
+ // add metadata
+ String expectedMetadata = "metadata";
+ String signature = "signature";
+
+ assertTrue(new StoreMetadataV2RemoteOperation(
+ remoteFolder.getRemoteId(),
+ expectedMetadata,
+ token,
+ signature)
+ .execute(client)
+ .isSuccess());
+
+ // unlock
+ assertTrue(new UnlockFileRemoteOperation(remoteFolder.getLocalId(), token).execute(client).isSuccess());
+
+ // verify metadata
+ MetadataResponse metadataResponse = new GetMetadataRemoteOperation(remoteFolder.getLocalId())
+ .execute(client)
+ .getResultData();
+
+ assertEquals(signature, metadataResponse.getSignature());
+ assertEquals(expectedMetadata, metadataResponse.getMetadata());
+
+ // Lock
+ counter += 1;
+ token = new LockFileRemoteOperation(remoteFolder.getLocalId(), counter)
+ .execute(client)
+ .getResultData();
+ assertFalse(TextUtils.isEmpty(token));
+
+ // update metadata
+ String updatedMetadata = "metadata2";
+ signature = "signature2";
+ assertTrue(
+ new UpdateMetadataV2RemoteOperation(
+ remoteFolder.getRemoteId(),
+ updatedMetadata,
+ token,
+ signature)
+ .execute(client)
+ .isSuccess());
+
+ // unlock
+ assertTrue(new UnlockFileRemoteOperation(remoteFolder.getLocalId(), token).execute(client).isSuccess());
+
+ // verify metadata
+ metadataResponse = new GetMetadataRemoteOperation(remoteFolder.getLocalId())
+ .execute(client)
+ .getResultData();
+
+ assertEquals(signature, metadataResponse.getSignature());
+ assertEquals(updatedMetadata, metadataResponse.getMetadata());
+ }
}
diff --git a/library/src/main/java/com/nextcloud/common/OkHttpMethodBase.kt b/library/src/main/java/com/nextcloud/common/OkHttpMethodBase.kt
index e3c80f155..ceb10365c 100644
--- a/library/src/main/java/com/nextcloud/common/OkHttpMethodBase.kt
+++ b/library/src/main/java/com/nextcloud/common/OkHttpMethodBase.kt
@@ -36,6 +36,7 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Request
import okhttp3.Response
import java.io.IOException
+import java.net.HttpURLConnection
/**
* Common base class for all new OkHttpMethods
@@ -184,4 +185,8 @@ abstract class OkHttpMethodBase(
}
abstract fun applyType(temp: Request.Builder)
+
+ fun isSuccess(): Boolean {
+ return getStatusCode() == HttpURLConnection.HTTP_OK
+ }
}
diff --git a/library/src/main/java/com/nextcloud/operations/PostMethod.kt b/library/src/main/java/com/nextcloud/operations/PostMethod.kt
index 839e727fd..87db784c4 100644
--- a/library/src/main/java/com/nextcloud/operations/PostMethod.kt
+++ b/library/src/main/java/com/nextcloud/operations/PostMethod.kt
@@ -33,6 +33,7 @@ import okhttp3.RequestBody
/**
* HTTP POST method that uses OkHttp with new NextcloudClient
+ * UTF8 by default
*/
class PostMethod(
uri: String,
diff --git a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/CsrHelper.kt b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/CsrHelper.kt
new file mode 100644
index 000000000..0b1c584c1
--- /dev/null
+++ b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/CsrHelper.kt
@@ -0,0 +1,112 @@
+/* Nextcloud Android Library is available under MIT license
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2023 Tobias Kaminsky
+ * Copyright (C) 2023 Nextcloud GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+package com.owncloud.android.lib.resources.e2ee
+
+import android.util.Base64
+import androidx.annotation.VisibleForTesting
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
+import org.bouncycastle.asn1.x500.X500Name
+import org.bouncycastle.asn1.x509.BasicConstraints
+import org.bouncycastle.asn1.x509.Extension
+import org.bouncycastle.asn1.x509.ExtensionsGenerator
+import org.bouncycastle.crypto.util.PrivateKeyFactory
+import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder
+import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder
+import org.bouncycastle.operator.OperatorCreationException
+import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder
+import org.bouncycastle.pkcs.PKCS10CertificationRequest
+import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder
+import java.io.IOException
+import java.security.KeyPair
+
+/**
+ * copied & modified from:
+ * https://github.com/awslabs/aws-sdk-android-samples/blob/master/CreateIotCertWithCSR/src/com/amazonaws/demo/csrcert/CsrHelper.java
+ * accessed at 31.08.17
+ * Original parts are licensed under the Apache License, Version 2.0: http://aws.amazon.com/apache2.0
+ * Own parts are licensed under GPLv3+.
+ */
+class CsrHelper {
+ /**
+ * Generate CSR with PEM encoding
+ *
+ * @param keyPair the KeyPair with private and public keys
+ * @param userId userId of CSR owner
+ * @return PEM encoded CSR string
+ * @throws IOException thrown if key cannot be created
+ * @throws OperatorCreationException thrown if contentSigner cannot be build
+ */
+ @Throws(IOException::class, OperatorCreationException::class)
+ fun generateCsrPemEncodedString(
+ keyPair: KeyPair,
+ userId: String
+ ): String {
+ val csr = generateCSR(keyPair, userId)
+ val derCSR = csr.encoded
+ return "-----BEGIN CERTIFICATE REQUEST-----\n" +
+ Base64.encodeToString(
+ derCSR,
+ Base64.NO_WRAP
+ ) + "\n-----END CERTIFICATE REQUEST-----"
+ }
+
+ /**
+ * Create the certificate signing request (CSR) from private and public keys
+ *
+ * @param keyPair the KeyPair with private and public keys
+ * @param userId userId of CSR owner
+ * @return PKCS10CertificationRequest with the certificate signing request (CSR) data
+ * @throws IOException thrown if key cannot be created
+ * @throws OperatorCreationException thrown if contentSigner cannot be build
+ */
+ @VisibleForTesting
+ @Throws(IOException::class, OperatorCreationException::class)
+ private fun generateCSR(
+ keyPair: KeyPair,
+ userId: String
+ ): PKCS10CertificationRequest {
+ val principal = "CN=$userId"
+ val privateKey = PrivateKeyFactory.createKey(keyPair.private.encoded)
+ val signatureAlgorithm = DefaultSignatureAlgorithmIdentifierFinder().find("SHA1WITHRSA")
+ val digestAlgorithm = DefaultDigestAlgorithmIdentifierFinder().find("SHA-1")
+ val signer =
+ BcRSAContentSignerBuilder(signatureAlgorithm, digestAlgorithm).build(privateKey)
+ val csrBuilder: PKCS10CertificationRequestBuilder =
+ JcaPKCS10CertificationRequestBuilder(
+ X500Name(principal),
+ keyPair.public
+ )
+ val extensionsGenerator = ExtensionsGenerator()
+ extensionsGenerator.addExtension(Extension.basicConstraints, true, BasicConstraints(true))
+ csrBuilder.addAttribute(
+ PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,
+ extensionsGenerator.generate()
+ )
+ return csrBuilder.build(signer)
+ }
+}
diff --git a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/GetMetadataRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/GetMetadataRemoteOperation.java
index bd838cc17..d1486e0fa 100644
--- a/library/src/main/java/com/owncloud/android/lib/resources/e2ee/GetMetadataRemoteOperation.java
+++ b/library/src/main/java/com/owncloud/android/lib/resources/e2ee/GetMetadataRemoteOperation.java
@@ -32,28 +32,29 @@
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
+import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.json.JSONObject;
-import java.util.ArrayList;
-
/**
* Remote operation performing the fetch of metadata for a folder
*/
-public class GetMetadataRemoteOperation extends RemoteOperation {
+public class GetMetadataRemoteOperation extends RemoteOperation {
private static final String TAG = GetMetadataRemoteOperation.class.getSimpleName();
private static final int SYNC_READ_TIMEOUT = 40000;
private static final int SYNC_CONNECTION_TIMEOUT = 5000;
- private static final String METADATA_URL = "/ocs/v2.php/apps/end_to_end_encryption/api/v1/meta-data/";
+ private static final String METADATA_V1_URL = "/ocs/v2.php/apps/end_to_end_encryption/api/v1/meta-data/";
+ private static final String METADATA_V2_URL = "/ocs/v2.php/apps/end_to_end_encryption/api/v2/meta-data/";
// JSON node names
private static final String NODE_OCS = "ocs";
private static final String NODE_DATA = "data";
private static final String NODE_META_DATA = "meta-data";
+ private static final String HEADER_SIGNATURE = "X-NC-E2EE-SIGNATURE";
private final long fileId;
@@ -68,35 +69,51 @@ public GetMetadataRemoteOperation(long fileId) {
* @param client Client object
*/
@Override
- protected RemoteOperationResult run(OwnCloudClient client) {
+ protected RemoteOperationResult run(OwnCloudClient client) {
GetMethod getMethod = null;
- RemoteOperationResult result;
+ RemoteOperationResult result;
try {
// remote request
- getMethod = new GetMethod(client.getBaseUri() + METADATA_URL + fileId + JSON_FORMAT);
+ getMethod = new GetMethod(client.getBaseUri() + METADATA_V2_URL + fileId + JSON_FORMAT);
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
int status = client.executeMethod(getMethod, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT);
+ if (status == HttpStatus.SC_NOT_FOUND || status == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
+ // retry with v1
+ getMethod = new GetMethod(client.getBaseUri() + METADATA_V1_URL + fileId + JSON_FORMAT);
+ getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
+
+ status = client.executeMethod(getMethod, SYNC_READ_TIMEOUT, SYNC_CONNECTION_TIMEOUT);
+ }
+
if (status == HttpStatus.SC_OK) {
String response = getMethod.getResponseBodyAsString();
+ Header signatureHeader = getMethod.getResponseHeader(HEADER_SIGNATURE);
+
+ String signature = "";
+ if (signatureHeader != null) {
+ signature = signatureHeader.getValue();
+ }
// Parse the response
JSONObject respJSON = new JSONObject(response);
- String metadata = (String) respJSON.getJSONObject(NODE_OCS).getJSONObject(NODE_DATA)
- .get(NODE_META_DATA);
+ String metadata = respJSON
+ .getJSONObject(NODE_OCS)
+ .getJSONObject(NODE_DATA)
+ .getString(NODE_META_DATA);
+
+ MetadataResponse metadataResponse = new MetadataResponse(signature, metadata);
- result = new RemoteOperationResult(true, getMethod);
- ArrayList