Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.owncloud.android.datamodel.e2e.v2.decrypted.DecryptedUser
import com.owncloud.android.datamodel.e2e.v2.encrypted.EncryptedFiledrop
import com.owncloud.android.datamodel.e2e.v2.encrypted.EncryptedFiledropUser
import com.owncloud.android.datamodel.e2e.v2.encrypted.EncryptedFolderMetadataFile
import com.owncloud.android.lib.resources.status.E2EVersion
import com.owncloud.android.operations.RefreshFolderOperation
import com.owncloud.android.util.EncryptionTestIT
import junit.framework.TestCase.assertEquals
Expand Down Expand Up @@ -469,6 +470,7 @@ class EncryptionUtilsV2IT : EncryptionIT() {
val v2 = encryptionUtilsV2.migrateV1ToV2(
v1,
enc1UserId,
storageManager.user,
enc1Cert,
folder,
storageManager
Expand Down Expand Up @@ -601,7 +603,7 @@ class EncryptionUtilsV2IT : EncryptionIT() {

metadata.keyChecksums.add(encryptionUtilsV2.hashMetadataKey(metadata.metadataKey))

return DecryptedFolderMetadataFile(metadata, users, mutableMapOf())
return DecryptedFolderMetadataFile(metadata, users, mutableMapOf(), E2EVersion.V2_1.value)
}

@Test
Expand Down
47 changes: 14 additions & 33 deletions app/src/main/java/com/nextcloud/utils/e2ee/E2EVersionHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,55 +37,36 @@ object E2EVersionHelper {
fun isV1(version: E2EVersion): Boolean =
version == E2EVersion.V1_0 || version == E2EVersion.V1_1 || version == E2EVersion.V1_2

/**
* Returns the latest supported E2EE version.
*
* @param isV2 indicates whether the E2EE v2 series should be used
*/
fun latestVersion(isV2: Boolean): E2EVersion = if (isV2) {
E2EVersion.V2_1
} else {
E2EVersion.V1_2
}
fun getMaxCompatibleE2EEVersion(serverE2EEVersion: E2EVersion): E2EVersion {
if (serverE2EEVersion == E2EVersion.UNKNOWN && serverE2EEVersion.unknownValue.isNullOrEmpty()) {
return E2EVersion.UNKNOWN
}

/**
* Maps a raw version string to an [E2EVersion].
*
* @param version version string
* @return resolved [E2EVersion] or [E2EVersion.UNKNOWN] if unsupported
*/
fun fromVersionString(version: String?): E2EVersion = when (version?.trim()) {
"1.0" -> E2EVersion.V1_0
"1.1" -> E2EVersion.V1_1
"1.2" -> E2EVersion.V1_2
"2", "2.0" -> E2EVersion.V2_0
"2.1" -> E2EVersion.V2_1
else -> E2EVersion.UNKNOWN
E2EVersion.entries.forEach {
it.unknownValue = null
}

val clientMax = E2EVersion.max()
return minOf(serverE2EEVersion, clientMax)
}

/**
* Determines the E2EE version by inspecting encrypted folder metadata.
*
* Supports both V1 and V2 metadata formats and falls back safely
* to [E2EVersion.UNKNOWN] if parsing fails.
*/
fun fromMetadata(metadata: String): E2EVersion = runCatching {
val v1 = EncryptionUtils.deserializeJSON<EncryptedFolderMetadataFileV1>(
val v1 = EncryptionUtils.deserializeJSON(
metadata,
object : TypeToken<EncryptedFolderMetadataFileV1>() {}
)

fromVersionString(v1?.metadata?.version.toString()).also {
E2EVersion.fromValue(v1?.metadata?.version.toString()).also {
if (it == E2EVersion.UNKNOWN) {
throw IllegalStateException("Unknown V1 version")
}
}
}.recoverCatching {
val v2 = EncryptionUtils.deserializeJSON<EncryptedFolderMetadataFile>(
val v2 = EncryptionUtils.deserializeJSON(
metadata,
object : TypeToken<EncryptedFolderMetadataFile>() {}
)

fromVersionString(v2.version)
E2EVersion.fromValue(v2.version)
}.getOrDefault(E2EVersion.UNKNOWN)
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.nextcloud.model.OfflineOperationType;
import com.nextcloud.model.ShareeEntry;
import com.nextcloud.utils.date.DateFormatPattern;
import com.nextcloud.utils.e2ee.E2EVersionHelper;
import com.nextcloud.utils.extensions.DateExtensionsKt;
import com.nextcloud.utils.extensions.FileExtensionsKt;
import com.nextcloud.utils.extensions.StringExtensionsKt;
Expand Down Expand Up @@ -2452,6 +2453,16 @@ private Cursor getCapabilityCursorForAccount(String accountName) {
return cursor;
}

public String getE2EEVersion(@NonNull User user) {
return getE2EEVersionObject(user).getValue();
}

public E2EVersion getE2EEVersionObject(@NonNull User user) {
final var capabilities = getCapability(user);
final var serverE2EEVersion = capabilities.getEndToEndEncryptionApiVersion();
return E2EVersionHelper.INSTANCE.getMaxCompatibleE2EEVersion(serverE2EEVersion);
}

@NonNull
public OCCapability getCapability(User user) {
return getCapability(user.getAccountName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,10 @@
*/
package com.owncloud.android.datamodel.e2e.v2.decrypted

import com.nextcloud.utils.e2ee.E2EVersionHelper

/**
* Decrypted class representation of metadata json of folder metadata.
*/
data class DecryptedFolderMetadataFile(
val metadata: DecryptedMetadata,
var users: MutableList<DecryptedUser> = mutableListOf(),
@Transient
val filedrop: MutableMap<String, DecryptedFile> = HashMap(),
val version: String = E2EVersionHelper.latestVersion(true).value
val version: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ data class EncryptedFolderMetadataFile(
val metadata: EncryptedMetadata,
val users: List<EncryptedUser>,
@Transient val filedrop: MutableMap<String, EncryptedFiledrop>?,
val version: String = E2EVersionHelper.latestVersion(true).value
val version: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation;
import com.owncloud.android.lib.resources.files.ReadFolderRemoteOperation;
import com.owncloud.android.lib.resources.files.model.RemoteFile;
import com.owncloud.android.lib.resources.status.E2EVersion;
import com.owncloud.android.operations.common.SyncOperation;
import com.owncloud.android.utils.EncryptionUtils;
import com.owncloud.android.utils.EncryptionUtilsV2;
Expand Down Expand Up @@ -139,14 +140,16 @@ private RemoteOperationResult encryptedCreateV1(OCFile parent, OwnCloudClient cl
// lock folder
token = EncryptionUtils.lockFolder(parent, client, EncryptionUtils.E2E_V1_INITIAL_COUNTER);

final var e2eeVersion = getStorageManager().getE2EEVersion(user);

// get metadata
Pair<Boolean, DecryptedFolderMetadataFileV1> metadataPair = EncryptionUtils.retrieveMetadataV1(parent,
client,
privateKey,
publicKey,
arbitraryDataProvider,
user
);
user,
e2eeVersion);

metadataExists = metadataPair.first;
metadata = metadataPair.second;
Expand Down Expand Up @@ -177,13 +180,15 @@ private RemoteOperationResult encryptedCreateV1(OCFile parent, OwnCloudClient cl
);
String serializedFolderMetadata = EncryptionUtils.serializeJSON(encryptedFolderMetadata);

final var e2eeVersionAsObject = getStorageManager().getE2EEVersionObject(user);

// upload metadata
EncryptionUtils.uploadMetadata(parent,
serializedFolderMetadata,
token,
client,
metadataExists,
E2EVersionHelper.INSTANCE.latestVersion(false),
e2eeVersionAsObject,
"",
arbitraryDataProvider,
user);
Expand Down Expand Up @@ -304,7 +309,8 @@ private RemoteOperationResult encryptedCreateV2(OCFile parent, OwnCloudClient cl
String remoteId = result.getResultData();

if (result.isSuccess()) {
DecryptedFolderMetadataFile subFolderMetadata = encryptionUtilsV2.createDecryptedFolderMetadataFile();
String e2eeVersion = getStorageManager().getE2EEVersion(user);
DecryptedFolderMetadataFile subFolderMetadata = encryptionUtilsV2.createDecryptedFolderMetadataFile(e2eeVersion);

// upload metadata
encryptionUtilsV2.serializeAndUploadMetadata(remoteId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ protected RemoteOperationResult run(OwnCloudClient client) {
boolean metadataExists;
if (metadata == null) {
String cert = EncryptionUtils.retrievePublicKeyForUser(user, context);
metadata = new EncryptionUtilsV2().createDecryptedFolderMetadataFile();
String e2eeVersion = getStorageManager().getE2EEVersion(user);
metadata = new EncryptionUtilsV2().createDecryptedFolderMetadataFile(e2eeVersion);
metadata.getUsers().add(new DecryptedUser(client.getUserId(), cert, null));

metadataExists = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,12 +549,10 @@ private void synchronizeData(List<Object> folderAndFiles) {

// get current data about local contents of the folder to synchronize
Map<String, OCFile> localFilesMap;
E2EVersion e2EVersion;
E2EVersion e2EVersion = fileDataStorageManager.getE2EEVersionObject(user);
if (object instanceof DecryptedFolderMetadataFileV1 metadataFileV1) {
e2EVersion = E2EVersionHelper.INSTANCE.latestVersion(false);
localFilesMap = prefillLocalFilesMap(metadataFileV1, fileDataStorageManager.getFolderContent(mLocalFolder, false));
} else {
e2EVersion = E2EVersionHelper.INSTANCE.latestVersion(true);
localFilesMap = prefillLocalFilesMap(object, fileDataStorageManager.getFolderContent(mLocalFolder, false));

// update counter
Expand Down Expand Up @@ -601,7 +599,7 @@ private void synchronizeData(List<Object> folderAndFiles) {
FileStorageUtils.searchForLocalFileInDefaultPath(updatedFile, user.getAccountName());

// update file name for encrypted files
if (e2EVersion == E2EVersionHelper.INSTANCE.latestVersion(false)) {
if (E2EVersionHelper.INSTANCE.isV1(e2EVersion)) {
updateFileNameForEncryptedFileV1(fileDataStorageManager,
(DecryptedFolderMetadataFileV1) object,
updatedFile);
Expand All @@ -624,7 +622,7 @@ private void synchronizeData(List<Object> folderAndFiles) {

// save updated contents in local database
// update file name for encrypted files
if (e2EVersion == E2EVersionHelper.INSTANCE.latestVersion(false)) {
if (E2EVersionHelper.INSTANCE.isV1(e2EVersion)) {
updateFileNameForEncryptedFileV1(fileDataStorageManager,
(DecryptedFolderMetadataFileV1) object,
mLocalFolder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.owncloud.android.lib.common.OwnCloudClient
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 com.owncloud.android.lib.resources.status.E2EVersion
import com.owncloud.android.utils.EncryptionUtils
import com.owncloud.android.utils.EncryptionUtilsV2
import com.owncloud.android.utils.theme.CapabilityUtils
Expand Down Expand Up @@ -57,6 +58,7 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
var token: String? = null
val capability = CapabilityUtils.getCapability(context)
val isE2EVersionAtLeast2 = (E2EVersionHelper.isV2Plus(capability))
val e2eeVersion = capability.endToEndEncryptionApiVersion

try {
token = EncryptionUtils.lockFolder(parentFolder, client, parentFolder.e2eCounter + 1)
Expand All @@ -67,7 +69,7 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
delete = deleteResult.second
result
} else {
val deleteResult = deleteForV1(client, token)
val deleteResult = deleteForV1(client, token, e2eeVersion)
result = deleteResult.first
delete = deleteResult.second
result
Expand Down Expand Up @@ -112,7 +114,11 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
return Pair(result, delete)
}

private fun deleteForV1(client: OwnCloudClient, token: String?): Pair<RemoteOperationResult<Void>, DeleteMethod> {
private fun deleteForV1(
client: OwnCloudClient,
token: String?,
e2eeVersion: E2EVersion
): Pair<RemoteOperationResult<Void>, DeleteMethod> {
@Suppress("DEPRECATION")
val arbitraryDataProvider: ArbitraryDataProvider = ArbitraryDataProviderImpl(context)
val privateKey = arbitraryDataProvider.getValue(user.accountName, EncryptionUtils.PRIVATE_KEY)
Expand All @@ -124,7 +130,8 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
privateKey,
publicKey,
arbitraryDataProvider,
user
user,
e2eeVersion.value
)

val (result, delete) = deleteRemoteFile(client, token)
Expand All @@ -149,7 +156,7 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
token,
client,
metadataExists,
E2EVersionHelper.latestVersion(false),
e2eeVersion,
"",
arbitraryDataProvider,
user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation;
import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation;
import com.owncloud.android.lib.resources.files.model.RemoteFile;
import com.owncloud.android.lib.resources.status.E2EVersion;
import com.owncloud.android.lib.resources.status.OCCapability;
import com.owncloud.android.operations.common.SyncOperation;
import com.owncloud.android.operations.e2e.E2EClientData;
Expand Down Expand Up @@ -881,13 +882,15 @@ private void updateMetadataForV1(DecryptedFolderMetadataFileV1 metadata, E2EData
serializedFolderMetadata = EncryptionUtils.serializeJSON(encryptedFolderMetadata);
}

final var e2eeVersion = getStorageManager().getE2EEVersionObject(user);

// upload metadata
EncryptionUtils.uploadMetadata(parentFile,
serializedFolderMetadata,
clientData.getToken(),
clientData.getClient(),
metadataExists,
E2EVersionHelper.INSTANCE.latestVersion(false),
e2eeVersion,
"",
arbitraryDataProvider,
user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1996,9 +1996,10 @@ private void encryptFolder(OCFile folder,
DecryptedFolderMetadataFileV1 metadata = new DecryptedFolderMetadataFileV1();
metadata.setMetadata(new DecryptedMetadata());

final var latestV1E2EEVersion = E2EVersionHelper.INSTANCE.latestVersion(false);
final var e2eeVersion = storageManager.getE2EEVersionObject(user);
final var e2eeVersionAsString = e2eeVersion.getValue();
metadata.getMetadata().setVersion(Double.parseDouble(e2eeVersionAsString));

metadata.getMetadata().setVersion(Double.parseDouble(latestV1E2EEVersion.getValue()));
metadata.getMetadata().setMetadataKeys(new HashMap<>());
String metadataKey = EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateKey());
String encryptedMetadataKey = EncryptionUtils.encryptStringAsymmetric(metadataKey, publicKey);
Expand All @@ -2018,7 +2019,7 @@ private void encryptFolder(OCFile folder,
token,
client,
false,
E2EVersionHelper.INSTANCE.latestVersion(false),
e2eeVersion,
"",
arbitraryDataProvider,
user);
Expand Down
Loading
Loading