#
msgid ""
msgstr ""
"PO-Revision-Date: 2024-06-26 16:09+0000\n"
"Last-Translator: Ana Isabel Carvalho <ana@manufacturaindependente.org>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/jshelter/"
"website-posts/pt/>\n"
"Language: pt\n"
"Content-Type: text/plain; charset=utf-8\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 5.6-rc\n"
"Content-Transfer-Encoding: 8bit\n"

#: ../content/posts/cooperation.md:block 1 (header)
msgid ""
"title: Cooperation with the JShelter project, rebranding, and latest features\n"
"date: 2022-03-17 15:00\n"
"Series: JShelter background"
msgstr ""

#: ../content/posts/cooperation.md:block 2 (paragraph)
msgid ""
"This project started as JavaScript Restrictor at [Brno University of "
"Technology](https://www.fit.vut.cz). As announced in [a previous "
"post](/support), we got funding from NLNet [NGI0 PET "
"Fund](https://nlnet.nl/project/JSRestrictor/). Furthermore, NLNet allowed us"
" to cooperate with another NGI0 PET Fund project - [JShelter project "
"(formerly known as JavaScript Shield project) run by Free Software "
"Foundation](https://nlnet.nl/project/JavascriptShield/)."
msgstr ""

#: ../content/posts/cooperation.md:block 3 (paragraph)
msgid ""
"What did the cooperation bring to the users? More experience, more "
"developers, new ideas. Let us go through the list."
msgstr ""

#: ../content/posts/cooperation.md:block 4 (header)
msgid "1. Open development"
msgstr ""

#: ../content/posts/cooperation.md:block 5 (paragraph)
msgid ""
"We created [mailing list](https://lists.nongnu.org/archive/html/js-shield/) "
"where we discussed the core issues of the development of the extension. We "
"held weekly meetings with the minutes available in the mailing list "
"archives."
msgstr ""

#: ../content/posts/cooperation.md:block 6 (header)
msgid "2. Integration of NoScript Common Library"
msgstr ""

#: ../content/posts/cooperation.md:block 7 (paragraph)
msgid ""
"Giorgio Maone, the developer of NoScript Suite, is a part of the JShelter "
"project. His recent efforts were in developing NoScript Common Library "
"(NSCL). The library aims at simplifying the development of privacy and "
"security-oriented web extensions with cross-browser support."
msgstr ""

#: ../content/posts/cooperation.md:block 8 (paragraph)
msgid ""
"Giorgio refactored the defence mechanism code injection and cross-browser "
"support. Both now depend on NSCL."
msgstr ""

#: ../content/posts/cooperation.md:block 9 (paragraph)
msgid ""
"The improved code injection solved several long-term issues of the previous "
"mechanism like (1) the uncertainty that the defences are inserted in time "
"before page scripts have access to the environment and (2) the vulnerability"
" to [Firefox bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1267027) that"
" did not allow to insert (full) defenses for pages relying on [CSP "
"headers](https://content-security-policy.com/)."
msgstr ""

#: ../content/posts/cooperation.md:block 10 (paragraph)
msgid ""
"Improved cross-browser support should make the future lives of developers "
"easier. Should there be a change like the switch to Manifest3, we will "
"benefit from the effort put into NSCL."
msgstr ""

#: ../content/posts/cooperation.md:block 11 (header)
msgid "3. Development of a new site"
msgstr ""

#: ../content/posts/cooperation.md:block 12 (paragraph)
msgid ""
"[Manufactura Independente](https://manufacturaindependente.org/), another "
"participant of JShelter, created a new website for the extension, see "
"<https://jshelter.org/>. Besides the polished structure and look, the new "
"website allows generating documentation for the Javascript Shield wrappers "
"directly from the comments in the source code. We do not have automatic "
"updates, yet. But we are working on that."
msgstr ""

#: ../content/posts/cooperation.md:block 13 (header)
msgid "4. Improved user interface"
msgstr ""

#: ../content/posts/cooperation.md:block 14 (paragraph)
msgid ""
"The original method of assigning JavaScript Shield levels of protection to "
"each domain is nice to explain and should be easy to understand for users. "
"However, as the number of protected APIs grew, it became clear that we "
"needed to fine-tune the protection for each page for power users. For "
"example, allow Geolocation API for maps or allow Media Devices on a video "
"call application."
msgstr ""

#: ../content/posts/cooperation.md:block 15 (paragraph)
msgid ""
"The user often had to create a new level for each misbehaving domain. With "
"time, the amount of levels becomes overwhelming, and the user needs to keep "
"them in sync with the addition of the new APIs. Each version of the "
"extension that adds new wrappers tries to guess how to modify user-defined "
"levels to ease this task. But these modifications are not perfect."
msgstr ""

#: ../content/posts/cooperation.md:block 16 (paragraph)
msgid ""
"0.7 brought a redesigned UI and backend that allows fine-tuning JavaScript "
"Shield protection for each domain. The new UI is a result of the effort of "
"most of the developers of the extension."
msgstr ""

#: ../content/posts/cooperation.md:block 17 (paragraph)
msgid "![visited page]({attach}/images/cooperation/fine-tuning.png)"
msgstr ""

#: ../content/posts/cooperation.md:block 18 (paragraph)
msgid ""
"0.6 introduced Fingerprint Detector that was improved in 0.8. The pop up "
"shows the number of potentially suspicious calls and the likelihood of "
"fingerprinting behaviour. The fingerprint report provides an explanation "
"about the fingerprinting activities. Marek Saloň is the main author of the "
"Fingerprint Detector."
msgstr ""

#: ../content/posts/cooperation.md:block 19 (paragraph)
msgid ""
"![FPD report shows the reasoning to claim that a page is fingerprinting the "
"browser]({attach}/images/cooperation/fpd-report.png)"
msgstr ""

#: ../content/posts/cooperation.md:block 20 (paragraph)
msgid ""
"Marek also improved notifications so that the user cannot be overwhelmed by "
"many similar notifications during a very short period. Starting from 0.8, it"
" is also possible to use the extension for passive monitoring of page "
"activities without active modifications to the JavaScript environment. "
"Network Boundary Shield cannot be turned into notify mode, but it is very "
"rare to find a page accessing a local network. This configuration should not"
" break any page, the user is not protected from fingerprinting, but the "
"extension notifies about suspicious activities."
msgstr ""

#: ../content/posts/cooperation.md:block 21 (paragraph)
msgid ""
"![Almost passive configuration of the "
"extension]({attach}/images/cooperation/almost-passive.png)"
msgstr ""

#: ../content/posts/cooperation.md:block 22 (header)
msgid "5. Publicity"
msgstr ""

#: ../content/posts/cooperation.md:block 23 (paragraph)
msgid ""
"At the beginning of 2021, we only had a handful of users. When FSF "
"[announced the project](https://www.fsf.org/news/fsf-announces-jshelter-"
"browser-add-on-to-combat-threats-from-nonfree-javascript) the number of "
"users raised. We managed to retain about 75% of the peek of Firefox and "
"Chrome users. See graphs below."
msgstr ""

#: ../content/posts/cooperation.md:block 24 (paragraph)
msgid "The number of daily users with Firefox browser:"
msgstr ""

#: ../content/posts/cooperation.md:block 25 (paragraph)
msgid ""
"![30th, some users left afterwards]({attach}/images/cooperation/firefox-"
"daily-2022-03-17.png)"
msgstr ""

#: ../content/posts/cooperation.md:block 26 (paragraph)
msgid "The number of weekly users with Chrome browser:"
msgstr ""

#: ../content/posts/cooperation.md:block 27 (paragraph)
msgid ""
"![We managed to keep most of the Chrome "
"users]({attach}/images/cooperation/chrome-weekly-2022-03-17.png)"
msgstr ""

#: ../content/posts/cooperation.md:block 28 (paragraph)
msgid ""
"The more users we have, the more bugs are found and the more likely we "
"receive contributions from other parties. Also, keep in mind that some "
"defences against fingerprinting work best when many users employ the "
"defences. So it is beneficial for everyone to have as many users as "
"possible."
msgstr ""

#: ../content/posts/cooperation.md:block 29 (header)
msgid "6. New name, rebranding"
msgstr ""

#: ../content/posts/cooperation.md:block 30 (paragraph)
msgid ""
"The cooperation initially started between JavaScript Restrictor and "
"JavaScript Shield project. We thought about several rebranding options for "
"the project to give users a warm feeling of safety. Starting from 0.7 the "
"extension is called JShelter, uses a more privacy-friendly repository, and "
"we already had a new crab icon in the late 0.5 releases."
msgstr ""

#: ../content/posts/cooperation.md:block 31 (paragraph)
msgid ""
"We intend to keep the current infrastructure like the Github repository "
"intact. All Github pages links should work and are redirected to the new "
"website."
msgstr ""

#: ../content/posts/crawling.md:block 1 (header)
msgid ""
"title: Measurement of JavaScript API usage on the web\n"
"date: 2021-03-30 14:00\n"
"Series: JavaScript API usage"
msgstr ""

#: ../content/posts/crawling.md:block 2 (paragraph)
msgid ""
"The world wide web is a complex environment. Web pages can access many APIs "
"ranging from text formatting to access to nearby Bluetooth devices. While "
"many APIs are used for legitimate purposes, some are misused to track and "
"identify their users without their knowledge. In this paper, we propose a "
"methodology to measure the usage of JavaScript APIs on the public web. The "
"methodology consists of an automated visit of several thousand websites and "
"intercepting JavaScript calls performed by the pages. We also provide a "
"design and architecture of a measurement platform that can be used for an "
"automated visit of a list of websites. The proposed platform is based on "
"OpenWPM. The browser is instrumented by OpenWPM and a customized Web API "
"Manager extension is responsible for capturing JavaScript API calls."
msgstr ""

#: ../content/posts/crawling.md:block 3 (header)
msgid "Introduction"
msgstr ""

#: ../content/posts/crawling.md:block 4 (paragraph)
msgid ""
"Web browsers offer a wide range of possibilities. on the surface they *just*"
" display web pages, but under the hood, web browsers provide a bridge "
"between a viewed page and the host operating system. A web browser allows a "
"web page to access information like values from sensors, information about "
"battery status, installed fonts, and much more. The advertisement industry "
"often takes advantage of the wide range of information provided by web "
"browsers to create a web browser [fingerprint](https://amiunique.org/links)."
" Most commonly, the fingeprinters misuse Web APIs (also called JavaScript "
"APIs)."
msgstr ""

#: ../content/posts/crawling.md:block 5 (paragraph)
msgid ""
"This blog post is mainly concerned with user tracking and fingerprinting. "
"For example Battery Status API implementation on Mozilla Firefox revealed "
"very precise value allowing the trackers to identify the user for a [period "
"of time](https://petsymposium.org/2017/papers/hotpets/batterystatus-not-"
"included.pdf). As the Battery Status API was used heavily for "
"fingerprinting, it has been removed from Mozilla Firefox in 2017. Other "
"examples of JavaScript APIs that are used often for fingerprinting are "
"[Canvas API](http://cseweb.ucsd.edu/~hovav/papers/ms12.html), [Audio "
"API](https://senglehardt.com/papers/princeton_phd_dissertation_englehardt.pdf),"
" [Permissions API](https://arxiv.org/abs/2008.04480) or [APIs for device "
"sensors](https://dl.acm.org/doi/10.1145/3243734.3243860)."
msgstr ""

#: ../content/posts/crawling.md:block 6 (paragraph)
msgid ""
"In our work, we aim to measure the JavaScript APIs usage by popular "
"websites. In this article, we present core technologies to accomplish these "
"measurements. The stack of technologies is based on "
"[OpenWPM](https://github.com/mozilla/OpenWPM) enriched by a browser "
"extension, that allows us to intercept JavaScript calls of different APIs. "
"This browser extension is based on Proxy objects."
msgstr ""

#: ../content/posts/crawling.md:block 7 (paragraph)
msgid ""
"Our work is based on work of [Peter Snyders et "
"al.](https://www3.cs.uic.edu/pub/Bits/PeterSnyder/Browser_Feature_Usage_on_the_Modern_Web.pdf)"
" carried in 2016. Since then many new APIs were specified and implemented in"
" web browsers, see the figure below (based on data from [Can I Use? "
"website](https://caniuse.com/))."
msgstr ""

#: ../content/posts/crawling.md:block 8 (paragraph)
msgid ""
"![Progress of Web APIs amount implemented in distinct browsers in "
"time.]({attach}/images/crawling-apis.png)"
msgstr ""

#: ../content/posts/crawling.md:block 9 (header)
msgid "Methodology proposal"
msgstr ""

#: ../content/posts/crawling.md:block 10 (paragraph)
msgid ""
"This section describes the methodology that we plan to use. This methodology"
" is based on As it is based on the work of Peter Snyders, it is already "
"validated. Moreover, using a methodology that is very close to the original "
"one should show us a difference in the usage of the JavaScript APIs in 2016 "
"and 2021."
msgstr ""

#: ../content/posts/crawling.md:block 11 (paragraph)
msgid ""
"The main idea of the measurement is to visit several thousands of the most "
"[popular pages](https://tranco-list.eu/#aboutus) on the internet and "
"intercept as many JavaScript calls as possible."
msgstr ""

#: ../content/posts/crawling.md:block 12 (paragraph)
msgid ""
"Visiting websites will be performed through Mozilla Firefox with an "
"extension that intercepts and logs the JavaScript calls. We will visit not "
"only the landing page but also the subset of subpages of each website. From "
"the landing page, we will extract three links that point to a subpage of a "
"given page. From each of these three subpages, we will get another three "
"subpage links resulting in up to 13 pages of a given website being visited. "
"This amount of pages should be high enough to catch the most of JavaScript "
"calls. We will wait and intercept JavaScript calls for 30 seconds on each "
"page to wait of API calls performed during the page load."
msgstr ""

#: ../content/posts/crawling.md:block 13 (paragraph)
msgid ""
"Results of our measurements should also provide information about the "
"JavaScript APIs, that were probably used in a manner, that is not necessary "
"for a page to be working and is very likely used in a way, that the user "
"would not find useful. To achieve this,"
msgstr ""

#: ../content/posts/crawling.md:block 14 (paragraph)
msgid ""
"We will run our measurements on every page in two different modes. Firstly, "
"we will visit the page using the a browser withou adblocker. Later, we will "
"also employ an adblocker. Hence, the study will show the difference API "
"usage of regular pages and trackers."
msgstr ""

#: ../content/posts/crawling.md:block 15 (header)
msgid "The original study"
msgstr ""

#: ../content/posts/crawling.md:block 16 (paragraph)
msgid ""
"The Snyders' study suggests that some of the JavaScript APIs are extremely "
"popular and they are used on more than 90% of measured pages (e.g. a well "
"known `Document.createElement` method from DOM API). On the other hand, "
"there are many APIs that are used by a minority of measured pages. That "
"being said, almost 50% of JavaScript APIs implemented in the browser at the "
"time were not used by any of the measured pages."
msgstr ""

#: ../content/posts/crawling.md:block 17 (paragraph)
msgid ""
"The study also suggests that there is no direct connection between the "
"implementation date of a given JavaScript API in the browser (or by its "
"specification date by some of the specifications vendors) and its popularity"
" in using by websites. Concretely, there are some old JavaScript APIs, such "
"as `XMLHttpRequest` that are still very popular. However, there are also "
"quite new JavaScript APIs, that are used very frequently (i.e., `Selectors "
"API Level 1`)."
msgstr ""

#: ../content/posts/crawling.md:block 18 (paragraph)
msgid ""
"The conducted study also measured the pages in two ways - with the ad "
"blocker and without any ad blocking extension. Results of measurements "
"showed that the blocking of different JavaScript APIs is not uniform and "
"some APIs are blocked more often than others. Specifically, 10% of "
"JavaScript APIs were blocked in 90% of cases resulting in a fact that 83% of"
" APIs were used on less than 1% of websites when the page was visited with "
"active blocking extension."
msgstr ""

#: ../content/posts/crawling.md:block 19 (header)
msgid "Web API Manager"
msgstr ""

#: ../content/posts/crawling.md:block 20 (paragraph)
msgid ""
"Web API Manager is a browser extension, that aims to block explicitly "
"defined JavaScript APIs. It has been developed by Snyders in 2016 and used "
"in several studies conducted by [Snyders et "
"al.](https://www.peteresnyder.com/https://www.peteresnyder.com/)."
msgstr ""

#: ../content/posts/crawling.md:block 21 (paragraph)
msgid ""
"The original purpose of the Web API Manager is to block explicitly defined "
"JavaScript APIs. However, in our measurements, we just need to intercept the"
" API calls, log these calls and delegate the calls to original receivers."
msgstr ""

#: ../content/posts/crawling.md:block 22 (paragraph)
msgid ""
"The main principle of Web API Manager is based on Proxy objects. This "
"metaprogramming technique allows intercepting calls performed on objects. "
"While the main goal of the Web API Manager extension is to block the calls "
"performed on objects that belong to particular JavaScript APIs, our goal is "
"only to intercept these operations and delegate them to their original "
"receivers. We will use the Log Aggregator interface to log the API calls."
msgstr ""

#: ../content/posts/crawling.md:block 23 (paragraph)
msgid ""
"To provide a Web API Manager the list of JavaScript APIs members we need a "
"list of supported APIs. The APIs implemented in Mozilla Firefox are "
"available as [IDL files](https://searchfox.org/mozilla-"
"central/source/dom/webidl)."
msgstr ""

#: ../content/posts/crawling.md:block 24 (header)
msgid "Measurement tools"
msgstr ""

#: ../content/posts/crawling.md:block 25 (paragraph)
msgid ""
"The figure below shows a simplified illustration of the measurement "
"platform. There is OpenWPM in the middle of the architecture. OpenWPM "
"orchestrates Selenium and Mozilla Firefox with the proxy-based intercepting "
"Web API Manager."
msgstr ""

#: ../content/posts/crawling.md:block 26 (paragraph)
msgid "![image]({attach}/images/crawling-architecture.png)"
msgstr ""

#: ../content/posts/crawling.md:block 27 (header)
msgid "The impact on JShelter"
msgstr ""

#: ../content/posts/crawling.md:block 28 (paragraph)
msgid ""
"Once we have data from our crawling study, we will compare the data with "
"[another recent study](https://github.com/uiowa-irl/FP-"
"Inspector/blob/master/Data/potential_fingerprinting_APIs.md). As already "
"mentioned, we want to develop a fingerprinting detection based on counting "
"the number of different APIs employed by a page, especially APIs that are "
"not frequently used for benign purposes. When a fingerprinting attempt is "
"identified, we want to (1) inform the user, (2) prevent uploading of the "
"fingerprint to the server, (3) prevent storing the fingerprint for later "
"usage."
msgstr ""

#: ../content/posts/crawling_results.md:block 1 (header)
msgid ""
"title: \"RESULTS: Measurement of JavaScript API usage on the web\"\n"
"date: 2022-01-14 12:00\n"
"Series: JavaScript API usage"
msgstr ""

#: ../content/posts/crawling_results.md:block 2 (paragraph)
msgid ""
"A [previous blogpost](/crawling/) introduced a methodology to measure the "
"usage of JavaScript APIs on the web by crawling the web. The starting point "
"of our web crawling research is the [work of Peter "
"Snyder](https://www.peteresnyder.com/static/papers/improving-web-privacy-"
"and-security-thesis.pdf). Most importantly, we wanted to compare the "
"differences in JS API usage between browsers with and without privacy "
"extension (e.g., uBlock Origin). We have finished the development of the "
"[crawling tool](https://github.com/martinbednar/web_crawler). We crawled "
"thousands of websites and collected JavaScript calls on the visited web "
"pages."
msgstr ""

#: ../content/posts/crawling_results.md:block 3 (paragraph)
msgid "This blog post introduces the methodology and results of the crawling."
msgstr ""

#: ../content/posts/crawling_results.md:block 5 (paragraph)
msgid ""
"When a user opens a webpage in a JavaScript-enabled web browser, that "
"webpage can access various APIs supported by the web browser. The webpage "
"can read, for example, the value of performance.now(), battery status or "
"data from sensors (when available). All these values can be misused to "
"create a [device fingerprint](https://arxiv.org/pdf/1905.01051.pdf) that can"
" be used to identify the user."
msgstr ""

#: ../content/posts/crawling_results.md:block 6 (paragraph)
msgid ""
"We aim to research how JS APIs are used on websites. The main research "
"questions are:"
msgstr ""

#: ../content/posts/crawling_results.md:block 7 (unordered list)
msgid "What APIs do websites use?"
msgstr ""

#: ../content/posts/crawling_results.md:block 7 (unordered list)
msgid "How many APIs does a website use?"
msgstr ""

#: ../content/posts/crawling_results.md:block 7 (unordered list)
msgid "What endpoints do websites access most often?"
msgstr ""

#: ../content/posts/crawling_results.md:block 7 (unordered list)
msgid "How many JS calls are made?"
msgstr ""

#: ../content/posts/crawling_results.md:block 7 (unordered list)
msgid ""
"What are the differences in results in all the previous questions with an "
"active privacy web-browser extension (e.g., uBlock Origin)? For example, "
"What JS calls are blocked by uBlock Origin?"
msgstr ""

#: ../content/posts/crawling_results.md:block 8 (paragraph)
msgid ""
"The answers to these questions should help us better understand websites' "
"behaviour. Based on the obtained data, we want to define the suspicious "
"behaviour indicating that the website is trying to fingerprint the user's "
"device."
msgstr ""

#: ../content/posts/crawling_results.md:block 9 (paragraph)
msgid ""
"We plan to keep the [anti-fingerprint mechanism](/fpdetection/) updated "
"based on derived heuristics. The heuristics are derived from the following "
"statistics:"
msgstr ""

#: ../content/posts/crawling_results.md:block 10 (unordered list)
msgid "How many APIs and endpoints does the website access?"
msgstr ""

#: ../content/posts/crawling_results.md:block 10 (unordered list)
msgid "How many JS calls did the website make?"
msgstr ""

#: ../content/posts/crawling_results.md:block 10 (unordered list)
msgid "Is the number and combination of JS APIs calls suspicious?"
msgstr ""

#: ../content/posts/crawling_results.md:block 11 (paragraph)
msgid ""
"When our anti-fingerprint mechanism detects suspicious combinations or a "
"high number of used APIs, it can block communication with the webpage."
msgstr ""

#: ../content/posts/crawling_results.md:block 12 (header)
msgid "Crawler"
msgstr ""

#: ../content/posts/crawling_results.md:block 13 (paragraph)
msgid ""
"We have developed [Web "
"crawler](https://github.com/martinbednar/web_crawler/) - a tool for "
"automatically visiting websites from a given list and collecting JavaScript "
"calls made by the website. Our Web crawler is based on the "
"[OpenWPM](https://github.com/openwpm/OpenWPM) platform. A modified web "
"browser extension [Web API Manager](https://github.com/pes10k/web-api-"
"manager) collects statistics on called JS APIs."
msgstr ""

#: ../content/posts/crawling_results.md:block 14 (paragraph)
msgid "The crawling process can be described in the following steps:"
msgstr ""

#: ../content/posts/crawling_results.md:block 15 (ordered list)
msgid ""
"The python script `start_docker_runs.py` launches the Docker image "
"[martan305/web_crawler](https://hub.docker.com/repository/docker/martan305/web_crawler)."
" The parameters set in the Python startup script are given to the Docker "
"container as environmental variables."
msgstr ""

#: ../content/posts/crawling_results.md:block 15 (ordered list)
msgid ""
"If a privacy extension is required (in the script parameter), uBlock Origin "
"will be installed as soon as the web browser is started."
msgstr ""

#: ../content/posts/crawling_results.md:block 15 (ordered list)
msgid ""
"Python script running in the container visits web pages from a given list "
"one by one."
msgstr ""

#: ../content/posts/crawling_results.md:block 15 (ordered list)
msgid ""
"The browser waits for 30 seconds on each page. The customised web browser "
"extension Web API Manager intercepts JS calls and stores the stats into the "
"SQLite database."
msgstr ""

#: ../content/posts/crawling_results.md:block 15 (ordered list)
msgid ""
"When the script finishes the crawl of assigned pages, it checks if there is "
"a batch of pages not yet visited. If there is an unprocessed batch, the "
"crawling continues with step 3 and the new list of web pages to visit. If "
"the crawler visited all sites, the crawling ends."
msgstr ""

#: ../content/posts/crawling_results.md:block 16 (paragraph)
msgid ""
"For now, we only visited the homepages because we wanted to visit as many "
"different websites as possible. In the future, we plan to launch long-term "
"crawling, which will include subpages. In particular, we want to focus on "
"visiting login pages, where we expect fingerprint scripts to be included. "
"Then, we can compare API calls on login pages and other pages."
msgstr ""

#: ../content/posts/crawling_results.md:block 17 (paragraph)
msgid ""
"Afterwards, we analyse the collected data with a standalone [analysis "
"tool](https://github.com/martinbednar/web_crawler_data_analysis). The "
"analysis process consists of the following steps:"
msgstr ""

#: ../content/posts/crawling_results.md:block 18 (ordered list)
msgid ""
"Databases created by browsing with and without the web-browser extension "
"uBlock Origin are loaded separately."
msgstr ""

#: ../content/posts/crawling_results.md:block 18 (ordered list)
msgid ""
"Aggregation SQL queries are executed in databases. The results are loaded "
"into Python dictionaries."
msgstr ""

#: ../content/posts/crawling_results.md:block 18 (ordered list)
msgid ""
"Data sets are analysed, compared and the results are exported to CSV files."
msgstr ""

#: ../content/posts/crawling_results.md:block 19 (header)
msgid "Measurement results"
msgstr ""

#: ../content/posts/crawling_results.md:block 20 (paragraph)
msgid "This section presents the results of the analysis."
msgstr ""

#: ../content/posts/crawling_results.md:block 21 (paragraph)
msgid ""
"We tried to visit the first 250 000 websites from the [Tranco list "
"X79N](https://tranco-list.eu/list/X79N/1000000). 211 843 homepages of "
"websites from the Tranco list were successfully visited in both modes - with"
" and without uBlock Origin. More than 4 000 000 000 JS calls were "
"intercepted and stored into 5 000 [SQLite "
"databases](https://nextcloud.fit.vutbr.cz/s/XKm3PCZnr2xkPH9) that have a "
"total size of over 880 GB."
msgstr ""

#: ../content/posts/crawling_results.md:block 22 (paragraph)
msgid ""
"Let us focus on the answers to the research questions on JavaScript API "
"calls made by the websites. This blog post usually lists only 10 result "
"lines for each experiment. Complete tables with all rows can be found in the"
" [results stored on the "
"server](https://nextcloud.fit.vutbr.cz/s/xDfSAe3Nx7iFSm4)."
msgstr ""

#: ../content/posts/crawling_results.md:block 23 (paragraph)
msgid "The meaning of the table columns:"
msgstr ""

#: ../content/posts/crawling_results.md:block 24 (unordered list)
msgid "Endpoint = a function or a property provided by a web browser."
msgstr ""

#: ../content/posts/crawling_results.md:block 24 (unordered list)
msgid ""
"API = a group of functions and properties that are thematically related."
msgstr ""

#: ../content/posts/crawling_results.md:block 24 (unordered list)
msgid "Website = URL of the visited website."
msgstr ""

#: ../content/posts/crawling_results.md:block 24 (unordered list)
msgid ""
"Calls without uBlock Origin = the number of JavaScript calls intercepted "
"without the uBlock Origin extension."
msgstr ""

#: ../content/posts/crawling_results.md:block 24 (unordered list)
msgid ""
"Calls with uBlock Origin = the number of JavaScript calls intercepted with "
"the uBlock Origin extension."
msgstr ""

#: ../content/posts/crawling_results.md:block 24 (unordered list)
msgid ""
"Difference = the difference between the number of JavaScript calls "
"intercepted with and without the uBlock Origin extension."
msgstr ""

#: ../content/posts/crawling_results.md:block 24 (unordered list)
msgid ""
"Difference [%] = the difference expressed as a percentage. Difference [%] = "
"100 \\* Difference/Calls without uBlock Origin"
msgstr ""

#: ../content/posts/crawling_results.md:block 24 (unordered list)
msgid ""
"Websites without uBlock [%] - what percentage of websites use the given API "
"(measured without the uBlock Origin extension installed)."
msgstr ""

#: ../content/posts/crawling_results.md:block 24 (unordered list)
msgid ""
"Websites with uBlock [%] - what percentage of websites use the given API "
"(measured with the uBlock Origin extension installed)."
msgstr ""

#: ../content/posts/crawling_results.md:block 25 (paragraph)
msgid ""
"All result tables are sorted by the `Difference [%]` column decreasing."
msgstr ""

#: ../content/posts/crawling_results.md:block 26 (header)
msgid "The most blocked API"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "API"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Calls without uBlock"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Calls with uBlock"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Difference"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Difference [%]"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Non-Standard"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "340 777"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "18 180"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "322 597"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "94,67%"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Web Audio API"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "14 390 507"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "1 431 286"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "12 959 221"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "90,05%"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Web Speech API"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "93 889"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "10 712"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "83 177"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "88,59%"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Background Tasks API"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "5 950 947"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "954 740"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "4 996 207"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "83,96%"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "High Resolution Time (Level 2)"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "367 400 369"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "63 507 434"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "303 892 935"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "82,71%"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Navigation Timing"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "8 160"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "1 749"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "6 411"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "78,57%"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "CSS Animations Level 1"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "1 301"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "317"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "984"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "75,63%"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Beacon"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "223 209"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "62 651"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "160 558"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "71,93%"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "DOM Level 2: Traversal and Range"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "25 814 025"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "7 996 500"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "17 817 525"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "69,02%"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "Indexed Database API"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "1 308 464"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "408 983"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "899 481"
msgstr ""

#: ../content/posts/crawling_results.md:block 27 (table)
msgid "68,74%"
msgstr ""

#: ../content/posts/crawling_results.md:block 28 (header)
msgid "The most blocked API endpoints"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "Endpoint"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "Range.prototype.cloneContents"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "2 603"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "16"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "2 587"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "99,39%"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "Range.prototype.setStartAfter"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "1 234"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "9"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "1 225"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "99,27%"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "MessagePort.prototype.close"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "HTML: Channel Messaging"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "51 802"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "416"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "51 386"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "99,20%"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "SubtleCrypto.prototype.deriveBits"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "Web Cryptography API"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "208"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "2"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "206"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "99,04%"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "Range.prototype.selectNode"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "337 795"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "7 384"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "330 411"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "97,81%"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "Range.prototype.getBoundingClientRect"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "337 650"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "7 565"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "330 085"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "97,76%"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "Document.prototype.close"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "HTML: Dynamic Markup Insertion"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "21 666"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "666"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "21 000"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "96,93%"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "Navigator.prototype.javaEnabled"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "334 580"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "11 781"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "322 799"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "96,48%"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "ServiceWorkerContainer.prototype.getRegistration"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "Service Workers"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "34 176"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "1 375"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "32 801"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "95,98%"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "FormData.prototype.append"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "XMLHttpRequest"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "670 137"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "27 767"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "642 370"
msgstr ""

#: ../content/posts/crawling_results.md:block 29 (table)
msgid "95,86%"
msgstr ""

#: ../content/posts/crawling_results.md:block 30 (header)
msgid "Use of APIs on websites"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "Websites without uBlock [%]"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "Websites with uBlock [%]"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "62,06%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "4,80%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "57,29%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "61,40%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "21,98%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "39,56%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "32,91%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "7,60%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "25,36%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "71,53%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "47,76%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "24,08%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "45,58%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "24,71%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "21,03%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "Performance Timeline"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "41,15%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "21,22%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "20,06%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "57,37%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "39,24%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "18,39%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "HTML 5"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "50,14%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "33,45%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "16,91%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "HTML: Web Storage"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "65,69%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "49,48%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "16,53%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "URL"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "29,73%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "15,79%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "14,05%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "14,41%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "0,81%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "13,61%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "22,23%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "9,40%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "12,89%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "HTML: Canvas Element"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "42,54%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "29,89%"
msgstr ""

#: ../content/posts/crawling_results.md:block 31 (table)
msgid "12,85%"
msgstr ""

#: ../content/posts/crawling_results.md:block 32 (header)
msgid "The number of APIs used by the website"
msgstr ""

#: ../content/posts/crawling_results.md:block 33 (paragraph)
msgid ""
"**Average value** - Number of APIs used without uBlock Origin: **18.78**"
msgstr ""

#: ../content/posts/crawling_results.md:block 34 (paragraph)
msgid "![image]({attach}/images/crawling_results/APIs_without_uBlock.png)"
msgstr ""

#: ../content/posts/crawling_results.md:block 35 (paragraph)
msgid "**Average value** - Number of APIs used with uBlock Origin: **14.27**"
msgstr ""

#: ../content/posts/crawling_results.md:block 36 (paragraph)
msgid "![image]({attach}/images/crawling_results/APIs_with_uBlock.png)"
msgstr ""

#: ../content/posts/crawling_results.md:block 37 (header)
msgid "The number of JavaScript calls on websites"
msgstr ""

#: ../content/posts/crawling_results.md:block 38 (paragraph)
msgid ""
"**Average value** - Number of JavaScript calls made without uBlock Origin: "
"**10 629.92**"
msgstr ""

#: ../content/posts/crawling_results.md:block 39 (paragraph)
msgid "![image]({attach}/images/crawling_results/JScalls_without_uBlock.png)"
msgstr ""

#: ../content/posts/crawling_results.md:block 40 (paragraph)
msgid ""
"**Average value** - Number of JavaScript calls made with uBlock Origin: **7 "
"176.2**"
msgstr ""

#: ../content/posts/crawling_results.md:block 41 (paragraph)
msgid "![image]({attach}/images/crawling_results/JScalls_with_uBlock.png)"
msgstr ""

#: ../content/posts/crawling_results.md:block 42 (header)
msgid "The number of endpoint calls on websites"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "Website"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://www.woolworths.co.za/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "window.getComputedStyle"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "202 013"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "1"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "202 012"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "100,00%"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://www.superkopilka.com/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "Performance.prototype.now"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "158 034"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "158 033"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://www.jarir.com/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "DOMTokenList.prototype.contains"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "156 917"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "156 916"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://shm.ru/#"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "153 653"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "153 652"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://znanium.com/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "138 465"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "138 464"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://www.soliton.az/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "137 467"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "137 466"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://www.lasenza.com/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "118 945"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "118 944"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://nethouse.ru/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "113 580"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "113 579"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://boodmo.com/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "108 376"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "108 375"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://fipi.ru/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "108 255"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "108 254"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://belregion.ru/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "105 227"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "105 226"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "https://tsargrad.tv/"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "99 445"
msgstr ""

#: ../content/posts/crawling_results.md:block 43 (table)
msgid "99 444"
msgstr ""

#: ../content/posts/crawling_results.md:block 44 (header)
msgid "Measurement results for opensource websites only"
msgstr ""

#: ../content/posts/crawling_results.md:block 45 (paragraph)
msgid ""
"As this project focuses on free and open source software, we compared the "
"general results with a list of pages connected to free software or open "
"source."
msgstr ""

#: ../content/posts/crawling_results.md:block 46 (paragraph)
msgid ""
"We collected the list of the home pages from [Gentoo "
"repository](https://gitweb.gentoo.org/repo/gentoo.git/tree/)."
msgstr ""

#: ../content/posts/crawling_results.md:block 47 (paragraph)
msgid ""
"We tried to visit all 5 271 collected websites. 4 528 homepages were "
"successfully visited in both modes, with and without uBlock Origin. More "
"than 11 000 000 JS calls were intercepted and stored into 2 [SQLite "
"databases](https://nextcloud.fit.vutbr.cz/s/yoLa5rcGzkgbSka) that have a "
"total size of over 3 GB."
msgstr ""

#: ../content/posts/crawling_results.md:block 48 (paragraph)
msgid ""
"Only the first 10 lines of the analysis results are usually listed below. "
"Complete tables with all rows can be found in the [results stored on the "
"server](https://nextcloud.fit.vutbr.cz/s/LWANmRxoXc5YYzy)."
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "Resource Timing Level 2"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "348"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "8"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "340"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "97,70%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "1 711"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "66"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "1 645"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "96,14%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "18 763"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "1 037"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "17 726"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "94,47%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "306"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "18"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "288"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "94,12%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "HTML: Plugins"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "13"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "11"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "84,62%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "Permissions API"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "705"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "186"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "519"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "73,62%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "3 981"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "1 088"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "2 893"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "72,67%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "849 390"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "232 806"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "616 584"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "72,59%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "21"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "6"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "15"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "71,43%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "Performance Timeline (Level 2)"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "2 548"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "745"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "1 803"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "70,76%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "Storage API"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "3"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "66,67%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "727"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "250"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "477"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "65,61%"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "7 632"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "2 928"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "4 704"
msgstr ""

#: ../content/posts/crawling_results.md:block 50 (table)
msgid "61,64%"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "IdleDeadline.prototype.timeRemaining"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "2 258"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "2 256"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "99,91%"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "Element.prototype.getAttributeNames"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "DOM"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "1 648"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "12"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "1 636"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "268"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "266"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "99,25%"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "Document.prototype.elementFromPoint"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "CSS Object Model (CSSOM)"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "2 554"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "22"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "2 532"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "99,14%"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "106"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "105"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "99,06%"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "CanvasRenderingContext2D.prototype.createLinearGradient"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "4 634"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "56"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "4 578"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "98,79%"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "CanvasRenderingContext2D.prototype.transform"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "37 792"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "845"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "36 947"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "PerformanceResourceTiming.prototype.toJSON"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "1 691"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "47"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "1 644"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "97,22%"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "PerformanceObserverEntryList.prototype.getEntriesByName"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "52"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "50"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "96,15%"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "CanvasGradient.prototype.addColorStop"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "9 623"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "453"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "9 170"
msgstr ""

#: ../content/posts/crawling_results.md:block 52 (table)
msgid "95,29%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "26,47%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "1,13%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "25,26%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "21,94%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "7,24%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "14,64%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "26,42%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "14,94%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "11,41%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "13,70%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "9,08%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "4,58%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "6,35%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "1,76%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "10,07%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "5,68%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "4,36%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "15,46%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "11,12%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "4,29%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "10,79%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "6,46%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "20,60%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "16,26%"
msgstr ""

#: ../content/posts/crawling_results.md:block 54 (table)
msgid "4,27%"
msgstr ""

#: ../content/posts/crawling_results.md:block 56 (paragraph)
msgid "**Average value** - Number of APIs used without uBlock Origin: **7.4**"
msgstr ""

#: ../content/posts/crawling_results.md:block 57 (paragraph)
msgid "![image](crawling_results/APIs_without_uBlock_opensource.png)"
msgstr ""

#: ../content/posts/crawling_results.md:block 58 (paragraph)
msgid "**Average value** - Number of APIs used with uBlock Origin: **6.2**"
msgstr ""

#: ../content/posts/crawling_results.md:block 59 (paragraph)
msgid "![image](crawling_results/APIs_with_uBlock_opensource.png)"
msgstr ""

#: ../content/posts/crawling_results.md:block 61 (paragraph)
msgid ""
"**Average value** - Number of JavaScript calls made without uBlock Origin: "
"**1598.18**"
msgstr ""

#: ../content/posts/crawling_results.md:block 62 (paragraph)
msgid "![image](crawling_results/JScalls_without_uBlock_opensource.png)"
msgstr ""

#: ../content/posts/crawling_results.md:block 63 (paragraph)
msgid ""
"**Average value** - Number of JavaScript calls made with uBlock Origin: "
"**1304.06**"
msgstr ""

#: ../content/posts/crawling_results.md:block 64 (paragraph)
msgid "![image](crawling_results/JScalls_with_uBlock_opensource.png)"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "https://wci.llnl.gov/"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "Element.prototype.hasAttribute"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "34 860"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "34 859"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "https://wiibrew.org/wiki/Main_Page"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "6 512"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "6 511"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "99,98%"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "http://www.vsound.org/"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "Document.prototype.getElementById"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "5 797"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "5 796"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "http://wormsofprey.org/"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "5 793"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "5 792"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "http://konst.org.ua/"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "Element.prototype.setAttribute"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "4 248"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "4 247"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "https://www.union.edu/mathematics"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "5 317"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "5 315"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "99,96%"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "https://www.mongodb.com/"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "30 516"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "14"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "30 502"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "99,95%"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "https://www.monotype.com/"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "4 091"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "4 089"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "https://sylabs.io/"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "1 839"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "1 838"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "http://vlgothic.dicey.org/"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "3 427"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "3 425"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "99,94%"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "https://www.ppsspp.org/"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "3 397"
msgstr ""

#: ../content/posts/crawling_results.md:block 66 (table)
msgid "3 395"
msgstr ""

#: ../content/posts/crawling_results.md:block 67 (header)
msgid "Measurement results for FingerPrint Detector"
msgstr ""

#: ../content/posts/crawling_results.md:block 68 (paragraph)
msgid ""
"We designed the web crawling primarily to retrieve data to create or "
"evaluate heuristics for the [FingerPrint Detector (FPD)](/fpdetection/). The"
" above results are helpful in understanding the JavaScript APIs usage on the"
" web. For FPD, only the name of the endpoint and the weight of this endpoint"
" are important. The weight expresses how often a given endpoint is used to "
"create a fingerprint."
msgstr ""

#: ../content/posts/crawling_results.md:block 69 (paragraph)
msgid ""
"The resulting table below was created from crawled data from websites of the"
" Tranco list . Two data sets were combined to obtain more accurate results. "
"The first dataset obtained while crawling with uBlock Origin, the second one"
" obtained while crawling with uMatrix. The resulting endpoint weight (marked"
" as `average_weight`) was calculated in Python as follows:"
msgstr ""

#: ../content/posts/crawling_results.md:block 71 (paragraph)
msgid ""
"Again, only the first 10 lines of the FPD analysis result are listed below. "
"Complete table with all rows can be found in the [results stored on the "
"server](https://nextcloud.fit.vutbr.cz/s/GjkTJzweccgxw6n)."
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Average weight"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "uMatrix weight"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "uBlock weight"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Calls without extension"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Calls with uMatrix"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Difference uMatrix"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Difference uBlock"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Difference uMatrix [%]"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Difference uBlock [%]"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "13,427"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "13,060"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "455"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "454"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "449"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,998"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,987"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Range.prototype.insertNode"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "13,138"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "12,920"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "460"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "5"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "452"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,989"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,983"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "HTMLFormControlsCollection.prototype.namedItem"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "12,714"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "12,623"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "2 211"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "19"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "25"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "2 192"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "2 186"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,991"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Document.prototype.open"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "12,475"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "11,274"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "8 190"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "129"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "424"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "8 061"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "7 766"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,984"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,948"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "12,438"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "12,424"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "16 208"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "30"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "37"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "16 178"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "16 171"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Document.prototype.getElementsByTagNameNS"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "12,374"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "10,811"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "533"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "43"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "515"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "490"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,966"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,919"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "12,086"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "11,944"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "7 731"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "212"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "245"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "7 519"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "7 486"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,973"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,968"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "SubtleCrypto.prototype.generateKey"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "11,876"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "11,503"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "985"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "48"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "59"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "937"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "926"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,951"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,940"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "Document.prototype.elementsFromPoint"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "12,469"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "11,365"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "46 938"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "44"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "1 598"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "46 894"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "45 340"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,999"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "10,892"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "110 665"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "3 677"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "3 679"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "106 988"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "106 986"
msgstr ""

#: ../content/posts/crawling_results.md:block 72 (table)
msgid "0,967"
msgstr ""

#: ../content/posts/crawling_results.md:block 73 (paragraph)
msgid ""
"More about FingerPrint Detector is written in the [following "
"blogpost](/fpdetection/)."
msgstr ""

#: ../content/posts/crawling_results.md:block 74 (header)
msgid "Conclusion"
msgstr ""

#: ../content/posts/crawling_results.md:block 75 (paragraph)
msgid ""
"The crawl identified JavaScript endpoints, often used to create a browser "
"fingerprint. The observed data allow assigning weights for each endpoint. "
"[FingerPrint Detector](/fpdetection/) configuration file uses the crawl "
"results."
msgstr ""

#: ../content/posts/farbling.md:block 1 (header)
msgid ""
"title: Farbling-based wrappers to hinder browser fingerprinting\n"
"date: 2021-08-23 09:00\n"
"Series: Browser fingerprinting"
msgstr ""

#: ../content/posts/farbling.md:block 2 (paragraph)
msgid ""
"[Browser fingerprinting](https://arxiv.org/pdf/1905.01051.pdf) is a more and"
" more popular technique used to identify browsers. The fingerprint is "
"computed based on the results of JavaScript calls, the content of HTTP "
"headers, hardware characteristics, underlying operating system and other "
"software information. Consequently, browser fingerprints are used for cross-"
"domain tracking. However, users cannot clear their browser fingerprint as it"
" is not stored on the client-side. It is also challenging to determine "
"whether a browser is being fingerprinted."
msgstr ""

#: ../content/posts/farbling.md:block 3 (paragraph)
msgid ""
"Another issue that hinders fingerprinting protection is the ever-changing "
"variety of supported APIs. Browsers implement new APIs over time, and "
"existing APIs change. Consequently, it is necessary to continuously monitor "
"the APIs being used for fingerprinting purposes to block fingerprinting "
"attempts."
msgstr ""

#: ../content/posts/farbling.md:block 4 (paragraph)
msgid ""
"Due to fingerprinting scripts being [more "
"prevalent](https://www.cs.princeton.edu/~arvindn/publications/OpenWPM_1_million_site_tracking_measurement.pdf),"
" various web browsers - for example, Tor, Brave, and Firefox - started "
"implementing fingerprinting protection to protect users and their privacy."
msgstr ""

#: ../content/posts/farbling.md:block 5 (paragraph)
msgid "This post contains:"
msgstr ""

#: ../content/posts/farbling.md:block 6 (paragraph)
msgid "[TOC]"
msgstr ""

#: ../content/posts/farbling.md:block 7 (header)
msgid "Brave fingerprinting protection"
msgstr ""

#: ../content/posts/farbling.md:block 8 (paragraph)
msgid ""
"Why is Brave's Farbling special? Until recently, [Tor "
"browser](https://2019.www.torproject.org/projects/torbrowser/design/#fingerprinting-"
"linkability) had the most robust defence against fingerprinting. It (1) "
"implemented modifications in various APIs, (2) blocks some other APIs, (3) "
"runs in a window of predefined size, etc. to ensure all users have the same "
"fingerprint. This approach is very effective at producing uniform "
"fingerprint for all users, which makes it difficult for fingerprinters to "
"differentiate between browsers. Still, such fingerprint is also brittle -- "
"minor changes like resizing the window could cause the browser to have a "
"unique fingerprint. Hence, users need to follow inconvenient steps to keep "
"their fingerprint uniform."
msgstr ""

