SkillRack Math Captcha Solver

Solves Math Captcha on the SkillRack website using Tesseract.js.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         SkillRack Math Captcha Solver
// @namespace    http://tampermonkey.net/
// @version      0.6
// @description  Solves Math Captcha on the SkillRack website using Tesseract.js.
// @author       Bit-Blazer
// @license      GNU GPLv3
// @match        https://www.skillrack.com/faces/candidate/codeprogram.xhtml
// @match        https://www.skillrack.com/faces/candidate/tutorprogram.xhtml
// @icon         https://envs.sh/GiG.png
// @require      https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js
// @grant        none
// ==/UserScript==

(function () {
  "use strict";

  // Define the IDs of the captcha input field, and proceed button
  const CAPTCHA_INPUT = "capval";
  const PROCEED_BTN = "proceedbtn";

  console.log("[Captcha Solver] Script initialized.");

  /**
   * Inverts the colors of the Captcha Image for better OCR results.
   * This is useful for enhancing the text recognition capability of Tesseract.js.
   * @param {HTMLImageElement} image - The image to be inverted.
   * @returns {string} - Base64 encoded data URL of the inverted image.
   */
  function invertColors(image) {
    try {
      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");
      canvas.width = image.width;
      canvas.height = image.height;
      ctx.drawImage(image, 0, 0);
      ctx.globalCompositeOperation = "difference"; // Invert colors
      ctx.fillStyle = "white"; // Set background to white
      ctx.fillRect(0, 0, canvas.width, canvas.height); // Fill the canvas
      console.log("[Captcha Solver] Image colors inverted successfully.");
      return canvas.toDataURL(); // Return the inverted image as a data URL
    } catch (error) {
      console.error("[Captcha Solver] Error inverting colors:", error);
      throw new Error("Image processing failed.");
    }
  }

  /**
   * Extracts the username from the span element.
   * This function looks for the username pattern in the badge label.
   * @returns {string} - The extracted username or an empty string if not found.
   */
  function getUsername() {
    const usernameElement = document.querySelector(".ui-chip-text"); // Select the username element
    const match = usernameElement.textContent.match(/(\d{12}@\w{3})/); // Match the username pattern
    const username = match ? match[0] : ""; // Return the matched username or empty string
    console.log("[Captcha Solver] Extracted username:", username);
    return username;
  }

  /**
   * Solves the captcha by extracting numbers and performing the calculation.
   * @param {string} text - The OCR result from the captcha image.
   * @param {string} username - The username to be removed from the OCR text.
   * @returns {number|null} - The result of the addition or null if not found.
   */
  function solveCaptcha(text, username) {
    try {
      // Remove the username from the OCR text and trim whitespace
      const cleanedText = text.replace(new RegExp(username, "gi"), "").trim();
      // Match the addition pattern in the cleaned text
      const match = cleanedText.match(/(\d+)\s*\+\s*(\d+)/);
      // Return the sum of the two numbers if a match is found

      if (!match) {
        console.warn(
          "[Captcha Solver] No valid captcha pattern found in OCR text:",
          text
        );
        return null;
      }
      const result = parseInt(match[1], 10) + parseInt(match[2], 10);
      console.log(
        "[Captcha Solver] Captcha solved:",
        `${match[1]} + ${match[2]} = ${result}`
      );
      return result;
    } catch (error) {
      console.error("[Captcha Solver] Error solving captcha:", error);
      return null;
    }
  }

  /**
   * Handles the captcha-solving process.
   * This function orchestrates the overall captcha solving by coordinating image processing and user interactions.
   */
  async function handleCaptcha() {
    // Get the captcha elements from the DOM
    console.log("[Captcha Solver] Handling captcha...");

    try {
      const captchaImage = document.querySelector("img[src*='data:image']");
      const captchaInput = document.getElementById(CAPTCHA_INPUT);
      const proceedBtn = document.getElementById(PROCEED_BTN);

      // Log an error and exit if any elements are not found
      if (!captchaImage) throw new Error("Captcha image not found.");
      if (!captchaInput) throw new Error("Captcha input field not found.");
      if (!proceedBtn) throw new Error("Proceed button not found.");

      // Get the username from the UI
      const username = getUsername();
      // Invert the colors of the captcha image for better OCR processing
      const invertedImg = invertColors(captchaImage);

      // Process the inverted image using Tesseract.js for OCR
      const {
        data: { text },
      } = await Tesseract.recognize(invertedImg, "eng", {
        whitelist:
          "1234567890+=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@ ", // Allowed characters
        psm: 6, // Page segmentation mode
      });

      console.log("[Captcha Solver] OCR text extracted:", text);

      // Solve the Captcha using the OCR text and username
      const result = solveCaptcha(text, username);
      // Notify if the captcha could not be solved
      if (result === null) {
        console.warn("[Captcha Solver] Unable to solve captcha.");
        return;
      }

      // Fill the captcha input with the calculated result
      captchaInput.value = result;
      // Click the submit button to proceed

      console.log("[Captcha Solver] Filled captcha input with result:", result);

      proceedBtn.click();
      console.log("[Captcha Solver] Proceed button clicked.");
    } catch (error) {
      // Log any errors encountered during the OCR process

      console.error("[Captcha Solver] Error handling captcha:", error);
    }
  }

  /**
   * Checks if the required elements are available and triggers captcha solving.
   */
  function monitorElements() {
    console.log("Finding Elements....");
    const interval = setInterval(() => {
      const captchaImage = document.querySelector("img[src*='data:image']");
      const captchaInput = document.getElementById(CAPTCHA_INPUT);
      const proceedBtn = document.getElementById(PROCEED_BTN);

      if (captchaImage && captchaInput && proceedBtn) {
        console.log(
          "[Captcha Solver] Required elements found. Starting captcha solver."
        );
        clearInterval(interval);
        handleCaptcha();
      }
    }, 500); // Check every 500ms
  }

  monitorElements(); // Start looking for elements here
})();