Skip to content

Commit

Permalink
Let confirmRequestWithUser return null on timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
fmeum committed Apr 13, 2020
1 parent 6f1aec7 commit 6d196de
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ enum class AuthenticatorSpecialStatus {
abstract class AuthenticatorContext(private val context: Context, val isHidTransport: Boolean) {
abstract fun notifyUser(info: RequestInfo)
abstract fun handleSpecialStatus(specialStatus: AuthenticatorSpecialStatus)
abstract suspend fun confirmRequestWithUser(info: RequestInfo): Boolean
abstract suspend fun confirmRequestWithUser(info: RequestInfo): Boolean?
abstract suspend fun confirmTransactionWithUser(rpId: String, prompt: String): String?

// We use cached credentials only over NFC, where low latency responses are very important
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ object Authenticator {
if ((rpId == ".dummy" && userName == "dummy") /* Chrome */ ||
(rpId == "SelectDevice" && userName == "SelectDevice") /* Windows Hello */) {
val requestInfo = Ctap2RequestInfo(PLATFORM_GET_TOUCH, rpId)
val followUpInClient = context.confirmRequestWithUser(requestInfo)
val followUpInClient = context.confirmRequestWithUser(requestInfo) == true
if (followUpInClient)
return DUMMY_MAKE_CREDENTIAL_RESPONSE
else
Expand All @@ -125,7 +125,7 @@ object Authenticator {
rpId = rpId,
rpName = rpName
)
val revealRegistration = context.confirmRequestWithUser(requestInfo)
val revealRegistration = context.confirmRequestWithUser(requestInfo) == true
if (revealRegistration)
CTAP_ERR(CredentialExcluded)
else
Expand Down Expand Up @@ -183,7 +183,7 @@ object Authenticator {
requiresUserVerification = requireUserVerification
)

if (!context.confirmRequestWithUser(requestInfo))
if (context.confirmRequestWithUser(requestInfo) != true)
CTAP_ERR(OperationDenied)

if (requireUserVerification && !context.verifyUser())
Expand Down Expand Up @@ -416,7 +416,7 @@ object Authenticator {
// We have not found any credentials, ask the user for permission to reveal this fact.
Ctap2RequestInfo(AUTHENTICATE_NO_CREDENTIALS, rpId)
}
if (requireUserPresence && !context.confirmRequestWithUser(requestInfo))
if (requireUserPresence && context.confirmRequestWithUser(requestInfo) != true)
CTAP_ERR(OperationDenied)
if (!requireUserPresence)
Log.i(TAG, "Processing silent GetAssertion request")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,9 @@ class TransactionManager(private val authenticatorContext: AuthenticatorContext)
// CONDITIONS_NOT_SATISFIED while waiting.
activeU2fConfirmation = U2fContinuation(
message,
async { authenticatorContext.confirmRequestWithUser(requestInfo) },
async {
authenticatorContext.confirmRequestWithUser(requestInfo) == true
},
cont
)
rearmU2fRetryTimeout()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,30 @@ class TimedAcceptDenyDialog(context: Context) : Dialog(context) {
private var vibrateOnShow = false
private var positiveButtonListener: DialogInterface.OnClickListener? = null
private var negativeButtonListener: DialogInterface.OnClickListener? = null
private var timeoutListener: DialogInterface.OnCancelListener? = null

private var wakeLock: PowerManager.WakeLock? = null

private val actionHandler: (View) -> Unit = { v: View ->
when (v) {
positiveButton -> {
when {
v == positiveButton -> {
positiveButtonListener?.let {
it.onClick(this, DialogInterface.BUTTON_POSITIVE)
dismiss()
}
}
negativeButton, negativeTimeout -> {
v == negativeButton || (v == negativeTimeout && timeoutListener == null) -> {
negativeButtonListener?.let {
it.onClick(this, DialogInterface.BUTTON_NEGATIVE)
dismiss()
}
}
v == negativeTimeout -> {
timeoutListener?.let {
it.onCancel(this)
dismiss()
}
}
}
}

Expand Down Expand Up @@ -150,6 +157,10 @@ class TimedAcceptDenyDialog(context: Context) : Dialog(context) {
setButton(DialogInterface.BUTTON_POSITIVE, listener)
}

fun setTimeoutListener(listener: DialogInterface.OnCancelListener) {
timeoutListener = listener
}

fun setTimeout(timeout: Long) {
negativeTimeout.totalTime = timeout
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ class HidAuthenticatorContext(private val activity: Activity) :
// a special status.
}

override suspend fun confirmRequestWithUser(info: RequestInfo): Boolean {
/**
* Returns true if the user confirms the request, false if the user denies it explicitly and
* null if the confirmation dialog times out.
*/
override suspend fun confirmRequestWithUser(info: RequestInfo): Boolean? {
return try {
status = AuthenticatorStatus.WAITING_FOR_UP
withContext(Dispatchers.Main) {
Expand All @@ -40,14 +44,17 @@ class HidAuthenticatorContext(private val activity: Activity) :
setVibrateOnShow(true)
setWakeOnShow(true)
}
suspendCancellableCoroutine<Boolean> { continuation ->
suspendCancellableCoroutine<Boolean?> { continuation ->
dialog.apply {
setPositiveButton(DialogInterface.OnClickListener { _, _ ->
continuation.resume(true)
})
setNegativeButton(DialogInterface.OnClickListener { _, _ ->
continuation.resume(false)
})
setTimeoutListener(DialogInterface.OnCancelListener {
continuation.resume(null)
})
}.show()
continuation.invokeOnCancellation {
dialog.dismiss()
Expand Down

0 comments on commit 6d196de

Please sign in to comment.