6

Я хочу загрузить ссылку resource://, соответственно, локальный файл из моего Firefox-аддона в iframe на веб-странице.Firefox Addon SDK: загрузка файла addon в iframe

Причина в том, что ресурс должен быть визуально встроен в веб-страницу, не предоставляя веб-сайту доступ к DOM по соображениям безопасности.

Вопрос обсуждался в разных местах в прошлом, например. здесь (без решения): https://bugzilla.mozilla.org/show_bug.cgi?id=792479

Поскольку большинство сообщений довольно старые, я хочу спросить, есть ли между тем новые решения или обходные пути.

ответ

11

Я думаю, что я предложил в жуке или в 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; 

Это обходной путь, конечно, и я надеюсь, что ошибка вы упомянули будет исправлена ​​в ближайшее время Обратите внимание, что в этом случае вы не можете общаться непосредственно из фрейма в документ родителя, но. это также означает, что вы не можете обойти вокруг, это то, что вы хотите предотвратить.

Конечно, вы можете использовать дополнительный код для связи между вашим iframe и документом родителя (вам нужно прикрепить сценарии содержания и использовать port и postMessage).

Edit: изменили способ URL установлен, в противном случае получает атрибут src из документа родителя является еще возможно, и содержит весь HTML.

+0

Спасибо. Не может ли родительский документ восстановить доступ к содержимому iframe, удалив атрибут sandbox? –

+0

** Редактировать: ** Нет, не может. Изменения атрибута «песочница» применяются только при перезагрузке страницы. –

+0

Со всеми последними усовершенствованиями API Jetpack, является ли это все еще лучшей техникой, доступной для работы этой функции iframe? – NoR

2

Я использовал a solution proposed here.

Он реализуется путем создания специального протокола, который обрабатывается вашим аддоном Firefox, который, в свою очередь, запрашивает ресурсы из своей папки.
Обратите внимание, что если папка ресурса может содержать что-то непубличное, я бы добавил дополнительные проверки, чтобы разрешить доступ только к этим ресурсам, которые действительно предназначены для веб-доступа.

Код на заказ протокол прилагается к сообщению упомянутого выше 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 + "://"); 
}; 

Дополнительное примечание: для page скриптов (не content сценариев) этот пользовательский протокол помогает в загрузке iframe и другие элементы HTML , но не при загрузке XMLHttpRequest или Worker. Для последнего применяются ограничения по кросс-началу и возникает ошибка безопасности: «Доступ к ограниченному URI отклонен» в случае XMLHttpRequest и «Операция небезопасна». для Worker.
Напротив, под Хром допускается XMLHttpRequest до web_accessible_resources. Worker не реализует доступ к web_accessible_resources под Chrome.
BUT для Workers Вы можете использовать этот URL-адрес настраиваемого протокола для метода importScripts.Используя это, вы также можете обойти проблему загрузки пользовательских ресурсов в Workers. Этот код работает также в 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); 
0

Я использую идею zer0. Однако на страницах с политикой безопасности контента я получил исключение (... result = 2153644038). По этой причине я добавить свой домен к контент-безопасности-политики заголовка ответа:

//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: Этот код может быть отклонен FF рецензента с: «Изменение«контента безопасности- политика "не допускается по соображениям безопасности".

Смежные вопросы