mirror of
https://github.com/nextcloud/android.git
synced 2024-11-27 09:39:25 +03:00
fix codacy
This commit is contained in:
parent
b6e84b66fd
commit
febe6b60c0
8 changed files with 17 additions and 1069 deletions
|
@ -53,10 +53,6 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||
import static com.owncloud.android.utils.EncryptionUtils.decodeStringToBase64Bytes;
|
||||
import static com.owncloud.android.utils.EncryptionUtils.encodeBytesToBase64String;
|
||||
import static com.owncloud.android.utils.EncryptionUtils.generateIV;
|
||||
import static com.owncloud.android.utils.EncryptionUtils.generateKey;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
@ -117,7 +113,7 @@ public class EncryptionTestIT {
|
|||
@Test
|
||||
public void encryptStringAsymmetric() throws Exception {
|
||||
byte[] key1 = EncryptionUtils.generateKey();
|
||||
String base64encodedKey = encodeBytesToBase64String(key1);
|
||||
String base64encodedKey = EncryptionUtils.encodeBytesToBase64String(key1);
|
||||
|
||||
String encryptedString = EncryptionUtils.encryptStringAsymmetric(base64encodedKey, cert);
|
||||
String decryptedString = EncryptionUtils.decryptStringAsymmetric(encryptedString, privateKey);
|
||||
|
@ -129,7 +125,7 @@ public class EncryptionTestIT {
|
|||
|
||||
@Test
|
||||
public void encryptStringSymmetric() throws Exception {
|
||||
byte[] key = generateKey();
|
||||
byte[] key = EncryptionUtils.generateKey();
|
||||
|
||||
String encryptedString = EncryptionUtils.encryptStringSymmetric(privateKey, key);
|
||||
String decryptedString = EncryptionUtils.decryptStringSymmetric(encryptedString, key);
|
||||
|
@ -146,7 +142,7 @@ public class EncryptionTestIT {
|
|||
KeyPair keyPair = keyGen.generateKeyPair();
|
||||
PrivateKey privateKey = keyPair.getPrivate();
|
||||
byte[] privateKeyBytes = privateKey.getEncoded();
|
||||
String privateKeyString = encodeBytesToBase64String(privateKeyBytes);
|
||||
String privateKeyString = EncryptionUtils.encodeBytesToBase64String(privateKeyBytes);
|
||||
|
||||
String encryptedString = EncryptionUtils.encryptPrivateKey(privateKeyString, keyPhrase);
|
||||
String decryptedString = EncryptionUtils.decryptPrivateKey(encryptedString, keyPhrase);
|
||||
|
@ -164,7 +160,7 @@ public class EncryptionTestIT {
|
|||
String urlEncoded = URLEncoder.encode("-----BEGIN CERTIFICATE REQUEST-----\n" + string +
|
||||
"\n-----END CERTIFICATE REQUEST-----", "UTF-8");
|
||||
|
||||
Log_OC.d(TAG, "public: " + encodeBytesToBase64String(keyPair.getPublic().getEncoded()));
|
||||
Log_OC.d(TAG, "public: " + EncryptionUtils.encodeBytesToBase64String(keyPair.getPublic().getEncoded()));
|
||||
Log_OC.d(TAG, "csrPEM: " + string);
|
||||
Log_OC.d(TAG, "csrPEM: " + urlEncoded);
|
||||
}
|
||||
|
@ -234,7 +230,7 @@ public class EncryptionTestIT {
|
|||
Set<String> keys = new HashSet<>();
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
assertTrue(keys.add(encodeBytesToBase64String(generateKey())));
|
||||
assertTrue(keys.add(EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateKey())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,7 +242,7 @@ public class EncryptionTestIT {
|
|||
Set<String> ivs = new HashSet<>();
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
assertTrue(ivs.add(encodeBytesToBase64String(generateIV())));
|
||||
assertTrue(ivs.add(EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateIV())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,9 +263,9 @@ public class EncryptionTestIT {
|
|||
}
|
||||
|
||||
private DecryptedFolderMetadata generateFolderMetadata() throws Exception {
|
||||
String metadataKey0 = encodeBytesToBase64String(EncryptionUtils.generateKey());
|
||||
String metadataKey1 = encodeBytesToBase64String(EncryptionUtils.generateKey());
|
||||
String metadataKey2 = encodeBytesToBase64String(EncryptionUtils.generateKey());
|
||||
String metadataKey0 = EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateKey());
|
||||
String metadataKey1 = EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateKey());
|
||||
String metadataKey2 = EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateKey());
|
||||
HashMap<Integer, String> metadataKeys = new HashMap<>();
|
||||
metadataKeys.put(0, EncryptionUtils.encryptStringAsymmetric(metadataKey0, cert));
|
||||
metadataKeys.put(1, EncryptionUtils.encryptStringAsymmetric(metadataKey1, cert));
|
||||
|
@ -332,7 +328,7 @@ public class EncryptionTestIT {
|
|||
fileOutputStream.write(encryptedFile.encryptedBytes);
|
||||
fileOutputStream.close();
|
||||
|
||||
byte[] authenticationTag = decodeStringToBase64Bytes(encryptedFile.authenticationTag);
|
||||
byte[] authenticationTag = EncryptionUtils.decodeStringToBase64Bytes(encryptedFile.authenticationTag);
|
||||
|
||||
// verify authentication tag
|
||||
assertTrue(Arrays.equals(expectedAuthTag, authenticationTag));
|
||||
|
|
|
@ -64,7 +64,6 @@ import com.owncloud.android.utils.AnalyticsUtils;
|
|||
import com.owncloud.android.utils.FilesSyncHelper;
|
||||
import com.owncloud.android.utils.PermissionUtil;
|
||||
import com.owncloud.android.utils.ReceiversHelper;
|
||||
import com.owncloud.android.utils.EncryptionUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
@ -72,8 +71,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
|
||||
|
|
|
@ -1055,19 +1055,8 @@ public class FileUploader extends Service
|
|||
mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
|
||||
getClientFor(ocAccount, this);
|
||||
|
||||
|
||||
// // If parent folder is encrypted, upload file encrypted
|
||||
// OCFile parent = mStorageManager.getFileByPath(mCurrentUpload.getFile().getParentRemotePath());
|
||||
|
||||
// if (parent.isEncrypted()) {
|
||||
// UploadEncryptedFileOperation uploadEncryptedFileOperation =
|
||||
// new UploadEncryptedFileOperation(parent, mCurrentUpload);
|
||||
//
|
||||
// uploadResult = uploadEncryptedFileOperation.execute(mUploadClient, mStorageManager);
|
||||
// } else {
|
||||
/// perform the regular upload
|
||||
uploadResult = mCurrentUpload.execute(mUploadClient, mStorageManager);
|
||||
// }
|
||||
/// perform the upload
|
||||
uploadResult = mCurrentUpload.execute(mUploadClient, mStorageManager);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -88,7 +88,6 @@ public class RemoveRemoteEncryptedFileOperation extends RemoteOperation {
|
|||
DecryptedFolderMetadata metadata;
|
||||
|
||||
String privateKey = arbitraryDataProvider.getValue(account.name, EncryptionUtils.PRIVATE_KEY);
|
||||
String publicKey = arbitraryDataProvider.getValue(account.name, EncryptionUtils.PUBLIC_KEY);
|
||||
|
||||
// unlock
|
||||
|
||||
|
@ -100,9 +99,9 @@ public class RemoveRemoteEncryptedFileOperation extends RemoteOperation {
|
|||
if (lockFileOperationResult.isSuccess()) {
|
||||
token = (String) lockFileOperationResult.getData().get(0);
|
||||
} else if (lockFileOperationResult.getHttpCode() == HttpStatus.SC_FORBIDDEN) {
|
||||
throw new Exception("Forbidden! Please try again later.)");
|
||||
throw new RuntimeException("Forbidden! Please try again later.)");
|
||||
} else {
|
||||
throw new Exception("Unknown error!");
|
||||
throw new RuntimeException("Unknown error!");
|
||||
}
|
||||
|
||||
// refresh metadata
|
||||
|
@ -119,7 +118,7 @@ public class RemoveRemoteEncryptedFileOperation extends RemoteOperation {
|
|||
|
||||
metadata = EncryptionUtils.decryptFolderMetaData(encryptedFolderMetadata, privateKey);
|
||||
} else {
|
||||
throw new Exception("No Metadata found!");
|
||||
throw new RuntimeException("No Metadata found!");
|
||||
}
|
||||
|
||||
// delete file remote
|
||||
|
@ -143,7 +142,7 @@ public class RemoveRemoteEncryptedFileOperation extends RemoteOperation {
|
|||
RemoteOperationResult uploadMetadataOperationResult = storeMetadataOperation.execute(client);
|
||||
|
||||
if (!uploadMetadataOperationResult.isSuccess()) {
|
||||
throw new Exception();
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
// return success
|
||||
|
|
|
@ -1,880 +0,0 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2017 Tobias Kaminsky
|
||||
* Copyright (C) 2017 Nextcloud GmbH.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.operations;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.datamodel.DecryptedFolderMetadata;
|
||||
import com.owncloud.android.datamodel.EncryptedFolderMetadata;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.files.services.FileUploader;
|
||||
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
|
||||
import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
|
||||
import com.owncloud.android.lib.common.operations.OperationCancelledException;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.ChunkedUploadRemoteFileOperation;
|
||||
import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
|
||||
import com.owncloud.android.lib.resources.files.GetMetadataOperation;
|
||||
import com.owncloud.android.lib.resources.files.LockFileOperation;
|
||||
import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
|
||||
import com.owncloud.android.lib.resources.files.RemoteFile;
|
||||
import com.owncloud.android.lib.resources.files.StoreMetadataOperation;
|
||||
import com.owncloud.android.lib.resources.files.UnlockFileOperation;
|
||||
import com.owncloud.android.lib.resources.files.UpdateMetadataOperation;
|
||||
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
|
||||
import com.owncloud.android.operations.common.SyncOperation;
|
||||
import com.owncloud.android.utils.EncryptionUtils;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
import com.owncloud.android.utils.MimeType;
|
||||
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.commons.httpclient.methods.RequestEntity;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.nio.channels.OverlappingFileLockException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.owncloud.android.utils.EncryptionUtils.encodeStringToBase64Bytes;
|
||||
|
||||
|
||||
/**
|
||||
* Operation performing the update in the ownCloud server
|
||||
* of a file that was modified locally.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public class UploadEncryptedFileOperation extends SyncOperation {
|
||||
|
||||
private static final String TAG = UploadEncryptedFileOperation.class.getSimpleName();
|
||||
|
||||
public static final int CREATED_BY_USER = 0;
|
||||
public static final int CREATED_AS_INSTANT_PICTURE = 1;
|
||||
public static final int CREATED_AS_INSTANT_VIDEO = 2;
|
||||
private OCFile parentFile;
|
||||
|
||||
/**
|
||||
* OCFile which is to be uploaded.
|
||||
*/
|
||||
private OCFile ocFile;
|
||||
private int localBehaviour = FileUploader.LOCAL_BEHAVIOUR_COPY;
|
||||
private final String originalStoragePath;
|
||||
private boolean chunked = false;
|
||||
private boolean mRemoteFolderToBeCreated = false;
|
||||
private int mCreatedBy = CREATED_BY_USER;
|
||||
|
||||
private long mOCUploadId = -1;
|
||||
/**
|
||||
* Local path to file which is to be uploaded (before any possible renaming or moving).
|
||||
*/
|
||||
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
|
||||
|
||||
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
|
||||
private final AtomicBoolean mUploadStarted = new AtomicBoolean(false);
|
||||
|
||||
private Context context;
|
||||
|
||||
private UploadRemoteFileOperation mUploadOperation;
|
||||
|
||||
protected RequestEntity mEntity = null;
|
||||
|
||||
private Account account;
|
||||
private ArbitraryDataProvider arbitraryDataProvider;
|
||||
|
||||
public UploadEncryptedFileOperation(OCFile parent, UploadFileOperation uploadFileOperation) {
|
||||
parentFile = parent;
|
||||
ocFile = uploadFileOperation.getFile();
|
||||
account = uploadFileOperation.getAccount();
|
||||
chunked = uploadFileOperation.isChunkedUploadSupported();
|
||||
context = uploadFileOperation.getContext();
|
||||
localBehaviour = uploadFileOperation.getLocalBehaviour();
|
||||
originalStoragePath = uploadFileOperation.getStoragePath();
|
||||
|
||||
arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return (ocFile != null) ? ocFile.getFileName() : null;
|
||||
}
|
||||
|
||||
public OCFile getFile() {
|
||||
return ocFile;
|
||||
}
|
||||
|
||||
public String getStoragePath() {
|
||||
return ocFile.getStoragePath();
|
||||
}
|
||||
|
||||
public String getRemotePath() {
|
||||
return ocFile.getParentRemotePath() + ocFile.getEncryptedFileName();
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return ocFile.getMimetype();
|
||||
}
|
||||
|
||||
public void setRemoteFolderToBeCreated() {
|
||||
mRemoteFolderToBeCreated = true;
|
||||
}
|
||||
|
||||
public void setCreatedBy(int createdBy) {
|
||||
mCreatedBy = createdBy;
|
||||
if (createdBy < CREATED_BY_USER || CREATED_AS_INSTANT_VIDEO < createdBy) {
|
||||
mCreatedBy = CREATED_BY_USER;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCreatedBy() {
|
||||
return mCreatedBy;
|
||||
}
|
||||
|
||||
public boolean isInstantPicture() {
|
||||
return mCreatedBy == CREATED_AS_INSTANT_PICTURE;
|
||||
}
|
||||
|
||||
public boolean isInstantVideo() {
|
||||
return mCreatedBy == CREATED_AS_INSTANT_VIDEO;
|
||||
}
|
||||
|
||||
public void setOCUploadId(long id) {
|
||||
mOCUploadId = id;
|
||||
}
|
||||
|
||||
public long getOCUploadId() {
|
||||
return mOCUploadId;
|
||||
}
|
||||
|
||||
public Set<OnDatatransferProgressListener> getDataTransferListeners() {
|
||||
return mDataTransferListeners;
|
||||
}
|
||||
|
||||
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.add(listener);
|
||||
}
|
||||
if (mEntity != null) {
|
||||
((ProgressiveDataTransferer) mEntity).addDatatransferProgressListener(listener);
|
||||
}
|
||||
if (mUploadOperation != null) {
|
||||
mUploadOperation.addDatatransferProgressListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
|
||||
synchronized (mDataTransferListeners) {
|
||||
mDataTransferListeners.remove(listener);
|
||||
}
|
||||
if (mEntity != null) {
|
||||
((ProgressiveDataTransferer) mEntity).removeDatatransferProgressListener(listener);
|
||||
}
|
||||
if (mUploadOperation != null) {
|
||||
mUploadOperation.removeDatatransferProgressListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteOperationResult run(OwnCloudClient client) {
|
||||
RemoteOperationResult result = null;
|
||||
boolean metadataExists = false;
|
||||
String token = null;
|
||||
mCancellationRequested.set(false);
|
||||
mUploadStarted.set(true);
|
||||
|
||||
File temporalFile = null;
|
||||
File originalFile = new File(ocFile.getStoragePath());
|
||||
File expectedFile = null;
|
||||
FileLock fileLock = null;
|
||||
|
||||
String privateKey = arbitraryDataProvider.getValue(account.name, EncryptionUtils.PRIVATE_KEY);
|
||||
String publicKey = arbitraryDataProvider.getValue(account.name, EncryptionUtils.PUBLIC_KEY);
|
||||
|
||||
try {
|
||||
|
||||
/// check if the file continues existing before schedule the operation
|
||||
if (!originalFile.exists()) {
|
||||
Log_OC.d(TAG, ocFile.getStoragePath() + " not exists anymore");
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
||||
/// check the existence of the parent folder for the file to upload
|
||||
String remoteParentPath = new File(getRemotePath()).getParent();
|
||||
remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ?
|
||||
remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR;
|
||||
result = grantFolderExistence(remoteParentPath, client);
|
||||
|
||||
if (!result.isSuccess()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO automatic rename? UploadFileOperation:365
|
||||
|
||||
/// set parent local id in uploading file
|
||||
// OCFile parent = getStorageManager().getFileByPath(remoteParentPath);
|
||||
// ocFile.setParentId(parent.getFileId());
|
||||
|
||||
|
||||
// if (mCancellationRequested.get()) {
|
||||
// throw new OperationCancelledException();
|
||||
// }
|
||||
|
||||
// Get the last modification date of the file from the file system
|
||||
Long timeStampLong = originalFile.lastModified() / 1000;
|
||||
String timeStamp = timeStampLong.toString();
|
||||
|
||||
// Lock folder
|
||||
LockFileOperation lockFileOperation = new LockFileOperation(parentFile.getLocalId());
|
||||
RemoteOperationResult lockFileOperationResult = lockFileOperation.execute(client);
|
||||
|
||||
|
||||
if (lockFileOperationResult.isSuccess()) {
|
||||
token = (String) lockFileOperationResult.getData().get(0);
|
||||
} else if (lockFileOperationResult.getHttpCode() == HttpStatus.SC_FORBIDDEN) {
|
||||
throw new Exception("Forbidden! Please try again later.)");
|
||||
} else {
|
||||
throw new Exception("Unknown error!");
|
||||
}
|
||||
|
||||
// Update metadata
|
||||
GetMetadataOperation getMetadataOperation = new GetMetadataOperation(parentFile.getLocalId());
|
||||
RemoteOperationResult getMetadataOperationResult = getMetadataOperation.execute(client);
|
||||
|
||||
DecryptedFolderMetadata metadata;
|
||||
|
||||
if (getMetadataOperationResult.isSuccess()) {
|
||||
metadataExists = true;
|
||||
|
||||
// decrypt metadata
|
||||
String serializedEncryptedMetadata = (String) getMetadataOperationResult.getData().get(0);
|
||||
|
||||
|
||||
EncryptedFolderMetadata encryptedFolderMetadata = EncryptionUtils.deserializeJSON(
|
||||
serializedEncryptedMetadata, new TypeToken<EncryptedFolderMetadata>() {
|
||||
});
|
||||
|
||||
metadata = EncryptionUtils.decryptFolderMetaData(encryptedFolderMetadata, privateKey);
|
||||
|
||||
} else if (getMetadataOperationResult.getHttpCode() == HttpStatus.SC_NOT_FOUND) {
|
||||
// new metadata
|
||||
metadata = new DecryptedFolderMetadata();
|
||||
metadata.metadata = new DecryptedFolderMetadata.Metadata();
|
||||
metadata.metadata.metadataKeys = new HashMap<>();
|
||||
String metadataKey = EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateKey());
|
||||
String encryptedMetadataKey = EncryptionUtils.encryptStringAsymmetric(metadataKey, publicKey);
|
||||
metadata.metadata.metadataKeys.put(0, encryptedMetadataKey);
|
||||
} else {
|
||||
// TODO error
|
||||
throw new Exception("something wrong");
|
||||
}
|
||||
|
||||
// Key
|
||||
byte[] key = null;
|
||||
|
||||
try {
|
||||
// TODO change key if file has changed, e.g. when file is updated
|
||||
key = encodeStringToBase64Bytes(metadata.files.get(ocFile.getFileName()).encrypted.key);
|
||||
} catch (Exception e) {
|
||||
// no key found
|
||||
}
|
||||
|
||||
if (key == null || key.length == 0) {
|
||||
key = EncryptionUtils.generateKey();
|
||||
}
|
||||
|
||||
// IV
|
||||
byte[] iv = null;
|
||||
|
||||
try {
|
||||
iv = encodeStringToBase64Bytes(metadata.files.get(ocFile.getFileName()).initializationVector);
|
||||
} catch (Exception e) {
|
||||
// no iv found
|
||||
}
|
||||
|
||||
if (iv == null || iv.length == 0) {
|
||||
iv = EncryptionUtils.generateIV();
|
||||
}
|
||||
|
||||
|
||||
EncryptionUtils.EncryptedFile encryptedFile = EncryptionUtils.encryptFile(ocFile, key, iv);
|
||||
|
||||
// new random file name, check if it exists in metadata
|
||||
String encryptedFileName = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
|
||||
while (metadata.files.get(encryptedFileName) != null) {
|
||||
encryptedFileName = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
ocFile.setEncryptedFileName(encryptedFileName);
|
||||
|
||||
File encryptedTempFile = File.createTempFile("encFile", encryptedFileName);
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(encryptedTempFile);
|
||||
fileOutputStream.write(encryptedFile.encryptedBytes);
|
||||
fileOutputStream.close();
|
||||
|
||||
/// perform the upload
|
||||
if (chunked &&
|
||||
(new File(ocFile.getStoragePath())).length() >
|
||||
ChunkedUploadRemoteFileOperation.CHUNK_SIZE) {
|
||||
mUploadOperation = new ChunkedUploadRemoteFileOperation(context, encryptedTempFile.getAbsolutePath(),
|
||||
ocFile.getParentRemotePath() + encryptedFileName, ocFile.getMimetype(),
|
||||
ocFile.getEtagInConflict(), timeStamp);
|
||||
} else {
|
||||
mUploadOperation = new UploadRemoteFileOperation(encryptedTempFile.getAbsolutePath(),
|
||||
ocFile.getParentRemotePath() + encryptedFileName, ocFile.getMimetype(),
|
||||
ocFile.getEtagInConflict(), timeStamp);
|
||||
}
|
||||
|
||||
Iterator<OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
|
||||
while (listener.hasNext()) {
|
||||
mUploadOperation.addDatatransferProgressListener(listener.next());
|
||||
}
|
||||
|
||||
if (mCancellationRequested.get()) {
|
||||
throw new OperationCancelledException();
|
||||
}
|
||||
|
||||
// FileChannel channel = null;
|
||||
// try {
|
||||
// channel = new RandomAccessFile(ocFile.getStoragePath(), "rw").getChannel();
|
||||
// fileLock = channel.tryLock();
|
||||
// } catch (FileNotFoundException e) {
|
||||
// if (temporalFile == null) {
|
||||
// String temporalPath = FileStorageUtils.getTemporalPath(account.name) + ocFile.getRemotePath();
|
||||
// ocFile.setStoragePath(temporalPath);
|
||||
// temporalFile = new File(temporalPath);
|
||||
//
|
||||
// result = copy(originalFile, temporalFile);
|
||||
//
|
||||
// if (result != null) {
|
||||
// return result;
|
||||
// } else {
|
||||
// if (temporalFile.length() == originalFile.length()) {
|
||||
// channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel();
|
||||
// fileLock = channel.tryLock();
|
||||
// } else {
|
||||
// while (temporalFile.length() != originalFile.length()) {
|
||||
// Files.deleteIfExists(Paths.get(temporalPath));
|
||||
// result = copy(originalFile, temporalFile);
|
||||
//
|
||||
// if (result != null) {
|
||||
// return result;
|
||||
// } else {
|
||||
// channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").
|
||||
// getChannel();
|
||||
// fileLock = channel.tryLock();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel();
|
||||
// fileLock = channel.tryLock();
|
||||
// }
|
||||
// }
|
||||
|
||||
result = mUploadOperation.execute(client);
|
||||
|
||||
/// move local temporal file or original file to its corresponding
|
||||
// location in the ownCloud local folder
|
||||
if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED) {
|
||||
result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
|
||||
}
|
||||
|
||||
if (result.isSuccess()) {
|
||||
// upload metadata
|
||||
DecryptedFolderMetadata.DecryptedFile decryptedFile = new DecryptedFolderMetadata.DecryptedFile();
|
||||
DecryptedFolderMetadata.Data data = new DecryptedFolderMetadata.Data();
|
||||
data.filename = ocFile.getFileName();
|
||||
data.mimetype = ocFile.getMimetype();
|
||||
data.key = EncryptionUtils.encodeBytesToBase64String(key);
|
||||
|
||||
decryptedFile.encrypted = data;
|
||||
decryptedFile.initializationVector = EncryptionUtils.encodeBytesToBase64String(iv);
|
||||
decryptedFile.authenticationTag = encryptedFile.authenticationTag;
|
||||
|
||||
metadata.files.put(encryptedFileName, decryptedFile);
|
||||
|
||||
EncryptedFolderMetadata encryptedFolderMetadata = EncryptionUtils.encryptFolderMetadata(metadata,
|
||||
privateKey);
|
||||
String serializedFolderMetadata = EncryptionUtils.serializeJSON(encryptedFolderMetadata);
|
||||
|
||||
// upload metadata
|
||||
RemoteOperationResult uploadMetadataOperationResult;
|
||||
if (metadataExists) {
|
||||
// update metadata
|
||||
UpdateMetadataOperation storeMetadataOperation = new UpdateMetadataOperation(parentFile.getLocalId(),
|
||||
serializedFolderMetadata, token);
|
||||
uploadMetadataOperationResult = storeMetadataOperation.execute(client);
|
||||
} else {
|
||||
// store metadata
|
||||
StoreMetadataOperation storeMetadataOperation = new StoreMetadataOperation(parentFile.getLocalId(),
|
||||
serializedFolderMetadata);
|
||||
uploadMetadataOperationResult = storeMetadataOperation.execute(client);
|
||||
}
|
||||
|
||||
if (!uploadMetadataOperationResult.isSuccess()) {
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log_OC.d(TAG, ocFile.getStoragePath() + " not exists anymore");
|
||||
result = new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND);
|
||||
} catch (OverlappingFileLockException e) {
|
||||
Log_OC.d(TAG, "Overlapping file lock exception");
|
||||
result = new RemoteOperationResult(ResultCode.LOCK_FAILED);
|
||||
} catch (Exception e) {
|
||||
result = new RemoteOperationResult(e);
|
||||
|
||||
} finally {
|
||||
mUploadStarted.set(false);
|
||||
|
||||
// unlock file
|
||||
if (token != null) {
|
||||
UnlockFileOperation unlockFileOperation = new UnlockFileOperation(parentFile.getLocalId(), token);
|
||||
RemoteOperationResult unlockFileOperationResult = unlockFileOperation.execute(client);
|
||||
|
||||
if (!unlockFileOperationResult.isSuccess()) {
|
||||
Log_OC.e(TAG, "Failed to unlock " + parentFile.getLocalId());
|
||||
}
|
||||
}
|
||||
|
||||
if (fileLock != null) {
|
||||
try {
|
||||
fileLock.release();
|
||||
} catch (IOException e) {
|
||||
Log_OC.e(TAG, "Failed to unlock file with path " + ocFile.getStoragePath());
|
||||
}
|
||||
}
|
||||
|
||||
if (temporalFile != null && !originalFile.equals(temporalFile)) {
|
||||
temporalFile.delete();
|
||||
}
|
||||
if (result == null) {
|
||||
result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR);
|
||||
}
|
||||
if (result.isSuccess()) {
|
||||
Log_OC.i(TAG, "Upload of " + ocFile.getStoragePath() + " to " + ocFile.getRemotePath() + ": " +
|
||||
result.getLogMessage());
|
||||
} else {
|
||||
if (result.getException() != null) {
|
||||
if (result.isCancelled()) {
|
||||
Log_OC.w(TAG, "Upload of " + ocFile.getStoragePath() + " to " + ocFile.getRemotePath() +
|
||||
": " + result.getLogMessage());
|
||||
} else {
|
||||
Log_OC.e(TAG, "Upload of " + ocFile.getStoragePath() + " to " + ocFile.getRemotePath() +
|
||||
": " + result.getLogMessage(), result.getException());
|
||||
}
|
||||
|
||||
} else {
|
||||
Log_OC.e(TAG, "Upload of " + ocFile.getStoragePath() + " to " + ocFile.getRemotePath() +
|
||||
": " + result.getLogMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (localBehaviour) {
|
||||
case FileUploader.LOCAL_BEHAVIOUR_FORGET:
|
||||
String temporalPath = FileStorageUtils.getTemporalPath(account.name) + ocFile.getRemotePath();
|
||||
if (originalStoragePath.equals(temporalPath)) {
|
||||
// delete local file is was pre-copied in temporary folder (see .ui.helpers.UriUploader)
|
||||
temporalFile = new File(temporalPath);
|
||||
temporalFile.delete();
|
||||
}
|
||||
ocFile.setStoragePath("");
|
||||
saveUploadedFile(client);
|
||||
break;
|
||||
|
||||
case FileUploader.LOCAL_BEHAVIOUR_DELETE:
|
||||
Log_OC.d(TAG, "Delete source file");
|
||||
|
||||
originalFile.delete();
|
||||
getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath());
|
||||
saveUploadedFile(client);
|
||||
break;
|
||||
|
||||
case FileUploader.LOCAL_BEHAVIOUR_COPY:
|
||||
if (temporalFile != null) {
|
||||
try {
|
||||
move(temporalFile, expectedFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
ocFile.setStoragePath(expectedFile.getAbsolutePath());
|
||||
saveUploadedFile(client);
|
||||
FileDataStorageManager.triggerMediaScan(expectedFile.getAbsolutePath());
|
||||
break;
|
||||
|
||||
case FileUploader.LOCAL_BEHAVIOUR_MOVE:
|
||||
|
||||
String expectedPath = FileStorageUtils.getDefaultSavePathFor(account.name, ocFile);
|
||||
expectedFile = new File(expectedPath);
|
||||
|
||||
try {
|
||||
move(originalFile, expectedFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath());
|
||||
ocFile.setStoragePath(expectedFile.getAbsolutePath());
|
||||
saveUploadedFile(client);
|
||||
FileDataStorageManager.triggerMediaScan(expectedFile.getAbsolutePath());
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the existence of the folder where the current file will be uploaded both
|
||||
* in the remote server and in the local database.
|
||||
* <p/>
|
||||
* If the upload is set to enforce the creation of the folder, the method tries to
|
||||
* create it both remote and locally.
|
||||
*
|
||||
* @param pathToGrant Full remote path whose existence will be granted.
|
||||
* @return An {@link OCFile} instance corresponding to the folder where the file
|
||||
* will be uploaded.
|
||||
*/
|
||||
private RemoteOperationResult grantFolderExistence(String pathToGrant, OwnCloudClient client) {
|
||||
RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, context, false);
|
||||
RemoteOperationResult result = operation.execute(client);
|
||||
if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND && mRemoteFolderToBeCreated) {
|
||||
SyncOperation syncOp = new CreateFolderOperation(pathToGrant, true);
|
||||
result = syncOp.execute(client, getStorageManager());
|
||||
}
|
||||
if (result.isSuccess()) {
|
||||
OCFile parentDir = getStorageManager().getFileByPath(pathToGrant);
|
||||
if (parentDir == null) {
|
||||
parentDir = createLocalFolder(pathToGrant);
|
||||
}
|
||||
if (parentDir != null) {
|
||||
result = new RemoteOperationResult(ResultCode.OK);
|
||||
} else {
|
||||
result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private OCFile createLocalFolder(String remotePath) {
|
||||
String parentPath = new File(remotePath).getParent();
|
||||
parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ?
|
||||
parentPath : parentPath + OCFile.PATH_SEPARATOR;
|
||||
OCFile parent = getStorageManager().getFileByPath(parentPath);
|
||||
if (parent == null) {
|
||||
parent = createLocalFolder(parentPath);
|
||||
}
|
||||
if (parent != null) {
|
||||
OCFile createdFolder = new OCFile(remotePath);
|
||||
createdFolder.setMimetype(MimeType.DIRECTORY);
|
||||
createdFolder.setParentId(parent.getFileId());
|
||||
getStorageManager().saveFile(createdFolder);
|
||||
return createdFolder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if remotePath does not exist in the server and returns it, or adds
|
||||
* a suffix to it in order to avoid the server file is overwritten.
|
||||
*
|
||||
* @param wc
|
||||
* @param remotePath
|
||||
* @return
|
||||
*/
|
||||
private String getAvailableRemotePath(OwnCloudClient wc, String remotePath) {
|
||||
boolean check = existsFile(wc, remotePath);
|
||||
if (!check) {
|
||||
return remotePath;
|
||||
}
|
||||
|
||||
int pos = remotePath.lastIndexOf('.');
|
||||
String suffix = "";
|
||||
String extension = "";
|
||||
if (pos >= 0) {
|
||||
extension = remotePath.substring(pos + 1);
|
||||
remotePath = remotePath.substring(0, pos);
|
||||
}
|
||||
int count = 2;
|
||||
do {
|
||||
suffix = " (" + count + ")";
|
||||
if (pos >= 0) {
|
||||
check = existsFile(wc, remotePath + suffix + "." + extension);
|
||||
} else {
|
||||
check = existsFile(wc, remotePath + suffix);
|
||||
}
|
||||
count++;
|
||||
} while (check);
|
||||
|
||||
if (pos >= 0) {
|
||||
return remotePath + suffix + "." + extension;
|
||||
} else {
|
||||
return remotePath + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean existsFile(OwnCloudClient client, String remotePath) {
|
||||
ExistenceCheckRemoteOperation existsOperation =
|
||||
new ExistenceCheckRemoteOperation(remotePath, context, false);
|
||||
RemoteOperationResult result = existsOperation.execute(client);
|
||||
return result.isSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to cancel the actual upload operation. If actual upload operating
|
||||
* is in progress it is cancelled, if upload preparation is being performed
|
||||
* upload will not take place.
|
||||
*/
|
||||
public void cancel() {
|
||||
if (mUploadOperation == null) {
|
||||
if (mUploadStarted.get()) {
|
||||
Log_OC.d(TAG, "Cancelling upload during upload preparations.");
|
||||
mCancellationRequested.set(true);
|
||||
} else {
|
||||
Log_OC.e(TAG, "No upload in progress. This should not happen.");
|
||||
}
|
||||
} else {
|
||||
Log_OC.d(TAG, "Cancelling upload during actual upload operation.");
|
||||
mUploadOperation.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* As soon as this method return true, upload can be cancel via cancel().
|
||||
*/
|
||||
public boolean isUploadInProgress() {
|
||||
return mUploadStarted.get();
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * TODO rewrite with homogeneous fail handling, remove dependency on {@link RemoteOperationResult},
|
||||
// * TODO use Exceptions instead
|
||||
// *
|
||||
// * @param sourceFile Source file to copy.
|
||||
// * @param targetFile Target location to copy the file.
|
||||
// * @return {@link RemoteOperationResult}
|
||||
// * @throws IOException
|
||||
// */
|
||||
// private RemoteOperationResult copy(File sourceFile, File targetFile) throws IOException {
|
||||
// Log_OC.d(TAG, "Copying local file");
|
||||
//
|
||||
// RemoteOperationResult result = null;
|
||||
//
|
||||
// if (FileStorageUtils.getUsableSpace(account.name) < sourceFile.length()) {
|
||||
// result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_FULL);
|
||||
// return result; // error condition when the file should be copied
|
||||
//
|
||||
// } else {
|
||||
// Log_OC.d(TAG, "Creating temporal folder");
|
||||
// File temporalParent = targetFile.getParentFile();
|
||||
// temporalParent.mkdirs();
|
||||
// if (!temporalParent.isDirectory()) {
|
||||
// throw new IOException(
|
||||
// "Unexpected error: parent directory could not be created");
|
||||
// }
|
||||
// Log_OC.d(TAG, "Creating temporal file");
|
||||
// targetFile.createNewFile();
|
||||
// if (!targetFile.isFile()) {
|
||||
// throw new IOException(
|
||||
// "Unexpected error: target file could not be created");
|
||||
// }
|
||||
//
|
||||
// Log_OC.d(TAG, "Copying file contents");
|
||||
// InputStream in = null;
|
||||
// OutputStream out = null;
|
||||
//
|
||||
// try {
|
||||
// if (!mOriginalStoragePath.equals(targetFile.getAbsolutePath())) {
|
||||
// // In case document provider schema as 'content://'
|
||||
// if (mOriginalStoragePath.startsWith(UriUtils.URI_CONTENT_SCHEME)) {
|
||||
// Uri uri = Uri.parse(mOriginalStoragePath);
|
||||
// in = context.getContentResolver().openInputStream(uri);
|
||||
// } else {
|
||||
// in = new FileInputStream(sourceFile);
|
||||
// }
|
||||
// out = new FileOutputStream(targetFile);
|
||||
// int nRead;
|
||||
// byte[] buf = new byte[4096];
|
||||
// while (!mCancellationRequested.get() &&
|
||||
// (nRead = in.read(buf)) > -1) {
|
||||
// out.write(buf, 0, nRead);
|
||||
// }
|
||||
// out.flush();
|
||||
//
|
||||
// } // else: weird but possible situation, nothing to copy
|
||||
//
|
||||
// if (mCancellationRequested.get()) {
|
||||
// result = new RemoteOperationResult(new OperationCancelledException());
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED);
|
||||
// return result;
|
||||
//
|
||||
// } finally {
|
||||
// try {
|
||||
// if (in != null) {
|
||||
// in.close();
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// Log_OC.d(TAG, "Weird exception while closing input stream for " +
|
||||
// mOriginalStoragePath + " (ignoring)", e);
|
||||
// }
|
||||
// try {
|
||||
// if (out != null) {
|
||||
// out.close();
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// Log_OC.d(TAG, "Weird exception while closing output stream for " +
|
||||
// targetFile.getAbsolutePath() + " (ignoring)", e);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* TODO rewrite with homogeneous fail handling, remove dependency on {@link RemoteOperationResult},
|
||||
* TODO use Exceptions instead
|
||||
* <p>
|
||||
* TODO refactor both this and 'copy' in a single method
|
||||
*
|
||||
* @param sourceFile Source file to move.
|
||||
* @param targetFile Target location to move the file.
|
||||
* @return {@link RemoteOperationResult}
|
||||
* @throws IOException
|
||||
*/
|
||||
private void move(File sourceFile, File targetFile) throws IOException {
|
||||
|
||||
if (!targetFile.equals(sourceFile)) {
|
||||
File expectedFolder = targetFile.getParentFile();
|
||||
expectedFolder.mkdirs();
|
||||
|
||||
if (expectedFolder.isDirectory()) {
|
||||
if (!sourceFile.renameTo(targetFile)) {
|
||||
// try to copy and then delete
|
||||
targetFile.createNewFile();
|
||||
FileChannel inChannel = new FileInputStream(sourceFile).getChannel();
|
||||
FileChannel outChannel = new FileOutputStream(targetFile).getChannel();
|
||||
try {
|
||||
inChannel.transferTo(0, inChannel.size(), outChannel);
|
||||
sourceFile.delete();
|
||||
} catch (Exception e) {
|
||||
ocFile.setStoragePath(""); // forget the local file
|
||||
// by now, treat this as a success; the file was uploaded
|
||||
// the best option could be show a warning message
|
||||
} finally {
|
||||
if (inChannel != null) {
|
||||
inChannel.close();
|
||||
}
|
||||
if (outChannel != null) {
|
||||
outChannel.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
ocFile.setStoragePath("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a OC File after a successful upload.
|
||||
* <p/>
|
||||
* A PROPFIND is necessary to keep the props in the local database
|
||||
* synchronized with the server, specially the modification time and Etag
|
||||
* (where available)
|
||||
* <p/>
|
||||
*/
|
||||
private void saveUploadedFile(OwnCloudClient client) {
|
||||
OCFile file = ocFile;
|
||||
if (file.fileExists()) {
|
||||
file = getStorageManager().getFileById(file.getFileId());
|
||||
}
|
||||
long syncDate = System.currentTimeMillis();
|
||||
file.setLastSyncDateForData(syncDate);
|
||||
|
||||
// new PROPFIND to keep data consistent with server
|
||||
// in theory, should return the same we already have
|
||||
// TODO from the appropriate OC server version, get data from last PUT response headers, instead
|
||||
// TODO of a new PROPFIND; the latter may fail, specially for chunked uploads
|
||||
ReadRemoteFileOperation operation = new ReadRemoteFileOperation(getRemotePath());
|
||||
RemoteOperationResult result = operation.execute(client);
|
||||
if (result.isSuccess()) {
|
||||
updateOCFile(file, (RemoteFile) result.getData().get(0));
|
||||
file.setLastSyncDateForProperties(syncDate);
|
||||
} else {
|
||||
Log_OC.e(TAG, "Error reading properties of file after successful upload; this is gonna hurt...");
|
||||
}
|
||||
|
||||
file.setEncrypted(true);
|
||||
file.setStoragePath("");
|
||||
file.setParentId(parentFile.getFileId());
|
||||
getStorageManager().saveFile(file);
|
||||
getStorageManager().saveConflict(file, null);
|
||||
|
||||
FileDataStorageManager.triggerMediaScan(file.getStoragePath());
|
||||
}
|
||||
|
||||
private void updateOCFile(OCFile file, RemoteFile remoteFile) {
|
||||
file.setCreationTimestamp(remoteFile.getCreationTimestamp());
|
||||
file.setFileLength(remoteFile.getLength());
|
||||
// file.setMimetype(file.getMimetype());
|
||||
file.setModificationTimestamp(remoteFile.getModifiedTimestamp());
|
||||
file.setModificationTimestampAtLastSyncForData(remoteFile.getModifiedTimestamp());
|
||||
file.setEtag(remoteFile.getEtag());
|
||||
file.setRemoteId(remoteFile.getRemoteId());
|
||||
}
|
||||
|
||||
public interface OnRenameListener {
|
||||
|
||||
void onRenameUpload();
|
||||
}
|
||||
|
||||
}
|
|
@ -52,7 +52,6 @@ import android.support.v4.view.MenuItemCompat;
|
|||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
|
|
@ -289,7 +289,7 @@ public class SetupEncryptionDialogFragment extends DialogFragment {
|
|||
|
||||
publicKey = (String) result.getData().get(0);
|
||||
} else {
|
||||
throw new Exception("Public key not stored!");
|
||||
throw new RuntimeException("Public key not stored!");
|
||||
}
|
||||
|
||||
keyWords = EncryptionUtils.getRandomWords(12, getContext());
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2017 Tobias Kaminsky
|
||||
* Copyright (C) 2017 Nextcloud GmbH.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.utils;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.owncloud.android.datamodel.DecryptedFolderMetadata;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public class EncryptionTest {
|
||||
private String encryptedString = "{\"metadata\":{\"encrypted\":\"np1sIwoAFCb/vRqV/jWOIe1UtyVO02EJhvPoh3VwcZuiSbDjwQO5QHUWtKXpHLyX6wfbkRX6nr8mSG0+HhLRud1t126UMxQK5BNINu99WlzPMa5PaKhTXlpuRUf3tR6PTQ\\u003d\\u003d\",\"initializationVector\":" +
|
||||
"\"kahzfT4u86Knc+e3\",\"sharing\":{\"recipient\":{\"blah@schiessle.org\":\"PUBLIC KEY\"," +
|
||||
"\"bjoern@schiessle.org\":\"PUBLIC KEY\"},\"signature\":\"HMACOFRECIPIENTANDNEWESTMETADATAKEY\"}," +
|
||||
"\"version\":1},\"files\":{\"ia7OEEEyXMoRa1QWQk8r\":{\"encrypted\":\"yl52TIccvo62LezCaFjQFJs7a1Q281pOuj59oNXMX7ti+7+h1SjK1AAk1HuwT+CI7BT64+R0ZLgyR/vBPjWvAQuxi9JWgsCjFMX91Mv2m2zI/bNQCarczOfnmf4FZ3Nv6yPLSjShmfQzemQ99Z3g7UHyrZ6pKT18m17IueJHF3V5kOhd9vcH\",\"metadataKey\":0," +
|
||||
"\"initializationVector\":\"+mHu52HyZq+pAAIN\"}," +
|
||||
"\"n9WXAIXO2wRY4R8nXwmo\":{\"encrypted\":\"Z9YTAgY/0YqKQlDwiqENcZRRupjgmJ1f0bTy0hOHP2/mHxFtoHCftT4STvt21OJMx8wF6V3cquQIGJ976WxkhA4SQxaQNpznhm1W9e8y+B5x8QnxSasYnOSFtZ/xVgQq6IZRjvYdPo7rvZk49hnqkwnUyvqtCj14aCE42qoxVZCd9M6XaZEBTA\\u003d\\u003d\",\"metadataKey\":0,\"initializationVector\":" +
|
||||
"\"sOFd17hCKWIv0gyB\"}}}";
|
||||
|
||||
private String decryptedString = "{\"metadata\":{\"encrypted\":{\"metadataKeys\":{\"0\":" +
|
||||
"\"s4k4LPDpxoO53TKwem3Lo1\",\"2\":\"…\",\"3\":\"NEWESTMETADATAKEY\"}},\"initializationVector\":" +
|
||||
"\"kahzfT4u86Knc+e3\",\"sharing\":{\"recipient\":{\"blah@schiessle.org\":\"PUBLIC KEY\"," +
|
||||
"\"bjoern@schiessle.org\":\"PUBLIC KEY\"},\"signature\":\"HMACOFRECIPIENTANDNEWESTMETADATAKEY\"}," +
|
||||
"\"version\":1},\"files\":{\"ia7OEEEyXMoRa1QWQk8r\":{\"encrypted\":{\"key\":" +
|
||||
"\"jtboLmgGR1OQf2uneqCVHpklQLlIwWL5TXAQ0keK\",\"filename\":\"test.txt\",\"authenticationTag\":" +
|
||||
"\"HMAC of file\",\"version\":1},\"metadataKey\":0,\"initializationVector\":\"+mHu52HyZq+pAAIN\"}," +
|
||||
"\"n9WXAIXO2wRY4R8nXwmo\":{\"encrypted\":{\"key\":\"s4k4LPDpxoO53TKwem3Lo1yJnbNUYH2KLrSFT8Ea\"," +
|
||||
"\"filename\":\"test2.txt\",\"authenticationTag\":\"HMAC of file\",\"version\":1}," +
|
||||
"\"metadataKey\":0,\"initializationVector\":\"sOFd17hCKWIv0gyB\"}}}";
|
||||
|
||||
private String privateKey = "TUlJRXZRSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2N3Z2dTakFnRUFBb0lCQVFEV0FKMDNuNlBLVDNJWlZTT1paSzgyd3dqRTVWSW4vclZ5L0VLbmsyMVgzQ1dPbkdsb0ZrUXdiSWFsYjlkVWNRcmQzM250NVFoMmhJeXM5TkdsMjdMUmhreU1qemYzaFdzbnljSVhZQURVSExweGJZbWpJRzRjbWlNQnI4ckhjVFEvM0dUTlBKWG00ZzUwQlZEOXZlRThoMkQrTXdIQXlTSkxZcG5FaDBKWExES0pvVnpQYldxdVZVdHZNMmdmWVFHNFgwbS9kamR5VzJ4ZGN2UkpZeUtpWDZ3UmY3U3ViaWJkR1V1MHgxckhRdGhnM1dtaXdLd09NR2pQQ3oxRDAwMC9vWjZnckRHcW03TG5XMVZaN0VNTWtWWjVjVlc4NlpGQ2lrcXNtcDd1MVg1YjdCTzBiaThyV2Z0Zm8zZnJaOUptdmkvZHpmeXo2RFRFOWIrZU9CNzlBZ01CQUFFQ2dnRUJBSURYYzlCR1k5VnRDWFBwQjNyVjNJdXExcis4bFQ4UklldHRweSsvR2dqWXVSL29XYW5hSmduRmZUZGpZNUFxVXZHTUY1dTcxZUdOSWlrTGFLRmo2WUF1VEM0Z0dBRUZLYU9WM0M0NGxhY2UrTDFMeHA4WTZsSjhGbkZ3aGpTWG1tNk1ZWUFUWnVqUDF3WFJJWmJ6V0FVYU9MSXl3VzV4YWgxYTZ0c2cyRGNrZ2h3YVoxMURiRTVkNEpNNXl0Q1J6YmZzWTA3cElrUmU4WlFLcm1sMXU0THlsWXVHVHBDZGMwSnNXdUx3d1NWbm8vK056RURiVVNKZThIRmpnM1k3L2JkajgzNE9INzBtQWdBVUdEQTJqQ1BqY1hzNHJnN25udkhuQm5WcVFaemFvVWhHYzFOak9pZzMwNitUV25OL1JUNWc0TThucDNuMXZETWF2dVBiM0lFQ2dZRUE2NVpQV243UlYxZVVVS20zcVRUN1BSa3NuLzZDVWdFaFQ1WDloc0c3cXJXMUVlalhuODE2S1A0R3VsaDc1S0dhQ3hUVmdGZDhHdHF1QVU3MGdaKzB5MHVGd2hTdGtWN1A0K2xlUXlYSmxtNDNWNU9zT3Jxb25ocTZyOCthZ3lGbnNuOEhGd3lVcG1VM0FqR2tXVUNzYWFNdWM4SEt0ajU4RkdGRlh6K3ZlcDBDZ1lFQTZJdUZVZmljLytpUXpsVjczTDdWSS9kRjJNcFRPeHVKb1c4MmM1OE1tdEhGMFFQSktlYU5YVGJuYzluUXZ0aFBWM3c1eEZWc3FkN3pKOEM4ZkJ5S21Xc2ZLOU1abGQvY3RZTk9EMTNLWlM2WTNvWXpGVU5ZRzFPSEhpamNZT3RSWUsvY3k0cS9SRnExQ0pZVCtPaEVTOXlmeGFqZlZXdzFPdGxNZGNuNlYrRUNnWUFwNlN5bTBjYldQZnRodWorMU4zcTJyT0xXZDhXaFp4Z1ErNE1GMVROWXRFakpMZDRtVEx5OXpDdFFQV3VWQ2ZiSW4rVTNsdGk2UWtzUWFvWnZCUVY1NFM2amoyQXRhMnVhaFNyQzBWY2lqdXNEaG43dVY4U2xrK1hBWHpPQ3ZvK2ZIcUFaUnFDdlZYUkt6S0FMVE1rZlpldGVwb3cwamJzdk9QckpiaC8rdFFLQmdIQUFpd1R4RmtVWGNXOC9zdm1lSERCSGI2ZTd3eHlyNWIwUVFJeXRwVGVJSTV2SkZBR1BYclR2dGNpUnR6M0VGMnJPbFZBZnlNZUViMTdOTUxzaVVBc1draHZjZiswMHRpdmlneDFaa2hycnQ0c3QzYnEzQmQrYmVtK25SSVdWc1VzOVNMM3NKTFU2Yndra3A1ZngzcnNmRndEdmxpbWhoWDNEblZUNkpBNWhBb0dBZUtSZGRBVFAxZmVDL1pIZWE0VWh1MEVIencrY2xraDBrdjFDQkNHNnhjM002Y245SzFUNlIwMHRZYlFjS1JvZHJ1ZnBZNUNOL3V2Zyt0VWRucTUxRFhwTU5tbDVMdGpRYnV3MktuZ1F1ZG9NQ1NFMHMzT0dnaGJqMzZtbEVsRERjUGxLaE0rb1hyaVRYdXUvWmljclZqcGxTcWxuSlN2aDh6STJGNFBLaDlnPQ==";
|
||||
|
||||
private String publicKey = "-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDpzCCAo+gAwIBAgIBADANBgkqhkiG9w0BAQUFADBuMRowGAYDVQQDDBF3d3cu\n" +
|
||||
"bmV4dGNsb3VkLmNvbTESMBAGA1UECgwJTmV4dGNsb3VkMRIwEAYDVQQHDAlTdHV0\n" +
|
||||
"dGdhcnQxGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzELMAkGA1UEBhMCREUw\n" +
|
||||
"HhcNMTcwOTA0MTEwNTQyWhcNMzcwODMwMTEwNTQyWjBuMRowGAYDVQQDDBF3d3cu\n" +
|
||||
"bmV4dGNsb3VkLmNvbTESMBAGA1UECgwJTmV4dGNsb3VkMRIwEAYDVQQHDAlTdHV0\n" +
|
||||
"dGdhcnQxGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzELMAkGA1UEBhMCREUw\n" +
|
||||
"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWAJ03n6PKT3IZVSOZZK82\n" +
|
||||
"wwjE5VIn/rVy/EKnk21X3CWOnGloFkQwbIalb9dUcQrd33nt5Qh2hIys9NGl27LR\n" +
|
||||
"hkyMjzf3hWsnycIXYADUHLpxbYmjIG4cmiMBr8rHcTQ/3GTNPJXm4g50BVD9veE8\n" +
|
||||
"h2D+MwHAySJLYpnEh0JXLDKJoVzPbWquVUtvM2gfYQG4X0m/djdyW2xdcvRJYyKi\n" +
|
||||
"X6wRf7SubibdGUu0x1rHQthg3WmiwKwOMGjPCz1D000/oZ6grDGqm7LnW1VZ7EMM\n" +
|
||||
"kVZ5cVW86ZFCikqsmp7u1X5b7BO0bi8rWftfo3frZ9Jmvi/dzfyz6DTE9b+eOB79\n" +
|
||||
"AgMBAAGjUDBOMB0GA1UdDgQWBBS3zNF86LEZFT/KDdscr4ZJEisXqDAfBgNVHSME\n" +
|
||||
"GDAWgBS3zNF86LEZFT/KDdscr4ZJEisXqDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3\n" +
|
||||
"DQEBBQUAA4IBAQCPMu5AKNlh0gTr/k9Vc7RJ01uF07D+lTPGIErfW7+qXO21kXyw\n" +
|
||||
"+w8sxw+e1B/gah/bxotfO7ZuOhs49d8QRUzPy/miBFaZXfjfiqs7UXSDQ6oUbX3a\n" +
|
||||
"X9eTFMHDcsSUbyqhwn2cghmPJEhE10mtH2DJNPqDYvdpekJ6sEUVaqx63CD3nxcl\n" +
|
||||
"7fXh0IfmvDQOrSBszRqPY8pvnZJIEwqaENPk9Vgbzs8oXVstKl6wCqM0B36tmhBl\n" +
|
||||
"f6Dz/EhriF3Rq9w5RrWZOpS6XAWwRpyHPN+lKPa321dF6EEsnvhX8G3UbLbr0uEg\n" +
|
||||
"dR8lPhuKejU/Ds0ARwQGmFXFzidFNZL5ymos\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
@Test
|
||||
public void deserializeJSON() {
|
||||
String file = "ia7OEEEyXMoRa1QWQk8r";
|
||||
DecryptedFolderMetadata metadata = EncryptionUtils.deserializeJSON(decryptedString,
|
||||
new TypeToken<DecryptedFolderMetadata>() {});
|
||||
|
||||
assertEquals("jtboLmgGR1OQf2uneqCVHpklQLlIwWL5TXAQ0keK", metadata.files.get(file).encrypted.key);
|
||||
assertEquals("+mHu52HyZq+pAAIN", metadata.files.get(file).initializationVector);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializeJSON() {
|
||||
try {
|
||||
HashMap<Integer, String> metadataKeys = new HashMap<>();
|
||||
metadataKeys.put(0, EncryptionUtils.encryptStringAsymmetric("s4k4LPDpxoO53TKwem3Lo1", publicKey));
|
||||
metadataKeys.put(1, EncryptionUtils.encryptStringAsymmetric("Q3ZobVJHbTlkK1VHT0g3ME", publicKey));
|
||||
metadataKeys.put(2, EncryptionUtils.encryptStringAsymmetric("lkK1VHT0g3ME3TKwem3Lo1", publicKey));
|
||||
DecryptedFolderMetadata.Encrypted encrypted = new DecryptedFolderMetadata.Encrypted();
|
||||
encrypted.metadataKeys = metadataKeys;
|
||||
|
||||
DecryptedFolderMetadata.Metadata metadata1 = new DecryptedFolderMetadata.Metadata();
|
||||
metadata1.metadataKeys = metadataKeys;
|
||||
metadata1.version = 1;
|
||||
|
||||
DecryptedFolderMetadata.Sharing sharing = new DecryptedFolderMetadata.Sharing();
|
||||
sharing.signature = "HMACOFRECIPIENTANDNEWESTMETADATAKEY";
|
||||
HashMap<String, String> recipient = new HashMap<>();
|
||||
recipient.put("blah@schiessle.org", "PUBLIC KEY");
|
||||
recipient.put("bjoern@schiessle.org", "PUBLIC KEY");
|
||||
sharing.recipient = recipient;
|
||||
metadata1.sharing = sharing;
|
||||
|
||||
HashMap<String, DecryptedFolderMetadata.DecryptedFile> files = new HashMap<>();
|
||||
|
||||
DecryptedFolderMetadata.Data data1 = new DecryptedFolderMetadata.Data();
|
||||
data1.key = "jtboLmgGR1OQf2uneqCVHpklQLlIwWL5TXAQ0keK";
|
||||
data1.filename = "test.txt";
|
||||
data1.version = 1;
|
||||
|
||||
DecryptedFolderMetadata.DecryptedFile file1 = new DecryptedFolderMetadata.DecryptedFile();
|
||||
file1.initializationVector = "+mHu52HyZq+pAAIN";
|
||||
file1.encrypted = data1;
|
||||
file1.metadataKey = 0;
|
||||
file1.authenticationTag = "HMAC of file";
|
||||
|
||||
files.put("ia7OEEEyXMoRa1QWQk8r", file1);
|
||||
|
||||
DecryptedFolderMetadata.Data data2 = new DecryptedFolderMetadata.Data();
|
||||
data2.key = "s4k4LPDpxoO53TKwem3Lo1yJnbNUYH2KLrSFT8Ea";
|
||||
data2.filename = "test2.txt";
|
||||
data2.version = 1;
|
||||
|
||||
DecryptedFolderMetadata.DecryptedFile file2 = new DecryptedFolderMetadata.DecryptedFile();
|
||||
file2.initializationVector = "sOFd17hCKWIv0gyB";
|
||||
file2.encrypted = data2;
|
||||
file2.metadataKey = 0;
|
||||
file2.authenticationTag = "HMAC of file";
|
||||
|
||||
files.put("n9WXAIXO2wRY4R8nXwmo", file2);
|
||||
|
||||
DecryptedFolderMetadata metadata = new DecryptedFolderMetadata(metadata1, files);
|
||||
|
||||
// serialize
|
||||
assertEquals(decryptedString, EncryptionUtils.serializeJSON(metadata));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue