You've already forked FIDO2_Bridge
mirror of
https://github.com/token2/FIDO2_Bridge.git
synced 2026-03-13 11:12:26 -07:00
Rename getPinToken to requestPinToken and wrap in Result
This commit is contained in:
@@ -530,21 +530,24 @@ class CredentialProviderActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
setInstruction(getString(R.string.instruction_verifying_pin))
|
||||
// Try CTAP2.1 style with permissions first
|
||||
val authenticated = withContext(Dispatchers.IO) {
|
||||
protocol.getPinToken(pin, permissions, rpId)
|
||||
}
|
||||
if (!authenticated) {
|
||||
val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() }.getOrThrow()
|
||||
if (retries > 0) {
|
||||
runOnUiThread {
|
||||
showProgress(false)
|
||||
setInstruction(getString(R.string.pin_invalid_retries, retries))
|
||||
setState(CredentialBottomSheet.State.PIN)
|
||||
bottomSheet?.showPinInput(true)
|
||||
// Try CTAP2.1 style with permissions first (falls back to basic internally)
|
||||
withContext(Dispatchers.IO) {
|
||||
protocol.requestPinToken(pin, permissions, rpId)
|
||||
}.onFailure { e ->
|
||||
if (e is CTAP.Exception && e.error == CTAP.Error.PIN_INVALID) {
|
||||
val retries = withContext(Dispatchers.IO) { protocol.getPinRetries() }.getOrThrow()
|
||||
if (retries > 0) {
|
||||
runOnUiThread {
|
||||
showProgress(false)
|
||||
setInstruction(getString(R.string.pin_invalid_retries, retries))
|
||||
setState(CredentialBottomSheet.State.PIN)
|
||||
bottomSheet?.showPinInput(true)
|
||||
}
|
||||
} else {
|
||||
throw Exception(getString(R.string.error_pin_blocked))
|
||||
}
|
||||
} else {
|
||||
throw Exception(getString(R.string.error_pin_blocked))
|
||||
throw e
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
|
||||
@@ -503,17 +503,23 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
resultText.text = getString(R.string.verifying_pin)
|
||||
val authenticated = withContext(Dispatchers.IO) {
|
||||
if (usePreviewCommand) protocol.getPinToken(pin)
|
||||
else protocol.getPinToken(pin, PinProtocol.PERMISSION_CM)
|
||||
}
|
||||
if (!authenticated) {
|
||||
if (isNfcDisconnected()) {
|
||||
showNfcReconnectDialog()
|
||||
} else {
|
||||
resultText.text = getString(R.string.error_invalid_pin)
|
||||
pendingAction = null
|
||||
withContext(Dispatchers.IO) {
|
||||
if (usePreviewCommand) protocol.requestPinToken(pin)
|
||||
else protocol.requestPinToken(pin, PinProtocol.PERMISSION_CM)
|
||||
}.onFailure { e ->
|
||||
when {
|
||||
e is java.io.IOException -> throw e
|
||||
e is CTAP.Exception && e.error == CTAP.Error.PIN_INVALID -> {
|
||||
resultText.text = getString(R.string.error_invalid_pin)
|
||||
}
|
||||
e is CTAP.Exception && e.error == CTAP.Error.PIN_BLOCKED -> {
|
||||
resultText.text = getString(R.string.error_pin_blocked)
|
||||
}
|
||||
else -> {
|
||||
resultText.text = getString(R.string.error_generic, e.message ?: "")
|
||||
}
|
||||
}
|
||||
pendingAction = null
|
||||
return@launch
|
||||
}
|
||||
|
||||
|
||||
@@ -56,11 +56,13 @@ class PinProtocol(private val transport: FidoTransport) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getPinToken(pin: String): Boolean {
|
||||
val secret = sharedSecret ?: return false
|
||||
val pubKey = platformPublicKey ?: return false
|
||||
suspend fun requestPinToken(pin: String): Result<Unit> {
|
||||
val secret = sharedSecret
|
||||
?: return Result.failure(Exception("Shared secret not available"))
|
||||
val pubKey = platformPublicKey
|
||||
?: return Result.failure(Exception("Platform key not available"))
|
||||
|
||||
try {
|
||||
return try {
|
||||
val sha256 = MessageDigest.getInstance("SHA-256")
|
||||
val pinHash = sha256.digest(pin.toByteArray(Charsets.UTF_8))
|
||||
val pinHashLeft16 = pinHash.copyOf(16)
|
||||
@@ -70,24 +72,28 @@ class PinProtocol(private val transport: FidoTransport) {
|
||||
val command = buildGetPinTokenCommand(pubKey, encryptedPinHash)
|
||||
val response = transport.sendCtapCommand(command)
|
||||
|
||||
if (!CTAP.isSuccess(response)) {
|
||||
return false
|
||||
val error = CTAP.getResponseError(response)
|
||||
if (error != null) {
|
||||
return Result.failure(CTAP.Exception(error))
|
||||
}
|
||||
|
||||
val encryptedToken = parsePinTokenResponse(response) ?: return false
|
||||
val encryptedToken = parsePinTokenResponse(response)
|
||||
?: return Result.failure(Exception("Failed to parse PIN token"))
|
||||
pinToken = aesDecrypt(secret, encryptedToken)
|
||||
|
||||
return pinToken != null
|
||||
Result.success(Unit)
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getPinToken(pin: String, permissions: Int, rpId: String? = null): Boolean {
|
||||
val secret = sharedSecret ?: return false
|
||||
val pubKey = platformPublicKey ?: return false
|
||||
suspend fun requestPinToken(pin: String, permissions: Int, rpId: String? = null): Result<Unit> {
|
||||
val secret = sharedSecret
|
||||
?: return Result.failure(Exception("Shared secret not available"))
|
||||
val pubKey = platformPublicKey
|
||||
?: return Result.failure(Exception("Platform key not available"))
|
||||
|
||||
try {
|
||||
return try {
|
||||
val sha256 = MessageDigest.getInstance("SHA-256")
|
||||
val pinHash = sha256.digest(pin.toByteArray(Charsets.UTF_8))
|
||||
val pinHashLeft16 = pinHash.copyOf(16)
|
||||
@@ -98,30 +104,34 @@ class PinProtocol(private val transport: FidoTransport) {
|
||||
val response = transport.sendCtapCommand(command)
|
||||
|
||||
if (response.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (CTAP.isSuccess(response)) {
|
||||
val encryptedToken = parsePinTokenResponse(response) ?: return false
|
||||
pinToken = aesDecrypt(secret, encryptedToken)
|
||||
return pinToken != null
|
||||
return Result.failure(Exception("Empty response"))
|
||||
}
|
||||
|
||||
val error = CTAP.getResponseError(response)
|
||||
val fallbackErrors = listOf(
|
||||
CTAP.Error.INVALID_COMMAND,
|
||||
CTAP.Error.INVALID_PARAMETER,
|
||||
CTAP.Error.CBOR_UNEXPECTED_TYPE,
|
||||
CTAP.Error.MISSING_PARAMETER
|
||||
)
|
||||
if (error in fallbackErrors) {
|
||||
return getPinToken(pin)
|
||||
if (error != null) {
|
||||
// Fallback to basic method if authenticator doesn't support permissions
|
||||
val fallbackErrors = listOf(
|
||||
CTAP.Error.INVALID_COMMAND,
|
||||
CTAP.Error.INVALID_PARAMETER,
|
||||
CTAP.Error.CBOR_UNEXPECTED_TYPE,
|
||||
CTAP.Error.MISSING_PARAMETER
|
||||
)
|
||||
if (error in fallbackErrors) {
|
||||
return requestPinToken(pin)
|
||||
}
|
||||
return Result.failure(CTAP.Exception(error))
|
||||
}
|
||||
|
||||
return false
|
||||
val encryptedToken = parsePinTokenResponse(response)
|
||||
?: return Result.failure(Exception("Failed to parse PIN token"))
|
||||
pinToken = aesDecrypt(secret, encryptedToken)
|
||||
|
||||
Result.success(Unit)
|
||||
} catch (e: java.io.IOException) {
|
||||
Result.failure(e)
|
||||
} catch (e: Exception) {
|
||||
return getPinToken(pin)
|
||||
// On unexpected exception, try fallback to basic method
|
||||
requestPinToken(pin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user