/* OGame Spy Auto-Importer — content script (isolated world) * * Esegue SOLO sulle pagine OGame (vedi manifest: *.ogame.gameforge.com). * * NON legge la clipboard (impossibile da content script: vale il permesso * della pagina, non quello dell'estensione). Intercetta invece il token nel * momento in cui viene copiato, tramite due sorgenti: * 1) evento DOM 'copy' → Ctrl+C, tasto destro, execCommand('copy') * 2) messaggio dal MAIN world → navigator.clipboard.writeText() (pulsante API) * * Il token intercettato viene inviato UNA volta al background che lo importa. * Se il background è occupato o non ancora pronto, si concede un solo retry. */ 'use strict'; // Stessa forma accettata dal server (ricerca dentro il testo copiato) const TOKEN_SEARCH_RE = /(cr|sr|rr|mr)-[a-z]{2}-\d{1,3}-[0-9a-f]{40}/i; const OGame_HOST_RE = /(^|\.)ogame\.gameforge\.com$/i; const CHANNEL = 'ogame-spy-importer'; const RETRY_MS = 1500; let autoImport = true; const done = new Set(); // token già inviati con esito definitivo const retried = new Set(); // token che hanno già usato il loro unico retry let inflight = null; // token attualmente in invio function isOgame() { return OGame_HOST_RE.test(window.location.hostname); } function extractToken(text) { if (!text || typeof text !== 'string') return null; const m = text.match(TOKEN_SEARCH_RE); return m ? m[0].toLowerCase() : null; } async function loadSettings() { const d = await chrome.storage.local.get({ settings: undefined }); autoImport = !d.settings || d.settings.autoImport !== false; } async function sendCapture(token) { try { const r = await chrome.runtime.sendMessage({ type: 'capture', token }); return (r && r.status) || 'error'; } catch { return 'unreachable'; // background non ancora pronto } } async function handleToken(token) { if (!token || !isOgame() || !autoImport) return; // già gestito (o in corso): niente doppioni se scattano entrambe le sorgenti if (done.has(token) || inflight === token) return; inflight = token; const status = await sendCapture(token); inflight = null; // 'busy'/'unreachable' = il background non ha risposto: un solo retry. if (status === 'busy' || status === 'unreachable') { if (!retried.has(token)) { retried.add(token); setTimeout(() => handleToken(token), RETRY_MS); } return; } // Esito definitivo: 'ok'/'dup'/'known' importato o già noto, // 'error' fallito (il background ha già mostrato la notifica d'errore). done.add(token); } // ---- sorgente 1: evento 'copy' (Ctrl+C, tasto destro, execCommand) ---- document.addEventListener('copy', (e) => { try { const text = e.clipboardData && e.clipboardData.getData('text'); const token = extractToken(text); if (token) handleToken(token); } catch (_) { /* noop */ } }, true); // ---- sorgente 2: writeText della pagina (main world → postMessage) ---- window.addEventListener('message', (e) => { if (e.source !== window || !e.data || e.data.__ogameSpyImporter !== CHANNEL) return; const token = extractToken(e.data.text); if (token) handleToken(token); }); chrome.storage.onChanged.addListener((changes, area) => { if (area !== 'local' || !changes.settings) return; autoImport = changes.settings.newValue.autoImport !== false; }); (async function init() { await loadSettings(); })();