πŸ“œ ⬆️ ⬇️

We translate Chrome extension to manifest_version 2

The owners of extensions (as well as applications) for Chrome should have thought about supporting the second version of the manifest.
If someone does not know, not so long ago new changes and innovations were announced in the development of browser extensions.
Next will be a selective translation of two pages and my way of using the template engine from within the sandbox.


First, a little about Google 's plans to support the old extensions


* Next, the old extensions will be called extensions and applications with version 1 of the manifest (or no version at all).


')

Differences between versions 1 and 2





Content Security Policy (CSP)



For extensions to be less prone to XSS vulnerabilities, common CSP principles were introduced. In general, the CSP is a mechanism for the white and black lists regarding resources that are loaded and executed by the extension. With CSP, you can set only the necessary permissions for the extension and thus increase its security.
This policy is an additional level of protection over rights to access resources ( host permissions )

You can set the security policy in the string parameter content_security_policy in manifest.json .
If the manifest version is not installed ( manifest_version ), then by default there is no content security policy. But for the second version of the manifest, it is installed by default with the value script-src 'self'; object-src 'self' script-src 'self'; object-src 'self' . Therefore, there are some limitations. For example, the eval function will fail. Also, inline (). - 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"] } }
will not be executed (). - 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"] } }

Source: https://habr.com/ru/post/149948/


All Articles