Left: | ||
Right: |
OLD | NEW |
---|---|
(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 }); | |
OLD | NEW |