Chromeの拡張機能(およびアプリケーション)の所有者は、マニフェストの2番目のバージョンをサポートすることを検討します。
誰かが知らない場合、ブラウザ拡張機能の開発における新しい変更と革新が発表されたのはそれほど前ではありません。
次は、
2 ページの選択的な翻訳と、サンドボックス内からテンプレートエンジンを使用する方法です。
最初に、古い拡張機能をサポートするGoogleの計画について少し説明します
*次に、マニフェストのバージョン1で古い拡張機能拡張機能とアプリケーションを呼び出します(またはバージョンをまったく使用しません)。- Chrome 21以降、マニフェストの最初のバージョンでの新しい拡張機能の作成はブロックされますが、マニフェストの古いバージョンへの既存の拡張機能の更新は許可されています。
- Chrome 23のリリース(11月初旬)で、 Webストアは古いバージョンのマニフェストを使用した拡張機能への更新がブロックされます。 Chromeは、開発用に古い拡張機能のパックとアンパックされたもののロードを停止します。
- 2013年の第1四半期 -古い拡張機能は、Webストアではなくなります。 開発者にはメールで通知されます。
- 2013年の第2四半期 -古い拡張機能はすべてWebストアから削除され、開発者に別の通知が届きます。 ただし、Chromeはマニフェストバージョン1でインストールされている拡張機能をダウンロードして実行します。
- 2013年第3四半期 -Chromeは古い拡張機能をダウンロードして実行しなくなります。
マニフェストバージョン1と2の違い
- コンテンツセキュリティポリシーは 、デフォルトで
`script-src 'self'; object-src 'self'
に設定されています`script-src 'self'; object-src 'self'
`script-src 'self'; object-src 'self'
。 これは本質的に最も重要なアップデートです。 彼については少し後で。 - すべての拡張リソースは、URL
chrome-extension://[PACKAGE ID]/[PATH]
で使用できなくなりましたchrome-extension://[PACKAGE ID]/[PATH]
。 つまり 拡張機能自体を除き、他のページから拡張機能のスクリプトまたは画像を接続することはできません。 しかし、この欠点を回避するために、 web_accessible_resources
プロパティweb_accessible_resources
しました。このプロパティでweb_accessible_resources
、必要なリソースへのパスを含む配列を指定できます。 background_page
プロパティ(文字列)の代わりに、 scripts
またはpage
プロパティを持つオブジェクトを含むbackground
書き込むbackground
になりました。- ブラウザーアクションの変更:
browser_actions
フィールドはbrowser_action
に置き換えられ、 chrome.browserActions
APIはchrome.browserAction
chrome.browserActions
chrome.browserAction
。browser_action
からicons
プロパティをbrowser_action
。 代わりに、 default_icon
またはchrome.browserAction.setIcon
使用してchrome.browserAction.setIcon
。browser_action
からname
プロパティをbrowser_action
。 代わりに、 default_title
またはchrome.browserAction.setTitle
使用してchrome.browserAction.setTitle
。browser_action
からpopup
プロパティをbrowser_action
。 代わりに、 default_popup
またはchrome.browserAction.setPopup
使用してchrome.browserAction.setPopup
。browser_action
のdefault_popup
プロパティはオブジェクトではなく文字列でなければなりません
- ページアクションの変更:
page_actions
フィールドはpage_action
に置き換えられ、 chrome.pageActions
APIはchrome.pageAction
chrome.pageActions
chrome.pageAction
。page_action
からicons
プロパティをpage_action
。 代わりに、 default_icon
またはchrome.pageAction.setIcon
使用してchrome.pageAction.setIcon
。page_action
からname
プロパティをpage_action
。 代わりに、 default_title
またはchrome.pageAction.setTitle
使用してchrome.pageAction.setTitle
。page_action
からpopup
プロパティをpage_action
。 代わりに、 default_popup
またはchrome.pageAction.setPopup
使用してchrome.pageAction.setPopup
。page_action
のdefault_popup
プロパティは、オブジェクトではなく文字列である必要があります。- APIから
chrome.self
を削除しchrome.self
。現在はchrome.extension
を使用する必要があります。
chrome.extension.getTabContentses
とchrome.extension.getExtensionTabs
もうchrome.extension.getTabContentses
ありません。 代わりに、 chrome.extension.getViews({ "type": "tab" })
ます。
Port.tab
代わりにPort.tab
使用しPort.sender
。
拡張機能がXSS脆弱性の影響を受けにくくするために、CSPの一般原則が実装されています。 一般に、CSPは、拡張機能によってロードおよび実行されるリソースのホワイトリストおよびブラックリストメカニズムです。 CSPを使用すると、拡張機能に必要な権限のみを設定して、セキュリティを強化できます。
このポリシーは、
ホストのアクセス許可に対する追加の保護層です。
manifest.json
文字列パラメーター
content_security_policy
でセキュリティポリシーを設定できます。
マニフェストバージョン(
manifest_version
)がインストールされていない場合、デフォルトではコンテンツセキュリティポリシーはありません。 ただし、マニフェストの2番目のバージョンでは、デフォルトで
script-src 'self'; object-src 'self'
値でインストールされます
script-src 'self'; object-src 'self'
script-src 'self'; object-src 'self'
。 したがって、いくつかの制限があります。 たとえば、
eval
関数は実行されません。 また、インライン
(). - setTimeout setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
は実行されません
(). - setTimeout setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }
(). - setTimeout
setInterval
, .
, ( CDN, ), .
. (, https). content_security_policy
, :
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
“ eval?” “ ?”
- eval? (, new Function()
). ( sandbox ).
, (, eval) ( CSP ).
postMessage()
.
underscore
sandboxed/template-renderer.html
template-renderer.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sandboxed Template Renderer</title> <script src="/js/libs/underscore/underscore-min.js"></script> </head> <body> <script> var templates = {}; window.addEventListener('message', function (event) { var template; if (typeof templates[event.data.templateName] == 'undefined') { template = _.template(event.data.template); templates[event.data.templateName] = template; } else { template = templates[event.data.templateName]; } event.source.postMessage({ id: event.data.id, result: template(event.data.context) }, event.origin); }); </script> </html>
html
{ ..., "sandbox": { "pages": ["sandboxed/template-renderer.html"] }, ... }
function getTemplate var getTemplate = (function(){ var iframe = document.createElement('iframe'), callbacks = []; iframe.src = 'sandboxed/template-renderer.html'; iframe.style.display = 'none'; document.body.appendChild(iframe); window.addEventListener('message', function (event) { callbacks.forEach(function (item, idx) { if (item && item.id == event.data.id) { item.callback(event.data.result); delete callbacks[idx]; } }); }); return function (templateName, template) { return function (context, callback) { var id = Math.random(); callbacks.push({ id: id, callback: callback }); iframe.contentWindow.postMessage({ id: id, templateName: templateName, template: template, context: context }, '*'); }; }; }());
// , var template = getTemplate('templateId', templateContent); // - template({text: 'Hello world'}, function (html) { // html // $('body').html , // $('body').html(html); });
- . (). .
, manifest.json
:
manifest.json { "name": "Twittext", "description": "A lightweight Google Chrome extension for Twitter", "background": { "page": "background.html" }, "manifest_version": 2, "browser_action": { "default_icon": "img/icon_19.png", "default_title": "Twittext", "default_popup": "popup.html" }, "icons": { "128": "img/icon_128.png", "19": "img/icon_19.png", "48": "img/icon_48.png" }, "options_page": "options.html", "version": "1.6.1", "permissions": [ "tabs", "background", "https://api.twitter.com/", "https://userstream.twitter.com/" ], "sandbox": { "pages": ["sandboxed/template-renderer.html"] } }