Skip to content
Closed
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
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
android:resource="@xml/shortcuts" />
</activity>

<!-- Enabled only while Bitkit can authorize with a locally managed Pubky identity. -->
<!-- Enabled only while Bitkit can read its Pubky identity's secret key, stored locally or in Pubky Ring. -->
<activity-alias
android:name=".ui.MainActivityPubkyAuth"
android:targetActivity=".ui.MainActivity"
Expand Down
235 changes: 159 additions & 76 deletions app/src/main/java/to/bitkit/repositories/PubkyRepo.kt

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion app/src/main/java/to/bitkit/services/PaykitSdkService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1250,8 +1250,8 @@ internal class PaykitSdkSessionProvider(
override fun clearSessionAccess() {
clearLiveSessionAccess()
keychain.accessBlocking {
delete(Keychain.Key.SHARED_PUBKY_SOURCE.name)
clearPubkySessionCredentials(::delete)
delete(Keychain.Key.SHARED_PUBKY_SOURCE.name)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
import javax.inject.Singleton

/** Advertises Pubky signup and authorization handlers when their required identity state is available. */
/**
* Advertises Pubky signup and authorization handlers when their required identity state is available.
*
* Both handlers are re-checked when the identity, the Paykit flag, the saved identity state or the reachability of
* an adopted Pubky Ring pubky changes, so the authorization handler follows Pubky Ring going away and coming back
* without a restart.
*/
@Singleton
internal class PubkyAuthHandlerRegistrar @Inject constructor(
@ApplicationContext private val context: Context,
Expand Down Expand Up @@ -54,7 +60,8 @@ internal class PubkyAuthHandlerRegistrar @Inject constructor(
pubkyRepo.publicKey,
pubkyRepo.backupStateVersion,
pubkyRepo.identityRefreshVersion,
) { localFlagEnabled, publicKey, _, _ ->
pubkyRepo.adoptedSourceUnreachable,
) { localFlagEnabled, publicKey, _, _, _ ->
val hasIdentity = runSuspendCatching { pubkyRepo.hasIdentity() }
.onFailure { Logger.warn("Failed to read saved Pubky identity", it, context = TAG) }
.getOrDefault(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import kotlinx.coroutines.launch
import to.bitkit.R
import to.bitkit.models.PubkyPublicKeyFormat
import to.bitkit.models.Toast
import to.bitkit.repositories.PubkyAlreadySignedInError
import to.bitkit.repositories.PubkyRepo
import to.bitkit.ui.shared.toast.ToastEventBus
import to.bitkit.utils.Logger
Expand Down Expand Up @@ -49,8 +50,9 @@ class PubkyChoiceViewModel @Inject constructor(
}

fun onIdentityClick(pubky: String) {
if (_uiState.value.adoptingPubky != null) return
_uiState.update { it.copy(adoptingPubky = pubky) }
viewModelScope.launch {
_uiState.update { it.copy(adoptingPubky = pubky) }
pubkyRepo.adoptRingIdentity(pubky)
.onSuccess { hasProfile ->
if (hasProfile) {
Expand All @@ -72,7 +74,10 @@ class PubkyChoiceViewModel @Inject constructor(
_effects.emit(effect)
}
.onFailure {
Logger.error("Failed to adopt ring identity", it, context = TAG)
if (it is PubkyAlreadySignedInError) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Picking a different pubky while an abandoned pick finishes signs in as the abandoned one.

After Back, pick A keeps running under NonCancellable, and _publicKey is published only at the end of commitRingIdentity (PubkyRepo.kt:441), so isAuthenticated stays false for the rest of the pick. During that window, Drawer → Profile still routes to Pubky Choice. The new view model has adoptingPubky == null, and the Ring list is tappable.

Tapping pubky B queues on withRingPickLock. When A commits, B throws PubkyAlreadySignedInError (PubkyRepo.kt:381), and this branch opens Profile without a toast. The user picked B and is signed in as A. On master the same sequence ends as B, because Back rolls A back before B takes the lock.

Fix: only a retry of the same pubky needs the silent path. Compare the requested pubky with pubkyRepo.publicKey.value (PubkyPublicKeyFormat.matches) and show the auth error when they differ, or throw PubkyAlreadySignedInError from adoptRingIdentity only when _publicKey matches pubky. Add a PubkyChoiceViewModelTest case with a different signed-in pubky.

_uiState.update { state -> state.copy(adoptingPubky = null, navigateToProfile = true) }
return@onFailure
}
_uiState.update { state -> state.copy(adoptingPubky = null) }
ToastEventBus.send(
type = Toast.ToastType.ERROR,
Expand Down
Loading
Loading