Skip to content

Commit

Permalink
E2EE related changes with test cases.
Browse files Browse the repository at this point in the history
  • Loading branch information
surinder-tsys committed Apr 23, 2024
1 parent f0e1e3b commit af5447d
Show file tree
Hide file tree
Showing 16 changed files with 2,648 additions and 1,998 deletions.
152 changes: 152 additions & 0 deletions app/src/androidTest/java/com/nmc/android/FileMenuFilterIT.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Nextcloud Android client application
*
* @author Álvaro Brey Vilas
* Copyright (C) 2022 Álvaro Brey Vilas
* Copyright (C) 2022 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.nmc.android

import androidx.test.core.app.launchActivity
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.nextcloud.client.account.User
import com.nextcloud.client.jobs.download.FileDownloadWorker
import com.nextcloud.client.jobs.upload.FileUploadHelper
import com.nextcloud.test.TestActivity
import com.nextcloud.utils.EditorUtils
import com.owncloud.android.AbstractIT
import com.owncloud.android.R
import com.owncloud.android.datamodel.ArbitraryDataProvider
import com.owncloud.android.datamodel.FileDataStorageManager
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.files.FileMenuFilter
import com.owncloud.android.lib.resources.status.CapabilityBooleanType
import com.owncloud.android.lib.resources.status.OCCapability
import com.owncloud.android.services.OperationsService
import com.owncloud.android.ui.activity.ComponentsGetter
import com.owncloud.android.utils.MimeType
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.security.SecureRandom

@RunWith(AndroidJUnit4::class)
class FileMenuFilterIT : AbstractIT() {

@MockK
private lateinit var mockComponentsGetter: ComponentsGetter

@MockK
private lateinit var mockStorageManager: FileDataStorageManager

@MockK
private lateinit var mockFileUploaderBinder: FileUploadHelper

@MockK
private lateinit var mockOperationsServiceBinder: OperationsService.OperationsServiceBinder

@MockK
private lateinit var mockFileDownloadProgressListener: FileDownloadWorker.FileDownloadProgressListener

@MockK
private lateinit var mockArbitraryDataProvider: ArbitraryDataProvider

private lateinit var editorUtils: EditorUtils

@Before
fun setup() {
MockKAnnotations.init(this)
every { mockFileUploaderBinder.isUploading(any(), any()) } returns false
every { mockComponentsGetter.fileUploaderHelper } returns mockFileUploaderBinder
every { mockFileDownloadProgressListener.isDownloading(any(), any()) } returns false
every { mockComponentsGetter.fileDownloadProgressListener } returns mockFileDownloadProgressListener
every { mockOperationsServiceBinder.isSynchronizing(any(), any()) } returns false
every { mockComponentsGetter.operationsServiceBinder } returns mockOperationsServiceBinder
every { mockStorageManager.getFileById(any()) } returns OCFile("/")
every { mockStorageManager.getFolderContent(any(), any()) } returns ArrayList<OCFile>()
every { mockArbitraryDataProvider.getValue(any<User>(), any()) } returns ""
editorUtils = EditorUtils(mockArbitraryDataProvider)
}

@Test
fun hide_shareAndFavouriteMenu_encryptedFolder() {
val capability = OCCapability().apply {
endToEndEncryption = CapabilityBooleanType.TRUE
}

val encryptedFolder = OCFile("/encryptedFolder/").apply {
isEncrypted = true
mimeType = MimeType.DIRECTORY
fileLength = SecureRandom().nextLong()
}

configureCapability(capability)

launchActivity<TestActivity>().use {
it.onActivity { activity ->
val filterFactory =
FileMenuFilter.Factory(mockStorageManager, activity, editorUtils)

val sut = filterFactory.newInstance(encryptedFolder, mockComponentsGetter, true, user)
val toHide = sut.getToHide(false)

// encrypted folder
assertTrue(toHide.contains(R.id.action_see_details))
assertTrue(toHide.contains(R.id.action_favorite))
assertTrue(toHide.contains(R.id.action_unset_favorite))
}
}
}

@Test
fun show_shareAndFavouriteMenu_normalFolder() {
val capability = OCCapability().apply {
endToEndEncryption = CapabilityBooleanType.TRUE
}

val normalFolder = OCFile("/folder/").apply {
mimeType = MimeType.DIRECTORY
fileLength = SecureRandom().nextLong()
}

configureCapability(capability)

launchActivity<TestActivity>().use {
it.onActivity { activity ->
val filterFactory =
FileMenuFilter.Factory(mockStorageManager, activity, editorUtils)

val sut = filterFactory.newInstance(normalFolder, mockComponentsGetter, true, user)
val toHide = sut.getToHide(false)

// normal folder
assertFalse(toHide.contains(R.id.action_see_details))
assertFalse(toHide.contains(R.id.action_favorite))
assertTrue(toHide.contains(R.id.action_unset_favorite))
}
}
}

private fun configureCapability(capability: OCCapability) {
every { mockStorageManager.getCapability(any<User>()) } returns capability
every { mockStorageManager.getCapability(any<String>()) } returns capability
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.nmc.android

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.intent.rule.IntentsTestRule
import androidx.test.espresso.matcher.ViewMatchers.withHint
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
import com.nextcloud.test.TestActivity
import com.owncloud.android.AbstractIT
import com.owncloud.android.ui.dialog.SetupEncryptionDialogFragment
import org.junit.Rule
import org.junit.Test
import com.owncloud.android.R

class SetupEncryptionDialogFragmentIT : AbstractIT() {

@get:Rule
val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false)

@Test
fun validatePassphraseInputHint() {
val activity = testActivityRule.launchActivity(null)

val sut = SetupEncryptionDialogFragment.newInstance(user, 0)

sut.show(activity.supportFragmentManager, "1")

val keyWords = arrayListOf(
"ability",
"able",
"about",
"above",
"absent",
"absorb",
"abstract",
"absurd",
"abuse",
"access",
"accident",
"account",
"accuse"
)

shortSleep()

UiThreadStatement.runOnUiThread {
sut.setMnemonic(keyWords)
sut.showMnemonicInfo()
}

waitForIdleSync()

onView(withId(R.id.encryption_passwordInput)).check(matches(withHint("Passphrase…")))
}
}
7 changes: 6 additions & 1 deletion app/src/main/java/com/owncloud/android/datamodel/OCFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -620,14 +620,19 @@ public boolean isHidden() {
}

/**
* The unique fileId for the file within the instance This only works if we have 12 digits for instanceId RemoteId
* is a combination of localId + instanceId If a file has remoteId: 4174305739oc97a8ddfc96, in this 4174305739 is
* localId & oc97a8ddfc96 is instanceId which is of 12 digits
*
* unique fileId for the file within the instance
*/
@SuppressFBWarnings("STT")
public long getLocalId() {
if (localId > 0) {
return localId;
} else if (remoteId != null && remoteId.length() > 8) {
return Long.parseLong(remoteId.substring(0, 8).replaceAll("^0*", ""));
//NMC Customization --> for long remote id's
return Long.parseLong(remoteId.substring(0, remoteId.length() - 12).replaceAll("^0*", ""));
} else {
return -1;
}
Expand Down
20 changes: 12 additions & 8 deletions app/src/main/java/com/owncloud/android/files/FileMenuFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ private List<Integer> filter(boolean inSingleFileFragment) {


private void filterShareFile(List<Integer> toHide, OCCapability capability) {
if (!isSingleSelection() || containsEncryptedFile() || hasEncryptedParent() ||
if (!isSingleSelection() || containsEncryptedFile() || hasEncryptedParent() || containsEncryptedFolder() ||
(!isShareViaLinkAllowed() && !isShareWithUsersAllowed()) ||
!isShareApiEnabled(capability) || !files.iterator().next().canReshare()) {
toHide.add(R.id.action_send_share_file);
Expand All @@ -191,19 +191,21 @@ private void filterSendFiles(List<Integer> toHide, boolean inSingleFileFragment)
}

private void filterDetails(Collection<Integer> toHide) {
if (!isSingleSelection()) {
if (!isSingleSelection() || containsEncryptedFolder() || containsEncryptedFile()) {
toHide.add(R.id.action_see_details);
}
}

private void filterFavorite(List<Integer> toHide, boolean synchronizing) {
if (files.isEmpty() || synchronizing || allFavorites()) {
if (files.isEmpty() || synchronizing || allFavorites() || containsEncryptedFile()
|| containsEncryptedFolder()) {
toHide.add(R.id.action_favorite);
}
}

private void filterUnfavorite(List<Integer> toHide, boolean synchronizing) {
if (files.isEmpty() || synchronizing || allNotFavorites()) {
if (files.isEmpty() || synchronizing || allNotFavorites() || containsEncryptedFile()
|| containsEncryptedFolder()) {
toHide.add(R.id.action_unset_favorite);
}
}
Expand Down Expand Up @@ -289,8 +291,8 @@ private boolean isRichDocumentEditingSupported(OCCapability capability, String m
}

private void filterSync(List<Integer> toHide, boolean synchronizing) {
if (files.isEmpty() || (!anyFileDown() && !containsFolder()) || synchronizing || containsEncryptedFile()
|| containsEncryptedFolder()) {
//NMC Customization --> show sync option for e2ee folder
if (files.isEmpty() || (!anyFileDown() && !containsFolder()) || synchronizing) {
toHide.add(R.id.action_sync_file);
}
}
Expand Down Expand Up @@ -332,8 +334,10 @@ private void filterSelectAll(List<Integer> toHide, boolean inSingleFileFragment)
}

private void filterRemove(List<Integer> toHide, boolean synchronizing) {
if (files.isEmpty() || synchronizing || containsLockedFile()
|| containsEncryptedFolder() || isFolderAndContainsEncryptedFile()) {
if ((files.isEmpty() || synchronizing || containsLockedFile()
|| containsEncryptedFolder() || isFolderAndContainsEncryptedFile())
//show delete option for encrypted sub-folder
&& !hasEncryptedParent()) {
toHide.add(R.id.action_remove_file);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ open class FolderPickerActivity :
private var mSyncBroadcastReceiver: SyncBroadcastReceiver? = null
private var mSyncInProgress = false
private var mSearchOnlyFolders = false
private var mShowOnlyFolder = false
private var mHideEncryptedFolder = false
var isDoNotEnterEncryptedFolder = false
private set

Expand Down Expand Up @@ -113,6 +115,9 @@ open class FolderPickerActivity :
}

private fun setupAction() {
mShowOnlyFolder = intent.getBooleanExtra(EXTRA_SHOW_ONLY_FOLDER, false)
mHideEncryptedFolder = intent.getBooleanExtra(EXTRA_HIDE_ENCRYPTED_FOLDER, false)

action = intent.getStringExtra(EXTRA_ACTION)

if (action != null && action == CHOOSE_LOCATION) {
Expand Down Expand Up @@ -358,7 +363,7 @@ open class FolderPickerActivity :
}

private fun refreshListOfFilesFragment(fromSearch: Boolean) {
listOfFilesFragment?.listDirectory(false, fromSearch)
listOfFilesFragment?.listDirectoryFolder(false, fromSearch, mShowOnlyFolder, mHideEncryptedFolder)
}

fun browseToRoot() {
Expand Down Expand Up @@ -660,6 +665,12 @@ open class FolderPickerActivity :
@JvmField
val EXTRA_ACTION = FolderPickerActivity::class.java.canonicalName?.plus(".EXTRA_ACTION")

@JvmField
val EXTRA_SHOW_ONLY_FOLDER = FolderPickerActivity::class.java.canonicalName?.plus(".EXTRA_SHOW_ONLY_FOLDER")

@JvmField
val EXTRA_HIDE_ENCRYPTED_FOLDER = FolderPickerActivity::class.java.canonicalName?.plus(".EXTRA_HIDE_ENCRYPTED_FOLDER")

const val MOVE_OR_COPY = "MOVE_OR_COPY"
const val CHOOSE_LOCATION = "CHOOSE_LOCATION"
private val TAG = FolderPickerActivity::class.java.simpleName
Expand Down
Loading

0 comments on commit af5447d

Please sign in to comment.