简体   繁体   English

Firefox Addon SDK:将插件文件加载到iframe中

[英]Firefox Addon SDK: Loading addon file into iframe

I want to load a resource:// link, respectively a local file from my Firefox addon into an iframe in a web page. 我想将一个resource://链接分别加载到我的Firefox插件中的本地文件到网页中的iframe

The reason is, that the resource should be visually embedded into the web page while not giving the website access to it's DOM for security reasons. 原因是,出于安全原因,资源应该可视地嵌入到网页中,而不是让网站访问它的DOM。

The issue has been discussed in various places in the past, eg here (without solution): https://bugzilla.mozilla.org/show_bug.cgi?id=792479 这个问题在过去的各个地方已经讨论过了,例如这里(没有解决方案): https//bugzilla.mozilla.org/show_bug.cgi?id = 792479

As most of the postings are rather old, I want to ask, if in the meantime there are any new solutions or workarounds. 由于大多数帖子都比较陈旧,我想问一下,如果在此期间有任何新的解决方案或解决方法。

I think I suggested in the bug or in the ML of jetpack a terrible workaround, that basically is convert your resource:// in a data: url (using data.load to load the HTML content, and then encode and append as prefix, so something like that should works: 我认为我在错误或在jetpack的ML中提出了一个糟糕的解决方法,基本上是在data: url中转换你的resource:// (使用data.load加载HTML内容,然后编码并附加为前缀,所以这样的事情应该有效:

/* main.js */
const { data } = require('sdk/self');

// just an example, you can use `tab.attach` too
require('sdk/page-mod').PageMod({
  include: '*',
  contentScriptFile: data.url('content.js'),
  contentScriptOptions: {
    content: encodeURIComponent(data.load('index.html'))
  }
});

/* content.js */
let iframe = document.body.appendChild(document.createElement('iframe'));

iframe.setAttribute('sandbox', 'allow-scripts');
// maybe you want also use the seamless attribute, see:
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe

iframe.contentWindow.location.href = 'data:text/html;charset=utf-8,' + self.options.content;

It's a workaround of course, and I hope that the bug you mentioned will be fixed soon. 这当然是一种解决方法,我希望你提到的错误很快就会解决。 Notice that in this way you cannot communicate directly from the iframe to the parent's document, but it means also that you can't do the way around, that is what you want to prevent. 请注意,通过这种方式,您无法直接从iframe与父文档进行通信,但这也意味着您无法绕过,这就是您想要阻止的。

Of course, you can still use the add-on code to communicate between your iframe and the parent's document (you need to attach content scripts and use port and postMessage ). 当然,您仍然可以使用附加代码在iframe和父文档之间进行通信(您需要附加内容脚本并使用portpostMessage )。

Edit: changed the way the url is set, otherwise getting the src attribute from the parent's document is still possible, and contains whole HTML. 编辑:更改了url的设置方式,否则仍然可以从父文档中获取src属性,并包含完整的HTML。

I used a solution proposed here . 我使用了这里提出的解决方案

It is implemented by creating a special protocol that is handled by your Firefox addon, which in turn requests the resources from its folder. 它是通过创建由Firefox插件处理的特殊协议来实现的,该插件又从其文件夹中请求资源。
Note that in case the resource folder may contain something non-public then I would add additional checks to allow only these resources that really are intended to be web-accessible. 请注意,如果资源文件夹可能包含非公开的内容,那么我会添加其他检查以仅允许那些真正可以通过Web访问的资源。

The custom-protocol code attached to the post mentioned above is available here : 附上上述帖子的自定义协议代码可在此处获得

/*
Makes any file within the data directory available to use in an iframe.
Replace this: require("sdk/self").data.url(...)
With this: require("name-of-this-file").url(...)
*/
var { Class } = require('sdk/core/heritage');
var { Unknown, Factory } = require('sdk/platform/xpcom');
var { Cc, Ci, Cr } = require('chrome');
var self = require("sdk/self");

var resourceProtocolHandler = Cc["@mozilla.org/network/io-service;1"]
    .getService(Ci.nsIIOService)
    .getProtocolHandler('resource');

var scheme = "res-" + self.id.toLowerCase().replace(/[^a-z0-9+\-\.]/g, "-");

var AddonProtocolHandler = Class({
    extends: Unknown,
    interfaces: ['nsIProtocolHandler'],

    scheme: scheme,
    defaultPort: -1,
    protocolFlags: Ci.nsIProtocolHandler.URI_STD
        | Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE
        | Ci.nsIProtocolHandler.URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT,

    newURI: function(spec, originCharset, baseURI) {
        let uri = Cc["@mozilla.org/network/standard-url;1"].createInstance(Ci.nsIStandardURL);
        uri.init(uri.URLTYPE_STANDARD, this.defaultPort, spec, originCharset, baseURI);
        return uri.QueryInterface(Ci.nsIURI);
    },

    newChannel: function(uri) {
        if (uri.spec.indexOf(exports.url("")) != 0) {
            throw Cr.NS_ERROR_ILLEGAL_VALUE;
        }
        var resourceUri = resourceProtocolHandler.newURI(uri.spec.replace(scheme + "://", "resource://"), uri.originCharset, null);
        var channel = resourceProtocolHandler.newChannel(resourceUri);
        channel.originalURI = uri;
        return channel;
    },

    allowPort: (port, scheme) => false
});

Factory({
    contract: "@mozilla.org/network/protocol;1?name=" + scheme,
    Component: AddonProtocolHandler
});

exports.url = function(url) {
    return self.data.url(url).replace("resource://", scheme + "://");
};

Additional note : for page scripts (not content scripts) this custom protocol helps in loading an iframe and other HTML elements, but not in loading a XMLHttpRequest or Worker . 附加说明 :对于page脚本(不是content脚本),此自定义协议有助于加载iframe和其他HTML元素,但不能加载XMLHttpRequestWorker For the latter, still cross-origin restrictions apply and a security error is raised: "Access to restricted URI denied" in case of XMLHttpRequest , and "The operation is insecure." 对于后者,仍然存在跨源限制并且引发安全性错误:在XMLHttpRequest情况下“访问受限制的URI被拒绝”,并且“操作是不安全的”。 for Worker . Worker
In contrast, under Chrome the XMLHttpRequest to web_accessible_resources is permitted. 相反,在Chrome下,允许使用XMLHttpRequestweb_accessible_resources Worker does not implement access to web_accessible_resources under Chrome either. Worker也没有在Chrome下实现对web_accessible_resources访问。
BUT for Workers you can use this custom-protocol url for importScripts method. 但是对于Workers您可以将此自定义协议URL用于importScripts方法。 Using that you can also work around the problem of loading custom resources into Workers . 使用它您还可以解决将自定义资源加载到Workers This code works also in Chrome, as an alternative to using XMLHttpRequest . 此代码也适用于Chrome,作为使用XMLHttpRequest的替代方法。

var code = "self.onmessage = function (message)\
{\
    self.onmessage = null;\
    self.importScripts(message.data);\
};";

var blob = new Blob([code], {type: 'application/javascript'});
var blobUrl = URL.createObjectURL(blob);
var w = new Worker(blobUrl);
w.postMessage(*webAccessibleResourceUrl*);
URL.revokeObjectURL(blobUrl);

I'm using zer0 's idea. 我正在使用zer0的想法。 However, on pages with a content-security-policy I got an exception (...result = 2153644038). 但是,在具有content-security-policy的页面上,我得到了一个异常(... result = 2153644038)。 For that reason, I add my domain to the content-security-policy of the response header: 出于这个原因,我将我的域添加到响应头的content-security-policy:

//main.js 
var { Cc, Ci } = require('chrome');

var observer = {
    observe : function(aSubject, aTopic, aData) {
      if (aTopic == "http-on-examine-response") {
        aSubject.QueryInterface(Ci.nsIHttpChannel);
        var csp = aSubject.getResponseHeader("content-security-policy");
        if(csp.indexOf('frame-src') > -1) {
            var cspParts = csp.split(';');
            for (var i=0; i<cspParts.length; i++) {
                if(cspParts[i].indexOf('frame-src') > -1) {
                    cspParts[i] += ' yourdomain.tld';
                    break;
                }
            }
            aSubject.setResponseHeader("content-security-policy", cspParts.join(';'), false);
        } 
      }
    }
}; 
var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
observerService.addObserver(observer, "http-on-examine-response", false);

//content-script.js 
iframe.src = yourdomain.tld/...

EDIT : This code might be rejected by a FF reviewer with: "Modifying 'content-security-policy' is not allowed for security reasons." 编辑 :FF审核员可能拒绝此代码:“出于安全原因,不允许修改'content-security-policy'。”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM