Clawptcha bypasser

Bypass Clawptcha - a captcha that verifies you're not a human

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name               Clawptcha bypasser
// @name:zh-CN         Clawptcha 验证绕过
// @name:zh-TW         Clawptcha 驗證繞過
// @namespace          https://greasyfork.org/users/667968-pyudng
// @version            1.1
// @description        Bypass Clawptcha - a captcha that verifies you're not a human
// @description:zh-CN  绕过 Clawptcha - 一种验证您不是人类的验证码
// @description:zh-TW  繞過 Clawptcha - 一種驗證您不是人類的驗證碼
// @author             PY-DNG
// @license            MIT
// @homepageURL        https://greasyfork.org/scripts/565015
// @supportURL         https://greasyfork.org/scripts/565015/feedback
// @match              https://clawptcha.com/*
// @require            https://update.greasyfork.org/scripts/456034/1651347/Basic%20Functions%20%28For%20userscripts%29.js
// @require            https://cdn.jsdelivr.net/npm/[email protected]/src/sha256.min.js
// @icon               https://clawptcha.com/favicon.svg
// @grant              none
// ==/UserScript==

!async function() {
    detectDom({
        selector: '#challenge-popup > #challenge-content, .clawptcha-challenge-popup .clawptcha-challenge-content',
        /**
         * @param {HTMLDivElement} container 
         */
        callback(container) {
            // 验证类型:Hash Computation
            detectDom({
                root: container,
                selector: '#hash-submit',
                /**
                 * @param {HTMLButtonElement} btnSubmit 提交答案的按钮
                 */
                async callback(btnSubmit) {
                    // 当存在"Generate"按钮时自动点击
                    $(container, '#hash-start')?.click();

                    /** @type {HTMLDivElement} 包含了需计算Hash的原始文本的div */
                    const divHash = await detectDom(container, '.hash-display, .clawptcha-hash-display');
                    await detectElement(divHash, divHash => divHash.innerText.includes('Hash this:') || divHash.innerText.includes('Hash:'), { childList: true });
                    /** @type {HTMLDivElement} */
                    const text = divHash.innerText.replace('Hash this:', '').replace('Hash:', '').trim();
                    /** @type {string} */
                    const hash = sha256(text).substring(0, 16);
                    $(container, '#hash-answer').value = hash;
                    btnSubmit.click();
                }
            });

            // 验证类型:Reaction Time
            detectDom({
                root: container,
                selector: '#reaction-target, #reaction-start',
                /**
                 * @param {HTMLButtonElement} button 需尽快点击的按钮
                 */
                callback(button) {
                    button.click();
                }
            });

            // 验证类型:Precision Timing
            // 注:这种类型验证可能失败 —— 因为即使是bot,也难以在±1ms的精度上完成点击
            // **这是设计的不合理而不是我们的能力不达标**
            detectDom({
                root: container,
                selector: '#timing-start',
                /**
                 * @param {HTMLButtonElement} btnStart 开始按钮
                 */
                callback(btnStart) {
                    const btnTiming = $(container, '#timing-click');
                    btnStart.click();
                    setTimeout(() => btnTiming.click(), 5000);
                }
            });

            // 验证类型:Crypto Chain
            detectDom({
                root: container,
                selector: '#crypto-input',
                /**
                 * @param {HTMLDivElement} divHash 包含了需计算Hash的原始文本的div
                 */
                async callback(divHash) {
                    // 当存在"Start"按钮时自动点击
                    $(container, '#crypto-start')?.click();
                    await detectElement(divHash, divHash => divHash.innerText.includes('Hash:'), { childList: true });

                    // 连续完成3次哈希计算
                    let counter = 0;
                    const observer = new MutationObserver(submit);
                    observer.observe(divHash, {
                        childList: true,
                    });
                    submit();

                    function submit() {
                        if (++counter >= 3) observer.disconnect();

                        /** @type {HTMLDivElement} */
                        const text = divHash.innerText.replace('Hash:', '').trim();
                        /** @type {string} */
                        const hash = sha256(text);
                        $(container, '#crypto-answer').value = hash;
                        $(container, '#crypto-submit').click();
                    }
                }
            });

            // 验证类型:Prime Factorization
            detectDom({
                root: container,
                selector: '#prime-submit',
                /**
                 * @param {HTMLButtonElement} btnSubmit 提交答案的按钮
                 */
                async callback(btnSubmit) {
                    /** @type {HTMLDivElement} 包含了需分解质因数的数值的div */
                    const divHash = $(container, '.hash-display, .clawptcha-prime-display');

                    // 当从API加载验证码时,需要等待验证码加载完毕
                    if (!/\d+/.test(divHash.innerText)) {
                        const { promise, resolve } = Promise.withResolvers();
                        const observer = new MutationObserver(() => {
                            if (/\d+/.test(divHash.innerText)) {
                                resolve();
                                observer.disconnect();
                            }
                        });
                        observer.observe(divHash, { childList: true });
                        await promise;
                    }

                    // 分解质因数
                    /** @type {HTMLDivElement} */
                    const text = divHash.innerText.replace('Find the prime factors of', '').trim();
                    /** @type {number} 需分解质因数的数值 */
                    const number = parseInt(text, 10);
                    const { prime1, prime2 } = primeFactorization(number);

                    // 提交结果
                    $(container, '#prime-answer').value = `${prime1},${prime2}`;
                    btnSubmit.click();

                    /**
                     * 简单分解质因数
                     * @param {number} number 一个由两个质数相乘得到的合数
                     * @returns {{prime1: number, prime2: number}} 分解结果
                     */
                    function primeFactorization(number) {
                        for (let i = 2; i <= Math.sqrt(number); i++) {
                            if (number % i === 0) {
                                return { prime1: i, prime2: number / i };
                            }
                        }
                        return { prime1: 1, prime2: number };
                    }
                }
            });
        }
    });

    /**
     * 类似{@link detectDom},监听元素变化并在给定条件符合时resolve
     * @template {HTMLElement} T
     * @param {T} element 需要监听的HTML元素
     * @param {(element: T) => boolean} condition 判断元素当前是否符合条件的无副作用的方法
     * @param {MutationObserverInit} options
     * @returns {Promise<T>}
     */
    function detectElement(element, condition, options) {
        const { promise, resolve } = Promise.withResolvers();
        const verify = () => {
            if (condition(element)) {
                resolve(element);
                observer.disconnect();
            }
        };
        const observer = new MutationObserver(verify);
        observer.observe(element, options);
        verify();
        return promise;
    }
} ();