Chrome拡張機能をmanifest_version 2に変換します

Chromeの拡張機能(およびアプリケーション)の所有者は、マニフェストの2番目のバージョンをサポートすることを検討します。

誰かが知らない場合、ブラウザ拡張機能の開発における新しい変更と革新が発表されたのはそれほど前ではありません。

次は、 2 ページの選択的な翻訳と、サンドボックス内からテンプレートエンジンを使用する方法です。





最初に、古い拡張機能をサポートするGoogle計画について少し説明します



*次に、マニフェストのバージョン1で古い拡張機能拡張機能とアプリケーションを呼び出します(またはバージョンをまったく使用しません)。







マニフェストバージョン1と2の違い









コンテンツセキュリティポリシー (CSP)





拡張機能が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"] } }











  1. (). - 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"] } }











  2. (). - 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"] } }











  3. (). - 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"] } }











  4. (). - 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"] } }














All Articles