Skip to content

Commit

Permalink
Release 3.1.0
Browse files Browse the repository at this point in the history
• Support other apps sharing data with Cryptool.
• Implement user feedback.
• Fix stability issues.
  • Loading branch information
nfdz committed Feb 11, 2023
1 parent 6e9bf99 commit 4899e32
Show file tree
Hide file tree
Showing 46 changed files with 742 additions and 234 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package io.github.nfdz.cryptool.shared.message.repository

import io.github.nfdz.cryptool.shared.core.realm.FakeRealmGateway
import io.github.nfdz.cryptool.shared.encryption.entity.AlgorithmVersion
import io.github.nfdz.cryptool.shared.encryption.entity.MessageSource
import io.github.nfdz.cryptool.shared.encryption.entity.serialize
import io.github.nfdz.cryptool.shared.encryption.repository.realm.EncryptionRealm
import io.github.nfdz.cryptool.shared.message.entity.Message
import io.github.nfdz.cryptool.shared.message.entity.MessageOwnership
import io.github.nfdz.cryptool.shared.message.repository.realm.MessageRealm
import io.realm.kotlin.ext.query
import junit.framework.TestCase.assertEquals
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
import org.junit.Test

class MessageReceiverTest {

private val encryptionRealmA = EncryptionRealm().also { new ->
new.id = "encryptionId-A"
new.name = "Encryption A"
new.password = "testAA"
new.algorithm = AlgorithmVersion.V2.name
new.source = MessageSource.Manual.serialize()
}
private val messageA = Message(
id = "A",
encryptionId = "encryptionId-A",
message = "Lorem ipsum dolor A",
encryptedMessage =
"LD8azzqjc-e8C90bJ8Ut2bYa7WU.1QVQGS10pFb-LndU.128.idB9lucOGxHPLLusE_h0iumSadSum1AqzZ3fJQfCjl4OvkS-uWMSmfYb9HhAdkOeKvGP5p4vUQ",
timestampInMillis = 100,
isFavorite = false,
ownership = MessageOwnership.OTHER,
)
private lateinit var realm: FakeRealmGateway

@Before
fun beforeTest() {
realm = FakeRealmGateway()
}

@After
fun afterTest() {
realm.tearDownTest()
}

@Test(expected = java.util.NoSuchElementException::class)
fun testReceiveWithInvalidEncryption() = runTest {
val instance = MessageReceiverImpl(realm)

instance.receive(encryptionId = "Invalid", encryptedMessage = messageA.encryptedMessage, isRead = false)
}

@Test(expected = java.lang.IllegalStateException::class)
fun testReceiveWithInvalidMessage() = runTest {
realm.instance.write {
copyToRealm(encryptionRealmA)
}
val instance = MessageReceiverImpl(realm)

instance.receive(encryptionId = messageA.encryptionId, encryptedMessage = "Invalid", isRead = false)
}

@Test
fun testReceive() = runTest {
realm.instance.write {
copyToRealm(encryptionRealmA)
}
val instance = MessageReceiverImpl(realm)

instance.receive(
encryptionId = messageA.encryptionId,
encryptedMessage = messageA.encryptedMessage,
isRead = false,
)

val stored = realm.instance.query<MessageRealm>().find()
assertEquals(1, stored.size)
val storedMessage = stored.first().toEntity()
assertEquals(MessageOwnership.OTHER, storedMessage.ownership)
assertEquals(messageA.message, storedMessage.message)
assertEquals(messageA.encryptedMessage, storedMessage.encryptedMessage)
val storedEncryptions = realm.instance.query<EncryptionRealm>().find()
assertEquals(1, storedEncryptions.size)
val storedEncryption = storedEncryptions.first().toEntity()
assertEquals(1, storedEncryption.unreadMessagesCount)
assertEquals("${encryptionRealmA.name}: ${messageA.encryptedMessage}", storedEncryption.lastMessage)
}

@Test
fun testReceive2() = runTest {
realm.instance.write {
copyToRealm(encryptionRealmA)
}
val instance = MessageReceiverImpl(realm)

instance.receive(
encryption = encryptionRealmA.toEntity(),
encryptedMessage = messageA.encryptedMessage,
timestampInMillis = messageA.timestampInMillis,
isRead = false,
)

val stored = realm.instance.query<MessageRealm>().find()
assertEquals(1, stored.size)
val storedMessage = stored.first().toEntity()
assertEquals(MessageOwnership.OTHER, storedMessage.ownership)
assertEquals(messageA.message, storedMessage.message)
assertEquals(messageA.encryptedMessage, storedMessage.encryptedMessage)
val storedEncryptions = realm.instance.query<EncryptionRealm>().find()
assertEquals(1, storedEncryptions.size)
val storedEncryption = storedEncryptions.first().toEntity()
assertEquals(1, storedEncryption.unreadMessagesCount)
assertEquals("${encryptionRealmA.name}: ${messageA.encryptedMessage}", storedEncryption.lastMessage)
assertEquals(messageA.timestampInMillis, storedEncryption.lastMessageTimestamp)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,40 +125,6 @@ class MessageRepositoryTest {
assertEquals(listOf(messageA), content)
}

@Test(expected = java.util.NoSuchElementException::class)
fun testReceiveMessageWithInvalidEncryption() = runTest {
val instance = createInstance()

instance.receiveMessage(encryptionId = "Invalid", encryptedMessage = messageA.encryptedMessage)
}

@Test(expected = java.lang.IllegalStateException::class)
fun testReceiveMessageWithInvalidMessage() = runTest {
realm.instance.write {
copyToRealm(encryptionRealmA)
}
val instance = createInstance()

instance.receiveMessage(encryptionId = messageA.encryptionId, encryptedMessage = "Invalid")
}

@Test
fun testReceiveMessage() = runTest {
realm.instance.write {
copyToRealm(encryptionRealmA)
}
val instance = createInstance()

instance.receiveMessage(encryptionId = messageA.encryptionId, encryptedMessage = messageA.encryptedMessage)

val stored = realm.instance.query<MessageRealm>().find()
assertEquals(1, stored.size)
val storedMessage = stored.first().toEntity()
assertEquals(MessageOwnership.OTHER, storedMessage.ownership)
assertEquals(messageA.message, storedMessage.message)
assertEquals(messageA.encryptedMessage, storedMessage.encryptedMessage)
}

@Test(expected = java.util.NoSuchElementException::class)
fun testSendMessageWithInvalidEncryption() = runTest {
val instance = createInstance()
Expand Down
6 changes: 6 additions & 0 deletions androidApp/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
<action android:name="io.github.nfdz.cryptool.OPEN_FLOATING_BALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>

<service
Expand Down
23 changes: 18 additions & 5 deletions androidApp/src/main/java/io/github/nfdz/cryptool/AppActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import io.github.nfdz.cryptool.platform.shortcut.ShortcutAndroid
import io.github.nfdz.cryptool.service.ball.OverlayBallService
import io.github.nfdz.cryptool.service.tool.OverlayToolService
import io.github.nfdz.cryptool.shared.core.constant.AppUrl
import io.github.nfdz.cryptool.shared.encryption.viewModel.EncryptionAction
import io.github.nfdz.cryptool.shared.encryption.viewModel.EncryptionViewModel
import io.github.nfdz.cryptool.shared.gatekeeper.viewModel.GatekeeperAction
import io.github.nfdz.cryptool.shared.gatekeeper.viewModel.GatekeeperViewModel
import io.github.nfdz.cryptool.shared.platform.version.VersionProvider
Expand Down Expand Up @@ -45,28 +47,31 @@ class AppActivity : FragmentActivity(), CoroutineScope by CoroutineScope(Dispatc
private val versionProvider: VersionProvider by inject()
private val overlayPermission = OverlayPermissionImpl(this)
private val gatekeeperViewModel: GatekeeperViewModel by inject()
private val encryptionViewModel: EncryptionViewModel by inject()
private val msgEventReceiver = MessageEventBroadcast.createReceiver(get())
private val closeReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (context?.packageName != intent?.`package`) return
finishAffinity()
}
}
private var router: RouterApp? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
registerReceiver(closeReceiver, IntentFilter(closeAction))
MessageEventBroadcast.registerReceiver(this, msgEventReceiver)
WindowCompat.setDecorFitsSystemWindows(window, false)
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
if (!launchShortcut(intent)) {
handleShareInputIfNeeded(intent)
if (!launchShortcutIfNeeded(intent)) {
closeOverlay()
updateShortcut()
askThis()
setContent {
val navController = rememberNavController()
val router = RouterApp(navController, this, overlayPermission)
AppEntryPoint(this, router, navController, gatekeeperViewModel)
router = RouterApp(navController, this, overlayPermission)
AppEntryPoint(this, router!!, navController, gatekeeperViewModel)
}
}
}
Expand All @@ -79,10 +84,18 @@ class AppActivity : FragmentActivity(), CoroutineScope by CoroutineScope(Dispatc

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
launchShortcut(intent)
launchShortcutIfNeeded(intent)
handleShareInputIfNeeded(intent)
}

private fun launchShortcut(intent: Intent?): Boolean {
private fun handleShareInputIfNeeded(intent: Intent?) {
if (intent?.action != Intent.ACTION_SEND) return
val text = intent.getStringExtra(Intent.EXTRA_TEXT)?.ifEmpty { null } ?: return
encryptionViewModel.dispatch(EncryptionAction.AskAboutIncomingData(text))
router?.popBackStackToRoot()
}

private fun launchShortcutIfNeeded(intent: Intent?): Boolean {
if (packageName != intent?.`package`) return false
return if (ShortcutAndroid.shouldOpen(intent) && hasOverlayPermission()) {
OverlayBallService.start(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import io.github.nfdz.cryptool.shared.gatekeeper.repository.LegacyMigrationManag
import io.github.nfdz.cryptool.shared.gatekeeper.repository.LegacyMigrationManagerImpl
import io.github.nfdz.cryptool.shared.gatekeeper.viewModel.GatekeeperViewModel
import io.github.nfdz.cryptool.shared.gatekeeper.viewModel.GatekeeperViewModelImpl
import io.github.nfdz.cryptool.shared.message.repository.MessageReceiver
import io.github.nfdz.cryptool.shared.message.repository.MessageReceiverImpl
import io.github.nfdz.cryptool.shared.message.repository.MessageRepository
import io.github.nfdz.cryptool.shared.message.repository.MessageRepositoryImpl
import io.github.nfdz.cryptool.shared.message.viewModel.MessageViewModel
Expand Down Expand Up @@ -86,6 +88,7 @@ class CryptoolApp : Application() {
single<ExportData> { ExportDataImpl(get(), get(), get()) }
single<ImportData> { ImportDataImpl(get(), get(), get()) }
single<LocalizedError> { LocalizedErrorAndroid(applicationContext) }
single<MessageReceiver> { MessageReceiverImpl(get()) }

// Sender + Receivers
single<LanReceiver>(createdAtStart = true) { LanReceiverAndroid(get(), get(), get(), get(), get(), get()) }
Expand All @@ -108,8 +111,8 @@ class CryptoolApp : Application() {

// View Models
single<PasswordViewModel> { PasswordViewModelImpl(get()) }
single<EncryptionViewModel> { EncryptionViewModelImpl(get()) }
single<MessageViewModel> { MessageViewModelImpl(get(), get(), get()) }
single<EncryptionViewModel> { EncryptionViewModelImpl(get(), get(), get()) }
single<MessageViewModel> { MessageViewModelImpl(get(), get(), get(), get()) }
single<GatekeeperViewModel> { GatekeeperViewModelImpl(get(), get(), get(), get()) }

// Legacy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class RouterApp(
navController: NavHostController,
private val context: Context,
private val overlayPermission: OverlayPermission,
) : RouterBase(context, navController) {
) : RouterBase(navController) {

override val isOverlayMode: Boolean = false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class RouterOverlay(
navController: NavController,
private val context: Context,
private val minimizeOverlay: () -> Unit,
) : RouterBase(context, navController) {
) : RouterBase(navController) {

override val isOverlayMode: Boolean = true

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class MainScreenScreenshotTest {
encryptions = encryptions,
selectedEncryptionIds = setOf(),
initialized = true,
incomingData = null,
),
)
}
Expand All @@ -84,6 +85,7 @@ class MainScreenScreenshotTest {
encryptions = encryptions,
selectedEncryptionIds = setOf(),
initialized = true,
incomingData = null,
),
)
}
Expand All @@ -105,6 +107,7 @@ class MainScreenScreenshotTest {
encryptions = encryptions,
selectedEncryptionIds = selectedEncryptionIds,
initialized = true,
incomingData = null,
),
)
}
Expand All @@ -126,6 +129,7 @@ class MainScreenScreenshotTest {
encryptions = encryptions,
selectedEncryptionIds = selectedEncryptionIds,
initialized = true,
incomingData = null,
),
)
}
Expand All @@ -147,6 +151,7 @@ class MainScreenScreenshotTest {
encryptions = listOf(),
selectedEncryptionIds = setOf(),
initialized = true,
incomingData = null,
),
)
}
Expand All @@ -168,6 +173,7 @@ class MainScreenScreenshotTest {
encryptions = listOf(),
selectedEncryptionIds = setOf(),
initialized = true,
incomingData = null,
),
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.github.nfdz.cryptool.ui.main

import dev.testify.ComposableScreenshotRule
import dev.testify.annotation.ScreenshotInstrumentation
import io.github.nfdz.cryptool.shared.encryption.entity.AlgorithmVersion
import io.github.nfdz.cryptool.shared.encryption.entity.Encryption
import io.github.nfdz.cryptool.ui.DarkColorScheme
import io.github.nfdz.cryptool.ui.LightColorScheme
import io.github.nfdz.cryptool.ui.test.TestEntry
import org.junit.Rule
import org.junit.Test

class PickEncryptionDialogScreenshotTest {

@get:Rule
val rule = ComposableScreenshotRule()

private val incomingData =
"-99Vkg91QTKxpapuXQjqwJ5Mw.fDcHFT5r2nF42S0nq28PQQ.128.rbbgZVnc9f5hE7KHaL_t_pMgmulmWLYl9HrCqb8IhdnasIUmA"
private val encryptions = listOf(
Encryption("", "Conversation 1", "", AlgorithmVersion.V2, null, false, 0, "", 0L),
Encryption("", "Conversation 2", "", AlgorithmVersion.V2, null, false, 0, "", 0L),
Encryption("", "Conversation 3", "", AlgorithmVersion.V2, null, false, 0, "", 0L),
)

@ScreenshotInstrumentation
@Test
fun light() {
rule.setCompose {
TestEntry(colorScheme = LightColorScheme) {
PickEncryptionDialogContent(incomingData, encryptions) {}
}
}.assertSame()
}

@ScreenshotInstrumentation
@Test
fun dark() {
rule.setCompose {
TestEntry(colorScheme = DarkColorScheme) {
PickEncryptionDialogContent(incomingData, encryptions) {}
}
}.assertSame()
}
}
Loading

0 comments on commit 4899e32

Please sign in to comment.