From 7b8facfecb23bae16146ca31d008054828940e0d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 16 Oct 2023 17:41:06 -0300 Subject: [PATCH 001/144] Define PasskeyRestClient --- .../fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt new file mode 100644 index 0000000000..c4d2e530e1 --- /dev/null +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -0,0 +1,4 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.wc.passkey + +class PasskeyRestClient { +} \ No newline at end of file From e339c5cea5809bd8a177348a104de7e69214d42a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 13:09:24 -0300 Subject: [PATCH 002/144] Define WebauthnChallengeInfo model --- .../rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt new file mode 100644 index 0000000000..7d754b0f90 --- /dev/null +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt @@ -0,0 +1,8 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.wc.passkey + +data class WebauthnChallengeInfo( + val challenge: String, + val rpId: String, + val twoStepNonce: String, + val allowedCredentials: List +) From 1ed8b71dcf7076973543d2eb380388621dd57450 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 13:20:38 -0300 Subject: [PATCH 003/144] Add endpoint values to PasskeyRestClient --- .../fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index c4d2e530e1..c7cffd30a1 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -1,4 +1,9 @@ package org.wordpress.android.fluxc.network.rest.wpcom.wc.passkey class PasskeyRestClient { + companion object { + const val baseURLWithAction = "wp-login.php?action" + const val challengeEndpoint = "webauthn-challenge-endpoint" + const val authEndpoint = "webauthn-authentication-endpoint" + } } \ No newline at end of file From 71cf4aff7df3d914eef2cbbf327b26c4715598cf Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 19:20:04 -0300 Subject: [PATCH 004/144] Define basic challenge request method --- .../wpcom/wc/passkey/PasskeyRestClient.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index c7cffd30a1..e758121761 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -1,6 +1,29 @@ package org.wordpress.android.fluxc.network.rest.wpcom.wc.passkey +import org.wordpress.android.fluxc.model.SiteModel +import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooPayload + class PasskeyRestClient { + fun requestWebauthnChallenge( + userId: Long, + twoStepNonce: String + ): WooPayload { + val parameters = mapOf( + "user_id" to userId.toString(), + "two_step_nonce" to twoStepNonce, + "auth_type" to "webauthn" + ) + + return WooPayload( + WebauthnChallengeInfo( + challenge = "challenge", + rpId = "rpId", + twoStepNonce = "twoStepNonce", + allowedCredentials = listOf("allowedCredentials") + ) + ) + } + companion object { const val baseURLWithAction = "wp-login.php?action" const val challengeEndpoint = "webauthn-challenge-endpoint" From 89b84c2a26972166c21b134f4f012a24fa6a67c6 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 19:35:18 -0300 Subject: [PATCH 005/144] Configure PasskeyRestClient constructor --- .../wpcom/wc/passkey/PasskeyRestClient.kt | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index e758121761..53fbdda2bb 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -1,9 +1,31 @@ package org.wordpress.android.fluxc.network.rest.wpcom.wc.passkey -import org.wordpress.android.fluxc.model.SiteModel +import android.content.Context +import com.android.volley.RequestQueue +import com.android.volley.Response +import org.wordpress.android.fluxc.Dispatcher +import org.wordpress.android.fluxc.network.UserAgent +import org.wordpress.android.fluxc.network.rest.wpcom.BaseWPComRestClient +import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest +import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener +import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError +import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooPayload +import javax.inject.Inject -class PasskeyRestClient { +class PasskeyRestClient @Inject constructor( + context: Context, + dispatcher: Dispatcher, + requestQueue: RequestQueue, + accessToken: AccessToken, + userAgent: UserAgent +): BaseWPComRestClient( + context, + dispatcher, + requestQueue, + accessToken, + userAgent +) { fun requestWebauthnChallenge( userId: Long, twoStepNonce: String From 49ec224275c1ddfee4f681dc2c7605a5f21e5ffa Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 19:37:16 -0300 Subject: [PATCH 006/144] Implement basic challenge request --- .../wpcom/wc/passkey/PasskeyRestClient.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index 53fbdda2bb..688f0b6d54 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -36,6 +36,24 @@ class PasskeyRestClient @Inject constructor( "auth_type" to "webauthn" ) + triggerAccountRequest( + url = "", + body = parameters, + onSuccess = { response -> + val challengeInfo = WebauthnChallengeInfo( + challenge = response["challenge"] as String, + rpId = response["rpId"] as String, + twoStepNonce = response["twoStepNonce"] as String, + allowedCredentials = response["allowedCredentials"] as List + ) + + WooPayload(challengeInfo) + }, + onFailure = { error -> + WooPayload(error) + } + ) + return WooPayload( WebauthnChallengeInfo( challenge = "challenge", @@ -46,6 +64,26 @@ class PasskeyRestClient @Inject constructor( ) } + fun triggerAccountRequest( + url: String, + body: Map, + onSuccess: (response: Map) -> Unit, + onFailure: (error: WPComGsonNetworkError) -> Unit + ) { + val successListener = Response.Listener> { onSuccess(it) } + val failureListener = WPComErrorListener { onFailure(it) } + + val request = WPComGsonRequest.buildPostRequest( + url, + body, + Map::class.java, + successListener, + failureListener + ) + + add(request) + } + companion object { const val baseURLWithAction = "wp-login.php?action" const val challengeEndpoint = "webauthn-challenge-endpoint" From 1e34a473e203eddfaf51f074445830fa8b699d6e Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 19:39:32 -0300 Subject: [PATCH 007/144] Refactor challenge info construction --- .../wpcom/wc/passkey/PasskeyRestClient.kt | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index 688f0b6d54..21e64bf9e7 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -39,19 +39,8 @@ class PasskeyRestClient @Inject constructor( triggerAccountRequest( url = "", body = parameters, - onSuccess = { response -> - val challengeInfo = WebauthnChallengeInfo( - challenge = response["challenge"] as String, - rpId = response["rpId"] as String, - twoStepNonce = response["twoStepNonce"] as String, - allowedCredentials = response["allowedCredentials"] as List - ) - - WooPayload(challengeInfo) - }, - onFailure = { error -> - WooPayload(error) - } + onSuccess = { WooPayload(it.asChallengeInfo) }, + onFailure = { WooPayload(it) } ) return WooPayload( @@ -64,7 +53,7 @@ class PasskeyRestClient @Inject constructor( ) } - fun triggerAccountRequest( + private fun triggerAccountRequest( url: String, body: Map, onSuccess: (response: Map) -> Unit, @@ -84,6 +73,15 @@ class PasskeyRestClient @Inject constructor( add(request) } + private val Map.asChallengeInfo: WebauthnChallengeInfo + get() = WebauthnChallengeInfo( + challenge = this["challenge"] as String, + rpId = this["rpId"] as String, + twoStepNonce = this["twoStepNonce"] as String, + allowedCredentials = this["allowedCredentials"] as List + ) + + companion object { const val baseURLWithAction = "wp-login.php?action" const val challengeEndpoint = "webauthn-challenge-endpoint" From 28b111e2577ba49027a4ea76639c53fbba3d02bc Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 20:04:32 -0300 Subject: [PATCH 008/144] Improve data parsing null safety --- .../fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt | 4 +++- .../network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index 21e64bf9e7..b79e4b5ec8 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -78,7 +78,9 @@ class PasskeyRestClient @Inject constructor( challenge = this["challenge"] as String, rpId = this["rpId"] as String, twoStepNonce = this["twoStepNonce"] as String, - allowedCredentials = this["allowedCredentials"] as List + allowedCredentials = this["allowedCredentials"] + .run { this as? List<*> } + ?.map { it as String } ) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt index 7d754b0f90..10017e4a6e 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt @@ -4,5 +4,5 @@ data class WebauthnChallengeInfo( val challenge: String, val rpId: String, val twoStepNonce: String, - val allowedCredentials: List + val allowedCredentials: List? ) From 0ce2706ef3f2892fcc4e71dff0594a227865593f Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 20:06:30 -0300 Subject: [PATCH 009/144] Set challenge URL configuration --- .../network/rest/wpcom/wc/passkey/PasskeyRestClient.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index b79e4b5ec8..087630191d 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -37,7 +37,7 @@ class PasskeyRestClient @Inject constructor( ) triggerAccountRequest( - url = "", + url = webauthnChallengeEndpointUrl, body = parameters, onSuccess = { WooPayload(it.asChallengeInfo) }, onFailure = { WooPayload(it) } @@ -85,8 +85,9 @@ class PasskeyRestClient @Inject constructor( companion object { - const val baseURLWithAction = "wp-login.php?action" - const val challengeEndpoint = "webauthn-challenge-endpoint" - const val authEndpoint = "webauthn-authentication-endpoint" + private const val baseURLWithAction = "wp-login.php?action" + private const val challengeEndpoint = "webauthn-challenge-endpoint" + private const val authEndpoint = "webauthn-authentication-endpoint" + const val webauthnChallengeEndpointUrl = "$baseURLWithAction=$challengeEndpoint" } } \ No newline at end of file From af406d8d65098432bc96e79ef8da4fb35aa52f8d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 20:23:03 -0300 Subject: [PATCH 010/144] Introduce continuation wrapping around callbacks for PasskeyRestClient --- .../wpcom/wc/passkey/PasskeyRestClient.kt | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index 087630191d..44f292f4c5 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -10,8 +10,9 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken -import org.wordpress.android.fluxc.network.rest.wpcom.wc.WooPayload import javax.inject.Inject +import kotlin.Exception +import kotlin.coroutines.suspendCoroutine class PasskeyRestClient @Inject constructor( context: Context, @@ -19,38 +20,37 @@ class PasskeyRestClient @Inject constructor( requestQueue: RequestQueue, accessToken: AccessToken, userAgent: UserAgent -): BaseWPComRestClient( +) : BaseWPComRestClient( context, dispatcher, requestQueue, accessToken, userAgent ) { - fun requestWebauthnChallenge( + suspend fun requestWebauthnChallenge( userId: Long, twoStepNonce: String - ): WooPayload { + ): WebauthnChallengeInfo { val parameters = mapOf( "user_id" to userId.toString(), "two_step_nonce" to twoStepNonce, "auth_type" to "webauthn" ) - triggerAccountRequest( - url = webauthnChallengeEndpointUrl, - body = parameters, - onSuccess = { WooPayload(it.asChallengeInfo) }, - onFailure = { WooPayload(it) } - ) + return suspendCoroutine { cont -> + triggerAccountRequest( + url = webauthnChallengeEndpointUrl, + body = parameters, + onSuccess = { + cont.resumeWith(Result.success(it.asChallengeInfo)) - return WooPayload( - WebauthnChallengeInfo( - challenge = "challenge", - rpId = "rpId", - twoStepNonce = "twoStepNonce", - allowedCredentials = listOf("allowedCredentials") + }, + onFailure = { + val exception = Exception(it.message) + cont.resumeWith(Result.failure(exception)) + } ) - ) + } } private fun triggerAccountRequest( @@ -83,7 +83,6 @@ class PasskeyRestClient @Inject constructor( ?.map { it as String } ) - companion object { private const val baseURLWithAction = "wp-login.php?action" private const val challengeEndpoint = "webauthn-challenge-endpoint" From ee5825656c83f500831989f9f7dcb7e94c3945a3 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 20:30:23 -0300 Subject: [PATCH 011/144] Add remaining parameters to requestWebauthnChallenge --- .../network/rest/wpcom/wc/passkey/PasskeyRestClient.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index 44f292f4c5..b1c17a9885 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -29,12 +29,16 @@ class PasskeyRestClient @Inject constructor( ) { suspend fun requestWebauthnChallenge( userId: Long, + clientId: Long, + secret: String, twoStepNonce: String ): WebauthnChallengeInfo { val parameters = mapOf( "user_id" to userId.toString(), - "two_step_nonce" to twoStepNonce, - "auth_type" to "webauthn" + "client_id" to clientId.toString(), + "client_secret" to secret, + "auth_type" to "webauthn", + "two_step_nonce" to twoStepNonce ) return suspendCoroutine { cont -> From 766abf01d63a894579479b9e8dc80dbd049442d1 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 20:45:36 -0300 Subject: [PATCH 012/144] Introduce webauthn signature authentication function --- .../wpcom/wc/passkey/PasskeyRestClient.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index b1c17a9885..70cc9def92 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -1,6 +1,7 @@ package org.wordpress.android.fluxc.network.rest.wpcom.wc.passkey import android.content.Context +import android.util.Base64 import com.android.volley.RequestQueue import com.android.volley.Response import org.wordpress.android.fluxc.Dispatcher @@ -57,6 +58,29 @@ class PasskeyRestClient @Inject constructor( } } + suspend fun authenticateWebauthnSignature( + userId: Long, + twoStepNonce: String, + credentialId: ByteArray, + clientDataJson: ByteArray, + authenticatorData: ByteArray, + signature: ByteArray, + userHandle: ByteArray + ) { + val clientData = mapOf( + "id" to Base64.encode(credentialId, Base64.DEFAULT), + "rawId" to Base64.encode(credentialId, Base64.DEFAULT), + "type" to "public-key", + "clientExtensionResults" to mapOf(), + "response" to mapOf( + "clientDataJSON" to Base64.encode(clientDataJson, Base64.DEFAULT), + "authenticatorData" to Base64.encode(authenticatorData, Base64.DEFAULT), + "signature" to Base64.encode(signature, Base64.DEFAULT), + "userHandle" to Base64.encode(userHandle, Base64.DEFAULT) + ) + ) + } + private fun triggerAccountRequest( url: String, body: Map, From ef3d06b9a5a230036e1579d3aace65357fbf5f94 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 20:52:24 -0300 Subject: [PATCH 013/144] Trigger signature authentication request in PasskeyRestClient --- .../wpcom/wc/passkey/PasskeyRestClient.kt | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index 70cc9def92..4eb4f07485 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -4,6 +4,7 @@ import android.content.Context import android.util.Base64 import com.android.volley.RequestQueue import com.android.volley.Response +import com.google.gson.Gson import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.network.UserAgent import org.wordpress.android.fluxc.network.rest.wpcom.BaseWPComRestClient @@ -60,13 +61,15 @@ class PasskeyRestClient @Inject constructor( suspend fun authenticateWebauthnSignature( userId: Long, + clientId: Long, + secret: String, twoStepNonce: String, credentialId: ByteArray, clientDataJson: ByteArray, authenticatorData: ByteArray, signature: ByteArray, userHandle: ByteArray - ) { + ): String { val clientData = mapOf( "id" to Base64.encode(credentialId, Base64.DEFAULT), "rawId" to Base64.encode(credentialId, Base64.DEFAULT), @@ -78,7 +81,32 @@ class PasskeyRestClient @Inject constructor( "signature" to Base64.encode(signature, Base64.DEFAULT), "userHandle" to Base64.encode(userHandle, Base64.DEFAULT) ) + ).let { Gson().toJson(it) } + + val parameters = mapOf( + "user_id" to userId.toString(), + "client_id" to clientId, + "client_secret" to secret, + "auth_type" to "webauthn", + "two_step_nonce" to twoStepNonce, + "client_data" to clientData, + "get_bearer_token" to true, + "create_2fa_cookies_only" to true ) + + return suspendCoroutine { cont -> + triggerAccountRequest( + url = webauthnAuthEndpointUrl, + body = parameters, + onSuccess = { + cont.resumeWith(Result.success("")) + }, + onFailure = { + val exception = Exception(it.message) + cont.resumeWith(Result.failure(exception)) + } + ) + } } private fun triggerAccountRequest( @@ -116,5 +144,6 @@ class PasskeyRestClient @Inject constructor( private const val challengeEndpoint = "webauthn-challenge-endpoint" private const val authEndpoint = "webauthn-authentication-endpoint" const val webauthnChallengeEndpointUrl = "$baseURLWithAction=$challengeEndpoint" + const val webauthnAuthEndpointUrl = "$baseURLWithAction=$authEndpoint" } } \ No newline at end of file From 4013c8325960d66b810accbf2482db63cb788bec Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 21:05:05 -0300 Subject: [PATCH 014/144] Finish PasskeyRestClient.authenticateWebauthnSignature operation --- .../network/rest/wpcom/wc/passkey/PasskeyRestClient.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt index 4eb4f07485..ac4ac18316 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt @@ -99,7 +99,7 @@ class PasskeyRestClient @Inject constructor( url = webauthnAuthEndpointUrl, body = parameters, onSuccess = { - cont.resumeWith(Result.success("")) + cont.resumeWith(Result.success(it.asBearerToken)) }, onFailure = { val exception = Exception(it.message) @@ -139,6 +139,12 @@ class PasskeyRestClient @Inject constructor( ?.map { it as String } ) + private val Map.asBearerToken: String + get() = this["data"] + ?.run { this as? Map<*, *> } + ?.let { this["bearer_token"] as? String } + .orEmpty() + companion object { private const val baseURLWithAction = "wp-login.php?action" private const val challengeEndpoint = "webauthn-challenge-endpoint" From 234701817d55ac6f953c44626f01374ebe05a296 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 21:25:24 -0300 Subject: [PATCH 015/144] Move Passkey code to WP package --- .../fluxc/network/rest/wpcom/auth}/passkey/PasskeyRestClient.kt | 2 +- .../network/rest/wpcom/auth}/passkey/WebauthnChallengeInfo.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename {plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc => fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth}/passkey/PasskeyRestClient.kt (98%) rename {plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc => fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth}/passkey/WebauthnChallengeInfo.kt (69%) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt similarity index 98% rename from plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt rename to fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index ac4ac18316..20b2f46950 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.fluxc.network.rest.wpcom.wc.passkey +package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey import android.content.Context import android.util.Base64 diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt similarity index 69% rename from plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt rename to fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt index 10017e4a6e..36bf4b7f1c 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/passkey/WebauthnChallengeInfo.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.fluxc.network.rest.wpcom.wc.passkey +package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey data class WebauthnChallengeInfo( val challenge: String, From 2e958b388b4b90a949183fb10035e360258eb296 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 21:27:21 -0300 Subject: [PATCH 016/144] Add PasskeyRestClient in the AccountStore --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 0c2f593353..18261d8c76 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -39,6 +39,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; import org.wordpress.android.util.AppLog; @@ -831,16 +832,18 @@ public static NewUserErrorType fromString(String string) { private AccountModel mAccount; private AccessToken mAccessToken; private SelfHostedEndpointFinder mSelfHostedEndpointFinder; + private PasskeyRestClient mPasskeyRestClient; @Inject public AccountStore(Dispatcher dispatcher, AccountRestClient accountRestClient, SelfHostedEndpointFinder selfHostedEndpointFinder, Authenticator authenticator, - AccessToken accessToken) { + AccessToken accessToken, PasskeyRestClient passkeyRestClient) { super(dispatcher); mAuthenticator = authenticator; mAccountRestClient = accountRestClient; mSelfHostedEndpointFinder = selfHostedEndpointFinder; mAccount = loadAccount(); mAccessToken = accessToken; + mPasskeyRestClient = passkeyRestClient; } @Override From 4841d4cb1437da61d90e4fcfa745b615b2330cd0 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 17 Oct 2023 21:28:58 -0300 Subject: [PATCH 017/144] Define PasskeyRestClientTest --- .../auth/passkey/PasskeyRestClientTest.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt diff --git a/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt b/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt new file mode 100644 index 0000000000..30b0193bc2 --- /dev/null +++ b/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt @@ -0,0 +1,19 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey + +import org.junit.Before +import org.mockito.kotlin.mock + +class PasskeyRestClientTest { + private lateinit var sut: PasskeyRestClient + + @Before + fun setUp() { + sut = PasskeyRestClient( + context = mock(), + dispatcher = mock(), + requestQueue = mock(), + accessToken = mock(), + userAgent = mock() + ) + } +} \ No newline at end of file From 0064200a3a750d4d717ab97780ce172e4a91cf07 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 18 Oct 2023 01:10:07 -0300 Subject: [PATCH 018/144] Add Singleton inject annotation to PasskeyRestClient --- .../fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 20b2f46950..10eafb158a 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -13,9 +13,11 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErro import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken import javax.inject.Inject +import javax.inject.Singleton import kotlin.Exception import kotlin.coroutines.suspendCoroutine +@Singleton class PasskeyRestClient @Inject constructor( context: Context, dispatcher: Dispatcher, From 20793e0416670b6386b63a137e110dceb53ce3dc Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 18 Oct 2023 01:39:29 -0300 Subject: [PATCH 019/144] Add missing qualifier to PasskeyRestClient --- .../network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 10eafb158a..8fc2b4bce2 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -13,15 +13,15 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErro import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken import javax.inject.Inject +import javax.inject.Named import javax.inject.Singleton -import kotlin.Exception import kotlin.coroutines.suspendCoroutine @Singleton class PasskeyRestClient @Inject constructor( context: Context, dispatcher: Dispatcher, - requestQueue: RequestQueue, + @Named("regular") requestQueue: RequestQueue, accessToken: AccessToken, userAgent: UserAgent ) : BaseWPComRestClient( From d4b69540bdbdd029795e13c21b4e5102855e013d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 18 Oct 2023 01:50:27 -0300 Subject: [PATCH 020/144] Fix detekt issues --- .../fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 3 ++- .../network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 8fc2b4bce2..d6aa4e1011 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -61,6 +61,7 @@ class PasskeyRestClient @Inject constructor( } } + @Suppress("LongParameterList") suspend fun authenticateWebauthnSignature( userId: Long, clientId: Long, @@ -154,4 +155,4 @@ class PasskeyRestClient @Inject constructor( const val webauthnChallengeEndpointUrl = "$baseURLWithAction=$challengeEndpoint" const val webauthnAuthEndpointUrl = "$baseURLWithAction=$authEndpoint" } -} \ No newline at end of file +} diff --git a/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt b/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt index 30b0193bc2..a336c743a7 100644 --- a/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt +++ b/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt @@ -16,4 +16,4 @@ class PasskeyRestClientTest { userAgent = mock() ) } -} \ No newline at end of file +} From a34956327b2765a5cefcb2026a6565047b5c902b Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 18 Oct 2023 04:36:52 -0300 Subject: [PATCH 021/144] Fix checkstyle issues --- .../fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index d6aa4e1011..c63d0ee0a2 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -51,7 +51,6 @@ class PasskeyRestClient @Inject constructor( body = parameters, onSuccess = { cont.resumeWith(Result.success(it.asChallengeInfo)) - }, onFailure = { val exception = Exception(it.message) From cbca4a3dfdac0750a8f02497249b7d03fb175b0a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 18 Oct 2023 17:32:27 -0300 Subject: [PATCH 022/144] Fix AccountStoreTest --- .../fluxc/account/AccountStoreTest.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java b/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java index 75be3d6fb7..03ac38ae8d 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java +++ b/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java @@ -21,6 +21,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.account.AccountRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; import org.wordpress.android.fluxc.persistence.WellSqlConfig; import org.wordpress.android.fluxc.store.AccountStore; @@ -50,17 +51,19 @@ public void testLoadAccount() { testAccount.setAboutMe("testAboutMe"); AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), - getMockSelfHostedEndpointFinder(), getMockAuthenticator(), getMockAccessToken(true)); + getMockSelfHostedEndpointFinder(), getMockAuthenticator(), + getMockAccessToken(true), getMockPasskeyRestClient()); Assert.assertEquals(testAccount, testStore.getAccount()); } @Test public void testHasAccessToken() { AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), - getMockSelfHostedEndpointFinder(), getMockAuthenticator(), getMockAccessToken(true)); + getMockSelfHostedEndpointFinder(), getMockAuthenticator(), + getMockAccessToken(true), getMockPasskeyRestClient()); Assert.assertTrue(testStore.hasAccessToken()); testStore = new AccountStore(new Dispatcher(), getMockRestClient(), getMockSelfHostedEndpointFinder(), - getMockAuthenticator(), getMockAccessToken(false)); + getMockAuthenticator(), getMockAccessToken(false), getMockPasskeyRestClient()); Assert.assertFalse(testStore.hasAccessToken()); } @@ -70,12 +73,13 @@ public void testIsSignedIn() { testAccount.setVisibleSiteCount(0); AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), - getMockSelfHostedEndpointFinder(), getMockAuthenticator(), getMockAccessToken(false)); + getMockSelfHostedEndpointFinder(), getMockAuthenticator(), + getMockAccessToken(false), getMockPasskeyRestClient()); Assert.assertFalse(testStore.hasAccessToken()); testAccount.setVisibleSiteCount(1); AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); testStore = new AccountStore(new Dispatcher(), getMockRestClient(), getMockSelfHostedEndpointFinder(), - getMockAuthenticator(), getMockAccessToken(true)); + getMockAuthenticator(), getMockAccessToken(true), getMockPasskeyRestClient()); Assert.assertTrue(testStore.hasAccessToken()); } @@ -87,7 +91,8 @@ public void testSignOut() throws Exception { testAccount.setUserId(24); AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), - getMockSelfHostedEndpointFinder(), getMockAuthenticator(), testToken); + getMockSelfHostedEndpointFinder(), getMockAuthenticator(), + testToken, getMockPasskeyRestClient()); Assert.assertTrue(testStore.hasAccessToken()); // Signout is private (and it should remain private) Method privateMethod = AccountStore.class.getDeclaredMethod("signOut"); @@ -128,4 +133,8 @@ private AccessToken getMockAccessToken(boolean exists) { private SelfHostedEndpointFinder getMockSelfHostedEndpointFinder() { return Mockito.mock(SelfHostedEndpointFinder.class); } + + private PasskeyRestClient getMockPasskeyRestClient() { + return Mockito.mock(PasskeyRestClient.class); + } } From f2f9094040773432eb7a94d50a5af95c518ceee2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 18 Oct 2023 20:42:04 -0300 Subject: [PATCH 023/144] Adjust authentication to account for security key presence --- .../android/fluxc/store/AccountStore.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 18261d8c76..dadb5d34bb 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -512,6 +512,7 @@ public enum AuthenticationErrorType { INVALID_REQUEST, INVALID_TOKEN, NEEDS_2FA, + NEEDS_SECURITY_KEY, UNSUPPORTED_GRANT_TYPE, UNSUPPORTED_RESPONSE_TYPE, UNKNOWN_TOKEN, @@ -1286,11 +1287,19 @@ private void authenticate(final AuthenticatePayload payload) { payload.shouldSendTwoStepSms, new Authenticator.Listener() { @Override public void onResponse(Token token) { - mAccessToken.set(token.getAccessToken()); - if (payload.nextAction != null) { - mDispatcher.dispatch(payload.nextAction); + // Check if token exists, if not, check for security key + if (token.getAccessToken() != null) { + mAccessToken.set(token.getAccessToken()); + if (payload.nextAction != null) { + mDispatcher.dispatch(payload.nextAction); + } + emitChange(new OnAuthenticationChanged()); + } else if (token.getUserId() != null) { + //TODO: Trigger security key request + } else { + OnAuthenticationChanged event = new OnAuthenticationChanged(); + event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); } - emitChange(new OnAuthenticationChanged()); } }, new Authenticator.ErrorListener() { @Override From db2ef19787fe7fc1657b8fd6c4d0d0b90a134b81 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 18 Oct 2023 20:42:40 -0300 Subject: [PATCH 024/144] Update Token type to support webauthn values --- .../network/rest/wpcom/auth/Authenticator.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 035d230c34..16aabacc4d 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -50,6 +50,7 @@ public class Authenticator { public static final String GRANT_TYPE_PARAM_NAME = "grant_type"; public static final String USERNAME_PARAM_NAME = "username"; public static final String PASSWORD_PARAM_NAME = "password"; + public static final String WITH_AUTH_TYPES = "with_auth_types"; public static final String PASSWORD_GRANT_TYPE = "password"; public static final String BEARER_GRANT_TYPE = "bearer"; @@ -90,8 +91,12 @@ public AuthEmailResponsePayload(boolean isSignup) { mAppSecrets = secrets; } - public void authenticate(String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, - Listener listener, ErrorListener errorListener) { + public void authenticate(String username, + String password, + String twoStepCode, + boolean shouldSendTwoStepSMS, + Listener listener, + ErrorListener errorListener) { TokenRequest tokenRequest = makeRequest(username, password, twoStepCode, shouldSendTwoStepSMS, listener, errorListener); mRequestQueue.add(tokenRequest); @@ -153,6 +158,7 @@ public PasswordRequest(String appId, String appSecret, String username, String p mParams.put(USERNAME_PARAM_NAME, username); mParams.put(PASSWORD_PARAM_NAME, password); mParams.put(GRANT_TYPE_PARAM_NAME, PASSWORD_GRANT_TYPE); + mParams.put(WITH_AUTH_TYPES, "true"); if (!TextUtils.isEmpty(twoStepCode)) { mParams.put("wpcom_otp", twoStepCode); @@ -186,6 +192,8 @@ public static class Token { private String mAccessToken; private String mSiteUrl; private String mSiteId; + private String mUserId; + private String twoStepWebauthnNonce; public Token(String accessToken, String siteUrl, String siteId, String scope, String tokenType) { mAccessToken = accessToken; @@ -203,6 +211,10 @@ public String toString() { return getAccessToken(); } + public String getUserId() { + return mUserId; + } + public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { return new Token(tokenJSON.getString(ACCESS_TOKEN_FIELD_NAME), tokenJSON.getString(SITE_URL_FIELD_NAME), tokenJSON.getString(SITE_ID_FIELD_NAME), tokenJSON.getString(SCOPE_FIELD_NAME), tokenJSON.getString( From 7650dafd6fbf5bfd59c42a5d73f6b8c8d634e926 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 18 Oct 2023 20:45:03 -0300 Subject: [PATCH 025/144] Allow Token to be built with webauthn values --- .../network/rest/wpcom/auth/Authenticator.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 16aabacc4d..c37fdf2f9c 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -186,6 +186,9 @@ public static class Token { private static final String SITE_URL_FIELD_NAME = "blog_url"; private static final String SCOPE_FIELD_NAME = "scope"; private static final String SITE_ID_FIELD_NAME = "blog_id"; + private static final String DATA = "data"; + private static final String USER_ID = "user_id"; + private static final String TWO_STEP_WEBAUTHN_NONCE = "two_step_webauthn_nonce"; private String mTokenType; private String mScope; @@ -195,12 +198,15 @@ public static class Token { private String mUserId; private String twoStepWebauthnNonce; - public Token(String accessToken, String siteUrl, String siteId, String scope, String tokenType) { + public Token(String accessToken, String siteUrl, String siteId, String scope, + String tokenType, String userId, String twoStepWebauthnNonce) { mAccessToken = accessToken; mSiteUrl = siteUrl; mSiteId = siteId; mScope = scope; mTokenType = tokenType; + mUserId = userId; + this.twoStepWebauthnNonce = twoStepWebauthnNonce; } public String getAccessToken() { @@ -216,9 +222,11 @@ public String getUserId() { } public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { + JSONObject data = tokenJSON.getJSONObject(DATA); return new Token(tokenJSON.getString(ACCESS_TOKEN_FIELD_NAME), tokenJSON.getString(SITE_URL_FIELD_NAME), - tokenJSON.getString(SITE_ID_FIELD_NAME), tokenJSON.getString(SCOPE_FIELD_NAME), tokenJSON.getString( - TOKEN_TYPE_FIELD_NAME)); + tokenJSON.getString(SITE_ID_FIELD_NAME), tokenJSON.getString(SCOPE_FIELD_NAME), + tokenJSON.getString(TOKEN_TYPE_FIELD_NAME), + data.getString(USER_ID), data.getString(TWO_STEP_WEBAUTHN_NONCE)); } } From 37c8d09495aa3b97690ea369cdfa49ffa6100da3 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 18 Oct 2023 20:47:25 -0300 Subject: [PATCH 026/144] Refactor AccountStore.authenticate function --- .../android/fluxc/store/AccountStore.java | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index dadb5d34bb..f46a52801f 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1284,34 +1284,34 @@ private AccountModel loadAccount() { private void authenticate(final AuthenticatePayload payload) { mAuthenticator.authenticate(payload.username, payload.password, payload.twoStepCode, - payload.shouldSendTwoStepSms, new Authenticator.Listener() { - @Override - public void onResponse(Token token) { - // Check if token exists, if not, check for security key - if (token.getAccessToken() != null) { - mAccessToken.set(token.getAccessToken()); - if (payload.nextAction != null) { - mDispatcher.dispatch(payload.nextAction); - } - emitChange(new OnAuthenticationChanged()); - } else if (token.getUserId() != null) { - //TODO: Trigger security key request - } else { - OnAuthenticationChanged event = new OnAuthenticationChanged(); - event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); - } - } - }, new Authenticator.ErrorListener() { - @Override - public void onErrorResponse(VolleyError volleyError) { - AppLog.e(T.API, "Authentication error"); - OnAuthenticationChanged event = new OnAuthenticationChanged(); - event.error = new AuthenticationError( - Authenticator.volleyErrorToAuthenticationError(volleyError), - Authenticator.volleyErrorToErrorMessage(volleyError)); - emitChange(event); - } - }); + payload.shouldSendTwoStepSms, + token -> handleAuthResponse(token, payload), + this::handleAuthError); + } + + private void handleAuthError(VolleyError volleyError) { + AppLog.e(T.API, "Authentication error"); + OnAuthenticationChanged event = new OnAuthenticationChanged(); + event.error = new AuthenticationError( + Authenticator.volleyErrorToAuthenticationError(volleyError), + Authenticator.volleyErrorToErrorMessage(volleyError)); + emitChange(event); + } + + private void handleAuthResponse(Token token, AuthenticatePayload payload) { + // Check if token exists, if not, check for security key + if (token.getAccessToken() != null) { + mAccessToken.set(token.getAccessToken()); + if (payload.nextAction != null) { + mDispatcher.dispatch(payload.nextAction); + } + emitChange(new OnAuthenticationChanged()); + } else if (token.getUserId() != null) { + //TODO: Trigger security key request + } else { + OnAuthenticationChanged event = new OnAuthenticationChanged(); + event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); + } } private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { From 9741c3edbaf1f0ae1251b29fb923e0e2a308ba0c Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 19 Oct 2023 16:59:02 -0300 Subject: [PATCH 027/144] Adjust Token constructor naming convention --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index c37fdf2f9c..ce754c48f5 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -196,7 +196,7 @@ public static class Token { private String mSiteUrl; private String mSiteId; private String mUserId; - private String twoStepWebauthnNonce; + private String mTwoStepWebauthnNonce; public Token(String accessToken, String siteUrl, String siteId, String scope, String tokenType, String userId, String twoStepWebauthnNonce) { @@ -206,7 +206,7 @@ public Token(String accessToken, String siteUrl, String siteId, String scope, mScope = scope; mTokenType = tokenType; mUserId = userId; - this.twoStepWebauthnNonce = twoStepWebauthnNonce; + mTwoStepWebauthnNonce = twoStepWebauthnNonce; } public String getAccessToken() { From 738f48bb1883969a702ab1fe0487d294f3dad0c9 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 19 Oct 2023 16:59:28 -0300 Subject: [PATCH 028/144] Trigger auth error when handling auth response --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index f46a52801f..24683af5e7 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1307,10 +1307,13 @@ private void handleAuthResponse(Token token, AuthenticatePayload payload) { } emitChange(new OnAuthenticationChanged()); } else if (token.getUserId() != null) { - //TODO: Trigger security key request + OnAuthenticationChanged event = new OnAuthenticationChanged(); + event.error = new AuthenticationError(AuthenticationErrorType.NEEDS_SECURITY_KEY, ""); + emitChange(event); } else { OnAuthenticationChanged event = new OnAuthenticationChanged(); event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); + emitChange(event); } } From 2ebb5e11c04cd8a2461634327d693d14b07c22ef Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 19 Oct 2023 21:18:35 -0300 Subject: [PATCH 029/144] Define AuthSecurityKeyPayload in AccountStore --- .../android/fluxc/store/AccountStore.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 1ae61ec075..dfd0fa07a8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -117,6 +117,32 @@ public AuthEmailPayload(String emailOrUsername, boolean isSignup, AuthEmailPaylo } } + public static class AuthSecurityKeyPayload extends Payload { + public long userId; + public long clientId; + public String secret; + public String twoStepNonce; + public byte[] credentialId; + public byte[] clientDataJson; + public byte[] authenticatorData; + public byte[] signature; + public byte[] userHandle; + + public AuthSecurityKeyPayload(long userId, long clientId, String secret, String twoStepNonce, + byte[] credentialId, byte[] clientDataJson, byte[] authenticatorData, + byte[] signature, byte[] userHandle) { + this.userId = userId; + this.clientId = clientId; + this.secret = secret; + this.twoStepNonce = twoStepNonce; + this.credentialId = credentialId; + this.clientDataJson = clientDataJson; + this.authenticatorData = authenticatorData; + this.signature = signature; + this.userHandle = userHandle; + } + } + public enum AuthEmailPayloadScheme { WORDPRESS("wordpress"), WOOCOMMERCE("woocommerce"), From 91c91fa6d97a982a1204e0c6dedca730e8c8b095 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 19 Oct 2023 22:58:00 -0300 Subject: [PATCH 030/144] Update AuthenticationAction --- .../wordpress/android/fluxc/action/AuthenticationAction.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java index 6a8130c679..86f90d1b8a 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java @@ -6,6 +6,7 @@ import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder.DiscoveryResultPayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; +import org.wordpress.android.fluxc.store.AccountStore.AuthSecurityKeyPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticateErrorPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticatePayload; @@ -25,5 +26,7 @@ public enum AuthenticationAction implements IAction { @Action(payloadType = DiscoveryResultPayload.class) DISCOVERY_RESULT, @Action(payloadType = AuthEmailResponsePayload.class) - SENT_AUTH_EMAIL + SENT_AUTH_EMAIL, + @Action(payloadType = AuthSecurityKeyPayload.class) + AUTHENTICATE_SECURITY_KEY } From f8b53de1f8ad18364c0cddf1c702f9dba403aa1e Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 21:33:18 -0300 Subject: [PATCH 031/144] Handle SecurityKey payload interception --- .../org/wordpress/android/fluxc/store/AccountStore.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index dfd0fa07a8..de68a131e8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1029,6 +1029,10 @@ private void onAuthenticationAction(AuthenticationAction actionType, Object payl case SENT_AUTH_EMAIL: handleSentAuthEmail((AuthEmailResponsePayload) payload); break; + case AUTHENTICATE_SECURITY_KEY: + handleSecurityKeyCredentials((AuthSecurityKeyPayload) payload); + break; + } } @@ -1354,6 +1358,10 @@ private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { } } + private void handleSecurityKeyCredentials(final AuthSecurityKeyPayload payload) { + + } + private boolean checkError(AccountRestPayload payload, String log) { if (payload.isError()) { AppLog.w(T.API, log + "\nError: " + payload.error.volleyError); From 73d509cef9bbba96de3cb8bb95d99b4364ad5c6d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 21:37:49 -0300 Subject: [PATCH 032/144] Define SecurityKeyRequest --- .../network/rest/wpcom/auth/Authenticator.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index ce754c48f5..18bcac77ad 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -180,6 +180,20 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } + public static class SecurityKeyRequest { + public Long userId; + public Long clientId; + public String secret; + public String twoStepNonce; + + public SecurityKeyRequest(String userId, String clientId, String secret, String twoStepNonce) { + this.userId = Long.parseLong(userId); + this.clientId = Long.parseLong(clientId); + this.secret = secret; + this.twoStepNonce = twoStepNonce; + } + } + public static class Token { private static final String TOKEN_TYPE_FIELD_NAME = "token_type"; private static final String ACCESS_TOKEN_FIELD_NAME = "access_token"; From 4bc79c5d6eb529ab674c55f00d6eab6c29dae918 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 21:47:07 -0300 Subject: [PATCH 033/144] Adjust SecurityKeyRequest to conform with TokenRequest --- .../network/rest/wpcom/auth/Authenticator.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 18bcac77ad..76b0926d80 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -180,16 +180,14 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } - public static class SecurityKeyRequest { - public Long userId; - public Long clientId; - public String secret; + public static class SecurityKeyRequest extends TokenRequest { + public String userId; public String twoStepNonce; - public SecurityKeyRequest(String userId, String clientId, String secret, String twoStepNonce) { - this.userId = Long.parseLong(userId); - this.clientId = Long.parseLong(clientId); - this.secret = secret; + public SecurityKeyRequest(String userId, String appId, String appSecret, String twoStepNonce + , Listener listener, ErrorListener errorListener) { + super(appId, appSecret, listener, errorListener); + this.userId = userId; this.twoStepNonce = twoStepNonce; } } From dd21131ecf41bef2252a34df635f6c3b623f45bf Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 22:08:45 -0300 Subject: [PATCH 034/144] Create request when PushSecurityKeyPayload is received --- .../android/fluxc/store/AccountStore.java | 32 ++++++------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index de68a131e8..39bfe54bf5 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -117,29 +117,13 @@ public AuthEmailPayload(String emailOrUsername, boolean isSignup, AuthEmailPaylo } } - public static class AuthSecurityKeyPayload extends Payload { - public long userId; - public long clientId; - public String secret; + public static class PushSecurityKeyPayload extends Payload { + public String userId; public String twoStepNonce; - public byte[] credentialId; - public byte[] clientDataJson; - public byte[] authenticatorData; - public byte[] signature; - public byte[] userHandle; - - public AuthSecurityKeyPayload(long userId, long clientId, String secret, String twoStepNonce, - byte[] credentialId, byte[] clientDataJson, byte[] authenticatorData, - byte[] signature, byte[] userHandle) { + + public PushSecurityKeyPayload(String userId, String twoStepNonce) { this.userId = userId; - this.clientId = clientId; - this.secret = secret; this.twoStepNonce = twoStepNonce; - this.credentialId = credentialId; - this.clientDataJson = clientDataJson; - this.authenticatorData = authenticatorData; - this.signature = signature; - this.userHandle = userHandle; } } @@ -1030,7 +1014,7 @@ private void onAuthenticationAction(AuthenticationAction actionType, Object payl handleSentAuthEmail((AuthEmailResponsePayload) payload); break; case AUTHENTICATE_SECURITY_KEY: - handleSecurityKeyCredentials((AuthSecurityKeyPayload) payload); + handleSecurityKeyCredentials((PushSecurityKeyPayload) payload); break; } @@ -1358,8 +1342,10 @@ private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { } } - private void handleSecurityKeyCredentials(final AuthSecurityKeyPayload payload) { - + private void handleSecurityKeyCredentials(final PushSecurityKeyPayload payload) { + mAuthenticator.makeRequest(payload.userId, payload.twoStepNonce, + token -> {}, + this::handleAuthError); } private boolean checkError(AccountRestPayload payload, String log) { From 6806c6cf603ee2031049d88829b794f3f38eb3b9 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 22:09:08 -0300 Subject: [PATCH 035/144] Adjust AuthenticationAction to follow new payload naming pattern --- .../wordpress/android/fluxc/action/AuthenticationAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java index 86f90d1b8a..af2f6b9fb9 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java @@ -6,7 +6,7 @@ import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder.DiscoveryResultPayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; -import org.wordpress.android.fluxc.store.AccountStore.AuthSecurityKeyPayload; +import org.wordpress.android.fluxc.store.AccountStore.PushSecurityKeyPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticateErrorPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticatePayload; @@ -27,6 +27,6 @@ public enum AuthenticationAction implements IAction { DISCOVERY_RESULT, @Action(payloadType = AuthEmailResponsePayload.class) SENT_AUTH_EMAIL, - @Action(payloadType = AuthSecurityKeyPayload.class) + @Action(payloadType = PushSecurityKeyPayload.class) AUTHENTICATE_SECURITY_KEY } From 86a2e9e78941fe00e97cabe3cd3a5f6352ce8db1 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 22:09:58 -0300 Subject: [PATCH 036/144] Create SecurityKeyChallengeRequest in Authenticator --- .../fluxc/network/rest/wpcom/auth/Authenticator.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 76b0926d80..364140d04f 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -116,6 +116,12 @@ public TokenRequest makeRequest(String code, Listener listener, ErrorListener er return new BearerRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), code, listener, errorListener); } + public SecurityKeyChallengeRequest makeRequest(String userId, String twoStepNonce, + Listener listener, ErrorListener errorListener) { + return new SecurityKeyChallengeRequest(userId, mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), twoStepNonce, + listener, errorListener); + } + private static class TokenRequest extends Request { private final Listener mListener; protected Map mParams = new HashMap<>(); @@ -180,11 +186,11 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } - public static class SecurityKeyRequest extends TokenRequest { + public static class SecurityKeyChallengeRequest extends TokenRequest { public String userId; public String twoStepNonce; - public SecurityKeyRequest(String userId, String appId, String appSecret, String twoStepNonce + public SecurityKeyChallengeRequest(String userId, String appId, String appSecret, String twoStepNonce , Listener listener, ErrorListener errorListener) { super(appId, appSecret, listener, errorListener); this.userId = userId; From 565bce244a224f133d36c4c547ba92c4f8351a7a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 22:11:23 -0300 Subject: [PATCH 037/144] Refactor SecurityKeyChallengeRequest --- .../rest/wpcom/auth/Authenticator.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 364140d04f..db1f4b8914 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -186,15 +186,17 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } - public static class SecurityKeyChallengeRequest extends TokenRequest { - public String userId; - public String twoStepNonce; - - public SecurityKeyChallengeRequest(String userId, String appId, String appSecret, String twoStepNonce - , Listener listener, ErrorListener errorListener) { - super(appId, appSecret, listener, errorListener); - this.userId = userId; - this.twoStepNonce = twoStepNonce; + public static class SecurityKeyChallengeRequest { + public String mUserId; + public String mClientId; + public String mAppSecret; + public String mTwoStepNonce; + + public SecurityKeyChallengeRequest(String userId, String appId, String appSecret, String twoStepNonce) { + this.mUserId = userId; + this.mClientId = appId; + this.mAppSecret = appSecret; + this.mTwoStepNonce = twoStepNonce; } } From c3b6520c1cac415ea80a3e19ae8c78baab761619 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 22:33:22 -0300 Subject: [PATCH 038/144] Remove coroutines usage from PasskeyRestClient.requestWebauthnChallenge --- .../wpcom/auth/passkey/PasskeyRestClient.kt | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index c63d0ee0a2..93e7eff32d 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -31,33 +31,28 @@ class PasskeyRestClient @Inject constructor( accessToken, userAgent ) { - suspend fun requestWebauthnChallenge( - userId: Long, - clientId: Long, + fun requestWebauthnChallenge( + userId: String, + clientId: String, secret: String, - twoStepNonce: String - ): WebauthnChallengeInfo { + twoStepNonce: String, + onSuccess: (response: WebauthnChallengeInfo) -> Unit, + onFailure: (error: WPComGsonNetworkError) -> Unit + ) { val parameters = mapOf( - "user_id" to userId.toString(), - "client_id" to clientId.toString(), + "user_id" to userId, + "client_id" to clientId, "client_secret" to secret, "auth_type" to "webauthn", "two_step_nonce" to twoStepNonce ) - return suspendCoroutine { cont -> - triggerAccountRequest( - url = webauthnChallengeEndpointUrl, - body = parameters, - onSuccess = { - cont.resumeWith(Result.success(it.asChallengeInfo)) - }, - onFailure = { - val exception = Exception(it.message) - cont.resumeWith(Result.failure(exception)) - } - ) - } + triggerAccountRequest( + url = webauthnChallengeEndpointUrl, + body = parameters, + onSuccess = { onSuccess(it.asChallengeInfo) }, + onFailure = onFailure + ) } @Suppress("LongParameterList") From e284c33254569b9c48051b750757c58959961ee0 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 22:37:10 -0300 Subject: [PATCH 039/144] Trigger webauthn challenge request --- .../network/rest/wpcom/auth/Authenticator.java | 7 +++---- .../android/fluxc/store/AccountStore.java | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index db1f4b8914..cc8e0c2ce7 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -116,10 +116,9 @@ public TokenRequest makeRequest(String code, Listener listener, ErrorListener er return new BearerRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), code, listener, errorListener); } - public SecurityKeyChallengeRequest makeRequest(String userId, String twoStepNonce, - Listener listener, ErrorListener errorListener) { - return new SecurityKeyChallengeRequest(userId, mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), twoStepNonce, - listener, errorListener); + public SecurityKeyChallengeRequest makeRequest(String userId, String twoStepNonce) { + return new SecurityKeyChallengeRequest(userId, mAppSecrets.getAppId(), + mAppSecrets.getAppSecret(), twoStepNonce); } private static class TokenRequest extends Request { diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 39bfe54bf5..121e9a0317 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -38,6 +38,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.SecurityKeyChallengeRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; @@ -1343,9 +1344,18 @@ private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { } private void handleSecurityKeyCredentials(final PushSecurityKeyPayload payload) { - mAuthenticator.makeRequest(payload.userId, payload.twoStepNonce, - token -> {}, - this::handleAuthError); + SecurityKeyChallengeRequest request = mAuthenticator.makeRequest(payload.userId, payload.twoStepNonce); + mPasskeyRestClient.requestWebauthnChallenge( + request.mUserId, request.mClientId, + request.mAppSecret, request.mTwoStepNonce, + info -> { + + return null; + }, + error -> { + + return null; + }); } private boolean checkError(AccountRestPayload payload, String log) { From 86c27f62f4761d0f39a183a56e6a93829671da86 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 23:03:39 -0300 Subject: [PATCH 040/144] Fix checkstyle issues --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 121e9a0317..02744adb98 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1017,7 +1017,6 @@ private void onAuthenticationAction(AuthenticationAction actionType, Object payl case AUTHENTICATE_SECURITY_KEY: handleSecurityKeyCredentials((PushSecurityKeyPayload) payload); break; - } } @@ -1349,11 +1348,9 @@ private void handleSecurityKeyCredentials(final PushSecurityKeyPayload payload) request.mUserId, request.mClientId, request.mAppSecret, request.mTwoStepNonce, info -> { - return null; }, error -> { - return null; }); } From f4d5d34ea3fe51d2789d4fc892044b970f4cea67 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 20 Oct 2023 23:04:21 -0300 Subject: [PATCH 041/144] Fix lint issues --- .../fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 93e7eff32d..0d5b51a8c5 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -31,6 +31,7 @@ class PasskeyRestClient @Inject constructor( accessToken, userAgent ) { + @Suppress("LongParameterList") fun requestWebauthnChallenge( userId: String, clientId: String, From 35e1d39836ea18ddd09f6172d0fd402fa3c6b047 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Sat, 21 Oct 2023 23:50:28 -0300 Subject: [PATCH 042/144] Emit challenge info received --- .../android/fluxc/store/AccountStore.java | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 02744adb98..47d47334a3 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -24,6 +24,7 @@ import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder; import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder.DiscoveryError; import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder.DiscoveryResultPayload; +import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError; import org.wordpress.android.fluxc.network.rest.wpcom.account.AccountRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.account.AccountRestClient.AccountFetchUsernameSuggestionsResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.account.AccountRestClient.AccountPushSettingsResponsePayload; @@ -41,6 +42,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.SecurityKeyChallengeRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnChallengeInfo; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; import org.wordpress.android.util.AppLog; @@ -118,16 +120,6 @@ public AuthEmailPayload(String emailOrUsername, boolean isSignup, AuthEmailPaylo } } - public static class PushSecurityKeyPayload extends Payload { - public String userId; - public String twoStepNonce; - - public PushSecurityKeyPayload(String userId, String twoStepNonce) { - this.userId = userId; - this.twoStepNonce = twoStepNonce; - } - } - public enum AuthEmailPayloadScheme { WORDPRESS("wordpress"), WOOCOMMERCE("woocommerce"), @@ -338,6 +330,32 @@ public enum SubscriptionType { NOTIFICATION_POST } + public static class PushSecurityKeyPayload extends Payload { + public String userId; + public String twoStepNonce; + + public PushSecurityKeyPayload(String userId, String twoStepNonce) { + this.userId = userId; + this.twoStepNonce = twoStepNonce; + } + } + + public static class OnWebauthnChallengeReceived extends OnChanged { + public WebauthnChallengeInfo challengeInfo; + + public OnWebauthnChallengeReceived(WebauthnChallengeInfo challengeInfo) { + this.challengeInfo = challengeInfo; + } + } + + public static class OnWebauthnChallengeError implements OnChangedError { + public WPComGsonNetworkError error; + + public OnWebauthnChallengeError(WPComGsonNetworkError error) { + this.error = error; + } + } + /** * Error for any of these methods: * {@link AccountRestClient#updateSubscriptionEmailComment(String, @@ -1348,6 +1366,8 @@ private void handleSecurityKeyCredentials(final PushSecurityKeyPayload payload) request.mUserId, request.mClientId, request.mAppSecret, request.mTwoStepNonce, info -> { + OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(info); + emitChange(event); return null; }, error -> { From f03798a84203f4845eb4a0dbbd45373ea3d35583 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Sat, 21 Oct 2023 23:54:48 -0300 Subject: [PATCH 043/144] Set a TODO comment for error handling --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 1 + 1 file changed, 1 insertion(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 47d47334a3..fae5da08f3 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1371,6 +1371,7 @@ private void handleSecurityKeyCredentials(final PushSecurityKeyPayload payload) return null; }, error -> { + //TODO: Handle error return null; }); } From e2bfb24eacf53551cba8c7b6f3f33d4984ef4139 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Sat, 21 Oct 2023 23:56:54 -0300 Subject: [PATCH 044/144] Correctly handle errors when requesting the webauthn challenge --- .../wordpress/android/fluxc/store/AccountStore.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index fae5da08f3..eff7b513ad 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -342,10 +342,6 @@ public PushSecurityKeyPayload(String userId, String twoStepNonce) { public static class OnWebauthnChallengeReceived extends OnChanged { public WebauthnChallengeInfo challengeInfo; - - public OnWebauthnChallengeReceived(WebauthnChallengeInfo challengeInfo) { - this.challengeInfo = challengeInfo; - } } public static class OnWebauthnChallengeError implements OnChangedError { @@ -1366,12 +1362,15 @@ private void handleSecurityKeyCredentials(final PushSecurityKeyPayload payload) request.mUserId, request.mClientId, request.mAppSecret, request.mTwoStepNonce, info -> { - OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(info); + OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); + event.challengeInfo = info; emitChange(event); return null; }, error -> { - //TODO: Handle error + OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); + event.error = new OnWebauthnChallengeError(error); + emitChange(event); return null; }); } From 409ffa0bb169d20813553053b53030aa75e40374 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Sat, 21 Oct 2023 23:57:12 -0300 Subject: [PATCH 045/144] Rename WebauthChallengeError --- .../org/wordpress/android/fluxc/store/AccountStore.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index eff7b513ad..07340e80e8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -340,14 +340,14 @@ public PushSecurityKeyPayload(String userId, String twoStepNonce) { } } - public static class OnWebauthnChallengeReceived extends OnChanged { + public static class OnWebauthnChallengeReceived extends OnChanged { public WebauthnChallengeInfo challengeInfo; } - public static class OnWebauthnChallengeError implements OnChangedError { + public static class WebauthnChallengeError implements OnChangedError { public WPComGsonNetworkError error; - public OnWebauthnChallengeError(WPComGsonNetworkError error) { + public WebauthnChallengeError(WPComGsonNetworkError error) { this.error = error; } } @@ -1369,7 +1369,7 @@ private void handleSecurityKeyCredentials(final PushSecurityKeyPayload payload) }, error -> { OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); - event.error = new OnWebauthnChallengeError(error); + event.error = new WebauthnChallengeError(error); emitChange(event); return null; }); From c9fa1d2461cdea02fcaf2aac2962089fdfa5d609 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 12:01:05 -0300 Subject: [PATCH 046/144] Define WebauthnUserData --- .../network/rest/wpcom/auth/passkey/WebauthnUserData.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt new file mode 100644 index 0000000000..3f5940ad2c --- /dev/null +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt @@ -0,0 +1,6 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey + +data class WebauthnUserData( + val userId: Long, + val webauthnNonce: String +) \ No newline at end of file From ea790a0702d2e6a0f68d395b3e264c3035bda0f3 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 12:01:18 -0300 Subject: [PATCH 047/144] Add webauthn user data request function in PasskeyRestClient --- .../wpcom/auth/passkey/PasskeyRestClient.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 0d5b51a8c5..be4fbac995 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -12,6 +12,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton @@ -31,6 +32,32 @@ class PasskeyRestClient @Inject constructor( accessToken, userAgent ) { + fun requestWebauthnInitialData( + clientId: String, + secret: String, + username: String, + password: String, + onSuccess: (response: WebauthnUserData) -> Unit, + onFailure: (error: WPComGsonNetworkError) -> Unit + ) { + val parameters = mapOf( + "client_id" to clientId, + "client_secret" to secret, + "grant_type" to "password", + "username" to username, + "password" to password, + "wpcom_supports_2fa" to true, + "with_auth_types" to true + ) + + triggerAccountRequest( + url = wpcomTokenEndpoint, + body = parameters, + onSuccess = { onSuccess(it.asWebauthnUserData) }, + onFailure = onFailure + ) + } + @Suppress("LongParameterList") fun requestWebauthnChallenge( userId: String, @@ -143,7 +170,18 @@ class PasskeyRestClient @Inject constructor( ?.let { this["bearer_token"] as? String } .orEmpty() + private val Map.asWebauthnUserData: WebauthnUserData + get() { + val data = this["data"] as Map<*, *> + return WebauthnUserData( + userId = data["user_id"] as Long, + webauthnNonce = data["two_step_nonce_webauthn"] as String + ) + } + companion object { + private const val wpcomOauthPrefix = "https://public-api.wordpress.com/oauth2" + private const val wpcomTokenEndpoint = "$wpcomOauthPrefix/token" private const val baseURLWithAction = "wp-login.php?action" private const val challengeEndpoint = "webauthn-challenge-endpoint" private const val authEndpoint = "webauthn-authentication-endpoint" From f554988fe1c905d5f9b3d8349e0e8a0dc17e737d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 12:08:53 -0300 Subject: [PATCH 048/144] Adjust Authenticator to request only the Webauthn necessary data --- .../rest/wpcom/auth/Authenticator.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index cc8e0c2ce7..cc0907ee6b 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -116,9 +116,9 @@ public TokenRequest makeRequest(String code, Listener listener, ErrorListener er return new BearerRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), code, listener, errorListener); } - public SecurityKeyChallengeRequest makeRequest(String userId, String twoStepNonce) { - return new SecurityKeyChallengeRequest(userId, mAppSecrets.getAppId(), - mAppSecrets.getAppSecret(), twoStepNonce); + public WebauthnRequest makeRequest(String username, String password) { + return new WebauthnRequest(username, password, mAppSecrets.getAppId(), + mAppSecrets.getAppSecret()); } private static class TokenRequest extends Request { @@ -185,17 +185,17 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } - public static class SecurityKeyChallengeRequest { - public String mUserId; + public static class WebauthnRequest { + public String mUsername; + public String mPassword; public String mClientId; public String mAppSecret; - public String mTwoStepNonce; - public SecurityKeyChallengeRequest(String userId, String appId, String appSecret, String twoStepNonce) { - this.mUserId = userId; + public WebauthnRequest(String username, String password, String appId, String appSecret) { + this.mUsername = username; + this.mPassword = password; this.mClientId = appId; this.mAppSecret = appSecret; - this.mTwoStepNonce = twoStepNonce; } } @@ -207,7 +207,7 @@ public static class Token { private static final String SITE_ID_FIELD_NAME = "blog_id"; private static final String DATA = "data"; private static final String USER_ID = "user_id"; - private static final String TWO_STEP_WEBAUTHN_NONCE = "two_step_webauthn_nonce"; + private static final String TWO_STEP_WEBAUTHN_NONCE = "two_step_nonce_webauthn"; private String mTokenType; private String mScope; @@ -241,6 +241,7 @@ public String getUserId() { } public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { + //TODO: check if this is really necessary or can be accessed easily JSONObject data = tokenJSON.getJSONObject(DATA); return new Token(tokenJSON.getString(ACCESS_TOKEN_FIELD_NAME), tokenJSON.getString(SITE_URL_FIELD_NAME), tokenJSON.getString(SITE_ID_FIELD_NAME), tokenJSON.getString(SCOPE_FIELD_NAME), From 49d86b10f92e1435a01ff62f440ea5ce9723c3d9 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 12:13:19 -0300 Subject: [PATCH 049/144] Handle complete webauthn startup scenario --- .../android/fluxc/store/AccountStore.java | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 07340e80e8..307faa1d32 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -39,8 +39,8 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.SecurityKeyChallengeRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnChallengeInfo; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; @@ -331,12 +331,12 @@ public enum SubscriptionType { } public static class PushSecurityKeyPayload extends Payload { - public String userId; - public String twoStepNonce; + public String username; + public String password; - public PushSecurityKeyPayload(String userId, String twoStepNonce) { - this.userId = userId; - this.twoStepNonce = twoStepNonce; + public PushSecurityKeyPayload(String username, String password) { + this.username = username; + this.password = password; } } @@ -1357,10 +1357,30 @@ private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { } private void handleSecurityKeyCredentials(final PushSecurityKeyPayload payload) { - SecurityKeyChallengeRequest request = mAuthenticator.makeRequest(payload.userId, payload.twoStepNonce); + WebauthnRequest request = mAuthenticator.makeRequest(payload.username, payload.password); + mPasskeyRestClient.requestWebauthnInitialData( + request.mClientId, + request.mAppSecret, + request.mUsername, + request.mPassword, + userData -> { + requestWebauthnChallenge(String.valueOf(userData.getUserId()), userData.getWebauthnNonce(), + request.mClientId, request.mAppSecret); + return null; + }, + error -> { + OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); + event.error = new WebauthnChallengeError(error); + emitChange(event); + return null; + }); + } + + private void requestWebauthnChallenge(String userId, String webauthnNonce, + String clientId, String secret) { mPasskeyRestClient.requestWebauthnChallenge( - request.mUserId, request.mClientId, - request.mAppSecret, request.mTwoStepNonce, + userId, clientId, + secret, webauthnNonce, info -> { OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); event.challengeInfo = info; From 653c84ca44cefb4643aeeff2791f4755e50a0302 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 12:24:37 -0300 Subject: [PATCH 050/144] Fix detekt and checkstyle issues --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 2 +- .../fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 2 +- .../fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index cc0907ee6b..01685c7f1f 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -241,7 +241,7 @@ public String getUserId() { } public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { - //TODO: check if this is really necessary or can be accessed easily + // TODO: check if this is really necessary or can be accessed easily JSONObject data = tokenJSON.getJSONObject(DATA); return new Token(tokenJSON.getString(ACCESS_TOKEN_FIELD_NAME), tokenJSON.getString(SITE_URL_FIELD_NAME), tokenJSON.getString(SITE_ID_FIELD_NAME), tokenJSON.getString(SCOPE_FIELD_NAME), diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index be4fbac995..0aa817f15d 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -12,7 +12,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken -import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton @@ -32,6 +31,7 @@ class PasskeyRestClient @Inject constructor( accessToken, userAgent ) { + @Suppress("LongParameterList") fun requestWebauthnInitialData( clientId: String, secret: String, diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt index 3f5940ad2c..da9650e26a 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt @@ -3,4 +3,4 @@ package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey data class WebauthnUserData( val userId: Long, val webauthnNonce: String -) \ No newline at end of file +) From 04988098d30a9da5e3d765ee2f6529f2c28bbdc6 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 18:46:34 -0300 Subject: [PATCH 051/144] Allow double Token construction strategy --- .../network/rest/wpcom/auth/Authenticator.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 01685c7f1f..73ac4f6d0c 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -217,15 +217,17 @@ public static class Token { private String mUserId; private String mTwoStepWebauthnNonce; - public Token(String accessToken, String siteUrl, String siteId, String scope, - String tokenType, String userId, String twoStepWebauthnNonce) { + public Token(String accessToken, String siteUrl, String siteId, String scope, String tokenType) { mAccessToken = accessToken; mSiteUrl = siteUrl; mSiteId = siteId; mScope = scope; mTokenType = tokenType; + } + + public Token(String userId, String webAuthTwoStepNonce) { mUserId = userId; - mTwoStepWebauthnNonce = twoStepWebauthnNonce; + mTwoStepWebauthnNonce = webAuthTwoStepNonce; } public String getAccessToken() { @@ -241,12 +243,14 @@ public String getUserId() { } public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { - // TODO: check if this is really necessary or can be accessed easily JSONObject data = tokenJSON.getJSONObject(DATA); + if (data.isNull(USER_ID) || data.isNull(TWO_STEP_WEBAUTHN_NONCE)) { + return new Token(data.getString(USER_ID), data.getString(TWO_STEP_WEBAUTHN_NONCE)); + } + return new Token(tokenJSON.getString(ACCESS_TOKEN_FIELD_NAME), tokenJSON.getString(SITE_URL_FIELD_NAME), tokenJSON.getString(SITE_ID_FIELD_NAME), tokenJSON.getString(SCOPE_FIELD_NAME), - tokenJSON.getString(TOKEN_TYPE_FIELD_NAME), - data.getString(USER_ID), data.getString(TWO_STEP_WEBAUTHN_NONCE)); + tokenJSON.getString(TOKEN_TYPE_FIELD_NAME)); } } From 397ffbde550875af88fc3926425c94e7acda2a6b Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 19:03:09 -0300 Subject: [PATCH 052/144] Add webauthnNonce getter into Token class --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 73ac4f6d0c..abff1c9f08 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -242,6 +242,10 @@ public String getUserId() { return mUserId; } + public String getWebauthnNonce() { + return mTwoStepWebauthnNonce; + } + public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { JSONObject data = tokenJSON.getJSONObject(DATA); if (data.isNull(USER_ID) || data.isNull(TWO_STEP_WEBAUTHN_NONCE)) { From 6f120235aed635485039d4f9b52b55858e0989c2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 19:03:21 -0300 Subject: [PATCH 053/144] Create login step when account requires passkey --- .../android/fluxc/store/AccountStore.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 307faa1d32..9533c8174e 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -450,6 +450,16 @@ public static class OnUsernameChanged extends OnChanged { public String username; } + public static class OnSecurityKeyAuthStarted extends OnChanged { + public String userId; + public String webauthnNonce; + + public OnSecurityKeyAuthStarted(String userId, String webauthnNonce) { + this.userId = userId; + this.webauthnNonce = webauthnNonce; + } + } + public static class OnUsernameSuggestionsFetched extends OnChanged { public List suggestions; } @@ -1335,8 +1345,8 @@ private void handleAuthResponse(Token token, AuthenticatePayload payload) { } emitChange(new OnAuthenticationChanged()); } else if (token.getUserId() != null) { - OnAuthenticationChanged event = new OnAuthenticationChanged(); - event.error = new AuthenticationError(AuthenticationErrorType.NEEDS_SECURITY_KEY, ""); + OnSecurityKeyAuthStarted event = new OnSecurityKeyAuthStarted(token.getUserId(), + token.getWebauthnNonce()); emitChange(event); } else { OnAuthenticationChanged event = new OnAuthenticationChanged(); From 33e4ddcc456cc18ba62202c8609ba59d3ab9af9a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 20:12:00 -0300 Subject: [PATCH 054/144] Improve Token parsing in Authenticator --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index abff1c9f08..efa2c32bf0 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -247,8 +247,8 @@ public String getWebauthnNonce() { } public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { - JSONObject data = tokenJSON.getJSONObject(DATA); - if (data.isNull(USER_ID) || data.isNull(TWO_STEP_WEBAUTHN_NONCE)) { + JSONObject data = tokenJSON.optJSONObject(DATA); + if (data != null) { return new Token(data.getString(USER_ID), data.getString(TWO_STEP_WEBAUTHN_NONCE)); } From 50f299595f46a572e71afb0bd60f4cc8692e7727 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 23:02:14 -0300 Subject: [PATCH 055/144] Rename Security key challenge payload name and fields --- .../fluxc/action/AuthenticationAction.java | 6 ++-- .../android/fluxc/store/AccountStore.java | 28 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java index af2f6b9fb9..f9d1daa5d4 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java @@ -6,7 +6,7 @@ import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder.DiscoveryResultPayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; -import org.wordpress.android.fluxc.store.AccountStore.PushSecurityKeyPayload; +import org.wordpress.android.fluxc.store.AccountStore.StartSecurityKeyChallengePayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticateErrorPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticatePayload; @@ -27,6 +27,6 @@ public enum AuthenticationAction implements IAction { DISCOVERY_RESULT, @Action(payloadType = AuthEmailResponsePayload.class) SENT_AUTH_EMAIL, - @Action(payloadType = PushSecurityKeyPayload.class) - AUTHENTICATE_SECURITY_KEY + @Action(payloadType = StartSecurityKeyChallengePayload.class) + SECURITY_KEY_CHALLENGE } diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 9533c8174e..c1122dd5f8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -40,7 +40,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnRequest; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnChallengeRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnChallengeInfo; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; @@ -330,13 +330,13 @@ public enum SubscriptionType { NOTIFICATION_POST } - public static class PushSecurityKeyPayload extends Payload { - public String username; - public String password; + public static class StartSecurityKeyChallengePayload extends Payload { + public String mUserId; + public String mWebauthnNonce; - public PushSecurityKeyPayload(String username, String password) { - this.username = username; - this.password = password; + public StartSecurityKeyChallengePayload(String mUserId, String mWebauthnNonce) { + this.mUserId = mUserId; + this.mWebauthnNonce = mWebauthnNonce; } } @@ -1038,8 +1038,8 @@ private void onAuthenticationAction(AuthenticationAction actionType, Object payl case SENT_AUTH_EMAIL: handleSentAuthEmail((AuthEmailResponsePayload) payload); break; - case AUTHENTICATE_SECURITY_KEY: - handleSecurityKeyCredentials((PushSecurityKeyPayload) payload); + case SECURITY_KEY_CHALLENGE: + handleSecurityKeyCredentials((StartSecurityKeyChallengePayload) payload); break; } } @@ -1344,7 +1344,7 @@ private void handleAuthResponse(Token token, AuthenticatePayload payload) { mDispatcher.dispatch(payload.nextAction); } emitChange(new OnAuthenticationChanged()); - } else if (token.getUserId() != null) { + } else if (token.getUserId() != null && token.getWebauthnNonce() != null) { OnSecurityKeyAuthStarted event = new OnSecurityKeyAuthStarted(token.getUserId(), token.getWebauthnNonce()); emitChange(event); @@ -1366,13 +1366,13 @@ private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { } } - private void handleSecurityKeyCredentials(final PushSecurityKeyPayload payload) { - WebauthnRequest request = mAuthenticator.makeRequest(payload.username, payload.password); + private void handleSecurityKeyCredentials(final StartSecurityKeyChallengePayload payload) { + WebauthnChallengeRequest request = mAuthenticator.makeRequest(payload.mUserId, payload.mWebauthnNonce); mPasskeyRestClient.requestWebauthnInitialData( request.mClientId, request.mAppSecret, - request.mUsername, - request.mPassword, + request.mUserId, + request.mWebauthnNonce, userData -> { requestWebauthnChallenge(String.valueOf(userData.getUserId()), userData.getWebauthnNonce(), request.mClientId, request.mAppSecret); From 1acba13da1cdf4ee1be79cdf824c9299fdfc529c Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 23:02:23 -0300 Subject: [PATCH 056/144] Rename webauthn challenge request --- .../network/rest/wpcom/auth/Authenticator.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index efa2c32bf0..631e976055 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -116,8 +116,8 @@ public TokenRequest makeRequest(String code, Listener listener, ErrorListener er return new BearerRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), code, listener, errorListener); } - public WebauthnRequest makeRequest(String username, String password) { - return new WebauthnRequest(username, password, mAppSecrets.getAppId(), + public WebauthnChallengeRequest makeRequest(String userId, String webauthnNonce) { + return new WebauthnChallengeRequest(userId, webauthnNonce, mAppSecrets.getAppId(), mAppSecrets.getAppSecret()); } @@ -185,15 +185,15 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } - public static class WebauthnRequest { - public String mUsername; - public String mPassword; + public static class WebauthnChallengeRequest { + public String mUserId; + public String mWebauthnNonce; public String mClientId; public String mAppSecret; - public WebauthnRequest(String username, String password, String appId, String appSecret) { - this.mUsername = username; - this.mPassword = password; + public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String appId, String appSecret) { + this.mUserId = userId; + this.mWebauthnNonce = mWebauthnNonce; this.mClientId = appId; this.mAppSecret = appSecret; } From a1aa46c7eea60a3355f9687484a89e3e63ad2e95 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 23:08:36 -0300 Subject: [PATCH 057/144] Correctly trigger the challenge request --- .../android/fluxc/store/AccountStore.java | 28 +++---------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index c1122dd5f8..df6378b3e8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1039,7 +1039,7 @@ private void onAuthenticationAction(AuthenticationAction actionType, Object payl handleSentAuthEmail((AuthEmailResponsePayload) payload); break; case SECURITY_KEY_CHALLENGE: - handleSecurityKeyCredentials((StartSecurityKeyChallengePayload) payload); + requestWebauthnChallenge((StartSecurityKeyChallengePayload) payload); break; } } @@ -1366,31 +1366,11 @@ private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { } } - private void handleSecurityKeyCredentials(final StartSecurityKeyChallengePayload payload) { + private void requestWebauthnChallenge(final StartSecurityKeyChallengePayload payload) { WebauthnChallengeRequest request = mAuthenticator.makeRequest(payload.mUserId, payload.mWebauthnNonce); - mPasskeyRestClient.requestWebauthnInitialData( - request.mClientId, - request.mAppSecret, - request.mUserId, - request.mWebauthnNonce, - userData -> { - requestWebauthnChallenge(String.valueOf(userData.getUserId()), userData.getWebauthnNonce(), - request.mClientId, request.mAppSecret); - return null; - }, - error -> { - OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); - event.error = new WebauthnChallengeError(error); - emitChange(event); - return null; - }); - } - - private void requestWebauthnChallenge(String userId, String webauthnNonce, - String clientId, String secret) { mPasskeyRestClient.requestWebauthnChallenge( - userId, clientId, - secret, webauthnNonce, + request.mUserId, request.mClientId, + request.mAppSecret, request.mWebauthnNonce, info -> { OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); event.challengeInfo = info; From 681b818a7c84c0017be20b6d9ad4063e163175b2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 23:08:43 -0300 Subject: [PATCH 058/144] Remove unused code from PasskeyRestClient --- .../wpcom/auth/passkey/PasskeyRestClient.kt | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 0aa817f15d..2f728f7a0e 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -31,33 +31,6 @@ class PasskeyRestClient @Inject constructor( accessToken, userAgent ) { - @Suppress("LongParameterList") - fun requestWebauthnInitialData( - clientId: String, - secret: String, - username: String, - password: String, - onSuccess: (response: WebauthnUserData) -> Unit, - onFailure: (error: WPComGsonNetworkError) -> Unit - ) { - val parameters = mapOf( - "client_id" to clientId, - "client_secret" to secret, - "grant_type" to "password", - "username" to username, - "password" to password, - "wpcom_supports_2fa" to true, - "with_auth_types" to true - ) - - triggerAccountRequest( - url = wpcomTokenEndpoint, - body = parameters, - onSuccess = { onSuccess(it.asWebauthnUserData) }, - onFailure = onFailure - ) - } - @Suppress("LongParameterList") fun requestWebauthnChallenge( userId: String, From 3b6edee6025f7a7ec192cabcaa7bda55580eb161 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Mon, 23 Oct 2023 23:18:44 -0300 Subject: [PATCH 059/144] Fix lint issues --- .../rest/wpcom/auth/passkey/PasskeyRestClient.kt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 2f728f7a0e..0d5b51a8c5 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -143,18 +143,7 @@ class PasskeyRestClient @Inject constructor( ?.let { this["bearer_token"] as? String } .orEmpty() - private val Map.asWebauthnUserData: WebauthnUserData - get() { - val data = this["data"] as Map<*, *> - return WebauthnUserData( - userId = data["user_id"] as Long, - webauthnNonce = data["two_step_nonce_webauthn"] as String - ) - } - companion object { - private const val wpcomOauthPrefix = "https://public-api.wordpress.com/oauth2" - private const val wpcomTokenEndpoint = "$wpcomOauthPrefix/token" private const val baseURLWithAction = "wp-login.php?action" private const val challengeEndpoint = "webauthn-challenge-endpoint" private const val authEndpoint = "webauthn-authentication-endpoint" From bdca9c2531a81f65613e41de615beab0076eb653 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 00:28:45 -0300 Subject: [PATCH 060/144] Update base URL --- .../fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 0d5b51a8c5..40888ed0da 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -144,7 +144,7 @@ class PasskeyRestClient @Inject constructor( .orEmpty() companion object { - private const val baseURLWithAction = "wp-login.php?action" + private const val baseURLWithAction = "https://wordpress.com/wp-login.php?action" private const val challengeEndpoint = "webauthn-challenge-endpoint" private const val authEndpoint = "webauthn-authentication-endpoint" const val webauthnChallengeEndpointUrl = "$baseURLWithAction=$challengeEndpoint" From 7673b579ca6af92432e99abc3f5a1e1397052166 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 00:43:07 -0300 Subject: [PATCH 061/144] Update base URL --- .../network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 40888ed0da..e087d7c041 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -144,10 +144,10 @@ class PasskeyRestClient @Inject constructor( .orEmpty() companion object { - private const val baseURLWithAction = "https://wordpress.com/wp-login.php?action" + private const val baseWPLoginUrl = "https://wordpress.com/wp-login.php?action" private const val challengeEndpoint = "webauthn-challenge-endpoint" private const val authEndpoint = "webauthn-authentication-endpoint" - const val webauthnChallengeEndpointUrl = "$baseURLWithAction=$challengeEndpoint" - const val webauthnAuthEndpointUrl = "$baseURLWithAction=$authEndpoint" + const val webauthnChallengeEndpointUrl = "$baseWPLoginUrl=$challengeEndpoint" + const val webauthnAuthEndpointUrl = "$baseWPLoginUrl=$authEndpoint" } } From 405b10164c32d9a714efe368f340ee5d83e89dc8 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 01:57:18 -0300 Subject: [PATCH 062/144] Set user and client ID as numbers --- .../network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index e087d7c041..ee015972d7 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -41,8 +41,8 @@ class PasskeyRestClient @Inject constructor( onFailure: (error: WPComGsonNetworkError) -> Unit ) { val parameters = mapOf( - "user_id" to userId, - "client_id" to clientId, + "user_id" to userId.toLong(), + "client_id" to clientId.toLong(), "client_secret" to secret, "auth_type" to "webauthn", "two_step_nonce" to twoStepNonce From 69b72e37aaddd2f7201b3be8a9bc141162b978f5 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 16:52:37 -0300 Subject: [PATCH 063/144] Adjust PasskeyRestClient incorrect usage of request body --- .../wpcom/auth/passkey/PasskeyRestClient.kt | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index ee015972d7..64f4f1d139 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -41,8 +41,8 @@ class PasskeyRestClient @Inject constructor( onFailure: (error: WPComGsonNetworkError) -> Unit ) { val parameters = mapOf( - "user_id" to userId.toLong(), - "client_id" to clientId.toLong(), + "user_id" to userId, + "client_id" to clientId, "client_secret" to secret, "auth_type" to "webauthn", "two_step_nonce" to twoStepNonce @@ -50,7 +50,7 @@ class PasskeyRestClient @Inject constructor( triggerAccountRequest( url = webauthnChallengeEndpointUrl, - body = parameters, + parameters = parameters, onSuccess = { onSuccess(it.asChallengeInfo) }, onFailure = onFailure ) @@ -83,19 +83,19 @@ class PasskeyRestClient @Inject constructor( val parameters = mapOf( "user_id" to userId.toString(), - "client_id" to clientId, + "client_id" to clientId.toString(), "client_secret" to secret, "auth_type" to "webauthn", "two_step_nonce" to twoStepNonce, "client_data" to clientData, - "get_bearer_token" to true, - "create_2fa_cookies_only" to true + "get_bearer_token" to true.toString(), + "create_2fa_cookies_only" to true.toString() ) return suspendCoroutine { cont -> triggerAccountRequest( url = webauthnAuthEndpointUrl, - body = parameters, + parameters = parameters, onSuccess = { cont.resumeWith(Result.success(it.asBearerToken)) }, @@ -109,16 +109,17 @@ class PasskeyRestClient @Inject constructor( private fun triggerAccountRequest( url: String, - body: Map, - onSuccess: (response: Map) -> Unit, + parameters: Map, + onSuccess: (response: Map<*, *>) -> Unit, onFailure: (error: WPComGsonNetworkError) -> Unit ) { - val successListener = Response.Listener> { onSuccess(it) } + val successListener = Response.Listener> { onSuccess(it) } val failureListener = WPComErrorListener { onFailure(it) } val request = WPComGsonRequest.buildPostRequest( url, - body, + parameters, + emptyMap(), Map::class.java, successListener, failureListener @@ -127,7 +128,7 @@ class PasskeyRestClient @Inject constructor( add(request) } - private val Map.asChallengeInfo: WebauthnChallengeInfo + private val Map<*, *>.asChallengeInfo: WebauthnChallengeInfo get() = WebauthnChallengeInfo( challenge = this["challenge"] as String, rpId = this["rpId"] as String, @@ -137,7 +138,7 @@ class PasskeyRestClient @Inject constructor( ?.map { it as String } ) - private val Map.asBearerToken: String + private val Map<*, *>.asBearerToken: String get() = this["data"] ?.run { this as? Map<*, *> } ?.let { this["bearer_token"] as? String } From 6c926c3fd1100af72fa68a91b0743921a2612b3a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 18:26:50 -0300 Subject: [PATCH 064/144] Adjust WebauthnChallengeRequest to conform with Authenticator Requests strategy --- .../rest/wpcom/auth/Authenticator.java | 56 +++++++++++++++---- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 631e976055..0cbc42583c 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -1,10 +1,14 @@ package org.wordpress.android.fluxc.network.rest.wpcom.auth; +import static org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient.webauthnChallengeEndpointUrl; + import android.content.Context; import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.android.volley.AuthFailureError; import com.android.volley.NetworkResponse; import com.android.volley.ParseError; import com.android.volley.Request; @@ -22,6 +26,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnChallengeInfo; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailError; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailErrorType; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; @@ -32,7 +37,9 @@ import org.wordpress.android.util.LanguageUtils; import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.inject.Inject; @@ -185,17 +192,44 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } - public static class WebauthnChallengeRequest { - public String mUserId; - public String mWebauthnNonce; - public String mClientId; - public String mAppSecret; - - public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String appId, String appSecret) { - this.mUserId = userId; - this.mWebauthnNonce = mWebauthnNonce; - this.mClientId = appId; - this.mAppSecret = appSecret; + public static class WebauthnChallengeRequest extends Request { + private final Response.Listener mListener; + private Map mParams = new HashMap<>(); + + public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String appId, + String appSecret, Response.Listener listener, + ErrorListener errorListener) { + super(Method.POST, webauthnChallengeEndpointUrl, errorListener); + mListener = listener; + mParams.put(CLIENT_ID_PARAM_NAME, appId); + mParams.put(CLIENT_SECRET_PARAM_NAME, appSecret); + mParams.put("user_id", userId); + mParams.put("auth_type", "webauthn"); + mParams.put("two_step_nonce", mWebauthnNonce); + } + + + @Override protected Response parseNetworkResponse(NetworkResponse response) { + try { + String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); + JSONObject challengeData = new JSONObject(jsonString).getJSONObject("data"); + String challenge = challengeData.getString("challenge"); + String rpId = challengeData.getString("rpId"); + String nonce = challengeData.getString("two_step_nonce"); + List allowCredentials = new ArrayList<>(); + WebauthnChallengeInfo info = new WebauthnChallengeInfo(challenge, rpId, nonce, allowCredentials); + return Response.success(info, HttpHeaderParser.parseCacheHeaders(response)); + } catch (UnsupportedEncodingException | JSONException e) { + return Response.error(new ParseError(e)); + } + } + + @Override protected void deliverResponse(WebauthnChallengeInfo response) { + mListener.onResponse(response); + } + + @Nullable @Override protected Map getParams() throws AuthFailureError { + return super.getParams(); } } From 51eae875ea710c97871ad5cb3fe2271ed54d06a6 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 18:34:13 -0300 Subject: [PATCH 065/144] Trigger conformed WebauthnChallengeRequest following Authenticator Requests strategy --- .../network/rest/wpcom/auth/Authenticator.java | 17 ++++++++++------- .../android/fluxc/store/AccountStore.java | 13 +++---------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 0cbc42583c..5c2bb695a0 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -104,7 +104,7 @@ public void authenticate(String username, boolean shouldSendTwoStepSMS, Listener listener, ErrorListener errorListener) { - TokenRequest tokenRequest = makeRequest(username, password, twoStepCode, shouldSendTwoStepSMS, listener, + TokenRequest tokenRequest = requestChallenge(username, password, twoStepCode, shouldSendTwoStepSMS, listener, errorListener); mRequestQueue.add(tokenRequest); } @@ -113,19 +113,22 @@ public String getAuthorizationURL() { return String.format(AUTHORIZE_ENDPOINT_FORMAT, AUTHORIZE_ENDPOINT, mAppSecrets.getAppId()); } - public TokenRequest makeRequest(String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, - Listener listener, ErrorListener errorListener) { + public TokenRequest requestChallenge(String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, + Listener listener, ErrorListener errorListener) { return new PasswordRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), username, password, twoStepCode, shouldSendTwoStepSMS, listener, errorListener); } - public TokenRequest makeRequest(String code, Listener listener, ErrorListener errorListener) { + public TokenRequest requestChallenge(String code, Listener listener, ErrorListener errorListener) { return new BearerRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), code, listener, errorListener); } - public WebauthnChallengeRequest makeRequest(String userId, String webauthnNonce) { - return new WebauthnChallengeRequest(userId, webauthnNonce, mAppSecrets.getAppId(), - mAppSecrets.getAppSecret()); + public void requestChallenge(String userId, String webauthnNonce, + Response.Listener listener, + ErrorListener errorListener) { + WebauthnChallengeRequest request = new WebauthnChallengeRequest(userId, webauthnNonce, mAppSecrets.getAppId(), + mAppSecrets.getAppSecret(), listener, errorListener); + mRequestQueue.add(request); } private static class TokenRequest extends Request { diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index df6378b3e8..d9c0265799 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -24,7 +24,6 @@ import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder; import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder.DiscoveryError; import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder.DiscoveryResultPayload; -import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError; import org.wordpress.android.fluxc.network.rest.wpcom.account.AccountRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.account.AccountRestClient.AccountFetchUsernameSuggestionsResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.account.AccountRestClient.AccountPushSettingsResponsePayload; @@ -40,7 +39,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnChallengeRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnChallengeInfo; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; @@ -345,9 +343,9 @@ public static class OnWebauthnChallengeReceived extends OnChanged { OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); event.challengeInfo = info; emitChange(event); - return null; }, error -> { OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); event.error = new WebauthnChallengeError(error); emitChange(event); - return null; }); } From b60b51e3977b4844dd723c5a0dda9c7bb8d95894 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 18:48:46 -0300 Subject: [PATCH 066/144] Fix checkstyle issues --- .../fluxc/network/rest/wpcom/auth/Authenticator.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 5c2bb695a0..bb940d48f0 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -1,7 +1,5 @@ package org.wordpress.android.fluxc.network.rest.wpcom.auth; -import static org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient.webauthnChallengeEndpointUrl; - import android.content.Context; import android.text.TextUtils; @@ -26,6 +24,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnChallengeInfo; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailError; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailErrorType; @@ -113,8 +112,9 @@ public String getAuthorizationURL() { return String.format(AUTHORIZE_ENDPOINT_FORMAT, AUTHORIZE_ENDPOINT, mAppSecrets.getAppId()); } - public TokenRequest requestChallenge(String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, - Listener listener, ErrorListener errorListener) { + public TokenRequest requestChallenge(String username, String password, String twoStepCode, + boolean shouldSendTwoStepSMS, Listener listener, + ErrorListener errorListener) { return new PasswordRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), username, password, twoStepCode, shouldSendTwoStepSMS, listener, errorListener); } @@ -202,7 +202,7 @@ public static class WebauthnChallengeRequest extends Request listener, ErrorListener errorListener) { - super(Method.POST, webauthnChallengeEndpointUrl, errorListener); + super(Method.POST, PasskeyRestClient.webauthnChallengeEndpointUrl, errorListener); mListener = listener; mParams.put(CLIENT_ID_PARAM_NAME, appId); mParams.put(CLIENT_SECRET_PARAM_NAME, appSecret); From b2775a14f73b56669b83cc4e72d0b94a1f6e8609 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 19:30:59 -0300 Subject: [PATCH 067/144] Fix incorrect parameters --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index bb940d48f0..67bd9220e9 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -232,7 +232,7 @@ public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String app } @Nullable @Override protected Map getParams() throws AuthFailureError { - return super.getParams(); + return mParams; } } From 0a43791a40db8d88e627cf42f6770903b403706e Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 21:02:28 -0300 Subject: [PATCH 068/144] Fully parse all data from WebauthnChallengeInfo --- .../network/rest/wpcom/auth/Authenticator.java | 18 ++++++++++++++++-- .../auth/passkey/WebauthnChallengeInfo.kt | 8 +++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 67bd9220e9..bc3b2fac74 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -15,6 +15,7 @@ import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.wordpress.android.fluxc.Dispatcher; @@ -26,6 +27,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnChallengeInfo; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnCredential; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailError; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailErrorType; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; @@ -219,8 +221,20 @@ public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String app String challenge = challengeData.getString("challenge"); String rpId = challengeData.getString("rpId"); String nonce = challengeData.getString("two_step_nonce"); - List allowCredentials = new ArrayList<>(); - WebauthnChallengeInfo info = new WebauthnChallengeInfo(challenge, rpId, nonce, allowCredentials); + List credentials = new ArrayList<>(); + JSONArray allowCredentials = challengeData.getJSONArray("allowCredentials"); + for (int i = 0; i < allowCredentials.length(); i++) { + JSONObject credentialJson = allowCredentials.getJSONObject(i); + JSONArray transportsJson = credentialJson.getJSONArray("transports"); + List transports = new ArrayList<>(); + for (int j = 0; j < transportsJson.length(); j++) { + transports.add(transportsJson.getString(j)); + } + WebauthnCredential credential = new WebauthnCredential(credentialJson.getString("type"), + credentialJson.getString("id"), transports); + credentials.add(credential); + } + WebauthnChallengeInfo info = new WebauthnChallengeInfo(challenge, rpId, nonce, credentials); return Response.success(info, HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException | JSONException e) { return Response.error(new ParseError(e)); diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt index 36bf4b7f1c..b8d812ead2 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt @@ -4,5 +4,11 @@ data class WebauthnChallengeInfo( val challenge: String, val rpId: String, val twoStepNonce: String, - val allowedCredentials: List? + val allowCredentials: List +) + +data class WebauthnCredential( + val type: String, + val id: String, + val transports: List ) From b77798f6b60ef5c736bd92131ff73abc23b4a901 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 21:09:10 -0300 Subject: [PATCH 069/144] Include additional data to the webauthn challenge response --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 3 ++- .../network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt | 3 ++- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index bc3b2fac74..7d719b8cc5 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -221,6 +221,7 @@ public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String app String challenge = challengeData.getString("challenge"); String rpId = challengeData.getString("rpId"); String nonce = challengeData.getString("two_step_nonce"); + int timeout = challengeData.getInt("timeout"); List credentials = new ArrayList<>(); JSONArray allowCredentials = challengeData.getJSONArray("allowCredentials"); for (int i = 0; i < allowCredentials.length(); i++) { @@ -234,7 +235,7 @@ public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String app credentialJson.getString("id"), transports); credentials.add(credential); } - WebauthnChallengeInfo info = new WebauthnChallengeInfo(challenge, rpId, nonce, credentials); + WebauthnChallengeInfo info = new WebauthnChallengeInfo(challenge, rpId, nonce, credentials, timeout); return Response.success(info, HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException | JSONException e) { return Response.error(new ParseError(e)); diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt index b8d812ead2..61a7dfd2b3 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt @@ -4,7 +4,8 @@ data class WebauthnChallengeInfo( val challenge: String, val rpId: String, val twoStepNonce: String, - val allowCredentials: List + val allowCredentials: List, + val timeout: Int ) data class WebauthnCredential( diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index d9c0265799..3a0efc52aa 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -340,6 +340,7 @@ public StartSecurityKeyChallengePayload(String mUserId, String mWebauthnNonce) { public static class OnWebauthnChallengeReceived extends OnChanged { public WebauthnChallengeInfo challengeInfo; + public String mUserId; } public static class WebauthnChallengeError implements OnChangedError { @@ -1369,6 +1370,7 @@ private void requestWebauthnChallenge(final StartSecurityKeyChallengePayload pay info -> { OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); event.challengeInfo = info; + event.mUserId = payload.mUserId; emitChange(event); }, error -> { From e3ed890348b853bdfede3087a880cda72a1ff828 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 21:14:04 -0300 Subject: [PATCH 070/144] Add rawJson parameter to WebauthnChallengeInfo --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 3 ++- .../network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 7d719b8cc5..2f635f6039 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -235,7 +235,8 @@ public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String app credentialJson.getString("id"), transports); credentials.add(credential); } - WebauthnChallengeInfo info = new WebauthnChallengeInfo(challenge, rpId, nonce, credentials, timeout); + WebauthnChallengeInfo info = new WebauthnChallengeInfo(challenge, rpId, nonce, + credentials, timeout, challengeData.toString()); return Response.success(info, HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException | JSONException e) { return Response.error(new ParseError(e)); diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt index 61a7dfd2b3..4fbc1dda5f 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt @@ -5,7 +5,8 @@ data class WebauthnChallengeInfo( val rpId: String, val twoStepNonce: String, val allowCredentials: List, - val timeout: Int + val timeout: Int, + val rawJson: String ) data class WebauthnCredential( From bb72a88fffada0bc21a16e6866258d4cfa64ecbe Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 21:24:51 -0300 Subject: [PATCH 071/144] Fix build issues --- .../network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 64f4f1d139..6890eb2095 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -133,9 +133,9 @@ class PasskeyRestClient @Inject constructor( challenge = this["challenge"] as String, rpId = this["rpId"] as String, twoStepNonce = this["twoStepNonce"] as String, - allowedCredentials = this["allowedCredentials"] - .run { this as? List<*> } - ?.map { it as String } + allowCredentials = emptyList(), + timeout = 0, + rawJson = "" ) private val Map<*, *>.asBearerToken: String From b3afde1e11beaf65c40059eb8100bb9e472ce491 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 21:59:56 -0300 Subject: [PATCH 072/144] Remove unused code from PasskeyRestClient --- .../wpcom/auth/passkey/PasskeyRestClient.kt | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 6890eb2095..7eec47ff5c 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -31,31 +31,6 @@ class PasskeyRestClient @Inject constructor( accessToken, userAgent ) { - @Suppress("LongParameterList") - fun requestWebauthnChallenge( - userId: String, - clientId: String, - secret: String, - twoStepNonce: String, - onSuccess: (response: WebauthnChallengeInfo) -> Unit, - onFailure: (error: WPComGsonNetworkError) -> Unit - ) { - val parameters = mapOf( - "user_id" to userId, - "client_id" to clientId, - "client_secret" to secret, - "auth_type" to "webauthn", - "two_step_nonce" to twoStepNonce - ) - - triggerAccountRequest( - url = webauthnChallengeEndpointUrl, - parameters = parameters, - onSuccess = { onSuccess(it.asChallengeInfo) }, - onFailure = onFailure - ) - } - @Suppress("LongParameterList") suspend fun authenticateWebauthnSignature( userId: Long, @@ -128,16 +103,6 @@ class PasskeyRestClient @Inject constructor( add(request) } - private val Map<*, *>.asChallengeInfo: WebauthnChallengeInfo - get() = WebauthnChallengeInfo( - challenge = this["challenge"] as String, - rpId = this["rpId"] as String, - twoStepNonce = this["twoStepNonce"] as String, - allowCredentials = emptyList(), - timeout = 0, - rawJson = "" - ) - private val Map<*, *>.asBearerToken: String get() = this["data"] ?.run { this as? Map<*, *> } From 91b872e776d3d529f8d429fc662a5255d28f97f9 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 22:00:23 -0300 Subject: [PATCH 073/144] Refactor Challenge response to only relay the raw JSON string --- .../rest/wpcom/auth/Authenticator.java | 34 ++++--------------- .../android/fluxc/store/AccountStore.java | 2 +- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 2f635f6039..1ab3f5ffeb 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -126,7 +126,7 @@ public TokenRequest requestChallenge(String code, Listener listener, ErrorListen } public void requestChallenge(String userId, String webauthnNonce, - Response.Listener listener, + Response.Listener listener, ErrorListener errorListener) { WebauthnChallengeRequest request = new WebauthnChallengeRequest(userId, webauthnNonce, mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), listener, errorListener); @@ -197,12 +197,11 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } - public static class WebauthnChallengeRequest extends Request { - private final Response.Listener mListener; + public static class WebauthnChallengeRequest extends Request { + private final Response.Listener mListener; private Map mParams = new HashMap<>(); - public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String appId, - String appSecret, Response.Listener listener, + String appSecret, Response.Listener listener, ErrorListener errorListener) { super(Method.POST, PasskeyRestClient.webauthnChallengeEndpointUrl, errorListener); mListener = listener; @@ -214,36 +213,17 @@ public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String app } - @Override protected Response parseNetworkResponse(NetworkResponse response) { + @Override protected Response parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); JSONObject challengeData = new JSONObject(jsonString).getJSONObject("data"); - String challenge = challengeData.getString("challenge"); - String rpId = challengeData.getString("rpId"); - String nonce = challengeData.getString("two_step_nonce"); - int timeout = challengeData.getInt("timeout"); - List credentials = new ArrayList<>(); - JSONArray allowCredentials = challengeData.getJSONArray("allowCredentials"); - for (int i = 0; i < allowCredentials.length(); i++) { - JSONObject credentialJson = allowCredentials.getJSONObject(i); - JSONArray transportsJson = credentialJson.getJSONArray("transports"); - List transports = new ArrayList<>(); - for (int j = 0; j < transportsJson.length(); j++) { - transports.add(transportsJson.getString(j)); - } - WebauthnCredential credential = new WebauthnCredential(credentialJson.getString("type"), - credentialJson.getString("id"), transports); - credentials.add(credential); - } - WebauthnChallengeInfo info = new WebauthnChallengeInfo(challenge, rpId, nonce, - credentials, timeout, challengeData.toString()); - return Response.success(info, HttpHeaderParser.parseCacheHeaders(response)); + return Response.success(challengeData.toString(), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException | JSONException e) { return Response.error(new ParseError(e)); } } - @Override protected void deliverResponse(WebauthnChallengeInfo response) { + @Override protected void deliverResponse(String response) { mListener.onResponse(response); } diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 3a0efc52aa..c8b51867c8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -339,7 +339,7 @@ public StartSecurityKeyChallengePayload(String mUserId, String mWebauthnNonce) { } public static class OnWebauthnChallengeReceived extends OnChanged { - public WebauthnChallengeInfo challengeInfo; + public String challengeInfo; public String mUserId; } From c86284e38eda7bfa0b3ad4c1b4baad91066550f7 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 22:02:29 -0300 Subject: [PATCH 074/144] Delete the WebauthnChallengeInfo from FluxC --- .../wpcom/auth/passkey/WebauthnChallengeInfo.kt | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt deleted file mode 100644 index 4fbc1dda5f..0000000000 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnChallengeInfo.kt +++ /dev/null @@ -1,16 +0,0 @@ -package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey - -data class WebauthnChallengeInfo( - val challenge: String, - val rpId: String, - val twoStepNonce: String, - val allowCredentials: List, - val timeout: Int, - val rawJson: String -) - -data class WebauthnCredential( - val type: String, - val id: String, - val transports: List -) From 8a281a0f3b6e628435fb414b61313d9a63a0e256 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 24 Oct 2023 22:03:10 -0300 Subject: [PATCH 075/144] Remove unused imports --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 5 ----- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 1 - 2 files changed, 6 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 1ab3f5ffeb..1cd002a880 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -15,7 +15,6 @@ import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.wordpress.android.fluxc.Dispatcher; @@ -26,8 +25,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnChallengeInfo; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnCredential; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailError; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailErrorType; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; @@ -38,9 +35,7 @@ import org.wordpress.android.util.LanguageUtils; import java.io.UnsupportedEncodingException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import javax.inject.Inject; diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index c8b51867c8..948dfe2088 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -40,7 +40,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.WebauthnChallengeInfo; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; import org.wordpress.android.util.AppLog; From 713609cbebaf6e581d8c421ccf59fc629bba62ac Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 12:43:59 -0300 Subject: [PATCH 076/144] Define Security Key Challenge submission payload and handle events --- .../wordpress/android/fluxc/store/AccountStore.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 948dfe2088..127caeb981 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -342,6 +342,10 @@ public static class OnWebauthnChallengeReceived extends OnChanged Date: Thu, 26 Oct 2023 12:44:11 -0300 Subject: [PATCH 077/144] Update AuthenticationAction with new Security Key payload --- .../android/fluxc/action/AuthenticationAction.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java index f9d1daa5d4..2a1227fd04 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java @@ -9,6 +9,7 @@ import org.wordpress.android.fluxc.store.AccountStore.StartSecurityKeyChallengePayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticateErrorPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticatePayload; +import org.wordpress.android.fluxc.store.AccountStore.FinishSecurityKeyChallengePayload; @ActionEnum public enum AuthenticationAction implements IAction { @@ -28,5 +29,8 @@ public enum AuthenticationAction implements IAction { @Action(payloadType = AuthEmailResponsePayload.class) SENT_AUTH_EMAIL, @Action(payloadType = StartSecurityKeyChallengePayload.class) - SECURITY_KEY_CHALLENGE + START_SECURITY_KEY_CHALLENGE, + + @Action(payloadType = FinishSecurityKeyChallengePayload.class) + FINISH_SECURITY_KEY_CHALLENGE } From e6a094986aee483ff564e0ea1c4a4720e6e79c5a Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 12:52:28 -0300 Subject: [PATCH 078/144] Add FinishSecurityKeyChallengePayload fields --- .../org/wordpress/android/fluxc/store/AccountStore.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 127caeb981..63f3f2bb4a 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -343,7 +343,13 @@ public static class OnWebauthnChallengeReceived extends OnChanged Date: Thu, 26 Oct 2023 15:09:38 -0300 Subject: [PATCH 079/144] Adjust Challenge payload response declarations inside AccountStore --- .../wordpress/android/fluxc/store/AccountStore.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 63f3f2bb4a..8bfea8562c 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -346,10 +346,22 @@ public static class FinishSecurityKeyChallengePayload { public String mId; public String mRawId; public String mType; + public WebauthnChallengeResponse mChallengeResponse; + } + + public static class WebauthnChallengeResponse { public String mUserHandle; public String mClientDataJSON; public String mSignature; public String mAuthenticatorData; + + public WebauthnChallengeResponse(String mUserHandle, String mClientDataJSON, + String mSignature, String mAuthenticatorData) { + this.mUserHandle = mUserHandle; + this.mClientDataJSON = mClientDataJSON; + this.mSignature = mSignature; + this.mAuthenticatorData = mAuthenticatorData; + } } public static class WebauthnChallengeError implements OnChangedError { From 4f5b63d6c21175fec566c0939eb17af2c7df81e3 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 15:13:48 -0300 Subject: [PATCH 080/144] Finish WebauthnTokenRequest implementation --- .../rest/wpcom/auth/Authenticator.java | 53 +++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 1cd002a880..b6a3c721d3 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -14,6 +14,7 @@ import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; +import com.google.gson.Gson; import org.json.JSONException; import org.json.JSONObject; @@ -30,6 +31,7 @@ import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayloadScheme; import org.wordpress.android.fluxc.store.AccountStore.AuthenticationErrorType; +import org.wordpress.android.fluxc.store.AccountStore.WebauthnChallengeResponse; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.LanguageUtils; @@ -208,7 +210,8 @@ public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String app } - @Override protected Response parseNetworkResponse(NetworkResponse response) { + @Override + protected Response parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); JSONObject challengeData = new JSONObject(jsonString).getJSONObject("data"); @@ -218,11 +221,55 @@ public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String app } } - @Override protected void deliverResponse(String response) { + @Override + protected void deliverResponse(String response) { mListener.onResponse(response); } - @Nullable @Override protected Map getParams() throws AuthFailureError { + @Nullable + @Override + protected Map getParams() throws AuthFailureError { + return mParams; + } + } + + public static class WebauthnTokenRequest extends Request { + private final Response.Listener mListener; + private Map mParams = new HashMap<>(); + + public WebauthnTokenRequest(String id, String rawId, + String type, WebauthnChallengeResponse challengeResponse, + Response.Listener listener, ErrorListener errorListener) { + super(Method.POST, PasskeyRestClient.webauthnAuthEndpointUrl, errorListener); + mListener = listener; + String jsonResponse = new Gson().toJson(challengeResponse); + mParams.put("id", id); + mParams.put("rawId", rawId); + mParams.put("type", type); + mParams.put("clientExtensionResults", "{}"); + mParams.put("response", jsonResponse); + } + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + try { + String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); + JSONObject responseData = new JSONObject(jsonString).getJSONObject("data"); + String token = responseData.getString("bearer_token"); + return Response.success(token, HttpHeaderParser.parseCacheHeaders(response)); + } catch(UnsupportedEncodingException | JSONException e) { + return Response.error(new ParseError(e)); + } + } + + @Override + protected void deliverResponse(String response) { + mListener.onResponse(response); + } + + @Nullable + @Override + protected Map getParams() throws AuthFailureError { return mParams; } } From d9a386167c22b26dc5d203ef0b67a9bcc9410b47 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 15:28:22 -0300 Subject: [PATCH 081/144] Fix unwanted method naming change --- .../network/rest/wpcom/auth/Authenticator.java | 16 ++++++++-------- .../android/fluxc/store/AccountStore.java | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index b6a3c721d3..a46b89c1e6 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -102,7 +102,7 @@ public void authenticate(String username, boolean shouldSendTwoStepSMS, Listener listener, ErrorListener errorListener) { - TokenRequest tokenRequest = requestChallenge(username, password, twoStepCode, shouldSendTwoStepSMS, listener, + TokenRequest tokenRequest = makeRequest(username, password, twoStepCode, shouldSendTwoStepSMS, listener, errorListener); mRequestQueue.add(tokenRequest); } @@ -111,20 +111,20 @@ public String getAuthorizationURL() { return String.format(AUTHORIZE_ENDPOINT_FORMAT, AUTHORIZE_ENDPOINT, mAppSecrets.getAppId()); } - public TokenRequest requestChallenge(String username, String password, String twoStepCode, - boolean shouldSendTwoStepSMS, Listener listener, - ErrorListener errorListener) { + public TokenRequest makeRequest(String username, String password, String twoStepCode, + boolean shouldSendTwoStepSMS, Listener listener, + ErrorListener errorListener) { return new PasswordRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), username, password, twoStepCode, shouldSendTwoStepSMS, listener, errorListener); } - public TokenRequest requestChallenge(String code, Listener listener, ErrorListener errorListener) { + public TokenRequest makeRequest(String code, Listener listener, ErrorListener errorListener) { return new BearerRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), code, listener, errorListener); } - public void requestChallenge(String userId, String webauthnNonce, - Response.Listener listener, - ErrorListener errorListener) { + public void makeRequest(String userId, String webauthnNonce, + Response.Listener listener, + ErrorListener errorListener) { WebauthnChallengeRequest request = new WebauthnChallengeRequest(userId, webauthnNonce, mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), listener, errorListener); mRequestQueue.add(request); diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 8bfea8562c..81980974ce 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1390,7 +1390,7 @@ private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { } private void requestWebauthnChallenge(final StartSecurityKeyChallengePayload payload) { - mAuthenticator.requestChallenge(payload.mUserId, payload.mWebauthnNonce, + mAuthenticator.makeRequest(payload.mUserId, payload.mWebauthnNonce, info -> { OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); event.challengeInfo = info; From fb3d9e81149f187c64b3d74ba4c1a27d89be8a2f Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 15:35:03 -0300 Subject: [PATCH 082/144] Create new makeRequest method with WebauthnTokenRequest --- .../fluxc/network/rest/wpcom/auth/Authenticator.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index a46b89c1e6..b831884f02 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -130,6 +130,15 @@ public void makeRequest(String userId, String webauthnNonce, mRequestQueue.add(request); } + public void makeRequest(String id, String rawId, String type, + WebauthnChallengeResponse challengeResponse, + Response.Listener listener, + ErrorListener errorListener) { + WebauthnTokenRequest request = new WebauthnTokenRequest(id, rawId, type, + challengeResponse, listener, errorListener); + mRequestQueue.add(request); + } + private static class TokenRequest extends Request { private final Listener mListener; protected Map mParams = new HashMap<>(); From 99b4118b8323e72cd3086de110af324bb4497ee2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 15:35:11 -0300 Subject: [PATCH 083/144] Trigger token request with webauthn challenge data --- .../wordpress/android/fluxc/store/AccountStore.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 81980974ce..484cca3f6e 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1405,7 +1405,17 @@ private void requestWebauthnChallenge(final StartSecurityKeyChallengePayload pay } private void submitWebauthnChallengeResult(final FinishSecurityKeyChallengePayload payload) { - // TODO: Implement payload submission + mAuthenticator.makeRequest(payload.mId, payload.mRawId, payload.mType, + payload.mChallengeResponse, + token -> { + OnAuthenticationChanged event = new OnAuthenticationChanged(); + emitChange(event); + }, + error -> { + OnAuthenticationChanged event = new OnAuthenticationChanged(); + event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); + emitChange(event); + }); } private boolean checkError(AccountRestPayload payload, String log) { From cc3b44fd99543e3c73ee2e38314408123ae6ce12 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 15:37:02 -0300 Subject: [PATCH 084/144] Fix checkstyle issues --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index b831884f02..c955153344 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -266,7 +266,7 @@ protected Response parseNetworkResponse(NetworkResponse response) { JSONObject responseData = new JSONObject(jsonString).getJSONObject("data"); String token = responseData.getString("bearer_token"); return Response.success(token, HttpHeaderParser.parseCacheHeaders(response)); - } catch(UnsupportedEncodingException | JSONException e) { + } catch (UnsupportedEncodingException | JSONException e) { return Response.error(new ParseError(e)); } } From 12a9c587dcf4990cf63cbab63ae59acc9fa7a8c7 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 17:42:07 -0300 Subject: [PATCH 085/144] Fix Webauthn bearer token request parameters --- .../rest/wpcom/auth/Authenticator.java | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index c955153344..7bffc946e0 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -130,12 +130,12 @@ public void makeRequest(String userId, String webauthnNonce, mRequestQueue.add(request); } - public void makeRequest(String id, String rawId, String type, - WebauthnChallengeResponse challengeResponse, - Response.Listener listener, + public void makeRequest(String userId, String twoStepNonce, + String clientId, String clientSecret, + String clientData, Response.Listener listener, ErrorListener errorListener) { - WebauthnTokenRequest request = new WebauthnTokenRequest(id, rawId, type, - challengeResponse, listener, errorListener); + WebauthnTokenRequest request = new WebauthnTokenRequest(userId, twoStepNonce, clientId, clientSecret, + clientData, listener, errorListener); mRequestQueue.add(request); } @@ -246,17 +246,20 @@ public static class WebauthnTokenRequest extends Request { private final Response.Listener mListener; private Map mParams = new HashMap<>(); - public WebauthnTokenRequest(String id, String rawId, - String type, WebauthnChallengeResponse challengeResponse, - Response.Listener listener, ErrorListener errorListener) { + public WebauthnTokenRequest(String userId, String twoStepNonce, + String clientId, String clientSecret, + String clientData, Response.Listener listener, + ErrorListener errorListener) { super(Method.POST, PasskeyRestClient.webauthnAuthEndpointUrl, errorListener); mListener = listener; - String jsonResponse = new Gson().toJson(challengeResponse); - mParams.put("id", id); - mParams.put("rawId", rawId); - mParams.put("type", type); - mParams.put("clientExtensionResults", "{}"); - mParams.put("response", jsonResponse); + mParams.put("user_id", userId); + mParams.put("two_step_nonce", twoStepNonce); + mParams.put("auth_type", "webauthn"); + mParams.put("client_data", clientData); + mParams.put("client_id", clientId); + mParams.put("client_secret", clientSecret); + mParams.put("get_bearer_token", "true"); + mParams.put("create_2fa_cookies_only", "true"); } @Override From 756ffde2bbf1f405dc63e6c77f845664f027a987 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 17:45:18 -0300 Subject: [PATCH 086/144] Update AccountStore Webauthn token payload --- .../rest/wpcom/auth/Authenticator.java | 1 - .../android/fluxc/store/AccountStore.java | 28 +++++-------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 7bffc946e0..f04a86a3c6 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -31,7 +31,6 @@ import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayloadScheme; import org.wordpress.android.fluxc.store.AccountStore.AuthenticationErrorType; -import org.wordpress.android.fluxc.store.AccountStore.WebauthnChallengeResponse; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.LanguageUtils; diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 484cca3f6e..ef5b8bb8fd 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -343,25 +343,11 @@ public static class OnWebauthnChallengeReceived extends OnChanged { OnAuthenticationChanged event = new OnAuthenticationChanged(); emitChange(event); From 51184ffc758b950a1db33e29b808559be78e8e4d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 17:45:59 -0300 Subject: [PATCH 087/144] Fix checkstyle issues --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index f04a86a3c6..93a7bc0de9 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -14,7 +14,6 @@ import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; -import com.google.gson.Gson; import org.json.JSONException; import org.json.JSONObject; From 38c527ec85372b3bc31408e7ab2c055dea9f457e Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 18:13:33 -0300 Subject: [PATCH 088/144] Use Authenticator client credentials instead of requesting them from a payload --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 4 ++-- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 93a7bc0de9..b26fa9492a 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -129,10 +129,10 @@ public void makeRequest(String userId, String webauthnNonce, } public void makeRequest(String userId, String twoStepNonce, - String clientId, String clientSecret, String clientData, Response.Listener listener, ErrorListener errorListener) { - WebauthnTokenRequest request = new WebauthnTokenRequest(userId, twoStepNonce, clientId, clientSecret, + WebauthnTokenRequest request = new WebauthnTokenRequest(userId, twoStepNonce, + mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), clientData, listener, errorListener); mRequestQueue.add(request); } diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index ef5b8bb8fd..544e9fe3e8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -345,8 +345,6 @@ public static class OnWebauthnChallengeReceived extends OnChanged { OnAuthenticationChanged event = new OnAuthenticationChanged(); emitChange(event); From 32f2984fa86ce1b65ebe0a3337e80eaf91c55233 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 22:43:29 -0300 Subject: [PATCH 089/144] Comment some parameters for test reasons --- .../fluxc/network/rest/wpcom/auth/Authenticator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index b26fa9492a..1a0cde1dfb 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -42,7 +42,7 @@ import javax.inject.Named; public class Authenticator { - private static final String WPCOM_OAUTH_PREFIX = "https://public-api.wordpress.com/oauth2"; + private static final String WPCOM_OAUTH_PREFIX = "https://192.0.92.96/oauth2"; private static final String AUTHORIZE_ENDPOINT = WPCOM_OAUTH_PREFIX + "/authorize"; private static final String TOKEN_ENDPOINT = WPCOM_OAUTH_PREFIX + "/token"; private static final String AUTHORIZE_ENDPOINT_FORMAT = "%s?client_id=%s&response_type=code"; @@ -256,8 +256,8 @@ public WebauthnTokenRequest(String userId, String twoStepNonce, mParams.put("client_data", clientData); mParams.put("client_id", clientId); mParams.put("client_secret", clientSecret); - mParams.put("get_bearer_token", "true"); - mParams.put("create_2fa_cookies_only", "true"); +// mParams.put("get_bearer_token", "true"); +// mParams.put("create_2fa_cookies_only", "true"); } @Override From ff76e4a02fb2652566150f745705ce0bb779ff70 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 26 Oct 2023 23:29:29 -0300 Subject: [PATCH 090/144] Fix WPCOM URL --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 1a0cde1dfb..a3086b1860 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -42,7 +42,7 @@ import javax.inject.Named; public class Authenticator { - private static final String WPCOM_OAUTH_PREFIX = "https://192.0.92.96/oauth2"; + private static final String WPCOM_OAUTH_PREFIX = "https://public-api.wordpress.com/oauth2"; private static final String AUTHORIZE_ENDPOINT = WPCOM_OAUTH_PREFIX + "/authorize"; private static final String TOKEN_ENDPOINT = WPCOM_OAUTH_PREFIX + "/token"; private static final String AUTHORIZE_ENDPOINT_FORMAT = "%s?client_id=%s&response_type=code"; From c46677b76d62dd091213b27cc9dd0bf379f418ae Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 27 Oct 2023 00:25:07 -0300 Subject: [PATCH 091/144] Adjust webauthn authentication function for test purposes --- .../rest/wpcom/auth/Authenticator.java | 6 +- .../wpcom/auth/passkey/PasskeyRestClient.kt | 63 ++++++------------- .../android/fluxc/store/AccountStore.java | 18 +++++- 3 files changed, 39 insertions(+), 48 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index a3086b1860..d0d194cea1 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -68,7 +68,7 @@ public class Authenticator { private final Context mAppContext; private final Dispatcher mDispatcher; private final RequestQueue mRequestQueue; - private AppSecrets mAppSecrets; + public AppSecrets mAppSecrets; public interface Listener extends Response.Listener { } @@ -256,8 +256,8 @@ public WebauthnTokenRequest(String userId, String twoStepNonce, mParams.put("client_data", clientData); mParams.put("client_id", clientId); mParams.put("client_secret", clientSecret); -// mParams.put("get_bearer_token", "true"); -// mParams.put("create_2fa_cookies_only", "true"); + mParams.put("get_bearer_token", "true"); + mParams.put("create_2fa_cookies_only", "true"); } @Override diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 7eec47ff5c..52dcb843b0 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -32,54 +32,32 @@ class PasskeyRestClient @Inject constructor( userAgent ) { @Suppress("LongParameterList") - suspend fun authenticateWebauthnSignature( - userId: Long, - clientId: Long, - secret: String, + fun authenticateWebauthnSignature( + userId: String, twoStepNonce: String, - credentialId: ByteArray, - clientDataJson: ByteArray, - authenticatorData: ByteArray, - signature: ByteArray, - userHandle: ByteArray - ): String { - val clientData = mapOf( - "id" to Base64.encode(credentialId, Base64.DEFAULT), - "rawId" to Base64.encode(credentialId, Base64.DEFAULT), - "type" to "public-key", - "clientExtensionResults" to mapOf(), - "response" to mapOf( - "clientDataJSON" to Base64.encode(clientDataJson, Base64.DEFAULT), - "authenticatorData" to Base64.encode(authenticatorData, Base64.DEFAULT), - "signature" to Base64.encode(signature, Base64.DEFAULT), - "userHandle" to Base64.encode(userHandle, Base64.DEFAULT) - ) - ).let { Gson().toJson(it) } - + clientData: String, + clientId: String, + secret: String, + onSuccess: (response: String) -> Unit, + onFailure: (error: WPComGsonNetworkError) -> Unit + ) { val parameters = mapOf( - "user_id" to userId.toString(), - "client_id" to clientId.toString(), - "client_secret" to secret, - "auth_type" to "webauthn", + "user_id" to userId, "two_step_nonce" to twoStepNonce, + "auth_type" to "webauthn", "client_data" to clientData, - "get_bearer_token" to true.toString(), - "create_2fa_cookies_only" to true.toString() + "client_id" to clientId, + "client_secret" to secret, + "get_bearer_token" to "true", + "create_2fa_cookies_only" to "true" ) - return suspendCoroutine { cont -> - triggerAccountRequest( - url = webauthnAuthEndpointUrl, - parameters = parameters, - onSuccess = { - cont.resumeWith(Result.success(it.asBearerToken)) - }, - onFailure = { - val exception = Exception(it.message) - cont.resumeWith(Result.failure(exception)) - } - ) - } + triggerAccountRequest( + url = webauthnAuthEndpointUrl, + parameters = parameters, + onSuccess = { onSuccess(it.asBearerToken) }, + onFailure = onFailure + ) } private fun triggerAccountRequest( @@ -94,7 +72,6 @@ class PasskeyRestClient @Inject constructor( val request = WPComGsonRequest.buildPostRequest( url, parameters, - emptyMap(), Map::class.java, successListener, failureListener diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 544e9fe3e8..58aae2104b 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -39,6 +39,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnTokenRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; @@ -1389,15 +1390,28 @@ private void requestWebauthnChallenge(final StartSecurityKeyChallengePayload pay } private void submitWebauthnChallengeResult(final FinishSecurityKeyChallengePayload payload) { - mAuthenticator.makeRequest(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, - token -> { +// mAuthenticator.makeRequest(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, +// token -> { +// OnAuthenticationChanged event = new OnAuthenticationChanged(); +// emitChange(event); +// }, +// error -> { +// OnAuthenticationChanged event = new OnAuthenticationChanged(); +// event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); +// emitChange(event); +// }); + mPasskeyRestClient.authenticateWebauthnSignature(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, + mAuthenticator.mAppSecrets.getAppId(), mAuthenticator.mAppSecrets.getAppSecret(), + response -> { OnAuthenticationChanged event = new OnAuthenticationChanged(); emitChange(event); + return null; }, error -> { OnAuthenticationChanged event = new OnAuthenticationChanged(); event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); emitChange(event); + return null; }); } From 7b26a5fd2dd4c28b3915e7617848e8efda2087d1 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 27 Oct 2023 00:31:38 -0300 Subject: [PATCH 092/144] Fix lint issues --- .../fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt | 3 --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 1 - 2 files changed, 4 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt index 52dcb843b0..6da00774fc 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt @@ -1,10 +1,8 @@ package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey import android.content.Context -import android.util.Base64 import com.android.volley.RequestQueue import com.android.volley.Response -import com.google.gson.Gson import org.wordpress.android.fluxc.Dispatcher import org.wordpress.android.fluxc.network.UserAgent import org.wordpress.android.fluxc.network.rest.wpcom.BaseWPComRestClient @@ -15,7 +13,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken import javax.inject.Inject import javax.inject.Named import javax.inject.Singleton -import kotlin.coroutines.suspendCoroutine @Singleton class PasskeyRestClient @Inject constructor( diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 58aae2104b..9f552ea39c 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -39,7 +39,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnTokenRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; From 16c2b656733d080ac9c3adb623a43de0251d2c2d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 27 Oct 2023 01:12:22 -0300 Subject: [PATCH 093/144] Revert unwanted changes --- .../network/rest/wpcom/auth/Authenticator.java | 2 +- .../android/fluxc/store/AccountStore.java | 18 +++--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index d0d194cea1..b26fa9492a 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -68,7 +68,7 @@ public class Authenticator { private final Context mAppContext; private final Dispatcher mDispatcher; private final RequestQueue mRequestQueue; - public AppSecrets mAppSecrets; + private AppSecrets mAppSecrets; public interface Listener extends Response.Listener { } diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 9f552ea39c..d80bf5350f 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -39,6 +39,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnTokenRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; @@ -1389,28 +1390,15 @@ private void requestWebauthnChallenge(final StartSecurityKeyChallengePayload pay } private void submitWebauthnChallengeResult(final FinishSecurityKeyChallengePayload payload) { -// mAuthenticator.makeRequest(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, -// token -> { -// OnAuthenticationChanged event = new OnAuthenticationChanged(); -// emitChange(event); -// }, -// error -> { -// OnAuthenticationChanged event = new OnAuthenticationChanged(); -// event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); -// emitChange(event); -// }); - mPasskeyRestClient.authenticateWebauthnSignature(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, - mAuthenticator.mAppSecrets.getAppId(), mAuthenticator.mAppSecrets.getAppSecret(), - response -> { + mAuthenticator.makeRequest(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, + token -> { OnAuthenticationChanged event = new OnAuthenticationChanged(); emitChange(event); - return null; }, error -> { OnAuthenticationChanged event = new OnAuthenticationChanged(); event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); emitChange(event); - return null; }); } From ff7cc5a056dc0acd57b6fad67d1a0e33a204a9ab Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 27 Oct 2023 04:32:13 -0300 Subject: [PATCH 094/144] Fix checkstyle issues --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 1 - 1 file changed, 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index d80bf5350f..544e9fe3e8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -39,7 +39,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnTokenRequest; import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; From ad984316bf3950203d41775dd61ae0aa32a28870 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 31 Oct 2023 17:55:22 -0300 Subject: [PATCH 095/144] Set token after it's received --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 544e9fe3e8..8f2d295ff9 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1391,8 +1391,8 @@ private void requestWebauthnChallenge(final StartSecurityKeyChallengePayload pay private void submitWebauthnChallengeResult(final FinishSecurityKeyChallengePayload payload) { mAuthenticator.makeRequest(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, token -> { - OnAuthenticationChanged event = new OnAuthenticationChanged(); - emitChange(event); + mAccessToken.set(token); + emitChange(new OnAuthenticationChanged()); }, error -> { OnAuthenticationChanged event = new OnAuthenticationChanged(); From 297503fc7032e6c8ebe894f5f3ed0f394dbec942 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 31 Oct 2023 17:56:00 -0300 Subject: [PATCH 096/144] Add hardcoded error message for Passkey flow --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 8f2d295ff9..a352ee4f2e 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1396,7 +1396,8 @@ private void submitWebauthnChallengeResult(final FinishSecurityKeyChallengePaylo }, error -> { OnAuthenticationChanged event = new OnAuthenticationChanged(); - event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, ""); + event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, + "Passkey login failed"); emitChange(event); }); } From 3460bd27fb43bf0b80b83c33dc3e80e1e106c428 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 31 Oct 2023 18:36:16 -0300 Subject: [PATCH 097/144] Change payload used for finishing the Security Key flow --- .../wordpress/android/fluxc/store/AccountStore.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index a352ee4f2e..2731ccec50 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -348,6 +348,10 @@ public static class FinishSecurityKeyChallengePayload { public String mClientData; } + public static class SecurityKeyCheckFinished extends OnChanged { + public String mBearerToken; + } + public static class WebauthnChallengeError implements OnChangedError { public VolleyError error; @@ -1391,11 +1395,13 @@ private void requestWebauthnChallenge(final StartSecurityKeyChallengePayload pay private void submitWebauthnChallengeResult(final FinishSecurityKeyChallengePayload payload) { mAuthenticator.makeRequest(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, token -> { + SecurityKeyCheckFinished event = new SecurityKeyCheckFinished(); + event.mBearerToken = token; mAccessToken.set(token); - emitChange(new OnAuthenticationChanged()); + emitChange(event); }, error -> { - OnAuthenticationChanged event = new OnAuthenticationChanged(); + SecurityKeyCheckFinished event = new SecurityKeyCheckFinished(); event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, "Passkey login failed"); emitChange(event); From b696857894f2b9c7ea97338f751bb28410122e00 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Tue, 31 Oct 2023 20:04:09 -0300 Subject: [PATCH 098/144] Add dispatching of the next action when trying to authenticate --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 2731ccec50..0a839d1bf9 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -1358,6 +1358,9 @@ private void handleAuthResponse(Token token, AuthenticatePayload payload) { } else if (token.getUserId() != null && token.getWebauthnNonce() != null) { OnSecurityKeyAuthStarted event = new OnSecurityKeyAuthStarted(token.getUserId(), token.getWebauthnNonce()); + if (payload.nextAction != null) { + mDispatcher.dispatch(payload.nextAction); + } emitChange(event); } else { OnAuthenticationChanged event = new OnAuthenticationChanged(); From c073e6d36f73371f90f04c868f67289ec5d07487 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 17:16:10 -0300 Subject: [PATCH 099/144] Refactor Webauthn payloads --- .../fluxc/action/AuthenticationAction.java | 8 ++-- .../android/fluxc/store/AccountStore.java | 42 ++++++++----------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java index 2a1227fd04..e2929ddd65 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java @@ -6,10 +6,10 @@ import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder.DiscoveryResultPayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; -import org.wordpress.android.fluxc.store.AccountStore.StartSecurityKeyChallengePayload; +import org.wordpress.android.fluxc.store.AccountStore.StartWebauthnChallengePayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticateErrorPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticatePayload; -import org.wordpress.android.fluxc.store.AccountStore.FinishSecurityKeyChallengePayload; +import org.wordpress.android.fluxc.store.AccountStore.FinishWebauthnChallengePayload; @ActionEnum public enum AuthenticationAction implements IAction { @@ -28,9 +28,9 @@ public enum AuthenticationAction implements IAction { DISCOVERY_RESULT, @Action(payloadType = AuthEmailResponsePayload.class) SENT_AUTH_EMAIL, - @Action(payloadType = StartSecurityKeyChallengePayload.class) + @Action(payloadType = StartWebauthnChallengePayload.class) START_SECURITY_KEY_CHALLENGE, - @Action(payloadType = FinishSecurityKeyChallengePayload.class) + @Action(payloadType = FinishWebauthnChallengePayload.class) FINISH_SECURITY_KEY_CHALLENGE } diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 0a839d1bf9..8028d48919 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -327,39 +327,31 @@ public enum SubscriptionType { NOTIFICATION_POST } - public static class StartSecurityKeyChallengePayload extends Payload { + public static class StartWebauthnChallengePayload extends Payload { public String mUserId; public String mWebauthnNonce; - public StartSecurityKeyChallengePayload(String mUserId, String mWebauthnNonce) { + public StartWebauthnChallengePayload(String mUserId, String mWebauthnNonce) { this.mUserId = mUserId; this.mWebauthnNonce = mWebauthnNonce; } } - public static class OnWebauthnChallengeReceived extends OnChanged { + public static class WebauthnChallengeReceived extends OnChanged { public String challengeInfo; public String mUserId; } - public static class FinishSecurityKeyChallengePayload { + public static class FinishWebauthnChallengePayload { public String mUserId; public String mTwoStepNonce; public String mClientData; } - public static class SecurityKeyCheckFinished extends OnChanged { + public static class WebauthnPasskeyAuthenticated extends OnChanged { public String mBearerToken; } - public static class WebauthnChallengeError implements OnChangedError { - public VolleyError error; - - public WebauthnChallengeError(VolleyError error) { - this.error = error; - } - } - /** * Error for any of these methods: * {@link AccountRestClient#updateSubscriptionEmailComment(String, @@ -560,6 +552,7 @@ public enum AuthenticationErrorType { UNSUPPORTED_RESPONSE_TYPE, UNKNOWN_TOKEN, EMAIL_LOGIN_NOT_ALLOWED, + WEBAUTHN_FAILED, // From response's "message" field - sadly... (be careful with i18n) INCORRECT_USERNAME_OR_PASSWORD, @@ -1047,10 +1040,10 @@ private void onAuthenticationAction(AuthenticationAction actionType, Object payl handleSentAuthEmail((AuthEmailResponsePayload) payload); break; case START_SECURITY_KEY_CHALLENGE: - requestWebauthnChallenge((StartSecurityKeyChallengePayload) payload); + requestWebauthnChallenge((StartWebauthnChallengePayload) payload); break; case FINISH_SECURITY_KEY_CHALLENGE: - submitWebauthnChallengeResult((FinishSecurityKeyChallengePayload) payload); + submitWebauthnChallengeResult((FinishWebauthnChallengePayload) payload); break; } } @@ -1380,33 +1373,34 @@ private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { } } - private void requestWebauthnChallenge(final StartSecurityKeyChallengePayload payload) { + private void requestWebauthnChallenge(final StartWebauthnChallengePayload payload) { mAuthenticator.makeRequest(payload.mUserId, payload.mWebauthnNonce, info -> { - OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); + WebauthnChallengeReceived event = new WebauthnChallengeReceived(); event.challengeInfo = info; event.mUserId = payload.mUserId; emitChange(event); }, error -> { - OnWebauthnChallengeReceived event = new OnWebauthnChallengeReceived(); - event.error = new WebauthnChallengeError(error); + WebauthnChallengeReceived event = new WebauthnChallengeReceived(); + event.error = new AuthenticationError(AuthenticationErrorType.WEBAUTHN_FAILED, + "Webauthn failed"); emitChange(event); }); } - private void submitWebauthnChallengeResult(final FinishSecurityKeyChallengePayload payload) { + private void submitWebauthnChallengeResult(final FinishWebauthnChallengePayload payload) { mAuthenticator.makeRequest(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, token -> { - SecurityKeyCheckFinished event = new SecurityKeyCheckFinished(); + WebauthnPasskeyAuthenticated event = new WebauthnPasskeyAuthenticated(); event.mBearerToken = token; mAccessToken.set(token); emitChange(event); }, error -> { - SecurityKeyCheckFinished event = new SecurityKeyCheckFinished(); - event.error = new AuthenticationError(AuthenticationErrorType.GENERIC_ERROR, - "Passkey login failed"); + WebauthnPasskeyAuthenticated event = new WebauthnPasskeyAuthenticated(); + event.error = new AuthenticationError(AuthenticationErrorType.WEBAUTHN_FAILED, + "Webauthn failed"); emitChange(event); }); } From a933546b32f78f3ef87e8aef5839471688c769cd Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 17:17:36 -0300 Subject: [PATCH 100/144] Rename passkey package to webauthn --- .../org/wordpress/android/fluxc/account/AccountStoreTest.java | 2 +- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 2 +- .../rest/wpcom/auth/{passkey => webauthn}/PasskeyRestClient.kt | 2 +- .../rest/wpcom/auth/{passkey => webauthn}/WebauthnUserData.kt | 2 +- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 2 +- .../wpcom/auth/{passkey => webauthn}/PasskeyRestClientTest.kt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/{passkey => webauthn}/PasskeyRestClient.kt (97%) rename fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/{passkey => webauthn}/WebauthnUserData.kt (54%) rename fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/{passkey => webauthn}/PasskeyRestClientTest.kt (84%) diff --git a/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java b/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java index 03ac38ae8d..59e4729f53 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java +++ b/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java @@ -21,7 +21,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.account.AccountRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.PasskeyRestClient; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; import org.wordpress.android.fluxc.persistence.WellSqlConfig; import org.wordpress.android.fluxc.store.AccountStore; diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index b26fa9492a..43423baf2e 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -24,7 +24,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.PasskeyRestClient; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailError; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailErrorType; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClient.kt similarity index 97% rename from fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt rename to fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClient.kt index 6da00774fc..36c28877d4 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClient.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClient.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey +package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn import android.content.Context import com.android.volley.RequestQueue diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnUserData.kt similarity index 54% rename from fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt rename to fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnUserData.kt index da9650e26a..2646fda1af 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/WebauthnUserData.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnUserData.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey +package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn data class WebauthnUserData( val userId: Long, diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 8028d48919..dfd56205b6 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -39,7 +39,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey.PasskeyRestClient; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.PasskeyRestClient; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; import org.wordpress.android.util.AppLog; diff --git a/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt b/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClientTest.kt similarity index 84% rename from fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt rename to fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClientTest.kt index a336c743a7..54196a54b2 100644 --- a/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/passkey/PasskeyRestClientTest.kt +++ b/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClientTest.kt @@ -1,4 +1,4 @@ -package org.wordpress.android.fluxc.network.rest.wpcom.auth.passkey +package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn import org.junit.Before import org.mockito.kotlin.mock From 915e97d9b8382dd1f2c21f2ff8e1b07ecb03b996 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 17:45:18 -0300 Subject: [PATCH 101/144] Introduce VolleyWebauthnRequests.kt with WebauthnChallengeRequest --- .../auth/webauthn/VolleyWebauthnRequests.kt | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt new file mode 100644 index 0000000000..7f0f72ba93 --- /dev/null +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt @@ -0,0 +1,70 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn + +import com.android.volley.NetworkResponse +import com.android.volley.ParseError +import com.android.volley.Request +import com.android.volley.Response +import com.android.volley.toolbox.HttpHeaderParser +import org.json.JSONObject +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.AUTH_TYPE +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CLIENT_ID +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CLIENT_SECRET +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.TWO_STEP_NONCE +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.USER_ID + +private const val baseWPLoginUrl = "https://wordpress.com/wp-login.php?action" +private const val challengeEndpoint = "webauthn-challenge-endpoint" +private const val authEndpoint = "webauthn-authentication-endpoint" +private const val webauthnChallengeEndpointUrl = "$baseWPLoginUrl=$challengeEndpoint" +private const val webauthnAuthEndpointUrl = "$baseWPLoginUrl=$authEndpoint" + +enum class WebauthnRequestParameters(val value: String) { + USER_ID("user_id"), + AUTH_TYPE("auth_type"), + TWO_STEP_NONCE("two_step_nonce"), + CLIENT_ID("client_id"), + CLIENT_SECRET("client_secret") +} + +class WebauthnChallengeRequest( + userId: String, + twoStepNonce: String, + clientId: String, + clientSecret: String, + errorListener: Response.ErrorListener, + private val listener: Response.Listener +): Request(Method.POST, webauthnChallengeEndpointUrl, errorListener) { + private val parameters: Map = mapOf( + CLIENT_ID.value to clientId, + CLIENT_SECRET.value to clientSecret, + USER_ID.value to userId, + AUTH_TYPE.value to WEBAUTHN_AUTH_TYPE, + TWO_STEP_NONCE.value to twoStepNonce + ) + + override fun getParams() = parameters + override fun deliverResponse(response: String) = listener.onResponse(response) + override fun parseNetworkResponse(response: NetworkResponse?): Response { + if (response == null) { + val error = WebauthnChallengeRequestException("Webauthn challenge response is null") + return Response.error(ParseError(error)) + } + + return try { + val headers = HttpHeaderParser.parseCacheHeaders(response) + val charsetName = HttpHeaderParser.parseCharset(response.headers) + String(response.data, charset(charsetName)) + .let { JSONObject(it).getJSONObject("data") } + .let { Response.success(it.toString(), headers) } + } catch (exception: Exception) { + val error = WebauthnChallengeRequestException("Webauthn challenge response is invalid") + Response.error(ParseError(error)) + } + } + + class WebauthnChallengeRequestException(message: String): Exception(message) + + companion object { + private const val WEBAUTHN_AUTH_TYPE = "webauthn" + } +} \ No newline at end of file From 97330ea4b1ee69ad8743d92078db36ca47547b01 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 17:51:38 -0300 Subject: [PATCH 102/144] Refactor VolleyWebauthnRequests.kt and add more possible parameters values --- .../auth/webauthn/VolleyWebauthnRequests.kt | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt index 7f0f72ba93..e79f742399 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt @@ -4,26 +4,34 @@ import com.android.volley.NetworkResponse import com.android.volley.ParseError import com.android.volley.Request import com.android.volley.Response +import com.android.volley.Response.ErrorListener import com.android.volley.toolbox.HttpHeaderParser import org.json.JSONObject import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.AUTH_TYPE +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CLIENT_DATA import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CLIENT_ID import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CLIENT_SECRET +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CREATE_2FA_COOKIES_ONLY +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.GET_BEARER_TOKEN import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.TWO_STEP_NONCE import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.USER_ID +private const val WEBAUTHN_AUTH_TYPE = "webauthn" private const val baseWPLoginUrl = "https://wordpress.com/wp-login.php?action" private const val challengeEndpoint = "webauthn-challenge-endpoint" private const val authEndpoint = "webauthn-authentication-endpoint" private const val webauthnChallengeEndpointUrl = "$baseWPLoginUrl=$challengeEndpoint" private const val webauthnAuthEndpointUrl = "$baseWPLoginUrl=$authEndpoint" -enum class WebauthnRequestParameters(val value: String) { +private enum class WebauthnRequestParameters(val value: String) { USER_ID("user_id"), AUTH_TYPE("auth_type"), TWO_STEP_NONCE("two_step_nonce"), CLIENT_ID("client_id"), - CLIENT_SECRET("client_secret") + CLIENT_SECRET("client_secret"), + CLIENT_DATA("client_data"), + GET_BEARER_TOKEN("get_bearer_token"), + CREATE_2FA_COOKIES_ONLY("create_2fa_cookies_only") } class WebauthnChallengeRequest( @@ -31,7 +39,7 @@ class WebauthnChallengeRequest( twoStepNonce: String, clientId: String, clientSecret: String, - errorListener: Response.ErrorListener, + errorListener: ErrorListener, private val listener: Response.Listener ): Request(Method.POST, webauthnChallengeEndpointUrl, errorListener) { private val parameters: Map = mapOf( @@ -42,8 +50,6 @@ class WebauthnChallengeRequest( TWO_STEP_NONCE.value to twoStepNonce ) - override fun getParams() = parameters - override fun deliverResponse(response: String) = listener.onResponse(response) override fun parseNetworkResponse(response: NetworkResponse?): Response { if (response == null) { val error = WebauthnChallengeRequestException("Webauthn challenge response is null") @@ -62,9 +68,7 @@ class WebauthnChallengeRequest( } } + override fun getParams() = parameters + override fun deliverResponse(response: String) = listener.onResponse(response) class WebauthnChallengeRequestException(message: String): Exception(message) - - companion object { - private const val WEBAUTHN_AUTH_TYPE = "webauthn" - } } \ No newline at end of file From f6b06bbcbaa4763844bcae5b5c8a8b77dc3eaa12 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 18:04:39 -0300 Subject: [PATCH 103/144] Introduce WebauthnTokenRequest to VolleyWebauthnRequests.kt --- .../auth/webauthn/VolleyWebauthnRequests.kt | 70 ++++++++++++++----- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt index e79f742399..5ca6561dba 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt @@ -34,6 +34,26 @@ private enum class WebauthnRequestParameters(val value: String) { CREATE_2FA_COOKIES_ONLY("create_2fa_cookies_only") } +class WebauthnChallengeRequestException(message: String): Exception(message) + +private fun NetworkResponse?.extractResult(parameterName: String): Response { + if (this == null) { + val error = WebauthnChallengeRequestException("Webauthn challenge response is null") + return Response.error(ParseError(error)) + } + + return try { + val headers = HttpHeaderParser.parseCacheHeaders(this) + val charsetName = HttpHeaderParser.parseCharset(this.headers) + return String(this.data, charset(charsetName)) + .let { JSONObject(it).getJSONObject(parameterName) } + .let { Response.success(it.toString(), headers) } + } catch (exception: Exception) { + val error = WebauthnChallengeRequestException("Webauthn challenge response is invalid") + Response.error(ParseError(error)) + } +} + class WebauthnChallengeRequest( userId: String, twoStepNonce: String, @@ -50,25 +70,43 @@ class WebauthnChallengeRequest( TWO_STEP_NONCE.value to twoStepNonce ) - override fun parseNetworkResponse(response: NetworkResponse?): Response { - if (response == null) { - val error = WebauthnChallengeRequestException("Webauthn challenge response is null") - return Response.error(ParseError(error)) - } + override fun getParams() = parameters + override fun deliverResponse(response: String) = listener.onResponse(response) + override fun parseNetworkResponse(response: NetworkResponse?) = + response.extractResult(responseParameterName) - return try { - val headers = HttpHeaderParser.parseCacheHeaders(response) - val charsetName = HttpHeaderParser.parseCharset(response.headers) - String(response.data, charset(charsetName)) - .let { JSONObject(it).getJSONObject("data") } - .let { Response.success(it.toString(), headers) } - } catch (exception: Exception) { - val error = WebauthnChallengeRequestException("Webauthn challenge response is invalid") - Response.error(ParseError(error)) - } + companion object { + private const val responseParameterName = "data" } +} + +class WebauthnTokenRequest( + userId: String, + twoStepNonce: String, + clientId: String, + clientSecret: String, + clientData: String, + errorListener: ErrorListener, + private val listener: Response.Listener +) : Request(Method.POST, webauthnAuthEndpointUrl, errorListener) { + private val parameters = mapOf( + CLIENT_ID.value to clientId, + CLIENT_SECRET.value to clientSecret, + USER_ID.value to userId, + AUTH_TYPE.value to WEBAUTHN_AUTH_TYPE, + TWO_STEP_NONCE.value to twoStepNonce, + CLIENT_DATA.value to clientData, + GET_BEARER_TOKEN.value to "true", + CREATE_2FA_COOKIES_ONLY.value to "true" + ) + + override fun parseNetworkResponse(response: NetworkResponse?) = + response.extractResult(responseParameterName) override fun getParams() = parameters override fun deliverResponse(response: String) = listener.onResponse(response) - class WebauthnChallengeRequestException(message: String): Exception(message) + + companion object { + private const val responseParameterName = "bearer_token" + } } \ No newline at end of file From 41b6350de65233f6ed91a03cea127e9235a3df67 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 18:11:44 -0300 Subject: [PATCH 104/144] Improve VolleyWebauthnRequests.kt types --- .../auth/webauthn/VolleyWebauthnRequests.kt | 118 +++++++++--------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt index 5ca6561dba..b7bed6998c 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt @@ -16,53 +16,15 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequ import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.TWO_STEP_NONCE import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.USER_ID -private const val WEBAUTHN_AUTH_TYPE = "webauthn" -private const val baseWPLoginUrl = "https://wordpress.com/wp-login.php?action" -private const val challengeEndpoint = "webauthn-challenge-endpoint" -private const val authEndpoint = "webauthn-authentication-endpoint" -private const val webauthnChallengeEndpointUrl = "$baseWPLoginUrl=$challengeEndpoint" -private const val webauthnAuthEndpointUrl = "$baseWPLoginUrl=$authEndpoint" - -private enum class WebauthnRequestParameters(val value: String) { - USER_ID("user_id"), - AUTH_TYPE("auth_type"), - TWO_STEP_NONCE("two_step_nonce"), - CLIENT_ID("client_id"), - CLIENT_SECRET("client_secret"), - CLIENT_DATA("client_data"), - GET_BEARER_TOKEN("get_bearer_token"), - CREATE_2FA_COOKIES_ONLY("create_2fa_cookies_only") -} - -class WebauthnChallengeRequestException(message: String): Exception(message) - -private fun NetworkResponse?.extractResult(parameterName: String): Response { - if (this == null) { - val error = WebauthnChallengeRequestException("Webauthn challenge response is null") - return Response.error(ParseError(error)) - } - - return try { - val headers = HttpHeaderParser.parseCacheHeaders(this) - val charsetName = HttpHeaderParser.parseCharset(this.headers) - return String(this.data, charset(charsetName)) - .let { JSONObject(it).getJSONObject(parameterName) } - .let { Response.success(it.toString(), headers) } - } catch (exception: Exception) { - val error = WebauthnChallengeRequestException("Webauthn challenge response is invalid") - Response.error(ParseError(error)) - } -} - class WebauthnChallengeRequest( userId: String, twoStepNonce: String, clientId: String, clientSecret: String, - errorListener: ErrorListener, - private val listener: Response.Listener -): Request(Method.POST, webauthnChallengeEndpointUrl, errorListener) { - private val parameters: Map = mapOf( + listener: Response.Listener, + errorListener: ErrorListener +): BaseWebauthnRequest(webauthnChallengeEndpointUrl, errorListener, listener) { + override val parameters: Map = mapOf( CLIENT_ID.value to clientId, CLIENT_SECRET.value to clientSecret, USER_ID.value to userId, @@ -70,14 +32,7 @@ class WebauthnChallengeRequest( TWO_STEP_NONCE.value to twoStepNonce ) - override fun getParams() = parameters - override fun deliverResponse(response: String) = listener.onResponse(response) - override fun parseNetworkResponse(response: NetworkResponse?) = - response.extractResult(responseParameterName) - - companion object { - private const val responseParameterName = "data" - } + override val responseParameterName = "data" } class WebauthnTokenRequest( @@ -86,10 +41,10 @@ class WebauthnTokenRequest( clientId: String, clientSecret: String, clientData: String, - errorListener: ErrorListener, - private val listener: Response.Listener -) : Request(Method.POST, webauthnAuthEndpointUrl, errorListener) { - private val parameters = mapOf( + listener: Response.Listener, + errorListener: ErrorListener +) : BaseWebauthnRequest(webauthnAuthEndpointUrl, errorListener, listener) { + override val parameters = mapOf( CLIENT_ID.value to clientId, CLIENT_SECRET.value to clientSecret, USER_ID.value to userId, @@ -100,13 +55,60 @@ class WebauthnTokenRequest( CREATE_2FA_COOKIES_ONLY.value to "true" ) - override fun parseNetworkResponse(response: NetworkResponse?) = - response.extractResult(responseParameterName) + override val responseParameterName = "bearer_token" +} + +abstract class BaseWebauthnRequest( + url: String, + errorListener: ErrorListener, + private val listener: Response.Listener +) : Request(Method.POST, url, errorListener) { + abstract val parameters: Map + abstract val responseParameterName: String + + private fun NetworkResponse?.extractResult(parameterName: String): Response { + if (this == null) { + val error = WebauthnChallengeRequestException("Webauthn challenge response is null") + return Response.error(ParseError(error)) + } + + return try { + val headers = HttpHeaderParser.parseCacheHeaders(this) + val charsetName = HttpHeaderParser.parseCharset(this.headers) + return String(this.data, charset(charsetName)) + .let { JSONObject(it).getJSONObject(parameterName) } + .let { Response.success(it.toString(), headers) } + } catch (exception: Exception) { + val error = WebauthnChallengeRequestException("Webauthn challenge response is invalid") + Response.error(ParseError(error)) + } + } override fun getParams() = parameters override fun deliverResponse(response: String) = listener.onResponse(response) + override fun parseNetworkResponse(response: NetworkResponse?) = + response.extractResult(responseParameterName) companion object { - private const val responseParameterName = "bearer_token" + private const val baseWPLoginUrl = "https://wordpress.com/wp-login.php?action" + private const val challengeEndpoint = "webauthn-challenge-endpoint" + private const val authEndpoint = "webauthn-authentication-endpoint" + + internal const val webauthnChallengeEndpointUrl = "$baseWPLoginUrl=$challengeEndpoint" + internal const val webauthnAuthEndpointUrl = "$baseWPLoginUrl=$authEndpoint" + internal const val WEBAUTHN_AUTH_TYPE = "webauthn" } -} \ No newline at end of file +} + +private enum class WebauthnRequestParameters(val value: String) { + USER_ID("user_id"), + AUTH_TYPE("auth_type"), + TWO_STEP_NONCE("two_step_nonce"), + CLIENT_ID("client_id"), + CLIENT_SECRET("client_secret"), + CLIENT_DATA("client_data"), + GET_BEARER_TOKEN("get_bearer_token"), + CREATE_2FA_COOKIES_ONLY("create_2fa_cookies_only") +} + +class WebauthnChallengeRequestException(message: String): Exception(message) \ No newline at end of file From 83fd792312fa1dbe33a0220d8c1f4db15b932ad3 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 18:14:22 -0300 Subject: [PATCH 105/144] Remove old request declarations from Authenticator --- .../rest/wpcom/auth/Authenticator.java | 112 +++--------------- 1 file changed, 19 insertions(+), 93 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 43423baf2e..b1d2f5d1c0 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -24,7 +24,8 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.PasskeyRestClient; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnChallengeRequest; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnTokenRequest; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailError; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailErrorType; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; @@ -116,24 +117,32 @@ public TokenRequest makeRequest(String username, String password, String twoStep shouldSendTwoStepSMS, listener, errorListener); } - public TokenRequest makeRequest(String code, Listener listener, ErrorListener errorListener) { - return new BearerRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), code, listener, errorListener); - } - public void makeRequest(String userId, String webauthnNonce, Response.Listener listener, ErrorListener errorListener) { - WebauthnChallengeRequest request = new WebauthnChallengeRequest(userId, webauthnNonce, mAppSecrets.getAppId(), - mAppSecrets.getAppSecret(), listener, errorListener); + WebauthnChallengeRequest request = new WebauthnChallengeRequest( + userId, + webauthnNonce, + mAppSecrets.getAppId(), + mAppSecrets.getAppSecret(), + listener, + errorListener + ); mRequestQueue.add(request); } public void makeRequest(String userId, String twoStepNonce, String clientData, Response.Listener listener, ErrorListener errorListener) { - WebauthnTokenRequest request = new WebauthnTokenRequest(userId, twoStepNonce, - mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), - clientData, listener, errorListener); + WebauthnTokenRequest request = new WebauthnTokenRequest( + userId, + twoStepNonce, + mAppSecrets.getAppId(), + mAppSecrets.getAppSecret(), + clientData, + listener, + errorListener + ); mRequestQueue.add(request); } @@ -201,89 +210,6 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } - public static class WebauthnChallengeRequest extends Request { - private final Response.Listener mListener; - private Map mParams = new HashMap<>(); - public WebauthnChallengeRequest(String userId, String mWebauthnNonce, String appId, - String appSecret, Response.Listener listener, - ErrorListener errorListener) { - super(Method.POST, PasskeyRestClient.webauthnChallengeEndpointUrl, errorListener); - mListener = listener; - mParams.put(CLIENT_ID_PARAM_NAME, appId); - mParams.put(CLIENT_SECRET_PARAM_NAME, appSecret); - mParams.put("user_id", userId); - mParams.put("auth_type", "webauthn"); - mParams.put("two_step_nonce", mWebauthnNonce); - } - - - @Override - protected Response parseNetworkResponse(NetworkResponse response) { - try { - String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); - JSONObject challengeData = new JSONObject(jsonString).getJSONObject("data"); - return Response.success(challengeData.toString(), HttpHeaderParser.parseCacheHeaders(response)); - } catch (UnsupportedEncodingException | JSONException e) { - return Response.error(new ParseError(e)); - } - } - - @Override - protected void deliverResponse(String response) { - mListener.onResponse(response); - } - - @Nullable - @Override - protected Map getParams() throws AuthFailureError { - return mParams; - } - } - - public static class WebauthnTokenRequest extends Request { - private final Response.Listener mListener; - private Map mParams = new HashMap<>(); - - public WebauthnTokenRequest(String userId, String twoStepNonce, - String clientId, String clientSecret, - String clientData, Response.Listener listener, - ErrorListener errorListener) { - super(Method.POST, PasskeyRestClient.webauthnAuthEndpointUrl, errorListener); - mListener = listener; - mParams.put("user_id", userId); - mParams.put("two_step_nonce", twoStepNonce); - mParams.put("auth_type", "webauthn"); - mParams.put("client_data", clientData); - mParams.put("client_id", clientId); - mParams.put("client_secret", clientSecret); - mParams.put("get_bearer_token", "true"); - mParams.put("create_2fa_cookies_only", "true"); - } - - @Override - protected Response parseNetworkResponse(NetworkResponse response) { - try { - String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); - JSONObject responseData = new JSONObject(jsonString).getJSONObject("data"); - String token = responseData.getString("bearer_token"); - return Response.success(token, HttpHeaderParser.parseCacheHeaders(response)); - } catch (UnsupportedEncodingException | JSONException e) { - return Response.error(new ParseError(e)); - } - } - - @Override - protected void deliverResponse(String response) { - mListener.onResponse(response); - } - - @Nullable - @Override - protected Map getParams() throws AuthFailureError { - return mParams; - } - } - public static class Token { private static final String TOKEN_TYPE_FIELD_NAME = "token_type"; private static final String ACCESS_TOKEN_FIELD_NAME = "access_token"; From 79b7c2cb35cbda03829acec3c29e8c4a827207b5 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 18:15:58 -0300 Subject: [PATCH 106/144] Delete PasskeyRestClient.kt --- .../fluxc/account/AccountStoreTest.java | 17 ++-- .../wpcom/auth/webauthn/PasskeyRestClient.kt | 93 ------------------- .../android/fluxc/store/AccountStore.java | 5 +- 3 files changed, 7 insertions(+), 108 deletions(-) delete mode 100644 fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClient.kt diff --git a/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java b/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java index 59e4729f53..88b75da268 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java +++ b/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java @@ -21,7 +21,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.account.AccountRestClient; import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.PasskeyRestClient; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; import org.wordpress.android.fluxc.persistence.WellSqlConfig; import org.wordpress.android.fluxc.store.AccountStore; @@ -52,7 +51,7 @@ public void testLoadAccount() { AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), getMockSelfHostedEndpointFinder(), getMockAuthenticator(), - getMockAccessToken(true), getMockPasskeyRestClient()); + getMockAccessToken(true)); Assert.assertEquals(testAccount, testStore.getAccount()); } @@ -60,10 +59,10 @@ public void testLoadAccount() { public void testHasAccessToken() { AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), getMockSelfHostedEndpointFinder(), getMockAuthenticator(), - getMockAccessToken(true), getMockPasskeyRestClient()); + getMockAccessToken(true)); Assert.assertTrue(testStore.hasAccessToken()); testStore = new AccountStore(new Dispatcher(), getMockRestClient(), getMockSelfHostedEndpointFinder(), - getMockAuthenticator(), getMockAccessToken(false), getMockPasskeyRestClient()); + getMockAuthenticator(), getMockAccessToken(false)); Assert.assertFalse(testStore.hasAccessToken()); } @@ -74,12 +73,12 @@ public void testIsSignedIn() { AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), getMockSelfHostedEndpointFinder(), getMockAuthenticator(), - getMockAccessToken(false), getMockPasskeyRestClient()); + getMockAccessToken(false)); Assert.assertFalse(testStore.hasAccessToken()); testAccount.setVisibleSiteCount(1); AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); testStore = new AccountStore(new Dispatcher(), getMockRestClient(), getMockSelfHostedEndpointFinder(), - getMockAuthenticator(), getMockAccessToken(true), getMockPasskeyRestClient()); + getMockAuthenticator(), getMockAccessToken(true)); Assert.assertTrue(testStore.hasAccessToken()); } @@ -92,7 +91,7 @@ public void testSignOut() throws Exception { AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), getMockSelfHostedEndpointFinder(), getMockAuthenticator(), - testToken, getMockPasskeyRestClient()); + testToken); Assert.assertTrue(testStore.hasAccessToken()); // Signout is private (and it should remain private) Method privateMethod = AccountStore.class.getDeclaredMethod("signOut"); @@ -133,8 +132,4 @@ private AccessToken getMockAccessToken(boolean exists) { private SelfHostedEndpointFinder getMockSelfHostedEndpointFinder() { return Mockito.mock(SelfHostedEndpointFinder.class); } - - private PasskeyRestClient getMockPasskeyRestClient() { - return Mockito.mock(PasskeyRestClient.class); - } } diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClient.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClient.kt deleted file mode 100644 index 36c28877d4..0000000000 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClient.kt +++ /dev/null @@ -1,93 +0,0 @@ -package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn - -import android.content.Context -import com.android.volley.RequestQueue -import com.android.volley.Response -import org.wordpress.android.fluxc.Dispatcher -import org.wordpress.android.fluxc.network.UserAgent -import org.wordpress.android.fluxc.network.rest.wpcom.BaseWPComRestClient -import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest -import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener -import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError -import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken -import javax.inject.Inject -import javax.inject.Named -import javax.inject.Singleton - -@Singleton -class PasskeyRestClient @Inject constructor( - context: Context, - dispatcher: Dispatcher, - @Named("regular") requestQueue: RequestQueue, - accessToken: AccessToken, - userAgent: UserAgent -) : BaseWPComRestClient( - context, - dispatcher, - requestQueue, - accessToken, - userAgent -) { - @Suppress("LongParameterList") - fun authenticateWebauthnSignature( - userId: String, - twoStepNonce: String, - clientData: String, - clientId: String, - secret: String, - onSuccess: (response: String) -> Unit, - onFailure: (error: WPComGsonNetworkError) -> Unit - ) { - val parameters = mapOf( - "user_id" to userId, - "two_step_nonce" to twoStepNonce, - "auth_type" to "webauthn", - "client_data" to clientData, - "client_id" to clientId, - "client_secret" to secret, - "get_bearer_token" to "true", - "create_2fa_cookies_only" to "true" - ) - - triggerAccountRequest( - url = webauthnAuthEndpointUrl, - parameters = parameters, - onSuccess = { onSuccess(it.asBearerToken) }, - onFailure = onFailure - ) - } - - private fun triggerAccountRequest( - url: String, - parameters: Map, - onSuccess: (response: Map<*, *>) -> Unit, - onFailure: (error: WPComGsonNetworkError) -> Unit - ) { - val successListener = Response.Listener> { onSuccess(it) } - val failureListener = WPComErrorListener { onFailure(it) } - - val request = WPComGsonRequest.buildPostRequest( - url, - parameters, - Map::class.java, - successListener, - failureListener - ) - - add(request) - } - - private val Map<*, *>.asBearerToken: String - get() = this["data"] - ?.run { this as? Map<*, *> } - ?.let { this["bearer_token"] as? String } - .orEmpty() - - companion object { - private const val baseWPLoginUrl = "https://wordpress.com/wp-login.php?action" - private const val challengeEndpoint = "webauthn-challenge-endpoint" - private const val authEndpoint = "webauthn-authentication-endpoint" - const val webauthnChallengeEndpointUrl = "$baseWPLoginUrl=$challengeEndpoint" - const val webauthnAuthEndpointUrl = "$baseWPLoginUrl=$authEndpoint" - } -} diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index dfd56205b6..5d0879d6cb 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -39,7 +39,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.PasskeyRestClient; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; import org.wordpress.android.util.AppLog; @@ -869,18 +868,16 @@ public static NewUserErrorType fromString(String string) { private AccountModel mAccount; private AccessToken mAccessToken; private SelfHostedEndpointFinder mSelfHostedEndpointFinder; - private PasskeyRestClient mPasskeyRestClient; @Inject public AccountStore(Dispatcher dispatcher, AccountRestClient accountRestClient, SelfHostedEndpointFinder selfHostedEndpointFinder, Authenticator authenticator, - AccessToken accessToken, PasskeyRestClient passkeyRestClient) { + AccessToken accessToken) { super(dispatcher); mAuthenticator = authenticator; mAccountRestClient = accountRestClient; mSelfHostedEndpointFinder = selfHostedEndpointFinder; mAccount = loadAccount(); mAccessToken = accessToken; - mPasskeyRestClient = passkeyRestClient; } @Override From 784d44f964766786af0e9812d0d170f675fb0d01 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 18:23:16 -0300 Subject: [PATCH 107/144] Fix lint issues --- .../rest/wpcom/auth/Authenticator.java | 2 -- .../auth/webauthn/VolleyWebauthnRequests.kt | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index b1d2f5d1c0..0b6d40a372 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -4,9 +4,7 @@ import android.text.TextUtils; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import com.android.volley.AuthFailureError; import com.android.volley.NetworkResponse; import com.android.volley.ParseError; import com.android.volley.Request; diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt index b7bed6998c..8f9e16ecb2 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt @@ -6,6 +6,7 @@ import com.android.volley.Request import com.android.volley.Response import com.android.volley.Response.ErrorListener import com.android.volley.toolbox.HttpHeaderParser +import org.json.JSONException import org.json.JSONObject import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.AUTH_TYPE import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CLIENT_DATA @@ -15,6 +16,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequ import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.GET_BEARER_TOKEN import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.TWO_STEP_NONCE import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.USER_ID +import java.io.UnsupportedEncodingException class WebauthnChallengeRequest( userId: String, @@ -35,6 +37,7 @@ class WebauthnChallengeRequest( override val responseParameterName = "data" } +@SuppressWarnings("LongParameterList") class WebauthnTokenRequest( userId: String, twoStepNonce: String, @@ -75,13 +78,19 @@ abstract class BaseWebauthnRequest( return try { val headers = HttpHeaderParser.parseCacheHeaders(this) val charsetName = HttpHeaderParser.parseCharset(this.headers) - return String(this.data, charset(charsetName)) + String(this.data, charset(charsetName)) .let { JSONObject(it).getJSONObject(parameterName) } .let { Response.success(it.toString(), headers) } - } catch (exception: Exception) { - val error = WebauthnChallengeRequestException("Webauthn challenge response is invalid") - Response.error(ParseError(error)) } + catch (exception: UnsupportedEncodingException) { handleError(exception) } + catch (exception: JSONException) { handleError(exception) } + + } + + private fun handleError(exception: Exception): Response { + val message = exception.message ?: "Webauthn challenge response is null" + val error = WebauthnChallengeRequestException(message) + return Response.error(ParseError(error)) } override fun getParams() = parameters @@ -111,4 +120,4 @@ private enum class WebauthnRequestParameters(val value: String) { CREATE_2FA_COOKIES_ONLY("create_2fa_cookies_only") } -class WebauthnChallengeRequestException(message: String): Exception(message) \ No newline at end of file +class WebauthnChallengeRequestException(message: String): Exception(message) From f8ba58b1e2c5e51220108df30201618fa3465d6b Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 18:23:56 -0300 Subject: [PATCH 108/144] Delete PasskeyRestClientTest.kt --- .../auth/webauthn/PasskeyRestClientTest.kt | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClientTest.kt diff --git a/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClientTest.kt b/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClientTest.kt deleted file mode 100644 index 54196a54b2..0000000000 --- a/fluxc/src/test/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/PasskeyRestClientTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn - -import org.junit.Before -import org.mockito.kotlin.mock - -class PasskeyRestClientTest { - private lateinit var sut: PasskeyRestClient - - @Before - fun setUp() { - sut = PasskeyRestClient( - context = mock(), - dispatcher = mock(), - requestQueue = mock(), - accessToken = mock(), - userAgent = mock() - ) - } -} From a7ba49a5d341bc69759257d56a43428737ad6208 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 18:34:45 -0300 Subject: [PATCH 109/144] Fix checkstyle issues --- .../android/fluxc/account/AccountStoreTest.java | 12 ++++-------- .../wpcom/auth/webauthn/VolleyWebauthnRequests.kt | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java b/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java index 88b75da268..75be3d6fb7 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java +++ b/example/src/test/java/org/wordpress/android/fluxc/account/AccountStoreTest.java @@ -50,16 +50,14 @@ public void testLoadAccount() { testAccount.setAboutMe("testAboutMe"); AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), - getMockSelfHostedEndpointFinder(), getMockAuthenticator(), - getMockAccessToken(true)); + getMockSelfHostedEndpointFinder(), getMockAuthenticator(), getMockAccessToken(true)); Assert.assertEquals(testAccount, testStore.getAccount()); } @Test public void testHasAccessToken() { AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), - getMockSelfHostedEndpointFinder(), getMockAuthenticator(), - getMockAccessToken(true)); + getMockSelfHostedEndpointFinder(), getMockAuthenticator(), getMockAccessToken(true)); Assert.assertTrue(testStore.hasAccessToken()); testStore = new AccountStore(new Dispatcher(), getMockRestClient(), getMockSelfHostedEndpointFinder(), getMockAuthenticator(), getMockAccessToken(false)); @@ -72,8 +70,7 @@ public void testIsSignedIn() { testAccount.setVisibleSiteCount(0); AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), - getMockSelfHostedEndpointFinder(), getMockAuthenticator(), - getMockAccessToken(false)); + getMockSelfHostedEndpointFinder(), getMockAuthenticator(), getMockAccessToken(false)); Assert.assertFalse(testStore.hasAccessToken()); testAccount.setVisibleSiteCount(1); AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); @@ -90,8 +87,7 @@ public void testSignOut() throws Exception { testAccount.setUserId(24); AccountSqlUtils.insertOrUpdateDefaultAccount(testAccount); AccountStore testStore = new AccountStore(new Dispatcher(), getMockRestClient(), - getMockSelfHostedEndpointFinder(), getMockAuthenticator(), - testToken); + getMockSelfHostedEndpointFinder(), getMockAuthenticator(), testToken); Assert.assertTrue(testStore.hasAccessToken()); // Signout is private (and it should remain private) Method privateMethod = AccountStore.class.getDeclaredMethod("signOut"); diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt index 8f9e16ecb2..6c164bfd9e 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt @@ -84,7 +84,6 @@ abstract class BaseWebauthnRequest( } catch (exception: UnsupportedEncodingException) { handleError(exception) } catch (exception: JSONException) { handleError(exception) } - } private fun handleError(exception: Exception): Response { From 46dd32a4496cc67a927dbb8239d1da5416edaae9 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 20:31:27 -0300 Subject: [PATCH 110/144] Introduce WebauthnModels.kt --- .../wpcom/auth/webauthn/WebauthnModels.kt | 25 +++++++++++++++++++ .../wpcom/auth/webauthn/WebauthnUserData.kt | 6 ----- 2 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt delete mode 100644 fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnUserData.kt diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt new file mode 100644 index 0000000000..c8639095f0 --- /dev/null +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt @@ -0,0 +1,25 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn + +import com.google.gson.annotations.SerializedName + +class WebauthnChallengeInfo( + val challenge: String, + val rpId: String, + val allowCredentials: List, + val timeout: Int, + @SerializedName("two_step_nonce") + val twoStepNonce: String +) + +class WebauthnCredentialResponse( + val type: String, + val id: String, + val transports: List +) + +class WebauthnToken( + @SerializedName("bearer_token") + val bearerToken: String, + @SerializedName("token_links") + val tokenLinks: String +) \ No newline at end of file diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnUserData.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnUserData.kt deleted file mode 100644 index 2646fda1af..0000000000 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnUserData.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn - -data class WebauthnUserData( - val userId: Long, - val webauthnNonce: String -) From 5f4a0744ef953222043a166e260ba8d3ab83525e Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 20:34:33 -0300 Subject: [PATCH 111/144] Overhaul VolleyWebauthnRequests.kt structure --- .../auth/webauthn/VolleyWebauthnRequests.kt | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt index 6c164bfd9e..f54f97f37e 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt @@ -6,6 +6,7 @@ import com.android.volley.Request import com.android.volley.Response import com.android.volley.Response.ErrorListener import com.android.volley.toolbox.HttpHeaderParser +import com.google.gson.Gson import org.json.JSONException import org.json.JSONObject import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.AUTH_TYPE @@ -23,9 +24,9 @@ class WebauthnChallengeRequest( twoStepNonce: String, clientId: String, clientSecret: String, - listener: Response.Listener, + listener: Response.Listener, errorListener: ErrorListener -): BaseWebauthnRequest(webauthnChallengeEndpointUrl, errorListener, listener) { +): BaseWebauthnRequest(webauthnChallengeEndpointUrl, errorListener, listener) { override val parameters: Map = mapOf( CLIENT_ID.value to clientId, CLIENT_SECRET.value to clientSecret, @@ -34,7 +35,8 @@ class WebauthnChallengeRequest( TWO_STEP_NONCE.value to twoStepNonce ) - override val responseParameterName = "data" + override fun serializeResponse(response: String): WebauthnChallengeInfo = + gson.fromJson(response, WebauthnChallengeInfo::class.java) } @SuppressWarnings("LongParameterList") @@ -44,9 +46,9 @@ class WebauthnTokenRequest( clientId: String, clientSecret: String, clientData: String, - listener: Response.Listener, + listener: Response.Listener, errorListener: ErrorListener -) : BaseWebauthnRequest(webauthnAuthEndpointUrl, errorListener, listener) { +) : BaseWebauthnRequest(webauthnAuthEndpointUrl, errorListener, listener) { override val parameters = mapOf( CLIENT_ID.value to clientId, CLIENT_SECRET.value to clientSecret, @@ -58,18 +60,21 @@ class WebauthnTokenRequest( CREATE_2FA_COOKIES_ONLY.value to "true" ) - override val responseParameterName = "bearer_token" + override fun serializeResponse(response: String): WebauthnToken = + gson.fromJson(response, WebauthnToken::class.java) } -abstract class BaseWebauthnRequest( +abstract class BaseWebauthnRequest( url: String, errorListener: ErrorListener, - private val listener: Response.Listener -) : Request(Method.POST, url, errorListener) { + private val listener: Response.Listener +) : Request(Method.POST, url, errorListener) { abstract val parameters: Map - abstract val responseParameterName: String + abstract fun serializeResponse(response: String): T - private fun NetworkResponse?.extractResult(parameterName: String): Response { + internal val gson by lazy { Gson() } + + private fun NetworkResponse?.extractResult(parameterName: String): Response { if (this == null) { val error = WebauthnChallengeRequestException("Webauthn challenge response is null") return Response.error(ParseError(error)) @@ -80,27 +85,29 @@ abstract class BaseWebauthnRequest( val charsetName = HttpHeaderParser.parseCharset(this.headers) String(this.data, charset(charsetName)) .let { JSONObject(it).getJSONObject(parameterName) } - .let { Response.success(it.toString(), headers) } + .let { serializeResponse(it.toString()) } + .let { Response.success(it, headers) } } catch (exception: UnsupportedEncodingException) { handleError(exception) } catch (exception: JSONException) { handleError(exception) } } - private fun handleError(exception: Exception): Response { + private fun handleError(exception: Exception): Response { val message = exception.message ?: "Webauthn challenge response is null" val error = WebauthnChallengeRequestException(message) return Response.error(ParseError(error)) } override fun getParams() = parameters - override fun deliverResponse(response: String) = listener.onResponse(response) + override fun deliverResponse(response: T) = listener.onResponse(response) override fun parseNetworkResponse(response: NetworkResponse?) = - response.extractResult(responseParameterName) + response.extractResult(WEBAUTHN_DATA) companion object { private const val baseWPLoginUrl = "https://wordpress.com/wp-login.php?action" private const val challengeEndpoint = "webauthn-challenge-endpoint" private const val authEndpoint = "webauthn-authentication-endpoint" + private const val WEBAUTHN_DATA = "data" internal const val webauthnChallengeEndpointUrl = "$baseWPLoginUrl=$challengeEndpoint" internal const val webauthnAuthEndpointUrl = "$baseWPLoginUrl=$authEndpoint" From fdf26d81569dc253dc193053ca18242b171f3ddf Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 20:34:52 -0300 Subject: [PATCH 112/144] Update AccountStore and Authenticator to correctly set the dedicated models --- .../fluxc/network/rest/wpcom/auth/Authenticator.java | 6 ++++-- .../wordpress/android/fluxc/store/AccountStore.java | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 0b6d40a372..d1bfa251d0 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -22,7 +22,9 @@ import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComErrorListener; import org.wordpress.android.fluxc.network.rest.wpcom.WPComGsonRequest.WPComGsonNetworkError; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnChallengeInfo; import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnChallengeRequest; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnToken; import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnTokenRequest; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailError; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailErrorType; @@ -116,7 +118,7 @@ public TokenRequest makeRequest(String username, String password, String twoStep } public void makeRequest(String userId, String webauthnNonce, - Response.Listener listener, + Response.Listener listener, ErrorListener errorListener) { WebauthnChallengeRequest request = new WebauthnChallengeRequest( userId, @@ -130,7 +132,7 @@ public void makeRequest(String userId, String webauthnNonce, } public void makeRequest(String userId, String twoStepNonce, - String clientData, Response.Listener listener, + String clientData, Response.Listener listener, ErrorListener errorListener) { WebauthnTokenRequest request = new WebauthnTokenRequest( userId, diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 5d0879d6cb..11f35b12f2 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -39,6 +39,8 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnChallengeInfo; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnToken; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; import org.wordpress.android.fluxc.persistence.AccountSqlUtils; import org.wordpress.android.util.AppLog; @@ -337,7 +339,7 @@ public StartWebauthnChallengePayload(String mUserId, String mWebauthnNonce) { } public static class WebauthnChallengeReceived extends OnChanged { - public String challengeInfo; + public WebauthnChallengeInfo mChallengeInfo; public String mUserId; } @@ -348,7 +350,7 @@ public static class FinishWebauthnChallengePayload { } public static class WebauthnPasskeyAuthenticated extends OnChanged { - public String mBearerToken; + public WebauthnToken mWebauthnToken; } /** @@ -1374,7 +1376,7 @@ private void requestWebauthnChallenge(final StartWebauthnChallengePayload payloa mAuthenticator.makeRequest(payload.mUserId, payload.mWebauthnNonce, info -> { WebauthnChallengeReceived event = new WebauthnChallengeReceived(); - event.challengeInfo = info; + event.mChallengeInfo = info; event.mUserId = payload.mUserId; emitChange(event); }, @@ -1390,8 +1392,8 @@ private void submitWebauthnChallengeResult(final FinishWebauthnChallengePayload mAuthenticator.makeRequest(payload.mUserId, payload.mTwoStepNonce, payload.mClientData, token -> { WebauthnPasskeyAuthenticated event = new WebauthnPasskeyAuthenticated(); - event.mBearerToken = token; - mAccessToken.set(token); + event.mWebauthnToken = token; + mAccessToken.set(token.getBearerToken()); emitChange(event); }, error -> { From 5550a55ea12d374fd42749a7f515f8e6bc934087 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 20:41:43 -0300 Subject: [PATCH 113/144] Refactor file distribution for Webauthn classes --- .../auth/webauthn/BaseWebauthnRequest.kt | 69 +++++++++++++++ .../auth/webauthn/VolleyWebauthnRequests.kt | 88 ++----------------- .../wpcom/auth/webauthn/WebauthnModels.kt | 2 +- 3 files changed, 78 insertions(+), 81 deletions(-) create mode 100644 fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/BaseWebauthnRequest.kt diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/BaseWebauthnRequest.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/BaseWebauthnRequest.kt new file mode 100644 index 0000000000..34e25b4349 --- /dev/null +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/BaseWebauthnRequest.kt @@ -0,0 +1,69 @@ +package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn + +import com.android.volley.NetworkResponse +import com.android.volley.ParseError +import com.android.volley.Request +import com.android.volley.Response +import com.android.volley.Response.ErrorListener +import com.android.volley.toolbox.HttpHeaderParser +import com.google.gson.Gson +import org.json.JSONException +import org.json.JSONObject +import java.io.UnsupportedEncodingException + +abstract class BaseWebauthnRequest( + url: String, + errorListener: ErrorListener, + private val listener: Response.Listener +) : Request(Method.POST, url, errorListener) { + abstract val parameters: Map + abstract fun serializeResponse(response: String): T + + internal val gson by lazy { Gson() } + + private fun NetworkResponse?.extractResult(): Response { + if (this == null) { + val error = WebauthnChallengeRequestException("Webauthn challenge response is null") + return Response.error(ParseError(error)) + } + + return try { + val headers = HttpHeaderParser.parseCacheHeaders(this) + val charsetName = HttpHeaderParser.parseCharset(this.headers) + String(this.data, charset(charsetName)) + .let { JSONObject(it).getJSONObject(WEBAUTHN_DATA) } + .let { serializeResponse(it.toString()) } + .let { Response.success(it, headers) } + } + catch (exception: UnsupportedEncodingException) { Response.error(ParseError(exception)) } + catch (exception: JSONException) { Response.error(ParseError(exception)) } + } + + override fun getParams() = parameters + override fun deliverResponse(response: T) = listener.onResponse(response) + override fun parseNetworkResponse(response: NetworkResponse?) = response.extractResult() + + internal enum class WebauthnRequestParameters(val value: String) { + USER_ID("user_id"), + AUTH_TYPE("auth_type"), + TWO_STEP_NONCE("two_step_nonce"), + CLIENT_ID("client_id"), + CLIENT_SECRET("client_secret"), + CLIENT_DATA("client_data"), + GET_BEARER_TOKEN("get_bearer_token"), + CREATE_2FA_COOKIES_ONLY("create_2fa_cookies_only") + } + + class WebauthnChallengeRequestException(message: String): Exception(message) + + companion object { + private const val baseWPLoginUrl = "https://wordpress.com/wp-login.php?action" + private const val challengeEndpoint = "webauthn-challenge-endpoint" + private const val authEndpoint = "webauthn-authentication-endpoint" + private const val WEBAUTHN_DATA = "data" + + internal const val webauthnChallengeEndpointUrl = "$baseWPLoginUrl=$challengeEndpoint" + internal const val webauthnAuthEndpointUrl = "$baseWPLoginUrl=$authEndpoint" + internal const val WEBAUTHN_AUTH_TYPE = "webauthn" + } +} diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt index f54f97f37e..e84f4bbbd9 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/VolleyWebauthnRequests.kt @@ -1,23 +1,15 @@ package org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn -import com.android.volley.NetworkResponse -import com.android.volley.ParseError -import com.android.volley.Request import com.android.volley.Response import com.android.volley.Response.ErrorListener -import com.android.volley.toolbox.HttpHeaderParser -import com.google.gson.Gson -import org.json.JSONException -import org.json.JSONObject -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.AUTH_TYPE -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CLIENT_DATA -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CLIENT_ID -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CLIENT_SECRET -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.CREATE_2FA_COOKIES_ONLY -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.GET_BEARER_TOKEN -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.TWO_STEP_NONCE -import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnRequestParameters.USER_ID -import java.io.UnsupportedEncodingException +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.BaseWebauthnRequest.WebauthnRequestParameters.AUTH_TYPE +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.BaseWebauthnRequest.WebauthnRequestParameters.CLIENT_DATA +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.BaseWebauthnRequest.WebauthnRequestParameters.CLIENT_ID +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.BaseWebauthnRequest.WebauthnRequestParameters.CLIENT_SECRET +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.BaseWebauthnRequest.WebauthnRequestParameters.CREATE_2FA_COOKIES_ONLY +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.BaseWebauthnRequest.WebauthnRequestParameters.GET_BEARER_TOKEN +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.BaseWebauthnRequest.WebauthnRequestParameters.TWO_STEP_NONCE +import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.BaseWebauthnRequest.WebauthnRequestParameters.USER_ID class WebauthnChallengeRequest( userId: String, @@ -63,67 +55,3 @@ class WebauthnTokenRequest( override fun serializeResponse(response: String): WebauthnToken = gson.fromJson(response, WebauthnToken::class.java) } - -abstract class BaseWebauthnRequest( - url: String, - errorListener: ErrorListener, - private val listener: Response.Listener -) : Request(Method.POST, url, errorListener) { - abstract val parameters: Map - abstract fun serializeResponse(response: String): T - - internal val gson by lazy { Gson() } - - private fun NetworkResponse?.extractResult(parameterName: String): Response { - if (this == null) { - val error = WebauthnChallengeRequestException("Webauthn challenge response is null") - return Response.error(ParseError(error)) - } - - return try { - val headers = HttpHeaderParser.parseCacheHeaders(this) - val charsetName = HttpHeaderParser.parseCharset(this.headers) - String(this.data, charset(charsetName)) - .let { JSONObject(it).getJSONObject(parameterName) } - .let { serializeResponse(it.toString()) } - .let { Response.success(it, headers) } - } - catch (exception: UnsupportedEncodingException) { handleError(exception) } - catch (exception: JSONException) { handleError(exception) } - } - - private fun handleError(exception: Exception): Response { - val message = exception.message ?: "Webauthn challenge response is null" - val error = WebauthnChallengeRequestException(message) - return Response.error(ParseError(error)) - } - - override fun getParams() = parameters - override fun deliverResponse(response: T) = listener.onResponse(response) - override fun parseNetworkResponse(response: NetworkResponse?) = - response.extractResult(WEBAUTHN_DATA) - - companion object { - private const val baseWPLoginUrl = "https://wordpress.com/wp-login.php?action" - private const val challengeEndpoint = "webauthn-challenge-endpoint" - private const val authEndpoint = "webauthn-authentication-endpoint" - private const val WEBAUTHN_DATA = "data" - - internal const val webauthnChallengeEndpointUrl = "$baseWPLoginUrl=$challengeEndpoint" - internal const val webauthnAuthEndpointUrl = "$baseWPLoginUrl=$authEndpoint" - internal const val WEBAUTHN_AUTH_TYPE = "webauthn" - } -} - -private enum class WebauthnRequestParameters(val value: String) { - USER_ID("user_id"), - AUTH_TYPE("auth_type"), - TWO_STEP_NONCE("two_step_nonce"), - CLIENT_ID("client_id"), - CLIENT_SECRET("client_secret"), - CLIENT_DATA("client_data"), - GET_BEARER_TOKEN("get_bearer_token"), - CREATE_2FA_COOKIES_ONLY("create_2fa_cookies_only") -} - -class WebauthnChallengeRequestException(message: String): Exception(message) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt index c8639095f0..3db090e200 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt @@ -22,4 +22,4 @@ class WebauthnToken( val bearerToken: String, @SerializedName("token_links") val tokenLinks: String -) \ No newline at end of file +) From c1a8ea1cec3228e989fd958a521aaaa8b6b24f26 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Wed, 1 Nov 2023 21:40:14 -0300 Subject: [PATCH 114/144] Remove unnecessary field from WebauthnToken model --- .../fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt index 3db090e200..b0d4876d84 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/webauthn/WebauthnModels.kt @@ -19,7 +19,5 @@ class WebauthnCredentialResponse( class WebauthnToken( @SerializedName("bearer_token") - val bearerToken: String, - @SerializedName("token_links") - val tokenLinks: String + val bearerToken: String ) From 2e52242ca83065edfe2c4a0611f53b0afb7839ca Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 2 Nov 2023 19:15:47 -0300 Subject: [PATCH 115/144] Refactor Token response to use a interface for better result handling --- .../rest/wpcom/auth/Authenticator.java | 69 ++++++++++--------- .../android/fluxc/store/AccountStore.java | 18 +++-- 2 files changed, 48 insertions(+), 39 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index d1bfa251d0..eb785e3528 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -71,7 +71,7 @@ public class Authenticator { private final RequestQueue mRequestQueue; private AppSecrets mAppSecrets; - public interface Listener extends Response.Listener { + public interface Listener extends Response.Listener { } public interface ErrorListener extends Response.ErrorListener { @@ -146,7 +146,8 @@ public void makeRequest(String userId, String twoStepNonce, mRequestQueue.add(request); } - private static class TokenRequest extends Request { + private static class TokenRequest extends Request { + private static final String DATA = "data"; private final Listener mListener; protected Map mParams = new HashMap<>(); @@ -163,20 +164,25 @@ public Map getParams() { } @Override - public void deliverResponse(Token token) { - mListener.onResponse(token); + public void deliverResponse(OauthResponse response) { + mListener.onResponse(response); } @Override - protected Response parseNetworkResponse(NetworkResponse response) { + protected Response parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); - JSONObject tokenData = new JSONObject(jsonString); - return Response.success(Token.fromJSONObject(tokenData), HttpHeaderParser.parseCacheHeaders(response)); - } catch (UnsupportedEncodingException e) { + JSONObject responseData = new JSONObject(jsonString); + JSONObject successData = responseData.optJSONObject(DATA); + if (successData != null) { + return Response.success(new WebauthnResponse(successData), + HttpHeaderParser.parseCacheHeaders(response)); + } + + return Response.success(Token.fromJSONObject(responseData), + HttpHeaderParser.parseCacheHeaders(response)); + } catch (UnsupportedEncodingException | JSONException e) { return Response.error(new ParseError(e)); - } catch (JSONException je) { - return Response.error(new ParseError(je)); } } } @@ -210,23 +216,20 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste } } - public static class Token { + public interface OauthResponse {} + + public static class Token implements OauthResponse { private static final String TOKEN_TYPE_FIELD_NAME = "token_type"; private static final String ACCESS_TOKEN_FIELD_NAME = "access_token"; private static final String SITE_URL_FIELD_NAME = "blog_url"; private static final String SCOPE_FIELD_NAME = "scope"; private static final String SITE_ID_FIELD_NAME = "blog_id"; - private static final String DATA = "data"; - private static final String USER_ID = "user_id"; - private static final String TWO_STEP_WEBAUTHN_NONCE = "two_step_nonce_webauthn"; private String mTokenType; private String mScope; private String mAccessToken; private String mSiteUrl; private String mSiteId; - private String mUserId; - private String mTwoStepWebauthnNonce; public Token(String accessToken, String siteUrl, String siteId, String scope, String tokenType) { mAccessToken = accessToken; @@ -236,11 +239,6 @@ public Token(String accessToken, String siteUrl, String siteId, String scope, St mTokenType = tokenType; } - public Token(String userId, String webAuthTwoStepNonce) { - mUserId = userId; - mTwoStepWebauthnNonce = webAuthTwoStepNonce; - } - public String getAccessToken() { return mAccessToken; } @@ -249,6 +247,24 @@ public String toString() { return getAccessToken(); } + public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { + return new Token(tokenJSON.getString(ACCESS_TOKEN_FIELD_NAME), tokenJSON.getString(SITE_URL_FIELD_NAME), + tokenJSON.getString(SITE_ID_FIELD_NAME), tokenJSON.getString(SCOPE_FIELD_NAME), + tokenJSON.getString(TOKEN_TYPE_FIELD_NAME)); + } + } + + public static class WebauthnResponse implements OauthResponse { + private static final String USER_ID = "user_id"; + private static final String TWO_STEP_WEBAUTHN_NONCE = "two_step_nonce_webauthn"; + private String mUserId; + private String mTwoStepWebauthnNonce; + + public WebauthnResponse(JSONObject data) throws JSONException { + mUserId = data.getString(USER_ID); + mTwoStepWebauthnNonce = data.getString(TWO_STEP_WEBAUTHN_NONCE); + } + public String getUserId() { return mUserId; } @@ -256,17 +272,6 @@ public String getUserId() { public String getWebauthnNonce() { return mTwoStepWebauthnNonce; } - - public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { - JSONObject data = tokenJSON.optJSONObject(DATA); - if (data != null) { - return new Token(data.getString(USER_ID), data.getString(TWO_STEP_WEBAUTHN_NONCE)); - } - - return new Token(tokenJSON.getString(ACCESS_TOKEN_FIELD_NAME), tokenJSON.getString(SITE_URL_FIELD_NAME), - tokenJSON.getString(SITE_ID_FIELD_NAME), tokenJSON.getString(SCOPE_FIELD_NAME), - tokenJSON.getString(TOKEN_TYPE_FIELD_NAME)); - } } public void sendAuthEmail(final AuthEmailPayload payload) { diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 11f35b12f2..66c6173d6e 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -38,7 +38,9 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.AccessToken; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.OauthResponse; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnResponse; import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnChallengeInfo; import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnToken; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; @@ -1326,7 +1328,7 @@ private AccountModel loadAccount() { private void authenticate(final AuthenticatePayload payload) { mAuthenticator.authenticate(payload.username, payload.password, payload.twoStepCode, payload.shouldSendTwoStepSms, - token -> handleAuthResponse(token, payload), + response -> handleAuthResponse(response, payload), this::handleAuthError); } @@ -1339,17 +1341,19 @@ private void handleAuthError(VolleyError volleyError) { emitChange(event); } - private void handleAuthResponse(Token token, AuthenticatePayload payload) { - // Check if token exists, if not, check for security key - if (token.getAccessToken() != null) { + private void handleAuthResponse(OauthResponse response, AuthenticatePayload payload) { + // Oauth endpoint can return a Token or a WebauthnResponse + if (response instanceof Token) { + Token token = (Token) response; mAccessToken.set(token.getAccessToken()); if (payload.nextAction != null) { mDispatcher.dispatch(payload.nextAction); } emitChange(new OnAuthenticationChanged()); - } else if (token.getUserId() != null && token.getWebauthnNonce() != null) { - OnSecurityKeyAuthStarted event = new OnSecurityKeyAuthStarted(token.getUserId(), - token.getWebauthnNonce()); + } else if (response instanceof WebauthnResponse) { + WebauthnResponse webauthnResponse = (WebauthnResponse) response; + OnSecurityKeyAuthStarted event = new OnSecurityKeyAuthStarted(webauthnResponse.getUserId(), + webauthnResponse.getWebauthnNonce()); if (payload.nextAction != null) { mDispatcher.dispatch(payload.nextAction); } From 07fd32cc7c4c70a4be9cb059b92d4a99843cd982 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 2 Nov 2023 19:37:02 -0300 Subject: [PATCH 116/144] Refactor unnecessary changes and modify TokenRequest naming --- .../rest/wpcom/auth/Authenticator.java | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index eb785e3528..fd01ba200e 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -95,24 +95,19 @@ public AuthEmailResponsePayload(boolean isSignup) { mAppSecrets = secrets; } - public void authenticate(String username, - String password, - String twoStepCode, - boolean shouldSendTwoStepSMS, - Listener listener, - ErrorListener errorListener) { - TokenRequest tokenRequest = makeRequest(username, password, twoStepCode, shouldSendTwoStepSMS, listener, + public void authenticate(String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, + Listener listener, ErrorListener errorListener) { + OauthRequest request = makeRequest(username, password, twoStepCode, shouldSendTwoStepSMS, listener, errorListener); - mRequestQueue.add(tokenRequest); + mRequestQueue.add(request); } public String getAuthorizationURL() { return String.format(AUTHORIZE_ENDPOINT_FORMAT, AUTHORIZE_ENDPOINT, mAppSecrets.getAppId()); } - public TokenRequest makeRequest(String username, String password, String twoStepCode, - boolean shouldSendTwoStepSMS, Listener listener, - ErrorListener errorListener) { + public OauthRequest makeRequest(String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, + Listener listener, ErrorListener errorListener) { return new PasswordRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), username, password, twoStepCode, shouldSendTwoStepSMS, listener, errorListener); } @@ -146,12 +141,12 @@ public void makeRequest(String userId, String twoStepNonce, mRequestQueue.add(request); } - private static class TokenRequest extends Request { + private static class OauthRequest extends Request { private static final String DATA = "data"; private final Listener mListener; protected Map mParams = new HashMap<>(); - TokenRequest(String appId, String appSecret, Listener listener, ErrorListener errorListener) { + OauthRequest(String appId, String appSecret, Listener listener, ErrorListener errorListener) { super(Method.POST, TOKEN_ENDPOINT, errorListener); mListener = listener; mParams.put(CLIENT_ID_PARAM_NAME, appId); @@ -187,7 +182,7 @@ protected Response parseNetworkResponse(NetworkResponse response) } } - public static class PasswordRequest extends TokenRequest { + public static class PasswordRequest extends OauthRequest { public PasswordRequest(String appId, String appSecret, String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, Listener listener, ErrorListener errorListener) { super(appId, appSecret, listener, errorListener); @@ -207,7 +202,7 @@ public PasswordRequest(String appId, String appSecret, String username, String p } } - public static class BearerRequest extends TokenRequest { + public static class BearerRequest extends OauthRequest { public BearerRequest(String appId, String appSecret, String code, Listener listener, ErrorListener errorListener) { super(appId, appSecret, listener, errorListener); From c1ff93045217310cb45b8ea6ebda105a1492f134 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 17:22:36 -0300 Subject: [PATCH 117/144] Update Authenticator endpoints declarations --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index fd01ba200e..83078ea244 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -44,10 +44,11 @@ public class Authenticator { private static final String WPCOM_OAUTH_PREFIX = "https://public-api.wordpress.com/oauth2"; + private static final String WPCOM_PREFIX = "https://wordpress.com"; private static final String AUTHORIZE_ENDPOINT = WPCOM_OAUTH_PREFIX + "/authorize"; private static final String TOKEN_ENDPOINT = WPCOM_OAUTH_PREFIX + "/token"; private static final String AUTHORIZE_ENDPOINT_FORMAT = "%s?client_id=%s&response_type=code"; - + private static final String LOGIN_BASE_ENDPOINT = WPCOM_PREFIX + "wp-login.php?action=login-endpoint"; public static final String CLIENT_ID_PARAM_NAME = "client_id"; public static final String CLIENT_SECRET_PARAM_NAME = "client_secret"; public static final String CODE_PARAM_NAME = "code"; From bae555f61546b2a346148be5685a7a1b30041d0c Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 17:40:51 -0300 Subject: [PATCH 118/144] Update Oauth URL --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 83078ea244..a6d918a67d 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -56,6 +56,7 @@ public class Authenticator { public static final String USERNAME_PARAM_NAME = "username"; public static final String PASSWORD_PARAM_NAME = "password"; public static final String WITH_AUTH_TYPES = "with_auth_types"; + public static final String GET_BEARER_TOKEN = "get_bearer_token"; public static final String PASSWORD_GRANT_TYPE = "password"; public static final String BEARER_GRANT_TYPE = "bearer"; @@ -148,7 +149,7 @@ private static class OauthRequest extends Request { protected Map mParams = new HashMap<>(); OauthRequest(String appId, String appSecret, Listener listener, ErrorListener errorListener) { - super(Method.POST, TOKEN_ENDPOINT, errorListener); + super(Method.POST, LOGIN_BASE_ENDPOINT, errorListener); mListener = listener; mParams.put(CLIENT_ID_PARAM_NAME, appId); mParams.put(CLIENT_SECRET_PARAM_NAME, appSecret); @@ -190,7 +191,7 @@ public PasswordRequest(String appId, String appSecret, String username, String p mParams.put(USERNAME_PARAM_NAME, username); mParams.put(PASSWORD_PARAM_NAME, password); mParams.put(GRANT_TYPE_PARAM_NAME, PASSWORD_GRANT_TYPE); - mParams.put(WITH_AUTH_TYPES, "true"); + mParams.put(GET_BEARER_TOKEN, "true"); if (!TextUtils.isEmpty(twoStepCode)) { mParams.put("wpcom_otp", twoStepCode); From 8995eb8032e76a5d36fecf7d7dd245e534d114a5 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 17:57:30 -0300 Subject: [PATCH 119/144] Adjust WebauthnResponse to support additional nonce parameters --- .../rest/wpcom/auth/Authenticator.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index a6d918a67d..0ec11777db 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -254,20 +254,23 @@ public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { public static class WebauthnResponse implements OauthResponse { private static final String USER_ID = "user_id"; private static final String TWO_STEP_WEBAUTHN_NONCE = "two_step_nonce_webauthn"; - private String mUserId; - private String mTwoStepWebauthnNonce; + private static final String TWO_STEP_BACKUP_NONCE = "two_step_nonce_backup"; + private static final String TWO_STEP_AUTHENTICATOR_NONCE = "two_step_nonce_authenticator"; + private static final String TWO_STEP_PUSH_NONCE = "two_step_nonce_push"; + public final String mUserId; + public final String mWebauthnNonce; + public final String mBackupNonce; + public final String mAuthenticatorNonce; + public final String mPushNonce; + public final String mTwoStepWebauthnNonce; public WebauthnResponse(JSONObject data) throws JSONException { mUserId = data.getString(USER_ID); mTwoStepWebauthnNonce = data.getString(TWO_STEP_WEBAUTHN_NONCE); - } - - public String getUserId() { - return mUserId; - } - - public String getWebauthnNonce() { - return mTwoStepWebauthnNonce; + mWebauthnNonce = data.getString(TWO_STEP_WEBAUTHN_NONCE); + mBackupNonce = data.getString(TWO_STEP_BACKUP_NONCE); + mAuthenticatorNonce = data.getString(TWO_STEP_AUTHENTICATOR_NONCE); + mPushNonce = data.getString(TWO_STEP_PUSH_NONCE); } } From 4175ede0a7c3b60d84c2a704f4723ee45dc1d3b1 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 17:58:34 -0300 Subject: [PATCH 120/144] Remove duplicate parameter --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 0ec11777db..78fc97d223 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -262,11 +262,9 @@ public static class WebauthnResponse implements OauthResponse { public final String mBackupNonce; public final String mAuthenticatorNonce; public final String mPushNonce; - public final String mTwoStepWebauthnNonce; public WebauthnResponse(JSONObject data) throws JSONException { mUserId = data.getString(USER_ID); - mTwoStepWebauthnNonce = data.getString(TWO_STEP_WEBAUTHN_NONCE); mWebauthnNonce = data.getString(TWO_STEP_WEBAUTHN_NONCE); mBackupNonce = data.getString(TWO_STEP_BACKUP_NONCE); mAuthenticatorNonce = data.getString(TWO_STEP_AUTHENTICATOR_NONCE); From 3bf138eb1d800539cb3203a7a72560f926f1320b Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 17:59:52 -0300 Subject: [PATCH 121/144] Relay nonce parameters inside SecurityKey authentication response --- .../android/fluxc/store/AccountStore.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 66c6173d6e..855606817a 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -454,12 +454,18 @@ public static class OnUsernameChanged extends OnChanged { } public static class OnSecurityKeyAuthStarted extends OnChanged { - public String userId; - public String webauthnNonce; + public final String userId; + public final String webauthnNonce; + public final String mBackupNonce; + public final String authenticatorNonce; + public final String pushNonce; - public OnSecurityKeyAuthStarted(String userId, String webauthnNonce) { - this.userId = userId; - this.webauthnNonce = webauthnNonce; + public OnSecurityKeyAuthStarted(WebauthnResponse response) { + userId = response.mUserId; + webauthnNonce = response.mWebauthnNonce; + mBackupNonce = response.mBackupNonce; + authenticatorNonce = response.mAuthenticatorNonce; + pushNonce = response.mPushNonce; } } @@ -1352,8 +1358,7 @@ private void handleAuthResponse(OauthResponse response, AuthenticatePayload payl emitChange(new OnAuthenticationChanged()); } else if (response instanceof WebauthnResponse) { WebauthnResponse webauthnResponse = (WebauthnResponse) response; - OnSecurityKeyAuthStarted event = new OnSecurityKeyAuthStarted(webauthnResponse.getUserId(), - webauthnResponse.getWebauthnNonce()); + OnSecurityKeyAuthStarted event = new OnSecurityKeyAuthStarted(webauthnResponse); if (payload.nextAction != null) { mDispatcher.dispatch(payload.nextAction); } From 3da6bc306cf22fd0320a54343ebd11a648baf66c Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 18:00:56 -0300 Subject: [PATCH 122/144] Rename WebauthnResponse to TwoFactorResponse --- .../fluxc/network/rest/wpcom/auth/Authenticator.java | 6 +++--- .../wordpress/android/fluxc/store/AccountStore.java | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 78fc97d223..ef33e4b997 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -172,7 +172,7 @@ protected Response parseNetworkResponse(NetworkResponse response) JSONObject responseData = new JSONObject(jsonString); JSONObject successData = responseData.optJSONObject(DATA); if (successData != null) { - return Response.success(new WebauthnResponse(successData), + return Response.success(new TwoFactorResponse(successData), HttpHeaderParser.parseCacheHeaders(response)); } @@ -251,7 +251,7 @@ public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { } } - public static class WebauthnResponse implements OauthResponse { + public static class TwoFactorResponse implements OauthResponse { private static final String USER_ID = "user_id"; private static final String TWO_STEP_WEBAUTHN_NONCE = "two_step_nonce_webauthn"; private static final String TWO_STEP_BACKUP_NONCE = "two_step_nonce_backup"; @@ -263,7 +263,7 @@ public static class WebauthnResponse implements OauthResponse { public final String mAuthenticatorNonce; public final String mPushNonce; - public WebauthnResponse(JSONObject data) throws JSONException { + public TwoFactorResponse(JSONObject data) throws JSONException { mUserId = data.getString(USER_ID); mWebauthnNonce = data.getString(TWO_STEP_WEBAUTHN_NONCE); mBackupNonce = data.getString(TWO_STEP_BACKUP_NONCE); diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 855606817a..4a9960c3ee 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -40,7 +40,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.OauthResponse; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.WebauthnResponse; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.TwoFactorResponse; import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnChallengeInfo; import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnToken; import org.wordpress.android.fluxc.network.xmlrpc.XMLRPCRequest.XmlRpcErrorType; @@ -460,7 +460,7 @@ public static class OnSecurityKeyAuthStarted extends OnChanged Date: Thu, 9 Nov 2023 18:01:26 -0300 Subject: [PATCH 123/144] Rename event to reflect proper Two factor detection --- .../org/wordpress/android/fluxc/store/AccountStore.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 4a9960c3ee..a171fde025 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -453,14 +453,14 @@ public static class OnUsernameChanged extends OnChanged { public String username; } - public static class OnSecurityKeyAuthStarted extends OnChanged { + public static class OnTwoFactorAuthStarted extends OnChanged { public final String userId; public final String webauthnNonce; public final String mBackupNonce; public final String authenticatorNonce; public final String pushNonce; - public OnSecurityKeyAuthStarted(TwoFactorResponse response) { + public OnTwoFactorAuthStarted(TwoFactorResponse response) { userId = response.mUserId; webauthnNonce = response.mWebauthnNonce; mBackupNonce = response.mBackupNonce; @@ -1358,7 +1358,7 @@ private void handleAuthResponse(OauthResponse response, AuthenticatePayload payl emitChange(new OnAuthenticationChanged()); } else if (response instanceof TwoFactorResponse) { TwoFactorResponse twoFactorResponse = (TwoFactorResponse) response; - OnSecurityKeyAuthStarted event = new OnSecurityKeyAuthStarted(twoFactorResponse); + OnTwoFactorAuthStarted event = new OnTwoFactorAuthStarted(twoFactorResponse); if (payload.nextAction != null) { mDispatcher.dispatch(payload.nextAction); } From 59cc81e479f3e129fad5d2d3484afdfa40a8c798 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 18:17:31 -0300 Subject: [PATCH 124/144] Fix URL mapping --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index ef33e4b997..b927cfe166 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -48,7 +48,7 @@ public class Authenticator { private static final String AUTHORIZE_ENDPOINT = WPCOM_OAUTH_PREFIX + "/authorize"; private static final String TOKEN_ENDPOINT = WPCOM_OAUTH_PREFIX + "/token"; private static final String AUTHORIZE_ENDPOINT_FORMAT = "%s?client_id=%s&response_type=code"; - private static final String LOGIN_BASE_ENDPOINT = WPCOM_PREFIX + "wp-login.php?action=login-endpoint"; + private static final String LOGIN_BASE_ENDPOINT = WPCOM_PREFIX + "/wp-login.php?action=login-endpoint"; public static final String CLIENT_ID_PARAM_NAME = "client_id"; public static final String CLIENT_SECRET_PARAM_NAME = "client_secret"; public static final String CODE_PARAM_NAME = "code"; From 86a533f01f4bb37c00027e128315031c2fb9e1d2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 19:16:47 -0300 Subject: [PATCH 125/144] Adjust TwoFactorResponse parameters parsing to become optionals --- .../fluxc/network/rest/wpcom/auth/Authenticator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index b927cfe166..44dca5669d 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -265,10 +265,10 @@ public static class TwoFactorResponse implements OauthResponse { public TwoFactorResponse(JSONObject data) throws JSONException { mUserId = data.getString(USER_ID); - mWebauthnNonce = data.getString(TWO_STEP_WEBAUTHN_NONCE); - mBackupNonce = data.getString(TWO_STEP_BACKUP_NONCE); - mAuthenticatorNonce = data.getString(TWO_STEP_AUTHENTICATOR_NONCE); - mPushNonce = data.getString(TWO_STEP_PUSH_NONCE); + mWebauthnNonce = data.optString(TWO_STEP_WEBAUTHN_NONCE); + mBackupNonce = data.optString(TWO_STEP_BACKUP_NONCE); + mAuthenticatorNonce = data.optString(TWO_STEP_AUTHENTICATOR_NONCE); + mPushNonce = data.optString(TWO_STEP_PUSH_NONCE); } } From 8d33bf03d7d8608d32000bfb7f1ddc1ed8e8b65c Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 19:22:53 -0300 Subject: [PATCH 126/144] Add supported types handling to TwoFactorResponse --- .../network/rest/wpcom/auth/Authenticator.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 44dca5669d..62de1fe3d7 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -13,6 +13,7 @@ import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.wordpress.android.fluxc.Dispatcher; @@ -36,7 +37,9 @@ import org.wordpress.android.util.LanguageUtils; import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.inject.Inject; @@ -257,11 +260,13 @@ public static class TwoFactorResponse implements OauthResponse { private static final String TWO_STEP_BACKUP_NONCE = "two_step_nonce_backup"; private static final String TWO_STEP_AUTHENTICATOR_NONCE = "two_step_nonce_authenticator"; private static final String TWO_STEP_PUSH_NONCE = "two_step_nonce_push"; + private static final String TWO_STEP_SUPPORTED_AUTH_TYPES = "two_step_supported_auth_types"; public final String mUserId; public final String mWebauthnNonce; public final String mBackupNonce; public final String mAuthenticatorNonce; public final String mPushNonce; + public final List mSupportedAuthTypes; public TwoFactorResponse(JSONObject data) throws JSONException { mUserId = data.getString(USER_ID); @@ -269,6 +274,16 @@ public TwoFactorResponse(JSONObject data) throws JSONException { mBackupNonce = data.optString(TWO_STEP_BACKUP_NONCE); mAuthenticatorNonce = data.optString(TWO_STEP_AUTHENTICATOR_NONCE); mPushNonce = data.optString(TWO_STEP_PUSH_NONCE); + JSONArray supportedTypes = data.getJSONArray(TWO_STEP_SUPPORTED_AUTH_TYPES); + if (supportedTypes.length() == 0) { + throw new JSONException("No supported auth types found"); + } + + ArrayList supportedAuthTypes = new ArrayList<>(); + for(int i = 0; i < supportedTypes.length(); i++) { + supportedAuthTypes.add(supportedTypes.getString(i)); + } + mSupportedAuthTypes = supportedAuthTypes; } } From 90d91377c367ce08d2ac312876fde9b9a495e55d Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 19:59:12 -0300 Subject: [PATCH 127/144] Refactor Authenticator to differentiate standard auth from two factor auth --- .../rest/wpcom/auth/Authenticator.java | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 62de1fe3d7..364539c0e8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -100,6 +100,10 @@ public AuthEmailResponsePayload(boolean isSignup) { mAppSecrets = secrets; } + public void authenticate(String username, String password, Listener listener, ErrorListener errorListener) { + + } + public void authenticate(String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, Listener listener, ErrorListener errorListener) { OauthRequest request = makeRequest(username, password, twoStepCode, shouldSendTwoStepSMS, listener, @@ -111,10 +115,15 @@ public String getAuthorizationURL() { return String.format(AUTHORIZE_ENDPOINT_FORMAT, AUTHORIZE_ENDPOINT, mAppSecrets.getAppId()); } + public OauthRequest makeRequest(String username, String password, Listener listener, ErrorListener errorListener) { + return new PasswordRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), + username, password, listener, errorListener); + } + public OauthRequest makeRequest(String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, Listener listener, ErrorListener errorListener) { - return new PasswordRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), username, password, twoStepCode, - shouldSendTwoStepSMS, listener, errorListener); + return new TwoFactorRequest(mAppSecrets.getAppId(), mAppSecrets.getAppSecret(), + username, password, twoStepCode, shouldSendTwoStepSMS, listener, errorListener); } public void makeRequest(String userId, String webauthnNonce, @@ -151,8 +160,8 @@ private static class OauthRequest extends Request { private final Listener mListener; protected Map mParams = new HashMap<>(); - OauthRequest(String appId, String appSecret, Listener listener, ErrorListener errorListener) { - super(Method.POST, LOGIN_BASE_ENDPOINT, errorListener); + OauthRequest(String url, String appId, String appSecret, Listener listener, ErrorListener errorListener) { + super(Method.POST, url, errorListener); mListener = listener; mParams.put(CLIENT_ID_PARAM_NAME, appId); mParams.put(CLIENT_SECRET_PARAM_NAME, appSecret); @@ -188,21 +197,27 @@ protected Response parseNetworkResponse(NetworkResponse response) } public static class PasswordRequest extends OauthRequest { - public PasswordRequest(String appId, String appSecret, String username, String password, String twoStepCode, - boolean shouldSendTwoStepSMS, Listener listener, ErrorListener errorListener) { - super(appId, appSecret, listener, errorListener); + public PasswordRequest(String appId, String appSecret, String username, String password, + Listener listener, ErrorListener errorListener) { + super(LOGIN_BASE_ENDPOINT, appId, appSecret, listener, errorListener); mParams.put(USERNAME_PARAM_NAME, username); mParams.put(PASSWORD_PARAM_NAME, password); mParams.put(GRANT_TYPE_PARAM_NAME, PASSWORD_GRANT_TYPE); - mParams.put(GET_BEARER_TOKEN, "true"); + mParams.put("wpcom_supports_2fa", "true"); + } + } - if (!TextUtils.isEmpty(twoStepCode)) { - mParams.put("wpcom_otp", twoStepCode); - } else { - mParams.put("wpcom_supports_2fa", "true"); - if (shouldSendTwoStepSMS) { - mParams.put("wpcom_resend_otp", "true"); - } + public static class TwoFactorRequest extends OauthRequest { + public TwoFactorRequest(String appId, String appSecret, String username, String password, String twoStepCode, + boolean shouldSendTwoStepSMS, Listener listener, ErrorListener errorListener) { + super(TOKEN_ENDPOINT, appId, appSecret, listener, errorListener); + mParams.put(USERNAME_PARAM_NAME, username); + mParams.put(PASSWORD_PARAM_NAME, password); + mParams.put(GRANT_TYPE_PARAM_NAME, PASSWORD_GRANT_TYPE); + mParams.put(GET_BEARER_TOKEN, "true"); + mParams.put("wpcom_otp", twoStepCode); + if (shouldSendTwoStepSMS && TextUtils.isEmpty(twoStepCode)) { + mParams.put("wpcom_resend_otp", "true"); } } } @@ -210,7 +225,7 @@ public PasswordRequest(String appId, String appSecret, String username, String p public static class BearerRequest extends OauthRequest { public BearerRequest(String appId, String appSecret, String code, Listener listener, ErrorListener errorListener) { - super(appId, appSecret, listener, errorListener); + super(TOKEN_ENDPOINT, appId, appSecret, listener, errorListener); mParams.put(CODE_PARAM_NAME, code); mParams.put(GRANT_TYPE_PARAM_NAME, BEARER_GRANT_TYPE); } From 426c571f6533dfa09d5d13bb278ad7f562767647 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 19:59:23 -0300 Subject: [PATCH 128/144] Create new AuthenticationAction --- .../wordpress/android/fluxc/action/AuthenticationAction.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java index e2929ddd65..ffdc24d134 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/action/AuthenticationAction.java @@ -6,6 +6,7 @@ import org.wordpress.android.fluxc.network.discovery.SelfHostedEndpointFinder.DiscoveryResultPayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.store.AccountStore.AuthEmailPayload; +import org.wordpress.android.fluxc.store.AccountStore.AuthenticateTwoFactorPayload; import org.wordpress.android.fluxc.store.AccountStore.StartWebauthnChallengePayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticateErrorPayload; import org.wordpress.android.fluxc.store.AccountStore.AuthenticatePayload; @@ -16,6 +17,8 @@ public enum AuthenticationAction implements IAction { // Remote actions @Action(payloadType = AuthenticatePayload.class) AUTHENTICATE, + @Action(payloadType = AuthenticateTwoFactorPayload.class) + AUTHENTICATE_TWO_FACTOR, @Action(payloadType = String.class) DISCOVER_ENDPOINT, @Action(payloadType = AuthEmailPayload.class) From 412523ccd99966cc6ae18d12448ce495b3234171 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 20:03:08 -0300 Subject: [PATCH 129/144] Adjust AccountStore to support separate Two factor auth request --- .../android/fluxc/store/AccountStore.java | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index a171fde025..d07cdded35 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -5,6 +5,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.volley.Response; import com.android.volley.VolleyError; import com.yarolegovich.wellsql.WellSql; @@ -62,15 +63,30 @@ @Singleton public class AccountStore extends Store { // Payloads - public static class AuthenticatePayload extends Payload { + public static class AuthenticationRequestPayload extends Payload { + public Action nextAction; + } + + public static class AuthenticatePayload extends AuthenticationRequestPayload { + public String username; + public String password; + public AuthenticatePayload(@NonNull String username, @NonNull String password) { + this.username = username; + this.password = password; + } + } + + public static class AuthenticateTwoFactorPayload extends AuthenticationRequestPayload { public String username; public String password; public String twoStepCode; public boolean shouldSendTwoStepSms; - public Action nextAction; - public AuthenticatePayload(@NonNull String username, @NonNull String password) { + public AuthenticateTwoFactorPayload(@NonNull String username, @NonNull String password, + @NonNull String twoStepCode, boolean shouldSendTwoStepSms) { this.username = username; this.password = password; + this.twoStepCode = twoStepCode; + this.shouldSendTwoStepSms = shouldSendTwoStepSms; } } @@ -1031,6 +1047,9 @@ private void onAuthenticationAction(AuthenticationAction actionType, Object payl case AUTHENTICATE: authenticate((AuthenticatePayload) payload); break; + case AUTHENTICATE_TWO_FACTOR: + authenticateTwoFactor((AuthenticateTwoFactorPayload) payload); + break; case AUTHENTICATE_ERROR: handleAuthenticateError((AuthenticateErrorPayload) payload); break; @@ -1332,6 +1351,12 @@ private AccountModel loadAccount() { } private void authenticate(final AuthenticatePayload payload) { + mAuthenticator.authenticate(payload.username, payload.password, + response -> handleAuthResponse(response, payload), + this::handleAuthError); + } + + private void authenticateTwoFactor(final AuthenticateTwoFactorPayload payload) { mAuthenticator.authenticate(payload.username, payload.password, payload.twoStepCode, payload.shouldSendTwoStepSms, response -> handleAuthResponse(response, payload), @@ -1347,7 +1372,7 @@ private void handleAuthError(VolleyError volleyError) { emitChange(event); } - private void handleAuthResponse(OauthResponse response, AuthenticatePayload payload) { + private void handleAuthResponse(OauthResponse response, AuthenticationRequestPayload payload) { // Oauth endpoint can return a Token or a WebauthnResponse if (response instanceof Token) { Token token = (Token) response; @@ -1383,7 +1408,7 @@ private void handleSentAuthEmail(final AuthEmailResponsePayload payload) { private void requestWebauthnChallenge(final StartWebauthnChallengePayload payload) { mAuthenticator.makeRequest(payload.mUserId, payload.mWebauthnNonce, - info -> { + (Response.Listener) info -> { WebauthnChallengeReceived event = new WebauthnChallengeReceived(); event.mChallengeInfo = info; event.mUserId = payload.mUserId; From fb22951d0271000b44165178b8848770b2e4a68c Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 20:07:04 -0300 Subject: [PATCH 130/144] Update MainFragment --- .../wordpress/android/fluxc/example/MainFragment.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/example/src/main/java/org/wordpress/android/fluxc/example/MainFragment.kt b/example/src/main/java/org/wordpress/android/fluxc/example/MainFragment.kt index 43ab749e88..488461d54d 100644 --- a/example/src/main/java/org/wordpress/android/fluxc/example/MainFragment.kt +++ b/example/src/main/java/org/wordpress/android/fluxc/example/MainFragment.kt @@ -30,6 +30,7 @@ import org.wordpress.android.fluxc.network.rest.wpapi.CookieNonceAuthenticator.C import org.wordpress.android.fluxc.network.rest.wpapi.CookieNonceAuthenticator.CookieNonceAuthenticationResult.Success import org.wordpress.android.fluxc.store.AccountStore import org.wordpress.android.fluxc.store.AccountStore.AuthenticatePayload +import org.wordpress.android.fluxc.store.AccountStore.AuthenticateTwoFactorPayload import org.wordpress.android.fluxc.store.AccountStore.AuthenticationErrorType import org.wordpress.android.fluxc.store.AccountStore.OnAccountChanged import org.wordpress.android.fluxc.store.AccountStore.OnAuthenticationChanged @@ -55,9 +56,11 @@ class MainFragment : Fragment() { // Would be great to not have to keep this state, but it makes HTTPAuth and self signed SSL management easier private var selfHostedPayload: RefreshSitesXMLRPCPayload? = null - // Used for 2fa private var authenticatePayload: AuthenticatePayload? = null + // Used for 2fa + private var authenticateTwoFactorPayload: AuthenticateTwoFactorPayload? = null + override fun onAttach(context: Context) { AndroidSupportInjection.inject(this) super.onAttach(context) @@ -174,8 +177,9 @@ class MainFragment : Fragment() { } private fun signIn2fa(twoStepCode: String) { - authenticatePayload?.twoStepCode = twoStepCode - dispatcher.dispatch(AuthenticationActionBuilder.newAuthenticateAction(authenticatePayload)) + authenticateTwoFactorPayload?.twoStepCode = twoStepCode + dispatcher.dispatch(AuthenticationActionBuilder + .newAuthenticateTwoFactorAction(authenticateTwoFactorPayload)) } private fun showHTTPAuthDialog(url: String) { From 24965e873a5c5b4b23a29fe7947554285a0e1e48 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 20:14:18 -0300 Subject: [PATCH 131/144] Fix missing calls --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 364539c0e8..fc07a347a1 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -101,7 +101,8 @@ public AuthEmailResponsePayload(boolean isSignup) { } public void authenticate(String username, String password, Listener listener, ErrorListener errorListener) { - + OauthRequest request = makeRequest(username, password, listener, errorListener); + mRequestQueue.add(request); } public void authenticate(String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, From 9f0f437a16f333100c377871986c905badd95ddb Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 20:14:34 -0300 Subject: [PATCH 132/144] Fix checkstyle issues --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index fc07a347a1..965b3ac75f 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -296,7 +296,7 @@ public TwoFactorResponse(JSONObject data) throws JSONException { } ArrayList supportedAuthTypes = new ArrayList<>(); - for(int i = 0; i < supportedTypes.length(); i++) { + for (int i = 0; i < supportedTypes.length(); i++) { supportedAuthTypes.add(supportedTypes.getString(i)); } mSupportedAuthTypes = supportedAuthTypes; From 61f29d213bc79f10cb9e765ef7e6f727e8a174e2 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 21:46:51 -0300 Subject: [PATCH 133/144] Introduce SupportedAuthTypes to Authenticator --- .../rest/wpcom/auth/Authenticator.java | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 965b3ac75f..a1a1f15ec6 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -282,7 +282,7 @@ public static class TwoFactorResponse implements OauthResponse { public final String mBackupNonce; public final String mAuthenticatorNonce; public final String mPushNonce; - public final List mSupportedAuthTypes; + public final List mSupportedAuthTypes; public TwoFactorResponse(JSONObject data) throws JSONException { mUserId = data.getString(USER_ID); @@ -295,14 +295,40 @@ public TwoFactorResponse(JSONObject data) throws JSONException { throw new JSONException("No supported auth types found"); } - ArrayList supportedAuthTypes = new ArrayList<>(); + ArrayList supportedAuthTypes = new ArrayList<>(); for (int i = 0; i < supportedTypes.length(); i++) { - supportedAuthTypes.add(supportedTypes.getString(i)); + SupportedAuthTypes type = SupportedAuthTypes.fromString(supportedTypes.getString(i)); + if (type != SupportedAuthTypes.UNKNOWN) { + supportedAuthTypes.add(type); + } } mSupportedAuthTypes = supportedAuthTypes; } } + public enum SupportedAuthTypes { + WEBAUTHN, + BACKUP, + AUTHENTICATOR, + PUSH, + UNKNOWN; + + static SupportedAuthTypes fromString(String value) { + switch (value) { + case "webauthn": + return WEBAUTHN; + case "backup": + return BACKUP; + case "authenticator": + return AUTHENTICATOR; + case "push": + return PUSH; + default: + return UNKNOWN; + } + } + } + public void sendAuthEmail(final AuthEmailPayload payload) { String url = payload.isSignup ? WPCOMREST.auth.send_signup_email.getUrlV1_1() : WPCOMREST.auth.send_login_email.getUrlV1_3(); From 21c82fef9756abc94826f2458b56b493fa7fb490 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 21:47:59 -0300 Subject: [PATCH 134/144] Update OnTwoFactorAuthStarted with supported types field --- .../java/org/wordpress/android/fluxc/store/AccountStore.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index d07cdded35..07e9ac1c4c 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -40,6 +40,7 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.OauthResponse; +import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.SupportedAuthTypes; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.TwoFactorResponse; import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnChallengeInfo; @@ -475,6 +476,7 @@ public static class OnTwoFactorAuthStarted extends OnChanged mSupportedAuthTypes; public OnTwoFactorAuthStarted(TwoFactorResponse response) { userId = response.mUserId; @@ -482,6 +484,7 @@ public OnTwoFactorAuthStarted(TwoFactorResponse response) { mBackupNonce = response.mBackupNonce; authenticatorNonce = response.mAuthenticatorNonce; pushNonce = response.mPushNonce; + mSupportedAuthTypes = response.mSupportedAuthTypes; } } From 52fc9b903d69281c8e3bbbede2b028700c10d509 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 22:16:09 -0300 Subject: [PATCH 135/144] Adjust supported auth types parameter to use Strings --- .../rest/wpcom/auth/Authenticator.java | 32 ++----------------- .../android/fluxc/store/AccountStore.java | 3 +- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index a1a1f15ec6..965b3ac75f 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -282,7 +282,7 @@ public static class TwoFactorResponse implements OauthResponse { public final String mBackupNonce; public final String mAuthenticatorNonce; public final String mPushNonce; - public final List mSupportedAuthTypes; + public final List mSupportedAuthTypes; public TwoFactorResponse(JSONObject data) throws JSONException { mUserId = data.getString(USER_ID); @@ -295,40 +295,14 @@ public TwoFactorResponse(JSONObject data) throws JSONException { throw new JSONException("No supported auth types found"); } - ArrayList supportedAuthTypes = new ArrayList<>(); + ArrayList supportedAuthTypes = new ArrayList<>(); for (int i = 0; i < supportedTypes.length(); i++) { - SupportedAuthTypes type = SupportedAuthTypes.fromString(supportedTypes.getString(i)); - if (type != SupportedAuthTypes.UNKNOWN) { - supportedAuthTypes.add(type); - } + supportedAuthTypes.add(supportedTypes.getString(i)); } mSupportedAuthTypes = supportedAuthTypes; } } - public enum SupportedAuthTypes { - WEBAUTHN, - BACKUP, - AUTHENTICATOR, - PUSH, - UNKNOWN; - - static SupportedAuthTypes fromString(String value) { - switch (value) { - case "webauthn": - return WEBAUTHN; - case "backup": - return BACKUP; - case "authenticator": - return AUTHENTICATOR; - case "push": - return PUSH; - default: - return UNKNOWN; - } - } - } - public void sendAuthEmail(final AuthEmailPayload payload) { String url = payload.isSignup ? WPCOMREST.auth.send_signup_email.getUrlV1_1() : WPCOMREST.auth.send_login_email.getUrlV1_3(); diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java index 07e9ac1c4c..fb9c099fe7 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/store/AccountStore.java @@ -40,7 +40,6 @@ import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.AuthEmailResponsePayload; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.OauthResponse; -import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.SupportedAuthTypes; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.Token; import org.wordpress.android.fluxc.network.rest.wpcom.auth.Authenticator.TwoFactorResponse; import org.wordpress.android.fluxc.network.rest.wpcom.auth.webauthn.WebauthnChallengeInfo; @@ -476,7 +475,7 @@ public static class OnTwoFactorAuthStarted extends OnChanged mSupportedAuthTypes; + public final List mSupportedAuthTypes; public OnTwoFactorAuthStarted(TwoFactorResponse response) { userId = response.mUserId; From c9128874e38128c59e8f154c45f968f048d9ca97 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Thu, 9 Nov 2023 23:21:25 -0300 Subject: [PATCH 136/144] Add bearer token parameter to PasswordRequest --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 965b3ac75f..6993f89156 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -204,6 +204,7 @@ public PasswordRequest(String appId, String appSecret, String username, String p mParams.put(USERNAME_PARAM_NAME, username); mParams.put(PASSWORD_PARAM_NAME, password); mParams.put(GRANT_TYPE_PARAM_NAME, PASSWORD_GRANT_TYPE); + mParams.put(GET_BEARER_TOKEN, "true"); mParams.put("wpcom_supports_2fa", "true"); } } From 7ba06021b2b448d0761bde84a4f277bed2536405 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 10 Nov 2023 00:03:12 -0300 Subject: [PATCH 137/144] Correctly handle a bearer token response --- .../fluxc/network/rest/wpcom/auth/Authenticator.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 6993f89156..201a7aa60d 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -158,6 +158,7 @@ public void makeRequest(String userId, String twoStepNonce, private static class OauthRequest extends Request { private static final String DATA = "data"; + private static final String BEARER_TOKEN = "bearer_token"; private final Listener mListener; protected Map mParams = new HashMap<>(); @@ -182,10 +183,10 @@ public void deliverResponse(OauthResponse response) { protected Response parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); - JSONObject responseData = new JSONObject(jsonString); - JSONObject successData = responseData.optJSONObject(DATA); - if (successData != null) { - return Response.success(new TwoFactorResponse(successData), + JSONObject responseData = new JSONObject(jsonString).getJSONObject(DATA); + JSONObject bearerToken = responseData.optJSONObject(BEARER_TOKEN); + if (bearerToken == null) { + return Response.success(new TwoFactorResponse(responseData), HttpHeaderParser.parseCacheHeaders(response)); } From b803f3f8b58aa99937e6ab9b621a7ff2226155a5 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 10 Nov 2023 00:33:46 -0300 Subject: [PATCH 138/144] Correctly handle Token response --- .../rest/wpcom/auth/Authenticator.java | 28 +++---------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 201a7aa60d..87a8d12ba8 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -184,13 +184,13 @@ protected Response parseNetworkResponse(NetworkResponse response) try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); JSONObject responseData = new JSONObject(jsonString).getJSONObject(DATA); - JSONObject bearerToken = responseData.optJSONObject(BEARER_TOKEN); - if (bearerToken == null) { + String bearerToken = responseData.optString(BEARER_TOKEN); + if (bearerToken.isEmpty()) { return Response.success(new TwoFactorResponse(responseData), HttpHeaderParser.parseCacheHeaders(response)); } - return Response.success(Token.fromJSONObject(responseData), + return Response.success(new Token(bearerToken), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException | JSONException e) { return Response.error(new ParseError(e)); @@ -237,24 +237,10 @@ public BearerRequest(String appId, String appSecret, String code, Listener liste public interface OauthResponse {} public static class Token implements OauthResponse { - private static final String TOKEN_TYPE_FIELD_NAME = "token_type"; - private static final String ACCESS_TOKEN_FIELD_NAME = "access_token"; - private static final String SITE_URL_FIELD_NAME = "blog_url"; - private static final String SCOPE_FIELD_NAME = "scope"; - private static final String SITE_ID_FIELD_NAME = "blog_id"; - - private String mTokenType; - private String mScope; private String mAccessToken; - private String mSiteUrl; - private String mSiteId; - public Token(String accessToken, String siteUrl, String siteId, String scope, String tokenType) { + public Token(String accessToken) { mAccessToken = accessToken; - mSiteUrl = siteUrl; - mSiteId = siteId; - mScope = scope; - mTokenType = tokenType; } public String getAccessToken() { @@ -264,12 +250,6 @@ public String getAccessToken() { public String toString() { return getAccessToken(); } - - public static Token fromJSONObject(JSONObject tokenJSON) throws JSONException { - return new Token(tokenJSON.getString(ACCESS_TOKEN_FIELD_NAME), tokenJSON.getString(SITE_URL_FIELD_NAME), - tokenJSON.getString(SITE_ID_FIELD_NAME), tokenJSON.getString(SCOPE_FIELD_NAME), - tokenJSON.getString(TOKEN_TYPE_FIELD_NAME)); - } } public static class TwoFactorResponse implements OauthResponse { From c79a311c295ba41d89320da2b181c3f7aa69e7f0 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 10 Nov 2023 11:10:10 +0100 Subject: [PATCH 139/144] Added weeklyAnchor and monthlyAnchor --- .../30.json | 18 +++++++++++++++--- .../woo/WooPaymentsDepositsOverview.kt | 4 ++++ .../WooPaymentsDepositsOverviewApiResponse.kt | 2 ++ .../WooPaymentsDepositsOverviewEntity.kt | 3 +++ .../WooPaymentsDepositsOverviewMapper.kt | 6 ++++++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/plugins/woocommerce/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/30.json b/plugins/woocommerce/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/30.json index 4ffe45713a..accaff4646 100644 --- a/plugins/woocommerce/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/30.json +++ b/plugins/woocommerce/schemas/org.wordpress.android.fluxc.persistence.WCAndroidDatabase/30.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 30, - "identityHash": "46e29ce7aa2fba81c03063031e265024", + "identityHash": "1e3ad3f4fb750ae397a8fee0c724ed14", "entities": [ { "tableName": "AddonEntity", @@ -1291,7 +1291,7 @@ }, { "tableName": "WooPaymentsDepositsOverview", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `depositsEnabled` INTEGER, `depositsBlocked` INTEGER, `defaultCurrency` TEXT, `delayDays` INTEGER, `interval` TEXT, PRIMARY KEY(`localSiteId`))", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`localSiteId` INTEGER NOT NULL, `depositsEnabled` INTEGER, `depositsBlocked` INTEGER, `defaultCurrency` TEXT, `delayDays` INTEGER, `weeklyAnchor` TEXT, `monthlyAnchor` INTEGER, `interval` TEXT, PRIMARY KEY(`localSiteId`))", "fields": [ { "fieldPath": "localSiteId", @@ -1323,6 +1323,18 @@ "affinity": "INTEGER", "notNull": false }, + { + "fieldPath": "account.depositsSchedule.weeklyAnchor", + "columnName": "weeklyAnchor", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "account.depositsSchedule.monthlyAnchor", + "columnName": "monthlyAnchor", + "affinity": "INTEGER", + "notNull": false + }, { "fieldPath": "account.depositsSchedule.interval", "columnName": "interval", @@ -1595,7 +1607,7 @@ "views": [], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '46e29ce7aa2fba81c03063031e265024')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1e3ad3f4fb750ae397a8fee0c724ed14')" ] } } \ No newline at end of file diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/payments/woo/WooPaymentsDepositsOverview.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/payments/woo/WooPaymentsDepositsOverview.kt index 696fb5cf32..cb0f989640 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/payments/woo/WooPaymentsDepositsOverview.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/payments/woo/WooPaymentsDepositsOverview.kt @@ -1,5 +1,7 @@ package org.wordpress.android.fluxc.model.payments.woo +import com.google.gson.annotations.SerializedName + data class WooPaymentsDepositsOverview( val account: Account?, val balance: Balance?, @@ -13,6 +15,8 @@ data class WooPaymentsDepositsOverview( ) { data class DepositsSchedule( val delayDays: Int?, + val weeklyAnchor: String?, + val monthlyAnchor: Int?, val interval: String? ) } diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/payments/woo/WooPaymentsDepositsOverviewApiResponse.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/payments/woo/WooPaymentsDepositsOverviewApiResponse.kt index fc88b54d66..d8443bdcbb 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/payments/woo/WooPaymentsDepositsOverviewApiResponse.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/network/rest/wpcom/wc/payments/woo/WooPaymentsDepositsOverviewApiResponse.kt @@ -63,5 +63,7 @@ data class WooPaymentsAccountDepositSummary( data class WooPaymentsDepositsSchedule( @SerializedName("delay_days") val delayDays: Int?, + @SerializedName("weekly_anchor") val weeklyAnchor: String?, + @SerializedName("monthly_anchor") val monthlyAnchor: Int?, val interval: String? ) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooPaymentsDepositsOverviewEntity.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooPaymentsDepositsOverviewEntity.kt index a15c4b43f4..2e33be57b0 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooPaymentsDepositsOverviewEntity.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooPaymentsDepositsOverviewEntity.kt @@ -5,6 +5,7 @@ import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.ForeignKey.CASCADE import androidx.room.PrimaryKey +import com.google.gson.annotations.SerializedName import org.wordpress.android.fluxc.model.LocalOrRemoteId @Entity(tableName = "WooPaymentsDepositsOverview") @@ -26,6 +27,8 @@ data class WooPaymentsAccountDepositSummaryEntity( data class WooPaymentsDepositsSchedule( val delayDays: Int?, + val weeklyAnchor: String?, + val monthlyAnchor: Int?, val interval: String? ) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/mappers/WooPaymentsDepositsOverviewMapper.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/mappers/WooPaymentsDepositsOverviewMapper.kt index 2a05e832bd..bbc436f9c3 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/mappers/WooPaymentsDepositsOverviewMapper.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/mappers/WooPaymentsDepositsOverviewMapper.kt @@ -34,6 +34,8 @@ class WooPaymentsDepositsOverviewMapper @Inject constructor() { depositsSchedule = summary.depositsSchedule?.let { DepositsSchedule( delayDays = it.delayDays, + weeklyAnchor = it.weeklyAnchor, + monthlyAnchor = it.monthlyAnchor, interval = it.interval ) } @@ -221,6 +223,8 @@ class WooPaymentsDepositsOverviewMapper @Inject constructor() { depositsSchedule?.let { DepositsSchedule( delayDays = it.delayDays, + weeklyAnchor = it.weeklyAnchor, + monthlyAnchor = it.monthlyAnchor, interval = it.interval ) } @@ -239,6 +243,8 @@ class WooPaymentsDepositsOverviewMapper @Inject constructor() { depositsSchedule?.let { WooPaymentsDepositsSchedule( delayDays = it.delayDays, + weeklyAnchor = it.weeklyAnchor, + monthlyAnchor = it.monthlyAnchor, interval = it.interval ) } From 3f353df328a3455586d9ff721fdceeb38b982dbf Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 10 Nov 2023 11:12:49 +0100 Subject: [PATCH 140/144] Added a unit test on changes --- .../WooPaymentsDepositsOverviewMapperTest.kt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/example/src/test/java/org/wordpress/android/fluxc/persistence/mappers/WooPaymentsDepositsOverviewMapperTest.kt b/example/src/test/java/org/wordpress/android/fluxc/persistence/mappers/WooPaymentsDepositsOverviewMapperTest.kt index 2acf35d483..b39933f85c 100644 --- a/example/src/test/java/org/wordpress/android/fluxc/persistence/mappers/WooPaymentsDepositsOverviewMapperTest.kt +++ b/example/src/test/java/org/wordpress/android/fluxc/persistence/mappers/WooPaymentsDepositsOverviewMapperTest.kt @@ -2,7 +2,6 @@ package org.wordpress.android.fluxc.persistence.mappers import org.assertj.core.api.Assertions.assertThat import org.junit.Test -import org.wordpress.android.fluxc.model.LocalOrRemoteId import org.wordpress.android.fluxc.model.LocalOrRemoteId.LocalId import org.wordpress.android.fluxc.model.payments.woo.WooPaymentsDepositsOverviewComposedEntities import org.wordpress.android.fluxc.network.rest.wpcom.wc.payments.woo.WooPaymentsAccountDepositSummary @@ -118,8 +117,10 @@ class WooPaymentsDepositsOverviewMapperTest { depositsEnabled = true, depositsBlocked = true, depositsSchedule = WooPaymentsDepositsSchedule( - delayDays = 1, - interval = "interval" + interval = "interval", + weeklyAnchor = "monday", + monthlyAnchor = 10, + delayDays = 1 ), defaultCurrency = "defaultCurrency" ) @@ -181,6 +182,8 @@ class WooPaymentsDepositsOverviewMapperTest { assertThat(result.account?.depositsBlocked).isEqualTo(true) assertThat(result.account?.depositsEnabled).isEqualTo(true) assertThat(result.account?.depositsSchedule?.delayDays).isEqualTo(1) + assertThat(result.account?.depositsSchedule?.monthlyAnchor).isEqualTo(10) + assertThat(result.account?.depositsSchedule?.weeklyAnchor).isEqualTo("monday") assertThat(result.account?.depositsSchedule?.interval).isEqualTo("interval") } @@ -190,13 +193,15 @@ class WooPaymentsDepositsOverviewMapperTest { // GIVEN val entity = WooPaymentsDepositsOverviewComposedEntities( overview = WooPaymentsDepositsOverviewEntity( - localSiteId = LocalOrRemoteId.LocalId(1), + localSiteId = LocalId(1), account = WooPaymentsAccountDepositSummaryEntity( depositsEnabled = true, depositsBlocked = true, depositsSchedule = WooPaymentsDepositsScheduleEntity( delayDays = 1, - interval = "interval" + interval = "interval", + monthlyAnchor = null, + weeklyAnchor = null, ), defaultCurrency = "defaultCurrency" ) @@ -348,6 +353,8 @@ class WooPaymentsDepositsOverviewMapperTest { assertThat(result.account?.depositsBlocked).isEqualTo(true) assertThat(result.account?.depositsEnabled).isEqualTo(true) assertThat(result.account?.depositsSchedule?.delayDays).isEqualTo(1) + assertThat(result.account?.depositsSchedule?.monthlyAnchor).isNull() + assertThat(result.account?.depositsSchedule?.weeklyAnchor).isNull() assertThat(result.account?.depositsSchedule?.interval).isEqualTo("interval") } } From 16c04bb7a42263c78acfb882f02a5c1d8e808fc6 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 10 Nov 2023 11:22:35 +0100 Subject: [PATCH 141/144] Removed unused imports --- .../fluxc/model/payments/woo/WooPaymentsDepositsOverview.kt | 2 -- .../persistence/entity/WooPaymentsDepositsOverviewEntity.kt | 1 - 2 files changed, 3 deletions(-) diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/payments/woo/WooPaymentsDepositsOverview.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/payments/woo/WooPaymentsDepositsOverview.kt index cb0f989640..6e706a4675 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/payments/woo/WooPaymentsDepositsOverview.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/model/payments/woo/WooPaymentsDepositsOverview.kt @@ -1,7 +1,5 @@ package org.wordpress.android.fluxc.model.payments.woo -import com.google.gson.annotations.SerializedName - data class WooPaymentsDepositsOverview( val account: Account?, val balance: Balance?, diff --git a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooPaymentsDepositsOverviewEntity.kt b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooPaymentsDepositsOverviewEntity.kt index 2e33be57b0..0b16699756 100644 --- a/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooPaymentsDepositsOverviewEntity.kt +++ b/plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/persistence/entity/WooPaymentsDepositsOverviewEntity.kt @@ -5,7 +5,6 @@ import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.ForeignKey.CASCADE import androidx.room.PrimaryKey -import com.google.gson.annotations.SerializedName import org.wordpress.android.fluxc.model.LocalOrRemoteId @Entity(tableName = "WooPaymentsDepositsOverview") From 17e84d56718695095d2fbbe459f0654214154492 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 10 Nov 2023 12:30:16 -0300 Subject: [PATCH 142/144] Modify TwoFactorRequest to use the login base endpoint --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index 87a8d12ba8..e8fbd8a7c5 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -213,7 +213,7 @@ public PasswordRequest(String appId, String appSecret, String username, String p public static class TwoFactorRequest extends OauthRequest { public TwoFactorRequest(String appId, String appSecret, String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, Listener listener, ErrorListener errorListener) { - super(TOKEN_ENDPOINT, appId, appSecret, listener, errorListener); + super(LOGIN_BASE_ENDPOINT, appId, appSecret, listener, errorListener); mParams.put(USERNAME_PARAM_NAME, username); mParams.put(PASSWORD_PARAM_NAME, password); mParams.put(GRANT_TYPE_PARAM_NAME, PASSWORD_GRANT_TYPE); From 5bc5ae1573d6c0b3cea4f3b5d0d5455bb95673a7 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 10 Nov 2023 13:01:49 -0300 Subject: [PATCH 143/144] Refactor response handling from Oauth endpoint --- .../rest/wpcom/auth/Authenticator.java | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index e8fbd8a7c5..f4d8c7b6cf 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -5,6 +5,7 @@ import androidx.annotation.NonNull; +import com.android.volley.Cache; import com.android.volley.NetworkResponse; import com.android.volley.ParseError; import com.android.volley.Request; @@ -159,6 +160,7 @@ public void makeRequest(String userId, String twoStepNonce, private static class OauthRequest extends Request { private static final String DATA = "data"; private static final String BEARER_TOKEN = "bearer_token"; + private static final String ACCESS_TOKEN = "access_token"; private final Listener mListener; protected Map mParams = new HashMap<>(); @@ -183,19 +185,31 @@ public void deliverResponse(OauthResponse response) { protected Response parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); - JSONObject responseData = new JSONObject(jsonString).getJSONObject(DATA); - String bearerToken = responseData.optString(BEARER_TOKEN); - if (bearerToken.isEmpty()) { - return Response.success(new TwoFactorResponse(responseData), - HttpHeaderParser.parseCacheHeaders(response)); + JSONObject responseJson = new JSONObject(jsonString); + JSONObject responseData = responseJson.optJSONObject(DATA); + Cache.Entry headers = HttpHeaderParser.parseCacheHeaders(response); + if (responseData != null) { + return handleDataObjectResponse(headers, responseData); + } else { + String accessToken = responseJson.getString(ACCESS_TOKEN); + return Response.success(new Token(accessToken), headers); } - return Response.success(new Token(bearerToken), - HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException | JSONException e) { return Response.error(new ParseError(e)); } } + + @NonNull + private static Response handleDataObjectResponse(Cache.Entry headers, JSONObject responseData) + throws JSONException { + String bearerToken = responseData.optString(BEARER_TOKEN); + if (bearerToken.isEmpty()) { + return Response.success(new TwoFactorResponse(responseData), headers); + } + + return Response.success(new Token(bearerToken), headers); + } } public static class PasswordRequest extends OauthRequest { @@ -213,7 +227,7 @@ public PasswordRequest(String appId, String appSecret, String username, String p public static class TwoFactorRequest extends OauthRequest { public TwoFactorRequest(String appId, String appSecret, String username, String password, String twoStepCode, boolean shouldSendTwoStepSMS, Listener listener, ErrorListener errorListener) { - super(LOGIN_BASE_ENDPOINT, appId, appSecret, listener, errorListener); + super(TOKEN_ENDPOINT, appId, appSecret, listener, errorListener); mParams.put(USERNAME_PARAM_NAME, username); mParams.put(PASSWORD_PARAM_NAME, password); mParams.put(GRANT_TYPE_PARAM_NAME, PASSWORD_GRANT_TYPE); From 591479f60ddcf1aad966a6711fcafcb4aee8f849 Mon Sep 17 00:00:00 2001 From: ThomazFB Date: Fri, 10 Nov 2023 13:03:17 -0300 Subject: [PATCH 144/144] Fix checkstyle issues --- .../android/fluxc/network/rest/wpcom/auth/Authenticator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java index f4d8c7b6cf..59b4cb6a4a 100644 --- a/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java +++ b/fluxc/src/main/java/org/wordpress/android/fluxc/network/rest/wpcom/auth/Authenticator.java @@ -194,7 +194,6 @@ protected Response parseNetworkResponse(NetworkResponse response) String accessToken = responseJson.getString(ACCESS_TOKEN); return Response.success(new Token(accessToken), headers); } - } catch (UnsupportedEncodingException | JSONException e) { return Response.error(new ParseError(e)); }