Extract logics to functions

Signed-off-by: alperozturk <alper_ozturk@proton.me>
This commit is contained in:
alperozturk 2024-04-25 09:41:59 +02:00 committed by Alper Öztürk
parent 6c8c58f220
commit b3357c0b07

View file

@ -77,6 +77,9 @@ import java.io.RandomAccessFile;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.channels.FileLock; import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException; import java.nio.channels.OverlappingFileLockException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -84,7 +87,10 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import androidx.annotation.CheckResult; import androidx.annotation.CheckResult;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -435,6 +441,78 @@ public class UploadFileOperation extends SyncOperation {
} }
} }
private String getToken(OwnCloudClient client, OCFile parentFile, long counter) throws UploadException {
String token;
if (mFolderUnlockToken != null && !mFolderUnlockToken.isEmpty()) {
token = mFolderUnlockToken;
} else {
token = EncryptionUtils.lockFolder(parentFile, client, counter);
mUpload.setFolderUnlockToken(token);
uploadsStorageManager.updateUpload(mUpload);
}
return token;
}
private long getE2ECounter(OCFile parentFile) {
long counter = -1;
if (CapabilityUtils.getCapability(mContext).getEndToEndEncryptionApiVersion().compareTo(E2EVersion.V2_0) >= 0) {
counter = parentFile.getE2eCounter() + 1;
}
return counter;
}
private DecryptedFolderMetadataFileV1 getDecryptedFolderMetadataV1(String publicKey, Object object)
throws NoSuchPaddingException, IllegalBlockSizeException, CertificateException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
DecryptedFolderMetadataFileV1 metadata = new DecryptedFolderMetadataFileV1();
metadata.setMetadata(new DecryptedMetadata());
metadata.getMetadata().setVersion(1.2);
metadata.getMetadata().setMetadataKeys(new HashMap<>());
String metadataKey = EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateKey());
String encryptedMetadataKey = EncryptionUtils.encryptStringAsymmetric(metadataKey, publicKey);
metadata.getMetadata().setMetadataKey(encryptedMetadataKey);
if (object instanceof DecryptedFolderMetadataFileV1) {
metadata = (DecryptedFolderMetadataFileV1) object;
}
return metadata;
}
private List<String> checkNameCollision(Object object) {
List<String> fileNames = new ArrayList<>();
if (object instanceof DecryptedFolderMetadataFileV1 metadata) {
for (DecryptedFile file : metadata.getFiles().values()) {
fileNames.add(file.getEncrypted().getFilename());
}
} else {
for (com.owncloud.android.datamodel.e2e.v2.decrypted.DecryptedFile file :
((DecryptedFolderMetadataFile) object).getMetadata().getFiles().values()) {
fileNames.add(file.getFilename());
}
}
return fileNames;
}
private String getEncryptedFileName(Object object) {
String encryptedFileName = EncryptionUtils.generateUid();
if (object instanceof DecryptedFolderMetadataFileV1 metadata) {
while (metadata.getFiles().get(encryptedFileName) != null) {
encryptedFileName = EncryptionUtils.generateUid();
}
} else {
while (((DecryptedFolderMetadataFile) object).getMetadata().getFiles().get(encryptedFileName) != null) {
encryptedFileName = EncryptionUtils.generateUid();
}
}
return encryptedFileName;
}
// TODO REFACTOR // TODO REFACTOR
@SuppressLint("AndroidLintUseSparseArrays") // gson cannot handle sparse arrays easily, therefore use hashmap @SuppressLint("AndroidLintUseSparseArrays") // gson cannot handle sparse arrays easily, therefore use hashmap
private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile parentFile) { private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile parentFile) {
@ -454,29 +532,14 @@ public class UploadFileOperation extends SyncOperation {
String publicKey = arbitraryDataProvider.getValue(user.getAccountName(), EncryptionUtils.PUBLIC_KEY); String publicKey = arbitraryDataProvider.getValue(user.getAccountName(), EncryptionUtils.PUBLIC_KEY);
try { try {
// check conditions
result = checkConditions(originalFile); result = checkConditions(originalFile);
if (result != null) { if (result != null) {
return result; return result;
} }
/***** E2E *****/ long counter = getE2ECounter(parentFile);
// Only on V2+: whenever we change something, increase counter token = getToken(client, parentFile,counter);
long counter = -1;
if (CapabilityUtils.getCapability(mContext).getEndToEndEncryptionApiVersion().compareTo(E2EVersion.V2_0) >= 0) {
counter = parentFile.getE2eCounter() + 1;
}
// we might have an old token from interrupted upload
if (mFolderUnlockToken != null && !mFolderUnlockToken.isEmpty()) {
token = mFolderUnlockToken;
} else {
token = EncryptionUtils.lockFolder(parentFile, client, counter);
// immediately store it
mUpload.setFolderUnlockToken(token);
uploadsStorageManager.updateUpload(mUpload);
}
// Update metadata // Update metadata
EncryptionUtilsV2 encryptionUtilsV2 = new EncryptionUtilsV2(); EncryptionUtilsV2 encryptionUtilsV2 = new EncryptionUtilsV2();
@ -487,46 +550,13 @@ public class UploadFileOperation extends SyncOperation {
if (CapabilityUtils.getCapability(mContext).getEndToEndEncryptionApiVersion().compareTo(E2EVersion.V2_0) >= 0) { if (CapabilityUtils.getCapability(mContext).getEndToEndEncryptionApiVersion().compareTo(E2EVersion.V2_0) >= 0) {
if (object == null) { if (object == null) {
// TODO return error
return new RemoteOperationResult(new IllegalStateException("Metadata does not exist")); return new RemoteOperationResult(new IllegalStateException("Metadata does not exist"));
} }
} else { } else {
// v1 is allowed to be null, thus create it object = getDecryptedFolderMetadataV1(publicKey,object);
DecryptedFolderMetadataFileV1 metadata = new DecryptedFolderMetadataFileV1();
metadata.setMetadata(new DecryptedMetadata());
metadata.getMetadata().setVersion(1.2);
metadata.getMetadata().setMetadataKeys(new HashMap<>());
String metadataKey = EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateKey());
String encryptedMetadataKey = EncryptionUtils.encryptStringAsymmetric(metadataKey, publicKey);
metadata.getMetadata().setMetadataKey(encryptedMetadataKey);
if (object instanceof DecryptedFolderMetadataFileV1) {
metadata = (DecryptedFolderMetadataFileV1) object;
}
object = metadata;
} }
// todo fail if no metadata List<String> fileNames = checkNameCollision(object);
// metadataExists = metadataPair.getFirst();
// DecryptedFolderMetadataFile metadata = metadataPair.getSecond();
// TODO E2E: check counter: must be less than our counter, check rest: signature, etc
/**** E2E *****/
// check name collision
List<String> fileNames = new ArrayList<>();
if (object instanceof DecryptedFolderMetadataFileV1 metadata) {
for (DecryptedFile file : metadata.getFiles().values()) {
fileNames.add(file.getEncrypted().getFilename());
}
} else {
for (com.owncloud.android.datamodel.e2e.v2.decrypted.DecryptedFile file :
((DecryptedFolderMetadataFile) object).getMetadata().getFiles().values()) {
fileNames.add(file.getFilename());
}
}
RemoteOperationResult collisionResult = checkNameCollision(client, fileNames, parentFile.isEncrypted()); RemoteOperationResult collisionResult = checkNameCollision(client, fileNames, parentFile.isEncrypted());
if (collisionResult != null) { if (collisionResult != null) {
@ -543,30 +573,15 @@ public class UploadFileOperation extends SyncOperation {
return result; return result;
} }
// Get the last modification date of the file from the file system
long lastModifiedTimestamp = originalFile.lastModified() / 1000; long lastModifiedTimestamp = originalFile.lastModified() / 1000;
Long creationTimestamp = FileUtil.getCreationTimestamp(originalFile); Long creationTimestamp = FileUtil.getCreationTimestamp(originalFile);
/***** E2E *****/
byte[] key = EncryptionUtils.generateKey(); byte[] key = EncryptionUtils.generateKey();
byte[] iv = EncryptionUtils.randomBytes(EncryptionUtils.ivLength); byte[] iv = EncryptionUtils.randomBytes(EncryptionUtils.ivLength);
Cipher cipher = EncryptionUtils.getCipher(Cipher.ENCRYPT_MODE, key, iv); Cipher cipher = EncryptionUtils.getCipher(Cipher.ENCRYPT_MODE, key, iv);
File file = new File(mFile.getStoragePath()); File file = new File(mFile.getStoragePath());
EncryptedFile encryptedFile = EncryptionUtils.encryptFile(user.getAccountName(), file, cipher); EncryptedFile encryptedFile = EncryptionUtils.encryptFile(user.getAccountName(), file, cipher);
String encryptedFileName = getEncryptedFileName(object);
// new random file name, check if it exists in metadata
String encryptedFileName = EncryptionUtils.generateUid();
if (object instanceof DecryptedFolderMetadataFileV1 metadata) {
while (metadata.getFiles().get(encryptedFileName) != null) {
encryptedFileName = EncryptionUtils.generateUid();
}
} else {
while (((DecryptedFolderMetadataFile) object).getMetadata().getFiles().get(encryptedFileName) != null) {
encryptedFileName = EncryptionUtils.generateUid();
}
}
encryptedTempFile = encryptedFile.getEncryptedFile(); encryptedTempFile = encryptedFile.getEncryptedFile();