Skip to content

Commit 91d63b0

Browse files
committed
fix(flipcash): move register call pre-payment as intended
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent d284dbb commit 91d63b0

File tree

6 files changed

+50
-30
lines changed

6 files changed

+50
-30
lines changed

apps/flipcash/features/purchase/src/main/kotlin/com/flipcash/app/purchase/internal/PurchaseAccountViewModel.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import com.getcode.view.BaseViewModel2
2020
import com.getcode.view.LoadingSuccessState
2121
import dagger.hilt.android.lifecycle.HiltViewModel
2222
import kotlinx.coroutines.delay
23-
import kotlinx.coroutines.flow.distinctUntilChanged
2423
import kotlinx.coroutines.flow.filter
2524
import kotlinx.coroutines.flow.filterIsInstance
2625
import kotlinx.coroutines.flow.flatMapLatest
@@ -152,7 +151,7 @@ internal class PurchaseAccountViewModel @Inject constructor(
152151
}.filterIsInstance<IapPaymentEvent.OnSuccess>()
153152
.onEach {
154153
dispatchEvent(Event.OnCreatingChanged(true))
155-
authManager.registerAccount()
154+
authManager.presentCredentialStorage()
156155
.onSuccess {
157156
dispatchEvent(Event.OnCreatingChanged(creating = false, created = true))
158157
delay(2.seconds)

apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/AuthManager.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class AuthManager @Inject constructor(
7575
}
7676

7777
suspend fun createAccount(): Result<Unit> {
78-
return credentialManager.create()
78+
return credentialManager.createAccount()
7979
.onSuccess { entropy ->
8080
persistence.openDatabase(entropy)
8181
}.onFailure {
@@ -90,8 +90,8 @@ class AuthManager @Inject constructor(
9090
}.map { Unit }
9191
}
9292

93-
suspend fun registerAccount(): Result<Unit> {
94-
return credentialManager.registerCreatedAccount()
93+
suspend fun presentCredentialStorage(): Result<Unit> {
94+
return credentialManager.presentSaveOption()
9595
.onSuccess {
9696
accountController.getUserFlags().onSuccess { userManager.set(it) }
9797
}.onFailure {

apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/internal/credentials/PassphraseCredentialManager.kt

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.flipcash.app.auth.internal.credentials
22

33
import android.content.Context
44
import androidx.credentials.CreatePasswordRequest
5-
import androidx.credentials.Credential
65
import androidx.credentials.CredentialManager
76
import androidx.credentials.GetCredentialRequest
87
import androidx.credentials.GetPasswordOption
@@ -46,8 +45,9 @@ class PassphraseCredentialManager @Inject constructor(
4645
private val mnemonicManager: MnemonicManager,
4746
) {
4847
companion object {
49-
private val temporaryAccountKey = stringPreferencesKey("temporaryAccount")
50-
private fun seenAccessKeyKey(entropy: String) = booleanPreferencesKey("${entropy}_seenAccessKey")
48+
private val temporaryEntropyKey = stringPreferencesKey("temporaryEntropy")
49+
private val temporaryUserIdKey = stringPreferencesKey("temporaryUserId")
50+
private fun seenAccessKeyKey(accountId: String) = booleanPreferencesKey("${accountId}_seenAccessKey")
5151
private val selectedAccountIdKey = stringPreferencesKey("selectedAccount")
5252
private fun entropyKey(accountId: String) = stringPreferencesKey("${accountId}_entropy")
5353
private fun userIdKey(entropy: String) = stringPreferencesKey("${entropy}_userId")
@@ -70,27 +70,14 @@ class PassphraseCredentialManager @Inject constructor(
7070
produceFile = { context.preferencesDataStoreFile("credentials") }
7171
)
7272

73-
suspend fun create(): Result<String> {
73+
suspend fun createAccount(): Result<String> {
7474
// Setup as new
7575
val seedB64 = Ed25519.createSeed16().encodeBase64()
7676
userManager.establish(seedB64)
7777
storage.edit { preferences ->
78-
preferences[temporaryAccountKey] = seedB64
79-
}
80-
return Result.success(seedB64)
81-
}
82-
83-
suspend fun onUserAccessKeySeen(): Result<Unit> {
84-
storage.edit { prefs ->
85-
prefs[temporaryAccountKey]?.let { entropy ->
86-
prefs[seenAccessKeyKey(entropy)] = true
87-
}
78+
preferences[temporaryEntropyKey] = seedB64
8879
}
8980

90-
return Result.success(Unit)
91-
}
92-
93-
suspend fun registerCreatedAccount(): Result<AccountMetadata> {
9481
// Seed is retrieved internally via userManager state
9582
val backendResult = accountController.createAccount()
9683
if (backendResult.isFailure) {
@@ -102,15 +89,38 @@ class PassphraseCredentialManager @Inject constructor(
10289
}
10390

10491
val userId = backendResult.getOrNull()!!
92+
93+
storage.edit { preferences ->
94+
preferences[temporaryUserIdKey] = userId.base58
95+
}
96+
97+
updateUserManager(userId, AuthState.Unregistered(false))
98+
99+
return Result.success(seedB64)
100+
}
101+
102+
suspend fun onUserAccessKeySeen(): Result<Unit> {
103+
storage.edit { prefs ->
104+
prefs[temporaryUserIdKey]?.let { userId ->
105+
prefs[seenAccessKeyKey(userId)] = true
106+
}
107+
}
108+
109+
return Result.success(Unit)
110+
}
111+
112+
suspend fun presentSaveOption(): Result<AccountMetadata> {
113+
val userId = userManager.userId!!
105114
val entropy = userManager.entropy.orEmpty()
106115

107116
// Store credential
108117
storeCredential(entropy, userId)
109118

110119
// remove temporary states
111120
storage.edit {
112-
it.remove(temporaryAccountKey)
113-
it.remove(seenAccessKeyKey(entropy))
121+
it.remove(temporaryEntropyKey)
122+
it.remove(temporaryUserIdKey)
123+
it.remove(seenAccessKeyKey(userId.base58))
114124
}
115125

116126
// Store metadata
@@ -133,7 +143,7 @@ class PassphraseCredentialManager @Inject constructor(
133143
return LookupResult.ExistingAccountFound(existingAccount)
134144
}
135145

136-
val temporaryAccount = storage.data.map { it[temporaryAccountKey] }.firstOrNull()
146+
val temporaryAccount = storage.data.map { it[temporaryUserIdKey] }.firstOrNull()
137147
if (temporaryAccount != null) {
138148
val seenAccessKey = storage.data.map { it[seenAccessKeyKey(temporaryAccount)] }.firstOrNull() ?: false
139149
return LookupResult.TemporaryAccountCreated(temporaryAccount, seenAccessKey)

services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.codeinc.flipcash.gen.iap.v1.IapGrpc
55
import com.codeinc.flipcash.gen.iap.v1.IapService
66
import com.flipcash.services.internal.annotations.FlipcashManagedChannel
77
import com.flipcash.services.internal.model.billing.IapMetadata
8+
import com.flipcash.services.internal.model.billing.Receipt
89
import com.flipcash.services.internal.network.extensions.authenticate
910
import com.getcode.ed25519.Ed25519.KeyPair
1011
import com.getcode.opencode.internal.network.core.GrpcApi
@@ -24,12 +25,12 @@ class PurchaseApi @Inject constructor(
2425
// OnPurchaseCompleted is called when an IAP has been completed
2526
fun onPurchaseCompleted(
2627
owner: KeyPair,
27-
receiptValue: String,
28+
receipt: Receipt,
2829
metadata: IapMetadata,
2930
): Flow<IapService.OnPurchaseCompletedResponse> {
3031
val request = IapService.OnPurchaseCompletedRequest.newBuilder()
3132
.setPlatform(Common.Platform.GOOGLE)
32-
.setReceipt(IapService.Receipt.newBuilder().setValue(receiptValue))
33+
.setReceipt(IapService.Receipt.newBuilder().setValue(receipt.value))
3334
.setMetadata(IapService.Metadata.newBuilder()
3435
.setProduct(metadata.product)
3536
.setCurrency(metadata.currency.name.lowercase())

services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ internal class PurchaseService @Inject constructor(
1717
) {
1818
suspend fun onPurchaseCompleted(owner: KeyPair, receipt: Receipt, metadata: IapMetadata): Result<Unit> {
1919
return try {
20-
networkOracle.managedRequest(api.onPurchaseCompleted(owner, receipt.value, metadata))
20+
networkOracle.managedRequest(api.onPurchaseCompleted(owner, receipt, metadata))
2121
.map { response ->
2222
when (response.result) {
2323
IapService.OnPurchaseCompletedResponse.Result.OK -> Result.success(Unit)

services/flipcash/src/main/kotlin/com/flipcash/services/user/UserManager.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package com.flipcash.services.user
22

33
import com.bugsnag.android.Bugsnag
44
import com.flipcash.services.internal.model.account.UserFlags
5+
import com.getcode.crypt.DerivePath
6+
import com.getcode.crypt.DerivePath.Companion
57
import com.getcode.crypt.DerivedKey
68
import com.getcode.opencode.controllers.BalanceController
79
import com.getcode.opencode.events.Events
@@ -20,10 +22,18 @@ import javax.inject.Inject
2022
import javax.inject.Singleton
2123

2224
sealed interface AuthState {
25+
// still to determine
2326
data object Unknown : AuthState
27+
// account has been created but not yet paid for
28+
// seenAccessKey used as a flag whether to land them back on
29+
// access key screen or purchase
2430
data class Unregistered(val seenAccessKey: Boolean = true) : AuthState
31+
// account has been created and paid for
32+
// and we are waiting for metadata to be pulled from storage
2533
data object LoggedInAwaitingUser : AuthState
34+
// account is paid for and we ready for use in app
2635
data object LoggedIn : AuthState
36+
// logged out
2737
data object LoggedOut : AuthState
2838

2939
val canAccessAuthenticatedApis: Boolean
@@ -73,7 +83,7 @@ class UserManager @Inject constructor(
7383

7484
fun establish(entropy: String) {
7585
val mnemonic = mnemonicManager.fromEntropyBase64(entropy)
76-
val authority = DerivedKey.derive(com.getcode.crypt.DerivePath.primary, mnemonic)
86+
val authority = DerivedKey.derive(DerivePath.primary, mnemonic)
7787
val cluster = AccountCluster.newInstance(authority)
7888
_state.update {
7989
it.copy(

0 commit comments

Comments
 (0)