Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/snippets.js

Issue 29737561: Issue 6539, 6782 - Implement support for snippets (Closed) Base URL: https://hg.adblockplus.org/adblockpluschrome/
Patch Set: Add support for remote loading Created March 31, 2018, 11:55 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/requestBlocker.js ('k') | metadata.chrome » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 "use strict";
19
20 const {defaultMatcher} = require("matcher");
21 const {RegExpFilter, WhitelistFilter} = require("filterClasses");
22 const {verifySignature} = require("rsa");
23 const {extractHostFromFrame, getDecodedHostname,
24 isThirdParty, stringifyURL} = require("url");
25 const {checkWhitelisted} = require("whitelisting");
26 const {FilterNotifier} = require("filterNotifier");
27 const devtools = require("devtools");
28 const info = require("info");
29
30 const {typeMap} = RegExpFilter;
31
32 // Dummy public key and remote URL
Manish Jethani 2018/03/31 12:06:02 The key is only for illustration purposes. If you
33 const publicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALZc50pEXnz9TSRozwM04rryuaXl/ wgUFqV9FHq8HDlkdKvRU0hXhb/AKrSpCJ0NCxHtal1l/kHYlHG9e7Ev6+MCAwEAAQ==";
34 const remoteURL = "https://easylist-downloads.adblockplus.org/snippets.js";
35
36 let libraries = {local: "", remote: ""};
37 let executableCode = new Map();
38
39 function fetchText(url)
40 {
41 return fetch(url, {cache: "no-cache"}).then(response => response.text());
42 }
43
44 function updateLibrary(name, text)
45 {
46 libraries[name] = text;
47
48 executableCode.clear();
49 }
50
51 function checkLibrarySignature(url, text)
52 {
53 return fetchText(url + ".sig").then(
Manish Jethani 2018/03/31 12:06:02 Even though we load the code over a TLS connection
54 signature => verifySignature(publicKey, signature, text)
55 );
56 }
57
58 function loadLibrary(name, url, {verify = true} = {})
59 {
60 fetchText(url).then(text =>
61 {
62 if (text != libraries[name])
63 {
64 let check = verify ? checkLibrarySignature(url, text) :
65 Promise.resolve(true);
66 check.then(ok =>
67 {
68 if (ok)
69 updateLibrary(name, text);
70 });
71 }
72 });
73 }
74
75 function loadLocalLibrary()
76 {
77 loadLibrary("local", browser.extension.getURL("/snippets.js"),
78 {verify: false});
79 }
80
81 function loadRemoteLibrary()
82 {
83 loadLibrary("remote", remoteURL);
84 }
85
86 function getExecutableCode(snippet)
87 {
88 let code = executableCode.get(snippet);
89 if (code)
90 return code;
91
92 code = `
93 "use strict";
94 {
95 let localImports = Object.create(null);
96 let remoteImports = Object.create(null);
97 new Function("exports", ${JSON.stringify(libraries.local)})(
98 localImports
99 );
100 new Function("exports", ${JSON.stringify(libraries.remote)})(
101 remoteImports
102 );
103 let imports = Object.assign(Object.create(null),
Manish Jethani 2018/03/31 12:06:02 Remote imports override local imports.
104 localImports,
105 remoteImports);
106 let key = ${JSON.stringify(snippet)};
107 if (Object.prototype.hasOwnProperty.call(imports, key))
108 {
109 let value = imports[key];
110 if (typeof value == "function")
111 value();
112 }
113 }
114 `;
115
116 executableCode.set(snippet, code);
117 return code;
118 }
119
120 function injectCode(snippet, tabId, frameId)
121 {
122 browser.tabs.executeScript(tabId, {
123 code: getExecutableCode(snippet),
124 frameId,
125 matchAboutBlank: true,
126 runAt: "document_start"
127 });
128 }
129
130 loadLocalLibrary();
131
132 // Only Chrome supports dynamic loading of JS.
Manish Jethani 2018/03/31 12:06:03 According to Felix Mozilla doesn't allow loading J
133 if (info.platform == "chromium")
134 {
135 loadRemoteLibrary();
136
137 // Download every 24 hours.
138 setInterval(loadRemoteLibrary, 24 * 60 * 60 * 1000);
139 }
140
141 browser.webNavigation.onCommitted.addListener(details =>
142 {
143 // There's a bug in Chrome that causes webNavigation.onCommitted to get
144 // dispatched twice if there's a URL filter present, therefore we must listen
145 // for all URLs and do an explicit check here.
146 if (!/^https?:\/\//.test(details.url))
147 return;
148
149 let url = new URL(details.url);
150 let urlString = stringifyURL(url);
151 let parentFrame = ext.getFrame(details.tabId, details.parentFrameId);
152 let hostname = extractHostFromFrame(parentFrame) || getDecodedHostname(url);
153 let thirdParty = isThirdParty(url, hostname);
154
155 let filter = defaultMatcher.matchesAny(urlString, typeMap.SNIPPET, hostname,
156 thirdParty, null, true);
157 if (!filter)
158 return;
159
160 let page = new ext.Page({id: details.tabId, url: details.url});
161 let frame = ext.getFrame(details.tabId, details.frameId);
162
163 if (checkWhitelisted(page, frame))
164 return;
165
166 devtools.logRequest(page, urlString, "SNIPPET", hostname, thirdParty, null,
167 true, filter);
168 FilterNotifier.emit("filter.hitCount", filter, 0, 0, page);
169
170 if (filter instanceof WhitelistFilter)
171 return;
172
173 for (let snippet of filter.snippets)
174 injectCode(snippet, details.tabId, details.frameId);
175 });
OLDNEW
« no previous file with comments | « lib/requestBlocker.js ('k') | metadata.chrome » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld