From 67b117dc000c89f9870fe43deeb2cb4c37f4acc9 Mon Sep 17 00:00:00 2001 From: Anshul Gupta Date: Thu, 9 Nov 2023 13:34:03 -0600 Subject: [PATCH] Revert "fix(liveness): Liveness web socket expiration retry (#2615)" This reverts commit acdaa9ec54fc2eabf0d30dc0e32735a18a6c65d3. --- aws-analytics-pinpoint/build.gradle.kts | 2 +- aws-auth-cognito/build.gradle.kts | 2 +- .../auth/cognito/AWSCognitoAuthService.kt | 4 +- .../cognito/RealAWSCognitoAuthPluginTest.kt | 33 ------- .../utilities/CognitoMockFactory.kt | 2 - ...f_user_is_confirmed_in_the_first_step.json | 3 +- ...r_cognito_request_and_returns_success.json | 3 +- aws-auth-plugins-core/build.gradle.kts | 2 +- aws-logging-cloudwatch/build.gradle.kts | 2 +- aws-pinpoint-core/build.gradle.kts | 2 +- .../pinpoint/core/EventRecorder.kt | 11 ++- aws-predictions/build.gradle.kts | 2 +- .../predictions/aws/http/AWSV4Signer.kt | 5 - .../predictions/aws/http/LivenessWebSocket.kt | 91 ++++--------------- .../liveness/InvalidSignatureException.kt | 28 ------ .../models/liveness/LivenessResponseStream.kt | 3 +- .../aws/http/LivenessWebSocketTest.kt | 59 +----------- build.gradle.kts | 2 +- canaries/example/build.gradle | 2 +- gradle/libs.versions.toml | 10 +- .../http/AWSRequestSignerInterceptor.kt | 4 +- testutils/build.gradle.kts | 2 +- 22 files changed, 46 insertions(+), 228 deletions(-) delete mode 100644 aws-predictions/src/main/java/com/amplifyframework/predictions/aws/models/liveness/InvalidSignatureException.kt diff --git a/aws-analytics-pinpoint/build.gradle.kts b/aws-analytics-pinpoint/build.gradle.kts index c3c99f6fc4..b563cc6805 100644 --- a/aws-analytics-pinpoint/build.gradle.kts +++ b/aws-analytics-pinpoint/build.gradle.kts @@ -14,7 +14,7 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" + id("org.jetbrains.kotlin.plugin.serialization") version "1.6.10" id("com.android.library") id("kotlin-android") } diff --git a/aws-auth-cognito/build.gradle.kts b/aws-auth-cognito/build.gradle.kts index 0a0a7e1496..7a002160da 100644 --- a/aws-auth-cognito/build.gradle.kts +++ b/aws-auth-cognito/build.gradle.kts @@ -14,7 +14,7 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" + id("org.jetbrains.kotlin.plugin.serialization") version "1.6.10" id("com.android.library") id("kotlin-android") } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt index d845168276..4d00bf04bd 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthService.kt @@ -18,9 +18,9 @@ package com.amplifyframework.auth.cognito import aws.sdk.kotlin.runtime.http.operation.customUserAgentMetadata import aws.sdk.kotlin.services.cognitoidentity.CognitoIdentityClient import aws.sdk.kotlin.services.cognitoidentityprovider.CognitoIdentityProviderClient -import aws.sdk.kotlin.services.cognitoidentityprovider.endpoints.CognitoIdentityProviderEndpointProvider import aws.smithy.kotlin.runtime.client.RequestInterceptorContext import aws.smithy.kotlin.runtime.client.endpoints.Endpoint +import aws.smithy.kotlin.runtime.client.endpoints.EndpointProvider import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor import com.amplifyframework.statemachine.codegen.data.AuthConfiguration @@ -36,7 +36,7 @@ interface AWSCognitoAuthService { CognitoIdentityProviderClient { this.region = it.region this.endpointProvider = it.endpoint?.let { endpoint -> - CognitoIdentityProviderEndpointProvider { Endpoint(endpoint) } + EndpointProvider { Endpoint(endpoint) } } this.interceptors += object : HttpInterceptor { override suspend fun modifyBeforeSerialization(context: RequestInterceptorContext): Any { diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt index 032082aab6..3fb992ce1f 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPluginTest.kt @@ -512,7 +512,6 @@ class RealAWSCognitoAuthPluginTest { authService.cognitoIdentityProviderClient?.getUser(any()) } returns GetUserResponse.invoke { this.userAttributes = userAttributes - username = "" } every { @@ -1807,8 +1806,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = listOf("SMS_MFA", "SOFTWARE_TOKEN_MFA") preferredMfaSetting = "SOFTWARE_TOKEN_MFA" - userAttributes = listOf() - username = "" } } plugin.fetchMFAPreference(onSuccess, onError) @@ -1845,8 +1842,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = null preferredMfaSetting = null - userAttributes = listOf() - username = "" } } plugin.updateMFAPreference(MFAPreference.ENABLED, MFAPreference.PREFERRED, onSuccess, onError) @@ -1892,8 +1887,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = listOf("SMS_MFA", "SOFTWARE_TOKEN_MFA") preferredMfaSetting = "SOFTWARE_TOKEN_MFA" - userAttributes = listOf() - username = "" } } @@ -1944,8 +1937,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = listOf("SMS_MFA", "SOFTWARE_TOKEN_MFA") preferredMfaSetting = "SMS_MFA" - userAttributes = listOf() - username = "" } } @@ -2049,8 +2040,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = null preferredMfaSetting = null - userAttributes = listOf() - username = "" } } @@ -2101,8 +2090,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = null preferredMfaSetting = null - userAttributes = listOf() - username = "" } } @@ -2153,8 +2140,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = null preferredMfaSetting = null - userAttributes = listOf() - username = "" } } @@ -2205,8 +2190,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = null preferredMfaSetting = null - userAttributes = listOf() - username = "" } } @@ -2257,8 +2240,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = null preferredMfaSetting = null - userAttributes = listOf() - username = "" } } @@ -2309,8 +2290,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = null preferredMfaSetting = null - userAttributes = listOf() - username = "" } } @@ -2361,8 +2340,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = null preferredMfaSetting = null - userAttributes = listOf() - username = "" } } @@ -2413,8 +2390,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = listOf("SOFTWARE_TOKEN_MFA") preferredMfaSetting = "SOFTWARE_TOKEN_MFA" - userAttributes = listOf() - username = "" } } @@ -2465,8 +2440,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = listOf("SMS_MFA") preferredMfaSetting = "SMS_MFA" - userAttributes = listOf() - username = "" } } @@ -2517,8 +2490,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = listOf("SMS_MFA") preferredMfaSetting = "SMS_MFA" - userAttributes = listOf() - username = "" } } @@ -2569,8 +2540,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = listOf("SOFTWARE_TOKEN_MFA") preferredMfaSetting = "SOFTWARE_TOKEN_MFA" - userAttributes = listOf() - username = "" } } @@ -2621,8 +2590,6 @@ class RealAWSCognitoAuthPluginTest { GetUserResponse.invoke { userMfaSettingList = listOf("SMS_MFA") preferredMfaSetting = "SMS_MFA" - userAttributes = listOf() - username = "" } } diff --git a/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt b/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt index 954e800442..9a6dfeabae 100644 --- a/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt +++ b/aws-auth-cognito/src/test/java/featureTest/utilities/CognitoMockFactory.kt @@ -77,7 +77,6 @@ class CognitoMockFactory( this.userConfirmed = if (responseObject.containsKey("userConfirmed")) { (responseObject["userConfirmed"] as? JsonPrimitive)?.boolean ?: false } else false - this.userSub = "" } } } @@ -140,7 +139,6 @@ class CognitoMockFactory( value = "000-000-0000" } ) - username = "" } } } diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/signUp/Sign_up_finishes_if_user_is_confirmed_in_the_first_step.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signUp/Sign_up_finishes_if_user_is_confirmed_in_the_first_step.json index 902a401f73..156fa4a187 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/testsuites/signUp/Sign_up_finishes_if_user_is_confirmed_in_the_first_step.json +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signUp/Sign_up_finishes_if_user_is_confirmed_in_the_first_step.json @@ -57,8 +57,7 @@ "signUpStep": "DONE", "additionalInfo": { } - }, - "userId": "" + } } } ] diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/signUp/Test_that_signup_invokes_proper_cognito_request_and_returns_success.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signUp/Test_that_signup_invokes_proper_cognito_request_and_returns_success.json index 8ea70d469e..767b69b838 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/testsuites/signUp/Test_that_signup_invokes_proper_cognito_request_and_returns_success.json +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/signUp/Test_that_signup_invokes_proper_cognito_request_and_returns_success.json @@ -61,8 +61,7 @@ "deliveryMedium": "EMAIL", "attributeName": "attributeName" } - }, - "userId": "" + } } } ] diff --git a/aws-auth-plugins-core/build.gradle.kts b/aws-auth-plugins-core/build.gradle.kts index 5c5a568869..94f9546f5c 100644 --- a/aws-auth-plugins-core/build.gradle.kts +++ b/aws-auth-plugins-core/build.gradle.kts @@ -14,7 +14,7 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" + id("org.jetbrains.kotlin.plugin.serialization") version "1.6.10" id("com.android.library") id("kotlin-android") } diff --git a/aws-logging-cloudwatch/build.gradle.kts b/aws-logging-cloudwatch/build.gradle.kts index d2295f9169..d5b57024f4 100644 --- a/aws-logging-cloudwatch/build.gradle.kts +++ b/aws-logging-cloudwatch/build.gradle.kts @@ -14,7 +14,7 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" + id("org.jetbrains.kotlin.plugin.serialization") version "1.6.10" id("com.android.library") id("kotlin-android") } diff --git a/aws-pinpoint-core/build.gradle.kts b/aws-pinpoint-core/build.gradle.kts index a35762d90e..a4030852f1 100644 --- a/aws-pinpoint-core/build.gradle.kts +++ b/aws-pinpoint-core/build.gradle.kts @@ -14,7 +14,7 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" + id("org.jetbrains.kotlin.plugin.serialization") version "1.6.10" id("com.android.library") id("kotlin-android") } diff --git a/aws-pinpoint-core/src/main/java/com/amplifyframework/pinpoint/core/EventRecorder.kt b/aws-pinpoint-core/src/main/java/com/amplifyframework/pinpoint/core/EventRecorder.kt index b289c8ba4c..519d223e36 100644 --- a/aws-pinpoint-core/src/main/java/com/amplifyframework/pinpoint/core/EventRecorder.kt +++ b/aws-pinpoint-core/src/main/java/com/amplifyframework/pinpoint/core/EventRecorder.kt @@ -40,7 +40,6 @@ import com.amplifyframework.pinpoint.core.database.PinpointDatabase import com.amplifyframework.pinpoint.core.endpointProfile.EndpointProfile import com.amplifyframework.pinpoint.core.models.PinpointEvent import com.amplifyframework.pinpoint.core.util.millisToIsoDate -import java.util.concurrent.atomic.AtomicBoolean import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -60,7 +59,7 @@ class EventRecorder( AWS_PINPOINT_ANALYTICS_LOG_NAMESPACE.format(EventRecorder::class.java.simpleName) ) ) { - private var isSyncInProgress = AtomicBoolean(false) + private var isSyncInProgress = false private val defaultMaxSubmissionAllowed = 3 private val defaultMaxSubmissionSize = 1024 * 100 private val serviceDefinedMaxEventsPerBatch: Int = 100 @@ -80,10 +79,12 @@ class EventRecorder( } } + @Synchronized internal suspend fun submitEvents(): List { return withContext(coroutineDispatcher) { val result = runCatching { - if (isSyncInProgress.compareAndSet(false, true)) { + if (!isSyncInProgress) { + isSyncInProgress = true processEvents() } else { logger.info("Sync is already in progress, skipping") @@ -92,11 +93,11 @@ class EventRecorder( } when { result.isSuccess -> { - isSyncInProgress.set(false) + isSyncInProgress = false result.getOrNull() ?: emptyList() } else -> { - isSyncInProgress.set(false) + isSyncInProgress = false logger.error("Failed to submit events ${result.exceptionOrNull()}") emptyList() } diff --git a/aws-predictions/build.gradle.kts b/aws-predictions/build.gradle.kts index 9db0c3a5e9..7b64243839 100644 --- a/aws-predictions/build.gradle.kts +++ b/aws-predictions/build.gradle.kts @@ -14,7 +14,7 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" + id("org.jetbrains.kotlin.plugin.serialization") version "1.8.10" id("com.android.library") id("kotlin-android") } diff --git a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/http/AWSV4Signer.kt b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/http/AWSV4Signer.kt index 2da96d3027..a93452907d 100755 --- a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/http/AWSV4Signer.kt +++ b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/http/AWSV4Signer.kt @@ -56,11 +56,6 @@ internal class AWSV4Signer { timeFormatter.isLenient = false } - // used in incorrect time flow where we send an invalid response first to get time offset - fun resetPriorSignature() { - priorSignature = "" - } - fun getSignedUri( uri: URI, credentials: Credentials, diff --git a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/http/LivenessWebSocket.kt b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/http/LivenessWebSocket.kt index ad4c8c1e61..2009ca60a3 100644 --- a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/http/LivenessWebSocket.kt +++ b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/http/LivenessWebSocket.kt @@ -46,9 +46,7 @@ import com.amplifyframework.util.UserAgent import java.net.URI import java.net.URLDecoder import java.nio.ByteBuffer -import java.text.SimpleDateFormat import java.util.Date -import java.util.Locale import java.util.UUID import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -78,24 +76,6 @@ internal class LivenessWebSocket( private val signer = AWSV4Signer() private var credentials: Credentials? = null - internal var offset = 0L - internal enum class ReconnectState { - INITIAL, - RECONNECTING, - RECONNECTING_AGAIN; - - companion object { - fun next(state: ReconnectState): ReconnectState { - return when (state) { - INITIAL -> RECONNECTING - RECONNECTING -> RECONNECTING_AGAIN - RECONNECTING_AGAIN -> RECONNECTING_AGAIN - } - } - } - } - internal var reconnectState = ReconnectState.INITIAL - @VisibleForTesting internal var webSocket: WebSocket? = null internal val challengeId = UUID.randomUUID().toString() @@ -111,24 +91,8 @@ internal class LivenessWebSocket( internal var webSocketListener = object : WebSocketListener() { override fun onOpen(webSocket: WebSocket, response: Response) { LOG.debug("WebSocket onOpen") - - // device time may be set incorrectly; read the header to skew time and retry - val sdf = SimpleDateFormat(datePattern, Locale.US) - val date = response.header("Date")?.let { sdf.parse(it) } - val tempOffset = if (date != null) { - date.time - adjustedDate() - } else 0 - - reconnectState = ReconnectState.next(reconnectState) - // if offset is > 5 minutes, server will reject the request - if (kotlin.math.abs(tempOffset) < FIVE_MINUTES) { - super.onOpen(webSocket, response) - this@LivenessWebSocket.webSocket = webSocket - } else { - // server will close this websocket, don't report that failure back - offset = tempOffset - start() - } + super.onOpen(webSocket, response) + this@LivenessWebSocket.webSocket = webSocket } override fun onMessage(webSocket: WebSocket, text: String) { @@ -146,10 +110,7 @@ internal class LivenessWebSocket( livenessResponse.serverSessionInformationEvent.sessionInformation ) } else if (livenessResponse.disconnectionEvent != null) { - this@LivenessWebSocket.webSocket?.close( - NORMAL_SOCKET_CLOSURE_STATUS_CODE, - "Liveness flow completed." - ) + this@LivenessWebSocket.webSocket?.close(1000, "Liveness flow completed.") } else { handleWebSocketError(livenessResponse) } @@ -169,9 +130,7 @@ internal class LivenessWebSocket( override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { LOG.debug("WebSocket onClosed") super.onClosed(webSocket, code, reason) - if (reconnectState == ReconnectState.RECONNECTING) { - // do nothing; we expected the server to close the connection - } else if (code != NORMAL_SOCKET_CLOSURE_STATUS_CODE && !clientStoppedSession) { + if (code != 1000 && !clientStoppedSession) { val faceLivenessException = webSocketError ?: PredictionsException( "An error occurred during the face liveness check.", reason @@ -197,14 +156,6 @@ internal class LivenessWebSocket( } fun start() { - if (reconnectState == ReconnectState.RECONNECTING_AGAIN) { - onErrorReceived.accept( - PredictionsException( - "Invalid device time", - "Too many attempts were made to correct device time" - ) - ) - } val userAgent = getUserAgent() val okHttpClient = OkHttpClient.Builder() @@ -222,10 +173,7 @@ internal class LivenessWebSocket( try { val credentials = credentialsProvider.resolve(emptyAttributes()) this@LivenessWebSocket.credentials = credentials - signer.resetPriorSignature() - val signedUri = signer.getSignedUri( - URI.create(endpoint), credentials, region, userAgent, adjustedDate() - ) + val signedUri = signer.getSignedUri(URI.create(endpoint), credentials, region, userAgent) if (signedUri != null) { val signedEndpoint = URLDecoder.decode(signedUri.toString(), "UTF-8") val signedEndpointNoSpaces = signedEndpoint.replace(" ", signer.encodedSpace) @@ -326,14 +274,14 @@ internal class LivenessWebSocket( videoStartTime: Long ) { // Send initial ClientSessionInformationEvent - videoStartTimestamp = adjustedDate(videoStartTime) + videoStartTimestamp = videoStartTime initialDetectedFace = BoundingBox( left = initialFaceRect.left / sessionInformation.videoWidth, top = initialFaceRect.top / sessionInformation.videoHeight, height = initialFaceRect.height() / sessionInformation.videoHeight, width = initialFaceRect.width() / sessionInformation.videoWidth ) - faceDetectedStart = adjustedDate(videoStartTime) + faceDetectedStart = videoStartTime val clientInfoEvent = ClientSessionInformationEvent( challenge = ClientChallenge( @@ -361,8 +309,8 @@ internal class LivenessWebSocket( initialFaceDetectedTimestamp = faceDetectedStart ), targetFace = TargetFace( - faceDetectedInTargetPositionStartTimestamp = adjustedDate(faceMatchedStart), - faceDetectedInTargetPositionEndTimestamp = adjustedDate(faceMatchedEnd), + faceDetectedInTargetPositionStartTimestamp = faceMatchedStart, + faceDetectedInTargetPositionEndTimestamp = faceMatchedEnd, boundingBox = BoundingBox( left = targetFaceRect.left / sessionInformation.videoWidth, top = targetFaceRect.top / sessionInformation.videoHeight, @@ -390,7 +338,7 @@ internal class LivenessWebSocket( currentColor = currentColor, previousColor = previousColor, sequenceNumber = sequenceNumber, - currentColorStartTimestamp = adjustedDate(colorStartTime) + currentColorStartTimestamp = colorStartTime ) ) ) @@ -410,7 +358,7 @@ internal class LivenessWebSocket( ":content-type" to "application/json" ) ) - val eventDate = Date(adjustedDate()) + val eventDate = Date() val signedPayload = signer.getSignedFrame( region, encodedPayload.array(), @@ -433,12 +381,12 @@ internal class LivenessWebSocket( fun sendVideoEvent(videoBytes: ByteArray, videoEventTime: Long) { if (videoBytes.isNotEmpty()) { - videoEndTimestamp = adjustedDate(videoEventTime) + videoEndTimestamp = videoEventTime } credentials?.let { val videoBuffer = ByteBuffer.wrap(videoBytes) val videoEvent = VideoEvent( - timestampMillis = adjustedDate(videoEventTime), + timestampMillis = videoEventTime, videoChunk = videoBuffer ) val videoJsonString = Json.encodeToString(videoEvent) @@ -451,7 +399,7 @@ internal class LivenessWebSocket( ":content-type" to "application/json" ) ) - val videoEventDate = Date(adjustedDate()) + val videoEventDate = Date() val signedVideoPayload = signer.getSignedFrame( region, encodedVideoPayload.array(), @@ -472,18 +420,11 @@ internal class LivenessWebSocket( } fun destroy() { - // Close gracefully - webSocket?.close(NORMAL_SOCKET_CLOSURE_STATUS_CODE, null) - } - - fun adjustedDate(date: Long = Date().time): Long { - return date + offset + // Close gracefully; 1000 means "normal closure" + webSocket?.close(1000, null) } companion object { - private const val NORMAL_SOCKET_CLOSURE_STATUS_CODE = 1000 - private val FIVE_MINUTES = 1000 * 60 * 5 - @VisibleForTesting val datePattern = "EEE, d MMM yyyy HH:mm:ss z" private val LOG = Amplify.Logging.logger(CategoryType.PREDICTIONS, "amplify:aws-predictions") } } diff --git a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/models/liveness/InvalidSignatureException.kt b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/models/liveness/InvalidSignatureException.kt deleted file mode 100644 index 42cfa685ef..0000000000 --- a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/models/liveness/InvalidSignatureException.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ -package com.amplifyframework.predictions.aws.models.liveness - -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -/** - * Constructs a new InvalidSignatureException with the specified error message. - * - * @param message Describes the error encountered. - */ -@Serializable -internal data class InvalidSignatureException( - @SerialName("Message") override val message: String -) : Exception(message) diff --git a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/models/liveness/LivenessResponseStream.kt b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/models/liveness/LivenessResponseStream.kt index 0d9c6e60d8..f6348ac9ad 100644 --- a/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/models/liveness/LivenessResponseStream.kt +++ b/aws-predictions/src/main/java/com/amplifyframework/predictions/aws/models/liveness/LivenessResponseStream.kt @@ -29,6 +29,5 @@ internal data class LivenessResponseStream( ServiceQuotaExceededException? = null, @SerialName("ServiceUnavailableException") val serviceUnavailableException: ServiceUnavailableException? = null, @SerialName("SessionNotFoundException") val sessionNotFoundException: SessionNotFoundException? = null, - @SerialName("AccessDeniedException") val accessDeniedException: AccessDeniedException? = null, - @SerialName("InvalidSignatureException") val invalidSignatureException: InvalidSignatureException? = null + @SerialName("AccessDeniedException") val accessDeniedException: AccessDeniedException? = null ) diff --git a/aws-predictions/src/test/java/com/amplifyframework/predictions/aws/http/LivenessWebSocketTest.kt b/aws-predictions/src/test/java/com/amplifyframework/predictions/aws/http/LivenessWebSocketTest.kt index 42756f0932..7ab4b99cf9 100644 --- a/aws-predictions/src/test/java/com/amplifyframework/predictions/aws/http/LivenessWebSocketTest.kt +++ b/aws-predictions/src/test/java/com/amplifyframework/predictions/aws/http/LivenessWebSocketTest.kt @@ -35,18 +35,11 @@ import com.amplifyframework.predictions.aws.models.liveness.ServerSessionInforma import com.amplifyframework.predictions.aws.models.liveness.SessionInformation import com.amplifyframework.predictions.aws.models.liveness.ValidationException import com.amplifyframework.predictions.models.FaceLivenessSessionInformation -import io.mockk.every import io.mockk.mockk -import io.mockk.mockkConstructor import io.mockk.verify import java.net.URL -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.TimeZone import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit -import kotlin.math.abs import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.resetMain @@ -55,7 +48,6 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import mockwebserver3.MockResponse import mockwebserver3.MockWebServer -import okhttp3.Headers import okhttp3.Protocol import okhttp3.Request import okhttp3.Response @@ -65,6 +57,7 @@ import okio.ByteString import okio.ByteString.Companion.toByteString import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Ignore @@ -196,12 +189,14 @@ internal class LivenessWebSocketTest { assertTrue(livenessWebSocket.webSocket != null) val originalRequest = livenessWebSocket.webSocket!!.request() + assertEquals("AWS4-HMAC-SHA256", originalRequest.url.queryParameter("X-Amz-Algorithm")) assertTrue( originalRequest.url.queryParameter("X-Amz-Credential")!!.endsWith("//rekognition/aws4_request") ) assertEquals("299", originalRequest.url.queryParameter("X-Amz-Expires")) assertEquals("host", originalRequest.url.queryParameter("X-Amz-SignedHeaders")) assertEquals("AWS4-HMAC-SHA256", originalRequest.url.queryParameter("X-Amz-Algorithm")) + assertNotNull("x-amz-user-agent") } @Test @@ -322,54 +317,6 @@ internal class LivenessWebSocketTest { assertEquals(livenessWebSocket.getUserAgent(), "$baseline $additional") } - @Test - fun `web socket detects clock skew from server response`() { - val livenessWebSocket = createLivenessWebSocket() - mockkConstructor(WebSocket::class) - val socket: WebSocket = mockk() - livenessWebSocket.webSocket = socket - val sdf = SimpleDateFormat(LivenessWebSocket.datePattern, Locale.US) - - // server responds saying time is actually 1 hour in the future - val oneHour = 1000 * 3600 - val futureDate = sdf.format(Date(Date().time + oneHour)) - val response: Response = mockk() - every { response.headers }.returns(Headers.headersOf("Date", futureDate)) - every { response.header("Date") }.returns(futureDate) - livenessWebSocket.webSocketListener.onOpen(socket, response) - - // now we should restart the websocket with an adjusted time - val openLatch = CountDownLatch(1) - val latchingListener = LatchingWebSocketResponseListener( - livenessWebSocket.webSocketListener, - openLatch = openLatch - ) - livenessWebSocket.webSocketListener = latchingListener - - server.enqueue(MockResponse().withWebSocketUpgrade(ServerWebSocketListener())) - server.start() - - openLatch.await(3, TimeUnit.SECONDS) - - assertTrue(livenessWebSocket.webSocket != null) - val originalRequest = livenessWebSocket.webSocket!!.request() - - // make sure that followup request sends offset date - val sdfGMT = SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US) - sdfGMT.timeZone = TimeZone.getTimeZone("GMT") - val sentDate = originalRequest.url.queryParameter("X-Amz-Date") ?.let { sdfGMT.parse(it) } - val diff = abs(Date().time - sentDate?.time!!) - assert(oneHour - 10000 < diff && diff < oneHour + 10000) - - // also make sure that followup request is valid - assertTrue( - originalRequest.url.queryParameter("X-Amz-Credential")!!.endsWith("//rekognition/aws4_request") - ) - assertEquals("299", originalRequest.url.queryParameter("X-Amz-Expires")) - assertEquals("host", originalRequest.url.queryParameter("X-Amz-SignedHeaders")) - assertEquals("AWS4-HMAC-SHA256", originalRequest.url.queryParameter("X-Amz-Algorithm")) - } - @Test @Ignore("Need to work on parsing the onMessage byteString from ServerWebSocketListener") fun `sendInitialFaceDetectedEvent test`() { diff --git a/build.gradle.kts b/build.gradle.kts index a02cc75d3c..0155bdb33b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,7 +25,7 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle:7.3.1") - classpath(kotlin("gradle-plugin", version = "1.9.10")) + classpath(kotlin("gradle-plugin", version = "1.7.10")) classpath("com.google.gms:google-services:4.3.15") classpath("org.jlleitschuh.gradle:ktlint-gradle:11.0.0") classpath("org.gradle:test-retry-gradle-plugin:1.4.1") diff --git a/canaries/example/build.gradle b/canaries/example/build.gradle index feb90d5b24..088af1ae8b 100644 --- a/canaries/example/build.gradle +++ b/canaries/example/build.gradle @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.9.10" + ext.kotlin_version = "1.8.0" repositories { google() jcenter() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 46a1474009..2059cd784a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,10 +15,10 @@ androidx-test-junit = "1.1.2" androidx-test-orchestrator = "1.3.0" androidx-test-runner = "1.3.0" androidx-workmanager = "2.7.1" -aws-kotlin = "0.33.1-beta" # ensure proper aws-smithy version also set +aws-kotlin = "0.29.1-beta" # ensure proper aws-smithy version also set aws-sdk = "2.62.2" -aws-smithy = "0.28.1" # ensure proper aws-kotlin version also set -coroutines = "1.7.3" +aws-smithy = "0.25.0" # ensure proper aws-kotlin version also set +coroutines = "1.6.3" desugar = "1.2.0" espresso = "3.3.0" fcm = "23.1.0" @@ -27,8 +27,8 @@ json = "20210307" jsonassert = "1.5.0" junit = "4.13.2" kotest = "5.6.2" -kotlin = "1.9.10" -kotlin-serialization = "1.6.0" +kotlin = "1.7.10" +kotlin-serialization = "1.3.3" maplibre = "9.6.0" maplibre-annotations = "1.0.0" material = "1.8.0" diff --git a/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt b/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt index 6877361f87..1a73511c71 100644 --- a/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt +++ b/maplibre-adapter/src/main/java/com/amplifyframework/geo/maplibre/http/AWSRequestSignerInterceptor.kt @@ -19,8 +19,8 @@ import aws.smithy.kotlin.runtime.InternalApi import aws.smithy.kotlin.runtime.auth.awssigning.AwsSigningConfig import aws.smithy.kotlin.runtime.auth.awssigning.DefaultAwsSigner import aws.smithy.kotlin.runtime.http.Headers as AwsHeaders -import aws.smithy.kotlin.runtime.http.HttpBody import aws.smithy.kotlin.runtime.http.HttpMethod +import aws.smithy.kotlin.runtime.http.content.ByteArrayContent import aws.smithy.kotlin.runtime.http.request.HttpRequest import aws.smithy.kotlin.runtime.net.Host import aws.smithy.kotlin.runtime.net.QueryParameters @@ -125,7 +125,7 @@ internal class AWSRequestSignerInterceptor( ) val bodyBytes: ByteArray = getBytes(request.body) - val body2 = HttpBody.fromBytes(bodyBytes) + val body2 = ByteArrayContent(bodyBytes) val method = HttpMethod.parse(request.method) val awsRequest = HttpRequest(method, httpUrl, headers, body2) diff --git a/testutils/build.gradle.kts b/testutils/build.gradle.kts index 0bfecd69d3..63a600e402 100644 --- a/testutils/build.gradle.kts +++ b/testutils/build.gradle.kts @@ -14,7 +14,7 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" + id("org.jetbrains.kotlin.plugin.serialization") version "1.6.10" id("com.android.library") id("kotlin-android") }