Skip to content

Commit

Permalink
Update based on PR comments
Browse files Browse the repository at this point in the history
  • Loading branch information
vincetran committed Jun 19, 2024
1 parent ac31076 commit 13e4a1b
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ import com.amplifyframework.predictions.aws.models.liveness.LivenessResponseStre
import com.amplifyframework.predictions.aws.models.liveness.SessionInformation
import com.amplifyframework.predictions.aws.models.liveness.TargetFace
import com.amplifyframework.predictions.aws.models.liveness.VideoEvent
import com.amplifyframework.predictions.models.ChallengeType
import com.amplifyframework.predictions.models.Challenge
import com.amplifyframework.predictions.models.FaceLivenessChallengeType
import com.amplifyframework.predictions.models.FaceLivenessSessionInformation
import com.amplifyframework.util.UserAgent
import java.net.URI
Expand Down Expand Up @@ -96,7 +97,7 @@ internal class LivenessWebSocket(
@VisibleForTesting
internal var webSocket: WebSocket? = null
internal val challengeId = UUID.randomUUID().toString()
var challengeType: ChallengeType? = null
lateinit var challengeType: FaceLivenessChallengeType
private var initialDetectedFace: BoundingBox? = null
private var faceDetectedStart = 0L
private var videoStartTimestamp = 0L
Expand Down Expand Up @@ -138,6 +139,16 @@ internal class LivenessWebSocket(
}
}

init {
// If the client session is requesting a 1.0.0 FaceMovementAndLight challenge, the backend won't return a
// ChallengeEvent so we have to set the challengeType manually
clientSessionInformation.challengeVersions.forEach {
if (it.compareType(Challenge.FaceMovementAndLightChallenge("1.0.0"))) {
challengeType = FaceLivenessChallengeType.FaceMovementAndLightChallenge
}
}
}

