Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,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 @@ -106,7 +121,7 @@ protected RemoteOperationResult run(OwnCloudClient client) {
}
return new RemoteOperationResult(new IllegalStateException("E2E not supported"));
} else {
return normalCreate(client);
return normalCreate(client, encrypted);
}
}

Expand Down Expand Up @@ -490,7 +505,7 @@ private String createRandomFileName(DecryptedFolderMetadataFileV1 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 @@ -499,6 +514,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 @@ -85,6 +85,7 @@ public class OperationsService extends Service {
public static final String EXTRA_POST_DIALOG_EVENT = "EXTRA_POST_DIALOG_EVENT";
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 @@ -708,7 +709,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 @@ -323,7 +323,7 @@ open class FolderPickerActivity :
val itemId = item.itemId

if (itemId == R.id.action_create_dir) {
val dialog = CreateFolderDialogFragment.newInstance(currentFolder)
val dialog = CreateFolderDialogFragment.newInstance(currentFolder, false)
dialog.show(supportFragmentManager, CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT)
} else if (itemId == android.R.id.home) {
val currentDir = currentFolder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();

if (itemId == R.id.action_create_dir) {
CreateFolderDialogFragment dialog = CreateFolderDialogFragment.newInstance(mFile);
CreateFolderDialogFragment dialog = CreateFolderDialogFragment.newInstance(mFile, false);
dialog.show(getSupportFragmentManager(), CreateFolderDialogFragment.CREATE_FOLDER_FRAGMENT);
} else if (itemId == android.R.id.home) {
if (mParents.size() > SINGLE_PARENT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.lib.resources.status.OCCapability
import com.owncloud.android.services.OperationsService.EXTRA_ENCRYPTED
import com.owncloud.android.ui.activity.ComponentsGetter
import com.owncloud.android.ui.activity.FileDisplayActivity
import com.owncloud.android.utils.DisplayUtils
Expand Down Expand Up @@ -69,6 +70,7 @@ class CreateFolderDialogFragment :
lateinit var accountProvider: CurrentAccountProvider

private var parentFolder: OCFile? = null
private var encrypted = false
private var positiveButton: MaterialButton? = null

private lateinit var binding: EditBoxDialogBinding
Expand Down Expand Up @@ -104,6 +106,7 @@ class CreateFolderDialogFragment :
@Suppress("EmptyFunctionBlock")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
parentFolder = arguments?.getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java)
encrypted = arguments?.getBoolean(EXTRA_ENCRYPTED, false) ?: false

val inflater = requireActivity().layoutInflater
binding = EditBoxDialogBinding.inflate(inflater, null, false)
Expand Down Expand Up @@ -190,7 +193,7 @@ class CreateFolderDialogFragment :
val path = parentFolder?.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR
connectivityService.isNetworkAndServerAvailable { result ->
if (result) {
typedActivity<ComponentsGetter>()?.fileOperationsHelper?.createFolder(path)
typedActivity<ComponentsGetter>()?.fileOperationsHelper?.createFolder(path, encrypted)
} else {
Log_OC.d(TAG, "Network not available, creating offline operation")
fileDataStorageManager.addCreateFolderOfflineOperation(
Expand All @@ -217,9 +220,10 @@ class CreateFolderDialogFragment :
* @return Dialog ready to show.
*/
@JvmStatic
fun newInstance(parentFolder: OCFile?): CreateFolderDialogFragment {
fun newInstance(parentFolder: OCFile?, encrypted: Boolean): CreateFolderDialogFragment {
val bundle = Bundle().apply {
putParcelable(ARG_PARENT_FOLDER, parentFolder)
putBoolean(EXTRA_ENCRYPTED, encrypted)
}

return CreateFolderDialogFragment().apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@
import com.owncloud.android.lib.common.Creator;

/**
* Actions interface to be implemented by any class that makes use of
* {@link com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog}.
* Actions interface to be implemented by any class that makes use of {@link com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog}.
*/
public interface OCFileListBottomSheetActions {
/**
* creates a folder within the actual folder.
*/
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 @@ -513,10 +513,18 @@ public void registerFabListener() {

@Override
public void createFolder() {
CreateFolderDialogFragment.newInstance(mFile)
CreateFolderDialogFragment.newInstance(mFile, false)
.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 @@ -1259,10 +1267,17 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
int position = data.getIntExtra(SetupEncryptionDialogFragment.ARG_POSITION, -1);
OCFile file = mAdapter.getItem(position);

// TODO needed?
if (file != null) {
mContainerActivity.getFileOperationsHelper().toggleEncryption(file, true);
mAdapter.setEncryptionAttributeForItemID(file.getRemoteId(), true);
}

if (file == null) {
return;
}

encryptFolder(file.getLocalId(), file.getRemoteId(), file.getRemotePath(), true);

// update state and view of this fragment
searchFragment = false;
Expand Down Expand Up @@ -1883,56 +1898,62 @@ protected RemoteOperation getSearchRemoteOperation(final User currentUser, final

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(EncryptionEvent event) {
new Thread(() -> {{
final User user = accountManager.getUser();
if (checkEncryptionIsSetup(event.getRemoteId())) {
encryptFolder(event.getLocalId(),
event.getRemoteId(),
event.getRemotePath(),
event.getShouldBeEncrypted());
}
}

// check if keys are stored
String publicKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY);
String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY);
private boolean checkEncryptionIsSetup(@Nullable String remoteId) {
final User user = accountManager.getUser();

FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
OCFile file = storageManager.getFileByRemoteId(event.getRemoteId());
// check if keys are stored
String publicKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PUBLIC_KEY);
String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY);

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

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

int position;
int position;
if (remoteId != null) {
OCFile file = storageManager.getFileByRemoteId(remoteId);
if (file != null) {
position = mAdapter.getItemPosition(file);
} else {
position = -1;
}

requireActivity().runOnUiThread(() -> {
SetupEncryptionDialogFragment dialog = SetupEncryptionDialogFragment.newInstance(user, position);
dialog.setTargetFragment(OCFileListFragment.this, SETUP_ENCRYPTION_REQUEST_CODE);
dialog.show(getParentFragmentManager(), SETUP_ENCRYPTION_DIALOG_TAG);
});
} else {
// TODO E2E: if encryption fails, to not set it as encrypted!
encryptFolder(file,
event.getLocalId(),
event.getRemoteId(),
event.getRemotePath(),
event.getShouldBeEncrypted(),
publicKey,
privateKey,
storageManager);
position = -1;
}
}}).start();

requireActivity().runOnUiThread(() -> {
SetupEncryptionDialogFragment dialog = SetupEncryptionDialogFragment.newInstance(user, position);
dialog.setTargetFragment(OCFileListFragment.this, SETUP_ENCRYPTION_REQUEST_CODE);
dialog.show(getParentFragmentManager(), SETUP_ENCRYPTION_DIALOG_TAG);
});
return false;
} else {
return true;
}
}

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

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

Log_OC.d(TAG, "encrypt folder " + folder.getRemoteId());
User user = accountManager.getUser();
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 @@ -970,6 +970,10 @@ public void removeFiles(Collection<OCFile> files, boolean onlyLocalCopy, boolean
for (OCFile file : files) {
removeFile(file, onlyLocalCopy, inBackground);
}

if (!inBackground) {
fileActivity.showLoadingDialog(fileActivity.getString(R.string.wait_a_moment));
}
}

public void removeFile(OCFile file, boolean onlyLocalCopy, boolean inBackground) {
Expand All @@ -983,11 +987,16 @@ public void removeFile(OCFile file, boolean onlyLocalCopy, boolean inBackground)
}

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
2 changes: 2 additions & 0 deletions app/src/main/res/drawable/ic_action_create_dir.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@
<path
android:fillColor="@android:color/white"
android:pathData="M560,640L640,640L640,560L720,560L720,480L640,480L640,400L560,400L560,480L480,480L480,560L560,560L560,640ZM160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L400,160L480,240L800,240Q833,240 856.5,263.5Q880,287 880,320L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM160,720L800,720Q800,720 800,720Q800,720 800,720L800,320Q800,320 800,320Q800,320 800,320L447,320L367,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720ZM160,720Q160,720 160,720Q160,720 160,720L160,240Q160,240 160,240Q160,240 160,240L160,240L160,320L160,320Q160,320 160,320Q160,320 160,320L160,720Q160,720 160,720Q160,720 160,720Z" />


</vector>
21 changes: 21 additions & 0 deletions app/src/main/res/drawable/ic_action_create_encrypted_dir.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!--
~ Nextcloud - Android Client
~
~ SPDX-FileCopyrightText: 2018-2025 Google LLC
~ SPDX-License-Identifier: Apache-2.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="960"
android:viewportHeight="960">

<path
android:fillColor="@android:color/white"
android:pathData="m 160,800 c -22,0 -40.83333,-7.83333 -56.5,-23.5 C 87.833333,760.83333 80,742 80,720 V 240 c 0,-22 7.833333,-40.83333 23.5,-56.5 C 119.16667,167.83333 138,160 160,160 h 240 l 80,80 h 320 c 22,0 40.83333,7.83333 56.5,23.5 15.66667,15.66667 23.5,34.5 23.5,56.5 v 400 c 0,22 -7.83333,40.83333 -23.5,56.5 C 840.83333,792.16667 822,800 800,800 Z m 0,-80 h 640 v 0 0 -400 0 0 H 447 L 367,240 H 160 v 0 0 z m 0,0 v 0 0 -480 0 0 0 80 0 0 0 z" />

<path
android:fillColor="@android:color/white"
android:pathData="m 411.05968,600.05968 h 51.70524 v -51.70523 h 34.47016 v 51.70523 h 51.70523 v 34.47016 h -51.70523 v 51.70523 h -34.47016 v -51.70523 h -51.70524 z m -17.23507,-51.70523 c -28.73088,0 -53.13575,-10.04805 -73.24908,-30.16139 -20.11334,-20.11334 -30.16139,-44.51821 -30.16139,-73.24908 0,-28.73087 10.04805,-53.13574 30.16139,-73.24909 20.11333,-20.11333 44.5182,-30.16138 73.24908,-30.16138 18.95859,0 36.33154,4.73965 52.1361,14.21894 15.80457,9.4793 28.30002,21.97472 37.48631,37.48629 H 669.58586 V 496.64921 H 635.1157 v 51.70524 H 531.70523 v -51.70524 h -48.25821 c -9.18629,15.51157 -21.68174,28.007 -37.48631,37.4863 -15.80456,9.47929 -33.17751,14.21894 -52.1361,14.21894 z m 0,-34.47016 c 18.95859,0 34.17716,-5.80823 45.67295,-17.45914 11.4958,-11.61643 18.38983,-23.04329 20.6821,-34.24609 h 105.99573 v 51.70523 h 34.47016 V 462.17906 H 635.1157 V 427.7089 H 460.17966 c -2.29227,-11.2028 -9.1863,-22.61242 -20.6821,-34.26334 -11.49579,-11.63367 -26.71436,-17.44189 -45.67295,-17.44189 -18.95859,0 -35.19404,6.75614 -48.68909,20.25121 -13.49507,13.49506 -20.25122,29.73051 -20.25122,48.6891 0,18.95859 6.75615,35.19403 20.25122,48.6891 13.49505,13.49506 29.7305,20.25121 48.68909,20.25121 z m 0,-34.47015 c -9.47929,0 -17.59702,-3.37808 -24.33593,-10.117 -6.75616,-6.75615 -10.13422,-14.87387 -10.13422,-24.35316 0,-9.47929 3.37806,-17.59702 10.13422,-24.35316 6.73891,-6.73892 14.85664,-10.117 24.33593,-10.117 9.4793,0 17.59701,3.37808 24.35317,10.117 6.73891,6.75614 10.11699,14.87387 10.11699,24.35316 0,9.47929 -3.37808,17.59701 -10.11699,24.35316 -6.75616,6.73892 -14.87387,10.117 -24.35317,10.117 z" />
</vector>
Loading
Loading