// ==UserScript==
// @name torn-crack
// @namespace torn-crack
// @version 0.0.8.1
// @description Simple Cracking Helper
// @author SirAua [3785905]
// @match *://www.torn.com/page.php?sid=crimes*
// @grant GM_xmlhttpRequest
// @license mit
// ==/UserScript==
// 🔴Clear the Wordlist Cache🔴
(function () {
'use strict';
if (window.CRACK_INJECTED) return;
window.CRACK_INJECTED = true;
const debug = true;
const UPDATE_INTERVAL = 800;
const MAX_SUG = 8;
const MIN_LENGTH = 4;
const MAX_LENGTH = 10;
const wordlistUrl = 'https://gitlab.com/kalilinux/packages/seclists/-/raw/kali/master/Passwords/Common-Credentials/Pwdb_top-1000000.txt?ref_type=heads';
const SUPABASE_GET_WORDS_URL = "https://mthndavliqfbtaplgfau.supabase.co/functions/v1/get-words";
const SUPABASE_ADD_WORD_URL = "https://mthndavliqfbtaplgfau.supabase.co/functions/v1/add-word";
const DB_NAME = 'crack';
const STORE_NAME = 'dictionary';
let dict = [];
let dictLoaded = false;
let dictLoading = false;
let supabaseWords = new Set();
let statusEl = null;
function crackLog(...args) {
if (debug) console.log('[Crack]', ...args);
}
function ensureStatusBadge() {
if (statusEl) return statusEl;
statusEl = document.createElement('div');
statusEl.id = '__crack_status';
statusEl.style.cssText = `
position: fixed; right: 10px; bottom: 10px; z-index: 10000;
background:#000; color:#0f0; border:1px solid #0f0; border-radius:6px;
padding:6px 8px; font-size:11px; font-family:monospace; opacity:0.9;
`;
statusEl.textContent = 'Dictionary: Idle';
document.body.appendChild(statusEl);
return statusEl;
}
function setStatus(msg) {
ensureStatusBadge().textContent = `Dictionary: ${msg}`;
crackLog('STATUS →', msg);
}
function openDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, 1);
request.onupgradeneeded = () => {
const db = request.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
db.createObjectStore(STORE_NAME);
}
};
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async function idbSet(key, value) {
const db = await openDB();
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE_NAME, 'readwrite');
tx.objectStore(STORE_NAME).put(value, key);
tx.oncomplete = resolve;
tx.onerror = () => reject(tx.error);
});
}
async function idbGet(key) {
const db = await openDB();
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE_NAME, 'readonly');
const req = tx.objectStore(STORE_NAME).get(key);
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
async function idbClear() {
const db = await openDB();
return new Promise((resolve, reject) => {
const tx = db.transaction(STORE_NAME, 'readwrite');
tx.objectStore(STORE_NAME).clear();
tx.oncomplete = resolve;
tx.onerror = () => reject(tx.error);
});
}
async function clearLocalDictCache() {
await idbClear();
crackLog('Cleared cached dictionary from IndexedDB');
setStatus('Cleared cache — reload');
}
function loadSupabaseWords() {
return new Promise((resolve) => {
if (!SUPABASE_GET_WORDS_URL) return resolve([]);
GM_xmlhttpRequest({
method: 'GET',
url: SUPABASE_GET_WORDS_URL,
timeout: 15000,
onload: (res) => {
try {
if (res.status === 200) {
const arr = JSON.parse(res.responseText);
const up = arr.map(w => (typeof w === 'string' ? w.toUpperCase() : '')).filter(Boolean);
supabaseWords = new Set(up);
crackLog(`Loaded ${supabaseWords.size} words from Supabase`);
resolve(up);
} else {
crackLog('Supabase get-words returned:', res.status);
resolve([]);
}
} catch (e) {
crackLog('Error parsing supabase words', e);
resolve([]);
}
},
onerror: () => {
crackLog('Error fetching supabase words');
resolve([]);
}
});
});
}
async function sendWordToSupabase(word) {
if (!SUPABASE_ADD_WORD_URL) {
crackLog('SUPABASE_ADD_WORD_URL not set. skipping send:', word);
return;
}
const payload = { word: word.toUpperCase() };
GM_xmlhttpRequest({
method: 'POST',
url: SUPABASE_ADD_WORD_URL,
headers: { 'Content-Type': 'application/json' },
data: JSON.stringify(payload),
onload: (res) => {
crackLog('sent to supabase', payload, 'status', res.status);
supabaseWords.add(payload.word);
},
onerror: (err) => {
crackLog('failed to send to supabase', err);
}
});
}
function fetchWordlistAndCache() {
setStatus('Downloading base wordlist…');
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'get',
url: wordlistUrl,
timeout: 30000,
ontimeout: (err) => reject(new Error(`Timeout: ${JSON.stringify(err)}`)),
onerror: (err) => reject(new Error(`Request failed: ${JSON.stringify(err)}`)),
onload: async (res) => {
setStatus('Indexing…');
const lines = res.responseText.split(/\r?\n/).map(w => (w || '').trim().toUpperCase());
dict = [];
for (const word of lines) {
if (!/^[A-Z0-9_.]+$/.test(word)) continue;
const len = word.length;
if (len < MIN_LENGTH || len > MAX_LENGTH) continue;
if (!dict[len]) dict[len] = [];
dict[len].push(word);
}
for (let len = MIN_LENGTH; len <= MAX_LENGTH; len++) {
if (dict[len]) {
await idbSet(`len_${len}`, dict[len]);
}
}
crackLog('Base dictionary downloaded and cached in IndexedDB');
resolve();
},
});
});
}
async function mergeSupabaseIntoCache(words) {
if (!words || !words.length) return 0;
let added = 0;
for (const w of words) {
const len = w.length;
if (len < MIN_LENGTH || len > MAX_LENGTH) continue;
let chunk = await idbGet(`len_${len}`);
if (!chunk) chunk = [];
if (!chunk.includes(w)) {
chunk.push(w);
await idbSet(`len_${len}`, chunk);
if (!dict[len]) dict[len] = [];
if (!dict[len].includes(w)) dict[len].push(w);
added++;
}
}
return added;
}
async function loadDict() {
if (dictLoaded || dictLoading) return;
dictLoading = true;
setStatus('Loading from cache…');
let hasData = false;
dict = [];
for (let len = MIN_LENGTH; len <= MAX_LENGTH; len++) {
const chunk = await idbGet(`len_${len}`);
if (chunk && chunk.length) {
dict[len] = chunk;
hasData = true;
}
}
if (!hasData) {
crackLog('No cache found. Downloading dictionary…');
try {
await fetchWordlistAndCache();
} catch (e) {
crackLog('Failed to download base wordlist:', e);
}
} else {
crackLog('Dictionary loaded from IndexedDB');
}
dictLoaded = true;
dictLoading = false;
setStatus('Ready');
setStatus('Ready (database sync…)');
loadSupabaseWords()
.then(mergeSupabaseIntoCache)
.then((added) => {
if (added && added > 0) {
setStatus(`Ready (+${added} words)`);
} else {
setStatus('Ready');
}
})
.catch(() => setStatus('Ready'));
}
async function suggest(pat) {
const len = pat.length;
if (len < MIN_LENGTH || len > MAX_LENGTH) return [];
if (!dict[len]) {
const chunk = await idbGet(`len_${len}`);
if (!chunk) return [];
dict[len] = chunk;
}
const worker = new Worker(URL.createObjectURL(new Blob([`
self.onmessage = function(e) {
const { dictChunk, pattern, max } = e.data;
const regex = new RegExp('^' + pattern.replace(/[*]/g, '.') + '$');
const out = [];
for (const word of dictChunk) {
if (regex.test(word)) out.push(word);
if (out.length >= max) break;
}
self.postMessage(out);
};
`], { type: 'application/javascript' })));
return new Promise((resolve) => {
worker.onmessage = (e) => {
worker.terminate();
resolve([...new Set(e.data)]);
};
worker.postMessage({ dictChunk: dict[len], pattern: pat.toUpperCase(), max: MAX_SUG });
});
}
function prependPanelToRow(row, pat) {
const existing = row.querySelector('.__crackhelp_panel');
if (existing && existing.dataset.pattern === pat && existing.querySelector('span')) return;
if (existing) existing.remove();
const panel = document.createElement('div');
panel.className = '__crackhelp_panel';
panel.dataset.pattern = pat;
panel.style.cssText = 'background: #000; 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() {
listDiv.innerHTML = '';
if (dictLoading && !dictLoaded) {
const sp = document.createElement('span');
sp.style.cssText = 'padding:2px; color:#ff0;';
sp.textContent = '(loading dictionary…)';
listDiv.appendChild(sp);
return;
}
const sugs = await suggest(pat);
listDiv.innerHTML = '';
if (sugs.length > 0) {
sugs.forEach(word => {
const sp = document.createElement('span');
sp.style.cssText = 'padding:2px; color: #00ff00;';
sp.textContent = word;
listDiv.appendChild(sp);
});
} else {
const none = document.createElement('span');
none.textContent = dictLoaded ? '(no matches)' : '(loading dictionary…)';
none.style.color = dictLoaded ? '#a00' : '#ff0';
listDiv.appendChild(none);
}
}
loadDict().then(updateSuggestions);
}
async function isWordInLocalDict(word) {
const len = word.length;
if (!dict[len]) {
const chunk = await idbGet(`len_${len}`);
if (!chunk) return false;
dict[len] = chunk;
}
return dict[len].includes(word);
}
async function addWordToLocalCache(word) {
const len = word.length;
if (len < MIN_LENGTH || len > MAX_LENGTH) return;
let chunk = await idbGet(`len_${len}`);
if (!chunk) chunk = [];
if (!chunk.includes(word)) {
chunk.push(word);
await idbSet(`len_${len}`, chunk);
if (!dict[len]) dict[len] = [];
if (!dict[len].includes(word)) dict[len].push(word);
crackLog('Added to local cache:', word);
}
}
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;
const crimeOptions = container.querySelectorAll('[class^="crimeOptionWrapper"]');
crackLog('Scanning crime options:', crimeOptions.length);
for (const crimeOption of crimeOptions) {
let patText = '';
const charSlots = crimeOption.querySelectorAll('[class^="charSlot"]:not([class*="charSlotDummy"])');
for (const charSlot of charSlots) {
let char = charSlot.textContent.trim();
patText += char ? char.toUpperCase() : '*';
}
if (!/[*]/.test(patText)) {
const newWord = patText.toUpperCase();
if (!/^[A-Z0-9_.]+$/.test(newWord)) {
crackLog('Revealed word contains invalid chars. skippin:', newWord);
} else {
(async () => {
const localHas = await isWordInLocalDict(newWord);
const supHas = supabaseWords.has(newWord);
if (!localHas && !supHas) {
crackLog('New fully cracked word sendin:', newWord);
await addWordToLocalCache(newWord);
sendWordToSupabase(newWord);
} else {
crackLog('Fully cracked but known not sendin: ', newWord);
if (supHas && !localHas) {
await addWordToLocalCache(newWord);
}
}
})();
}
}
if (!/^[*]+$/.test(patText)) prependPanelToRow(crimeOption, patText);
}
}
async function showMenuOverlay() {
const overlay = document.createElement('div');
overlay.style.cssText = `
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.7); color: #fff;
display: flex; align-items: center; justify-content: center;
z-index: 10000; font-size: 14px;
`;
const box = document.createElement('div');
box.style.cssText = `
background: #111; padding: 20px; border: 1px solid #0f0;
border-radius: 6px; text-align: center; min-width: 320px;
`;
box.innerHTML = `<div style="margin-bottom: 12px; font-size: 20px; color: #0f0;">Settings</div>`;
const statusLine = document.createElement('div');
statusLine.style.cssText = 'color:#0f0; font-size:12px; margin-bottom:8px;';
statusLine.textContent = ensureStatusBadge().textContent;
box.appendChild(statusLine);
const wordCountDiv = document.createElement('div');
wordCountDiv.style.cssText = 'color: #0f0; font-size: 12px; margin-bottom: 10px;';
wordCountDiv.textContent = 'Loading dictionary stats...';
box.appendChild(wordCountDiv);
(async () => {
let stats = [];
for (let len = MIN_LENGTH; len <= MAX_LENGTH; len++) {
const chunk = await idbGet(`len_${len}`);
stats.push(`${len}: ${chunk ? chunk.length : 0}`);
}
wordCountDiv.textContent = `Stored words per length → ${stats.join(' | ')}`;
})();
const btnCache = document.createElement('button');
btnCache.textContent = 'Clear Wordlist Cache';
btnCache.style.cssText = 'margin: 4px; padding: 4px 8px; background: #a00; color: #fff; cursor: pointer;';
btnCache.onclick = async () => { await clearLocalDictCache(); location.reload(); };
const cancelBtn = document.createElement('button');
cancelBtn.textContent = 'Close';
cancelBtn.style.cssText = 'margin: 4px; padding: 4px 8px; background: #222; color: #fff; cursor: pointer;';
cancelBtn.onclick = () => { document.body.removeChild(overlay); };
box.appendChild(btnCache);
box.appendChild(cancelBtn);
const line = document.createElement('hr');
line.style.cssText = 'border: none; border-top: 1px solid #0f0; margin: 10px 0;';
box.appendChild(line);
const pwrdByMsg = document.createElement('div');
pwrdByMsg.style.cssText = 'color: #0f0; font-size: 12px; margin-bottom: 10px;';
pwrdByMsg.textContent = 'Powered by Supabase / IndexedDB - Made with Love ❤ by SirAua [3785905] (and friends)';
box.appendChild(pwrdByMsg);
const psMsg = document.createElement('div');
psMsg.style.cssText = 'color: #0f0; font-size: 9px; margin-bottom: 10px;';
psMsg.textContent = 'Ps: Clear the cache after updates';
box.appendChild(psMsg);
overlay.appendChild(box);
document.body.appendChild(overlay);
}
function injectMenuButton() {
if (!location.href.endsWith('cracking')) return;
if (document.getElementById('__crack_menu_btn')) return;
const appHeader = document.querySelector('[class^="appHeaderDelimiter"]');
if (!appHeader) return;
const btn = document.createElement('button');
btn.id = '__crack_menu_btn';
btn.textContent = 'Bruteforce characters to show suggestions! (Click this to open a menu)';
btn.style.cssText = 'background: #000; color: #0f0; font-size: 10px; text-align: left; z-index: 9999; cursor: pointer;';
btn.onclick = showMenuOverlay;
appHeader.appendChild(btn);
ensureStatusBadge();
}
(async function init() {
ensureStatusBadge();
setStatus('Initializing…');
loadDict();
scanCrimePage();
setInterval(scanCrimePage, UPDATE_INTERVAL);
setInterval(injectMenuButton, UPDATE_INTERVAL);
})();
})();