Skip to content
Open
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
@@ -1,6 +1,7 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2023 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
Expand Down Expand Up @@ -300,8 +301,7 @@ class EncryptionUtilsV2IT : EncryptionIT() {
// random string, not real tag
EncryptionUtils.generateUid(),
EncryptionUtils.generateKey(),
metadataFile,
storageManager
metadataFile
)

assertEquals(3, updatedMetadata.metadata.files.size)
Expand Down Expand Up @@ -341,7 +341,6 @@ class EncryptionUtilsV2IT : EncryptionIT() {

@Test
fun addFolder() {
val folder = OCFile("/e/")
val enc1 = MockUser("enc1", "Nextcloud")
val metadataFile = generateDecryptedFolderMetadataFile(enc1, enc1Cert)
assertEquals(2, metadataFile.metadata.files.size)
Expand All @@ -350,9 +349,7 @@ class EncryptionUtilsV2IT : EncryptionIT() {
val updatedMetadata = encryptionUtilsV2.addFolderToMetadata(
EncryptionUtils.generateUid(),
"new subfolder",
metadataFile,
folder,
storageManager
metadataFile
)

assertEquals(2, updatedMetadata.metadata.files.size)
Expand All @@ -361,7 +358,6 @@ class EncryptionUtilsV2IT : EncryptionIT() {

@Test
fun removeFolder() {
val folder = OCFile("/e/")
val enc1 = MockUser("enc1", "Nextcloud")
val metadataFile = generateDecryptedFolderMetadataFile(enc1, enc1Cert)
assertEquals(2, metadataFile.metadata.files.size)
Expand All @@ -371,9 +367,7 @@ class EncryptionUtilsV2IT : EncryptionIT() {
var updatedMetadata = encryptionUtilsV2.addFolderToMetadata(
encryptedFileName,
"new subfolder",
metadataFile,
folder,
storageManager
metadataFile
)

assertEquals(2, updatedMetadata.metadata.files.size)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.media.MediaScannerConnection;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.MediaStore;
Expand All @@ -50,8 +50,8 @@
import com.nextcloud.utils.e2ee.E2EVersionHelper;
import com.nextcloud.utils.extensions.DateExtensionsKt;
import com.nextcloud.utils.extensions.FileExtensionsKt;
import com.nextcloud.utils.extensions.StringExtensionsKt;
import com.owncloud.android.MainApp;
import com.owncloud.android.datamodel.e2e.v2.decrypted.DecryptedFolderMetadataFile;
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
import com.owncloud.android.lib.common.network.WebdavEntry;
import com.owncloud.android.lib.common.utils.Log_OC;
Expand Down Expand Up @@ -2919,4 +2919,14 @@ public FileEntity getFileEntity(OCFile file) {
public void updateFileEntity(@NonNull FileEntity entity) {
fileDao.update(entity);
}

public void updateE2EECounter(OCFile file, DecryptedFolderMetadataFile metadata) {
updateE2EECounter(file, metadata.getMetadata().getCounter());
}

public void updateE2EECounter(OCFile file, long counter) {
Log_OC.d(TAG, "e2ee counter stored: " + counter + " for " + file.getDecryptedRemotePath());
file.setE2eCounter(counter);
saveFile(file);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020-2023 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2020 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2020 Andy Scherzinger <info@andy-scherzinger.de>
Expand Down Expand Up @@ -336,9 +337,7 @@ private RemoteOperationResult encryptedCreateV2(OCFile parent, OwnCloudClient cl
// update metadata
DecryptedFolderMetadataFile updatedMetadataFile = encryptionUtilsV2.addFolderToMetadata(encryptedFileName,
filename,
metadata,
parent,
getStorageManager());
metadata);

// upload metadata
encryptionUtilsV2.serializeAndUploadMetadata(parent,
Expand All @@ -351,9 +350,10 @@ private RemoteOperationResult encryptedCreateV2(OCFile parent, OwnCloudClient cl
getStorageManager());

// unlock folder
RemoteOperationResult unlockFolderResult = EncryptionUtils.unlockFolder(parent, client, token);
final var unlockFolderResult = EncryptionUtils.unlockFolder(parent, client, token);

if (unlockFolderResult.isSuccess()) {
getStorageManager().updateE2EECounter(parent, metadata);
token = null;
} else {
// TODO E2E: do better
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -554,10 +554,8 @@ private void synchronizeData(List<Object> folderAndFiles) {
localFilesMap = prefillLocalFilesMap(metadataFileV1, fileDataStorageManager.getFolderContent(mLocalFolder, false));
} else {
localFilesMap = prefillLocalFilesMap(object, fileDataStorageManager.getFolderContent(mLocalFolder, false));

// update counter
if (object != null) {
mLocalFolder.setE2eCounter(((DecryptedFolderMetadataFile) object).getMetadata().getCounter());
if (object instanceof DecryptedFolderMetadataFile metadataFile) {
mLocalFolder.setE2eCounter(metadataFile.getMetadata().getCounter());
}
}

Expand Down Expand Up @@ -599,14 +597,10 @@ private void synchronizeData(List<Object> folderAndFiles) {
FileStorageUtils.searchForLocalFileInDefaultPath(updatedFile, user.getAccountName());

// update file name for encrypted files
if (E2EVersionHelper.INSTANCE.isV1(e2EVersion)) {
updateFileNameForEncryptedFileV1(fileDataStorageManager,
(DecryptedFolderMetadataFileV1) object,
updatedFile);
} else if (object != null) {
updateFileNameForEncryptedFile(fileDataStorageManager,
(DecryptedFolderMetadataFile) object,
updatedFile);
if (E2EVersionHelper.INSTANCE.isV1(e2EVersion) && object instanceof DecryptedFolderMetadataFileV1 metadata) {
updateFileNameForEncryptedFileV1(fileDataStorageManager, metadata, updatedFile);
} else if (object instanceof DecryptedFolderMetadataFile metadata) {
updateFileNameForEncryptedFile(fileDataStorageManager, metadata, updatedFile);
if (localFile != null) {
updatedFile.setE2eCounter(localFile.getE2eCounter());
}
Expand All @@ -622,15 +616,12 @@ private void synchronizeData(List<Object> folderAndFiles) {

// save updated contents in local database
// update file name for encrypted files
if (E2EVersionHelper.INSTANCE.isV1(e2EVersion)) {
updateFileNameForEncryptedFileV1(fileDataStorageManager,
(DecryptedFolderMetadataFileV1) object,
mLocalFolder);
} else {
updateFileNameForEncryptedFile(fileDataStorageManager,
(DecryptedFolderMetadataFile) object,
mLocalFolder);
if (E2EVersionHelper.INSTANCE.isV1(e2EVersion) && object instanceof DecryptedFolderMetadataFileV1 metadata) {
updateFileNameForEncryptedFileV1(fileDataStorageManager, metadata, mLocalFolder);
} else if (object instanceof DecryptedFolderMetadataFile metadata) {
updateFileNameForEncryptedFile(fileDataStorageManager, metadata, mLocalFolder);
}

fileDataStorageManager.saveFolder(remoteFolder, updatedFiles, localFilesMap.values());

mChildren = updatedFiles;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2017 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
Expand Down Expand Up @@ -28,15 +29,6 @@ import org.apache.commons.httpclient.HttpStatus
import org.apache.commons.httpclient.NameValuePair
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod

/**
* Remote operation performing the removal of a remote encrypted file or folder
*
* Constructor
*
* @param remotePath RemotePath of the remote file or folder to remove from the server
* @param parentFolder parent folder
*/

@Suppress("LongParameterList")
class RemoveRemoteEncryptedFileOperation internal constructor(
private val remotePath: String,
Expand All @@ -47,9 +39,6 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
private val isFolder: Boolean
) : RemoteOperation<Void>() {

/**
* Performs the remove operation.
*/
@Deprecated("Deprecated in Java")
@Suppress("TooGenericExceptionCaught")
override fun run(client: OwnCloudClient): RemoteOperationResult<Void> {
Expand All @@ -59,12 +48,14 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
val capability = CapabilityUtils.getCapability(context)
val isE2EVersionAtLeast2 = (E2EVersionHelper.isV2Plus(capability))
val e2eeVersion = capability.endToEndEncryptionApiVersion
val storageManager = FileDataStorageManager(user, context.contentResolver)
val counter = parentFolder.e2eCounter + 1

try {
token = EncryptionUtils.lockFolder(parentFolder, client, parentFolder.e2eCounter + 1)
token = EncryptionUtils.lockFolder(parentFolder, client, counter)

return if (isE2EVersionAtLeast2) {
val deleteResult = deleteForV2(client, token)
val deleteResult = deleteForV2(counter, storageManager, client, token)
result = deleteResult.first
delete = deleteResult.second
result
Expand All @@ -79,20 +70,28 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
Log_OC.e(TAG, "Remove " + remotePath + ": " + result.logMessage, e)
} finally {
delete?.releaseConnection()
token?.let { unlockFile(client, it, isE2EVersionAtLeast2) }
token?.let { unlockFile(counter, storageManager, client, it, isE2EVersionAtLeast2) }
}

return result
}

private fun unlockFile(client: OwnCloudClient, token: String, isE2EVersionAtLeast2: Boolean) {
private fun unlockFile(
counter: Long,
storageManager: FileDataStorageManager,
client: OwnCloudClient,
token: String,
isE2EVersionAtLeast2: Boolean
) {
val unlockFileOperationResult = if (isE2EVersionAtLeast2) {
EncryptionUtils.unlockFolder(parentFolder, client, token)
} else {
EncryptionUtils.unlockFolderV1(parentFolder, client, token)
}

if (!unlockFileOperationResult.isSuccess) {
if (unlockFileOperationResult.isSuccess && isE2EVersionAtLeast2) {
storageManager.updateE2EECounter(parentFolder, counter)
} else {
Log_OC.e(TAG, "Failed to unlock " + parentFolder.localId)
}
}
Expand Down Expand Up @@ -165,7 +164,12 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
return Pair(result, delete)
}

private fun deleteForV2(client: OwnCloudClient, token: String?): Pair<RemoteOperationResult<Void>, DeleteMethod> {
private fun deleteForV2(
counter: Long,
storageManager: FileDataStorageManager,
client: OwnCloudClient,
token: String?
): Pair<RemoteOperationResult<Void>, DeleteMethod> {
val encryptionUtilsV2 = EncryptionUtilsV2()

val (metadataExists, metadata) = encryptionUtilsV2.retrieveMetadata(
Expand All @@ -175,6 +179,9 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
context
)

// update counter before delete
metadata.metadata.counter = counter

val (result, delete) = deleteRemoteFile(client, token)

if (isFolder) {
Expand All @@ -183,10 +190,6 @@ class RemoveRemoteEncryptedFileOperation internal constructor(
encryptionUtilsV2.removeFileFromMetadata(fileName, metadata)
}

parentFolder.setE2eCounter(metadata.metadata.counter)
val storageManager = FileDataStorageManager(user, context.contentResolver)
storageManager.saveFile(parentFolder)
Comment thread
alperozturk96 marked this conversation as resolved.

encryptionUtilsV2.serializeAndUploadMetadata(
parentFolder,
metadata,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2026 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2020-2023 Tobias Kaminsky <tobias@kaminsky.me>
* SPDX-FileCopyrightText: 2021 Chris Narkiewicz <hello@ezaquarii.com>
* SPDX-FileCopyrightText: 2017-2018 Andy Scherzinger <info@andy-scherzinger.de>
Expand Down Expand Up @@ -601,7 +602,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare
result = performE2EUpload(clientData);

if (result.isSuccess()) {
updateMetadataForE2E(object, e2eData, clientData, e2eFiles, arbitraryDataProvider, encryptionUtilsV2, isV1MetadataExists);
upsertMetadata(object, e2eData, clientData, e2eFiles, arbitraryDataProvider, encryptionUtilsV2, isV1MetadataExists);
}
} catch (FileNotFoundException e) {
Log_OC.e(TAG, mFile.getStoragePath() + " does not exist anymore");
Expand All @@ -613,13 +614,13 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare
Log_OC.e(TAG, "UploadFileOperation exception: " + e.getLocalizedMessage());
result = new RemoteOperationResult<>(e);
} finally {
result = cleanupE2EUpload(fileLock, channel, e2eFiles, result, object, client, token);
result = releaseLocksAndUnlockE2EFolder(fileLock, channel, e2eFiles, result, object, client, token);

// update upload status
uploadsStorageManager.updateDatabaseUploadResult(result, this);
}

completeE2EUpload(result, e2eFiles, client);
handleLocalBehaviourOrSaveConflictAndDeleteTemporalFile(result, e2eFiles, client);

return result;
}
Expand Down Expand Up @@ -811,7 +812,10 @@ private E2EData getE2EData(Object object) throws InvalidAlgorithmParameterExcept
return new E2EData(key, iv, encryptedFile, encryptedFileName);
}

private void updateMetadataForE2E(Object object, E2EData e2eData, E2EClientData clientData, E2EFiles e2eFiles, ArbitraryDataProvider arbitraryDataProvider, EncryptionUtilsV2 encryptionUtilsV2, boolean isV1MetadataExists)
/**
* Stores or updates metadata of the encrypted file along with e2ee counter.
*/
private void upsertMetadata(Object object, E2EData e2eData, E2EClientData clientData, E2EFiles e2eFiles, ArbitraryDataProvider arbitraryDataProvider, EncryptionUtilsV2 encryptionUtilsV2, boolean isV1MetadataExists)

throws InvalidAlgorithmParameterException, UploadException, NoSuchPaddingException, IllegalBlockSizeException, CertificateException,
NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
Expand Down Expand Up @@ -892,11 +896,7 @@ private void updateMetadataForV2(DecryptedFolderMetadataFile metadata, Encryptio
e2eData.getIv(),
e2eData.getEncryptedFile().getAuthenticationTag(),
e2eData.getKey(),
metadata,
getStorageManager());

parentFile.setE2eCounter(metadata.getMetadata().getCounter());
Comment thread
alperozturk96 marked this conversation as resolved.
getStorageManager().saveFile(parentFile);
metadata);

// upload metadata
encryptionUtilsV2.serializeAndUploadMetadata(parentFile,
Expand All @@ -909,7 +909,7 @@ private void updateMetadataForV2(DecryptedFolderMetadataFile metadata, Encryptio
getStorageManager());
}

private void completeE2EUpload(RemoteOperationResult result, E2EFiles e2eFiles, OwnCloudClient client) {
private void handleLocalBehaviourOrSaveConflictAndDeleteTemporalFile(RemoteOperationResult result, E2EFiles e2eFiles, OwnCloudClient client) {
if (result.isSuccess()) {
handleLocalBehaviour(e2eFiles.getTemporalFile(), e2eFiles.getExpectedFile(), e2eFiles.getOriginalFile(), client);
} else if (RemoteOperationResultExtensionsKt.isConflict(result.getCode())) {
Expand All @@ -919,7 +919,7 @@ private void completeE2EUpload(RemoteOperationResult result, E2EFiles e2eFiles,
e2eFiles.deleteTemporalFile();
}

private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, FileChannel channel, E2EFiles e2eFiles, RemoteOperationResult result, Object object, OwnCloudClient client, String token) {
private RemoteOperationResult releaseLocksAndUnlockE2EFolder(FileLock fileLock, FileChannel channel, E2EFiles e2eFiles, RemoteOperationResult result, Object object, OwnCloudClient client, String token) {
mUploadStarted.set(false);

if (fileLock != null) {
Expand Down Expand Up @@ -989,6 +989,12 @@ private RemoteOperationResult cleanupE2EUpload(FileLock fileLock, FileChannel ch
return Unit.INSTANCE;
});
}

// only update local counter after unlock
if (object instanceof DecryptedFolderMetadataFile metadata) {
final var parentFile = e2eFiles.getParentFile();
getStorageManager().updateE2EECounter(parentFile, metadata);
}
}

e2eFiles.deleteEncryptedTempFile();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,8 @@ public void updateFileEncryptionById(String fileId, boolean encrypted) {
e2eCounter = EncryptionUtils.E2E_V2_INITIAL_COUNTER;
}

file.setE2eCounter(e2eCounter);
mStorageManager.saveFile(file);
mStorageManager.updateE2EECounter(file, e2eCounter);

int position = getItemPosition(file);
if (position != -1) {
notifyItemChanged(position);
Expand Down
Loading
Loading