All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.stormbit.sdk.utils.vkapi.Auth.kt Maven / Gradle / Ivy

package com.github.stormbit.sdk.utils.vkapi

import com.github.stormbit.sdk.exceptions.CaptchaException
import com.github.stormbit.sdk.exceptions.NotValidAuthorization
import com.github.stormbit.sdk.exceptions.TwoFactorException
import com.github.stormbit.sdk.objects.Captcha
import com.github.stormbit.sdk.utils.*
import com.github.stormbit.sdk.utils.Utils.Companion.AUTH_HASH
import com.github.stormbit.sdk.utils.Utils.Companion.RE_CAPTCHAID
import com.github.stormbit.sdk.utils.Utils.Companion.toJsonObject
import com.google.gson.JsonObject
import net.dongliu.requests.Cookie
import net.dongliu.requests.Header
import org.jsoup.Jsoup
import org.jsoup.nodes.FormElement
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File

class Auth {
    private val log: Logger = LoggerFactory.getLogger(Auth::class.java)
    private var login: String? = null
    private var password: String? = null

    private var isSaveCookie: Boolean = false
    private var isLoadFromCookie: Boolean = false
    private val cookiesMap = HashMap()
    private val cookiesFile = File("cookies.json")

    private val STRING_USER_AGENT = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36"
    private val USER_AGENT = Header("User-Agent", STRING_USER_AGENT)
    private val FORM_ID = "quick_login_form"

    var session: Session = Session()
    private var twoFactorListener: TwoFactorListener? = null
    private var captchaListener: CaptchaListener? = null

    constructor(login: String, password: String, saveCookie: Boolean = false, loadFromCookie: Boolean = false, twoFactorListener: TwoFactorListener? = null, captchaListener: CaptchaListener? = null) {
        this.login = login
        this.password = password
        this.isSaveCookie = saveCookie
        this.isLoadFromCookie = loadFromCookie
        this.twoFactorListener = twoFactorListener
        this.captchaListener = captchaListener

        auth()
    }

    constructor()

    private fun auth(parameters: Map = HashMap()) {
        if (login == null || password == null) return

        if (isLoadFromCookie && cookiesFile.exists()) {
            val json = toJsonObject(cookiesFile.readText())
            val cookieList = json.getAsJsonArray("cookies").map {
                (it as JsonObject)
                Cookie(it.getString("domain"), it.getString("path"), it.getString("name"), it.getString("value"), it.getLong("expiry"), it.getBoolean("secure"), it.getBoolean("hostOnly"))
            }.toTypedArray()

            session = Session(cookieList.toMutableList())
            return
        }

        val data = session.get("https://vk.com/")
                .headers(USER_AGENT)
                .send().readToText()

        val form = Jsoup.parse(data).getElementById(FORM_ID) as FormElement

        setData(form, login!!, password!!)

        val formData = form.formData()

        val params = formData.map { it.key() to it.value() }.toMap() as HashMap

        params.putAll(parameters)

        var response = session.post(form.attr("action"))
                .headers(USER_AGENT)
                .body(params)
                .send().readToText()

        when {
            response.contains("act=authcheck") -> {
                log.info("Two Factor is required")

                response = session.get("https://vk.com/login?act=authcheck").send().readToText()
                passTwoFactor(response)
            }
            response.contains("onLoginCaptcha(") -> {
                log.info("Captcha code is required")

                val captchaSid = Utils.regexSearch(RE_CAPTCHAID, response)
                val captcha = Captcha(session, captchaSid!!)

                val code = captchaListener?.onCaptcha(captcha) ?: throw CaptchaException("Captcha listener is required")
                auth(mapOf(
                        "captcha_sid" to captchaSid,
                        "captcha_key" to code
                ))
            }
            response.contains("onLoginReCaptcha(") -> {
                log.info("Captcha code is required (recaptcha)")

                val captchaSid = System.currentTimeMillis().toString()
                val captcha = Captcha(session, captchaSid)

                val code = captchaListener?.onCaptcha(captcha) ?: throw CaptchaException("Captcha listener is required")
                auth(mapOf(
                        "captcha_sid" to captchaSid,
                        "captcha_key" to code
                ))
            }
            response.contains("onLoginFailed(4") -> throw NotValidAuthorization("Incorrect login or password")
        }

        if (isSaveCookie) {
            if (!cookiesFile.exists()) cookiesFile.createNewFile()

            cookiesMap["cookies"] = session.sessionCookies()
            cookiesFile.writeText(toJsonObject(cookiesMap).toString())
        }
    }

    private fun passTwoFactor(response: String): String {
        val pair = twoFactorListener?.twoFactor() ?: throw TwoFactorException("Two Factor listener is not initialized")

        val authHash = Utils.regexSearch(AUTH_HASH, response, 1)!!

        val values = HashMap()
        values["act"] = "a_authcheck_code"
        values["al"] = "1"
        values["code"] = pair.first
        values["remember"] = if (pair.second) 1 else 0
        values["hash"] = authHash

        val resp = session.post("https://vk.com/al_login.php")
                .headers(USER_AGENT)
                .body(values)
                .send().readToText()

        val data = toJsonObject(resp.replace("[-]".toRegex(), ""))
        val status = data.getAsJsonArray("payload").getInt(0)

        when {
            status == 4 -> {
                val path = data.getAsJsonArray("payload").getJsonArray(1).getString(0).replace("[\\\\\"]".toRegex(), "")
                return session.get("https://vk.com/$path").send().readToText()
            }
            listOf(0, 8).contains(status) -> return passTwoFactor(response)

            status == 2 -> throw TwoFactorException("ReCaptcha required")
        }

        throw TwoFactorException("Two factor authentication failed")
    }

    private fun setData(form: FormElement, login: String, password: String) {
        val loginField = form.select("[name=email]").first()
        val passwordField = form.select("[name=pass]").first()

        loginField.`val`(login)
        passwordField.`val`(password)

        form.submit()
                .userAgent(STRING_USER_AGENT)
                .execute()
    }

    fun interface TwoFactorListener {
        fun twoFactor(): Pair
    }

    fun interface CaptchaListener {
        fun onCaptcha(captcha: Captcha): String
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy