xs的xul容器函数和我想从页面上的外部iframe调用js函数之一

时间:2011-11-22 11:16:09

标签: javascript xul xulrunner

我构建了xul模板,并在xul中添加了js。

主页面包含iframe标记。 我想从加载的iframe页面调用特定的js函数(在xul中)。

例如:

这是xul文件:

<?xml version="1.0"?>

         <script type="application/x-javascript"
        src="chrome://tuttoolbar/content/general.js" />

<toolbox id="navigator-toolbox">

    <toolbar id="TutTB-Toolbar" toolbarname="Tutorial Toolbar" accesskey="T"
             class="chromeclass-toolbar" context="toolbar-context-menu" 
             hidden="false" persist="hidden">

        <toolbarbutton id="TutTB-MainMenu" type="menu"
                       tooltiptext="Tutorial Toolbar Main Menu">
            <menupopup>
                <menuitem label="Google Home Page" accesskey="G"
                          tooltiptext="Navigate to Google"
                          oncommand="countChild('rso','li')" />

                <menuseparator />

                <menuitem label="Born Geek Website" accesskey="B"
                          tooltiptext="Navigate to Born Geek"
                          oncommand="te()" />
            </menupopup>
        </toolbarbutton>


    </toolbar>



</toolbox>

这是General JS文件(在xul文件中):

function box(){
alert("Box Work");
}

test.php - 这是在iframe中加载的源页面:

     <html>
    <head>
    </head> 
    <body>
   <div id="call" onclick="javascript:box();">
    </body>
    </html>

这是主文件:

    <html>
    <head>
    </head> 
    <body>
   <iframe src="test.php" width="400" height="40"></iframe>
    </body>
    </html>

有什么办法吗?

1 个答案:

答案 0 :(得分:0)

内容(不可信)文档(包括任何IFRAME)不能直接运行扩展中定义的函数或XulRunner加载的其他特权代码。即使您的特权代码将函数分配给不受信任的内容窗口,但只要该函数尝试使用/调用特权内容,您就会收到安全错误。

但是,您可以使用特权代码向不受信任的内容窗口添加事件侦听器!通过一些争论,您可以构建一个方案,将“特权”功能轻松安装到不受信任的内容中 - 即:打破安全沙箱。


以下是允许不受信任的domWindow执行(特权)跨域HTTP GET操作的示例:

/* 
   Give the end-user this API: 
     xdomainGET(sURL, 
                function(
                  iHTTPStatusCode, 
                  sHTTPStatusText, 
                  sHTTPResponseText
                ) { ... })             
*/

function install_xdomainGET_on_my_special_page(chromeWindow, domWindow) {

  install_privileged_method(
    /* this is the current browser chromeWindow (your XUL overlay is here!) */
    chromeWindow,     

    /* this is the unstrusted domWindow containing your IFRAME              */
    domWindow,  

    /* the name of the method we're adding to the untrusted domWindow       */
    'xdomainGET',     

    /* This is the methodFactory */
    function(priv) {
      /* This is the method that will be installed onto the untrusted 
         domWindow. It takes two arguments, 'sURL' and 'cb'. 'sURL' is a 
         cross-domain HTTP URL which we want to be able to GET from the 
         untrusted domWindow. 'cb' is a callback function which returns 
         3 values to the caller...                                          */
      return function(sURL, cb) {
        priv.call([sURL], function(rstatus, rdata, rerror){
          cb(rstatus ? rdata.statusCode   : 0,      // iHTTPStatusCode
             rstatus ? rdata.statusText   : rerror, // sHTTPStatusText
             rstatus ? rdata.responseText : null);  // sHTTPResponseText
        });
      };
    },

    /* This is the privileged 'handler code. It has access to the 
       chromeWindow, and all of the privileged APIs that are available 
       there. (e.g: nsI*, XPCom, js-ctypes, etc)                            */
    function (chromeWindow, args, cb) {
      var [url] = args;
      var xhr = new chromeWindow.XMLHttpRequest();
      xhr.onload = function(){
        cb(1, {
          statusCode: this.status,
          statusText: this.statusText,
          responseText: this.responseText
        }, null);
      };
      xhr.addEventListener('error', function(error_evt) { 
        cb(0, null, error_evt.error); 
      }, false);
      xhr.open('get', url, true);
      xhr.send();
    }
  );
}

这是我的库函数,这使得这成为可能。基本上,它做了两件事(来自特权代码):

  1. 它将一个函数安装到不受信任的domWindow中,该函数为最终用户提供了预期的API,当调用它时会打包参数(包括回调函数)并引发一个合成事件。它将此组织为方法工厂,以便最终用户可以拥有他们想要的任何形状的API(只要它需要回调!)。

  2. 它在不受信任的窗口上安装事件处理程序。当不受信任的窗口调度其合成事件时,事件处理程序捕获它,解包参数执行提供的特权代码。然后它调用事件详细信息中提供的不受信任的回调函数。


  3. const Cc = Components.classes;
    const Ci = Components.interfaces;
    let consoleService = Cc["@mozilla.org/consoleservice;1"]
                           .getService(Ci.nsIConsoleService);
    function LOG(msg) { 
      consoleService.logStringMessage("EXTENSION: "+msg); 
    }
    
    // install a privileged method on the given (untrusted) 'target' window 
    var install_privileged_method = (function(){
      var gensym = (function (){
        var __sym = 0;
        return function () { return '__sym_'+(__sym++); }
      })();
    
      return function (chromeWindow, target, slot, handler, methodFactory) {
        try {
    
          // initialise target window with ticket/callback-dict/namespace
          target.__pmcache__ = target.hasOwnProperty('__pmcache__') 
            ? target.__pmcache__ 
            : { ticket_no: 0, callbacks: {}, namespace: gensym() };
    
          // install the user factory-generated dispatcher method on 
          // the 'target' untrusted content window.
          target[slot] = methodFactory({ call: function(fargs, fcb) {
            try {
              var ticket_no = target.__pmcache__.ticket_no++;
              target.__pmcache__.callbacks[ticket_no] = fcb;
              var cevent = target.document.createEvent("CustomEvent");
              cevent.initCustomEvent(
                target.__pmcache__.namespace+'.'+slot, 
                true, true, { fargs: fargs, ticket_no: ticket_no }
              );
              target.dispatchEvent(cevent);
            } catch (ue) {
              fcb(0, null, 'untrusted dispatcher error: '+ue);
            }
          }});
          LOG("installed untrusted dispatcher for method '"+slot+"'.");
    
          // Add an event listener to (untrusted) target window which 
          // listens for custom event generated by above dispatcher method.
          target.addEventListener(
            target.__pmcache__.namespace+'.'+slot, 
            function(cevent){
              var ticket_no = cevent.detail.ticket_no;
              var fargs = cevent.detail.fargs;
              var fcb = target.__pmcache__.callbacks[ticket_no];
              try {
                handler(chromeWindow, fargs, fcb);
              } catch (pe) {
                fcb(0, null, 'privileged handler error: '+pe);
              }
            }, 
            false, 
            true
          );
          LOG("installed privileged handler for method '"+slot+"'.");
    
        } catch (ie) {
          LOG("ERROR installing handler/factory for privileged "+
              "method '"+slot+"': "+ie);
        }
      };
    })();
    

    既然我们已经找到了摆脱沙盒的方法,我们需要确保我们只将这种可能性添加到我们的“可信”网页中。 (即:您托管PHP的URL)。

    我一直在Firefox中这样做,所以我在用户界面中处理一个或多个TabBrowser XUL元素。当您使用XulRunner时,情况可能并非如此。

    为了找到我们的“可信”页面,我们需要查看所有当前(以及将来)的chromeWindows并在其上安装“加载”处理程序。

    let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
               .getService(Ci.nsIWindowMediator);
    let windows = wm.getEnumerator("navigator:browser");
    while (windows.hasMoreElements()) {
      let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
      WindowListener.setupBrowserUI(domWindow);
    }
    wm.addListener(WindowListener);
    

    其中WindowListener定义为:

    var WindowListener = {
      setupBrowserUI: function(window, xulWindow, othWindow) {
        window.gBrowser.addEventListener('load', my_load_handler, true); 
      },
      tearDownBrowserUI: function(window) { 
        window.gBrowser.removeEventListener('load', my_load_handler, true); 
      },
      onOpenWindow: function(xulWindow) {
        let domWindow = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIDOMWindow);
        domWindow.addEventListener("load", function listener() {
          domWindow.removeEventListener("load", listener, false); 
          var domDocument = domWindow.document.documentElement;
          var windowType = domDocument.getAttribute("windowtype");
          if (windowType == "navigator:browser")
            WindowListener.setupBrowserUI(domWindow);
        }, false);
      },
    
      onCloseWindow: function(xulWindow) { },
      onWindowTitleChange: function(xulWindow, newTitle) { }
    };
    

    其中my_load_handler定义为:

    var my_load_handler = function (evt) {
      try {
        var browserEnumerator = wm.getEnumerator("navigator:browser");
        while (browserEnumerator.hasMoreElements()) {
          var browserWin = browserEnumerator.getNext();
          var tabbrowser = browserWin.gBrowser;
          var numTabs = tabbrowser.browsers.length;
          for (var index = 0; index < numTabs; index++) {
            var currentBrowser = tabbrowser.getBrowserAtIndex(index);
            var domWindow = currentBrowser.contentWindow.wrappedJSObject;
    
            // identify your target page...
            if (domWindow.location.href == 'http://yourserver/yourpage') {
    
              // install the privileged method (if it's not already there!)
              if (!domWindow.hasOwnProperty('xdomainGET') {
                install_xdomainGET_on_my_special_page(browserWin, domWindow);
              } 
            } 
    
          }
        }
      } catch (e) {
        LOG(e);
      }
    }