RR Tracker Premium (Loader)

Premium RR Tracker Auth (PDA Hard Reload Fix)

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         RR Tracker Premium (Loader)
// @namespace    https://greasyfork.org/users/1493252
// @version      1.8
// @description  Premium RR Tracker Auth (PDA Hard Reload Fix)
// @match        https://www.torn.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM.xmlHttpRequest
// @grant        GM_setValue
// @grant        GM.setValue
// @grant        GM_getValue
// @grant        GM.getValue
// @connect      api.torn.com
// @connect      script.google.com
// @connect      script.googleusercontent.com
// @connect      workers.dev
// ==/UserScript==

(async function() {
    'use strict';

    // 🛑 CLOUDFLARE URL 🛑
    const WORKER_URL = "https://rr-tracker-auth.othmanmohamadre.workers.dev";

    // 1. PDA-Safe Helper to get the active Torn Player ID
    function getActiveTornId() {
        let match = document.cookie.match(/(?:^|; )uid=([^;]*)/);
        if (match && match[1]) return match[1];
        if (typeof window.uid !== 'undefined') return String(window.uid);
        return null;
    }

    // ---------------------------------------------------------
    // 2. OMNI-STORAGE HELPERS (Bulletproof Saving for PDA)
    // ---------------------------------------------------------
    async function getSavedCreds() {
        let u = "", k = "";
        try { if (typeof GM !== 'undefined' && GM.getValue) { u = await GM.getValue("rr_prem_uid", ""); k = await GM.getValue("rr_prem_key", ""); } } catch(e) {}
        try { if (!u && typeof GM_getValue === 'function') { u = GM_getValue("rr_prem_uid", ""); k = GM_getValue("rr_prem_key", ""); } } catch(e) {}
        try { if (!u) { u = localStorage.getItem("rr_prem_uid") || sessionStorage.getItem("rr_prem_uid") || ""; k = localStorage.getItem("rr_prem_key") || sessionStorage.getItem("rr_prem_key") || ""; } } catch(e) {}
        return { uid: u, key: k };
    }

    async function saveCreds(u, k, remember) {
        if (remember) {
            try { if (typeof GM !== 'undefined' && GM.setValue) { await GM.setValue("rr_prem_uid", u); await GM.setValue("rr_prem_key", k); } } catch(e) {}
            try { if (typeof GM_setValue === 'function') { GM_setValue("rr_prem_uid", u); GM_setValue("rr_prem_key", k); } } catch(e) {}
            try { localStorage.setItem("rr_prem_uid", u); localStorage.setItem("rr_prem_key", k); } catch(e) {}
        } else {
            try { sessionStorage.setItem("rr_prem_uid", u); sessionStorage.setItem("rr_prem_key", k); } catch(e) {}
        }
    }

    async function clearCreds() {
        try { if (typeof GM !== 'undefined' && GM.setValue) { await GM.setValue("rr_prem_uid", ""); await GM.setValue("rr_prem_key", ""); } } catch(e) {}
        try { if (typeof GM_setValue === 'function') { GM_setValue("rr_prem_uid", ""); GM_setValue("rr_prem_key", ""); } } catch(e) {}
        try { localStorage.removeItem("rr_prem_uid"); localStorage.removeItem("rr_prem_key"); } catch(e) {}
        try { sessionStorage.removeItem("rr_prem_uid"); sessionStorage.removeItem("rr_prem_key"); } catch(e) {}
    }

    // ---------------------------------------------------------

    const creds = await getSavedCreds();
    let savedUid = creds.uid;
    let savedKey = creds.key;

    // 3. THE LOGIN PANEL UI
    function showLoginPanel() {
        if (!document.body) {
            setTimeout(showLoginPanel, 50);
            return;
        }

        const panel = document.createElement('div');
        Object.assign(panel.style, {
            position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
            background: 'linear-gradient(135deg, #1e1e1e 0%, #000000 100%)',
            border: '2px solid #64B4FF', borderRadius: '10px', padding: '25px',
            color: 'white', zIndex: '999999', fontFamily: 'monospace', width: '300px',
            boxShadow: '0px 10px 30px rgba(0,0,0,0.9)', textAlign: 'center'
        });

        panel.innerHTML = `
            <h2 style="color: #64B4FF; margin-top: 0; border-bottom: 1px solid #444; padding-bottom: 10px;">RR Tracker Premium</h2>
            <div style="text-align: left; margin-bottom: 10px;">
                <label>Torn ID:</label><br>
                <input id="rr-auth-uid" type="number" style="width: 100%; padding: 8px; margin-top: 5px; background: #222; color: #fff; border: 1px solid #555; border-radius: 4px; box-sizing: border-box;" placeholder="e.g. 1234567">
            </div>
            <div style="text-align: left; margin-bottom: 15px;">
                <label>License Key:</label><br>
                <input id="rr-auth-key" type="password" style="width: 100%; padding: 8px; margin-top: 5px; background: #222; color: #fff; border: 1px solid #555; border-radius: 4px; box-sizing: border-box;" placeholder="Paste Key Here">
            </div>
            <div style="text-align: left; margin-bottom: 20px;">
                <input type="checkbox" id="rr-auth-remember" checked>
                <label for="rr-auth-remember">Keep me logged in</label>
            </div>
            <button id="rr-auth-btn" style="width: 100%; padding: 12px; background: #2196F3; color: white; font-weight: bold; border: none; border-radius: 4px; cursor: pointer;">Login & Load Script</button>
            <div id="rr-auth-status" style="margin-top: 10px; color: #ff7a7a; font-size: 12px; height: 15px;"></div>
        `;

        document.body.appendChild(panel);

        document.getElementById('rr-auth-btn').onclick = async (e) => {
            e.preventDefault(); // Prevents double-taps on mobile
            const uid = document.getElementById('rr-auth-uid').value.trim();
            const key = document.getElementById('rr-auth-key').value.trim();
            const remember = document.getElementById('rr-auth-remember').checked;
            const status = document.getElementById('rr-auth-status');

            if (!uid || !key) {
                status.innerText = "Please fill in all fields.";
                return;
            }

            const currentActiveId = getActiveTornId();
            if (currentActiveId && currentActiveId !== uid) {
                status.innerText = "Error: This ID does not match your active Torn account!";
                return;
            }

            // Visual feedback that the button worked
            status.style.color = "#64B4FF";
            status.innerText = "Saving credentials...";

            await saveCreds(uid, key, remember);
            
            status.style.color = "#4CAF50";
            status.innerText = "Success! Reloading page...";

            // Hard Reload (Bypasses PDA's reload block)
            setTimeout(() => {
                window.location.href = "https://www.torn.com/page.php?sid=russianRoulette&refresh=" + Date.now();
            }, 500);
        };
    }

    // 4. Initial Gatekeeper Check
    if (!savedUid || !savedKey) {
        if (window.location.href.includes('sid=russianRoulette')) {
            showLoginPanel();
        }
        return; 
    }

    // 5. Active User ID Mismatch Check
    const activeId = getActiveTornId();
    if (activeId && activeId !== savedUid) {
        alert("RR Tracker Premium: Account mismatch detected! Logging out.");
        await clearCreds();
        window.location.href = "https://www.torn.com/page.php?sid=russianRoulette&refresh=" + Date.now();
        return;
    }

    // 6. Network Fetcher Detection
    let fetchFunc = null;
    if (typeof GM_xmlhttpRequest !== 'undefined') {
        fetchFunc = GM_xmlhttpRequest;
    } else if (typeof GM !== 'undefined' && typeof GM.xmlHttpRequest !== 'undefined') {
        fetchFunc = GM.xmlHttpRequest;
    }

    if (!fetchFunc) {
        if (window.location.href.includes('sid=russianRoulette')) {
            alert("RR Tracker: Your script manager does not support network requests. Please ensure GM_xmlhttpRequest is enabled.");
        }
        return;
    }

    // 7. Fetch the Obfuscated Payload from Cloudflare
    fetchFunc({
        method: "GET",
        url: `${WORKER_URL}?uid=${savedUid}&key=${savedKey}`,
        onload: function(response) {
            if (response.status === 200) {
                try {
                    const safeEvalCode = `
                        var GM = typeof GM !== 'undefined' ? GM : {};
                        if (!GM.xmlHttpRequest && typeof GM_xmlhttpRequest !== 'undefined') GM.xmlHttpRequest = GM_xmlhttpRequest;
                        if (!GM.setValue && typeof GM_setValue !== 'undefined') GM.setValue = GM_setValue;
                        if (!GM.getValue && typeof GM_getValue !== 'undefined') GM.getValue = GM_getValue;
                        
                        ${response.responseText}
                    `;
                    eval(safeEvalCode);
                    console.log("RR Tracker Premium: Vault Unlocked and Running.");

                    // 8. THE 5-MINUTE SECURITY CHECK LOOP
                    setInterval(async () => {
                        const currentId = getActiveTornId();
                        if (currentId && currentId !== savedUid) {
                            alert("RR Tracker Security: Active Torn ID has changed! Session terminated.");
                            await clearCreds();
                            window.location.href = "https://www.torn.com/page.php?sid=russianRoulette&refresh=" + Date.now();
                        }
                    }, 5 * 60 * 1000); 

                } catch (e) {
                    console.error("RR Tracker Execution Error:", e);
                }
            } else {
                if (window.location.href.includes('sid=russianRoulette')) {
                    alert("RR Tracker Authentication Failed: " + response.responseText);
                    clearCreds().then(() => showLoginPanel());
                } else {
                    clearCreds();
                }
            }
        }
    });
})();