mirror of
https://github.com/nextcloud/android.git
synced 2024-11-26 15:15:51 +03:00
Extract logics to functions
Signed-off-by: alperozturk <alper_ozturk@proton.me>
This commit is contained in:
parent
6c8c58f220
commit
b3357c0b07
1 changed files with 83 additions and 68 deletions
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue