Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Android create banana split #2362

Open
wants to merge 59 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
6371708
started work with create bs
Dmitry-Borodin Feb 15, 2024
298d92e
create bs progress
Dmitry-Borodin Feb 15, 2024
6c7e7a5
restore flow camera icon work in progress
Dmitry-Borodin Feb 15, 2024
b925961
migrated flow row from depricated library to core compose. Added scan…
Dmitry-Borodin Feb 15, 2024
fdb40d5
implementing create BS layout
Dmitry-Borodin Feb 16, 2024
fd585b9
make numbers only keyboard
Dmitry-Borodin Feb 16, 2024
efe61d2
create bs layout work in progress
Dmitry-Borodin Feb 19, 2024
a993588
create bs layout work in progress 2
Dmitry-Borodin Feb 19, 2024
10d8b2e
create bs layout work in progress 2
Dmitry-Borodin Feb 19, 2024
ea62f25
banana split logic work started
Dmitry-Borodin Feb 19, 2024
04e266b
finilizing layout create BS
Dmitry-Borodin Feb 20, 2024
10f0683
Merge branch 'master' of github.com:paritytech/parity-signer into and…
Dmitry-Borodin Feb 20, 2024
b8fef34
working with BS export menu
Dmitry-Borodin Feb 20, 2024
e1a0ee5
export banana split passphrase manu added and bottom sheet clarificat…
Dmitry-Borodin Feb 20, 2024
d0241aa
ba menu strings
Dmitry-Borodin Feb 20, 2024
869e6d1
иы скуфеуbs create flow work in progress
Dmitry-Borodin Feb 21, 2024
a58d2d8
fixing create bs layout
Dmitry-Borodin Feb 21, 2024
c35efb8
bs_show_screens
Dmitry-Borodin Feb 21, 2024
80a8197
banana split export screens gluing together
Dmitry-Borodin Feb 21, 2024
13107fc
Merge branch 'master' of github.com:paritytech/parity-signer into and…
Dmitry-Borodin Feb 21, 2024
d374f96
passing arguments for create bs
Dmitry-Borodin Feb 22, 2024
bdbe8d6
working with BS repository
Dmitry-Borodin Feb 22, 2024
c1b7b1d
working on banana split
Dmitry-Borodin Feb 26, 2024
3efd536
Merge branch 'master' of github.com:paritytech/parity-signer into and…
Dmitry-Borodin Feb 26, 2024
1253378
work in progress create bs
Dmitry-Borodin Feb 27, 2024
47d7745
Merge branch 'master' of github.com:paritytech/parity-signer into and…
Dmitry-Borodin Feb 27, 2024
53e21a1
work in progress create bs 2
Dmitry-Borodin Feb 27, 2024
5805be1
integrating clean encrzpted storage into bs flow
Dmitry-Borodin Feb 27, 2024
916092c
implemented crypto storage for non auth data
Dmitry-Borodin Feb 28, 2024
8654863
created test siute for qr codes storage
Dmitry-Borodin Feb 28, 2024
03c6ca2
finished tested crzpto storage
Dmitry-Borodin Feb 28, 2024
f7211d4
integrated clear storage into existing repositories
Dmitry-Borodin Feb 29, 2024
fa7cfcc
banana split repo implementation
Dmitry-Borodin Mar 1, 2024
221d08a
Merge branch 'master' of github.com:paritytech/parity-signer into and…
Dmitry-Borodin Mar 1, 2024
1447503
wipe data will wipe bs as well now
Dmitry-Borodin Mar 1, 2024
1fa8ebc
saving bs create data is implemented
Dmitry-Borodin Mar 1, 2024
908db51
bs repository storage functions implementation
Dmitry-Borodin Mar 1, 2024
f7350dc
banana split remove logic implemented
Dmitry-Borodin Mar 4, 2024
11eb08e
implemented banana split password screen
Dmitry-Borodin Mar 4, 2024
ae02731
implemented start flow create bs
Dmitry-Borodin Mar 4, 2024
d63023f
fixed seedname state in keyset details so create bs would work
Dmitry-Borodin Mar 5, 2024
4c191f7
fixing create bs password now shown and repository threading
Dmitry-Borodin Mar 5, 2024
6a9acb3
fixing show password
Dmitry-Borodin Mar 6, 2024
b933534
added extra padding
Dmitry-Borodin Mar 6, 2024
e26a4da
Merge branch 'master' of github.com:paritytech/parity-signer into and…
Dmitry-Borodin Mar 6, 2024
34689c4
fixing remove bs threading
Dmitry-Borodin Mar 6, 2024
1d89447
create bs fixing updating passphrase updating
Dmitry-Borodin Mar 6, 2024
b8a4c65
updating create bs
Dmitry-Borodin Mar 6, 2024
f2704c4
handling shards state
Dmitry-Borodin Mar 6, 2024
fb5e82a
remove saving shards - we don't need to store them
Dmitry-Borodin Mar 7, 2024
e7d6ef0
Merge branch 'master' of github.com:paritytech/parity-signer into and…
Dmitry-Borodin Mar 10, 2024
73f2251
tested things - removed todos
Dmitry-Borodin Mar 10, 2024
e57c73d
added seed name comment here - would be useful
Dmitry-Borodin Mar 11, 2024
b632a29
added another todo to check out
Dmitry-Borodin Mar 11, 2024
292c6dd
fix for menu navigation is implemented
Dmitry-Borodin Mar 11, 2024
f5cc93c
tested fix
Dmitry-Borodin Mar 12, 2024
d3a211e
tested fix2
Dmitry-Borodin Mar 12, 2024
1c6bef9
passed entered seed name during recovery to camera so it will be reus…
Dmitry-Borodin Mar 14, 2024
2695be2
Merge branch 'master' into android-banana-split-create
Dmitry-Borodin Mar 15, 2024
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
3 changes: 1 addition & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ dependencies {
implementation "androidx.compose.material:material:$compose_libs_version"
implementation "androidx.compose.material:material-icons-extended:$compose_libs_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_libs_version"
implementation "com.google.accompanist:accompanist-flowlayout:$accompanist_version" //for flow-layout which is non-lazy grid
implementation "com.google.accompanist:accompanist-permissions:$accompanist_version"
implementation "androidx.datastore:datastore-preferences:1.0.0"
implementation "androidx.navigation:navigation-compose:2.7.7"
Expand All @@ -122,7 +121,7 @@ dependencies {
testImplementation "androidx.test:core:1.5.0"
testImplementation "androidx.test.ext:junit:1.1.5"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_libs_version"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.parity.signer.domain.storage

import io.parity.signer.dependencygraph.ServiceLocator
import io.parity.signer.ui.helpers.PreviewData
import io.parity.signer.uniffi.QrData
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Test


class ClearCryptedStorageTest {

private val storage = ClearCryptedStorage()

@Before
fun setUp() {
val context = ServiceLocator.appContext
storage.init(context)
}

@After
fun tearDown() {
}

@Test
fun savingQrCodes() {
val seedName = "testname"
val qrCodes = listOf(QrData.Regular(PreviewData.exampleQRData),
QrData.Regular(PreviewData.exampleQRData.asReversed()))

storage.saveBsQRCodes(seedName, qrCodes)
val recovered = storage.getBsQrCodes(seedName)

Assert.assertEquals(qrCodes.size, recovered!!.size)
Assert.assertEquals(qrCodes, recovered)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fun PublicKeyBottomSheetView(
) {
BottomSheetHeader(
title = name,
onCloseClicked = onClose
onClose = onClose
)
SignerDivider(sidePadding = 24.dp)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fun BottomSheetHeader(
title: String,
modifier: Modifier = Modifier,
subtitile: String? = null,
onCloseClicked: Callback?
onClose: Callback?
) {
Row(
modifier = modifier
Expand All @@ -46,9 +46,9 @@ fun BottomSheetHeader(
)
}
}
if (onCloseClicked != null) {
if (onClose != null) {
CloseIcon(
onCloseClicked = onCloseClicked,
onCloseClicked = onClose,
modifier = Modifier.padding(start = 16.dp)
)
}
Expand Down Expand Up @@ -86,11 +86,11 @@ fun BottomSheetSubtitle(
private fun PreviewHeaderWithClose() {
SignerNewTheme {
Column() {
BottomSheetHeader(title = "Title", onCloseClicked = {})
BottomSheetHeader(title = "Title", onClose = {})
Divider()
BottomSheetHeader(title = "Very very very very long title Very very very very long title") {}
Divider()
BottomSheetHeader(title = "Title", subtitile = "With subtitle", onCloseClicked = {})
BottomSheetHeader(title = "Title", subtitile = "With subtitle", onClose = {})
Divider()
BottomSheetSubtitle(R.string.subtitle_secret_recovery_phrase)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package io.parity.signer.components.base

import android.content.res.Configuration
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import io.parity.signer.R
import io.parity.signer.domain.Callback
import io.parity.signer.ui.theme.SignerNewTheme
import io.parity.signer.ui.theme.fill18
import io.parity.signer.ui.theme.fill6
import io.parity.signer.ui.theme.forcedFill30
import io.parity.signer.ui.theme.pink500



@Composable
fun ScanIconPlain(
onClick: Callback,
modifier: Modifier = Modifier,
) {
Box(
modifier = modifier
.size(32.dp)
.clip(CircleShape)
.clickable(onClick = onClick)
.background(MaterialTheme.colors.fill6),
contentAlignment = Alignment.Center,
) {
Image(
painter = painterResource(R.drawable.ic_qr_code_2),
contentDescription = stringResource(R.string.description_scan_icon),
colorFilter = ColorFilter.tint(MaterialTheme.colors.primary),
modifier = Modifier.size(20.dp)
)
}
}



@Preview(
name = "light", group = "themes", uiMode = Configuration.UI_MODE_NIGHT_NO,
showBackground = true, backgroundColor = 0xFFFFFFFF,
)
@Preview(
name = "dark", group = "themes", uiMode = Configuration.UI_MODE_NIGHT_YES,
showBackground = true, backgroundColor = 0xFF000000,
)
@Composable
private fun PreviewScanIcon() {
SignerNewTheme {
Column() {
ScanIconPlain(onClick = {})
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import io.parity.signer.domain.backend.UniffiInteractor
import io.parity.signer.components.networkicon.UnknownNetworkColorsGenerator
import io.parity.signer.domain.Authentication
import io.parity.signer.domain.NetworkExposedStateKeeper
import io.parity.signer.domain.storage.BananaSplitRepository
import io.parity.signer.domain.storage.ClearCryptedStorage
import io.parity.signer.domain.storage.DatabaseAssetsInteractor
import io.parity.signer.domain.storage.PreferencesRepository
import io.parity.signer.domain.storage.SeedRepository
Expand Down Expand Up @@ -34,6 +36,7 @@ object ServiceLocator {
val uniffiInteractor by lazy { UniffiInteractor(appContext) }

val seedStorage: SeedStorage = SeedStorage()
val clearCryptedStorage: ClearCryptedStorage = ClearCryptedStorage()
val preferencesRepository: PreferencesRepository by lazy {
PreferencesRepository(
appContext
Expand All @@ -42,7 +45,8 @@ object ServiceLocator {
val databaseAssetsInteractor by lazy {
DatabaseAssetsInteractor(
appContext,
seedStorage
seedStorage,
clearCryptedStorage,
)
}
val networkExposedStateKeeper by lazy {
Expand All @@ -57,10 +61,19 @@ object ServiceLocator {

class ActivityScope(val activity: FragmentActivity) {
val seedRepository: SeedRepository = SeedRepository(
storage = seedStorage,
seedStorage = seedStorage,
clearCryptedStorage = clearCryptedStorage,
authentication = authentication,
activity = activity,
uniffiInteractor = uniffiInteractor
uniffiInteractor = uniffiInteractor,
)

val bsRepository: BananaSplitRepository = BananaSplitRepository(
seedStorage = seedStorage,
clearCryptedStorage = clearCryptedStorage,
authentication = authentication,
activity = activity,
uniffiInteractor = uniffiInteractor,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object FeatureFlags {
FeatureOption.EXPORT_SECRET_KEY -> false //unused
FeatureOption.FAIL_DB_VERSION_CHECK -> false
FeatureOption.SKIP_USB_CHECK -> true

FeatureOption.CREATE_BANANA_SPLIT_ENABLED -> true
}
}

Expand All @@ -23,6 +23,7 @@ object FeatureFlags {

enum class FeatureOption {
FAIL_DB_VERSION_CHECK,
CREATE_BANANA_SPLIT_ENABLED,
SKIP_UNLOCK_FOR_DEVELOPMENT,
SKIP_ROOTED_CHECK_EMULATOR,
SKIP_USB_CHECK,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,32 @@ class UniffiInteractor(val appContext: Context) {
UniffiResult.Error(e)
}
}

suspend fun bsGeneratePassphrase(
shards: Int
): UniffiResult<String> =
withContext(Dispatchers.IO) {
try {
val result =
io.parity.signer.uniffi.bsGeneratePassphrase(shards.toUInt())
UniffiResult.Success(result)
} catch (e: ErrorDisplayed) {
UniffiResult.Error(e)
}
}

suspend fun generateBananaSplit(
secret: String, title: String, passphrase: String, totalShards: UInt, requiredShards: UInt
): UniffiResult<List<QrData>> =
withContext(Dispatchers.IO) {
try {
val transactionResult =
io.parity.signer.uniffi.bsEncrypt(secret, title, passphrase, totalShards, requiredShards)
UniffiResult.Success(transactionResult)
} catch (e: ErrorDisplayed) {
UniffiResult.Error(e)
}
}
}

sealed class UniffiResult<T> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package io.parity.signer.domain.storage

import androidx.fragment.app.FragmentActivity
import io.parity.signer.domain.AuthResult
import io.parity.signer.domain.Authentication
import io.parity.signer.domain.backend.OperationResult
import io.parity.signer.domain.backend.UniffiInteractor
import io.parity.signer.domain.backend.toOperationResult
import io.parity.signer.screens.scan.bananasplitcreate.BananaSplit
import io.parity.signer.uniffi.ErrorDisplayed
import io.parity.signer.uniffi.QrData
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext


class BananaSplitRepository(
private val seedStorage: SeedStorage,
private val clearCryptedStorage: ClearCryptedStorage,
private val authentication: Authentication,
private val activity: FragmentActivity,
private val uniffiInteractor: UniffiInteractor,
) {

suspend fun creaseBs(
seedName: String,
maxShards: Int,
passPhrase: String
): OperationResult<Unit, ErrorDisplayed> {

return when (val authResult = authentication.authenticate(activity)) {
AuthResult.AuthSuccess -> {
val phrase = seedStorage.getSeed(seedName, false)
val qrResults: OperationResult<List<QrData>, ErrorDisplayed> =
uniffiInteractor.generateBananaSplit(
secret = phrase,
title = seedName,
passphrase = passPhrase,
totalShards = maxShards.toUInt(),
requiredShards = BananaSplit.getMinShards(maxShards).toUInt()
).toOperationResult()
when (qrResults) {
is OperationResult.Err -> qrResults
is OperationResult.Ok -> {
//saving data
seedStorage.saveBsData(seedName, passPhrase)
clearCryptedStorage.saveBsQRCodes(seedName, qrResults.result)
OperationResult.Ok(Unit)
}
}
}

AuthResult.AuthError,
AuthResult.AuthFailed,
AuthResult.AuthUnavailable -> {
OperationResult.Err(ErrorDisplayed.Str("auth error - $authResult"))
}
}
}

fun getBsQrs(seedName: String): List<QrData>? {
return clearCryptedStorage.getBsQrCodes(seedName)
}

suspend fun removeBS(seedName: String): OperationResult<Unit, ErrorDisplayed> {
return when (val authResult = authentication.authenticate(activity)) {
AuthResult.AuthSuccess -> {
//removing bs data data
withContext(Dispatchers.IO) {
seedStorage.removeBSData(seedName)
clearCryptedStorage.removeQrCode(seedName)
}
OperationResult.Ok(Unit)
}

AuthResult.AuthError,
AuthResult.AuthFailed,
AuthResult.AuthUnavailable -> {
OperationResult.Err(ErrorDisplayed.Str("auth error - $authResult"))
}
}
}

suspend fun getBsPassword(seedName: String): OperationResult<String, ErrorDisplayed> {
return when (val authResult = authentication.authenticate(activity)) {
AuthResult.AuthSuccess -> {
val bsPassword = withContext(Dispatchers.IO) {
seedStorage.getBsPassword(seedName)
}
OperationResult.Ok(bsPassword)
}

AuthResult.AuthError,
AuthResult.AuthFailed,
AuthResult.AuthUnavailable -> {
OperationResult.Err(ErrorDisplayed.Str("auth error - $authResult"))
}
}
}
}


Loading
Loading