Chrome Extension: Get Page Variables in Content Script

后端 未结 9 940
抹茶落季
抹茶落季 2020-11-27 03:44

Is there any way to retrieve a page\'s javascript variables from a Google Chrome Content Script?

9条回答
  •  余生分开走
    2020-11-27 04:24

    Chrome's documentation gives you a good starting point: https://developer.chrome.com/extensions/content_scripts#host-page-communication

    This method allows you to extract a global page variable to your content script. It also uses an idea to only accept incoming messages that you recognize given your handshake. You can also just use Math.random() for the handshake but I was having some fun.

    Explanation

    1. This method creates a script tag
    2. It stringifies the function propagateVariable and passes the current handShake and targeted variable name into the string for preservation since the function will not have access to our content script scope.
    3. Then it injects that script tag to the page.
    4. We then create a listener in our content script waiting to hear back from the page to pass back the variable we're after.
    5. By now the injected script has hit the page.
    6. The injected code was wrapped in an IIFE so it runs itself pushing the data to the listener.
    7. Optional: The listener makes sure that it had the correct handshake and voila we can trust the source of the data (It's not actually secure, but it helps create an identifier in this case, that gives us some level of trust).

    Round 1

    v1.0

    const globalToExtract = 'someVariableName';
    const array = new Uint32Array(5);
    const handShake = window.crypto.getRandomValues(array).toString();
    
    function propagateVariable(handShake, variableName) {
      const message = { handShake };
      message[variableName] = window[variableName];
      window.postMessage(message, "*");
    }
    
    (function injectPropagator() {
      const script = `( ${propagateVariable.toString()} )('${handShake}', '${globalToExtract}');`
      const scriptTag = document.createElement('script');
      const scriptBody = document.createTextNode(script);
      
      scriptTag.id = 'chromeExtensionDataPropagator';
      scriptTag.appendChild(scriptBody);
      document.body.append(scriptTag);
    })();
    
    window.addEventListener("message", function({data}) {
      console.log("INCOMINGGGG!", data);
      // We only accept messages from ourselves
      if (data.handShake != handShake) return;
    
      console.log("Content script received: ", data);
    }, false);

    v1.1 With Promise!

    function extractGlobal(variableName) {
    
      const array = new Uint32Array(5);
      const handShake = window.crypto.getRandomValues(array).toString();
    
      function propagateVariable(handShake, variableName) {
        const message = { handShake };
        message[variableName] = window[variableName];
        window.postMessage(message, "*");
      }
    
      (function injectPropagator() {
        const script = `( ${propagateVariable.toString()} )('${handShake}', '${variableName}');`
        const scriptTag = document.createElement('script');
        const scriptBody = document.createTextNode(script);
    
        scriptTag.id = 'chromeExtensionDataPropagator';
        scriptTag.appendChild(scriptBody);
        document.body.append(scriptTag);
      })();
    
      return new Promise(resolve => {
        window.addEventListener("message", function({data}) {
          // We only accept messages from ourselves
          if (data.handShake != handShake) return;
          resolve(data);
        }, false);
      });
    }
    
    extractGlobal('someVariableName').then(data => {
      // Do Work Here
    });

    Round 2 - Class & Promises

    v2.0

    I would recommend tossing the class into its own file and exporting it as a default if using es modules. Then it simply becomes:

    ExtractPageVariable('someGlobalPageVariable').data.then(pageVar => {
      // Do work here 

提交回复
热议问题