#: ../content/posts/farbling.md:block 9 (paragraph)
msgid ""
"With all this in [mind](https://brave.com/brave-fingerprinting-and-privacy-"
"budgets/), Brave software decided to improve their fingerprinting "
"protection. They [proposed](https://brave.com/privacy-updates-3/) new "
"fingerprinting protection, Farbling, arguing that it is (almost) impossible "
"to produce uniform fingerprint without compromising user experience. Their "
"countermeasures involve randomising values based on previous research papers"
" [PriVaricator](https://www.doc.ic.ac.uk/~livshits/papers/pdf/www15.pdf) and"
" [FPRandom](https://hal.inria.fr/hal-01527580/document) Both papers have "
"shown promising results, and Brave has perfected this approach, creating "
"effective defence while retaining almost full user experience. Farbling is a"
" comprehensive collection of modifications that aim at producing a unique "
"fingerprint on every domain and in every session."
msgstr ""

#: ../content/posts/farbling.md:block 10 (header)
msgid "How does farbling work?"
msgstr ""

#: ../content/posts/farbling.md:block 11 (paragraph)
msgid ""
"Farbling uses generated session and [eTLD+1](https://web.dev/same-site-same-"
"origin/) keys to deterministically change outputs of certain APIs commonly "
"used for browser fingerprinting. These little lies result in different "
"websites calculating different fingerprints. Moreover, a previously visited "
"website calculates a different fingerprint in a new browsing session."
msgstr ""

#: ../content/posts/farbling.md:block 12 (paragraph)
msgid ""
"Farbling implementation is publicly available on Github "
"[issue](https://github.com/brave/brave-browser/issues/8787) with discussions"
" on design decisions, future plans and possible changes in a separate "
"[issue](https://github.com/brave/brave-browser/issues/11770)."
msgstr ""

#: ../content/posts/farbling.md:block 13 (paragraph)
msgid "Farbling operates on three levels:"
msgstr ""

#: ../content/posts/farbling.md:block 14 (ordered list)
msgid "**Off** - countermeasures are not active"
msgstr ""

#: ../content/posts/farbling.md:block 14 (ordered list)
msgid ""
"**Balanced** - various APIs have modified values based on domain/session "
"keys"
msgstr ""

#: ../content/posts/farbling.md:block 14 (ordered list)
msgid ""
"**Maximum** - various APIs values replaced by randomised values based on "
"domain/session keys"
msgstr ""

#: ../content/posts/farbling.md:block 15 (paragraph)
msgid "Now, what changes did actually Brave implement to specific APIs?"
msgstr ""

#: ../content/posts/farbling.md:block 16 (header)
msgid "Canvas"
msgstr ""

#: ../content/posts/farbling.md:block 17 (paragraph)
msgid ""
"Canvas modifications are tracked in a separate "
"[issue](https://github.com/brave/brave-browser/issues/9186). Both *balanced*"
" and *maximum* approach modify API calls "
"`CanvasRendering2dContext.getImageData`, `HTMLCanvasElement.toDataURL`, "
"`HTMLCanvasElement.toBlob`, and `OffscreenCanvas.convertToBlob`. A [Filter "
"function](https://github.com/brave/brave-"
"core/blob/master/chromium_src/third_party/blink/renderer/core/execution_context/execution_context.cc)"
" changes values of certain pixels chosen based on session/domain keys, "
"resulting in a unique canvas fingerprint. On *maximum* level, methods "
"`CanvasRenderingContext2D.isPointInPath` and "
"`CanvasRenderingContext2D.isPointInStroke` always return *false*."
msgstr ""

#: ../content/posts/farbling.md:block 18 (header)
msgid "WebGL"
msgstr ""

#: ../content/posts/farbling.md:block 19 (paragraph)
msgid ""
"Modifications for both WebGL and WebGL2 are described in issues "
"[webgl](https://github.com/brave/brave-browser/issues/9188) , "
"[webgl2](https://github.com/brave/brave-browser/issues/9189). On *balanced* "
"level `WebGLRenderingContext.getParameter` and other methods return slightly"
" modified values. `WebGLRenderingContext.readPixels` is modified similarly "
"to canvas methods. On *maximum* level, `WebGLRenderingContext.getParameter` "
"returns random strings for unmasked vendor and renderer, bottom values for "
"other arguments. Other modified calls return bottom values. All "
"modifications can be found in the issues mentioned above or directly in the "
"[code](https://github.com/brave/brave-"
"core/tree/master/chromium_src/third_party/blink/renderer/modules/webgl)."
msgstr ""

#: ../content/posts/farbling.md:block 20 (header)
msgid "Web Audio"
msgstr ""

#: ../content/posts/farbling.md:block 21 (paragraph)
msgid ""
"The [issue](https://github.com/brave/brave-browser/issues/9187) modifies "
"several endpoints of `AnalyserNode` and `AudioBuffer` APIs used for audio "
"data handling are modified. On the *balanced* level, the amplitude of "
"returned audio data is slightly changed based on the domain key. However, "
"data are replaced by white noise generated from domain hash on the maximum "
"level, so there is no relation with original data."
msgstr ""

#: ../content/posts/farbling.md:block 22 (header)
msgid "Plugins"
msgstr ""

#: ../content/posts/farbling.md:block 23 (paragraph)
msgid ""
"Currently, `navigator.plugins` and `navigator.mimeTypes` are modified on "
"*balanced* level to return an array with altered plugins and two fake "
"plugins. On *maximum* level, the returned array contains only two fake "
"plugins. See [issue1](https://github.com/brave/brave-browser/issues/9435) "
"and [issue2](https://github.com/brave/brave-browser/issues/10597) for more "
"details."
msgstr ""

#: ../content/posts/farbling.md:block 24 (header)
msgid "User agent"
msgstr ""

#: ../content/posts/farbling.md:block 25 (paragraph)
msgid ""
"Brave employs the default Chrome UA and the newest OS version as the user "
"agent string. Also, a random number of blank spaces (up to 5) appended to "
"the end of the user agent string. For more details, see the [GitHub "
"issue](https://github.com/brave/brave-browser/issues/9190)."
msgstr ""

#: ../content/posts/farbling.md:block 26 (header)
msgid "EnumerateDevices"
msgstr ""

#: ../content/posts/farbling.md:block 27 (paragraph)
msgid ""
"This API is used to list I/O media devices like microphone or speakers. When"
" fingerprinting protection is active, Brave returns a shuffled list of "
"devices. For more details, see [issue1](https://github.com/brave/brave-"
"browser/issues/11271) and [issue2](https://github.com/brave/brave-"
"browser/issues/8666)."
msgstr ""

#: ../content/posts/farbling.md:block 28 (header)
msgid "HardwareConcurrency"
msgstr ""

#: ../content/posts/farbling.md:block 29 (paragraph)
msgid ""
"The number of logical processors returned by this interface is modified as "
"follows -- on *balanced* level, a valid value between 2 and the true value, "
"on *maximum* level, a valid value between 2 and 8. See the [GitHub "
"issue](https://github.com/brave/brave-browser/issues/10808) for more "
"details."
msgstr ""

#: ../content/posts/farbling.md:block 30 (header)
msgid "Porting Farbling to JShelter"
msgstr ""

#: ../content/posts/farbling.md:block 31 (paragraph)
msgid ""
"Our goal was to extend JShelter anti-fingerprinting protections with similar"
" measures to those available in Brave's Farbling. We decided to implement "
"Brave Farbling with minor tweaks. As Brave is an open-source project based "
"on [Chromium](https://www.chromium.org/Home), core changes are available in "
"the public [repository](https://github.com/brave/brave-core). Furthermore, "
"as Brave is licensed under [MPL 2.0](https://www.mozilla.org/en-US/MPL/2.0/)"
" license, its countermeasures can be ported to JShelter. Similarly to Brave,"
" JShelter utilises session and domain hashes (currently, we use a different "
"domain hash based on origin, however, we consider switching to the eTLD+1 "
"approach used by Brave). Nevertheless, we ported only those changes that an "
"extension can reasonably apply. So we do not plan to change system fonts as "
"the true set of fonts can leak in several ways (e.g., CSS, canvas). We will "
"keep a close eye on anti-fingerprining techniquest applied by Brave in the "
"future."
msgstr ""

#: ../content/posts/farbling.md:block 32 (paragraph)
msgid ""
"Former JShelter defences were left as an option so user can choose which "
"protection they want. For example, for **Canvas API**, JShelter retains the "
"old defence that returns a white image, but it is also possible to use "
"Farbling and slightly modify the image."
msgstr ""

#: ../content/posts/farbling.md:block 33 (paragraph)
msgid ""
"`CanvasRenderingContext2D.isPointInPath` and "
"`CanvasRenderingContext2D.isPointInStroke` are modified to return *false* "
"with 5% probability, returning *false* to every call seems to be easily "
"identifiable and it limits the usablity of the calls."
msgstr ""

#: ../content/posts/farbling.md:block 34 (paragraph)
msgid ""
"**WebGL**, **Web audio**, **plugins**, **hardwareConcurrency** and "
"**deviceMemory** have been changed accordingly to Brave. API "
"**enumerateDevices** has the same functionality as in Brave. In addition, we"
" add fake devices to the list. **User agent** wasn't modified because it can"
" cause compatibility issues as we support multiple browsers. Adding empty "
"spaces at the end of UAS seems to be quite a weak countermeasure. We will "
"continue to watch changes in the user agent and may implement some defence "
"in future, although it looks like a [better "
"solution](https://datatracker.ietf.org/doc/html/rfc8942) is on the way."
msgstr ""

#: ../content/posts/farbling.md:block 35 (paragraph)
msgid ""
"JShelter 0.5 changes the default level -- **level 2** to apply the farbling-"
"based defence for all covered APIs, and it will be very similar to the "
"*balanced* level of *Brave*. **Level 3** is redesigned to partly apply new "
"and partly old countermeasures to provide as little information as possible."
" Please report websites that does not work correctly with Farbling."
msgstr ""

#: ../content/posts/farbling.md:block 36 (paragraph)
msgid ""
"During the examination of the ported code, we [identified and "
"reported](https://github.com/brave/brave-browser/issues/15882) an issue in "
"the original Brave implementation. The issue was acknowledged and fixed by "
"Brave. This is the beauty of the free software: several projects can benefit"
" from the same code-base and mutualy improve the quality."
msgstr ""

#: ../content/posts/farbling.md:block 38 (paragraph)
msgid ""
"Farbling-based wrappers produce very similar outputs to Brave. So with "
"JShelter, Farbling-like capabilities are available in multiple browsers. "
"Nevertheless, keep in mind that the best anti-fingerprinting techniques are "
"still a research question, fingerprinting techniques are deployed for "
"security reasons (and farbling-like anti-fingerprinting masking may "
"complicate some log in processes), so it is not completely clear what "
"defences are the best and the choice of the defences also depends on "
"specific use cases. We will investigate fingerprinting scripts further "
"during the future work on this project."
msgstr ""

#: ../content/posts/fingerprinting.md:block 1 (header)
msgid ""
"title: Browser fingerprinting and JShelter\n"
"date: 2022-01-14 13:00\n"
"modified: 2023-04-14 14:00\n"
"Series: Browser fingerprinting\n"
"series_index: 1"
msgstr ""

#: ../content/posts/fingerprinting.md:block 2 (paragraph)
msgid ""
"This post introduces [browser "
"fingerprinting](https://arxiv.org/pdf/1905.01051.pdf) and anti-"
"fingerprinting mechanisms. We explain what JShelter implements and the "
"strengths and downsides of the anti-fingerprinting mechanisms."
msgstr ""

#: ../content/posts/fingerprinting.md:block 3 (paragraph)
msgid ""
"In short, browser fingerprinting is a stateless tracking method vastly "
"prevalent on the web in recent years. Similarly to a human *fingerprint*, "
"browser fingerprinting tries to find a set of features that make (almost) "
"every fingerprint unique and the browser uniquely identifiable."
msgstr ""

#: ../content/posts/fingerprinting.md:block 4 (paragraph)
msgid ""
"The fingerprinting features contain various sources, mostly accessible "
"through browser application interfaces, APIs. The APIs provide essential "
"functionality for modern websites; however, they leak sensitive information "
"about the browser, operating system, or device itself. Many different "
"devices are connected to the internet — most of them with a very specific "
"configuration. Leaking hardware and software properties may result in a "
"sufficiently identifiable browser fingerprint. Furthermore, do not forget "
"about the possibility of leaking information that may uncover "
"vulnerabilities of your system for the sake of potential attackers."
msgstr ""

#: ../content/posts/fingerprinting.md:block 5 (paragraph)
msgid ""
"At first glance, browser fingerprinting seems to be a great evil in the "
"world full of privacy concerns. However, we should be aware of two distinct "
"purposes for using browser fingerprinting."
msgstr ""

#: ../content/posts/fingerprinting.md:block 6 (paragraph)
msgid ""
"Firstly, there is *a negative or destructive use case* during which websites"
" profile cross-domain user activities without user consent. Trackers use the"
" fingerprint as a cross-domain identifier."
msgstr ""

#: ../content/posts/fingerprinting.md:block 7 (paragraph)
msgid ""
"Secondly, there is *a positive or constructive use case*, where websites "
"tend to collect information about your system to improve the usability or "
"security of their application. For example, applications can recommend "
"installing critical security updates based on your system properties. Some "
"websites collect browser fingerprints to verify known devices of their users"
" to prevent fraud. The JShelter.org website offers the download link in the "
"extension store based on the user agent."
msgstr ""

#: ../content/posts/fingerprinting.md:block 8 (paragraph)
msgid ""
"Many browser vendors have already introduced changes to the cookie policy. "
"Browsers such as Firefox, Safari, and Brave block third-party cookies, often"
" abused for stateful tracking. Chrome developers [recently "
"announced](https://blog.google/products/chrome/updated-timeline-privacy-"
"sandbox-milestones/) that they will jump on the bandwagon too. The counter-"
"measures against stateful tracking techniques result in a substantial "
"increase in the usage of browser fingerprinting."
msgstr ""

#: ../content/posts/fingerprinting.md:block 9 (header)
msgid "Counter-measures to browser fingerprinting"
msgstr ""

#: ../content/posts/fingerprinting.md:block 10 (paragraph)
msgid ""
"Unlike cookies, browser fingerprinting does not require storing an "
"identifier on the device. Instead, the identifier is recomputed with each "
"visited page. Once the fingerprint is obtained, it can be sent to a tracking"
" server in a subsequent request. Moreover, the whole process of fingerprint "
"extraction is invisible to a user. There are many sources of potentially "
"identifiable information from which a fingerprint can be constructed. A "
"fingerprint is considered *passive* when it contains natively accessible "
"information from HTTP headers or network traffic. On the other hand, "
"*active* fingerprint runs JavaScript code to retrieve data from browser "
"APIs. JShelter focuses on detecting and preventing active fingerprinting."
msgstr ""

#: ../content/posts/fingerprinting.md:block 11 (paragraph)
msgid ""
"Nowadays, there are many solutions to mitigate the effects of browser "
"fingerprinting to improve internet privacy."
msgstr ""

#: ../content/posts/fingerprinting.md:block 12 (paragraph)
msgid ""
"[Modifying the content of fingerprints](/farbling/) is a valid choice to "
"resist a fingerprinting attempt. However, each modification may create an "
"inconsistency that may improve the fingerprintability of the browser. Many "
"protection tools use predefined or real fingerprints instead of the user's "
"one to counter this issue."
msgstr ""

#: ../content/posts/fingerprinting.md:block 13 (paragraph)
msgid ""
"Another approach is to create homogeneous fingerprints. If every fingerprint"
" is the same, there is no way to tell the users behind the browsers apart. "
"The leading representative of this approach is the [Tor "
"browser](https://www.torproject.org/). Level 3 of JShelter aims to create a "
"homogenous fingerprint. Unfortunately, homogeneous fingerprints have an "
"inherent downside of following specific rules to be effective. Most "
"importantly, the effectiveness of the approach depends on the broad coverage"
" of the blocked APIs and the size of the population employing the counter-"
"measures. All browsers with the same fingerprint form an anonymity set. An "
"observer cannot distinguish between browsers in the anonymity set. With "
"every missed fingerprintable attribute, the anonymity set breaks into "
"smaller sets. For example, the Tor browser strongly recommends using a "
"specific window size. Suppose you use a window size different from all other"
" Tor browser users. In that case, a fingerprinter can identify you solely by"
" this attribute. Also, keep in mind that Tor browser hides your IP address, "
"which JShelter does not do. Hence we see Level 3 protections more as leak "
"prevention than an anti-fingerprinting measure. If you like the idea of "
"homogeneous fingerprints, install Tor browser."
msgstr ""

#: ../content/posts/fingerprinting.md:block 14 (paragraph)
msgid ""
"[Brave browser](https://brave.com/) modifies the readings from APIs misused "
"to create fingerprints. Nevertheless, the goal is to [create a unique "
"fingerprint for each domain and session](/farbling/). As the fingerprint "
"changes for every visited domain, its use for linking cross-domain "
"activities is smaller. JShelter already [implements the farbling protection "
"of Brave](/farbling/) and uses them as the default anti-fingerprinting "
"approach."
msgstr ""

#: ../content/posts/fingerprinting.md:block 15 (paragraph)
msgid ""
"Recently, we added [Fingerprint detector (FPD)](/fpdetection/) to JShelter. "
"FPD does not modify the fingerprint. Instead, FPD monitors APIs that are "
"often misused by fingerprinters. When FPD detects a fingerprinting attempt, "
"it warns the user. You can also allow FPD to block all subsequent "
"transmissions of the page and remove stored data to prevent storing the "
"fingerprint and loading it after a page reload. Hence, FPD allows the page "
"to compute the fingerprint but (if allowed) blocks the page from uploading "
"the fingerprint away from your computer."
msgstr ""

#: ../content/posts/fingerprinting.md:block 16 (paragraph)
msgid ""
"Other approaches include blocking JavaScript code from suspicious sources or"
" decreasing the surface of browser APIs with explicit permission control. "
"Extensions like [NoScript Suite](https://noscript.net/) are perfect "
"complementary measures to JShelter."
msgstr ""

#: ../content/posts/fingerprinting.md:block 17 (paragraph)
msgid ""
"Despite all the efforts, there is no ultimate approach that can prevent "
"fingerprinting while keeping a high level of usability in mind. Every "
"approach has its strengths and weaknesses, so the challenge is to find a "
"balance between privacy and usability."
msgstr ""

#: ../content/posts/fpdetection.md:block 1 (header)
msgid ""
"title: Catch websites red-handed fingerprinting your browser\n"
"date: 2022-01-14 14:00\n"
"Series: Browser fingerprinting"
msgstr ""

#: ../content/posts/fpdetection.md:block 2 (paragraph)
msgid ""
"We want to identify [fingerprinting](/fingerprinting/) attempts by counting "
"the number of different APIs employed by a page, especially those not "
"frequently used for benign purposes. This blog post introduces a new "
"fingerprinting protection mechanism - FingerPrint Detector (FPD) available "
"in JShelter 0.6. This tool allows users to gain more control over browser "
"fingerprinting, which has become an invisible threat to our privacy."
msgstr ""

#: ../content/posts/fpdetection.md:block 3 (header)
msgid "Heuristics as a template for the fingerprinting detection"
msgstr ""

#: ../content/posts/fpdetection.md:block 4 (paragraph)
msgid ""
"[Mitigation of browser fingerprinting is not "
"straightforward](/fingerprinting/). FPD does not attempt to prevent a script"
" from taking a fingerprint. Neither does FPD falsify a fingerprint. Instead,"
" FPD monitors the APIs that a web page accesses and detects suspicious "
"activities. FPD quickly reacts in case of fingerprint extraction and blocks "
"further web page communication, including storing information."
msgstr ""

#: ../content/posts/fpdetection.md:block 5 (paragraph)
msgid ""
"Several studies over the last decade detected fingerprinting attempts. Many "
"of them used a simple heuristic approach to create a set of conditions. If "
"these conditions are met, suspicious activity is detected. Studies like [The"
" Web Never "
"Forgets](https://securehomes.esat.kuleuven.be/~gacar/persistent/the_web_never_forgets.pdf)"
" and [A 1-million-site Measurement and "
"Analysis](https://www.cs.princeton.edu/~arvindn/publications/OpenWPM_1_million_site_tracking_measurement.pdf)"
" used this approach to measure the real-world occurrence of web tracking. At"
" the same time, they verified the usability of heuristic-based detection. "
"They found the detection effective with a very low false-positive rate. The "
"most challenging part of this approach is a careful selection of detection "
"conditions. Later, studies began to experiment with more sophisticated "
"methods. For example, [Fingerprinting the "
"Fingerprinters](https://web.cs.ucdavis.edu/~zubair/files/fpinspector-"
"sp2021.pdf) used machine learning for fingerprinting detection. They managed"
" to achieve even better precision, but at the cost of demanding model "
"training."
msgstr ""

#: ../content/posts/fpdetection.md:block 6 (paragraph)
msgid ""
"For JShelter, we settled down on using a simple heuristic approach, but with"
" a little twist to it. Internet technology is constantly changing, so we "
"want to make our heuristics as flexible as possible. Instead of hard-coding "
"them, we propose a declarative way to describe the heuristics. This concept "
"allows us to make changes with a new release and progressively [adapt to the"
" latest changes in the field](/crawling_results/). For this purpose, we "
"defined JSON configuration files, which contain all the information required"
" for fingerprinting detection. As these files make an input for our "
"evaluation/detection logic, their content directly reflects how JShelter "
"should evaluate websites in terms of fingerprinting."
msgstr ""

#: ../content/posts/fpdetection.md:block 7 (paragraph)
msgid ""
"On closer inspection, the configuration files contain two basic types of "
"entries. Firstly, they define JavaScript endpoints, which are relevant for "
"fingerprinting detection. Secondly, they group related endpoints. For "
"example, we group endpoints according to their semantic properties. Imagine "
"that there are two different endpoints. Both provide hardware information "
"about the device. We can assign both endpoints to a group that covers access"
" to hardware properties in this scenario. The configuration allows "
"clustering groups to other groups and creating a hierarchy of groups. "
"Ultimately, the configuration is a tree-like structure whose evaluation can "
"detect browser fingerprinting."
msgstr ""

#: ../content/posts/fpdetection.md:block 8 (paragraph)
msgid ""
"The whole evaluation process dynamically observes the API calls performed by"
" a web page. Note that we analyse the calls themselves. Hence, the dynamic "
"analysis overcomes any obfuscation of fingerprinting scripts."
msgstr ""

#: ../content/posts/fpdetection.md:block 9 (paragraph)
msgid ""
"The current heuristics are based on many prior studies, [our own "
"crawl](/crawling_results/), and available tools focused on browser "
"fingerprinting."
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid "We extracted and modified detection rules from studies like:"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid ""
"[Fingerprinting the "
"Fingerprinters](https://web.cs.ucdavis.edu/~zubair/files/fpinspector-"
"sp2021.pdf)"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid ""
"[A 1-million-site Measurement and "
"Analysis](https://www.cs.princeton.edu/~arvindn/publications/OpenWPM_1_million_site_tracking_measurement.pdf)"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid ""
"[The Web Never "
"Forgets](https://securehomes.esat.kuleuven.be/~gacar/persistent/the_web_never_forgets.pdf)"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid "We reflected traits of known fingerprinting tools like:"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid "[FingerprintJS](https://github.com/fingerprintjs)"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid "[Am I Unique](https://amiunique.org/)"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid "[Cover Your Tracks](https://coveryourtracks.eff.org/)"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid "We utilized knowledge of existing detection tools like:"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid ""
"[A Fingerprinting Monitor For Chrome "
"(FPMON)](https://fpmon.github.io/fingerprinting-monitor/)"
msgstr ""

#: ../content/posts/fpdetection.md:block 10 (unordered list)
msgid "[Don't FingerPrint Me (DFPM)](https://github.com/freethenation/DFPM)"
msgstr ""

#: ../content/posts/fpdetection.md:block 11 (header)
msgid "Keep your fingerprint for yourself"
msgstr ""

#: ../content/posts/fpdetection.md:block 12 (paragraph)
msgid ""
"FPD works in three basic phases, *monitoring*, *evaluation* and *reactive*."
msgstr ""

#: ../content/posts/fpdetection.md:block 13 (header)
msgid "Monitoring phase"
msgstr ""

#: ../content/posts/fpdetection.md:block 14 (paragraph)
msgid ""
"If the FPD module is active, it locally logs all accesses to crucial "
"JavaScript API endpoints during the monitoring phase. FPD injects custom "
"wrapping code of all suspicious APIs (properties or methods) into the "
"browser when a user visits a page. Hence, the extension observes API calls "
"initiated by the website."
msgstr ""

#: ../content/posts/fpdetection.md:block 15 (paragraph)
msgid ""
"FPD stores the number of accessed calls in the context of a displayed page. "
"It contains all the metadata needed for evaluation. This metadata includes "
"the number of calls for each logged endpoint with a corresponding argument "
"value. Consequently, FPD can tell how often the visited web page called a "
"particular endpoint and the arguments for these calls."
msgstr ""

#: ../content/posts/fpdetection.md:block 16 (header)
msgid "Evaluation phase"
msgstr ""

#: ../content/posts/fpdetection.md:block 17 (paragraph)
msgid ""
"The evaluation phase starts whenever a new HTTP request occurs. FPD counts "
"the fingerprinting score from the observed calls in the past. If the "
"fingerprinting score is above a specified threshold, FPD considers a web "
"page to perform fingerprinting. In this case, FPD warns the user with a "
"notification."
msgstr ""

#: ../content/posts/fpdetection.md:block 18 (paragraph)
msgid ""
"![Notification example for Chrome (left) and Firefox "
"(right).]({attach}/images/fpdetection/notifications.png)"
msgstr ""

#: ../content/posts/fpdetection.md:block 19 (header)
msgid "Reactive phase"
msgstr ""

#: ../content/posts/fpdetection.md:block 20 (paragraph)
msgid ""
"FPD blocks all subsequent asynchronous HTTP requests initiated by the "
"fingerprinting page in the reaction phase. After that, FPD cleans all "
"supported browser storage mechanisms such as `cookies` and `localStorage`. "
"This measure prevents web pages from caching already extracted fingerprints "
"for later transmission. To be clear, blocking of subsequent requests **may "
"result in breakage** of the visited page. The user can create an exception "
"for the page and add it to a whitelist in this situation. FPD is not active "
"on whitelisted domains for browser fingerprinting. Users can opt in to be "
"fingerprinted on the pages they trust."
msgstr ""

#: ../content/posts/fpdetection.md:block 21 (paragraph)
msgid ""
"For now, we only support whitelisting of the visited domains. However, as "
"fingerprinting is often performed for security reasons and it is more "
"prevalent on login pages, we plan to evaluate if adding a specific behaviour"
" for a URL is a better choice."
msgstr ""

#: ../content/posts/fpdetection.md:block 22 (header)
msgid "Testing fingerprinting detection in the wild"
msgstr ""

#: ../content/posts/fpdetection.md:block 23 (paragraph)
msgid ""
"The line between fingerprinting and non-fingerprinting behaviour is very "
"thin. Defining the fixed threshold can easily result in very doubtful "
"results. Hence, the heuristics approach needs careful fine-tuning."
msgstr ""

#: ../content/posts/fpdetection.md:block 24 (paragraph)
msgid ""
"We have made significant efforts to tailor the heuristics in such a way as "
"to target mainly excessive fingerprints that identify users. We also focused"
" on achieving a very low number of false positives for a better user "
"experience. Because of the radical step of blocking subsequent requests, we "
"must ensure that this blocking occurs only in the necessary cases when there"
" is a high probability of fingerprinting."
msgstr ""

#: ../content/posts/fpdetection.md:block 25 (paragraph)
msgid ""
"Additionally, it is very hard to differentiate between benign and "
"fingerprinting usage of a JavaScript endpoint. From the heuristic point of "
"view, setting a higher threshold for fingerprinting behaviour helps FPD "
"reduce false positives. We decided to verify all these assumptions in "
"practice. We tested FPD on real-world web pages and refined heuristics "
"accordingly."
msgstr ""

#: ../content/posts/fpdetection.md:block 26 (paragraph)
msgid ""
"In terms of methodology, we manually visited homepages and login pages of "
"the top 100 websites from [the Tranco list](https://tranco-"
"list.eu/list/23W9/1000000). For inaccessible websites at the time of "
"testing, we replaced them with random websites from the top 200 list."
msgstr ""

#: ../content/posts/fpdetection.md:block 27 (paragraph)
msgid ""
"With each access to the tested page, we wiped browser settings to ensure "
"determinism of initial access. As the erasure removed any previously-stored "
"identifier, the visited pages may have deployed fingerprinting scripts more "
"aggressively to identify the user and reinstall the identifier."
msgstr ""

#: ../content/posts/fpdetection.md:block 28 (paragraph)
msgid ""
"To boost the probability of fingerprinting even more, we switched off all "
"protection mechanisms offered by the browser. However, we blocked third-"
"party cookies because our previous experience suggests that the missing "
"possibility to store a permanent identifier tempts trackers to start "
"fingerprinting. To see an impact of a browser on the detection process, we "
"used both [Google Chrome](https://www.google.com/chrome/) and [Mozzila "
"Firefox](https://www.mozilla.org/en-US/firefox/)."
msgstr ""

#: ../content/posts/fpdetection.md:block 29 (paragraph)
msgid ""
"We needed the ground truth for web pages employing fingerprinting. We used "
"[FPMON](https://fpmon.github.io/fingerprinting-monitor/) and "
"[DFPM](https://github.com/freethenation/DFPM) to create the ground truth. We"
" selected these two extensions because they are the only ones capable of "
"real-time fingerprinting detection. FPMON reports fingerprinting pages with "
"colour. We assigned Yellow colour 1 point and red colour 3 points. DFPM "
"reports danger warnings. If DFPM reports one danger warning, we assign 1 "
"point to the page. For a higher number of danger warnings, we assign 3 "
"points to the page. Therefore, each page gets a fingerprinting score from 0 "
"to 6."
msgstr ""

#: ../content/posts/fpdetection.md:block 30 (paragraph)
msgid ""
"The score of 6 means that both extensions detected excessive fingerprinting "
"behaviour. Web pages with the score of 6 certainly deploy fingerprinting, "
"and FPD must detect such pages. FPD does not detect fingerprinting on "
"*Google login* pages since FPD heuristics evaluate *Google login* pages just"
" below its threshold. FPMON and DFPM detect fingerprinting on *Google login*"
" pages but just above their thresholds. *Google login* pages occurred six "
"times in total during testing. According to the methodology, these are false"
" negatives. Nevertheless, the final fingerprint is not aggressive enough to "
"provide enough entropy to identify most users uniquely."
msgstr ""

#: ../content/posts/fpdetection.md:block 31 (paragraph)
msgid ""
"The score of 4 means that one extension detected fingerprinting and the "
"other suspects. We classify these web pages as deploying fingerprinting. FPD"
" managed to detect all web pages with two exceptions, *Facebook login* page "
"and `yandex.ru`. Both are border-line cases that do not obtain enough "
"entropy, similarly to *Google login* pages."
msgstr ""

#: ../content/posts/fpdetection.md:block 32 (paragraph)
msgid ""
"The score of 3 means that one extension detected fingerprinting and the "
"other did not detect fingerprinting at all. FPMON and DFPM treat browser "
"fingerprinting differently, so we observed a few web pages with this score. "
"It is questionable how to classify these pages when the reference extensions"
" conflict. FPD does not detect most of these pages. FPD detected "
"fingerprinting only on one of these pages, *Paypal login* page. We consider "
"this detection justified as we manually checked FPD logs and found clear "
"tracks of [canvas fingerprinting](https://fingerprintjs.com/blog/canvas-"
"fingerprinting/). In contrast, FPMON reported negligible fingerprinting "
"signs and did not recognise the fingerprinting attempt."
msgstr ""

#: ../content/posts/fpdetection.md:block 33 (paragraph)
msgid ""
"The score of 2 means that both extensions suspect fingerprinting. We assume "
"that web pages with this score may or may not fingerprint. Nevertheless, the"
" fingerprint is likely not extensive enough to serve as a unique identifier "
"if they do. Moreover, these web pages are prone to misclassification because"
" they may be close to the heuristic threshold. FPD detected two web pages "
"with this score, namely *Cloudflare login* page and *Washingtonpost login* "
"page. A closer analysis revealed that both pages use canvas fingerprinting "
"in conjunction with other fingerprinting methods. Interestingly, the "
"reference extensions could not detect such fingerprinting with enough "
"certainty."
msgstr ""

#: ../content/posts/fpdetection.md:block 34 (paragraph)
msgid ""
"The score of 1 means that only one extension suspects fingerprinting, and "
"the other extension does not detect anything. Similarly, for the score of 0 "
"where neither reference extension does detect fingerprinting. According to "
"our testing methodology, FPD should not detect such web pages as "
"fingerprinting. However, FPD detected fingerprinting on `ebay.com`. Manual "
"inspection showed that `ebay.com` did fingerprint indeed using canvas "
"fingerprinting, [audio fingerprinting](https://fingerprintjs.com/blog/audio-"
"fingerprinting/) and other techniques. Amusingly, the string used by canvas "
"fingerprint says `\"@Browsers~%fingGPRint$&,<canvas>\"`."
msgstr ""

#: ../content/posts/fpdetection.md:block 35 (paragraph)
msgid ""
"We decided to classify web pages as follows. We considered a page to be "
"fingerprinting when its score is above or equal to 4. We did not count pages"
" with the score of 3 or 2 as fingerprinting because they may not be engaged "
"in fingerprinting in reality. It means that FPD may or may not detect such "
"pages; we do not count such classification as an error in both cases. As "
"discussed above, we manually inspected FPD in these situations. Finally, we "
"consider anything below the score of 2 as not fingerprinting."
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "Number of fingerprinting web pages identified by *our ground truth*."
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "Homepages: **20**"
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "Login pages: **34**"
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "Number of fingerprinting web pages identified by *JShelter*."
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "Login pages: **30**"
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "Number of wrong identifications by *JShelter*."
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "Homepages: **2**"
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "False positives: **1**"
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "False negatives: **1**"
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "Login pages: **7**"
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "False positives: **0**"
msgstr ""

#: ../content/posts/fpdetection.md:block 36 (unordered list)
msgid "False negatives: **7**"
msgstr ""

#: ../content/posts/fpdetection.md:block 37 (paragraph)
msgid ""
"At first glance, the numbers are close but not the same. Different heuristic"
" thresholds of the extensions caused the main difference. However, as we "
"found out, the ground truth is far from being flawless. We encountered many "
"exceptions during testing and examined them in detail. In many cases, FPD "
"detects fingerprinting, but the reference extensions do not. For `ebay.com`,"
" neither FPMON nor DPFM identified the ongoing fingerprinting. We got a very"
" low false positive rate and an acceptable false negative rate in terms of "
"methodology."
msgstr ""

#: ../content/posts/fpdetection.md:block 38 (paragraph)
msgid ""
"We also observed other notable behaviour during the testing. The asymmetry "
"between detection on different browsers was minor but did occur sometimes. "
"However, the difference between browsers should be minimal. We had "
"implemented a mechanism that automatically recalculates heuristics to "
"compensate unsupported APIs. Finally, note that blocking tools like "
"*adblockers* can significantly reduce the number of positive detections. "
"These tools use filter lists to block tracking scripts before their "
"execution. Using FPD with a filter-based blocking tool can significantly "
"improve user experience and privacy."
msgstr ""

#: ../content/posts/fpdetection.md:block 39 (header)
msgid "TL;DR"
msgstr ""

#: ../content/posts/fpdetection.md:block 40 (paragraph)
msgid ""
"We have developed a JShelter module dedicated to browser fingerprinting "
"detection called *FingerPrint Detector (FPD)*. FPD applies a heuristic "
"approach to detect fingerprinting behaviour in real-time. FPD counts calls "
"to JavaScript APIs often employed by fingerprinting scripts. When FPD "
"detects fingerprinting attempt, it will (1) inform the user, (2) prevent "
"uploading of the fingerprint to the server, (3) prevent storing the "
"fingerprint for later usage. We tested FPD on the top 100 homepages and "
"login pages. The results show that FPD identifies excessive fingerprinting "
"behaviour and takes the necessary measures against fingerprint leakage."
msgstr ""

#: ../content/posts/fpdetection.md:block 41 (paragraph)
msgid ""
"Nevertheless, there is always more work to do. The detection heuristics "
"still have room for improvement. The real-world testing yields stimulating "
"research questions. How to define an excessive fingerprint? What "
"fingerprints should be blocked by the extension, and what fingerprints "
"should not? What is the best behaviour (threshold) so that the users find "
"the extension helpful?"
msgstr ""

#: ../content/posts/i18n_developers.md:block 1 (header)
msgid ""
"title: What should a JShelter developer know about internationalization?\n"
"date: 2023-08-31 15:00\n"
"Series: i18n"
msgstr ""

#: ../content/posts/i18n_developers.md:block 2 (paragraph)
msgid ""
"We are working to improve the internationalization of JShelter. While the "
"webextension API already contains [APIs](https://developer.mozilla.org/en-"
"US/docs/Mozilla/Add-ons/WebExtensions/API/i18n) for internationalization, "
"not everything works great. This post is written for webextension developers"
" as well as JShelter developers working with strings presented to our users."
" Please see our [other post](/i18n/) if you are looking for ways to "
"translate JShelter."
msgstr ""

#: ../content/posts/i18n_developers.md:block 4 (header)
msgid "Translating manifest, CSS files, and JS files"
msgstr ""

#: ../content/posts/i18n_developers.md:block 5 (paragraph)
msgid ""
"Let us start with the simple and easy items. Adding your translated strings "
"to the [manifest](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions/Internationalization#internationalizing_manifest.json) and"
" [CSS](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions/Internationalization#locale-dependent_css) files is really"
" simple and straightforward. For example, if you want to provide a "
"translatable description of your extension, you would change your "
"`manifest.json` to contain a line like:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 7 (paragraph)
msgid ""
"You add the description as `extensionDescription` to your `messages.json`:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 9 (paragraph)
msgid "Similarly, you can localize CSS files like:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 11 (paragraph)
msgid "Afterward, you define `ShieldOnSlider`, and you are done."
msgstr ""

#: ../content/posts/i18n_developers.md:block 12 (paragraph)
msgid ""
"Translations in JavaScript files work a little bit differently, but it is "
"easy to adapt your JavaScript files. You just use the "
"`browser.i18n.getMessage` [API](https://developer.mozilla.org/en-"
"US/docs/Mozilla/Add-ons/WebExtensions/API/i18n/getMessage). You provide the "
"key in the `messages.json`. This time, you can add parameters that can be "
"utilized inside the `messages.json` file. For example, you can pass a string"
" that should appear inside the translated string:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 14 (paragraph)
msgid "and the `message.json` can contain something like:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 16 (paragraph)
msgid ""
"If you like the placeholders, for example, because you read in the best "
"practices that placeholder substitutions help specify parts that you [do not"
" want translated](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions/Internationalization#hardcoded_substitution). You are out "
"of luck if you want to add parameters to your manifest or CSS files. "
"Luckily, JShelter does not need parameters in manifest and CSS files, and "
"such a need is rare."
msgstr ""

#: ../content/posts/i18n_developers.md:block 17 (header)
msgid "Translating HTML files"
msgstr ""

#: ../content/posts/i18n_developers.md:block 18 (paragraph)
msgid ""
"Webextensions contain HTML pages. For example, you can configure "
"`options_ui` or `default_popup` in `manifest.json`. Even so, the "
"[internationalization page on MDN](https://developer.mozilla.org/en-"
"US/docs/Mozilla/Add-ons/WebExtensions/Internationalization) is quiet about "
"the internationalization of HTML files. Let us have a [look at what others "
"do](https://stackoverflow.com/questions/25467009/internationalization-of-"
"html-pages-for-my-google-chrome-extension)."
msgstr ""

#: ../content/posts/i18n_developers.md:block 19 (paragraph)
msgid ""
"In essence, others add some markup to the HTML file and later process that "
"markup in JS files. For example, in JShelter, we add `data-localize` "
"attribute to each element we want to translate. The attribute holds the key "
"in the `message.json`. For example, JShelter defines:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 21 (paragraph)
msgid ""
"We added a [translation "
"file](https://pagure.io/JShelter/webextension/blob/bff8ce9c69ca28c1952898125983429c1f7f8a32/f/common/i18n_translate_dom.js)"
" `i18n_translate_dom.js` to all HTML pages with translatable elements. The "
"script is simple. It finds elements with the correct attributes and forwards"
" the strings to the `browser.i18n.getMessage` "
"[API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions/API/i18n/getMessage)."
msgstr ""

#: ../content/posts/i18n_developers.md:block 22 (paragraph)
msgid ""
"Still, one needs to take care of special sections in the pages, like "
"[templates](https://pagure.io/JShelter/webextension/blob/bff8ce9c69ca28c1952898125983429c1f7f8a32/f/common/i18n_translate_dom.js#_43)."
msgstr ""

#: ../content/posts/i18n_developers.md:block 23 (paragraph)
msgid ""
"The lack of a standard way to cope with HTML translations means that if you "
"go to different webextension, they will likely have a similar script, but "
"the details would be different. That is not optimal."
msgstr ""

#: ../content/posts/i18n_developers.md:block 24 (header)
msgid "Language priorities"
msgstr ""

#: ../content/posts/i18n_developers.md:block 25 (paragraph)
msgid ""
"Webextension manifest file specifies `default_locale` as the default "
"language. This language is used as the last resort to pick untranslated "
"strings. Each language can have variants like `en_US` and `en_UK`. "
"Translators can create `message.json` for variants and the base language "
"(like `en`). Browsers select translations based on [the algorithm documented"
" on MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions/Internationalization#localized_string_selection). First, "
"they look for the variant, then for the base language, and if they are not "
"successful, they go to the `default_locale`. The API returns an empty string"
" if the default language does not contain the key."
msgstr ""

#: ../content/posts/i18n_developers.md:block 26 (paragraph)
msgid ""
"Unfortunately, there is no way to tweak the algorithm. For example, some "
"languages are similar. Czech speakers mostly understand Slovaks and vice-"
"versa. However, JShelter cannot tweak the algorithm to look at the Czech "
"translation if a Slovak translation is missing."
msgstr ""

#: ../content/posts/i18n_developers.md:block 27 (header)
msgid "Handling plurals"
msgstr ""

#: ../content/posts/i18n_developers.md:block 28 (paragraph)
msgid ""
"Plurals in English are simple for cardinal numbers. There is just the "
"singular and plural version. However, English has several forms for ordinal "
"numbers, like 1st, 2nd, 3rd, 4th, or 21st. Other languages behave "
"[differently](https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html)."
" In essence, almost every language has a specific handling of plurals."
msgstr ""

#: ../content/posts/i18n_developers.md:block 29 (paragraph)
msgid ""
"Although there is the `Intl.PluralRules()` "
"[API](https://developer.mozilla.org/en-"
"US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules) in "
"JavaScript that is available to webextensions, there is no direct support "
"for plural messages in the `browser.i18n` API."
msgstr ""

#: ../content/posts/i18n_developers.md:block 30 (paragraph)
msgid ""
"We considered creating several keys for the plural forms. For example, "
"suppose that JShelter needs to translate a string with `message.json` key "
"`pluralExample`. We would create a code like:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 32 (paragraph)
msgid ""
"At first sight, this is a straightforward solution. However, English defines"
" only categories \"one\" and \"other.\" Imagine that the user uses a "
"different locale with the category \"few.\" If JShelter supports that "
"language and that language defines `pluralExamplefew`, great, everything "
"works. But imagine the key `pluralExamplefew` is missing for that language. "
"The [string selection algorithm](https://developer.mozilla.org/en-"
"US/docs/Mozilla/Add-"
"ons/WebExtensions/Internationalization#localized_string_selection) would "
"search for `pluralExamplefew` in English `message.json`. However, that key "
"would not be defined in English. So, the string selection algorithm would "
"yield an empty string."
msgstr ""

#: ../content/posts/i18n_developers.md:block 33 (paragraph)
msgid "There are several solutions to the problem:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 34 (unordered list)
msgid ""
"Define all variants for the default locale language. We do not like that "
"idea because it would be confusing for the translators — why is there "
"`pluralExamplefew` and other categories if only `one` and `other` are used "
"in English? They might attempt to remove the unused variants. Moreover, we "
"would unnecessarily overload the translators as they would need to provide "
"the default translation even if that is the same as \"other.\" Finally, "
"translators of other languages would likely be confused and add their "
"translations that would overwhelm them as well."
msgstr ""

#: ../content/posts/i18n_developers.md:block 34 (unordered list)
msgid ""
"We could create code that handles the missing translations. For example, the"
" program should check that `message` is not empty. If empty, it would get "
"the plural category for the English locale and the English translation. We "
"might opt for this path in the future."
msgstr ""

#: ../content/posts/i18n_developers.md:block 34 (unordered list)
msgid ""
"There are libraries like [webextension-"
"plural](https://github.com/joelspadin/webextension-plural) that specialize "
"in this task. However, `webextension-plural` has not been developed for "
"several years."
msgstr ""

#: ../content/posts/i18n_developers.md:block 35 (paragraph)
msgid ""
"As JShelter would benefit from plurals only in notifications of Network "
"Boundary Shield that we might be forced to remove in Manifest v3, we decided"
" not to write complex code to handle all exceptions and not to add "
"additional dependencies. We decided to generate messages like \"Blocked "
"messages: 5\"."
msgstr ""

#: ../content/posts/i18n_developers.md:block 36 (header)
msgid "Placeholders used in complex messages"
msgstr ""

#: ../content/posts/i18n_developers.md:block 37 (paragraph)
msgid ""
"[Developers should not make assumptions about the composition of the "
"sentences](https://mozilla-l10n.github.io/documentation/localization/dev_best_practices.html#splitting-"
"and-composing-sentences). However, some texts need special rules."
msgstr ""

#: ../content/posts/i18n_developers.md:block 38 (paragraph)
msgid ""
"Consider the buttons for adding and removing exceptions for Network Boundary"
" Shield and Fingerprint Detector. For example, the \"Enable for the selected"
" domains\" button caption. We want to give the user a full and clear "
"explanation; hence, the text is long. But we also want to emphasize the word"
" \"Enable.\" So the button caption uses HTML markup: "
"`<strong>Enable</strong> for the selected domains`."
msgstr ""