override fun onMessage(webSocket: WebSocket, text: String) {
LOG.debug("WebSocket onMessage text")
super.onMessage(webSocket, text)
Expand All @@ -151,9 +162,21 @@ internal class LivenessWebSocket(
if (response.challengeEvent != null) {
challengeType = response.challengeEvent.challengeType
} else if (response.serverSessionInformationEvent != null) {
onSessionInformationReceived.accept(
response.serverSessionInformationEvent.sessionInformation
)
// If challengeType hasn't been initialized by this point it's because server sent an
// unsupported challenge type so return an error to the client.
if (!this@LivenessWebSocket::challengeType.isInitialized) {
onErrorReceived.accept(
PredictionsException(
"Received an unsupported ChallengeType from the backend",
"Verify that the Challenges configured in your backend are supported by the " +
"frontend code (e.g. Amplify UI)"
)
)
} else {
onSessionInformationReceived.accept(
response.serverSessionInformationEvent.sessionInformation
)
}
} else if (response.disconnectionEvent != null) {
this@LivenessWebSocket.webSocket?.close(
NORMAL_SOCKET_CLOSURE_STATUS_CODE,
Expand Down Expand Up @@ -527,15 +550,15 @@ internal class LivenessWebSocket(
private fun isTimeDiffSafe(diffInMillis: Long) = kotlin.math.abs(diffInMillis) < FOUR_MINUTES

private fun buildClientChallenge(
challengeType: ChallengeType?,
challengeType: FaceLivenessChallengeType,
challengeId: String,
videoStartTimestamp: Long? = null,
videoEndTimestamp: Long? = null,
initialFace: InitialFace? = null,
targetFace: TargetFace? = null,
colorDisplayed: ColorDisplayed? = null
): ClientChallenge = when (challengeType) {
ChallengeType.FaceMovementAndLightChallenge -> {
FaceLivenessChallengeType.FaceMovementAndLightChallenge -> {
ClientChallenge(
faceMovementAndLightChallenge = FaceMovementAndLightClientChallenge(
challengeId = challengeId,
Expand All @@ -548,7 +571,7 @@ internal class LivenessWebSocket(
faceMovementChallenge = null
)
}
ChallengeType.FaceMovementChallenge -> {
FaceLivenessChallengeType.FaceMovementChallenge -> {
ClientChallenge(
faceMovementAndLightChallenge = null,
faceMovementChallenge = FaceMovementClientChallenge(
Expand All @@ -560,21 +583,6 @@ internal class LivenessWebSocket(
)
)
}
null -> {
// A ChallengeType event is not returned when the v1 version of FaceMovementAndLightChallenge
// so we assume that the client challenge to send is of FaceMovementAndLight type
ClientChallenge(
faceMovementAndLightChallenge = FaceMovementAndLightClientChallenge(
challengeId = challengeId,
videoStartTimestamp = videoStartTimestamp,
videoEndTimestamp = videoEndTimestamp,
initialFace = initialFace,
targetFace = targetFace,
colorDisplayed = colorDisplayed
),
faceMovementChallenge = null
)
}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
*/
package com.amplifyframework.predictions.aws.models.liveness

import com.amplifyframework.predictions.models.ChallengeType
import com.amplifyframework.predictions.models.FaceLivenessChallengeType
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
internal data class ChallengeEvent(
@SerialName("Type") val challengeType: ChallengeType,
@SerialName("Type") val challengeType: FaceLivenessChallengeType,
@SerialName("Version") val version: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.amplifyframework.predictions.aws.service

import android.net.Uri
import androidx.annotation.VisibleForTesting
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProvider
import com.amplifyframework.core.Action
import com.amplifyframework.core.Consumer
Expand All @@ -34,9 +35,7 @@ import com.amplifyframework.predictions.aws.models.liveness.ChallengeConfig
import com.amplifyframework.predictions.aws.models.liveness.FreshnessColor
import com.amplifyframework.predictions.aws.models.liveness.OvalParameters
import com.amplifyframework.predictions.aws.models.liveness.SessionInformation
import com.amplifyframework.predictions.models.Challenge
import com.amplifyframework.predictions.models.ChallengeResponseEvent
import com.amplifyframework.predictions.models.ChallengeType
import com.amplifyframework.predictions.models.FaceLivenessChallengeType
import com.amplifyframework.predictions.models.FaceLivenessSession
import com.amplifyframework.predictions.models.FaceLivenessSessionChallenge
Expand All @@ -61,7 +60,7 @@ internal class RunFaceLivenessSession(
livenessVersion = livenessVersion,
onSessionInformationReceived = { serverSessionInformation ->
val challenges = processSessionInformation(serverSessionInformation)
val challengeType = processChallengeType()
val challengeType = getChallengeType()
val faceLivenessSession = FaceLivenessSession(
challengeId = getChallengeId(),
challengeType = challengeType,
Expand Down Expand Up @@ -129,24 +128,7 @@ internal class RunFaceLivenessSession(

private fun getChallengeId(): String = livenessWebSocket.challengeId

private fun processChallengeType(): FaceLivenessChallengeType =
when (livenessWebSocket.challengeType) {
ChallengeType.FaceMovementChallenge -> FaceLivenessChallengeType.FaceMovementChallenge
ChallengeType.FaceMovementAndLightChallenge -> FaceLivenessChallengeType.FaceMovementAndLightChallenge
null -> {
// A ChallengeType event is not returned when the v1 version of FaceMovementAndLightChallenge
// is requested so we'll check here for backwards compat
if (clientSessionInformation.challengeVersions != null &&
clientSessionInformation.challengeVersions!!.contains(
Challenge(ChallengeType.FaceMovementAndLightChallenge, "1.0.0")
)
) {
FaceLivenessChallengeType.FaceMovementAndLightChallenge
} else {
FaceLivenessChallengeType.Unknown
}
}
}
private fun getChallengeType(): FaceLivenessChallengeType = livenessWebSocket.challengeType

private fun getFaceTargetChallenge(
ovalParameters: OvalParameters,
Expand Down Expand Up @@ -222,11 +204,11 @@ internal class RunFaceLivenessSession(
reasonCode?.let { livenessWebSocket.destroy(it) } ?: livenessWebSocket.destroy()
}

private fun buildWebSocketEndpoint(): String {
val challengeVersionString = clientSessionInformation.challenge
?: clientSessionInformation.challengeVersions?.joinToString(",") {
it.toQueryParamString()
}
@VisibleForTesting
fun buildWebSocketEndpoint(): String {
val challengeVersionString = clientSessionInformation.challengeVersions.joinToString(",") {
it.toQueryParamString()
}

val uriBuilder = Uri.Builder()
.scheme("wss")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import com.amplifyframework.predictions.aws.models.liveness.ServerChallenge
import com.amplifyframework.predictions.aws.models.liveness.ServerSessionInformationEvent
import com.amplifyframework.predictions.aws.models.liveness.SessionInformation
import com.amplifyframework.predictions.aws.models.liveness.ValidationException
import com.amplifyframework.predictions.models.ChallengeType
import com.amplifyframework.predictions.models.FaceLivenessChallengeType
import com.amplifyframework.predictions.models.FaceLivenessSessionInformation
import io.mockk.every
import io.mockk.mockk
Expand Down Expand Up @@ -215,7 +215,7 @@ internal class LivenessWebSocketTest {
assertEquals(null, livenessWebSocket.challengeType)

val event = ChallengeEvent(
challengeType = ChallengeType.FaceMovementAndLightChallenge,
challengeType = FaceLivenessChallengeType.FaceMovementAndLightChallenge,
version = "2.0.0"
)

Expand All @@ -230,7 +230,7 @@ internal class LivenessWebSocketTest {

livenessWebSocket.webSocketListener.onMessage(mockk(), encodedByteString)

assertEquals(ChallengeType.FaceMovementAndLightChallenge, livenessWebSocket.challengeType)
assertEquals(FaceLivenessChallengeType.FaceMovementAndLightChallenge, livenessWebSocket.challengeType)
}

@Test
Expand All @@ -239,7 +239,7 @@ internal class LivenessWebSocketTest {
assertEquals(null, livenessWebSocket.challengeType)

val event = ChallengeEvent(
challengeType = ChallengeType.FaceMovementChallenge,
challengeType = FaceLivenessChallengeType.FaceMovementChallenge,
version = "1.0.0"
)

Expand All @@ -254,7 +254,7 @@ internal class LivenessWebSocketTest {

livenessWebSocket.webSocketListener.onMessage(mockk(), encodedByteString)

assertEquals(ChallengeType.FaceMovementChallenge, livenessWebSocket.challengeType)
assertEquals(FaceLivenessChallengeType.FaceMovementChallenge, livenessWebSocket.challengeType)
}

@Test
Expand Down
Loading

0 comments on commit 13e4a1b

Please sign in to comment.