Skip to content
Snippets Groups Projects
background.js 20.63 KiB
// ─────────────────────────────────────────────────────────────────────────────
// Variables globales
// ─────────────────────────────────────────────────────────────────────────────
let isExtensionActive = true;
let areStatsActive = false;
let originalTabId = null;
let loginTabId = null;

const AUTH_LOGIN_URL = "https://prisms.lezinter.net/fr/login";
const AUTH_BALEX_URL = "https://prisms.lezinter.net/fr/headquarters/balex";

// ─────────────────────────────────────────────────────────────────────────────
// Logs de démarrage
// ─────────────────────────────────────────────────────────────────────────────
log("🚀 ff2BaLex (background) chargé.");

browser.runtime.onInstalled.addListener((details) => {
  log("🔔 Extension installée ou mise à jour. Raison :", details.reason);
});

browser.runtime.onStartup.addListener(() => {
  log("🔄 Extension démarrée (onStartup).");
});

// ─────────────────────────────────────────────────────────────────────────────
// Suivi des changements dans le stockage
// ─────────────────────────────────────────────────────────────────────────────
browser.storage.onChanged.addListener((changes) => {
  if (changes.extensionActive) {
    isExtensionActive = changes.extensionActive.newValue;
    log("✅ Extension activée :", isExtensionActive);
  }
  if (changes.statsActive) {
    areStatsActive = changes.statsActive.newValue;
    log("📊 Statistiques activées :", areStatsActive);
  }
  refreshAllUI();
});

browser.storage.onChanged.addListener((changes, area) => {
  if (area === "local" && changes.accessToken) {
    const newToken = changes.accessToken.newValue;
    if (newToken) {
      browser.storage.local.get("extensionActive").then(({ extensionActive }) => {
        if (!extensionActive) {
          log("Token ajouté, activation automatique de l'extension.");
          browser.storage.local.set({ extensionActive: true });
          enableExtensionFeatures(); 
          browser.runtime.sendMessage({
            action: "updateUI",
            extensionActive: true,
            isTrackingActive: true,
            autoAdd: true
          });
        }
      });
    }
  }
});

// ─────────────────────────────────────────────────────────────────────────────
// Fonctions utilitaires
// ─────────────────────────────────────────────────────────────────────────────
async function isUserConnected() {
  const { accessToken } = await browser.storage.local.get("accessToken");
  return !!accessToken;
}

async function refreshAllUI() {
  log("🔄 Rafraîchissement global de l'UI...");
  browser.runtime.sendMessage({ action: "refreshUI" });
}

// ─────────────────────────────────────────────────────────────────────────────
// Initialisation du WebWorker
// ─────────────────────────────────────────────────────────────────────────────
let worker = null;

function initWorker() {
  if (!worker) {
    log("[Background] Initialisation du WebWorker...");
    try {
      worker = new Worker("src/workers/pyodide_worker.js");
      worker.onmessage = (event) => {
        log("[Background] Message reçu du WebWorker :", event.data);
      };
      worker.onerror = (error) => {
        console.error("[Background] Erreur dans le WebWorker :", error);
      };
      log("[Background] WebWorker initialisé avec succès.");
    } catch (error) {
      console.error("[Background] Échec de l'initialisation du WebWorker :", error);
    }
  }
}
// Initialisation
initWorker();
worker.postMessage({ command: "pyodide-simplemma" });

// ─────────────────────────────────────────────────────────────────────────────
// Écoute des messages de la popup et transmission au WebWorker
// ─────────────────────────────────────────────────────────────────────────────
browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
  log("[Background] Message reçu :", message);

  if (!worker) {
    initWorker();
  }

  if (message.command === "toggle-stats") {
    log(`[Background] Statistiques ${message.isActive ? "activées" : "désactivées"}`);
    await browser.storage.local.set({ isTrackingActive: message.isActive });
    // Transmettre l'activation des statistiques au WebWorker
    worker.postMessage({ command: "toggle-stats", isActive: message.isActive });
  }
  
  if (message.command === "pyodide-simplemma") {
    log("[Background] Demande d'initialisation de Pyodide et Simplemma...");
    worker.postMessage({ command: "pyodide-simplemma" });
  }

  return true; 
});

