-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use a webview for WP.com login #21414
base: trunk
Are you sure you want to change the base?
Changes from all commits
d8b9ea1
eb3d0d9
e2e9e16
8c8a89d
ed0fa69
2ab83b1
2824d28
f315a0d
921abfe
0fbfecd
355774f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
package org.wordpress.android.ui.accounts.login | ||
|
||
import android.content.Context | ||
|
||
interface LoginPrologueListener { | ||
// Login Prologue callbacks | ||
fun showEmailLoginScreen() | ||
fun showWPcomLoginScreen(context: Context) | ||
fun loginViaSiteAddress() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package org.wordpress.android.ui.accounts.login | ||
|
||
import android.content.ComponentName | ||
import android.content.Context | ||
import android.net.Uri | ||
import android.util.Log | ||
import androidx.browser.customtabs.CustomTabsCallback | ||
import androidx.browser.customtabs.CustomTabsClient | ||
import androidx.browser.customtabs.CustomTabsServiceConnection | ||
import androidx.browser.customtabs.CustomTabsSession | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.cancel | ||
import kotlinx.coroutines.runBlocking | ||
import org.wordpress.android.fluxc.network.rest.wpapi.WPcomLoginClient | ||
import org.wordpress.android.fluxc.network.rest.wpcom.auth.AppSecrets | ||
import org.wordpress.android.fluxc.store.AccountStore | ||
import javax.inject.Inject | ||
import kotlin.coroutines.CoroutineContext | ||
|
||
class WPcomLoginHelper @Inject constructor( | ||
private val loginClient: WPcomLoginClient, | ||
private val accountStore: AccountStore, | ||
appSecrets: AppSecrets | ||
) { | ||
private val context: CoroutineContext = Dispatchers.IO | ||
|
||
val wpcomLoginUri = loginClient.loginUri(appSecrets.redirectUri) | ||
private val customTabsServiceConnection = ServiceConnection(wpcomLoginUri) | ||
|
||
fun tryLoginWithDataString(data: String?) { | ||
if (data == null) { | ||
return | ||
} | ||
|
||
val code = this.codeFromAuthorizationUri(data) ?: return | ||
|
||
runBlocking { | ||
val tokenResult = loginClient.exchangeAuthCodeForToken(code) | ||
accountStore.updateAccessToken(tokenResult.getOrThrow()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you'd want to check if the token belongs to the current user before saving it. Users can log in with any account from the login webpage. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be for first-time authentication only – I'm thinking we'll want a |
||
Log.i("WPCOM_LOGIN", "Login Successful") | ||
} | ||
} | ||
|
||
fun isLoggedIn(): Boolean { | ||
return accountStore.hasAccessToken() | ||
} | ||
|
||
fun dispose() { | ||
context.cancel() | ||
} | ||
|
||
fun bindCustomTabsService(context: Context) { | ||
customTabsServiceConnection.bind(context) | ||
} | ||
|
||
private fun codeFromAuthorizationUri(string: String): String? { | ||
return Uri.parse(string).getQueryParameter("code") | ||
} | ||
} | ||
|
||
class ServiceConnection( | ||
var uri: Uri | ||
): CustomTabsServiceConnection() { | ||
private var client: CustomTabsClient? = null | ||
private var session: CustomTabsSession? = null | ||
|
||
override fun onCustomTabsServiceConnected(name: ComponentName, client: CustomTabsClient) { | ||
client.warmup(0) | ||
this.client = client | ||
|
||
val session = client.newSession(CustomTabsCallback()) | ||
session?.mayLaunchUrl(uri, null, null) | ||
session?.mayLaunchUrl(Uri.parse("https://wordpress.com/log-in/"), null, null) | ||
|
||
this.session = session | ||
} | ||
|
||
override fun onServiceDisconnected(name: ComponentName?) { | ||
this.client = null | ||
this.session = null | ||
} | ||
|
||
fun bind(context: Context) { | ||
// Do nothing if there is an existing service connection | ||
if (this.client != null) { | ||
return | ||
} | ||
|
||
// Get the default browser package name, this will be null if | ||
// the default browser does not provide a CustomTabsService | ||
val packageName = CustomTabsClient.getPackageName(context, null) ?: return | ||
|
||
CustomTabsClient.bindCustomTabsService(context, packageName, this) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ androidx-activity = '1.9.3' | |
androidx-annotation = '1.9.1' | ||
androidx-appcompat = '1.7.0' | ||
androidx-arch-core = '2.2.0' | ||
androidx-browser = '1.5.0' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that this is an outdated version of the library. The latest is 1.8.0. |
||
androidx-camera = '1.4.1' | ||
androidx-cardview = '1.0.0' | ||
androidx-compose-bom = '2024.12.01' | ||
|
@@ -120,6 +121,7 @@ androidx-annotation = { group = "androidx.annotation", name = "annotation", vers | |
androidx-appcompat-main = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } | ||
androidx-appcompat-resources = { group = "androidx.appcompat", name = "appcompat-resources", version.ref = "androidx-appcompat" } | ||
androidx-arch-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx-arch-core" } | ||
androidx-browser = { group="androidx.browser", "name" = "browser", version.ref = "androidx-browser" } | ||
androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "androidx-camera" } | ||
androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "androidx-camera" } | ||
androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "androidx-camera" } | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sonarcloud flags this as a security risk. Does it need to be exported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that this was required in order to handle custom URL schemes, but I might be incorrect!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I suspect you're right about that. This Sonarcloud page mentions ways to fix this warning.