#: ../content/posts/i18n_developers.md:block 39 (paragraph)
msgid ""
"We decided to use placeholders to describe to translators how to handle the "
"translation:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 41 (paragraph)
msgid ""
"This way, translators are free to change the structure of the message. For "
"example, consider that the translator decides that an appropriate "
"translation to Czech is \"Vybrané domény "
"&lt;strong&gt;povol&lt;/strong&gt;\". The word \"enable\" is translated as "
"\"povol\". The translator can generate text like:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 43 (paragraph)
msgid ""
"All perfect until we decided to use "
"[Weblate](https://hosted.weblate.org/projects/jshelter/webextension/) to "
"help with the translation, for example, to notify translators about new and "
"changed strings that need translations. According to the "
"[docs](https://docs.weblate.org/en/latest/formats/webextension.html), "
"Weblate does support Webextension JSON. [Weblate "
"manual](https://readthedocs.org/projects/weblate/downloads/pdf/weblate-3.9.1/)"
" lists `placeholders as supported. The Weblate UI does not properly display "
"placeholders. Translators [do not see the "
"description](https://github.com/WeblateOrg/weblate/issues/3398) and example "
"content of the placeholders. They cannot translate the content of the "
"placeholder."
msgstr ""

#: ../content/posts/i18n_developers.md:block 44 (paragraph)
msgid "In this case, we could change the definition to something like:"
msgstr ""

#: ../content/posts/i18n_developers.md:block 46 (paragraph)
msgid ""
"However, we have other complex cases where dividing the message into "
"placeholders makes sense. For example, we suggest different rules for "
"translating a part of the message, like API names. Hence, we created "
"[scripts](https://pagure.io/JShelter/webextension/blob/main/f/tools/i18n) to"
" help synchronize the strings between the repository and Weblate so that all"
" strings can be translated in Weblate. A developer needs to run the "
"synchronization scripts manually. The expected order is to first propagate "
"changes from Grammarly to main (or other branch), and after that, propagate "
"the changes from that branch in the repository to Weblate."
msgstr ""

#: ../content/posts/i18n_developers.md:block 47 (header)
msgid "Additional reading"
msgstr ""

#: ../content/posts/i18n_developers.md:block 48 (paragraph)
msgid ""
"If you are a JShelter developer or are interested in helping JShelter's "
"internationalization development, please read [localization best practices "
"for "
"developers](https://mozilla-l10n.github.io/documentation/localization/dev_best_practices.html),"
" [MDN guide on webextension "
"internationalization](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions/Internationalization), and the [i18n API "
"documentation](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions/API/i18n)."
msgstr ""

#: ../content/posts/i18n.md:block 1 (header)
msgid ""
"title: JShelter can be translated into different languages\n"
"date: 2023-09-08 14:00\n"
"Series: i18n\n"
"series_index: 1"
msgstr ""

#: ../content/posts/i18n.md:block 2 (paragraph)
msgid ""
"JShelter's audience is international. As not all people speak English, "
"JShelter is now adding support for internationalization. Hence, it can be "
"translated into languages other than English."
msgstr ""

#: ../content/posts/i18n.md:block 3 (paragraph)
msgid ""
"The webextension API already contains "
"[APIs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions/API/i18n) that help to [translate "
"extensions](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions/Internationalization). This way we can localize not only "
"the interface of the extension but also its description and even the name."
msgstr ""

#: ../content/posts/i18n.md:block 5 (header)
msgid "Status"
msgstr ""

#: ../content/posts/i18n.md:block 6 (paragraph)
msgid ""
"JShelter can be translated to other languages as of version 0.14. Besides "
"English, Czech and Russian translations are also available."
msgstr ""

#: ../content/posts/i18n.md:block 7 (paragraph)
msgid ""
"Nevertheless, we are looking for translators in other languages. If you are "
"willing to translate JShelter to a language that you know, please read on. "
"We suggest that you contact us early so that we have information about "
"ongoing translations and that we can tell you if someone else is already "
"interested in the same language as you."
msgstr ""

#: ../content/posts/i18n.md:block 8 (header)
msgid "How can I translate JShelter? Option 1: Weblate"
msgstr ""

#: ../content/posts/i18n.md:block 9 (paragraph)
msgid ""
"We use [Weblate](https://github.com/WeblateOrg/weblate) to manage the "
"translations. This software helps us monitor the status of the translations,"
" providing suggestions and improving the lives of the translators. If you "
"want to help, visit [JShelter on "
"Weblate](https://hosted.weblate.org/projects/jshelter/webextension/). You "
"can send us suggestions without registration. However, some features, like "
"notifications, are only available to registered users."
msgstr ""

#: ../content/posts/i18n.md:block 10 (paragraph)
msgid "When you start translating, you should see a form like:"
msgstr ""

#: ../content/posts/i18n.md:block 11 (paragraph)
msgid "![A screenshot from Weblate]({attach}/images/i18n/webly.png)"
msgstr ""

#: ../content/posts/i18n.md:block 12 (paragraph)
msgid "The interface shows:"
msgstr ""

#: ../content/posts/i18n.md:block 13 (ordered list)
msgid "The name of the key of the currently translated string,"
msgstr ""

#: ../content/posts/i18n.md:block 13 (ordered list)
msgid "the original English translation,"
msgstr ""

#: ../content/posts/i18n.md:block 13 (ordered list)
msgid "the description of the usage of the string,"
msgstr ""

#: ../content/posts/i18n.md:block 13 (ordered list)
msgid "the translation to the current target language,"
msgstr ""

#: ../content/posts/i18n.md:block 13 (ordered list)
msgid ""
"the information on similar and nearby strings that might be handy to grasp "
"the context of the string,"
msgstr ""

#: ../content/posts/i18n.md:block 13 (ordered list)
msgid "glossary containing key terms used in the project."
msgstr ""

#: ../content/posts/i18n.md:block 14 (paragraph)
msgid ""
"Most of the strings that translators face are simple, as shown above. "
"However, some strings are composed with `placeholders` (see the translation "
"option 2 for more details on placeholders). For example, consider [string "
"`defaultLevelSelection`](https://hosted.weblate.org/translate/jshelter/webextension/en/?checksum=a11db49ff616c6f0&sort_by=-priority,position)."
" Its English translation is `Default level ($levelName$)`. Strings enclosed "
"by `$` signs (`levelName` in this case) are `placeholders`. Each placeholder"
" is in the database with the key composed as `the base key "
"###placeholders### placeholder name`. So, in this case, the key of the "
"placeholder is `defaultLevelSelection###placeholders###levelName`."
msgstr ""

#: ../content/posts/i18n.md:block 15 (paragraph)
msgid ""
"Most placeholders should not be changed. The typical content of such "
"placeholders is like `$1`. It means that the extension generates the "
"content, and typically, translators are supposed to keep the string intact. "
"Always read carefully the description of the usage of the string that "
"indicates how the string should be translated."
msgstr ""

#: ../content/posts/i18n.md:block 16 (paragraph)
msgid ""
"Some placeholder strings contain the names of APIs or other technical terms."
" For example, `jssgroupTimePrecisionDescription2###placeholders###apis` in "
"English contains `(Date, Performance, events, Gamepad API, and Web VR API)`."
" Please read the instructions for each string carefully. In this case, "
"translators should keep the names of the APIs but translate the punctuation "
"and conjunctions."
msgstr ""

#: ../content/posts/i18n.md:block 17 (paragraph)
msgid ""
"Please consider the translations of each placeholder in the context of the "
"base string so that the whole string makes sense. It should be easy to find "
"the base key. Look at the start of the placeholder key or to the "
"instructions. Weblate should show the base string and its placeholders in "
"the *Nearby strings* section."
msgstr ""

#: ../content/posts/i18n.md:block 18 (paragraph)
msgid ""
"Strings containing URLs should not be translated. However, occasionally, "
"there is a localized version of the content at the original URL. In such "
"cases, it makes sense to provide URL to the localized version."
msgstr ""

#: ../content/posts/i18n.md:block 19 (paragraph)
msgid ""
"As we explain below, we do not support plural forms due to technical "
"limitations and our decisions. So, use phrasing that does not need plurals. "
"See the example for option 2 for more details."
msgstr ""

#: ../content/posts/i18n.md:block 20 (header)
msgid "How can I translate JShelter? Option 2: JSON files in the repository"
msgstr ""

#: ../content/posts/i18n.md:block 21 (paragraph)
msgid ""
"Technically, translations are strings located in JSON files, one JSON file "
"per language. The languages are stored in the "
"[`common/_locales`](https://pagure.io/JShelter/webextension/blob/i18n/f/common/_locales)"
" directory. If you do not see your language there, you can add a new "
"language by creating a new directory with the [language "
"code](https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html)"
" as the name, see the [docs](https://developer.mozilla.org/en-"
"US/docs/Mozilla/Add-"
"ons/WebExtensions/Internationalization#localized_string_selection)."
msgstr ""

#: ../content/posts/i18n.md:block 22 (paragraph)
msgid ""
"Then, copy the `en/messages.json` to the just created directory, and you "
"have the basis for the translation."
msgstr ""

#: ../content/posts/i18n.md:block 23 (paragraph)
msgid "Next, go through all the strings and translate them to your language."
msgstr ""

#: ../content/posts/i18n.md:block 24 (paragraph)
msgid "Typically, a translation entry looks like this:"
msgstr ""

#: ../content/posts/i18n.md:block 26 (paragraph)
msgid ""
"The first line (`javascriptShield`) displays the name of the string. "
"JShelter pairs the name of the string with the locations in the source code "
"where this translation should appear. So, do not change that line."
msgstr ""

#: ../content/posts/i18n.md:block 27 (paragraph)
msgid ""
"The second line (key `message`) shows the actual translation. Usually, "
"translators are supposed to change that line."
msgstr ""

#: ../content/posts/i18n.md:block 28 (paragraph)
msgid ""
"The third line is the description of the context of the string. So, for "
"example, the translator would learn where and how the extension uses the "
"message. Please do not translate the description."
msgstr ""

#: ../content/posts/i18n.md:block 29 (paragraph)
msgid "So, for example, in the Czech translation, the entry becomes:"
msgstr ""

#: ../content/posts/i18n.md:block 31 (paragraph)
msgid "However, some entries are more tricky, let us look at:"
msgstr ""

#: ../content/posts/i18n.md:block 33 (paragraph)
msgid ""
"The `message` contains a variable enclosed by the dollar sign (in this case,"
" `levelName`). Note that the `placeholders` section contains the "
"specification of the variable. We add substrings with special properties to "
"the `placeholders` section. Such substrings are either filled automatically "
"or hold data that should be translated according to the different rules than"
" the `message`. Follow the `description` to learn the rules."
msgstr ""

#: ../content/posts/i18n.md:block 34 (paragraph)
msgid ""
"In this case, the single `placeholders` entry contains three keys: "
"`content`, `description`, and `example`. The meaning of the description is "
"the same as in the original case. It explains the context of the variable. "
"Additionally, `example` gives example strings or their description to "
"provide the translator with more information about the possible content. The"
" `content` controls how the content is created. If the file does not give "
"translators any further instructions (like in this case), please do not "
"translate the `placeholder` section. So the translated entry becomes:"
msgstr ""

#: ../content/posts/i18n.md:block 36 (paragraph)
msgid "See that only the `message` string changed."
msgstr ""

#: ../content/posts/i18n.md:block 37 (paragraph)
msgid "A more complicated example is:"
msgstr ""

#: ../content/posts/i18n.md:block 39 (paragraph)
msgid ""
"This string holds two placeholders: `apis` and "
"`jssgroupPhysicalLocationGeolocation`. Let us start from the end. "
"`jssgroupPhysicalLocationGeolocation` should not be touched by the "
"translator. The text explains that `jssgroupPhysicalLocationGeolocation` "
"will hold the translation of the string with the same name during the "
"execution of the extension (\"Physical location (geolocation)\" in this "
"case). Do not change anything in entries like "
"`jssgroupPhysicalLocationGeolocation` during the translation."
msgstr ""

#: ../content/posts/i18n.md:block 40 (paragraph)
msgid ""
"Then, there is the entry called `apis`. If you look at the content, it does "
"not refer to any automatically filled string like the previous examples. "
"Instead, the string holds the names of several APIs. The `desription` "
"provides instructions on how to handle the translation. In this case, we "
"suggest keeping the APIs' names in English. That way, the user can search "
"for the APIs for more information. If you translate the API names, the user "
"would likely be unable to find any information about the API. However, "
"different languages have different rules for punctuation, and the "
"conjunction *and* must be translated. So the translation can look like:"
msgstr ""

#: ../content/posts/i18n.md:block 42 (paragraph)
msgid ""
"Note that the original translation used a different kind of quotation marks."
" The English original uses the same character as the JSON delimiter. Hence, "
"the character '' precedes the quotation mark. The Czech translation does not"
" use quotation marks conflicting with the JSON quotation marks, so it does "
"not need the '' sign."
msgstr ""

#: ../content/posts/i18n.md:block 43 (paragraph)
msgid ""
"Occasionally, we extract URLs to the `placeholders` section to highlight "
"that they should not be translated like:"
msgstr ""

#: ../content/posts/i18n.md:block 45 (paragraph)
msgid ""
"Note that strings for translation can hold HTML markup in some cases. In "
"that case, we suggest keeping the same markup. However, if other languages "
"handle such texts differently, translators are free to apply such rules. The"
" translation can look like:"
msgstr ""

#: ../content/posts/i18n.md:block 47 (paragraph)
msgid ""
"On rare occasions, we do not expect the translators to touch the `message` "
"itself but rather work with the placeholders. For example, see:"
msgstr ""

#: ../content/posts/i18n.md:block 49 (paragraph)
msgid ""
"You can see that the message holds a template with an HTML markup. In this "
"case, we opted for this approach for several reasons:"
msgstr ""

#: ../content/posts/i18n.md:block 50 (unordered list)
msgid ""
"We expect translators to preserve the same template (`message`) in most, if "
"not all, languages."
msgstr ""

#: ../content/posts/i18n.md:block 50 (unordered list)
msgid "Each paragraph (`placeholders` entry) can have specific instructions."
msgstr ""

#: ../content/posts/i18n.md:block 50 (unordered list)
msgid ""
"The text blocks are not as long as a single block containing all text would "
"be."
msgstr ""

#: ../content/posts/i18n.md:block 51 (paragraph)
msgid ""
"English has a single plural form for cardinal numbers (usually a suffix `s` "
"or `es` appended to the singular form) and several forms of ordinal numbers "
"(1st, 2nd, 3rd, 4th). [Other languages behave "
"differently.](https://www.unicode.org/cldr/charts/43/supplemental/language_plural_rules.html)"
" Unfortunately, the [Webextension APIs do not handle plurals "
"well](/i18n_developers/) and JShelter could use plurals only in "
"notifications of Network Boundary Shield, so we decided to rephrase the "
"messages so plurals are not needed:"
msgstr ""

#: ../content/posts/i18n.md:block 53 (header)
msgid "Final remarks"
msgstr ""

#: ../content/posts/i18n.md:block 54 (paragraph)
msgid ""
"If you want to start translating a new language, let us know. For example, "
"you can open an issue in the [issue "
"tracker](https://pagure.io/JShelter/webextension/issues) or send us "
"[e-mail](mailto:jshelter@gnu.org). If you are in doubt about how to "
"translate a string or do not understand its meaning, let us know in an "
"[issue](https://pagure.io/JShelter/webextension/issues) or send us "
"[e-mail](mailto:jshelter@gnu.org)."
msgstr ""

#: ../content/posts/jsrfinal.md:block 1 (header)
msgid ""
"title: Final remarks on the JSR project\n"
"date: 2022-05-10 18:00\n"
"Series: JShelter background"
msgstr ""

#: ../content/posts/jsrfinal.md:block 2 (paragraph)
msgid ""
"The [JavaScript Restrictor](https://nlnet.nl/project/JSRestrictor/) "
"([JSR](/support/)) project (supported by [NGI0 PET "
"Fund](https://nlnet.nl/PET), a fund established by "
"[NLnet](https://nlnet.nl/) with financial support from the European "
"Commission's [Next Generation Internet](https://ngi.eu/) programme, under "
"the aegis of DG Communications Networks, Content and Technology under grant "
"agreement No 825310) is heading towards its end, and we summarize what the "
"project gave JShelter and reiterate the chosen approaches."
msgstr ""

#: ../content/posts/jsrfinal.md:block 3 (header)
msgid "What are the steps that JShelter takes to protect users?"
msgstr ""

#: ../content/posts/jsrfinal.md:block 4 (paragraph)
msgid ""
"During the NGI0 PET Fund JSR project, we investigated fingerprinting scripts"
" and prepared wrappers, developed Fingerprint Detector, ported anti-"
"fingerprinting mechanisms from Brave, and improved the reliability of the "
"code-injection mechanisms (the credit for the relaible injection goes to "
"[the parallel NGI0 PET project](https://nlnet.nl/project/JShelter/)). Let us"
" go through the list in more detail:"
msgstr ""

#: ../content/posts/jsrfinal.md:block 5 (paragraph)
msgid ""
"We reviewed literature focusing on the fingerprinting scripts and studied "
"APIs [declined by Apple](https://github.com/polcak/jsrestrictor/issues/66). "
"During the project, we added or improved wrappers to JavaScript Shield for:"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "All API calls providing timestamps,"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`window.name`,"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`MediaDevices.prototype.enumerateDevices`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "Beacon API,"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "Canvas API and Web GL API,"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "Audio API,"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`Navigator.prototype.hardwareConcurrency`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`Navigator.prototype.deviceMemory`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`Navigator.prototype.getGamepads`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`Navigator.prototype.activeVRDisplays`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`Navigator.prototype.plugins`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid ""
"Sensor API: Magnetometer, Accelerometer, LinearAccelerationSensor, "
"GravitySensor, Gyroscope,"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid ""
"AbsoluteOrientationSensor, RelativeOrientationSensor, and AmbientLightSensor"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "BigInt typed arrays"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`Navigator.prototype.requestMediaKeySystemAccess`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`MediaCapabilities.prototype.encodingInfo`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`MediaCapabilities.prototype.decodingInfo`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "`HTMLMediaElement.prototype.canPlayType`"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "Network Information API"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "Web NFC API"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "Cooperative Scheduling of Background Tasks API"
msgstr ""

#: ../content/posts/jsrfinal.md:block 6 (unordered list)
msgid "User idle detection"
msgstr ""

#: ../content/posts/jsrfinal.md:block 7 (paragraph)
msgid ""
"Note that JShelter modifies APIs depending on the selected JavaScript Shield"
" level and the tweaks for the visited domain."
msgstr ""

#: ../content/posts/jsrfinal.md:block 8 (paragraph)
msgid ""
"Previous literature modifies outputs of some APIs differently during "
"repeated calls. JShelter [adopted the model of Brave](/farbling/). Hence, "
"different origins read different values from the same APIs. One origin reads"
" the same values for each repeated reading in the same browser session. "
"Therefore, a fingerprint computed from these values is different for each "
"origin and session, making cross-site correlation harder. Note that some "
"identifiers like an IP address are outside of JShelter reach. JShelter "
"provides different readings to the same origin in a new browser session."
msgstr ""

#: ../content/posts/jsrfinal.md:block 9 (paragraph)
msgid ""
"[FP-Random](https://github.com/plaperdr/fprandom) modifies data inserted "
"into the canvas. For example, if the page wants to draw with orange colour, "
"FP-Random draws with a different shade of orange. We do not think that this "
"is a good strategy for JShelter:"
msgstr ""

#: ../content/posts/jsrfinal.md:block 10 (unordered list)
msgid ""
"JShelter currently does not modify what users see in canvases (i.e. the "
"browser does not modify the visual representation). JShelter only modifies "
"read data - so each script sees different values than users. In other words,"
" while FP-Random breaks both visual representation and export functions, "
"JShelter breaks only export functions."
msgstr ""

#: ../content/posts/jsrfinal.md:block 10 (unordered list)
msgid ""
"Web GL offers visual effects produced by lighting, textures and other "
"techniques. Identifying all mechanisms that need to be wrapped and modified "
"seem to be too complex and out of the reach of this project."
msgstr ""

#: ../content/posts/jsrfinal.md:block 11 (paragraph)
msgid ""
"JShelter provides [Fingerprint Detector](/fpdetection/) (FPD), a module that"
" heuristically detects fingerprinting and notifies users with an option to "
"block future communications. This anti-fingerprinting mechanism is "
"orthogonal to the little lies anti-fingerprinting mechanisms in JavaScript "
"Shield, and we advise using both mechanisms. Little lies help if the "
"fingerprinting scripts upload some readings before FPD detects the attempt "
"or the user deactivates FPD for a website. FPD provides an additional safety"
" net for fingerprinters trying to nullify the little lies. FPD also provides"
" a report page that can educate users about the APIs misused for "
"fingerprinting. We developed code for crawling websites and detecting APIs "
"often blocked by uBlock Origin with the goal of gradually improving "
"heuristics. We do not have an automatic generation of heuristics, and manual"
" oversight is needed."
msgstr ""

#: ../content/posts/jsrfinal.md:block 12 (paragraph)
msgid ""
"The badge icon does not show level ID anymore. It shows the number of "
"wrapping groups accessed by the current page as a number; the colour informs"
" the user about the likelihood that the current page tries to fingerprint "
"the user. The user can see more details about the activated wrappers and FPD"
" findings in the popup window."
msgstr ""

#: ../content/posts/jsrfinal.md:block 13 (paragraph)
msgid ""
"JShelter depends on [NSCL](https://github.com/hackademix/nscl/) (developed "
"outside JSR project) that provides reliable cross-browser support to inject "
"scripts before page scripts can access original APIs. That solved several "
"long-standing bugs and allowed the extension to be used with confidence. "
"However, NSCL does not implement reliable code injections into WebWorkers, "
"so we apply Strict WebWorker protection by default. The protection disables "
"WebWorkers and replaces them with a polyfill."
msgstr ""

#: ../content/posts/jsrfinal.md:block 14 (header)
msgid "Issues"
msgstr ""

#: ../content/posts/jsrfinal.md:block 15 (paragraph)
msgid ""
"During the final stages of the NGI0 PET Fund project JSR project, we "
"investigated the consistency of the mechanisms and their real-world "
"deployment. We closed [6 issues on "
"Pagure](https://pagure.io/JShelter/webextension/issues?status=Closed&milestone=NLNet+evaluation)"
" and [13 issues on "
"Github](https://github.com/polcak/jsrestrictor/issues?q=is%3Aissue+label%3A%22NLNet+project+evaluation+phase%22+is%3Aclosed)."
msgstr ""

#: ../content/posts/jsrfinal.md:block 16 (paragraph)
msgid ""
"5 investigated issues remain open on "
"[Github](https://github.com/polcak/jsrestrictor/issues?q=is%3Aissue+label%3A%22NLNet+project+evaluation+phase%22+is%3Aopen)."
" For three we need more details or cannot reproduce the issue, two refer to "
"bugs that we are trying to fix (the issues were delegated to other JShelter "
"developer outside the JSR project)."
msgstr ""

#: ../content/posts/jsrfinal.md:block 17 (paragraph)
msgid ""
"We opened [8 "
"issues](https://pagure.io/JShelter/webextension/issues?status=Open&tags=enhancement&milestone=NLNet+evaluation&close_status=)"
" that cover possible enhancement of the JShelter, future directions, and "
"possible ideas for future projects. We have additional [5 opened issues on "
"Pagure](https://pagure.io/JShelter/webextension/issues?status=Open&milestone=NLNet+evaluation&close_status=)"
" that we investigated during the evaluation phase. "
"[One](https://pagure.io/JShelter/webextension/issue/55) is a duplicate of "
"the issue opened at Github, "
"[another](https://pagure.io/JShelter/webextension/issue/37) is almost "
"closed. We are working on all 5 issues outside the JSR project."
msgstr ""

