Skip to content

Commit

Permalink
Allow to create encrypted folder directly from bottom sheet dialog fr…
Browse files Browse the repository at this point in the history
…om NC PR: nextcloud#10782
  • Loading branch information
surinder-tsys committed Jan 10, 2024
1 parent e625f45 commit 0263556
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,11 @@ public void createFolder() {

}

@Override
public void createEncryptedFolder() {

}

@Override
public void uploadFromApp() {

Expand Down
13 changes: 12 additions & 1 deletion app/src/main/java/com/owncloud/android/files/FileMenuFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ private void filterUnlock(List<Integer> toHide, boolean fileLockingEnabled) {

private void filterEncrypt(List<Integer> toHide, boolean endToEndEncryptionEnabled) {
if (files.isEmpty() || !isSingleSelection() || isSingleFile() || isEncryptedFolder() || isGroupFolder()
|| !endToEndEncryptionEnabled || !isEmptyFolder() || isShared()) {
|| !endToEndEncryptionEnabled || !isEmptyFolder() || isShared() || isInSubFolder()) {
toHide.add(R.id.action_encrypted);
}
}
Expand Down Expand Up @@ -566,4 +566,15 @@ private boolean isShared() {
}
return false;
}

private boolean isInSubFolder() {
OCFile folder = files.iterator().next();
OCFile parent = storageManager.getFileById(folder.getParentId());

if (parent == null) {
return false;
}

return !OCFile.ROOT_PATH.equals(parent.getRemotePath());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,31 @@ public class CreateFolderOperation extends SyncOperation implements OnRemoteOper
private RemoteFile createdRemoteFolder;
private User user;
private Context context;
private boolean encrypted;

/**
* Constructor
*/
public CreateFolderOperation(String remotePath, User user, Context context, FileDataStorageManager storageManager) {
public CreateFolderOperation(String remotePath,
User user,
Context context,
FileDataStorageManager storageManager
) {
this(remotePath, false, user, context, storageManager);
}

public CreateFolderOperation(String remotePath,
boolean encrypted,
User user,
Context context,
FileDataStorageManager storageManager
) {
super(storageManager);

this.remotePath = remotePath;
this.user = user;
this.context = context;
this.encrypted = encrypted;
}

@Override
Expand Down Expand Up @@ -102,7 +117,7 @@ protected RemoteOperationResult run(OwnCloudClient client) {
if (encryptedAncestor) {
return encryptedCreate(parent, client);
} else {
return normalCreate(client);
return normalCreate(client, encrypted);
}
}

Expand Down Expand Up @@ -290,7 +305,7 @@ private String createRandomFileName(DecryptedFolderMetadata metadata) {
return encryptedFileName;
}

private RemoteOperationResult normalCreate(OwnCloudClient client) {
private RemoteOperationResult normalCreate(OwnCloudClient client, boolean encrypted) {
RemoteOperationResult result = new CreateFolderRemoteOperation(remotePath, true).execute(client);

if (result.isSuccess()) {
Expand All @@ -299,6 +314,21 @@ private RemoteOperationResult normalCreate(OwnCloudClient client) {

createdRemoteFolder = (RemoteFile) remoteFolderOperationResult.getData().get(0);
saveFolderInDB();

if (encrypted) {
final OCFile folder = getStorageManager().getFileByDecryptedRemotePath(remotePath);

final RemoteOperationResult remoteOperationResult =
new ToggleEncryptionRemoteOperation(folder.getLocalId(),
remotePath,
true)
.execute(client);

if (remoteOperationResult.isSuccess()) {
folder.setEncrypted(true);
getStorageManager().saveFile(folder);
}
}
} else {
Log_OC.e(TAG, remotePath + " hasn't been created");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public class OperationsService extends Service {
public static final String EXTRA_ACCOUNT = "ACCOUNT";
public static final String EXTRA_SERVER_URL = "SERVER_URL";
public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
public static final String EXTRA_ENCRYPTED = "ENCRYPTED";
public static final String EXTRA_NEWNAME = "NEWNAME";
public static final String EXTRA_REMOVE_ONLY_LOCAL = "REMOVE_LOCAL_COPY";
public static final String EXTRA_SYNC_FILE_CONTENTS = "SYNC_FILE_CONTENTS";
Expand Down Expand Up @@ -687,7 +688,9 @@ private Pair<Target, RemoteOperation> newOperation(Intent operationIntent) {

case ACTION_CREATE_FOLDER:
remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
boolean encrypted = operationIntent.getBooleanExtra(EXTRA_ENCRYPTED, false);
operation = new CreateFolderOperation(remotePath,
encrypted,
user,
getApplicationContext(),
fileDataStorageManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ public int getItemCount() {

@Nullable
public OCFile getItem(int position) {
if (position == -1) {
return null;
}

int newPosition = position;

if (shouldShowHeader() && position > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList
@JvmField
@Inject
var keyboardUtils: KeyboardUtils? = null
private var mParentFolder: OCFile? = null
private var parentFolder: OCFile? = null
private var positiveButton: MaterialButton? = null
private var encrypted = false

private lateinit var binding: EditBoxDialogBinding

Expand Down Expand Up @@ -93,7 +94,8 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList

@Suppress("EmptyFunctionBlock")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
mParentFolder = arguments?.getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java)
parentFolder = arguments?.getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java)
encrypted = arguments?.getBoolean(ARG_ENCRYPTED) ?: false

// Inflate the layout for the dialog
val inflater = requireActivity().layoutInflater
Expand Down Expand Up @@ -177,26 +179,32 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList
DisplayUtils.showSnackMessage(requireActivity(), R.string.filename_forbidden_charaters_from_server)
return
}
val path = mParentFolder!!.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR
(requireActivity() as ComponentsGetter).fileOperationsHelper.createFolder(path)
val path = parentFolder!!.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR
(requireActivity() as ComponentsGetter).fileOperationsHelper.createFolder(path, encrypted)
}
}

companion object {
private const val ARG_PARENT_FOLDER = "PARENT_FOLDER"
private const val ARG_ENCRYPTED = "ENCRYPTED"
const val CREATE_FOLDER_FRAGMENT = "CREATE_FOLDER_FRAGMENT"

@JvmStatic
fun newInstance(parentFolder: OCFile?): CreateFolderDialogFragment {
return newInstance(parentFolder, false)
}
/**
* Public factory method to create new CreateFolderDialogFragment instances.
*
* @param parentFolder Folder to create
* @return Dialog ready to show.
*/
@JvmStatic
fun newInstance(parentFolder: OCFile?): CreateFolderDialogFragment {
fun newInstance(parentFolder: OCFile?, encrypted: Boolean): CreateFolderDialogFragment {
val frag = CreateFolderDialogFragment()
val args = Bundle()
args.putParcelable(ARG_PARENT_FOLDER, parentFolder)
args.putBoolean(ARG_ENCRYPTED, encrypted)
frag.arguments = args
return frag
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ package com.owncloud.android.ui.events
* Event for set folder as encrypted/decrypted
*/
class EncryptionEvent(
@JvmField
val localId: Long,
@JvmField
val remoteId: String,
@JvmField
val remotePath: String,
@JvmField
val shouldBeEncrypted: Boolean
)
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public interface OCFileListBottomSheetActions {
*/
void createFolder();

/**
* creates an encrypted folder within the actual folder
*/
void createEncryptedFolder();

/**
* offers a file upload with the Android OS file picker to the current folder.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,8 @@ protected void onCreate(Bundle savedInstanceState) {
binding.addToCloud.setText(getContext().getResources().getString(R.string.add_to_cloud,
themeUtils.getDefaultDisplayNameForRootFolder(getContext())));

OCCapability capability = fileActivity.getCapabilities();
if (capability != null &&
capability.getRichDocuments().isTrue() &&
OCCapability capability = fileActivity.getStorageManager().getCapability(user.getAccountName());
if (capability.getRichDocuments().isTrue() &&
capability.getRichDocumentsDirectEditing().isTrue() &&
capability.getRichDocumentsTemplatesAvailable().isTrue() &&
!file.isEncrypted()) {
Expand Down Expand Up @@ -149,6 +148,12 @@ protected void onCreate(Bundle savedInstanceState) {
binding.menuDirectCameraUpload.setVisibility(View.GONE);
}

if (capability.getEndToEndEncryption().isTrue() && OCFile.ROOT_PATH.equals(file.getRemotePath())) {
binding.menuEncryptedMkdir.setVisibility(View.VISIBLE);
} else {
binding.menuEncryptedMkdir.setVisibility(View.GONE);
}

// create rich workspace
if (editorUtils.isEditorAvailable(user,
MimeTypeUtil.MIMETYPE_TEXT_MARKDOWN) &&
Expand Down Expand Up @@ -183,6 +188,11 @@ private void setupClickListener() {
dismiss();
});

binding.menuEncryptedMkdir.setOnClickListener(v -> {
actions.createEncryptedFolder();
dismiss();
});

binding.menuUploadFromApp.setOnClickListener(v -> {
actions.uploadFromApp();
dismiss();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,14 @@ public void createFolder() {
.show(getActivity().getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
}

@Override
public void createEncryptedFolder() {
if (checkEncryptionIsSetup(null)) {
CreateFolderDialogFragment.newInstance(mFile, true)
.show(getActivity().getSupportFragmentManager(), DIALOG_CREATE_FOLDER);
}
}

@Override
public void uploadFromApp() {
Intent action = new Intent(Intent.ACTION_GET_CONTENT);
Expand Down Expand Up @@ -1132,10 +1140,11 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
int position = data.getIntExtra(SetupEncryptionDialogFragment.ARG_POSITION, -1);
OCFile file = mAdapter.getItem(position);

if (file != null) {
mContainerActivity.getFileOperationsHelper().toggleEncryption(file, true);
mAdapter.setEncryptionAttributeForItemID(file.getRemoteId(), true);
if (file == null) {
return;
}
mContainerActivity.getFileOperationsHelper().toggleEncryption(file, true);
mAdapter.setEncryptionAttributeForItemID(file.getRemoteId(), true);

// update state and view of this fragment
searchFragment = false;
Expand Down Expand Up @@ -1692,45 +1701,51 @@ protected RemoteOperation getSearchRemoteOperation(final User currentUser, final

@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEvent(EncryptionEvent event) {
if (checkEncryptionIsSetup(event.remoteId)) {
encryptFolder(event.localId, event.remoteId, event.remotePath, event.shouldBeEncrypted);
}
}

private boolean checkEncryptionIsSetup(@Nullable String remoteId) {
final User user = accountManager.getUser();

// check if keys are stored
String publicKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY);
String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY);

FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
OCFile file = storageManager.getFileByRemoteId(event.getRemoteId());

if (publicKey.isEmpty() || privateKey.isEmpty()) {
Log_OC.d(TAG, "no public key for " + user.getAccountName());

FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
int position = -1;
if (file != null) {
position = mAdapter.getItemPosition(file);
if (remoteId != null) {
OCFile file = storageManager.getFileByRemoteId(remoteId);
if (file != null) {
position = mAdapter.getItemPosition(file);
}
}
SetupEncryptionDialogFragment dialog = SetupEncryptionDialogFragment.newInstance(user, position);
dialog.setTargetFragment(this, SETUP_ENCRYPTION_REQUEST_CODE);
dialog.show(getParentFragmentManager(), SETUP_ENCRYPTION_DIALOG_TAG);

return false;
} else {
encryptFolder(file,
event.getLocalId(),
event.getRemoteId(),
event.getRemotePath(),
event.getShouldBeEncrypted(),
publicKey,
privateKey);
return true;
}
}

private void encryptFolder(OCFile folder,
long localId,
private void encryptFolder(long localId,
String remoteId,
String remotePath,
boolean shouldBeEncrypted,
String publicKey,
String privateKey) {
boolean shouldBeEncrypted) {
try {
User user = accountManager.getUser();
String publicKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY);
String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY);

FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
OCFile folder = storageManager.getFileByRemoteId(remoteId);

OwnCloudClient client = clientFactory.create(user);
RemoteOperationResult remoteOperationResult = new ToggleEncryptionRemoteOperation(localId,
remotePath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -971,11 +971,16 @@ public void removeFiles(Collection<OCFile> files, boolean onlyLocalCopy, boolean


public void createFolder(String remotePath) {
createFolder(remotePath, false);
}

public void createFolder(String remotePath, boolean encrypted) {
// Create Folder
Intent service = new Intent(fileActivity, OperationsService.class);
service.setAction(OperationsService.ACTION_CREATE_FOLDER);
service.putExtra(OperationsService.EXTRA_ACCOUNT, fileActivity.getAccount());
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, remotePath);
service.putExtra(OperationsService.EXTRA_ENCRYPTED, encrypted);
mWaitingForOpId = fileActivity.getOperationsServiceBinder().queueNewOperation(service);

fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
Expand Down

0 comments on commit 0263556

Please sign in to comment.