dambaquyen96 / RecaptchaParser

// ==UserScript==
// @name         RecaptchaParser
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Auto worker bypass recaptcha
// @author       dambaquyen96
// @match        *://*/*
// @grant        none
// @require http://code.jquery.com/jquery-latest.js
// @copyright 2020, dambaquyen96 (https://openuserjs.org/users/dambaquyen96)
// @license MIT
// ==/UserScript==

/* Utils */
function uuidv4() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

function getCurrentURL() {
    return window.location.href;
}

function checkClassExists(class_name) {
    var keyword = "div." + class_name;
    // 'div.recaptcha-checkbox-checkmark'
    var status = $(keyword).length;
    return status > 0;
}
/* End Utils */

const STATE_INIT = 0;
const STATE_CHECKBOX_WAIT = 1;
const STATE_CHECKBOX_CLICK = 2;;
const STATE_READY = 3;
const STATE_PARSER = 4;
const STATE_PREPARE = 5;
const STATE_REQUEST = 6;
const STATE_WAIT_FOR_CHANGE = 7;
const STATE_TAB_DONE = 8;
const STATE_TAB_CHECK = 9;
const STATE_TAB_WAIT = 10;
const STATE_SUCCESS = 11;

//const URL_BYPASS_RECAPTCHA = "http://localhost:8080/predict/recaptcha";
const URL_BYPASS_RECAPTCHA = "https://aisol.vn/recaptcha/predict"
const URL_CHECKBOX = "www.google.com/recaptcha/api2/anchor";
const URL_RECAPTCHA = "www.google.com/recaptcha/api2/bframe";

const CHECKBOX_CLASSNAME = 'recaptcha-checkbox-checkmark';
const LABEL_DYNAMIC_CLASSNAME = 'rc-imageselect-desc-no-canonical';
const LABEL_STATIC_CLASSNAME = 'rc-imageselect-desc';
const BUTTON_VERIFY_ID = 'recaptcha-verify-button';
const BUTTON_RELOAD_ID = 'recaptcha-reload-button';
const LABELS_ERROR_CLASSNAME = ['rc-imageselect-incorrect-response', 'rc-imageselect-error-select-more', 'rc-imageselect-error-dynamic-more', 'rc-imageselect-error-select-something'];
const G_RESPONSE_ID = 'g-recaptcha-response'

