Extensión Manifest V3: acceso a funciones locales

Resumen y solución de problemas para la extensión de Manifest V3: Accediendo a funciones locales

En este artículo se aborda el problema que se presenta al desarrollar una extensión de Chrome bajo el modelo de Manifest V3, donde se requiere interactuar con una función JavaScript de una página web externa (no controlada por el desarrollador). A continuación, se analizan las dos estrategias intentadas y se propone una solución.

Contexto del Problema

El objetivo es ejecutar una función local getValue() de una página externa y enviar su resultado a un script de fondo (service worker) de la extensión. Sin embargo, las limitaciones de seguridad y el contexto de ejecución entre scripts de la extensión y contenido causan complicaciones.

Estrategias Intentadas

  1. Ejecutar getValue() en content_scripts:

    • Se logra invocar la función local usando "world": "MAIN" pero se enfrenta al error Extension context invalidated al intentar usar chrome.runtime.sendMessage().
  2. Enviar un mensaje desde content_scripts a background.js:
    • Se puede enviar un mensaje correctamente, pero se produce un ReferenceError porque getValue() no está accesible en el contexto del script de contenido.

Código Proporcionado

  1. manifest.json:
{
  "manifest_version": 3,
  "name": "ExtName",
  "version": "0.0.1",
  "content_scripts": [
    {
      "matches": ["*://url/*"],
      "js": ["main.js"]
    }
  ],
  "host_permissions": [
    "*://*/*"
  ],
  "background": {
    "service_worker": "background.js"
  }
}
  1. main.js:
var intervalID = window.setInterval(checkValue, 1000);

async function checkValue() {
    let value = getValue();
    if (value) {
        const response = await chrome.runtime.sendMessage({status: value});
        console.log(response.text);
    }
};
  1. background.js:
function handleMessage(request, sender, sendResponse) {
    console.log(request.status);
    sendResponse({ text: "Received!" });
}

chrome.runtime.onMessage.addListener(handleMessage);
  1. Script de página externa:
function getValue() {
    return "value";
}

Solución Propuesta

Para poder acceder tanto a la función getValue() en la página como enviar correctamente los mensajes al service worker, se puede modificar el enfoque utilizando una combinación de inyección y manejo de mensajes:

  1. Inyección de un script en la página que capture el valor y lo envíe a la extensión.

    En lugar de intentar acceder a getValue() directamente desde main.js, se puede crear un script que ejecute esta función y envíe el resultado a través de chrome.runtime.sendMessage().

    Modifiquemos main.js para inyectar un script que llame a getValue() y envíe el resultado a la extensión:

var intervalID = window.setInterval(async () => {
    const value = await new Promise((resolve) => {
        chrome.scripting.executeScript({
            target: { tabId: /* ID de la pestaña actual */ },
            func: getValue
        }, (injectionResults) => {
            resolve(injectionResults[0].result);
        });
    });

    if (value) {
        const response = await chrome.runtime.sendMessage({status: value});
        console.log(response.text);
    }
}, 1000);

Conclusión

El acceso a funciones locales en páginas web externas desde una extensión de Chrome puede ser complicado debido a las restricciones del modelo de seguridad. Sin embargo, al inyectar scripts que interactúan con el DOM de la página, se puede lograr la comunicación necesaria entre la extensión y el contenido de la página. Esta solución asegura que se cumplan las reglas de seguridad mientras se logra la funcionalidad requerida.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *