diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:43:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:43:14 +0000 |
commit | 8dd16259287f58f9273002717ec4d27e97127719 (patch) | |
tree | 3863e62a53829a84037444beab3abd4ed9dfc7d0 /mobile/android/android-components/components/feature/accounts | |
parent | Releasing progress-linux version 126.0.1-1~progress7.99u1. (diff) | |
download | firefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz firefox-8dd16259287f58f9273002717ec4d27e97127719.zip |
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mobile/android/android-components/components/feature/accounts')
6 files changed, 151 insertions, 20 deletions
diff --git a/mobile/android/android-components/components/feature/accounts/src/main/assets/extensions/fxawebchannel/background.js b/mobile/android/android-components/components/feature/accounts/src/main/assets/extensions/fxawebchannel/background.js index b90f57154a..e8cf40ba8d 100644 --- a/mobile/android/android-components/components/feature/accounts/src/main/assets/extensions/fxawebchannel/background.js +++ b/mobile/android/android-components/components/feature/accounts/src/main/assets/extensions/fxawebchannel/background.js @@ -10,12 +10,12 @@ let port = browser.runtime.connectNative(WEB_CHANNEL_BACKGROUND_MESSAGING_ID); /* Handle messages from native application, register content script for specific url. */ -port.onMessage.addListener( event => { - if(event.type == "overrideFxAServer"){ +port.onMessage.addListener(event => { + if (event.type == "overrideFxAServer") { browser.contentScripts.register({ - "matches": [ event.url+"/*" ], - "js": [{file: "fxawebchannel.js"}], - "runAt": "document_start" + matches: [event.url + "/*"], + js: [{ file: "fxawebchannel.js" }], + runAt: "document_start", }); port.disconnect(); } diff --git a/mobile/android/android-components/components/feature/accounts/src/main/assets/extensions/fxawebchannel/fxawebchannel.js b/mobile/android/android-components/components/feature/accounts/src/main/assets/extensions/fxawebchannel/fxawebchannel.js index 2f5934dff1..16614d3069 100644 --- a/mobile/android/android-components/components/feature/accounts/src/main/assets/extensions/fxawebchannel/fxawebchannel.js +++ b/mobile/android/android-components/components/feature/accounts/src/main/assets/extensions/fxawebchannel/fxawebchannel.js @@ -10,16 +10,18 @@ let port = browser.runtime.connectNative("mozacWebchannel"); /* Handle messages from native application, dispatch them to FxA via an event. */ -port.onMessage.addListener((event) => { - window.dispatchEvent(new CustomEvent('WebChannelMessageToContent', { - detail: JSON.stringify(event) - })); +port.onMessage.addListener(event => { + window.dispatchEvent( + new CustomEvent("WebChannelMessageToContent", { + detail: JSON.stringify(event), + }) + ); }); /* Handle messages from FxA. Messages are posted to the native application for processing. */ -window.addEventListener('WebChannelMessageToChrome', function (e) { +window.addEventListener("WebChannelMessageToChrome", function (e) { const detail = JSON.parse(e.detail); port.postMessage(detail); }); diff --git a/mobile/android/android-components/components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeature.kt b/mobile/android/android-components/components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeature.kt index 60913282b7..b244eb0de8 100644 --- a/mobile/android/android-components/components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeature.kt +++ b/mobile/android/android-components/components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeature.kt @@ -38,10 +38,15 @@ class FirefoxAccountsAuthFeature( * @param context [Context] The application context * @param entrypoint [FxAEntryPoint] The Firefox Accounts feature/entrypoint that is launching * authentication + * @param scopes [Set<String>] The oAuth scopes being requested */ - fun beginAuthentication(context: Context, entrypoint: FxAEntryPoint) { + fun beginAuthentication( + context: Context, + entrypoint: FxAEntryPoint, + scopes: Set<String> = emptySet(), + ) { beginAuthenticationAsync(context) { - accountManager.beginAuthentication(entrypoint = entrypoint) + accountManager.beginAuthentication(entrypoint = entrypoint, authScopes = scopes) } } @@ -50,15 +55,17 @@ class FirefoxAccountsAuthFeature( * @param context [Context] The application context * @param pairingUrl [String] The pairing URL retrieved from the QR scanner * @param entrypoint [FxAEntryPoint] The Firefox Accounts feature/entrypoint that is launching + * @param scopes [Set<String>] The oAuth scopes being requested * authentication */ fun beginPairingAuthentication( context: Context, pairingUrl: String, entrypoint: FxAEntryPoint, + scopes: Set<String> = emptySet(), ) { beginAuthenticationAsync(context) { - accountManager.beginAuthentication(pairingUrl, entrypoint = entrypoint) + accountManager.beginAuthentication(pairingUrl, entrypoint = entrypoint, scopes) } } diff --git a/mobile/android/android-components/components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FxaWebChannelFeature.kt b/mobile/android/android-components/components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FxaWebChannelFeature.kt index f5554c99e4..377d6b0d93 100644 --- a/mobile/android/android-components/components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FxaWebChannelFeature.kt +++ b/mobile/android/android-components/components/feature/accounts/src/main/java/mozilla/components/feature/accounts/FxaWebChannelFeature.kt @@ -20,6 +20,7 @@ import mozilla.components.concept.engine.webextension.MessageHandler import mozilla.components.concept.engine.webextension.Port import mozilla.components.concept.engine.webextension.WebExtensionRuntime import mozilla.components.concept.sync.AuthType +import mozilla.components.concept.sync.UserData import mozilla.components.lib.state.ext.flowScoped import mozilla.components.service.fxa.FxaAuthData import mozilla.components.service.fxa.ServerConfig @@ -157,6 +158,7 @@ class FxaWebChannelFeature( WebChannelCommand.CAN_LINK_ACCOUNT -> processCanLinkAccountCommand(messageId) WebChannelCommand.FXA_STATUS -> processFxaStatusCommand(accountManager, messageId, fxaCapabilities) WebChannelCommand.OAUTH_LOGIN -> processOauthLoginCommand(accountManager, payload) + WebChannelCommand.LOGIN -> processLoginCommand(accountManager, payload) } response?.let { port.postMessage(it) } } @@ -195,6 +197,7 @@ class FxaWebChannelFeature( enum class WebChannelCommand { CAN_LINK_ACCOUNT, + LOGIN, OAUTH_LOGIN, FXA_STATUS, } @@ -222,6 +225,12 @@ class FxaWebChannelFeature( private const val COMMAND_STATUS = "fxaccounts:fxa_status" /** + * Gets triggered when the web content is signed in/up, but not necessarily verified + * it passes in its payload the session token the web content is holding on to + */ + private const val COMMAND_LOGIN = "fxaccounts:login" + + /** * Handles the [COMMAND_CAN_LINK_ACCOUNT] event from the web-channel. * Currently this always response with 'ok=true'. * On Fx Desktop, this event prompts a possible "another user was previously logged in on @@ -329,6 +338,32 @@ class FxaWebChannelFeature( } /** + * Handles the [COMMAND_LOGIN] event from the web-channel + */ + private fun processLoginCommand(accountManager: FxaAccountManager, payload: JSONObject): JSONObject? { + val sessionToken: String + val email: String + val uid: String + val verified: Boolean + + try { + val data = payload.getJSONObject("data") + sessionToken = data.getString("sessionToken") + email = data.getString("email") + uid = data.getString("uid") + verified = data.getBoolean("verified") + } catch (e: JSONException) { + logger.error("Error while processing WebChannel login command", e) + return null + } + val userData = UserData(sessionToken, email, uid, verified) + CoroutineScope(Dispatchers.Main).launch { + accountManager.setUserData(userData) + } + return null + } + + /** * Handles the [COMMAND_OAUTH_LOGIN] event from the web-channel. */ private fun processOauthLoginCommand(accountManager: FxaAccountManager, payload: JSONObject): JSONObject? { @@ -368,6 +403,7 @@ class FxaWebChannelFeature( COMMAND_CAN_LINK_ACCOUNT -> WebChannelCommand.CAN_LINK_ACCOUNT COMMAND_OAUTH_LOGIN -> WebChannelCommand.OAUTH_LOGIN COMMAND_STATUS -> WebChannelCommand.FXA_STATUS + COMMAND_LOGIN -> WebChannelCommand.LOGIN else -> { logger.warn("Unrecognized WebChannel command: $this") null diff --git a/mobile/android/android-components/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt b/mobile/android/android-components/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt index a32681e8fe..ef7f78b336 100644 --- a/mobile/android/android-components/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt +++ b/mobile/android/android-components/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FirefoxAccountsAuthFeatureTest.kt @@ -17,8 +17,8 @@ import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.DeviceConfig import mozilla.components.concept.sync.DeviceType import mozilla.components.concept.sync.FxAEntryPoint -import mozilla.components.concept.sync.OAuthAccount import mozilla.components.concept.sync.Profile +import mozilla.components.service.fxa.FirefoxAccount import mozilla.components.service.fxa.FxaAuthData import mozilla.components.service.fxa.ServerConfig import mozilla.components.service.fxa.StorageWrapper @@ -45,13 +45,13 @@ internal class TestableStorageWrapper( manager: FxaAccountManager, accountEventObserverRegistry: ObserverRegistry<AccountEventsObserver>, serverConfig: ServerConfig, - private val block: () -> OAuthAccount = { - val account: OAuthAccount = mock() + private val block: () -> FirefoxAccount = { + val account: FirefoxAccount = mock() `when`(account.deviceConstellation()).thenReturn(mock()) account }, ) : StorageWrapper(manager, accountEventObserverRegistry, serverConfig) { - override fun obtainAccount(): OAuthAccount = block() + override fun obtainAccount(): FirefoxAccount = block() } // Same as the actual account manager, except we get to control how FirefoxAccountShaped instances @@ -63,7 +63,7 @@ class TestableFxaAccountManager( config: ServerConfig, scopes: Set<String>, coroutineContext: CoroutineContext, - block: () -> OAuthAccount = { mock() }, + block: () -> FirefoxAccount = { mock() }, ) : FxaAccountManager(context, config, DeviceConfig("test", DeviceType.MOBILE, setOf()), null, scopes, null, coroutineContext) { private val testableStorageWrapper = TestableStorageWrapper(this, accountEventObserverRegistry, serverConfig, block) override fun getStorageWrapper(): StorageWrapper { @@ -252,7 +252,7 @@ class FirefoxAccountsAuthFeatureTest { private suspend fun prepareAccountManagerForSuccessfulAuthentication( coroutineContext: CoroutineContext, ): TestableFxaAccountManager { - val mockAccount: OAuthAccount = mock() + val mockAccount: FirefoxAccount = mock() val profile = Profile(uid = "testUID", avatar = null, email = "test@example.com", displayName = "test profile") `when`(mockAccount.deviceConstellation()).thenReturn(mock()) @@ -279,7 +279,7 @@ class FirefoxAccountsAuthFeatureTest { private suspend fun prepareAccountManagerForFailedAuthentication( coroutineContext: CoroutineContext, ): TestableFxaAccountManager { - val mockAccount: OAuthAccount = mock() + val mockAccount: FirefoxAccount = mock() val profile = Profile(uid = "testUID", avatar = null, email = "test@example.com", displayName = "test profile") `when`(mockAccount.getProfile(anyBoolean())).thenReturn(profile) diff --git a/mobile/android/android-components/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FxaWebChannelFeatureTest.kt b/mobile/android/android-components/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FxaWebChannelFeatureTest.kt index 809ed7a703..3a49633f61 100644 --- a/mobile/android/android-components/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FxaWebChannelFeatureTest.kt +++ b/mobile/android/android-components/components/feature/accounts/src/test/java/mozilla/components/feature/accounts/FxaWebChannelFeatureTest.kt @@ -19,6 +19,7 @@ import mozilla.components.concept.engine.webextension.WebExtension import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.OAuthAccount import mozilla.components.concept.sync.Profile +import mozilla.components.concept.sync.UserData import mozilla.components.service.fxa.FxaAuthData import mozilla.components.service.fxa.ServerConfig import mozilla.components.service.fxa.SyncEngine @@ -701,6 +702,56 @@ class FxaWebChannelFeatureTest { assertTrue(FxaWebChannelFeature.isCommunicationAllowed("http://localhost", "http://localhost")) } + @Test + fun `COMMAND_LOGIN must be processed and sets the user's data`() = runTest { + val accountManager: FxaAccountManager = mock() // syncConfig is null by default (is not configured) + val engineSession: EngineSession = mock() + val ext: WebExtension = mock() + val port: Port = mock() + val messageHandler = argumentCaptor<MessageHandler>() + + WebExtensionController.installedExtensions[FxaWebChannelFeature.WEB_CHANNEL_EXTENSION_ID] = ext + + val webchannelFeature = prepareFeatureForTest(ext, port, engineSession, null, emptySet(), accountManager) + webchannelFeature.start() + shadowOf(getMainLooper()).idle() + + verify(ext).registerContentMessageHandler( + eq(engineSession), + eq(FxaWebChannelFeature.WEB_CHANNEL_MESSAGING_ID), + messageHandler.capture(), + ) + messageHandler.value.onPortConnected(port) + + // Action: signin + verifyLogin("sessiontoken123", "foo@bar.com", "uid123", false, messageHandler.value, accountManager) + } + + @Test + fun `COMMAND_LOGIN invalid json sends back`() = runTest { + val accountManager: FxaAccountManager = mock() // syncConfig is null by default (is not configured) + val engineSession: EngineSession = mock() + val ext: WebExtension = mock() + val port: Port = mock() + val messageHandler = argumentCaptor<MessageHandler>() + + WebExtensionController.installedExtensions[FxaWebChannelFeature.WEB_CHANNEL_EXTENSION_ID] = ext + + val webchannelFeature = prepareFeatureForTest(ext, port, engineSession, null, emptySet(), accountManager) + webchannelFeature.start() + shadowOf(getMainLooper()).idle() + + verify(ext).registerContentMessageHandler( + eq(engineSession), + eq(FxaWebChannelFeature.WEB_CHANNEL_MESSAGING_ID), + messageHandler.capture(), + ) + messageHandler.value.onPortConnected(port) + + // Action: signin + verifyLogin("sessiontoken123", "foo@bar.com", "uid123", false, messageHandler.value, accountManager) + } + private fun JSONObject.getSupportedEngines(): List<String> { val engines = this.getJSONObject("message") .getJSONObject("data") @@ -798,6 +849,41 @@ class FxaWebChannelFeatureTest { ) } + private suspend fun verifyLogin(sessionToken: String, email: String, uid: String, verified: Boolean, messageHandler: MessageHandler, accountManager: FxaAccountManager) { + val jsonToWebChannel = jsonLogin(sessionToken, email, uid, verified) + val port = mock<Port>() + whenever(port.senderUrl()).thenReturn("https://foo.bar/email") + messageHandler.onPortMessage(jsonToWebChannel, port) + + val expectedUserData = UserData( + sessionToken = sessionToken, + email = email, + uid = uid, + verified = verified, + ) + shadowOf(getMainLooper()).idle() + + verify(accountManager).setUserData(expectedUserData) + } + + private fun jsonLogin(sessionToken: String, email: String, uid: String, verified: Boolean): JSONObject { + return JSONObject( + """{ + "message":{ + "command": "fxaccounts:login", + "messageId":123, + "data":{ + "email":"$email", + "sessionToken":"$sessionToken", + "uid":"$uid", + "verified":$verified + } + } + } + """.trimIndent(), + ) + } + private fun prepareFeatureForTest( ext: WebExtension = mock(), port: Port = mock(), |