@@ -30,22 +30,18 @@ import com.amplifyframework.predictions.PredictionsException
30
30
import com.amplifyframework.predictions.aws.BuildConfig
31
31
import com.amplifyframework.predictions.aws.exceptions.AccessDeniedException
32
32
import com.amplifyframework.predictions.aws.exceptions.FaceLivenessSessionNotFoundException
33
- import com.amplifyframework.predictions.aws.exceptions.FaceLivenessUnsupportedChallengeTypeException
34
33
import com.amplifyframework.predictions.aws.models.liveness.BoundingBox
35
34
import com.amplifyframework.predictions.aws.models.liveness.ClientChallenge
36
35
import com.amplifyframework.predictions.aws.models.liveness.ClientSessionInformationEvent
37
36
import com.amplifyframework.predictions.aws.models.liveness.ColorDisplayed
38
37
import com.amplifyframework.predictions.aws.models.liveness.FaceMovementAndLightClientChallenge
39
- import com.amplifyframework.predictions.aws.models.liveness.FaceMovementClientChallenge
40
38
import com.amplifyframework.predictions.aws.models.liveness.FreshnessColor
41
39
import com.amplifyframework.predictions.aws.models.liveness.InitialFace
42
40
import com.amplifyframework.predictions.aws.models.liveness.InvalidSignatureException
43
41
import com.amplifyframework.predictions.aws.models.liveness.LivenessResponseStream
44
42
import com.amplifyframework.predictions.aws.models.liveness.SessionInformation
45
43
import com.amplifyframework.predictions.aws.models.liveness.TargetFace
46
44
import com.amplifyframework.predictions.aws.models.liveness.VideoEvent
47
- import com.amplifyframework.predictions.models.Challenge
48
- import com.amplifyframework.predictions.models.FaceLivenessChallengeType
49
45
import com.amplifyframework.predictions.models.FaceLivenessSessionInformation
50
46
import com.amplifyframework.util.UserAgent
51
47
import java.net.URI
@@ -77,16 +73,12 @@ internal class LivenessWebSocket(
77
73
val credentialsProvider : CredentialsProvider ,
78
74
val endpoint : String ,
79
75
val region : String ,
80
- val clientSessionInformation : FaceLivenessSessionInformation ,
76
+ val sessionInformation : FaceLivenessSessionInformation ,
81
77
val livenessVersion : String? ,
82
- val onSessionResponseReceived : Consumer <SessionResponse >,
78
+ val onSessionInformationReceived : Consumer <SessionInformation >,
83
79
val onErrorReceived : Consumer <PredictionsException >,
84
80
val onComplete : Action
85
81
) {
86
- internal data class SessionResponse (
87
- val faceLivenessSession : SessionInformation ,
88
- val livenessChallengeType : FaceLivenessChallengeType
89
- )
90
82
91
83
private val signer = AWSV4Signer ()
92
84
private var credentials: Credentials ? = null
@@ -102,7 +94,6 @@ internal class LivenessWebSocket(
102
94
@VisibleForTesting
103
95
internal var webSocket: WebSocket ? = null
104
96
internal val challengeId = UUID .randomUUID().toString()
105
- var challengeType: FaceLivenessChallengeType ? = null
106
97
private var initialDetectedFace: BoundingBox ? = null
107
98
private var faceDetectedStart = 0L
108
99
private var videoStartTimestamp = 0L
@@ -154,34 +145,10 @@ internal class LivenessWebSocket(
154
145
try {
155
146
when (val response = LivenessEventStream .decode(bytes, json)) {
156
147
is LivenessResponseStream .Event -> {
157
- if (response.challengeEvent != null ) {
158
- challengeType = response.challengeEvent.challengeType
159
- } else if (response.serverSessionInformationEvent != null ) {
160
-
161
- val clientRequestedOldLightChallenge = clientSessionInformation.challengeVersions
162
- .any { it == Challenge .FaceMovementAndLightChallenge (" 1.0.0" ) }
163
-
164
- if (challengeType == null && clientRequestedOldLightChallenge) {
165
- // For the 1.0.0 version of FaceMovementAndLight challenge, backend doesn't send a
166
- // ChallengeEvent so we need to manually check and set it if that specific challenge
167
- // was requested.
168
- challengeType = FaceLivenessChallengeType .FaceMovementAndLightChallenge
169
- }
170
-
171
- // If challengeType hasn't been initialized by this point it's because server sent an
172
- // unsupported challenge type so return an error to the client and close the web socket.
173
- val resolvedChallengeType = challengeType
174
- if (resolvedChallengeType == null ) {
175
- webSocketError = FaceLivenessUnsupportedChallengeTypeException ()
176
- destroy(UNSUPPORTED_CHALLENGE_CLOSURE_STATUS_CODE )
177
- } else {
178
- onSessionResponseReceived.accept(
179
- SessionResponse (
180
- response.serverSessionInformationEvent.sessionInformation,
181
- resolvedChallengeType
182
- )
183
- )
184
- }
148
+ if (response.serverSessionInformationEvent != null ) {
149
+ onSessionInformationReceived.accept(
150
+ response.serverSessionInformationEvent.sessionInformation
151
+ )
185
152
} else if (response.disconnectionEvent != null ) {
186
153
this @LivenessWebSocket.webSocket?.close(
187
154
NORMAL_SOCKET_CLOSURE_STATUS_CODE ,
@@ -391,26 +358,16 @@ internal class LivenessWebSocket(
391
358
// Send initial ClientSessionInformationEvent
392
359
videoStartTimestamp = adjustedDate(videoStartTime)
393
360
initialDetectedFace = BoundingBox (
394
- left = initialFaceRect.left / clientSessionInformation .videoWidth,
395
- top = initialFaceRect.top / clientSessionInformation .videoHeight,
396
- height = initialFaceRect.height() / clientSessionInformation .videoHeight,
397
- width = initialFaceRect.width() / clientSessionInformation .videoWidth
361
+ left = initialFaceRect.left / sessionInformation .videoWidth,
362
+ top = initialFaceRect.top / sessionInformation .videoHeight,
363
+ height = initialFaceRect.height() / sessionInformation .videoHeight,
364
+ width = initialFaceRect.width() / sessionInformation .videoWidth
398
365
)
399
366
faceDetectedStart = adjustedDate(videoStartTime)
400
-
401
- val resolvedChallengeType = challengeType
402
- if (resolvedChallengeType == null ) {
403
- onErrorReceived.accept(
404
- PredictionsException (
405
- " Failed to send an initial face detected event" ,
406
- AmplifyException .TODO_RECOVERY_SUGGESTION
407
- )
408
- )
409
- } else {
410
- val clientInfoEvent =
411
- ClientSessionInformationEvent (
412
- challenge = buildClientChallenge(
413
- challengeType = resolvedChallengeType,
367
+ val clientInfoEvent =
368
+ ClientSessionInformationEvent (
369
+ challenge = ClientChallenge (
370
+ faceMovementAndLightChallenge = FaceMovementAndLightClientChallenge (
414
371
challengeId = challengeId,
415
372
initialFace = InitialFace (
416
373
boundingBox = initialDetectedFace!! ,
@@ -419,23 +376,14 @@ internal class LivenessWebSocket(
419
376
videoStartTimestamp = videoStartTimestamp
420
377
)
421
378
)
422
- sendClientInfoEvent(clientInfoEvent )
423
- }
379
+ )
380
+ sendClientInfoEvent(clientInfoEvent)
424
381
}
425
382
426
383
fun sendFinalEvent (targetFaceRect : RectF , faceMatchedStart : Long , faceMatchedEnd : Long ) {
427
- val resolvedChallengeType = challengeType
428
- if (resolvedChallengeType == null ) {
429
- onErrorReceived.accept(
430
- PredictionsException (
431
- " Failed to send an initial face detected event" ,
432
- AmplifyException .TODO_RECOVERY_SUGGESTION
433
- )
434
- )
435
- } else {
436
- val finalClientInfoEvent = ClientSessionInformationEvent (
437
- challenge = buildClientChallenge(
438
- challengeType = resolvedChallengeType,
384
+ val finalClientInfoEvent = ClientSessionInformationEvent (
385
+ challenge = ClientChallenge (
386
+ FaceMovementAndLightClientChallenge (
439
387
challengeId = challengeId,
440
388
videoEndTimestamp = videoEndTimestamp,
441
389
initialFace = InitialFace (
@@ -446,16 +394,16 @@ internal class LivenessWebSocket(
446
394
faceDetectedInTargetPositionStartTimestamp = adjustedDate(faceMatchedStart),
447
395
faceDetectedInTargetPositionEndTimestamp = adjustedDate(faceMatchedEnd),
448
396
boundingBox = BoundingBox (
449
- left = targetFaceRect.left / clientSessionInformation .videoWidth,
450
- top = targetFaceRect.top / clientSessionInformation .videoHeight,
451
- height = targetFaceRect.height() / clientSessionInformation .videoHeight,
452
- width = targetFaceRect.width() / clientSessionInformation .videoWidth
397
+ left = targetFaceRect.left / sessionInformation .videoWidth,
398
+ top = targetFaceRect.top / sessionInformation .videoHeight,
399
+ height = targetFaceRect.height() / sessionInformation .videoHeight,
400
+ width = targetFaceRect.width() / sessionInformation .videoWidth
453
401
)
454
402
)
455
403
)
456
404
)
457
- sendClientInfoEvent(finalClientInfoEvent )
458
- }
405
+ )
406
+ sendClientInfoEvent(finalClientInfoEvent)
459
407
}
460
408
461
409
fun sendColorDisplayedEvent (
@@ -575,46 +523,8 @@ internal class LivenessWebSocket(
575
523
576
524
private fun isTimeDiffSafe (diffInMillis : Long ) = kotlin.math.abs(diffInMillis) < FOUR_MINUTES
577
525
578
- private fun buildClientChallenge (
579
- challengeType : FaceLivenessChallengeType ,
580
- challengeId : String ,
581
- videoStartTimestamp : Long? = null,
582
- videoEndTimestamp : Long? = null,
583
- initialFace : InitialFace ? = null,
584
- targetFace : TargetFace ? = null,
585
- colorDisplayed : ColorDisplayed ? = null
586
- ): ClientChallenge = when (challengeType) {
587
- FaceLivenessChallengeType .FaceMovementAndLightChallenge -> {
588
- ClientChallenge (
589
- faceMovementAndLightChallenge = FaceMovementAndLightClientChallenge (
590
- challengeId = challengeId,
591
- videoStartTimestamp = videoStartTimestamp,
592
- videoEndTimestamp = videoEndTimestamp,
593
- initialFace = initialFace,
594
- targetFace = targetFace,
595
- colorDisplayed = colorDisplayed
596
- ),
597
- faceMovementChallenge = null
598
- )
599
- }
600
- FaceLivenessChallengeType .FaceMovementChallenge -> {
601
- ClientChallenge (
602
- faceMovementAndLightChallenge = null ,
603
- faceMovementChallenge = FaceMovementClientChallenge (
604
- challengeId = challengeId,
605
- videoStartTimestamp = videoStartTimestamp,
606
- videoEndTimestamp = videoEndTimestamp,
607
- initialFace = initialFace,
608
- targetFace = targetFace
609
- )
610
- )
611
- }
612
- }
613
-
614
526
companion object {
615
527
private const val NORMAL_SOCKET_CLOSURE_STATUS_CODE = 1000
616
- // This is the same as the client-provided 'runtime error' status code
617
- private const val UNSUPPORTED_CHALLENGE_CLOSURE_STATUS_CODE = 4005
618
528
private const val FOUR_MINUTES = 1000 * 60 * 4
619
529
@VisibleForTesting val datePattern = " EEE, d MMM yyyy HH:mm:ss z"
620
530
private val LOG = Amplify .Logging .logger(CategoryType .PREDICTIONS , " amplify:aws-predictions" )
0 commit comments