Make sure downloadAndRunBotguard() is called after <script> loaded

This commit is contained in:
Stypox 2025-01-27 13:21:03 +01:00 committed by AudricV
parent 2b183a0576
commit e7fe84f2c7
No known key found for this signature in database
GPG key ID: DA92EC7905614198

View file

@ -39,7 +39,7 @@ class PoTokenWebView private constructor(
webviewSettings.blockNetworkLoads = true // the WebView does not need internet access webviewSettings.blockNetworkLoads = true // the WebView does not need internet access
// so that we can run async functions and get back the result // so that we can run async functions and get back the result
webView.addJavascriptInterface(this, "PoTokenWebView") webView.addJavascriptInterface(this, JS_INTERFACE)
} }
/** /**
@ -48,6 +48,10 @@ class PoTokenWebView private constructor(
* run it, and obtain an `integrityToken`. * run it, and obtain an `integrityToken`.
*/ */
private fun loadHtmlAndObtainBotguard(context: Context) { private fun loadHtmlAndObtainBotguard(context: Context) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "loadHtmlAndObtainBotguard() called")
}
disposables.add( disposables.add(
Single.fromCallable { Single.fromCallable {
val html = context.assets.open("po_token.html").bufferedReader() val html = context.assets.open("po_token.html").bufferedReader()
@ -60,12 +64,15 @@ class PoTokenWebView private constructor(
{ html -> { html ->
webView.loadDataWithBaseURL( webView.loadDataWithBaseURL(
"https://www.youtube.com", "https://www.youtube.com",
html, html.replace(
"</script>",
// calls downloadAndRunBotguard() when the page has finished loading
"\n$JS_INTERFACE.downloadAndRunBotguard()</script>"
),
"text/html", "text/html",
"utf-8", "utf-8",
null, null,
) )
downloadAndRunBotguard()
}, },
this::onInitializationErrorCloseAndCancel this::onInitializationErrorCloseAndCancel
) )
@ -73,9 +80,15 @@ class PoTokenWebView private constructor(
} }
/** /**
* Called during initialization after the WebView content has been loaded. * Called during initialization by the JavaScript snippet appended to the HTML page content in
* [loadHtmlAndObtainBotguard] after the WebView content has been loaded.
*/ */
private fun downloadAndRunBotguard() { @JavascriptInterface
fun downloadAndRunBotguard() {
if (BuildConfig.DEBUG) {
Log.d(TAG, "downloadAndRunBotguard() called")
}
makeJnnPaGoogleapisRequest( makeJnnPaGoogleapisRequest(
"https://jnn-pa.googleapis.com/\$rpc/google.internal.waa.v1.Waa/Create", "https://jnn-pa.googleapis.com/\$rpc/google.internal.waa.v1.Waa/Create",
"[ \"$REQUEST_KEY\" ]", "[ \"$REQUEST_KEY\" ]",
@ -86,9 +99,9 @@ class PoTokenWebView private constructor(
data = JSON.parse(String.raw`$responseBody`) data = JSON.parse(String.raw`$responseBody`)
result = await runBotGuard(data) result = await runBotGuard(data)
globalThis.webPoSignalOutput = result.webPoSignalOutput globalThis.webPoSignalOutput = result.webPoSignalOutput
PoTokenWebView.onRunBotguardResult(result.botguardResponse) $JS_INTERFACE.onRunBotguardResult(result.botguardResponse)
} catch (error) { } catch (error) {
PoTokenWebView.onJsInitializationError(error.toString()) $JS_INTERFACE.onJsInitializationError(error.toString())
} }
})();""", })();""",
) {} ) {}
@ -127,9 +140,9 @@ class PoTokenWebView private constructor(
"""(async function() { """(async function() {
try { try {
globalThis.integrityToken = JSON.parse(String.raw`$responseBody`) globalThis.integrityToken = JSON.parse(String.raw`$responseBody`)
PoTokenWebView.onInitializationFinished(integrityToken[1]) $JS_INTERFACE.onInitializationFinished(integrityToken[1])
} catch (error) { } catch (error) {
PoTokenWebView.onJsInitializationError(error.toString()) $JS_INTERFACE.onJsInitializationError(error.toString())
} }
})();""", })();""",
) {} ) {}
@ -145,6 +158,9 @@ class PoTokenWebView private constructor(
*/ */
@JavascriptInterface @JavascriptInterface
fun onInitializationFinished(expirationTimeInSeconds: Long) { fun onInitializationFinished(expirationTimeInSeconds: Long) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "onInitializationFinished() called, expiration=${expirationTimeInSeconds}s")
}
// leave 10 minutes of margin just to be sure // leave 10 minutes of margin just to be sure
expirationInstant = Instant.now().plusSeconds(expirationTimeInSeconds - 600) expirationInstant = Instant.now().plusSeconds(expirationTimeInSeconds - 600)
generatorEmitter.onSuccess(this) generatorEmitter.onSuccess(this)
@ -178,6 +194,9 @@ class PoTokenWebView private constructor(
override fun generatePoToken(identifier: String): Single<String> = override fun generatePoToken(identifier: String): Single<String> =
Single.create { emitter -> Single.create { emitter ->
if (BuildConfig.DEBUG) {
Log.d(TAG, "generatePoToken() called with identifier $identifier")
}
runOnMainThread(emitter) { runOnMainThread(emitter) {
addPoTokenEmitter(identifier, emitter) addPoTokenEmitter(identifier, emitter)
webView.evaluateJavascript( webView.evaluateJavascript(
@ -186,9 +205,9 @@ class PoTokenWebView private constructor(
try { try {
poToken = await obtainPoToken(webPoSignalOutput, integrityToken, poToken = await obtainPoToken(webPoSignalOutput, integrityToken,
identifier) identifier)
PoTokenWebView.onObtainPoTokenResult(identifier, poToken) $JS_INTERFACE.onObtainPoTokenResult(identifier, poToken)
} catch (error) { } catch (error) {
PoTokenWebView.onObtainPoTokenError(identifier, error.toString()) $JS_INTERFACE.onObtainPoTokenError(identifier, error.toString())
} }
})();""", })();""",
) {} ) {}
@ -309,6 +328,7 @@ class PoTokenWebView private constructor(
private const val REQUEST_KEY = "O43z0dpjhgX20SCx4KAo" private const val REQUEST_KEY = "O43z0dpjhgX20SCx4KAo"
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " + private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.3" "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.3"
private const val JS_INTERFACE = "PoTokenWebView"
override fun newPoTokenGenerator(context: Context): Single<PoTokenGenerator> = override fun newPoTokenGenerator(context: Context): Single<PoTokenGenerator> =
Single.create { emitter -> Single.create { emitter ->