VancedMicroG/firebase-auth-core/src/main/kotlin/org/microg/gms/firebase/auth/ReCaptchaActivity.kt

108 lines
4.2 KiB
Kotlin

/*
* SPDX-FileCopyrightText: 2020, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.firebase.auth
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.Intent.*
import android.os.Bundle
import android.os.ResultReceiver
import android.util.Log
import android.webkit.JavascriptInterface
import android.webkit.WebSettings
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity
import org.microg.gms.firebase.auth.core.R
import org.microg.gms.profile.Build
import org.microg.gms.profile.ProfileManager
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
private const val TAG = "GmsFirebaseAuthCaptcha"
class ReCaptchaActivity : AppCompatActivity() {
private val receiver: ResultReceiver?
get() = intent.getParcelableExtra(EXTRA_RESULT_RECEIVER)
private val hostname: String
get() = intent.getStringExtra(EXTRA_HOSTNAME) ?: "localhost:5000"
private var finished = false
@SuppressLint("SetJavaScriptEnabled", "AddJavascriptInterface")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
openWebsite()
}
private fun openWebsite() {
val apiKey = intent.getStringExtra(EXTRA_API_KEY) ?: return finishResult(Activity.RESULT_CANCELED)
setContentView(R.layout.activity_recaptcha)
val view = findViewById<WebView>(R.id.web)
val settings = view.settings
settings.javaScriptEnabled = true
settings.useWideViewPort = false
settings.setSupportZoom(false)
settings.displayZoomControls = false
settings.cacheMode = WebSettings.LOAD_NO_CACHE
ProfileManager.ensureInitialized(this)
settings.userAgentString = Build.generateWebViewUserAgentString(settings.userAgentString)
view.addJavascriptInterface(object : Any() {
@JavascriptInterface
fun onReCaptchaToken(token: String) {
Log.d(TAG, "onReCaptchaToken: $token")
finishResult(Activity.RESULT_OK, token)
}
}, "MyCallback")
val captcha = assets.open("recaptcha.html").bufferedReader().readText().replace("%apikey%", apiKey)
view.loadDataWithBaseURL("https://$hostname/", captcha, null, null, "https://$hostname/")
}
fun finishResult(resultCode: Int, token: String? = null) {
finished = true
setResult(resultCode, token?.let { Intent().apply { putExtra(EXTRA_TOKEN, it) } })
receiver?.send(resultCode, token?.let { Bundle().apply { putString(EXTRA_TOKEN, it) } })
finish()
}
override fun onDestroy() {
super.onDestroy()
if (!finished) receiver?.send(Activity.RESULT_CANCELED, null)
}
companion object {
const val EXTRA_TOKEN = "token"
const val EXTRA_API_KEY = "api_key"
const val EXTRA_HOSTNAME = "hostname"
const val EXTRA_RESULT_RECEIVER = "receiver"
fun isSupported(context: Context): Boolean = true
suspend fun awaitToken(context: Context, apiKey: String, hostname: String? = null) = suspendCoroutine<String> { continuation ->
val intent = Intent(context, ReCaptchaActivity::class.java)
val resultReceiver = object : ResultReceiver(null) {
override fun onReceiveResult(resultCode: Int, resultData: Bundle?) {
try {
if (resultCode == Activity.RESULT_OK) {
continuation.resume(resultData?.getString(EXTRA_TOKEN)!!)
}
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}
}
intent.putExtra(EXTRA_API_KEY, apiKey)
intent.putExtra(EXTRA_RESULT_RECEIVER, resultReceiver)
intent.putExtra(EXTRA_HOSTNAME, hostname)
intent.addFlags(FLAG_ACTIVITY_NEW_TASK)
intent.addFlags(FLAG_ACTIVITY_REORDER_TO_FRONT)
intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
context.startActivity(intent)
}
}
}