#: ../content/posts/jsrfinal.md:block 19 (paragraph)
msgid ""
"JShelter is not perfect, but we believe that we are heading in the right "
"direction. We want to continue to work on this project. However, be patient "
"with some issues that need time and a lot of work to be solved. The JSR "
"project and the [parallel NGI0 PET Fund "
"project](https://nlnet.nl/project/JShelter/) transformed the original "
"JavaScript Restrictor extension to JShelter, suitable for everyday "
"protection."
msgstr ""

#: ../content/posts/jsrfinal.md:block 20 (paragraph)
msgid ""
"If you have not noticed yet, we created a [FAQ section](/faq/) and the page "
"describing [JShelter threat model](/threatmodel/) during the final stages of"
" the JSR project."
msgstr ""

#: ../content/posts/localportscanning.md:block 1 (header)
msgid ""
"title: How JShelter prevents other parties from sniffing on your local applications?\n"
"date: 2021-06-15 09:00"
msgstr ""

#: ../content/posts/localportscanning.md:block 2 (paragraph)
msgid ""
"We recently found a [blog post](https://blog.nem.ec/2020/05/24/ebay-port-"
"scanning/) about ThreatMetrix Inc. (a part of LexisNexis) scanning locally "
"open ports for about 30,000 web sites, including eBay. The figure below "
"shows that a browser tries to connect to ports commonly used for remote "
"access to the computer (e.g., RDesktop, VNC, TeamViewer) and other "
"applications."
msgstr ""

#: ../content/posts/localportscanning.md:block 3 (paragraph)
msgid ""
"![A screenshot of the browser being used as a proxy to scan locally open "
"ports]({attach}/images/portscan-1_captured_traffic.png)"
msgstr ""

#: ../content/posts/localportscanning.md:block 4 (paragraph)
msgid ""
"The obvious question is, what is the reason for such behaviour? The simple "
"answer is security. See additional links to [Security "
"Boulevard](https://securityboulevard.com/2020/05/is-ebay-port-scanning-your-"
"pc-probably/), [Avast](https://blog.avast.com/why-is-ebay-port-scanning-my-"
"computer-avast), and [The "
"register](https://www.theregister.com/2020/05/26/ebay_port_scans_your_pc/)."
msgstr ""

#: ../content/posts/localportscanning.md:block 5 (paragraph)
msgid ""
"One possibility is that ThreatMetrix creates a "
"[fingerprint](https://arxiv.org/pdf/1905.01051.pdf), and locally running "
"applications are a part of the fingerprint. Consequently, the authentication"
" algorithm stores attributes about your device(s) and compare them during "
"each log in with the previous values. Seeing that you are logging in using a"
" previously seen device, the algorithm can let you in with just a password "
"without additional proves. However, should you use a new device, the "
"algorithm might decide that additional authentication steps are required and"
" send you an SMS."
msgstr ""

#: ../content/posts/localportscanning.md:block 6 (paragraph)
msgid ""
"Another option is that ThreatMetrix knows that many fraudulent activities "
"occur on devices with specific ports open. Recall that the ports being "
"checked concern remote desktop access. Having a remote desktop port open "
"means that the computer may be used by an adversary that does not sit near "
"the computer but is connected remotely. Consequently, the authentication "
"algorithm might decide that additional proves about the user identity should"
" be checked."
msgstr ""

#: ../content/posts/localportscanning.md:block 7 (paragraph)
msgid ""
"We do not know what the real reason behind the scanning is. It might be one "
"of the above, both, or a similar reason."
msgstr ""

#: ../content/posts/localportscanning.md:block 8 (header)
msgid "Ethical and legal issues"
msgstr ""

#: ../content/posts/localportscanning.md:block 9 (paragraph)
msgid ""
"Although it could be that the underlying intentions are benign and users "
"actually do benefit from the scanning, the scanning raises some ethical "
"issues."
msgstr ""

#: ../content/posts/localportscanning.md:block 10 (paragraph)
msgid ""
"Very often, security and privacy are interconnected. But sometimes, one "
"might increase security by revealing something private. In this case, "
"ThreatMetrix learns information about the running device that is not obvious"
" to the device owner (a user or a company). Typically, the owner of the "
"device does not even know that such information can leak. If the information"
" stays with ThreatMetrix, then the benefits could appear to be greater than "
"the disadvantages. However, adversaries could stole information from "
"ThreatMetrix (see for example the [Ecquifax "
"breach](https://en.wikipedia.org/wiki/2017_Equifax_data_breach)) or the "
"company can start to [sell](https://www.vice.com/en/article/qjdkq7/avast-"
"antivirus-sells-user-browsing-data-investigation) the "
"[information](https://www.pcmag.com/news/the-cost-of-avasts-free-antivirus-"
"companies-can-spy-on-your-clicks) or even [share with "
"others](https://brave.com/rtb-evidence/)."
msgstr ""

#: ../content/posts/localportscanning.md:block 11 (paragraph)
msgid ""
"So is the scanning and data collecting legal? As some of our developers and "
"users are based in the EU, we will dig into the EU perspective. You might "
"want to consult your local laws if you are outside the EU. Moreover, as we "
"are not lawyers, you might want to consult one even in the EU."
msgstr ""

#: ../content/posts/localportscanning.md:block 12 (paragraph)
msgid ""
"[EU ePrivacy Directive](https://eur-lex.europa.eu/legal-"
"content/EN/ALL/?uri=CELEX:32002L0058) applies. However, as [WP29 "
"clarified](https://ec.europa.eu/justice/article-29/documentation/opinion-"
"recommendation/files/2014/wp224_en.pdf) (use case 7.5), user-centric "
"security can be viewed as strictly necessary to provide the service. So it "
"seems likely that port scanning for security reasons would trigger the "
"ePrivacy exception and user consent is not necessary."
msgstr ""

#: ../content/posts/localportscanning.md:block 13 (paragraph)
msgid ""
"As the port scanning is a part of the login mechanism, open ports are "
"personal data without doubts. So GDPR also applies. GDPR also list security "
"as a possible legitimate interest of a data controller (e.g. eBay), see "
"recital 49. Nevertheless, if such a scan is proportionate is an open "
"question; it is possible that the legitimate interests of data controllers "
"(such as eBay) are overriden by the interests or fundamental rights and "
"freedoms of the data subject (you), see Article(6)(1)(f). The Court of "
"Justice of EU (CJEU) decided several issues that concerned legitimate "
"interests and the necessity of processing, e.g. [C-13/16, point 30 that also"
" points to other related "
"cases](https://curia.europa.eu/juris/liste.jsf?num=C-13/16) or [C-708/18 "
"points 40–45](https://curia.europa.eu/juris/liste.jsf?num=C-708/18). It "
"might be possible that it is strictly necessary for eBay to perform local "
"port scanning."
msgstr ""

#: ../content/posts/localportscanning.md:block 14 (paragraph)
msgid ""
"Nevertheless, Article 12-14 of GDPR lists requirements on the information "
"that a data controller should reveal to each data subject before the data "
"processing starts or in a reasonable time afterwards. Hence, each controller"
" employing ThreatMetrix should reveal, for example, in the privacy policy, "
"what categories of data it is using and for which purposes. From the "
"[linked](https://blog.avast.com/why-is-ebay-port-scanning-my-computer-avast)"
" "
"[articles](https://www.theregister.com/2020/05/26/ebay_port_scans_your_pc/),"
" it seems that ThreatMetrix and eBay are secretive about data being "
"collected."
msgstr ""

#: ../content/posts/localportscanning.md:block 15 (paragraph)
msgid ""
"Another GDPR issue might be data transfers to third countries. Data "
"transfers of open ports may not be compatible with GDPR in the light of the "
"[CJEU C-311/18](https://curia.europa.eu/juris/liste.jsf?num=C-311/18) "
"decision if the information leaves EEA."
msgstr ""

#: ../content/posts/localportscanning.md:block 16 (header)
msgid ""
"Why is not my browser protecting me from remote servers accessing local "
"information?"
msgstr ""

#: ../content/posts/localportscanning.md:block 17 (paragraph)
msgid ""
"OK, so even though the scanning could be legal, one can disagree that others"
" should be allowed to sniff on local applications. So why does a browser "
"leak the information?"
msgstr ""

#: ../content/posts/localportscanning.md:block 18 (paragraph)
msgid ""
"Well, the browser employs so called [same origin "
"policy](https://developer.mozilla.org/en-US/docs/Web/Security/Same-"
"origin_policy) (SOP) that in abstract theory should prevent websites from "
"the scans in question. As your local computer is of a different origin from "
"the remote website, your computer should be protected by SOP. Nevertheless, "
"SOP has its limitations. First of all, some [cross-origin resource "
"sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) is "
"beneficial, so the browser cannot block outgoing requests to other origins. "
"Such behaviour opens possibilities for [side-"
"channels](https://www.forcepoint.com/sites/default/files/resources/files/report-"
"attacking-internal-network-en_0.pdf) to be identified. So even though the "
"web page cannot communicate with applications on your computer (or in your "
"network) without the cooperation of these applications, it can observe the "
"behaviour and make some conclusions based on the observed errors, timing, "
"etc."
msgstr ""

#: ../content/posts/localportscanning.md:block 19 (paragraph)
msgid ""
"An (ad) blocker can prevent you from the activity. As the blockers typically"
" leverage blocklists, such a port scanning script URL needs to match a rule "
"in a block list. Once information about a misbehaving script becomes public,"
" a rule can be added to a block list. However, this could take some time. "
"Additional techniques like [DNS de-"
"cloaking](https://blog.lukaszolejnik.com/large-scale-analysis-of-dns-based-"
"tracking-evasion-broad-data-leaks-included/) need to be applied in this "
"case."
msgstr ""

#: ../content/posts/localportscanning.md:block 20 (header)
msgid "Network Boundary Shield to the rescue"
msgstr ""

#: ../content/posts/localportscanning.md:block 21 (paragraph)
msgid ""
"JShelter contains a Network Boundary Shield (NBS) that blocks outgoing "
"browser requests based on the observed behaviour, i.e. a page hosted on "
"public internet tries to access local URLs. NBS just works and cannot be "
"fooled by changes in the URL path, DNS cloaking or other techniques."
msgstr ""

#: ../content/posts/localportscanning.md:block 22 (paragraph)
msgid ""
"![JShelter blocks the scan]({attach}/images/portscan-2_request_blocked.png)"
msgstr ""
"![JShelter bloqueia a verificação]({attach}/images/portscan-2_request_blocked"
".png)"

#: ../content/posts/localportscanning.md:block 23 (paragraph)
msgid ""
"Firefox contains DNS API, so NBS works flawlessly. In Chromium-based "
"browsers, the exact blocking behaviour depends on how quickly a scanning "
"script can fire the requests and the precise destination (IP address or a "
"domain name). Depending on the interaction with DNS, NBS can be side-stepped"
" on Chrome. In this case, ThreatMetrix does not try any evasion technique, "
"so NBS just works in the case of eBay and ThreatMetrix."
msgstr ""

#: ../content/posts/mv3.md:block 1 (header)
msgid ""
"title: What is Manifest v3 and how it affects JShelter\n"
"date: 2023-11-01 12:00\n"
"Series: Manifest v3"
msgstr ""

#: ../content/posts/mv3.md:block 2 (paragraph)
msgid ""
"Over the years, privacy and security-oriented browser extensions in the same"
" category of JShelter (e.g. uBlock or NoScript, whose code is partially "
"inherited by JShelter through the NoScript Commons Library), have been "
"forced into multiple complex refactorings and modernizations, including "
"complete rewrites such as those [required by the transition from Mozilla's "
"original flexible XUL/XPCOM technology](https://yoric.github.io/post/why-"
"did-mozilla-remove-xul-addons/) to the more limiting [WebExtensions "
"API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-"
"ons/WebExtensions), largely copied from [Google Chrome's Extensions "
"API](https://developer.chrome.com/docs/extensions/reference/)."
msgstr ""

#: ../content/posts/mv3.md:block 3 (paragraph)
msgid ""
"During the past 2 years, the [Manifest V3 "
"API](https://developer.chrome.com/docs/extensions/mv3/intro/) (\"MV3\" from "
"now on) has been aggressively pushed by Google as the successor of the "
"current semi-unified browser extensions APIs (known as Manifest V2 or "
"\"MV2\")."
msgstr ""

#: ../content/posts/mv3.md:block 4 (paragraph)
msgid ""
"MV3 comes with renewed migration challenges, made worse by its "
"*incompleteness* and apparent [hostility against privacy and security use "
"cases](https://www.eff.org/deeplinks/2021/12/chrome-users-beware-"
"manifest-v3-deceitful-and-threatening>)."
msgstr ""

#: ../content/posts/mv3.md:block 5 (paragraph)
msgid ""
"Let's have a look at some threats that the MV3 specification poses to "
"JShelter and other security and privacy-oriented extensions:"
msgstr ""

#: ../content/posts/mv3.md:block 6 (unordered list)
msgid ""
"The new content script injection APIs are promising on paper, thanks also to"
" [specific](https://bugs.chromium.org/p/chromium/issues/detail?id=1128112) "
"[requests](https://bugs.chromium.org/p/chromium/issues/detail?id=1180659) "
"for "
"[enhancements](https://bugs.chromium.org/p/chromium/issues/detail?id=1180659#c5)"
" [coming](https://bugs.chromium.org/p/chromium/issues/detail?id=1054624#c19)"
" from [us](https://github.com/w3c/webextensions/issues/402), but their "
"implementation is still incomplete and buggy."
msgstr ""

#: ../content/posts/mv3.md:block 6 (unordered list)
msgid ""
"The removal of the blocking capabilities of the `webRequest` API excludes "
"any runtime [algorithmic "
"flexibility](https://lists.nongnu.org/archive/html/js-"
"shield/2021-02/msg00009.html) to [analyze and "
"manipulate](https://bugs.chromium.org/p/chromium/issues/detail?id=896897#c23)"
" the network traffic."
msgstr ""

#: ../content/posts/mv3.md:block 6 (unordered list)
msgid ""
"The new `declarativeNetRequest` API should replace the `webRequest` API. But"
" it is triggered by a [limited number of basic URL-matching "
"rules](https://github.com/w3c/webextensions/issues/394), which are easy to "
"bypass for malicious actors"
msgstr ""

#: ../content/posts/mv3.md:block 6 (unordered list)
msgid ""
"The forced switch of extensions' main logic from a persistent and stateful "
"background process (MV2) to an ephemeral and stateless service worker "
"(which, by MV3's design, can be killed at any time) hampers the ability of "
"security extensions to promptly counter-react synchronous events such as the"
" start of a page script execution and dramatically impacts any extension of "
"medium complexity, now forced to reconstruct its state from slow "
"asynchronous storage every time its service worker gets woken up by user "
"interaction or network events."
msgstr ""

#: ../content/posts/mv3.md:block 7 (paragraph)
msgid ""
"These and other technical problems are making the transition extremely "
"painful to privacy and security-oriented browser extensions, and more in "
"general those aimed to change the browser's default behavior in restrictive "
"/ protective directions or just give back some agency to the users rather "
"than prioritize the will of web authors, advertisers, and trackers."
msgstr ""

#: ../content/posts/mv3.md:block 8 (paragraph)
msgid "Further factors make any migration route even harder:"
msgstr ""

#: ../content/posts/mv3.md:block 9 (ordered list)
msgid ""
"*MV2 and MV3 API access is mutually exclusive*, meaning that we cannot pick "
"\"the best tool for the task\" during the transition. Therefore, web "
"developers are forced to maintain multiple versions, i.e. MV2-based for the "
"general public and MV3-based for early adopters/testers willing to bear with"
" bugs and missing features until MV3 is good enough."
msgstr ""

#: ../content/posts/mv3.md:block 9 (ordered list)
msgid ""
"*MV3 is far from having any finalized shape or roadmap*, despite the "
"relentless efforts to make it more viable from extensions developers, "
"including myself, convening with browser vendors in [W3C's Web Extensions "
"Community Group](https://www.w3.org/groups/cg/webextensions) (WECG)."
msgstr ""

#: ../content/posts/mv3.md:block 9 (ordered list)
msgid ""
"There's still *no stable, feature-complete and reliable MV3 API "
"implementation* for moderately complex extensions to experiment with."
msgstr ""

#: ../content/posts/mv3.md:block 9 (ordered list)
msgid ""
"Its actual implementations suffer from *fragmentation and countless "
"incompatibilities*, for the better or the worse, across browser vendors "
"adopting it, including Mozilla, Microsoft and Apple."
msgstr ""

#: ../content/posts/mv3.md:block 10 (paragraph)
msgid ""
"Notwithstanding the aforementioned critical issues, one year ago, Google "
"announced a bellicose [timeline to extinguish \"legacy\" MV2 "
"extensions](https://developer.chrome.com/docs/extensions/mv3/mv2-sunset/), "
"starting with a \"soft\" deprecation on the 1st of January 2023 but quickly "
"ramping up to enterprise-only support in June and complete extermination by "
"the end of the year, except for [backpedalling at the last "
"moment](https://arstechnica.com/gadgets/2022/12/chrome-delays-plan-to-limit-"
"ad-blockers-new-timeline-coming-in-march/), putting those dates \"under "
"review until March\" with the admission that an API still in such a bad "
"shape prevents too many extensions (even outside the controversial realm of "
"content blockers) from migrating."
msgstr ""

#: ../content/posts/mv3.md:block 11 (paragraph)
msgid ""
"In our project, we're seeking to navigate the uncertainty of Manifest V3 "
"transition towards a successful outcome, trying to stay compatible with as "
"many browsers as possible, preserving as many features as possible, through "
"different interventions, some sequential, some parallel:"
msgstr ""

#: ../content/posts/mv3.md:block 12 (ordered list)
msgid ""
"actively participating in the ongoing *browser extensions API design work* "
"of the [Web Extensions Community "
"Group](https://www.w3.org/groups/cg/webextensions), in order to steer the "
"MV3 specification in the most favorable direction for security and privacy "
"use cases;"
msgstr ""

#: ../content/posts/mv3.md:block 12 (ordered list)
msgid ""
"publishing a *MV3-compatible JShelter prototype* as much feature complete "
"and cross-browser compatible as possible, and developed/distributed/tested "
"separately from the MV2 version aimed at the general public;"
msgstr ""

#: ../content/posts/mv3.md:block 12 (ordered list)
msgid ""
"simultaneously advocating for, keeping track of and taking advantage of "
"*useful API changes* (even if browser-specific) to improve the MV3-based "
"prototype;"
msgstr ""

#: ../content/posts/mv3.md:block 12 (ordered list)
msgid ""
"*sharing the results with other extension developers* through the [NoScript "
"Commons Library](https://noscript.net/commons-library); the compatibility "
"layer eases the migration work for other developers."
msgstr ""

#: ../content/posts/optimizations.md:block 1 (header)
msgid ""
"title: Recent improvements in JShelter performance\n"
"date: 2023-09-21 15:00"
msgstr ""

#: ../content/posts/optimizations.md:block 2 (paragraph)
msgid ""
"You might have noticed that [recent versions](/versions/#015/) improved "
"JShelter performance. This blog post explains the improvements in more "
"detail and contains graphs. The improvements are based on the [bachelor "
"thesis of Martin Zmitko](https://www.vut.cz/en/students/final-"
"thesis/detail/147218). If you are interested in this topic, you will find "
"more information in the thesis. We thank Martin for his work and his "
"proposals."
msgstr ""

#: ../content/posts/optimizations.md:block 4 (header)
msgid "1. The code inserted into each page"
msgstr ""

#: ../content/posts/optimizations.md:block 5 (paragraph)
msgid ""
"Archaic versions of JShelter (at that time JavaScript Restrictor) generated "
"the wrapping code during each page load (in so-called content scripts). "
"However, we still needed to solve the reliable code injection at that time. "
"We wanted the lowest amount of work in content script. So, JShelter started "
"to generate the code in the background and send the generated code to the "
"content script."
msgstr ""

#: ../content/posts/optimizations.md:block 6 (paragraph)
msgid ""
"Starting from [0.5](/versions/#015/), NSCL solved the reliable code "
"injection. The preferred and fast solution is to inject the configuration in"
" the `BeforeNavigate` event handler. However, there is a race condition "
"between the `BeforeNavigate` event and `document_start` phase of the page "
"load. If the script detects that the configuration is not available during "
"the `document_start`, it initiates a synchronous request to retrieve the "
"configuration before page scripts start running."
msgstr ""

#: ../content/posts/optimizations.md:block 7 (paragraph)
msgid ""
"However, Martin realized that a synchronous request takes a long time. "
"Moreover, he confirmed [our old "
"observations](https://pagure.io/JShelter/webextension/issue/46#comment-793783)"
" that the synchronous request is needed very often. The time needed to "
"process the configuration increases linearly with the size of the "
"configuration. JShelter used to inject 572kB of code in the default "
"configuration. By shifting the code generation process back to content "
"scripts, we decreased the configuration size to 21.2kB."
msgstr ""

#: ../content/posts/optimizations.md:block 8 (paragraph)
msgid ""
"During the work, we also optimized the code-generating process and "
"eliminated duplicates in the code as well as Firefox-specific code in "
"Chromium-based browsers."
msgstr ""

#: ../content/posts/optimizations.md:block 9 (header)
msgid "2. Improvements to little-lies"
msgstr ""

#: ../content/posts/optimizations.md:block 10 (paragraph)
msgid ""
"As you probably know, the [anti-fingerprinting code](/farbling/) modifies "
"the results of some APIs with little lies. However, that approach is "
"performance-heavy for some APIs. The most critical are APIs that read from "
"canvas (`readPixels` and `toDataURL`) and `AudioBuffer.getChannelData`. For "
"example, the original `getChannelData` passes a reference to the underlying "
"buffer, so the browser does not need to do any computation. But JShelter "
"needs to copy each item, determine how to apply the lies (ensuring "
"consistent lies to the same data) and modify selected items."
msgstr ""

#: ../content/posts/optimizations.md:block 11 (paragraph)
msgid ""
"Martin discovered that the JShelter modifications to `readPixels`, "
"`toDataURL`, and `getChannelData` can benefit from a different iterator. "
"More importantly, Martin proposed to translate the code to WebAssembly, "
"which runs much faster."
msgstr ""

#: ../content/posts/optimizations.md:block 12 (header)
msgid "3. Improvements to FPD"
msgstr ""

#: ../content/posts/optimizations.md:block 13 (paragraph)
msgid ""
"[Fingerprint detector](/fpd/) collects information on each call of the APIs "
"that are often misused for fingerprinting. Martin discovered that some "
"serializations performed during its operations are not really needed."
msgstr ""

#: ../content/posts/optimizations.md:block 14 (header)
msgid "4. Other optimizations"
msgstr ""

#: ../content/posts/optimizations.md:block 15 (paragraph)
msgid ""
"Martin also implemented several other performance improvements, some aiming "
"at NSCL and not only JShelter. For example, NSCL included a JavaScript "
"library to compute SHA-256, while native `SubtleCrypto` implementation is "
"faster."
msgstr ""

#: ../content/posts/optimizations.md:block 16 (header)
msgid "5. Results"
msgstr ""

#: ../content/posts/optimizations.md:block 17 (paragraph)
msgid ""
"First, let us have a look at Firefox and the improvements in 2D Canvas in "
"`getImageData()` (note that the y-axis is logarithmic):"
msgstr ""

#: ../content/posts/optimizations.md:block 18 (paragraph)
msgid ""
"![Performance of getImageData in "
"Firefox]({attach}/images/optimizations/firefox_canvas_recommended.png)"
msgstr ""

#: ../content/posts/optimizations.md:block 19 (paragraph)
msgid ""
"As expected, the optimized implementation is slower than the original "
"because it needs much more work. Even so, the performance hit is several "
"magnitudes lower than the hit in 0.12.2."
msgstr ""

#: ../content/posts/optimizations.md:block 20 (paragraph)
msgid ""
"Now, let us have a look the improvements in 3D Canvas in `readPixels()` "
"(this time, we show the graph with the linear y-axis, the shape of the "
"points depicting the performance is similar for 2D and 3D canvas):"
msgstr ""

#: ../content/posts/optimizations.md:block 21 (paragraph)
msgid ""
"![Performance of readPixels in "
"Firefox]({attach}/images/optimizations/firefox_canvas3d_recommended.png)"
msgstr ""

#: ../content/posts/optimizations.md:block 22 (paragraph)
msgid ""
"See that the original implementation quickly leaves the plotted range. Its "
"performance hit was more significant than the 2D version while starting from"
" 0.14, the performance hit of 2D and 3D canvases are comparable."
msgstr ""

#: ../content/posts/optimizations.md:block 23 (paragraph)
msgid ""
"Firefox implementation of `getChannelData` has a negligible running time "
"(almost 0). The following figure shows that the little lies are computed "
"much quicker (about two orders of magnitude), but the impact is still "
"significant. Note that the y-axis is again logarithmic."
msgstr ""

#: ../content/posts/optimizations.md:block 24 (paragraph)
msgid ""
"![Performance of getChannelData in "
"Firefox]({attach}/images/optimizations/firefox_audio_recommended.png)"
msgstr ""

#: ../content/posts/optimizations.md:block 25 (paragraph)
msgid ""
"Martin also developed [performance "
"tests](https://pagure.io/JShelter/webextension/blob/1c86c45f565a36a6234c210392a89e3e20f32027/f/tests/performance_tests)"
" based on [Google Lighthouse](https://developer.chrome.com/docs/lighthouse/)"
" that run in Chrome. We tested on 46 pages from the 100 of "
"[Tranco](https://tranco-list.eu/) and give the [performance "
"score](https://developer.chrome.com/docs/lighthouse/performance/performance-"
"scoring/) below. The performance score approximates how users perceive the "
"loading speed of the visited page. The 25th percentile of all pages should "
"receive a score of 50."
msgstr ""

#: ../content/posts/optimizations.md:block 26 (paragraph)
msgid ""
"The average performance score of all tested pages was 66 without JShelter. "
"When tested with JShelter 0.12.2, the score dropped to 62.5. The average of "
"all tested pages raised to 64 with JShelter 0.15.1. The performance score "
"was the same or better in JShelter 0.15.1 compared to 0.12.2 on 33 pages. It"
" increased on 18 pages."
msgstr ""

#: ../content/posts/paper2022.md:block 1 (header)
msgid ""
"title: Paper about JShelter\n"
"date: 2022-04-05 00:00\n"
"Series: JShelter background"
msgstr ""

#: ../content/posts/paper2022.md:block 2 (paragraph)
msgid ""
"We recently submitted a position paper about JShelter for [CNIL Privacy "
"Research Day 2022](https://www.cnil.fr/en/privacy-research-day-2022) and "
"posted the paper on [arXive](https://arxiv.org/abs/2204.01392). If you are "
"interested in the project or if you are already using JShelter, we recommend"
" reading the paper as it explains the project, its historical decisions, the"
" thread model, design decision, experiments, and provides more information "
"that you should know if you want to use JShelter correctly, or, you might "
"decide that JShelter is not the correct tool for you and you might pick one "
"of the alternative tools referenced in the paper."
msgstr ""

#: ../content/posts/paper2022.md:block 3 (paragraph)
msgid ""
"The Web is used daily by billions. Even so, users are not protected from "
"many threats by default. Jshelter builds on previous web privacy and "
"security research and fights to return the browser to users. The paper "
"introduces [NSCL](https://noscript.net/commons-library), a library helping "
"with common webextension development tasks and fixing loopholes misused by "
"previous research. JShelter focuses on fingerprinting prevention, "
"limitations of rich web APIs, prevention of attacks connected to timing, and"
" learning information about the computer, the browser, the user, and "
"surrounding physical environment and location. We discovered a loophole in "
"the sensor timestamps that lets any page observe the device boot time if "
"sensor APIs are enabled in Chromium-based browsers. JShelter provides a "
"fingerprinting report and other feedback that can be used by future security"
" research and data protection authorities. Thousands of users around the "
"world use the webextension every day."
msgstr ""

#: ../content/posts/paper2022.md:block 4 (paragraph)
msgid ""
"Previous research established that browser security, privacy, and "
"customizability are important topics. The imminent danger of third-party "
"cookies' removal forces trackers to employ even more privacy-invading "
"techniques. Real-time bidding leaves users easy targets for various attacks,"
" including gaining information about other applications running on the local"
" computer. Moreover, continuous additions of new JavaScript APIs open new "
"ways for fingerprinting the browsers and gaining additional knowledge about "
"the browser or user preferences and physical environment. One of the major "
"concerns is a lack of effective tools that everyday user wants to use. "
"Current methods to tackle web threats are list-based blockers that might be "
"evaded with a change of URL, specialised browsers, or research-only projects"
" that are quickly abandoned."
msgstr ""

#: ../content/posts/paper2022.md:block 5 (paragraph)
msgid ""
"In contrast, JShelter is a webextension that can be installed on major "
"browsers and consequently does not require the user to change the browser "
"and routines. We integrate several previous research projects like [Chrome "
"Zero](https://github.com/IAIK/ChromeZero), [little-lies-based fingerprinting"
" prevention](https://brave.com/privacy-updates/3-fingerprint-"
"randomization/), and ideas of limiting APIs brought by [Web API "
"Manager](https://github.com/pes10k/web-api-manager). JShelter comes with [a "
"heuristic-based fingerprint detector](/fpdetection/) and prevents webpages "
"from [misusing the browser as a proxy to access the local network and "
"computer](/localportscanning/). We needed to solve issues with reliable "
"environment modifications that stem from webextension API that opens many "
"loopholes that previous research exploited. In addition to JShelter, we "
"introduce [NSCL](https://noscript.net/commons-library). Both NoScript "
"Security Suite and JShelter include NSCL. Moreover, NSCL is available for "
"other privacy- and security-related webextensions."
msgstr ""

#: ../content/posts/paper2022.md:block 6 (paragraph)
msgid ""
"In cooperation with the Free Software Foundation, we aim for long-term "
"JShelter development; thus, users' privacy and security should be improved "
"in the future. We explain fingerprinting vectors introduced by Sensor API in"
" mobile browsers. Data protection specialists should detect browser "
"fingerprinting and other information leaks with JShelter. We integrated "
"[fingerprint report](/cooperation/) and notifications to facilitate the "
"task. We discussed considerations and issues connected with deployment. The "
"webextension is under development. Future work will include fixing problems "
"breaking pages, improved heuristics of FPD, and research fingerprinting on "
"login pages. We want to revisit and evaluate the little-lies-based anti-"
"fingerprinting technique; are the little changes enough to stop a determined"
" fingerprinter that can, for example, approximate colour values of several "
"pixels or repeat an effect multiple times? JShelter should not be considered"
" a single bullet-proof solution. We anticipate that everyday users will "
"install JShelter together with other webextensions like list-based blockers "
"or JavaScript blockers."
msgstr ""

#: ../content/posts/sensorapi.md:block 1 (header)
msgid ""
"title: Protection against fingerprinting with Generic Sensor API\n"
"date: 2022-05-06 15:34\n"
"Series: Browser fingerprinting"
msgstr ""

#: ../content/posts/sensorapi.md:block 2 (paragraph)
msgid ""
"Today devices contain [various "
"sensors](https://www.researchgate.net/publication/224170986_A_survey_of_mobile_phone_sensing_IEEE_Commun_Mag)"
" for reading information about the device's position, state, and "
"environment. Such equipment is typical for mobile devices like cellphones, "
"tablets, or laptops that often include sensors for obtaining geolocation or "
"device orientation data. Another example is a smartwatch that could monitor "
"the heartbeat rate of the wearer, or a car with a tire pressure sensor, etc."
" While the benefits of having sensors are undisputed, allowing websites to "
"access their readings represents a considerable danger."
msgstr ""

#: ../content/posts/sensorapi.md:block 5 (header)
msgid "Generic Sensor API"
msgstr ""

#: ../content/posts/sensorapi.md:block 6 (paragraph)
msgid ""
"JavaScript's [Generic sensor API](https://www.w3.org/TR/generic-sensor/) "
"provides a unified way for accessing these sensors and reading data. The "
"physical (hardware) sensor instances are called **device sensors**, while "
"**platform sensors** represent interfaces over which the user agent can "
"interact with the device sensors and read data. JavaScript represents "
"sensors by a class hierarchy. The base class `Sensor` cannot be used "
"directly but provides essential properties, event handlers, and methods for "
"its subclasses. These represent concrete sensors like Accelerometer, "
"Magnetometer, or Gyroscope."
msgstr ""

#: ../content/posts/sensorapi.md:block 7 (header)
msgid "Browser Support"
msgstr ""

#: ../content/posts/sensorapi.md:block 8 (paragraph)
msgid ""
"The API is currently implemented, or partially implemented, in Chrome, Edge,"
" and Opera browsers. For Android devices, the support exists in Chrome for "
"Android, Opera for Android, and various Chromium-based browsers like Samsung"
" Mobile or Kiwi Browser. The concrete support for individual classes depends"
" on the browser type and version. Some features are considered experimental "
"and, for now, only work when browser flags like `#enable-experimental-web-"
"platform-features` or `#enable-generic-sensor-extra-classes` are enabled."
msgstr ""

#: ../content/posts/sensorapi.md:block 9 (header)
msgid "Sensor Types"
msgstr ""

#: ../content/posts/sensorapi.md:block 10 (paragraph)
msgid ""
"Some sensors are characterized by their implementation, e.g. a `Gyroscope` "
"or `Magnetometer`. Those are called **low-level** sensors. Sensors that are "
"named after their readings, not their implementation, are called **high-"
"level** sensors. For instance, the `GeolocationSensor` may read data from "
"the GPS chip, Wifi networks, cellular network triangulation, or their "
"combination. Using a combination of low-level sensor readings is called "
"**sensor fusion**. An example is the `AbsoluteOrientaionSensor` that uses "
"data from the Accelerometer, Gyroscope, and Magnetometer low-level sensors."
msgstr ""

#: ../content/posts/sensorapi.md:block 11 (header)
msgid "Threats"
msgstr ""

#: ../content/posts/sensorapi.md:block 12 (paragraph)
msgid ""
"The risk of using Generic Sensor API calls for device fingerprinting is "
"mentioned within the [W3C Candidate Recommendation Draft, 29 July "
"2021]((https://www.w3.org/TR/2021/CRD-generic-sensor-20210729/#device-"
"fingerprinting)). Documented threats include manufacturing imperfections and"
" differences that are unique to the concrete model of the device and can be "
"used for fingerprinting. Concrete examples are discussed in the following "
"sections dedicated to individual sensor classes."
msgstr ""

#: ../content/posts/sensorapi.md:block 13 (header)
msgid "Timestamps"
msgstr ""

#: ../content/posts/sensorapi.md:block 14 (paragraph)
msgid ""
"We discovered a loophole in the `Sensor.timestamp` attribute. The value "
"contains the time when the last `Sensor.onreading` event occurred, in "
"millisecond precision. We observed that the time is not relative to the time"
" of page context creation (like `performance.now`) but the last boot time of"
" the device. Exposing such information is dangerous as it allows to "
"fingerprint the user easily. Not many devices boot at the same time. The "
"longer a device is running, the less likely that another device booted at "
"the same time, and both are still running."
msgstr ""

#: ../content/posts/sensorapi.md:block 15 (paragraph)
msgid ""
"The behaviour was with the Magnetometer sensor on the following devices:"
msgstr ""

#: ../content/posts/sensorapi.md:block 16 (unordered list)
msgid ""
"Samsung Galaxy S21 Ultra; Android 11, kernel 5.4.6-215566388-abG99BXXU3AUE1,"
" Build/RP1A.200720.012.G998BXXU3AUE1, Chrome 94.0.4606.71 and Kiwi "
"(Chromium) 94.0.4606.56"
msgstr ""

#: ../content/posts/sensorapi.md:block 16 (unordered list)
msgid ""
"Xiaomi Redmi Note 5; Android 9, kernel 4.4.156-perf+, Build/9 "
"PKQ1.180901.001, Chrome 94.0.4606.71"
msgstr ""

#: ../content/posts/sensorapi.md:block 17 (paragraph)
msgid ""
"Our wrapper thus protects the device by changing the time origin to the page"
" context creation time, the timestamp should still uniquely identify the "
"reading, i.e. two readings by the same page have a different timestamp."
msgstr ""

#: ../content/posts/sensorapi.md:block 18 (header)
msgid "Global Orientation Settings"
msgstr ""

#: ../content/posts/sensorapi.md:block 19 (paragraph)
msgid ""
"Many sensor classes need access to the device's orientation to calculate its"
" values accordingly. Readings from different sensors are thus not "
"independent of each other, and relations between the sensor classes exist. "
"We wanted even the faked readings to look real and believable, and therefore"
" JShelter uses a model of the orientation that is shared between the "
"individual wrappers."
msgstr ""

#: ../content/posts/sensorapi.md:block 20 (paragraph)
msgid ""
"Let us consider a cell phone as a use case device. For all devices we "
"examined:"
msgstr ""

#: ../content/posts/sensorapi.md:block 21 (unordered list)
msgid "The `x` axis is oriented from the user's left to the right."
msgstr ""

#: ../content/posts/sensorapi.md:block 21 (unordered list)
msgid "The `y` axis from the bottom side of the display towards the top side."
msgstr ""

#: ../content/posts/sensorapi.md:block 21 (unordered list)
msgid ""
"The `z` axis is perpendicular to the display; it leads from the phone's "
"display towards the user's face."
msgstr ""

#: ../content/posts/sensorapi.md:block 22 (paragraph)
msgid ""
"Similar to [Aircaft principal "
"axes](https://www.grc.nasa.gov/www/k-12/airplane/rotations.html), the "
"rotation of the device is defined by three values: `yaw`, `pitch`, and "
"`roll`:"
msgstr ""

#: ../content/posts/sensorapi.md:block 23 (unordered list)
msgid ""
"`Yaw` defines rotation around the `z` axis. Assume a phone lying display up "
"on a flat surface - a table, for instance. If you rotate the phone without "
"taking any part up from the surface, only the yaw changes."
msgstr ""

#: ../content/posts/sensorapi.md:block 23 (unordered list)
msgid ""
"`Pitch` defines rotation around the `x` axis. Assume you want to have better"
" visibility of the display. You may put something under the top (camera) "
"part of the phone to lift it up a bit. This is where the pitch changes. For "
"the phone, the surface is not horizontal anymore."
msgstr ""

#: ../content/posts/sensorapi.md:block 23 (unordered list)
msgid ""
"`Roll` defines rotation around the `y` axis. This is done by rotating the "
"phone to the left and right. Assume you are holding the phone in your hand, "
"looking at the display. If you decide to look at the buttons on the side "
"instead, you rotate the phone, which applies the roll."
msgstr ""

#: ../content/posts/sensorapi.md:block 24 (paragraph)
msgid ""
"As we observed, the yaw, pitch, and roll define the rotation of the phone on"
" the Earth reference coordinate system:"
msgstr ""

#: ../content/posts/sensorapi.md:block 25 (unordered list)
msgid "The `x` axis is oriented towards the **East**"
msgstr ""

#: ../content/posts/sensorapi.md:block 25 (unordered list)
msgid "The `y` axis is oriented towards the (Earth's magnetic) **North**"
msgstr ""

#: ../content/posts/sensorapi.md:block 25 (unordered list)
msgid "The `-z` axis is oriented toward the **centre of the Earth**"
msgstr ""

#: ../content/posts/sensorapi.md:block 26 (paragraph)
msgid ""
"In our solution, the three values (`yaw`, `pitch`, and `roll`) are "
"pseudorandomly drawn using the "
"[Mulberry32](https://gist.github.com/tommyettinger/46a874533244883189143505d203312c)"
" PRNG that is seeded with a value generated from the `domainHash` which "
"ensures deterministic behaviour for the given website, e.g. producing same "
"values on different tabs."
msgstr ""

#: ../content/posts/sensorapi.md:block 27 (paragraph)
msgid ""
"Future improvements could also introduce movements where JShelter would "
"change the orientation over time."
msgstr ""

#: ../content/posts/sensorapi.md:block 28 (paragraph)
msgid ""
"A rotation matrix is calculated and stored within the global `orient` "
"variable from the values obtained. All our wrappers that need access to the "
"device's orientation load it from this variable."
msgstr ""

#: ../content/posts/sensorapi.md:block 29 (header)
msgid "AmbientLightSensor"
msgstr ""

#: ../content/posts/sensorapi.md:block 30 (paragraph)
msgid ""
"An ambient light sensor is a photodetector that senses the amount of ambient"
" light present. The motivation for integrating electronic devices is mostly "
"to dim the screen accordingly and protect users' eyes. In the Generic Sensor"
" API, the sensor is implemented using the `AmbientLightSensor` class "
"provides readings of the illuminance of the device's environment. The unit "
"of the illuminance values is `lux`."
msgstr ""

#: ../content/posts/sensorapi.md:block 31 (header)
msgid "Fingerprinting with AmbientLightSensor"
msgstr ""

#: ../content/posts/sensorapi.md:block 32 (paragraph)
msgid ""
"While the light sensors in devices may protect users' eyes, they do not "
"protect their privacy. As the illuminance value describes the light "
"conditions of the nearby physical surrounding of the device, an observer can"
" use the illuminance together with other sensors' readings to create a "
"unique fingerprint. Using readings from the `AmbientLightSensor`, it is "
"possible to [scan the nearby "
"environment](https://blog.lukaszolejnik.com/additional-security-and-privacy-"
"risks-of-light-sensors/). For instance, [behavioral "
"analysis](https://blog.lukaszolejnik.com/privacy-of-ambient-light-sensors/) "
"can reveal information about the time of day that the user usually works, "
"preferred lighting conditions, frequency of movement around different "
"places, etc. By applying the [inverse square law](http://hyperphysics.phy-"
"astr.gsu.edu/hbase/Forces/isq.html), one can also compute the distance "
"between the device and another light-emitting object: `d = sqrt(L / 4 * π * "
"B)` where `L` is luminosity that is roughly constant for a light source, and"
" `B` is brightness obtained from the sensor readings."
msgstr ""

#: ../content/posts/sensorapi.md:block 33 (paragraph)
msgid ""
"It is also possible to detect the position of the user's fingers by "
"analyzing the shadows the cast. An example that presents a serious danger is"
" [PIN "
"Skimming](https://www.researchgate.net/publication/262380810_PIN_Skimming_Exploiting_the_Ambient-"
"Light_Sensor_in_Mobile_Devices). In this case, a malicious website or "
"application exploits the sensor readings to detect PINs for applications "
"that make bank transactions, etc. Spreitzer et al. Using a linear "
"discriminant analysis with a training set of 15 PINs, each repeated eight "
"times, it was possible to classify more than 90 % of device PINs correctly. "
"The chance of correctly guessing the right PIN from the set of 15 is only "
"6.7 %. If the user watches TV and a light sensor-equipped smartphone or "
"smartwatch is nearby, it can [identify concrete TV channels and on-demand "
"videos](https://www.sciencedirect.com/science/article/pii/S1574119216302085)."
msgstr ""

#: ../content/posts/sensorapi.md:block 34 (paragraph)
msgid ""
"Multiple devices allow conducting [cross-device "
"tracking](https://blog.lukaszolejnik.com/privacy-of-ambient-light-sensors/)."
" For instance, when someone uses a phone and a tablet in the same room, a "
"website with access to their light sensors can compare the values to "
"distinguish whether the same person uses two separate devices. The sensor "
"can also be used for [cross-device "
"communication](https://blog.lukaszolejnik.com/privacy-of-ambient-light-"
"sensors/) where one device emits light by displaying content on its screen "
"and the other reads the message through the sensor-measured illuminance "
"values."
msgstr ""

#: ../content/posts/sensorapi.md:block 35 (header)
msgid "Wrapping the AmbientLightSensor readings"
msgstr ""

#: ../content/posts/sensorapi.md:block 36 (paragraph)
msgid ""
"To eliminate possible exploitation of sensor readings, we decided to "
"generate fake readings instead of modifying existing ones. On examined "
"stationary devices inside an office, the illuminance measured was between "
"500 and 900, depending on the concrete position's light conditions. All "
"measured values were rounded to the nearest 50 illuminance value. The "
"wrapper simulates the same behaviour under non-changing light conditions. In"
" the beginning, a pseudorandom illuminance value is drawn using PRNG seeded "
"with the domain hash - which should guarantee to produce the same values on "
"multiple browser tabs on the same domain. As we simulate a stationary device"
" under constant light conditions, this value remains the same for all "
"readings. The faked value is returned using a wrapped `illuminance` getter "
"of the `AmbientLightSensor.prototype`."
msgstr ""

#: ../content/posts/sensorapi.md:block 37 (header)
msgid "Accelerometer"
msgstr ""

#: ../content/posts/sensorapi.md:block 38 (paragraph)
msgid "Accelerometers provide information about the device's acceleration"
msgstr ""

#: ../content/posts/sensorapi.md:block 39 (unordered list)
msgid ""
"i.e., the rate of change of its velocity. The Generic Sensor API provides "
"access to the readings using three classes: the `Accelerometer` sensor, the "
"`LinearAccelerationSensor`, and the `GravitySensor`. All use data from the "
"underlying `accelerometer` device sensor. The difference between them is "
"whether and how the gravity acceleration is applied. The `Accelerometer` "
"sensor provides information about the total acceleration that is applied to "
"the device. The remaining two isolate the sources. The "
"`LinearAccelerationSensor` ignores the influence of gravity. The "
"`GravitySensor` returns just the gravity acceleration."
msgstr ""

#: ../content/posts/sensorapi.md:block 40 (header)
msgid "Fingerprinting with Accelerometer"
msgstr ""

#: ../content/posts/sensorapi.md:block 41 (paragraph)
msgid ""
"Readings from the accelerometer sensor classes represent a potential risk "
"and need to be protected. A unique fingerprint [can be obtained by "
"describing the device's "
"vibrations](https://link.springer.com/chapter/10.1007/978-3-319-30806-7_7). "
"Using [trajectory "
"inference](https://www.researchgate.net/publication/220990763_ACComplice_Location_inference_using_accelerometers_on_smartphones)"
" and matching the model to map data, one may use the readings from the "
"Accelerometer to determine the device's position"
msgstr ""

#: ../content/posts/sensorapi.md:block 42 (paragraph)
msgid ""
"From the accelerometer readings, [it is possible to "
"infer](https://www.mysk.blog/2021/10/24/accelerometer-ios/) whether the "
"device user is lying, sitting, walking, or cycling. For walking and running,"
" the data allow calculating steps. Accelerometer readings can also be used "
"to determine [human walking "
"patterns](https://www.researchgate.net/publication/322835708_Classifying_Human_Walking_Patterns_using_Accelerometer_Data_from_Smartphone)."
msgstr ""

#: ../content/posts/sensorapi.md:block 43 (paragraph)
msgid ""
"Similar to `Gyroscope`, the `Accelerometer` sensor is also influenced by "
"vibrations from speech. Using the [Spearphone "
"attack](https://arxiv.org/abs/1907.05972), it is possible to perform gender "
"classification (with accuracy over 90%) and speaker identification (with "
"accuracy over 80%). Speech recognition and classification can also be done "
"from the reading of this sensor."
msgstr ""

