| 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 window.ext = {}; |  | 
|   21  |  | 
|   22 let reportData = new DOMParser().parseFromString("<report></report>", "text/xml"
     ); |  | 
|   23  |  | 
|   24 let pages = { |  | 
|   25   "typeSelectorPage": [initTypeSelector, leaveTypeSelector], |  | 
|   26   "commentPage": [initCommentPage, leaveCommentPage], |  | 
|   27   "sendPage": [initSendPage, leaveSendPage] |  | 
|   28 }; |  | 
|   29  |  | 
|   30 document.addEventListener("DOMContentLoaded", () => |  | 
|   31 { |  | 
|   32   document.getElementById("cancel").addEventListener("click", () => |  | 
|   33   { |  | 
|   34     window.close(); |  | 
|   35   }); |  | 
|   36  |  | 
|   37   document.getElementById("continue").addEventListener("click", () => |  | 
|   38   { |  | 
|   39     if (!document.getElementById("continue").disabled) |  | 
|   40       pages[getCurrentPage()][1](); |  | 
|   41   }); |  | 
|   42  |  | 
|   43   document.addEventListener("keydown", event => |  | 
|   44   { |  | 
|   45     let blacklistedElements = new Set(["textarea", "button", "a"]) |  | 
|   46  |  | 
|   47     if (event.key == "Enter" && !blacklistedElements.has(event.target.localName)
     ) |  | 
|   48       document.getElementById("continue").click(); |  | 
|   49     else if (event.key == "Escape") |  | 
|   50       document.getElementById("cancel").click(); |  | 
|   51   }); |  | 
|   52  |  | 
|   53   browser.runtime.sendMessage({ |  | 
|   54     type: "app.get", |  | 
|   55     what: "doclink", |  | 
|   56     link: "reporter_privacy" |  | 
|   57   }).then(url => |  | 
|   58   { |  | 
|   59     document.getElementById("privacyPolicy").href = url; |  | 
|   60   }); |  | 
|   61  |  | 
|   62   initDataCollector(); |  | 
|   63 }); |  | 
|   64  |  | 
|   65 function getCurrentPage() |  | 
|   66 { |  | 
|   67   return document.querySelector(".page:not([hidden])").id; |  | 
|   68 } |  | 
|   69  |  | 
|   70 function setCurrentPage(pageId) |  | 
|   71 { |  | 
|   72   if (!pages.hasOwnProperty(pageId)) |  | 
|   73     return; |  | 
|   74  |  | 
|   75   let previousPage = document.querySelector(".page:not([hidden])"); |  | 
|   76   if (previousPage) |  | 
|   77     previousPage.hidden = true; |  | 
|   78  |  | 
|   79   document.getElementById(pageId).hidden = false; |  | 
|   80   pages[pageId][0](); |  | 
|   81 } |  | 
|   82  |  | 
|   83 function censorURL(url) |  | 
|   84 { |  | 
|   85   return url.replace(/([?;&\/#][^?;&\/#]+?=)[^?;&\/#]+/g, "$1*"); |  | 
|   86 } |  | 
|   87  |  | 
|   88 function encodeHTML(str) |  | 
|   89 { |  | 
|   90   return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").
     replace(/"/g, """); |  | 
|   91 } |  | 
|   92  |  | 
|   93 function serializeReportData() |  | 
|   94 { |  | 
|   95   let result = new XMLSerializer().serializeToString(reportData); |  | 
|   96  |  | 
|   97   // Insert line breaks before each new tag |  | 
|   98   result = result.replace(/(<[^\/]([^"<>]*|"[^"]*")*>)/g, "\n$1"); |  | 
|   99   result = result.replace(/^\n+/, ""); |  | 
|  100   return result; |  | 
|  101 } |  | 
|  102  |  | 
|  103 function retrieveAddonInfo() |  | 
|  104 { |  | 
|  105   let element = reportData.createElement("adblock-plus"); |  | 
|  106   return browser.runtime.sendMessage({ |  | 
|  107     type: "app.get", |  | 
|  108     what: "addonVersion" |  | 
|  109   }).then(addonVersion => |  | 
|  110   { |  | 
|  111     element.setAttribute("version", addonVersion); |  | 
|  112     return browser.runtime.sendMessage({ |  | 
|  113       type: "app.get", |  | 
|  114       what: "localeInfo" |  | 
|  115     }); |  | 
|  116   }).then(({locale}) => |  | 
|  117   { |  | 
|  118     element.setAttribute("locale", locale); |  | 
|  119     reportData.documentElement.appendChild(element); |  | 
|  120   }); |  | 
|  121 } |  | 
|  122  |  | 
|  123 function retrieveApplicationInfo() |  | 
|  124 { |  | 
|  125   let element = reportData.createElement("application"); |  | 
|  126   return browser.runtime.sendMessage({ |  | 
|  127     type: "app.get", |  | 
|  128     what: "application" |  | 
|  129   }).then(application => |  | 
|  130   { |  | 
|  131     element.setAttribute("name", application); |  | 
|  132     return browser.runtime.sendMessage({ |  | 
|  133       type: "app.get", |  | 
|  134       what: "applicationVersion" |  | 
|  135     }); |  | 
|  136   }).then(applicationVersion => |  | 
|  137   { |  | 
|  138     element.setAttribute("version", applicationVersion); |  | 
|  139     element.setAttribute("userAgent", navigator.userAgent); |  | 
|  140     reportData.documentElement.appendChild(element); |  | 
|  141   }); |  | 
|  142 } |  | 
|  143  |  | 
|  144 function retrievePlatformInfo() |  | 
|  145 { |  | 
|  146   let element = reportData.createElement("platform"); |  | 
|  147   return browser.runtime.sendMessage({ |  | 
|  148     type: "app.get", |  | 
|  149     what: "platform" |  | 
|  150   }).then(platform => |  | 
|  151   { |  | 
|  152     element.setAttribute("name", platform); |  | 
|  153     return browser.runtime.sendMessage({ |  | 
|  154       type: "app.get", |  | 
|  155       what: "platformVersion" |  | 
|  156     }); |  | 
|  157   }).then(platformVersion => |  | 
|  158   { |  | 
|  159     element.setAttribute("version", platformVersion); |  | 
|  160     reportData.documentElement.appendChild(element); |  | 
|  161   }); |  | 
|  162 } |  | 
|  163  |  | 
|  164 function retrieveTabURL(tabId) |  | 
|  165 { |  | 
|  166   return browser.tabs.get(tabId).then(tab => |  | 
|  167   { |  | 
|  168     let element = reportData.createElement("window"); |  | 
|  169     if (tab.url) |  | 
|  170       element.setAttribute("url", censorURL(tab.url)); |  | 
|  171     reportData.documentElement.appendChild(element); |  | 
|  172   }); |  | 
|  173 } |  | 
|  174  |  | 
|  175 function retrieveSubscriptions() |  | 
|  176 { |  | 
|  177   return browser.runtime.sendMessage({ |  | 
|  178     type: "subscriptions.get", |  | 
|  179     ignoreDisabled: true, |  | 
|  180     downloadable: true |  | 
|  181   }).then(subscriptions => |  | 
|  182   { |  | 
|  183     let element = reportData.createElement("subscriptions"); |  | 
|  184     for (let subscription of subscriptions) |  | 
|  185     { |  | 
|  186       if (!/^(http|https|ftp):/.test(subscription.url)) |  | 
|  187         continue; |  | 
|  188  |  | 
|  189       let now = Math.round(Date.now() / 1000); |  | 
|  190       let subscriptionElement = reportData.createElement("subscription"); |  | 
|  191       subscriptionElement.setAttribute("id", subscription.url); |  | 
|  192       if (subscription.lastDownload) |  | 
|  193         subscriptionElement.setAttribute("lastDownloadAttempt", subscription.las
     tDownload - now); |  | 
|  194       subscriptionElement.setAttribute("downloadStatus", subscription.downloadSt
     atus); |  | 
|  195       element.appendChild(subscriptionElement); |  | 
|  196     } |  | 
|  197     reportData.documentElement.appendChild(element); |  | 
|  198   }); |  | 
|  199 } |  | 
|  200  |  | 
|  201 function initDataCollector() |  | 
|  202 { |  | 
|  203   Promise.resolve().then(() => |  | 
|  204   { |  | 
|  205     let tabId = parseInt(location.search.replace(/^\?/, ""), 10) || 0; |  | 
|  206     let handlers = [ |  | 
|  207       retrieveAddonInfo(), |  | 
|  208       retrieveApplicationInfo(), |  | 
|  209       retrievePlatformInfo(), |  | 
|  210       retrieveTabURL(tabId), |  | 
|  211       retrieveSubscriptions() |  | 
|  212     ]; |  | 
|  213     return Promise.all(handlers); |  | 
|  214   }).then(() => |  | 
|  215   { |  | 
|  216     setCurrentPage("typeSelectorPage"); |  | 
|  217   }).catch(e => |  | 
|  218   { |  | 
|  219     if (!e.name && e.message) |  | 
|  220       e = e.message; |  | 
|  221     alert(e); |  | 
|  222     window.close(); |  | 
|  223   }); |  | 
|  224 } |  | 
|  225  |  | 
|  226 function initTypeSelector() |  | 
|  227 { |  | 
|  228   document.getElementById("typeFalsePositive").focus(); |  | 
|  229  |  | 
|  230  |  | 
|  231   for (let checkbox of document.querySelectorAll("input[name='type']")) |  | 
|  232   { |  | 
|  233     checkbox.addEventListener("click", () => |  | 
|  234     { |  | 
|  235       if (document.querySelector("input[name='type']:checked")) |  | 
|  236         document.getElementById("continue").disabled = false; |  | 
|  237     }); |  | 
|  238   } |  | 
|  239 } |  | 
|  240  |  | 
|  241 function leaveTypeSelector() |  | 
|  242 { |  | 
|  243   let checkbox = document.querySelector("input[name='type']:checked"); |  | 
|  244   reportData.documentElement.setAttribute("type", checkbox.value); |  | 
|  245   setCurrentPage("commentPage"); |  | 
|  246 } |  | 
|  247  |  | 
|  248 function initCommentPage() |  | 
|  249 { |  | 
|  250   let continueButton = document.getElementById("continue"); |  | 
|  251   continueButton.disabled = true; |  | 
|  252   continueButton.textContent = browser.i18n.getMessage("issueReporter_sendButton
     _label"); |  | 
|  253  |  | 
|  254   let emailElement = reportData.createElement("email"); |  | 
|  255   let emailField = document.getElementById("email"); |  | 
|  256   let anonymousSubmissionField = document.getElementById("anonymousSubmission"); |  | 
|  257   let validateEmail = () => |  | 
|  258   { |  | 
|  259     document.getElementById("anonymousSubmissionWarning").setAttribute("data-inv
     isible", !anonymousSubmissionField.checked); |  | 
|  260     if (anonymousSubmissionField.checked) |  | 
|  261     { |  | 
|  262       emailField.value = ""; |  | 
|  263       emailField.disabled = true; |  | 
|  264       continueButton.disabled = false; |  | 
|  265       if (emailElement.parentNode) |  | 
|  266         emailElement.parentNode.removeChild(emailElement); |  | 
|  267     } |  | 
|  268     else |  | 
|  269     { |  | 
|  270       emailField.disabled = false; |  | 
|  271  |  | 
|  272       let value = emailField.value.trim(); |  | 
|  273       emailElement.textContent = value; |  | 
|  274       reportData.documentElement.appendChild(emailElement); |  | 
|  275       continueButton.disabled = value == "" || !emailField.validity.valid; |  | 
|  276     } |  | 
|  277   }; |  | 
|  278   emailField.addEventListener("input", validateEmail); |  | 
|  279   anonymousSubmissionField.addEventListener("click", validateEmail); |  | 
|  280  |  | 
|  281   let commentElement = reportData.createElement("comment"); |  | 
|  282   document.getElementById("comment").addEventListener("input", event => |  | 
|  283   { |  | 
|  284     if (commentElement.parentNode) |  | 
|  285       commentElement.parentNode.removeChild(commentElement); |  | 
|  286  |  | 
|  287     let value = event.target.value.trim(); |  | 
|  288     commentElement.textContent = value.substr(0, 1000); |  | 
|  289     if (value) |  | 
|  290       reportData.documentElement.appendChild(commentElement); |  | 
|  291     document.getElementById("commentLengthWarning").setAttribute("data-invisible
     ", value.length <= 1000); |  | 
|  292   }); |  | 
|  293  |  | 
|  294   document.getElementById("showData").addEventListener("click", event => |  | 
|  295   { |  | 
|  296     event.preventDefault(); |  | 
|  297  |  | 
|  298     // window.open() won't open data: URIs in Chrome |  | 
|  299     browser.tabs.getCurrent().then(tab => |  | 
|  300     { |  | 
|  301       browser.tabs.create({ |  | 
|  302         url: "data:text/xml;charset=utf-8," + encodeURIComponent(serializeReport
     Data()), |  | 
|  303         openerTabId: tab.id |  | 
|  304       }); |  | 
|  305     }) |  | 
|  306   }); |  | 
|  307  |  | 
|  308   emailField.focus(); |  | 
|  309 } |  | 
|  310  |  | 
|  311 function leaveCommentPage() |  | 
|  312 { |  | 
|  313   setCurrentPage("sendPage"); |  | 
|  314 } |  | 
|  315  |  | 
|  316 function initSendPage() |  | 
|  317 { |  | 
|  318   document.getElementById("cancel").hidden = true; |  | 
|  319  |  | 
|  320   let continueButton = document.getElementById("continue"); |  | 
|  321   continueButton.textContent = browser.i18n.getMessage("issueReporter_doneButton
     _label"); |  | 
|  322   continueButton.disabled = true; |  | 
|  323  |  | 
|  324   let uuid = new Uint16Array(8); |  | 
|  325   window.crypto.getRandomValues(uuid); |  | 
|  326   uuid[3] = uuid[3] & 0x0FFF | 0x4000;  // version 4 |  | 
|  327   uuid[4] = uuid[4] & 0x3FFF | 0x8000;  // variant 1 |  | 
|  328  |  | 
|  329   let uuidString = ""; |  | 
|  330   for (let i = 0; i < uuid.length; i++) |  | 
|  331   { |  | 
|  332     let component = uuid[i].toString(16); |  | 
|  333     while (component.length < 4) |  | 
|  334       component = "0" + component; |  | 
|  335     uuidString += component; |  | 
|  336     if (i >= 1 && i<= 4) |  | 
|  337       uuidString += "-"; |  | 
|  338   } |  | 
|  339  |  | 
|  340   let params = new URLSearchParams({ |  | 
|  341     version: 1, |  | 
|  342     guid: uuidString, |  | 
|  343     lang: reportData.getElementsByTagName("adblock-plus")[0].getAttribute("local
     e") |  | 
|  344   }); |  | 
|  345   let url = "https://reports.adblockplus.org/submitReport?" + params; |  | 
|  346  |  | 
|  347   let reportSent = event => |  | 
|  348   { |  | 
|  349     let success = false; |  | 
|  350     let errorMessage = browser.i18n.getMessage("filters_subscription_lastDownloa
     d_connectionError"); |  | 
|  351     try |  | 
|  352     { |  | 
|  353       success = request.status == 200; |  | 
|  354       if (request.status != 0) |  | 
|  355         errorMessage = request.status + " " + request.statusText; |  | 
|  356     } |  | 
|  357     catch (e) |  | 
|  358     { |  | 
|  359       // Getting request status might throw if no connection was established |  | 
|  360     } |  | 
|  361  |  | 
|  362     let result; |  | 
|  363     try |  | 
|  364     { |  | 
|  365       result = request.responseText; |  | 
|  366     } |  | 
|  367     catch (e) |  | 
|  368     { |  | 
|  369       result = ""; |  | 
|  370     } |  | 
|  371  |  | 
|  372     if (!success) |  | 
|  373     { |  | 
|  374       let errorElement = document.getElementById("error"); |  | 
|  375       let template = browser.i18n.getMessage("issueReporter_errorMessage").repla
     ce(/[\r\n\s]+/g, " "); |  | 
|  376  |  | 
|  377       let [, beforeLink, linkText, afterLink] = /(.*)\[link\](.*)\[\/link\](.*)/
     .exec(template) || [null, "", template, ""]; |  | 
|  378       beforeLink = beforeLink.replace(/\?1\?/g, errorMessage); |  | 
|  379       afterLink = afterLink.replace(/\?1\?/g, errorMessage); |  | 
|  380  |  | 
|  381       while (errorElement.firstChild) |  | 
|  382         errorElement.removeChild(errorElement.firstChild); |  | 
|  383  |  | 
|  384       let link = document.createElement("a"); |  | 
|  385       link.textContent = linkText; |  | 
|  386       browser.runtime.sendMessage({ |  | 
|  387         type: "app.get", |  | 
|  388         what: "doclink", |  | 
|  389         link: "reporter_connect_issue" |  | 
|  390       }).then(url => |  | 
|  391       { |  | 
|  392         link.href = url; |  | 
|  393       }); |  | 
|  394  |  | 
|  395  |  | 
|  396       errorElement.appendChild(document.createTextNode(beforeLink)); |  | 
|  397       errorElement.appendChild(link); |  | 
|  398       errorElement.appendChild(document.createTextNode(afterLink)); |  | 
|  399  |  | 
|  400       errorElement.hidden = false; |  | 
|  401     } |  | 
|  402  |  | 
|  403     result = result.replace(/%CONFIRMATION%/g, encodeHTML(browser.i18n.getMessag
     e("issueReporter_confirmationMessage"))); |  | 
|  404     result = result.replace(/%KNOWNISSUE%/g, encodeHTML(browser.i18n.getMessage(
     "issueReporter_knownIssueMessage"))); |  | 
|  405     result = result.replace(/(<html)\b/, '$1 dir="' + encodeHTML(window.getCompu
     tedStyle(document.documentElement, "").direction + '"')); |  | 
|  406  |  | 
|  407     document.getElementById("sendReportMessage").hidden = true; |  | 
|  408     document.getElementById("sendingProgressContainer").hidden = true; |  | 
|  409  |  | 
|  410     let resultFrame = document.getElementById("result"); |  | 
|  411     resultFrame.setAttribute("src", "data:text/html;charset=utf-8," + encodeURIC
     omponent(result)); |  | 
|  412     resultFrame.hidden = false; |  | 
|  413  |  | 
|  414     document.getElementById("continue").disabled = false; |  | 
|  415   }; |  | 
|  416  |  | 
|  417   let request = new XMLHttpRequest(); |  | 
|  418   request.open("POST", url); |  | 
|  419   request.setRequestHeader("Content-Type", "text/xml"); |  | 
|  420   request.setRequestHeader("X-Adblock-Plus", "1"); |  | 
|  421   request.addEventListener("load", reportSent); |  | 
|  422   request.addEventListener("error", reportSent); |  | 
|  423   request.upload.addEventListener("progress", event => |  | 
|  424   { |  | 
|  425     if (!event.lengthComputable) |  | 
|  426       return; |  | 
|  427  |  | 
|  428     let progress = Math.round(event.loaded / event.total * 100); |  | 
|  429     if (event.loaded > 0) |  | 
|  430     { |  | 
|  431       let progress = document.getElementById("sendingProgress"); |  | 
|  432       progress.max = event.total; |  | 
|  433       progress.value = event.loaded; |  | 
|  434     } |  | 
|  435   }); |  | 
|  436   request.send(serializeReportData()); |  | 
|  437 } |  | 
|  438  |  | 
|  439 function leaveSendPage() |  | 
|  440 { |  | 
|  441   window.close(); |  | 
|  442 } |  | 
| OLD | NEW |