Solves Math Captcha on the SkillRack website using Tesseract.js.
// ==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
})();