SkillRack Math Captcha Solver

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

目前為 2024-10-15 提交的版本,檢視 最新版本

// ==UserScript==
// @name         SkillRack Math Captcha Solver
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Solves Math Captcha on the SkillRack website using Tesseract.js.
// @author       Bit-Blazer
// @license      GNU GPLv3 
// @match        https://www.skillrack.com/faces/candidate/codeprogramgroup.xhtml
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @require      https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js
// @grant        none
// ==/UserScript==

(function () {
    "use strict";

    // Element IDs
    const CAPTCHA_IMAGE = "j_id_78";
    const USERNAME = "113222031061@vec";
    const CAPTCHA_INPUT = "capval";
    const PROCEED_BTN = "proceedbtn";

    /**
     * Inverts the colors of Captcha Image for better OCR results.
     * @param {HTMLImageElement} image - The image to be inverted.
     * @returns {string} - Base64 encoded data URL of the inverted image.
     */
    function invertColors(image) {
        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";
        ctx.fillStyle = "white";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        return canvas.toDataURL();
    }

    /**
     * Solves the captcha by extracting numbers and performing the calculation.
     * @param {string} text - The OCR result from the captcha image.
     * @returns {number|null} - The result of the addition or null if not found.
     */
    function solveCaptcha(text) {
        const cleanedText = text.replace(new RegExp(USERNAME, "gi"), "").trim();
        const match = cleanedText.match(/(\d+)\s*\+\s*(\d+)/);
        if (match) {
            // Return the sum of the two numbers
            return parseInt(match[1], 10) + parseInt(match[2], 10);
        }
        return null; // Return null if no valid match is found
    }

    /**
     * Handles the captcha-solving process.
     */
    async function handleCaptcha() {
        // Get the captcha elements
        const captchaImage = document.getElementById(CAPTCHA_IMAGE);
        const captchaInput = document.getElementById(CAPTCHA_INPUT);
        const proceedBtn = document.getElementById(PROCEED_BTN);

        // Log an error if elements are not found
        if (!captchaImage || !captchaInput || !proceedBtn) {
            console.log("Captcha or input elements not found.");
            return;
        }

        // Invert the colors of the captcha image for better OCR
        const invertedImg = invertColors(captchaImage);

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

            // Solve the Captcha
            const result = solveCaptcha(text);
            if (result === null) {
                alert("Unable to solve Captcha...");
                return;
            }
            // Fill the captcha input with the calculated result
            captchaInput.value = result;
            // Click the submit button
            proceedBtn.click();
        } catch (error) {
            // Log any errors encountered during the OCR process
            console.error("Error processing captcha:", error);
        }
    }

    // Wait for the window to fully load before handling the captcha
    window.addEventListener("load", handleCaptcha);
})();