datnvt2712 / RecaptchaParser_1.1

// ==UserScript==
// @name         RecaptchaParser 1.1
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Auto worker bypass recaptcha
// @author       datnvt
// @match        *://*/*
// @grant        none
// @require http://code.jquery.com/jquery-latest.js
// @copyright 2020, datnvt2712 (https://openuserjs.org/users/datnvt2712)
// @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.rdTime = function (min, max) {
          return Math.floor(Math.random() * (max - min + 1) ) + min;
      } 

      self.timeClick = function(row, col, timing) {
          setTimeout(function() {
            self.boxElements[row][col].click();
            console.log(self.ID + " | Click row " + row + " col " + col);
          }, timing);
      }

      self.requestServer = async function (k){
          $.ajax({
              url: URL_BYPASS_RECAPTCHA,
              type: "POST",
              data: self.requestsData[k],
              success: function(result) {
                  console.log(result);
                  var extend = 0;
                  if (result.success) {
                      for (var i = 0; i < result.result.click_boxes.length; i++) {
                          extend += self.rdTime(100, 1000);
                          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.timeClick(row, col, (i+1)*750 +extend);
                          }
                          else if (row === 0 && col === 0) { // Small box and right choose
                            row = self.requestsData[k].row_offset;
                            col = self.requestsData[k].col_offset;
                            self.timeClick(row, col, (i+1)*750 + extend);
                          }
                      }
                  }
                  setTimeout(function() {
                    self.requestsData[k].process = true;
                  }, result.result.click_boxes.length*750 + 100 + extend);
              },
              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();