#: ../content/posts/sensorapi.md:block 44 (header)
msgid "Wrapping the Accelerometer readings"
msgstr ""

#: ../content/posts/sensorapi.md:block 45 (paragraph)
msgid ""
"Our wrapper replaces the acceleration getters of these sensors. The goal is "
"to simulate a stationary device, possibly rotated. A rotation matrix "
"represents the orientation of the device. Its values are drawn "
"pseudorandomly from the domain hash, and are shared between all sensor "
"wrappers to simulate the same behaviour."
msgstr ""

#: ../content/posts/sensorapi.md:block 46 (paragraph)
msgid ""
"The `GravitySensor` provides readings of gravity acceleration applied to the"
" device. This is represented by a vector made of `x`, `y`, `z` portions. To "
"get this faked gravity vector for the device, the reference vector `[0, 0, "
"9.8]` is multiplied with the rotation matrix. Wrappers for the "
"GravitySensor's getters return the individual portions of the fake gravity "
"vector."
msgstr ""

#: ../content/posts/sensorapi.md:block 47 (paragraph)
msgid ""
"Next, the `LinearAccelerationSensor` should return acceleration values "
"without the contribution of gravity. For a stationary device, it should be "
"all zeroes. Yet, vibrations may change values a little bit, e.g., spin "
"around `-0.1` to `+0.1`, as seen on the examined devices. Such vibrations "
"usually do not happen with every reading but only in intervals of seconds. "
"And thus, JShelter pseudorandomly changes these values after a few seconds."
msgstr ""

#: ../content/posts/sensorapi.md:block 48 (paragraph)
msgid ""
"Finally, the `Accelerometer` sensor combines the previous two. Our wrappers "
"thus return the values from the LinearAccelerationSensor with the fake "
"gravity vector portions added."
msgstr ""

#: ../content/posts/sensorapi.md:block 49 (paragraph)
msgid ""
"For all three classes, we return the faked orientation values using the "
"wrapped `x`, `y`, `z` component getters of the `Accelerometer.prototype`. "
"Based on the constructor name the wrapper detects which concrete class is "
"used and thus what behaviour to simulate."
msgstr ""

#: ../content/posts/sensorapi.md:block 50 (header)
msgid "Gyroscope"
msgstr ""

#: ../content/posts/sensorapi.md:block 51 (paragraph)
msgid ""
"The Gyroscope sensor provides readings of the angular velocity of the device"
" along the `x`, `y`, `z` axes. The class uses the underlying `gyroscope` "
"device sensor. Physically, classic gyroscopes used a spinning wheel or a "
"disc with free axes of rotation. In modern electronic devices, gyroscopes "
"use piezoelectric or silicon transducers and [various mechanical "
"structures](https://www5.epsondevice.com/en/information/technical_info/gyro/)."
msgstr ""

#: ../content/posts/sensorapi.md:block 52 (header)
msgid "Fingerprinting with Gyroscope"
msgstr ""

#: ../content/posts/sensorapi.md:block 53 (paragraph)
msgid ""
"Gyroscope readings can be used for [speech "
"recognition](https://crypto.stanford.edu/gyrophone/) and various "
"fingerprinting operations. For stationary devices, the resonance of the "
"unique internal or external sounds affect angular velocities affect the "
"Gyroscope, and [allow to create a "
"fingerprint](https://www.researchgate.net/publication/356678825_Mobile_Device_Fingerprint_Identification_Using_Gyroscope_Resonance)."
" For moving devices, one of the options is using the Gyroscope to analyze "
"[human walking "
"patterns](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7071017/)."
msgstr ""

#: ../content/posts/sensorapi.md:block 54 (header)
msgid "Wrapping the Gyroscope Readings"
msgstr ""

#: ../content/posts/sensorapi.md:block 55 (paragraph)
msgid ""
"All velocities should be zero in an ideal state for a stationary device. As "
"we observed on the examined devices, various device sensor imperfections and"
" tiny vibrations cause the values oscillate between `-0.002` and `0.002` on "
"the examined devices. Our wrapper thus simulates the same behaviour."
msgstr ""

#: ../content/posts/sensorapi.md:block 56 (paragraph)
msgid ""
"The changes are applied in pseudorandom intervals between `500 ms` to `2 s`."
" These boundaries were chosen with respect to our observations from the "
"examined devices' real sensors. The actual values of change are also "
"calculated pseudorandomly from the domain hash to ensure deterministic and "
"consistent behaviour within a given domain. The faked values are then "
"returned using wrapped `x`, `y`, `z` getters of the `Gyroscope.prototype`."
msgstr ""

#: ../content/posts/sensorapi.md:block 57 (header)
msgid "Magnetometer"
msgstr ""

#: ../content/posts/sensorapi.md:block 58 (paragraph)
msgid ""
"A magnetometer measures the strength and direction of the magnetic field "
"around the device. The interface offers sensor readings using three "
"properties: `x`, `y`, and `z`. Each returns a number that describes the "
"magnetic field around the particular axis. The numbers have a double "
"precision and can be positive or negative, depending on the orientation of "
"the field. The total strength of the magnetic field (`M`) can be calculated "
"as `M = sqrt(x^2 + z^2 + y^2)`. The unit is in microtesla (&micro;T)."
msgstr ""

#: ../content/posts/sensorapi.md:block 59 (header)
msgid "Fingerprinting with Magnetometer"
msgstr ""

#: ../content/posts/sensorapi.md:block 60 (paragraph)
msgid ""
"The Earth's magnetic field "
"[ranges](https://doi.org/10.1111%2Fj.1365-246X.2010.04804.x) between "
"approximately 25 and 65 &micro;T. Concrete values depend on location, "
"altitude, weather, and other factors. Yet, there are characteristics of the "
"field for different places on Earth. The common model used for their "
"description is the [International Geomagnetic Reference Field "
"(IGRF)](https://www.ngdc.noaa.gov/IAGA/vmod/igrf.html). While the magnetic "
"field changes over time, the changes are slow: There is a decrease of 5% "
"every 100 years. Therefore, for the given latitude, longitude, and altitude,"
" the average strength of the field should be stable. Can one determine the "
"device's location based on the data from the Magnetometer sensor? Not "
"exactly. The measured values are influenced by the interference with other "
"electrical devices, isolation (buildings, vehicles), the weather, and other "
"factors. Moreover, the field is not unique - similar fields can be measured "
"in different places on Earth."
msgstr ""

#: ../content/posts/sensorapi.md:block 61 (paragraph)
msgid ""
"What, however, can be determined is the orientation of the device. In the "
"case of a stationary (non-moving) device, the measured values can serve as a"
" fingerprint. As we experimentally examined, it is also possible to "
"distinguish whether the device is moving or when its environment changes. "
"When a person with a cellphone enters a car or an elevator, the metal "
"barrier serves as isolation, and the strength of the field gets lower "
"rapidly (e.g., from 60&micro;T outside to 27&micro;T inside). A cellphone "
"lying on a case of a running computer can produce values over 100&micro;T, "
"especially if it is near the power supply unit. Either way, for a single "
"device at the same location in the same environment, the average strength of"
" the magnetic field should be stable."
msgstr ""

#: ../content/posts/sensorapi.md:block 62 (paragraph)
msgid ""
"Magnetometer values can be used for fingerprinting. First, Magnetometer "
"readings can tell the attacker whether the device is moving or not. In the "
"case of a stationary device, we can make a fingerprint from the device "
"orientation. Another fingerprintable value is the average total strength of "
"the field, which should remain stable if the device is at the same position "
"and in the same environment."
msgstr ""

#: ../content/posts/sensorapi.md:block 63 (paragraph)
msgid ""
"Yet, even moving devices can be exploited. One can misuse the sensor "
"readings to make a [calibration fingerprint attack](https://www.ieee-"
"security.org/TC/SP2019/papers/405.pdf) that infers per device factory "
"calibration data. The researchers showed the attack to be usable and "
"efficient on both Android and iOS devices. A device can be identified using "
"Magnetometer reading [through the analysis of the "
"bias](https://seclab.bu.edu/papers/magnetometer-wisec2019.pdf). Moreover, "
"the device itself also produces electromagnetic emissions and can thus be "
"identified using the [physical proximity "
"attack](https://seclab.bu.edu/papers/magnetometer-wisec2019.pdf) is also "
"possible to use an external device. As the underlying device sensor is also "
"disturbed by the device's CPU activity, Magnetometer measurements can also "
"be [used to identify running applications or web "
"pages](https://arxiv.org/pdf/1906.11117.pdf)."
msgstr ""

#: ../content/posts/sensorapi.md:block 64 (header)
msgid "Wrapping of Magnetometer readings"
msgstr ""

#: ../content/posts/sensorapi.md:block 65 (paragraph)
msgid ""
"JShelter wraps the `x`, `y`, `z` getters of the `Magnetometer.prototype` "
"object to protect the device. Instead of using the original data, JShelter "
"returns artificially generated values that look like actual sensor readings."
msgstr ""

#: ../content/posts/sensorapi.md:block 66 (paragraph)
msgid ""
"At every moment, our wrapper stores information about the previous reading. "
"Each rewrapped getter first checks the `timestamp` value of the sensor "
"object. If there is no difference of the prior reading's timestamp, the "
"wrapper returns the last measured value. Otherwise, it provides a new fake "
"reading."
msgstr ""

#: ../content/posts/sensorapi.md:block 67 (paragraph)
msgid ""
"We designed our fake field generator to fulfil the following properties:"
msgstr ""

#: ../content/posts/sensorapi.md:block 68 (unordered list)
msgid ""
"The randomness of the generator should be high enough to prevent attackers "
"from deducing the sensor values."
msgstr ""

#: ../content/posts/sensorapi.md:block 68 (unordered list)
msgid ""
"Multiple scripts from the same website that access readings with the same "
"timestamp must get the same results. And thus:"
msgstr ""

#: ../content/posts/sensorapi.md:block 68 (unordered list)
msgid ""
"The readings are deterministic - e.g., for a given website and time, we must"
" be able to say what values to return."
msgstr ""

#: ../content/posts/sensorapi.md:block 69 (paragraph)
msgid ""
"For every \"random\" toss-up, we use the "
"[Mulberry32](https://gist.github.com/tommyettinger/46a874533244883189143505d203312c)"
" PRNG that is seeded with a value generated from the `domainHash`, which "
"ensures deterministic behaviour for the given website. First, we choose the "
"desired total strength `M` of the magnetic field at our simulated location. "
"This is a pseudorandom number from `25` to `60` &micro;T, like on the Earth."
msgstr ""

#: ../content/posts/sensorapi.md:block 70 (paragraph)
msgid ""
"First, we need to set the initial orientation of the axes. Our wrappers "
"support two methods:"
msgstr ""

#: ../content/posts/sensorapi.md:block 71 (unordered list)
msgid ""
"The original implementation where the orientation of axes is drawn "
"pseudorandomly."
msgstr ""

#: ../content/posts/sensorapi.md:block 71 (unordered list)
msgid ""
"An improved version where we use the faked device rotation shared by other "
"wrappers. In this case, we start with the reference magnetic field vector "
"that is oriented towards the Earth's magnetic North and towards the centre "
"of the Earth. The vector is then multiplied with the shared faked rotation "
"matrix. The elements of the resulting vector then represents the axes "
"orientation."
msgstr ""

#: ../content/posts/sensorapi.md:block 72 (paragraph)
msgid ""
"For both methods, the orientation is defined by a number from -1 to 1 for "
"each axis: JShelter simulates a stationary device with a pseudorandomly "
"drawn orientation in the current implementation. Therefore, we choose the "
"orientation of the device by generating a number from `-1` to `1` for each "
"axis. Those values we call `baseX`, `baseY`, and `baseZ`. By modifying the "
"above-shown formula, we calculate the `multiplier` that needs to be applied "
"to the base values to get the desired field. The calculation is done as "
"follows: `mult = (M * sqrt(baseX^2 + baseY^2 + baseZ^2) / (baseX^2 + baseY^2"
" + baseZ^2))` For axis `x`, the value should fluctuate around `baseX * "
"mult`, etc."
msgstr ""

#: ../content/posts/sensorapi.md:block 73 (paragraph)
msgid ""
"How much the field changes over time is specified by the **fluctuation "
"factor** from `(0;1]` that can also be configured. For instance, `0.2` means"
" that the magnetic field on the axis may change from the base value by `20%`"
" in both positive and negative ways."
msgstr ""

#: ../content/posts/sensorapi.md:block 74 (paragraph)
msgid ""
"The fluctuation is simulated by using a series of **sine** functions for "
"each axis. Each sine has a unique amplitude, phase shift, and period. The "
"number of sines per axis is chosen pseudorandomly based on the wrapper "
"settings. For initial experiments, we used around `20` to `30` sines for "
"each axis. The optimal configuration is in question. More sines give less "
"predictable results but also increase the computing complexity that could "
"have a negative impact on the browser's performance."
msgstr ""

#: ../content/posts/sensorapi.md:block 75 (paragraph)
msgid ""
"For the given timestamp `t`, we make the sum of all sine values at the point"
" `x=t`. The result is then shifted over the y-axis by adding `base[X|Y|Z] * "
"multiplier` to the sum. The initial configuration of the fake field "
"generator was chosen intuitively to resemble the results of the real "
"measurements. Currently, the generator uses **at least one** sine with the "
"period around `100` &micro;s (with `10%` tolerance), which seems to be the "
"minimum sampling rate obtainable using the API on mobile devices. Then, at "
"least one sine around `1 s`, around `10 s`, `1 minute` and `1 hour`. When "
"more than `5` sines are used, the cycle repeats using `modulo 5` and creates"
" a new sine with the period around `100` &micro;s, but this time the "
"tolerance is `20%`. The same follows for seconds, tens of seconds, minutes, "
"and hours. The tolerance grows every five sines. For 11+ sines, the "
"tolerance is `30%` up to the maximum (currently `50%`). The amplitude of "
"each sine is chosen pseudorandomly based on the **fluctuation factor** "
"described above. The phase shift of each sine is also a pseudorandom number "
"from [0;2&#960;)."
msgstr ""

#: ../content/posts/sensorapi.md:block 76 (paragraph)
msgid ""
"Based on the results, this heuristic returns believable values that look "
"like actual sensor readings. Nevertheless, the generator uses a series of "
"constants whose optimal values should be a subject of future research and "
"improvements. Perhaps, a correlation analysis with real measurements could "
"help in the future. Figures below show the values of `x`, `y`, `z`, and the "
"total strength `M` measured within 10 minutes on a: 1) Stationary device, 2)"
" Moving device, and 3) Device with the fake wrapped magnetometer."
msgstr ""

#: ../content/posts/sensorapi.md:block 77 (paragraph)
msgid ""
"![Stationary device]({attach}/images/device_stationary.svg) ![Moving "
"device]({attach}/images/device_moving.svg) ![Device with fake "
"magnetometer]({attach}/images/device_artificial.svg)"
msgstr ""

#: ../content/posts/sensorapi.md:block 78 (header)
msgid "Device Orientation Sensors"
msgstr ""

#: ../content/posts/sensorapi.md:block 79 (paragraph)
msgid ""
"This group includes two sensor classes: `AbsoluteOrientationSensor` and "
"`RelativeOrientationSensor`. Both describe the physical orientation of the "
"device, and both require access to the `accelerometer` and `gyroscope` "
"device sensors. The difference between the two classes is what they consider"
" as a reference coordinate system"
msgstr ""

#: ../content/posts/sensorapi.md:block 80 (unordered list)
msgid ""
"i.e., what is the real orientation of a non-rotated device. For this "
"purpose, the `AbsoluteOrientationSensor` uses the Earth's reference "
"coordinate system. And thus, it also requires access to the `magnetometer` "
"device sensor, simply to know where the North is. The "
"`RelativeOrientationSensor` does not require this information as the "
"cardinal directions are not used. Yet, the sensor still needs to some "
"coordinate system to calculate with - i.e., physical orientation of the "
"device that is considered as reference. For this purpose, it may use the "
"orientation from the moment the sensor instance is created. When the sensor "
"is initialized, it creates a new coordinate system, and the device can be "
"considered non-rotated. Any rotations from this point are done in relation "
"to this newly created coordinate system. Readings are represented by the "
"`OrientationSensor.quaternion` made of `x`, `y`, `z`, and `w` components "
"that describe the orientation of the device."
msgstr ""

#: ../content/posts/sensorapi.md:block 81 (header)
msgid "Fingerprinting with Device Orientation Sensors"
msgstr ""

#: ../content/posts/sensorapi.md:block 82 (paragraph)
msgid ""
"Device orientation sensors can be easily used for fingerprinting. As it "
"highly unlikely that two devices visiting the same site will be oriented "
"exactly the same, the orientation itself can serve as a fingerprint."
msgstr ""

#: ../content/posts/sensorapi.md:block 83 (paragraph)
msgid ""
"As the device orientation sensor use data from both the `accelerometer` and "
"the `gyroscope` device sensors, determining the location using [trajectory "
"inference](https://www.researchgate.net/publication/220990763_ACComplice_Location_inference_using_accelerometers_on_smartphones)"
" or determining [human walking "
"patterns](https://www.researchgate.net/publication/322835708_Classifying_Human_Walking_Patterns_using_Accelerometer_Data_from_Smartphone)."
" could be even easier than with bare `Accelerometer` class."
msgstr ""

#: ../content/posts/sensorapi.md:block 84 (header)
msgid "Wrapping of Device Orientation Readings"
msgstr ""

#: ../content/posts/sensorapi.md:block 85 (paragraph)
msgid ""
"The `AbsoluteOrientationSensor` returns a quaternion describing the physical"
" orientation of the device in relation to the Earth's reference coordinate "
"system. As discussed above, the faked orientation of the device is drawn "
"pseudorandomly using domain hash as a seed and sored inside a global "
"variable called `orient` that is accessible to all wrappers. With each "
"reading, it loads the \"orient\" 's contents, converts the rotation matrix "
"to a quaternion that is returned by the wrapped getter. This design makes "
"the outputs realistic and in accordance with other sensors' reading. The "
"implemenation also supports possible changes of orientation."
msgstr ""

#: ../content/posts/sensorapi.md:block 86 (paragraph)
msgid ""
"The `RelativeOrientationSensor` also describes the orientation, but without "
"regard to the Earth's reference coordinate system. We suppose the coordinate"
" system is chosen at the beginning of the sensor instance creation. As we "
"observed, no matter how the device is oriented, there is always a slight "
"difference from the AbsoluteOrientationSensor's in at least one axis. When "
"the device moves, both sensors' readings change. But their difference should"
" always be constant. And thus, we pseudorandomly generate rotation "
"deviations from the Earth's reference coordinate system. The deviations are "
"between `0` and `π/2`. For each reading, we take the values from the fake "
"AbsoluteOrientationSensor and modify them by the constant deviation."
msgstr ""

#: ../content/posts/sensorapi.md:block 87 (paragraph)
msgid ""
"For both sensor classes, we return the faked orientation values using the "
"wrapped `x`, `y`, `z`, and `w` quaternion component getters of the "
"`OrientationSensor.prototype`. Based on the constructor name the wrapper "
"detects whether it should simulate the absolute or relative orientation "
"sensor's behaviour."
msgstr ""

#: ../content/posts/support.md:block 1 (header)
msgid ""
"title: We received support from NGI0 PET Fund\n"
"date: 2021-03-30 09:00\n"
"Series: JShelter background"
msgstr ""

#: ../content/posts/support.md:block 2 (paragraph)
msgid ""
"We are very happy to announce that the <a "
"href=\"https://nlnet.nl/project/JSRestrictor/\">JavaScript Restrictor "
"received support from NGI0 PET Fund</a>, a fund established by NLnet with "
"financial support from the European Commission's Next Generation Internet "
"programme, under the aegis of DG Communications Networks, Content and "
"Technology under grant agreement No 825310."
msgstr ""

#: ../content/posts/support.md:block 3 (paragraph)
msgid ""
"We are very excited to improve the extension further. We will focus on the "
"following main goals:"
msgstr ""

#: ../content/posts/support.md:block 4 (header)
msgid "1. Investigate fingerprinting scripts and prepare wrappers"
msgstr ""

#: ../content/posts/support.md:block 5 (paragraph)
msgid ""
"Review the previously identified APIs suitable for fingerprinting. Select "
"APIs suitable for JShelter and add wrappers for these APIs. This work has "
"already started, see issue #66. Additionally, we want to focus on "
"identification of methods used for fingeprinting such as those identified by"
" Iqbal et al., see https://uiowa-irl.github.io/FP-Inspector/"
msgstr ""

#: ../content/posts/support.md:block 6 (header)
msgid "2. Prevent unique identification of a device"
msgstr ""

#: ../content/posts/support.md:block 7 (paragraph)
msgid ""
"It is hard, if not impossible, to both prevent fingerprinting and still "
"provide customized environment for the user. Hence, we want to identify "
"fingerprinting attempts by counting the number of different APIs employed by"
" a page, especially APIs that are not frequently used for benign purposes. "
"When a fingerprinting attempt is identified, we want to (1) inform the user,"
" (2) prevent uploading of the fingerprint to the server, (3) prevent storing"
" the fingerprint for later usage."
msgstr ""

#: ../content/posts/support.md:block 8 (header)
msgid "3. Code ported from Chrome Zero"
msgstr ""

#: ../content/posts/support.md:block 9 (paragraph)
msgid ""
"In version 0.3, we integrated features of Chrome Zero 7 as it is no longer "
"maintained. By integrating the functionality to JShelter, we want to keep "
"the counter-meassures available in a maintained extension. However, we do "
"not have sufficient tests for the functionality."
msgstr ""

#: ../content/posts/support.md:block 10 (header)
msgid "4. Evaluation and porting of code from Brave"
msgstr ""

#: ../content/posts/support.md:block 11 (paragraph)
msgid ""
"Brave browser currently implements anti-fingerprinting techniques that aim "
"at providing little lies about the browser environment. We want to evaluate "
"the messures and select techniques that are suitable for JShelter."
msgstr ""

#: ../content/posts/support.md:block 12 (header)
msgid "5. Fixing known bugs"
msgstr ""

#: ../content/posts/support.md:block 13 (paragraph)
msgid ""
"We want to focus on the proposed changes and found bugs that are reported in"
" the GitHub bug tracker."
msgstr ""

#: ../content/posts/support.md:block 14 (unordered list)
msgid ""
"We already closed issues #53, #62, and #72 as a part of this project. The "
"fixes are already available as a part of the 0.4 subversions."
msgstr ""

#: ../content/posts/support.md:block 14 (unordered list)
msgid ""
"We want to also deal with issues #56 and #71 that are crucial for the "
"success of the extension."
msgstr ""

#: ../content/posts/support.md:block 14 (unordered list)
msgid ""
"We will focus on other identified bugs in the wrappers or developped "
"techniques."
msgstr ""

#: ../content/posts/support.md:block 15 (header)
msgid "6. Cooperation with the Privacy Shield project"
msgstr ""

#: ../content/posts/support.md:block 16 (paragraph)
msgid ""
"We are also excited to announce that we found other partners that are "
"willing to work on our code base through the NGI0 PET Fund, <a "
"href=\"https://nlnet.nl/project/JavascriptShield/\">Privacy Shield project "
"run by Free Software Foundation</a>. Expect inclusion of code that will help"
" to defend your freedoms and provide anti-malware protections. This "
"cooperation should also improve the GUI of the extension and create "
"explenatory web pages explaining the functionality and its risks. It is "
"possible that the project will be rebranded as a result of the cooperation."
msgstr ""