function RecaptchaParser(){
    var self = this;

    self.ID = uuidv4();
    self.current_url = getCurrentURL();
    self.state = STATE_INIT;

    self.showInfo = function() {
        console.log(self.ID + " | " + self.current_url);
    }

    self.run = function() {
        var pid = setInterval(function(){
            if (self.current_url.includes(URL_CHECKBOX)) { // Url for tick checkbox
                if (self.state == STATE_INIT) {
                    self.clickCheckBox();
                    self.state = STATE_CHECKBOX_WAIT;
                } else if (self.state == STATE_CHECKBOX_CLICK) {
                    console.log(self.ID + " | Clicked " + CHECKBOX_CLASSNAME);
                    clearInterval(pid);
                }
            } else if (self.current_url.includes(URL_RECAPTCHA)) { // Url for parse recaptcha
                console.log(self.ID + " | State: " + self.state);
                if (self.state == STATE_INIT) {
                    if (checkClassExists(LABEL_DYNAMIC_CLASSNAME) || checkClassExists(LABEL_STATIC_CLASSNAME)){
                        self.state = STATE_READY;
                    }
                } else if (self.state == STATE_READY) {
                    if (checkClassExists(LABEL_DYNAMIC_CLASSNAME)) {
                        console.log(self.ID + " | Captcha type: Dynamic");
                    } else {
                        console.log(self.ID + " | Captcha type: Static");
                    }
                    self.parseRecaptchaElement();
                    console.log(self.ID + " | Done to get Infomation");
                    console.log(self.ID + " | Rows: " + self.rows);
                    console.log(self.ID + " | Columns: " + self.cols);
                    console.log(self.ID + " | Image URL: " + self.image_url);
                    console.log(self.ID + " | Labels: " + self.label);
                    self.state = STATE_PARSER;
                } else if (self.state == STATE_PARSER) {
                    self.requestsData = [{
                        "image_url": self.image_url,
                        "object": self.label,
                        "rows": self.rows,
                        "cols": self.cols,
                        "row_offset" : 0,
                        "col_offset": 0,
                        "process": false,
                    }];
                    self.newRequestsData = [];
                    self.state = STATE_PREPARE;
                } else if (self.state == STATE_PREPARE) {
                    for (var k = 0; k < self.requestsData.length; k ++) {
                        self.requestServer(k)
                    }
                    self.state = STATE_REQUEST;
                } else if (self.state == STATE_REQUEST) {
                    var oke = true;
                    for (k = 0; k < self.requestsData.length; k ++) {
                        if (!self.requestsData[k].process) {
                            oke = false;
                            break;
                        }
                    }
                    if (oke) {
                        self.parseUpdateBox();
                        self.state = STATE_WAIT_FOR_CHANGE;
                    }
                } else if (self.state == STATE_WAIT_FOR_CHANGE) {

                } else if (self.state == STATE_TAB_DONE) {
                    $("#" + BUTTON_VERIFY_ID).click();
                    self.state = STATE_TAB_CHECK;
                } else if (self.state == STATE_TAB_CHECK) {
                    var resTab = self.checkTabSuccess();
                    if (resTab) {
                        console.log("Success");
                        self.startNewTab(resTab);
                        self.state = STATE_TAB_WAIT;
                    } else {
                        console.log("Fail - Reload recaptcha");
                        $("#" + BUTTON_RELOAD_ID).click();
                        self.startNewTab(resTab);
                        self.state = STATE_TAB_WAIT;
                    }
                } else if (self.state == STATE_SUCCESS) {
                    clearInterval(pid);
                }
            } else { // Url for check response code
                if (self.state == STATE_INIT) {
                    var response_code = $("#" + G_RESPONSE_ID).val();
                    if (response_code !== undefined && response_code !== "") {
                        console.log(self.ID + " | Response code: " + response_code);
                        self.state = STATE_SUCCESS;
                    }
                } else if (self.state == STATE_SUCCESS) {
                    $("#recaptcha-demo-submit").click();
                    clearInterval(pid);
                }
            }
        }, 50);
    }

    self.clickCheckBox = function () {
        setTimeout(function() {
            var pid = setInterval(function(){
                if (checkClassExists(CHECKBOX_CLASSNAME)) {
                    document.documentElement.getElementsByClassName(CHECKBOX_CLASSNAME)[0].click();
                    self.state = STATE_CHECKBOX_CLICK;
                    clearInterval(pid);
                }
            }, 50);
        }, 1000);
    }

    self.parseRecaptchaElement = function (){
        self.rows = $("tbody").children().length;
        self.cols = $("tr").children().length/self.rows;
        self.image_url = $(".rc-image-tile-target").find("img").attr('src');
        self.label = $(".rc-imageselect-instructions div div strong").html();
        self.boxElements = new Array(self.rows);
        self.rememberImageUrl = new Array(self.rows);
        for (var i = 0; i < self.boxElements.length; i++) {
            self.boxElements[i] = new Array(self.cols);
            self.rememberImageUrl[i] = new Array(self.cols);
            for (var j = 0; j < self.boxElements[i].length; j++) {
                self.boxElements[i][j] = $("tr").eq(i).children("td").eq(j);
                self.rememberImageUrl[i][j] = $("tr").eq(i).children("td").eq(j).find("img").attr("src");
            }
        }
    }

    self.requestServer = async function (k){
        $.ajax({
            url: URL_BYPASS_RECAPTCHA,
            type: "POST",
            data: self.requestsData[k],
            success: function(result) {
                console.log(result);
                if (result.success) {
                    for (var i = 0; i < result.result.click_boxes.length; i++) {
                        var row = parseInt(result.result.click_boxes[i].row);
                        var col = parseInt(result.result.click_boxes[i].col);
                        if (self.requestsData[k].rows > 1 && self.requestsData[k].cols > 1) { // Big box
                            self.boxElements[row][col].click();
                            console.log(self.ID + " | Click row " + row + " col " + col);
                        } else if (row === 0 && col === 0) { // Small box and right choose
                            row = self.requestsData[k].row_offset;
                            col = self.requestsData[k].col_offset;
                            self.boxElements[row][col].click();
                            console.log(self.ID + " | Click row " + row + " col " + col);
                        }
                    }
                }
                self.requestsData[k].process = true;
            },
            error: function(error) {
                console.log(`ERROR ${error}`);
                self.requestsData[k].process = true;
            }
        });
    }

    self.parseUpdateBox = function () {
        setTimeout(function() {
            for (var i = 0; i < self.rows; i++) {
                for (var j = 0; j < self.cols; j++) {
                    var box_image_url = $("tr").eq(i).children("td").eq(j).find("img").attr("src");
                    if (box_image_url !== self.rememberImageUrl[i][j]) {
                        self.rememberImageUrl[i][j] = box_image_url;
                        self.newRequestsData.push({
                            "image_url": box_image_url,
                            "object": self.label,
                            "rows": 1,
                            "cols": 1,
                            "row_offset" : i,
                            "col_offset": j,
                            "process": false,
                        });
                        console.log(self.ID + " | Find new image at [" + i + ":" + j + "]: " + box_image_url);
                    }
                }
            }
            self.requestsData = self.newRequestsData.slice();
            self.newRequestsData = [];
            if (self.requestsData.length == 0) self.state = STATE_TAB_DONE;
            else self.state = STATE_PREPARE;
        }, 5000);
    }

    self.checkTabSuccess = function (){
        for (var i = 0; i < LABELS_ERROR_CLASSNAME.length; i++) {
            var ele = $("." + LABELS_ERROR_CLASSNAME[i]).first();
            if (ele.is(":visible")) return false;
        }
        return true;
    }

    self.startNewTab = function () {
        setTimeout(function() {
            if ($("#" + BUTTON_VERIFY_ID).prop('disabled')) self.state = STATE_SUCCESS;
            else self.state = STATE_READY;
        }, 1000);
    }
}

var recaptchaParser = new RecaptchaParser();
recaptchaParser.showInfo();
recaptchaParser.run();