nextcloud-android/src/main/java/com/owncloud/android/operations/RemoveRemoteEncryptedFileOp...

174 lines
7.1 KiB
Java

/*
* 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.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.GetMetadataOperation;
import com.owncloud.android.lib.resources.files.LockFileOperation;
import com.owncloud.android.lib.resources.files.UnlockFileOperation;
import com.owncloud.android.lib.resources.files.UpdateMetadataOperation;
import com.owncloud.android.utils.EncryptionUtils;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
/**
* Remote operation performing the removal of a remote encrypted file or folder
*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public class RemoveRemoteEncryptedFileOperation extends RemoteOperation {
private static final String TAG = RemoveRemoteEncryptedFileOperation.class.getSimpleName();
private static final int REMOVE_READ_TIMEOUT = 30000;
private static final int REMOVE_CONNECTION_TIMEOUT = 5000;
private String remotePath;
private String parentId;
private Account account;
private ArbitraryDataProvider arbitraryDataProvider;
private String fileName;
/**
* Constructor
*
* @param remotePath RemotePath of the remote file or folder to remove from the server
* @param parentId local id of parent folder
*/
public RemoveRemoteEncryptedFileOperation(String remotePath, String parentId, Account account, Context context,
String fileName) {
this.remotePath = remotePath;
this.parentId = parentId;
this.account = account;
this.fileName = fileName;
arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
}
/**
* Performs the remove operation.
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result;
DeleteMethod delete = null;
String token = null;
DecryptedFolderMetadata metadata;
String privateKey = arbitraryDataProvider.getValue(account.name, EncryptionUtils.PRIVATE_KEY);
String publicKey = arbitraryDataProvider.getValue(account.name, EncryptionUtils.PUBLIC_KEY);
// unlock
try {
// Lock folder
LockFileOperation lockFileOperation = new LockFileOperation(parentId);
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!");
}
// refresh metadata
GetMetadataOperation getMetadataOperation = new GetMetadataOperation(parentId);
RemoteOperationResult getMetadataOperationResult = getMetadataOperation.execute(client);
if (getMetadataOperationResult.isSuccess()) {
// decrypt metadata
String serializedEncryptedMetadata = (String) getMetadataOperationResult.getData().get(0);
EncryptedFolderMetadata encryptedFolderMetadata = EncryptionUtils.deserializeJSON(
serializedEncryptedMetadata, new TypeToken<EncryptedFolderMetadata>() {
});
metadata = EncryptionUtils.decryptFolderMetaData(encryptedFolderMetadata, privateKey);
} else {
throw new Exception("No Metadata found!");
}
// delete file remote
delete = new DeleteMethod(client.getWebdavUri() + WebdavUtils.encodePath(remotePath));
int status = client.executeMethod(delete, REMOVE_READ_TIMEOUT, REMOVE_CONNECTION_TIMEOUT);
delete.getResponseBodyAsString(); // exhaust the response, although not interesting
result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), delete);
Log_OC.i(TAG, "Remove " + remotePath + ": " + result.getLogMessage());
// remove file from metadata
metadata.files.remove(fileName);
EncryptedFolderMetadata encryptedFolderMetadata = EncryptionUtils.encryptFolderMetadata(metadata,
privateKey);
String serializedFolderMetadata = EncryptionUtils.serializeJSON(encryptedFolderMetadata);
// upload metadata
UpdateMetadataOperation storeMetadataOperation = new UpdateMetadataOperation(parentId,
serializedFolderMetadata, token);
RemoteOperationResult uploadMetadataOperationResult = storeMetadataOperation.execute(client);
if (!uploadMetadataOperationResult.isSuccess()) {
throw new Exception();
}
// return success
return result;
} catch (Exception e) {
result = new RemoteOperationResult(e);
Log_OC.e(TAG, "Remove " + remotePath + ": " + result.getLogMessage(), e);
} finally {
if (delete != null) {
delete.releaseConnection();
}
// unlock file
if (token != null) {
UnlockFileOperation unlockFileOperation = new UnlockFileOperation(parentId, token);
RemoteOperationResult unlockFileOperationResult = unlockFileOperation.execute(client);
if (!unlockFileOperationResult.isSuccess()) {
Log_OC.e(TAG, "Failed to unlock " + parentId);
}
}
}
return result;
}
}