// ─────────────────────────────────────────────────────────────────────────────
// Écouter les réponses du WebWorker
// ─────────────────────────────────────────────────────────────────────────────
worker.onmessage = (event) => {
  log("[Background] Message du WebWorker :", event.data);

  // Pyodide et Simplemma prêts : notifier tous les onglets
  if (event.data.type === "pyodide-simplemma" && event.data.status === "success") {
    browser.tabs.query({}).then((tabs) => {
      tabs.forEach((tab) => {
        if (!tab.url || (!tab.url.startsWith("https://") && (!tab.url.startsWith("https://")))) {
          return;
        }
        if (tab.url.includes("sidebar.html")) {
          return;
        }

        try {
          let response = browser.tabs.sendMessage(tab.id, { command: "pyodide-simplemma-ready" })
          if (response && typeof response.then === "function") {
            response.then(() => {
            }).catch((error) => {
              log("[Background] Impossible d'envoyer un message à l'onglet ${tab.id} : ${error}");
            });
          }
        } catch (error) {
          log("[Background] Erreur lors de l'envoi d'un message à l'onglet ${tab.id} : ${error}");
        }
      });
    })
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Fonctions d'authentification & de redirection
// ─────────────────────────────────────────────────────────────────────────────
browser.runtime.onConnect.addListener((port) => {
  if (port.name === "auth") {
    port.onMessage.addListener(async (message) => {
      if (message.action === "toggleAuth") {
        log("🔄 toggleAuth reçu via port dans le background.");
        const isConnected = await isUserConnected();
        if (isConnected) {
          await disconnectFromLexicalDB();
        } else {
          actuallyOpenLoginPage();
        }
      }
    });
  }
});

async function actuallyOpenLoginPage() {
  log("🔗 Ouverture de la page de connexion.");

  // Mémoriser l'onglet actif
  const [currentTab] = await browser.tabs.query({ active: true, currentWindow: true });
  if (currentTab) {
    originalTabId = currentTab.id;
    log("✅ Onglet courant mémorisé, ID =", originalTabId);
  }
  // Ouvre un nouvel onglet pour la page de connexion et l'active
  const loginTab = await browser.tabs.create({ url: AUTH_LOGIN_URL, active: true });
  loginTabId = loginTab.id;
  log("✅ Onglet de login créé, ID =", loginTabId);
  // Notifie que l'authentification est en cours
  browser.runtime.sendMessage({ action: "authStatusChanged", isLoggedIn: false });
}

// Déconnecte l'utilisateur 
async function disconnectFromLexicalDB() {
  await browser.storage.local.remove("accessToken");
  log("🔓 Token supprimé avec succès.");
  
  await browser.storage.local.remove("lexiconColors");
  
  // Désactivation automatique de l'extension
  await browser.storage.local.set({ extensionActive: false });
  disableExtensionFeatures(); 
  browser.runtime.sendMessage({ 
    action: "updateUI", 
    extensionActive: false, 
    isTrackingActive: false, 
    autoAdd: false 
  });
  setTimeout(async () => {
    await refreshAllUI();
  }, 500);
}

// Sauvegarde le token et ferme l'onglet de login si nécessaire
async function saveToken(token) {
  log("✅ Sauvegarde du token :", token);
  await browser.storage.local.set({ accessToken: token });

  if (loginTabId) {
    try {
      await browser.tabs.remove(loginTabId);
      log("🗙 Onglet de login fermé après connexion réussie.");
    } catch (err) {
      console.warn("Impossible de fermer l'onglet de login :", err);
    }
    loginTabId = null;
  }
  if (originalTabId) {
    try {
      await browser.tabs.update(originalTabId, { active: true });
      log("🔙 Retour sur l'onglet initial :", originalTabId);
    } catch (err) {
      console.warn("Impossible de basculer sur l'onglet initial :", err);
    }
    originalTabId = null;
  }

  // Activer automatiquement l'extension
  const { extensionActive } = await browser.storage.local.get("extensionActive");
  if (!extensionActive) {
    await browser.storage.local.set({ extensionActive: true });
    enableExtensionFeatures();
    browser.runtime.sendMessage({
      action: "updateUI",
      extensionActive: true,
      isTrackingActive: true,
      autoAdd: true
    });
  }
  await refreshAllUI();
}

// ─────────────────────────────────────────────────────────────────────────────
// Gestion des messages reçus
// ─────────────────────────────────────────────────────────────────────────────
browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
  log("📩 Message reçu dans background.js :", message);

  switch (message.action) {
    case "toggleAuth": {
      const isConnected = await isUserConnected();
      if (isConnected) {
        await disconnectFromLexicalDB();
        await browser.storage.local.remove("lexiconColors");
      } else {
        actuallyOpenLoginPage();
      }
      break;
    }
    case "getDefinitionWiki": {
      if (message.selectedText && message.selectedText.trim() !== "") {
        log("🌐 Requête Wiktionnaire pour :", message.selectedText);
        const definition = await window.fetchWiktionaryDefinition(message.selectedText.trim());
        browser.runtime.sendMessage({
          action: "fetchWiktionaryDefinitionResponse",
          selectedText: message.selectedText,
          definitions: [{
            source: "Wiktionnaire",
            text: definition,
          }],
        });
      } else {
        console.warn("⚠️ Texte sélectionné vide. Annulation de la requête.");
      }
      break;
    }
    case "checkAuthStatus": {
      const connected = await isUserConnected();
      sendResponse(connected);
      break;
    }
    case "authStatusChanged": {
      log("🔄 Mise à jour de l'état d'authentification :", message.isLoggedIn);
      break;
    }
    case "saveToken": {
      if (message.token) {
        await saveToken(message.token);
      } else {
        console.warn("⚠️ Aucune valeur de token reçue.");
      }
      break;
    }
    default:
      break;
  }
  return true;
});

// ─────────────────────────────────────────────────────────────────────────────
// Web Navigation : Injection de scripts et récupération du token
// ─────────────────────────────────────────────────────────────────────────────
browser.webNavigation.onCompleted.addListener(async (details) => {
  const url = new URL(details.url);

  // Injection d'un popup d'instruction sur la page de login
  if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/login") {
    log("📘 Injection du popup d'instruction sur la page de login Prisms.");
    showInstructionPopup(details);
  }
  // Récupération du token sur la page /balex
  if (url.hostname === "prisms.lezinter.net" && url.pathname === "/fr/headquarters/balex") {
    log("🟢 Page /balex détectée. Tentative de récupération du token.");
    try {
      await new Promise(resolve => setTimeout(resolve, 3000));
      await browser.tabs.executeScript(details.tabId, {
        code: `
          (function() {
            log("🔍 Recherche du token...");
            const tokenElement = document.getElementById("accessToken") || document.getElementById("accesToken");
            if (tokenElement) {
              const token = tokenElement.innerText.trim();
              log("🔐 Token détecté :", token);
              browser.runtime.sendMessage({ action: "saveToken", token });
            } else {
              console.error("❌ Token introuvable.");
            }
            return null;
          })();
        `
      });
    } catch (error) {
      console.error("❌ Erreur lors de la récupération du token :", error);
    }
  }
}, { url: [{ hostContains: "prisms.lezinter.net" }] });

// ─────────────────────────────────────────────────────────────────────────────
// Web Request : Redirection automatique vers /balex
// ─────────────────────────────────────────────────────────────────────────────
browser.webRequest.onBeforeRequest.addListener(
  function(details) {
    if (details.url === "https://prisms.lezinter.net/fr/headquarters/") {
      log("🚀 Redirection automatique vers /balex.");
      return { redirectUrl: AUTH_BALEX_URL };
    }
  },
  { urls: ["https://prisms.lezinter.net/fr/headquarters/*"] },
  ["blocking"]
);

// ─────────────────────────────────────────────────────────────────────────────
// Affichage d'un popup d'instruction sur /fr/login
// ─────────────────────────────────────────────────────────────────────────────
function showInstructionPopup(details) {
  browser.tabs.executeScript(details.tabId, {
    code: `
      if (!document.getElementById("balex-instruction-popup")) {
        const popup = document.createElement("div");
        popup.id = "balex-instruction-popup";
        popup.style.position = "fixed";
        popup.style.top = "50%";
        popup.style.left = "50%";
        popup.style.transform = "translate(-50%, -50%)";
        popup.style.backgroundColor = "#a08e9f";
        popup.style.color = "#323046";
        popup.style.padding = "20px";
        popup.style.borderRadius = "10px";
        popup.style.boxShadow = "0 2px 10px rgba(0, 0, 0, 0.3)";
        popup.style.zIndex = "10000";
        popup.style.fontFamily = "Helvetica, sans-serif";
        popup.style.fontSize = "14px";
        popup.style.width = "300px";
        popup.style.textAlign = "center";
  
        popup.innerHTML = \`
          <h5 style="color: #fff; font-weight: bold; margin-top: 0;">🔑 Connexion à l'extension</h5>
          <p style="margin: 15px 0;">
            Après avoir renseigné vos identifiants, cliquez sur 
            <strong>"Se connecter avec BaLex"</strong>.
          </p>
          <button id="close-popup-btn" style="
            width: 100%;
            margin-top: 15px;
            padding: 10px;
            border: none;
            background-color: #8d5c70;
            color: #fbfcfc;
            font-weight: bold;
            cursor: pointer;
            border-radius: 5px;
          ">Fermer</button>
        \`;
  
        document.body.appendChild(popup);
  
        const closeBtn = document.getElementById("close-popup-btn");
        closeBtn.onclick = () => popup.remove();
      }
    `
  });
}

// ─────────────────────────────────────────────────────────────────────────────
// Gestion de l'activation/désactivation de l'extension
// ─────────────────────────────────────────────────────────────────────────────
// === 1. Initialisation de l'état de l'extension ===
async function initializeExtensionState() {
  const { extensionActive } = await browser.storage.local.get("extensionActive");

  if (extensionActive === undefined) {
    await browser.storage.local.set({ extensionActive: true }); // Activation par défaut
    log("🔄 Initialisation : extension activée par défaut.");
    enableExtensionFeatures();
  } else {
    log(`🔄 État actuel de l'extension : ${extensionActive ? "activée" : "désactivée"}`);
    if (extensionActive) {
      enableExtensionFeatures();
    } else {
      disableExtensionFeatures();
    }
  }
}

// === 2. Gestion de l'activation/désactivation de l'extension ===
browser.runtime.onMessage.addListener(async (message) => {
  if (message.action === "toggleExtension") {
    log(`🔄 Changement d'état de l'extension : ${message.isActive ? "activée" : "désactivée"}`);
    await browser.storage.local.set({ extensionActive: message.isActive });

    if (!message.isActive) {
      disableExtensionFeatures();
    } else {
      enableExtensionFeatures();
    }
    browser.runtime.sendMessage({ action: "updateUI" });
  }
});

// === 3. Fonction pour désactiver les fonctionnalités de l'extension ===
async function disableExtensionFeatures() {
  log("Désactivation des fonctionnalités de l'extension.");
  browser.runtime.sendMessage({ 
    action: "updateUI", 
    autoAdd: false, 
    isTrackingActive: false,
    areStatsActive: false
  });
  // Suppression d'éventuelles actions spécifiques à la sidebar
  log("Les fonctionnalités de la sidebar ne sont plus utilisées.");
}

// === 4. Fonction pour activer les fonctionnalités de l'extension ===
async function enableExtensionFeatures() {
  log("Réactivation des fonctionnalités de l'extension.");
  browser.runtime.sendMessage({ 
    action: "updateUI", 
    autoAdd: true, 
    isTrackingActive: true,
    areStatsActive: true
  }).catch(err => {
    console.warn("Aucun récepteur pour le message updateUI :", err);
  });
}

initializeExtensionState();