OLD | NEW |
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-present eyeo GmbH | 3 * Copyright (C) 2006-present eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 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 | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 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/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
16 */ | 16 */ |
17 | 17 |
18 "use strict"; | 18 "use strict"; |
19 | 19 |
20 const publicSuffixes = require("../data/publicSuffixList.json"); | 20 const publicSuffixes = require("../data/publicSuffixList.json"); |
21 | 21 |
22 /** | 22 /** |
| 23 * Map of public suffixes to their offsets. |
| 24 * @type {Map.<string,number>} |
| 25 */ |
| 26 let publicSuffixMap = buildPublicSuffixMap(); |
| 27 |
| 28 /** |
| 29 * Builds a map of public suffixes to their offsets. |
| 30 * @returns {Map.<string,number>} |
| 31 */ |
| 32 function buildPublicSuffixMap() |
| 33 { |
| 34 let map = new Map(); |
| 35 |
| 36 for (let key in publicSuffixes) |
| 37 map.set(key, publicSuffixes[key]); |
| 38 |
| 39 return map; |
| 40 } |
| 41 |
| 42 /** |
| 43 * Yields all suffixes for a domain. For example, given the domain |
| 44 * <code>www.example.com</code>, this function yields |
| 45 * <code>www.example.com</code>, <code>example.com</code>, and |
| 46 * <code>com</code>, in that order. |
| 47 * |
| 48 * @param {string} domain The domain. |
| 49 * @yields {string} The next suffix for the domain. |
| 50 */ |
| 51 function* suffixes(domain) |
| 52 { |
| 53 while (domain != "") |
| 54 { |
| 55 yield domain; |
| 56 |
| 57 let dotIndex = domain.indexOf("."); |
| 58 domain = dotIndex == -1 ? "" : domain.substr(dotIndex + 1); |
| 59 } |
| 60 } |
| 61 |
| 62 /** |
23 * Checks whether the given hostname is a domain. | 63 * Checks whether the given hostname is a domain. |
24 * | 64 * |
25 * @param {string} hostname | 65 * @param {string} hostname |
26 * @returns {boolean} | 66 * @returns {boolean} |
27 */ | 67 */ |
28 function isDomain(hostname) | 68 function isDomain(hostname) |
29 { | 69 { |
30 // No hostname or IPv4 address, also considering hexadecimal octets. | 70 // No hostname or IPv4 address, also considering hexadecimal octets. |
31 if (/^((0x[\da-f]+|\d+)(\.|$))*$/i.test(hostname)) | 71 if (/^((0x[\da-f]+|\d+)(\.|$))*$/i.test(hostname)) |
32 return false; | 72 return false; |
33 | 73 |
34 // IPv6 address. Since there can't be colons in domains, we can | 74 // IPv6 address. Since there can't be colons in domains, we can |
35 // just check whether there are any colons to exclude IPv6 addresses. | 75 // just check whether there are any colons to exclude IPv6 addresses. |
36 return hostname.indexOf(":") == -1; | 76 return hostname.indexOf(":") == -1; |
37 } | 77 } |
38 | 78 |
39 /** | 79 /** |
40 * Gets the base domain for the given hostname. | 80 * Gets the base domain for the given hostname. |
41 * | 81 * |
42 * @param {string} hostname | 82 * @param {string} hostname |
43 * @returns {string} | 83 * @returns {string} |
44 */ | 84 */ |
45 function getDomain(hostname) | 85 function getDomain(hostname) |
46 { | 86 { |
47 let bits = hostname.split("."); | 87 let slices = []; |
48 let cutoff = bits.length - 2; | 88 let cutoff = null; |
49 | 89 |
50 for (let i = 0; i < bits.length; i++) | 90 for (let suffix of suffixes(hostname)) |
51 { | 91 { |
52 let offset = publicSuffixes[bits.slice(i).join(".")]; | 92 slices.push(suffix); |
| 93 |
| 94 let offset = publicSuffixMap.get(suffix); |
53 | 95 |
54 if (typeof offset != "undefined") | 96 if (typeof offset != "undefined") |
55 { | 97 { |
56 cutoff = i - offset; | 98 cutoff = slices.length - 1 - offset; |
57 break; | 99 break; |
58 } | 100 } |
59 } | 101 } |
60 | 102 |
| 103 if (cutoff == null) |
| 104 return slices.length > 2 ? slices[slices.length - 2] : hostname; |
| 105 |
61 if (cutoff <= 0) | 106 if (cutoff <= 0) |
62 return hostname; | 107 return hostname; |
63 | 108 |
64 return bits.slice(cutoff).join("."); | 109 return slices[cutoff]; |
65 } | 110 } |
66 | 111 |
| 112 exports.getDomain = getDomain; |
| 113 |
67 /** | 114 /** |
68 * Checks whether a request's origin is different from its document's origin. | 115 * Checks whether a request's origin is different from its document's origin. |
69 * | 116 * |
70 * @param {URL} url The request URL. | 117 * @param {URL} url The request URL. |
71 * @param {string} documentHostname The IDNA-encoded hostname of the document. | 118 * @param {string} documentHostname The IDNA-encoded hostname of the document. |
72 * | 119 * |
73 * @returns {boolean} | 120 * @returns {boolean} |
74 */ | 121 */ |
75 function isThirdParty(url, documentHostname) | 122 function isThirdParty(url, documentHostname) |
76 { | 123 { |
77 let requestHostname = url.hostname.replace(/\.+$/, ""); | 124 let requestHostname = url.hostname; |
78 documentHostname = documentHostname.replace(/\.+$/, ""); | 125 |
| 126 if (requestHostname[requestHostname.length - 1] == ".") |
| 127 requestHostname = requestHostname.replace(/\.+$/, ""); |
| 128 |
| 129 if (documentHostname[documentHostname.length - 1] == ".") |
| 130 documentHostname = documentHostname.replace(/\.+$/, ""); |
79 | 131 |
80 if (requestHostname == documentHostname) | 132 if (requestHostname == documentHostname) |
81 return false; | 133 return false; |
82 | 134 |
83 if (!isDomain(requestHostname) || !isDomain(documentHostname)) | 135 if (!isDomain(requestHostname) || !isDomain(documentHostname)) |
84 return true; | 136 return true; |
85 | 137 |
86 return getDomain(requestHostname) != getDomain(documentHostname); | 138 return getDomain(requestHostname) != getDomain(documentHostname); |
87 } | 139 } |
88 | 140 |
89 exports.isThirdParty = isThirdParty; | 141 exports.isThirdParty = isThirdParty; |
OLD | NEW |