Skip to content

Commit 4be6ee4

Browse files
committed
Merge PR #1050.
2 parents 49aa1a6 + ae93f39 commit 4be6ee4

File tree

1 file changed

+34
-17
lines changed
  • android/app/src/main/kotlin/com/yubico/authenticator/oath

1 file changed

+34
-17
lines changed

android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt

+34-17
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import kotlinx.coroutines.*
6363
import kotlinx.serialization.encodeToString
6464
import java.net.URI
6565
import java.util.concurrent.Executors
66+
import java.util.concurrent.atomic.AtomicBoolean
6667
import kotlin.coroutines.suspendCoroutine
6768

6869
typealias OathAction = (Result<YubiKitOathSession, Exception>) -> Unit
@@ -100,6 +101,7 @@ class OathManager(
100101
@TargetApi(Build.VERSION_CODES.M)
101102
private fun createKeyStoreProviderM(): KeyProvider = KeyStoreProvider()
102103

104+
private val unlockOnConnect = AtomicBoolean(true)
103105
private var pendingAction: OathAction? = null
104106
private var refreshJob: Job? = null
105107
private var addToAny = false
@@ -241,8 +243,7 @@ class OathManager(
241243
override suspend fun processYubiKey(device: YubiKeyDevice) {
242244
try {
243245
device.withConnection<SmartCardConnection, Unit> { connection ->
244-
val session = YubiKitOathSession(connection)
245-
246+
val session = getOathSession(connection)
246247
val previousId = oathViewModel.sessionState.value?.deviceId
247248
if (session.deviceId == previousId && device is NfcYubiKeyDevice) {
248249
// Run any pending action
@@ -414,7 +415,7 @@ class OathManager(
414415
currentPassword: String?,
415416
newPassword: String,
416417
): String =
417-
useOathSession("Set password") { session ->
418+
useOathSession("Set password", unlock = false) { session ->
418419
if (session.isAccessKeySet) {
419420
if (currentPassword == null) {
420421
throw Exception("Must provide current password to be able to change it")
@@ -599,6 +600,29 @@ class OathManager(
599600
return false // the unlock did not work, session is locked
600601
}
601602

603+
/**
604+
* Returns a [YubiKitOathSession] for the [connection].
605+
* The session will be unlocked if [unlockOnConnect] is true.
606+
*
607+
* Generally we always want to try to unlock the session and that is why the variable
608+
* [unlockOnConnect] is also reset to true.
609+
*
610+
* Currently, only setPassword and unsetPassword will not unlock the session.
611+
*
612+
* @param connection the device SmartCard connection
613+
* @return a [YubiKitOathSession] which is unlocked or locked based on an internal parameter
614+
*/
615+
private fun getOathSession(connection: SmartCardConnection) : YubiKitOathSession {
616+
val session = YubiKitOathSession(connection)
617+
618+
if (!unlockOnConnect.compareAndSet(false, true)) {
619+
tryToUnlockOathSession(session)
620+
}
621+
622+
return session
623+
}
624+
625+
602626
private fun calculateOathCodes(session: YubiKitOathSession): Map<Credential, Code?> {
603627
val isUsbKey = appViewModel.connectedYubiKey.value != null
604628
var timestamp = System.currentTimeMillis()
@@ -626,37 +650,30 @@ class OathManager(
626650
unlock: Boolean = true,
627651
action: (YubiKitOathSession) -> T
628652
): T {
653+
654+
// callers can decide whether the session should be unlocked first
655+
unlockOnConnect.set(unlock)
629656
return appViewModel.connectedYubiKey.value?.let {
630-
useOathSessionUsb(it, unlock, action)
631-
} ?: useOathSessionNfc(title, unlock, action)
657+
useOathSessionUsb(it, action)
658+
} ?: useOathSessionNfc(title, action)
632659
}
633660

634661
private suspend fun <T> useOathSessionUsb(
635662
device: UsbYubiKeyDevice,
636-
unlock: Boolean = true,
637663
block: (YubiKitOathSession) -> T
638664
): T = device.withConnection<SmartCardConnection, T> {
639-
val session = YubiKitOathSession(it)
640-
if (unlock) {
641-
tryToUnlockOathSession(session)
642-
}
643-
block(session)
665+
block(getOathSession(it))
644666
}
645667

646668
private suspend fun <T> useOathSessionNfc(
647669
title: String,
648-
unlock: Boolean = true,
649670
block: (YubiKitOathSession) -> T
650671
): T {
651672
try {
652673
val result = suspendCoroutine { outer ->
653674
pendingAction = {
654675
outer.resumeWith(runCatching {
655-
val session = it.value
656-
if (unlock) {
657-
tryToUnlockOathSession(session)
658-
}
659-
block.invoke(session)
676+
block.invoke(it.value)
660677
})
661678
}
662679
dialogManager.showDialog(Icon.NFC, "Tap your key", title) {

0 commit comments

Comments
 (0)