torn-crack

Simple Cracking Helper

Fra 06.08.2025. Se den seneste versjonen.

// ==UserScript==
// @name         torn-crack
// @namespace    torn-crack
// @version      0.0.4.5
// @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 ? 7 : 15;

    let dict = [];
    let dictLoaded = false;

    const wordlistUrl = 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Common-Credentials/xato-net-10-million-passwords-1000000.txt';
    //const wordlistUrl = 'https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Common-Credentials/xato-net-10-million-passwords.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;
                    const words = txt.trim()
                    .split(/\r?\n/)
                    .map(w => w.trim().toUpperCase())
                    .filter(w => /^[A-Z0-9_.]+$/.test(w));
                    for (const word of words) {
                        const len = word.length;
                        if (!dict[len]) {
                            dict[len] = [];
                        }
                        dict[len].push(word);
                    }
                    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) {
        const len = pat.length;
        let out = [];
        if (!dict[len]) return out;
        const regex = patToReg(pat);
        for (const word of dict[len]) {
            if (!regex.test(word)) continue;
            out.push(word);
            if (out.length >= MAX_SUG) break;
        }
        return [...new Set(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 scanCrimePage() {
        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);
        }
    }

    setInterval(() => {
        const el = document.getElementById('crackInfo');
        if (el) el.remove();

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

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

        const sp = document.createElement('span');
        sp.id = 'crackInfo';
        sp.style.cssText = `
      background: #000000ff;
      color: #00ff00ff;
      font-size: 10px;
      text-align: left;
      z-index: 9999;
    `;
        sp.textContent = 'Bruteforce characters to show suggestions!';
        appHeader.append(sp);
    }, UPDATE_INTERVAL);


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

})();