torn-crack

Simple Cracking Helper

目前為 2025-08-05 提交的版本,檢視 最新版本

// ==UserScript==
// @name         torn-crack
// @namespace    torn-crack
// @version      0.0.3
// @description  Simple Cracking Helper
// @author       SirAua [3785905]
// @match        *://www.torn.com/page.php?sid=crimes*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @license      mit
// ==/UserScript==

(function () {
    'use strict';

    if (window.CRACK_INJECTED) {
        return;
    }
    window.CRACK_INJECTED = true;

    let debug = false;
    function crackLog(...args) {
        if (!debug) return;
        args.forEach((arg) => {
            console.log('[Crack] ' + arg)
        })
    }

    crackLog('Userscript starts');

    const isPda = window.GM_info?.scriptHandler?.toLowerCase().includes('tornpda');
    const UPDATE_INTERVAL = 800; // ms
    const MAX_SUG = isPda ? 8 : 15;

    let dict = null;
    let dictLoaded = false;

    const wordlistUrl = 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Common-Credentials/xato-net-10-million-passwords-1000000.txt';
    async function loadDict() {
        return new Promise((resolve, reject) => {
            if (dictLoaded) resolve();
            crackLog('Loading wordlist...');
            GM_xmlhttpRequest({
                method: 'get',
                url: wordlistUrl,
                timeout: 30000,
                ontimeout: (error) => {
                    crackLog('GET: Timeout', error);
                    reject(error);
                },
                onerror: (error) => {
                    crackLog('GET Error:', error);
                    reject(error);
                },
                onload: (res) => {
                    const txt = res.responseText;
                    dict = txt.trim()
                        .split(/\r?\n/)
                        .map(w => w.trim().toUpperCase());
                    dictLoaded = true;
                    crackLog('Loaded', dict.length, 'words');
                    resolve();
                },
            });
        });
    }

    function patToReg(pat) {
        const standard = pat.toUpperCase().replace(/[*]/g, '.').trim();
        return new RegExp('^' + standard + '$');
    }

    function suggest(pat) {
        if (!dict) return [];
        const regex = patToReg(pat);
        const len = pat.length;
        let out = [];
        for (const word of dict) {
            if (word.length !== len) continue;
            if (!regex.test(word)) continue;
            out.push(word);
            if (out.length >= MAX_SUG) break;
        }
        return out;
    }

    function prependPanelToRow(row, pat) {
        const existing = row.querySelector('.__crackhelp_panel');
        if (existing) existing.remove();

        const panel = document.createElement('div');
        panel.className = '__crackhelp_panel';
        panel.style.cssText = `
      background: #000000ff;
      font-size: 10px;
      text-align: center;
      position: absolute;
      z-index: 9999;
    `;

        const listDiv = document.createElement('div');
        listDiv.style.cssText = 'margin-top: 2px;';
        panel.appendChild(listDiv);

        row.prepend(panel);

        async function updateSuggestions() {
            const sugs = suggest(pat);
            listDiv.innerHTML = '';
            sugs.forEach(word => {
                const sp = document.createElement('span');
                sp.style.cssText = 'padding:2px; color: #00ff00ff;';
                sp.textContent = word;
                listDiv.appendChild(sp);
            });
            if (sugs.length === 0) {
                const none = document.createElement('span');
                none.textContent = '(no matches)';
                none.style.color = '#a00';
                listDiv.appendChild(none);
            }
        }

        loadDict().then(updateSuggestions);
    }

    function scanOnce() {
        if (!location.href.endsWith('cracking')) return;

        const currentCrime = document.querySelector('[class^="currentCrime"]');
        if (!currentCrime) return;

        const container = currentCrime.querySelector('[class^="virtualList"]');
        if (!container) return;

        for (const crimeOption of container.getElementsByClassName('crimeOptionWrapper___IOnLO')) {
            let patText = '';
            for (const charSlot of crimeOption.getElementsByClassName('charSlot___b_S9h')) {
                if (!charSlot) return null;
                let char = charSlot.textContent.trim();
                if (char) {
                    patText += char.toUpperCase();
                } else {
                    patText += '*';
                }

            }
            let noChars = /^[*]+$/.test(patText);
            if (!noChars) prependPanelToRow(crimeOption, patText);
        }
    }

    const waitForElement = (selector, callback) => {
        const interval = setInterval(() => {
            const el = document.querySelector(selector);
            if (el) {
                clearInterval(interval);
                callback(el);
            }
        }, 300);
    };

    waitForElement('.appHeader___gUnYC.crimes-app-header', (element) => {
        const sp = document.createElement('span');
        sp.style.cssText = `
      background: #000000ff;
      color: #00ff00ff;
      font-size: 10px;
      text-align: left;
      z-index: 9999;
    `;
        sp.textContent = 'Bruteforce characters to show suggestions!';
        element.append(sp);
    });

    // Initial and periodic scan
    scanOnce();
    setInterval(scanOnce, UPDATE_INTERVAL);

})();