From 370c0a83a26ac8decef48dd47db5e114ff4962cd Mon Sep 17 00:00:00 2001 From: Mylloon Date: Tue, 31 Aug 2021 00:28:21 +0200 Subject: [PATCH] Adding Captcha support and call the login page when auth failed --- .../java/com/mylloon/mobidl/MainActivity.kt | 45 +++++++++++----- .../main/java/com/mylloon/mobidl/Scraper.kt | 51 ++++++++++++------- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/mylloon/mobidl/MainActivity.kt b/app/src/main/java/com/mylloon/mobidl/MainActivity.kt index cffb4d1..7f106a9 100644 --- a/app/src/main/java/com/mylloon/mobidl/MainActivity.kt +++ b/app/src/main/java/com/mylloon/mobidl/MainActivity.kt @@ -22,6 +22,7 @@ import androidx.core.content.ContextCompat import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.floatingactionbutton.FloatingActionButton +import kotlinx.coroutines.runBlocking import java.util.* @@ -162,7 +163,7 @@ class MainActivity : AppCompatActivity() { button?.setOnClickListener { val password = Credentials().get(1) if (password != null) { // call script - callScript(user, password.toString(), button?.text.toString()) + callScrapper(user, password.toString(), button?.text.toString()) } else { Toast.makeText(applicationContext, R.string.notConnected, Toast.LENGTH_LONG) .show() @@ -222,6 +223,36 @@ class MainActivity : AppCompatActivity() { } } + private fun callScrapper(user: String, password: String, app: String, captchaID: String? = null, captchaResponse: String? = null) { + if (ContextCompat.checkSelfPermission(this@MainActivity, Manifest.permission.INTERNET) + != PackageManager.PERMISSION_GRANTED + ) { + Toast.makeText(this@MainActivity, R.string.internetPermission, Toast.LENGTH_SHORT) + .show() + this.finishAffinity() + } else { + runBlocking { + val returns: MutableList? = Scraper(user, password, app, captchaID = captchaID, captchaResponse = captchaResponse, debug = true).search() + if (returns != null) { // if job is needed + if (returns[0] == "errorNotConnected") loginPage() + if (returns[0] == "loginAttemptsExceeded") { + val builder: android.app.AlertDialog.Builder = android.app.AlertDialog.Builder( + instance) + builder.setTitle("Captcha") + builder.setMessage(returns[1]) + val input = EditText(instance) + input.inputType = InputType.TYPE_CLASS_TEXT + builder.setView(input) + builder.setPositiveButton(R.string.validate) { _, _ -> callScrapper(user, password, app, returns[2], input.text.toString()) } + builder.setNeutralButton(R.string.cancel) { dialog, _ -> dialog.cancel() } + + builder.show() + } + } + } + } + } + @SuppressLint("SetTextI18n") private fun settingsPage() { setContentView(R.layout.activity_settings) @@ -252,18 +283,6 @@ class MainActivity : AppCompatActivity() { } } - private fun callScript(user: String, password: String, app: String) { - if (ContextCompat.checkSelfPermission(this@MainActivity, Manifest.permission.INTERNET) - != PackageManager.PERMISSION_GRANTED - ) { - Toast.makeText(this@MainActivity, R.string.internetPermission, Toast.LENGTH_SHORT) - .show() - this.finishAffinity() - } else { - Scraper(user, password, app = app, debug = true).search() - } - } - override fun onResume() { super.onResume() if (prefs!!.getBoolean("firstrun", true)) { diff --git a/app/src/main/java/com/mylloon/mobidl/Scraper.kt b/app/src/main/java/com/mylloon/mobidl/Scraper.kt index 81a3bee..d043671 100644 --- a/app/src/main/java/com/mylloon/mobidl/Scraper.kt +++ b/app/src/main/java/com/mylloon/mobidl/Scraper.kt @@ -14,6 +14,8 @@ class Scraper( private var password: String, private var app: String, private var debug: Boolean = false, + private var captchaID: String? = null, + private var captchaResponse: String? = null ) { private var url: String = "https://forum.mobilism.org" @@ -31,13 +33,18 @@ class Scraper( return "${if (code != null) "[$code]" else ""}${if ((message.isNotEmpty()) and (code is Int)) " " else ""}$message." } - private fun connect() { + private fun connect(): MutableList? { if (debug) println("Connection attempt...") retry++ FuelManager.instance.basePath = url FuelManager.instance.baseParams = listOf("mode" to "login") + val params = mutableListOf("username" to pseudo, "password" to password, "login" to "Login") + if (captchaID != null) { + params.add("qa_answer" to captchaResponse.toString()) + params.add("qa_confirm_id" to captchaID.toString()) + } val session = "/ucp.php" - .httpPost(listOf("username" to pseudo, "password" to password, "login" to "Login")) + .httpPost(params) .responseString { _, response, result -> when (result) { is FuelFailure -> { @@ -51,36 +58,45 @@ class Scraper( } val data = session.join().data.decodeToString() sid = "(?<=sid=)(.{32})".toRegex().find(data)?.value - if (errorNotConnected in data) return if (loginAttemptsExceeded in data) error(loginAttemptsExceeded) else error(data) + if (errorNotConnected in data) return error(data) Credentials().storeSID(sid.toString()) return search() } - private fun error(htmlPage: String) { + private fun error(htmlPage: String): MutableList? { var message = "" + var array: MutableList? = null if (errorNotConnected in htmlPage) { - message = "${applicationContext().getString(R.string.connectionFailed)}\n${applicationContext().getString(R.string.credentialsDeleted)}." - Credentials().delete() - } else if (loginAttemptsExceeded in htmlPage) { - message = applicationContext().getString(R.string.loginAttemptsExceeded) + if (loginAttemptsExceeded in htmlPage) { + message = applicationContext().getString(R.string.loginAttemptsExceeded) + val qaConfirmID = "(?<=qa_confirm_id\" value=\")(.{32})".toRegex().find(htmlPage)?.value + var answer = "(?<=answer\">)(.*)? { // Do the research. if (sid == null) { - println(errorFormat(message = "No SID found")) - if (retry < 3) return connect() else return + println(errorFormat(message = "SID not found")) + return if (retry < 3) connect() else null } else { if (debug) println("SID recovered") retry = 0 } if (debug) println("Going to search page...") FuelManager.instance.basePath = url - FuelManager.instance.baseParams = - listOf("sid" to sid, "sr" to "topics", "sf" to "titleonly") + FuelManager.instance.baseParams = listOf("sid" to sid, "sr" to "topics", "sf" to "titleonly") val session = "/search.php" .httpGet(listOf("keywords" to app)) .responseString { _, response, result -> @@ -95,15 +111,16 @@ class Scraper( } } val data = session.join().data.decodeToString() - if (searchNotLogged in data) { + return if (searchNotLogged in data) { println(errorFormat(message = "The SID doesn't work, new attempt...")) - if (retry < 3) return connect() else return - } else return parse(data) + if (retry < 3) connect() else null + } else parse(data) } - private fun parse(htmlPage: String) { + private fun parse(htmlPage: String): MutableList? { if (debug) println("Fetching results for $app...") // println(htmlPage) + return null } }