tbb-commits
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 19540 discussions
[Git][tpo/applications/tor-browser-update-responses][main] release: new version, 12.5.2
by richard (@richard) 02 Aug '23
by richard (@richard) 02 Aug '23
02 Aug '23
richard pushed to branch main at The Tor Project / Applications / Tor Browser update responses
Commits:
a0a02e43 by Richard Pospesel at 2023-08-02T20:34:39+00:00
release: new version, 12.5.2
- - - - -
30 changed files:
- update_3/release/.htaccess
- − update_3/release/12.0.6-12.5.1-linux32-ALL.xml
- − update_3/release/12.0.6-12.5.1-linux64-ALL.xml
- − update_3/release/12.0.6-12.5.1-macos-ALL.xml
- − update_3/release/12.0.6-12.5.1-win32-ALL.xml
- − update_3/release/12.0.6-12.5.1-win64-ALL.xml
- − update_3/release/12.0.7-12.5.1-linux32-ALL.xml
- − update_3/release/12.0.7-12.5.1-linux64-ALL.xml
- − update_3/release/12.0.7-12.5.1-macos-ALL.xml
- − update_3/release/12.0.7-12.5.1-win32-ALL.xml
- − update_3/release/12.0.7-12.5.1-win64-ALL.xml
- − update_3/release/12.5-12.5.1-linux32-ALL.xml
- − update_3/release/12.5-12.5.1-linux64-ALL.xml
- − update_3/release/12.5-12.5.1-macos-ALL.xml
- − update_3/release/12.5-12.5.1-win32-ALL.xml
- − update_3/release/12.5-12.5.1-win64-ALL.xml
- + update_3/release/12.5-12.5.2-linux32-ALL.xml
- + update_3/release/12.5-12.5.2-linux64-ALL.xml
- + update_3/release/12.5-12.5.2-macos-ALL.xml
- + update_3/release/12.5-12.5.2-win32-ALL.xml
- + update_3/release/12.5-12.5.2-win64-ALL.xml
- + update_3/release/12.5.1-12.5.2-linux32-ALL.xml
- + update_3/release/12.5.1-12.5.2-linux64-ALL.xml
- + update_3/release/12.5.1-12.5.2-macos-ALL.xml
- + update_3/release/12.5.1-12.5.2-win32-ALL.xml
- + update_3/release/12.5.1-12.5.2-win64-ALL.xml
- − update_3/release/12.5.1-linux32-ALL.xml
- − update_3/release/12.5.1-linux64-ALL.xml
- − update_3/release/12.5.1-macos-ALL.xml
- − update_3/release/12.5.1-win32-ALL.xml
The diff was not included because it is too large.
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-update-responses…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-update-responses…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build] Pushed new tag tbb-12.5.2-build1
by richard (@richard) 01 Aug '23
by richard (@richard) 01 Aug '23
01 Aug '23
richard pushed new tag tbb-12.5.2-build1 at The Tor Project / Applications / tor-browser-build
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/tree/tbb…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build] Pushed new tag mb-12.5.2-build1
by richard (@richard) 01 Aug '23
by richard (@richard) 01 Aug '23
01 Aug '23
richard pushed new tag mb-12.5.2-build1 at The Tor Project / Applications / tor-browser-build
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/tree/mb-…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][maint-12.5] Bugs 40896, 40897: Tor Browser and Mullvad Browser 12.5.2
by richard (@richard) 01 Aug '23
by richard (@richard) 01 Aug '23
01 Aug '23
richard pushed to branch maint-12.5 at The Tor Project / Applications / tor-browser-build
Commits:
25465ba5 by Richard Pospesel at 2023-08-01T15:08:38+00:00
Bugs 40896, 40897: Tor Browser and Mullvad Browser 12.5.2
- - - - -
11 changed files:
- projects/browser/Bundle-Data/Docs-MB/ChangeLog.txt
- projects/browser/Bundle-Data/Docs-TBB/ChangeLog.txt
- projects/browser/allowed_addons.json
- projects/browser/config
- projects/firefox/config
- projects/geckoview/config
- projects/go/config
- projects/manual/config
- projects/tor/config
- projects/translation/config
- rbm.conf
Changes:
=====================================
projects/browser/Bundle-Data/Docs-MB/ChangeLog.txt
=====================================
@@ -1,3 +1,54 @@
+Mullvad Browser 12.5.2 - July 31 2023
+ * All Platforms
+ * Updated NoScript to 11.4.26
+ * Upated uBlock Origin to 1.51.0
+ * Updated Firefox to 102.14.0esr
+ * Bug 217: Rebase Mullvad Browser 12.5 stable on top of 102.14esr [mullvad-browser]
+ * Build System
+ * All Platforms
+ * Bug 40889: Add mullvad sha256sums URL to tools/signing/download-unsigned-sha256sums-gpg-signatures-from-people-tpo [tor-browser-build]
+ * Bug 40894: Fix format of keyring/boklm.gpg [tor-browser-build]
+ * Bug 40909: Add dan_b and ma1 to list of taggers in relevant projects [tor-browser-build]
+ * Windows
+ * Bug 31546: Create and expose PDB files for Tor Browser debugging on Windows [tor-browser-build]
+
+Mullvad Browser 13.0a1 - July 20 2023
+ * All Platforms
+ * Updated NoScript to 11.4.25
+ * Updated uBlock Origin to 1.50.0
+ * Updated mullvad-browser-extension to 0.8.3
+ * Updated Firefox to 115.0.2esr
+ * Bug 166: Enable built-in URL anti-tracking query parameters stripping [mullvad-browser]
+ * Bug 183: Rebase Mullvad Browser to Firefox 115 [mullvad-browser]
+ * Bug 213: Add search engines to the default list [mullvad-browser]
+ * Bug 214: Enable cross-tab identity leak protection in "quiet" mode [mullvad-browser]
+ * Bug 26277: When "Safest" setting is enabled searching using duckduckgo should always use the Non-Javascript site for searches [tor-browser]
+ * Bug 33955: Selecting "Copy image" from menu leaks the source URL to the clipboard. This data is often dereferenced by other applications. [tor-browser]
+ * Bug 41759: Rebase Base Browser to 115 nightly [tor-browser]
+ * Bug 41834: Hide "Can't Be Removed - learn more" menu line for uninstallable add-ons [tor-browser]
+ * Bug 41854: Download Spam Protection cannot be overridden to allow legitimate downloads [tor-browser]
+ * Bug 41874: Visual & A11 regressions in add-on badges [tor-browser]
+ * Windows
+ * Bug 41806: Prevent Private Browsing start menu item to be added automatically [tor-browser]
+ * Build System
+ * All Platforms
+ * Bug 40089: Clean up usage of get-moz-build-date script [tor-browser-build]
+ * Bug 40410: Get rid of python2 [tor-browser-build]
+ * Bug 40487: Bump Python version [tor-browser-build]
+ * Bug 40802: Drop the patch for making WASI reproducible [tor-browser-build]
+ * Bug 40836: Update do-all-signing script to also deploy mullvad-browser installer bins to dist.torproject.org [tor-browser-build]
+ * Bug 40868: Bump Rust to 1.69.0 [tor-browser-build]
+ * Bug 40881: do-all-signing is asking for nssdb7 password when signing mullvadbrowser [tor-browser-build]
+ * Bug 40882: Fix static-update-component command in issue_templates [tor-browser-build]
+ * Bug 40886: Update README with instructions for Arch linux [tor-browser-build]
+ * Bug 40889: Add mullvad sha256sums URL to tools/signing/download-unsigned-sha256sums-gpg-signatures-from-people-tpo [tor-browser-build]
+ * Bug 40894: Fix format of keyring/boklm.gpg [tor-browser-build]
+ * Bug 40898: Add doc from tor-browser-spec/processes/ReleaseProcess to gitlab issue templates [tor-browser-build]
+ * Windows
+ * Bug 40832: Unify mingw-w64-clang 32+64 bits [tor-browser-build]
+ * Linux
+ * Bug 40102: Move from Debian Jessie to Debian Stretch for our Linux builds [tor-browser-build]
+
Mullvad Browser 12.5.1 - July 5 2023
* All Platforms
* Updated Firefox to 102.13.0esr
=====================================
projects/browser/Bundle-Data/Docs-TBB/ChangeLog.txt
=====================================
@@ -1,3 +1,66 @@
+Tor Browser 12.5.2 - July 31 2023
+ * All Platforms
+ * Updated Translations
+ * Updated NoScript to 11.4.26
+ * Bug 41908: Rebase stable 12.5 to 102.14esr [tor-browser]
+ * Windows + macOS + Linux
+ * Updated Firefox to 102.14.0esr
+ * Windows
+ * Bug 41761: xul.dll win crash tor-browser 12.5.1 (based on Mozilla Firefox 102.13.0esr) (64-Bit) [tor-browser]
+ * Android
+ * Updated GeckoView to 102.14.0esr
+ * Bug 41928: Backport Android-specific security fixes from Firefox 116 to ESR 102.14 / 115.1 - based Tor Browser [tor-browser]
+ * Build System
+ * All Platforms
+ * Updated Go to 1.20.6
+ * Bug 40889: Add mullvad sha256sums URL to tools/signing/download-unsigned-sha256sums-gpg-signatures-from-people-tpo [tor-browser-build]
+ * Bug 40894: Fix format of keyring/boklm.gpg [tor-browser-build]
+ * Bug 40909: Add dan_b and ma1 to list of taggers in relevant projects [tor-browser-build]
+ * Windows
+ * Bug 31546: Create and expose PDB files for Tor Browser debugging on Windows [tor-browser-build]
+
+Tor Browser 13.0a1 - July 20 2023
+ * All Platforms
+ * Updated Translations
+ * Updated NoScript to 11.4.25
+ * Updated OpenSSL to 3.0.9
+s * Updated tor to 0.4.8.2-alpha
+ * Bug 40577: Add "suggest url" in DDG onion's manifest [tor-browser]
+ * Bug 40885: Bump version of snowflake to v2.6.0 [tor-browser-build]
+ * Bug 40887: Update Webtunnel version to 38eb5505 [tor-browser-build]
+ * Bug 41092: Enable tracking query parameters stripping [tor-browser]
+ * Bug 41399: Update Mozilla's patch for Bug 1675054 to enable brotli encoding for HTTP onions as well [tor-browser]
+ * Bug 41759: Rebase Base Browser to 115 nightly [tor-browser]
+ * Bug 41796: Rebase Tor Browser to Firefox 115 [tor-browser]
+ * Windows + macOS + Linux
+ * Updated Firefox to 115.0.2esr
+ * Bug 26277: When "Safest" setting is enabled searching using duckduckgo should always use the Non-Javascript site for searches [tor-browser]
+ * Bug 33955: Selecting "Copy image" from menu leaks the source URL to the clipboard. This data is often dereferenced by other applications. [tor-browser]
+ * Bug 41741: Refactor the domain isolator and new circuit [tor-browser]
+ * Bug 41834: Hide "Can't Be Removed - learn more" menu line for uninstallable add-ons [tor-browser]
+ * Bug 41842: Remove the old removal logics from Torbutton [tor-browser]
+ * Bug 41845: Stop forcing (bad) pref values for non-PBM users [tor-browser]
+ * Bug 41854: Download Spam Protection cannot be overridden to allow legitimate downloads [tor-browser]
+ * Bug 41874: Visual & A11 regressions in add-on badges [tor-browser]
+ * Build System
+ * All Platforms
+ * Updated Go to 1.20.6
+ * Bug 40089: Clean up usage of get-moz-build-date script [tor-browser-build]
+ * Bug 40410: Get rid of python2 [tor-browser-build]
+ * Bug 40487: Bump Python version [tor-browser-build]
+ * Bug 40802: Drop the patch for making WASI reproducible [tor-browser-build]
+ * Bug 40854: Update to OpenSSL 3.0 [tor-browser-build]
+ * Bug 40855: Update toolchains for Mozilla 115 [tor-browser-build]
+ * Bug 40868: Bump Rust to 1.69.0 [tor-browser-build]
+ * Bug 40886: Update README with instructions for Arch linux [tor-browser-build]
+ * Bug 40889: Add mullvad sha256sums URL to tools/signing/download-unsigned-sha256sums-gpg-signatures-from-people-tpo [tor-browser-build]
+ * Bug 40894: Fix format of keyring/boklm.gpg [tor-browser-build]
+ * Bug 40898: Add doc from tor-browser-spec/processes/ReleaseProcess to gitlab issue templates [tor-browser-build]
+ * Windows
+ * Bug 40832: Unify mingw-w64-clang 32+64 bits [tor-browser-build]
+ * Linux
+ * Bug 40102: Move from Debian Jessie to Debian Stretch for our Linux builds [tor-browser-build]
+
Tor Browser 12.5.1 - July 5 2023
* All Platforms
* Updated Translations
=====================================
projects/browser/allowed_addons.json
=====================================
@@ -17,7 +17,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/34/9734/13299734/13299734.pn…"
}
],
- "average_daily_users": 976479,
+ "average_daily_users": 962930,
"categories": {
"android": [
"experimental",
@@ -221,10 +221,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.56,
- "bayesian_average": 4.5588356415270255,
- "count": 5048,
- "text_count": 1588
+ "average": 4.559,
+ "bayesian_average": 4.557842722028656,
+ "count": 5084,
+ "text_count": 1599
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/darkreader/reviews/",
"requires_payment": false,
@@ -321,7 +321,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/darkreader/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/darkreader/versions/",
- "weekly_downloads": 22317
+ "weekly_downloads": 23323
},
"notes": null
},
@@ -337,7 +337,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/56/7656/6937656/6937656.png?…"
}
],
- "average_daily_users": 254700,
+ "average_daily_users": 249584,
"categories": {
"android": [
"security-privacy"
@@ -553,10 +553,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.8141,
- "bayesian_average": 4.809441565441486,
- "count": 1345,
- "text_count": 239
+ "average": 4.8164,
+ "bayesian_average": 4.811755496156948,
+ "count": 1351,
+ "text_count": 238
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/decentraleyes/reviews/",
"requires_payment": false,
@@ -641,7 +641,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/decentraleyes/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/decentraleyes/versions/",
- "weekly_downloads": 3367
+ "weekly_downloads": 3565
},
"notes": null
},
@@ -657,7 +657,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/73/4073/5474073/5474073.png?…"
}
],
- "average_daily_users": 1106740,
+ "average_daily_users": 1076689,
"categories": {
"android": [
"security-privacy"
@@ -1180,10 +1180,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.8001,
- "bayesian_average": 4.797318686786584,
- "count": 2246,
- "text_count": 430
+ "average": 4.8004,
+ "bayesian_average": 4.797633259374899,
+ "count": 2260,
+ "text_count": 431
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-badger17/reviews/",
"requires_payment": false,
@@ -1207,7 +1207,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-badger17/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-badger17/versions/",
- "weekly_downloads": 16212
+ "weekly_downloads": 17062
},
"notes": null
},
@@ -1223,7 +1223,7 @@
"picture_url": null
}
],
- "average_daily_users": 6343757,
+ "average_daily_users": 6222480,
"categories": {
"android": [
"security-privacy"
@@ -1235,7 +1235,7 @@
"contributions_url": "",
"created": "2015-04-25T07:26:22Z",
"current_version": {
- "id": 5577564,
+ "id": 5596914,
"compatibility": {
"firefox": {
"min": "78.0",
@@ -1246,7 +1246,7 @@
"max": "*"
}
},
- "edit_url": "https://addons.mozilla.org/en-US/developers/addon/ublock-origin/versions/55…",
+ "edit_url": "https://addons.mozilla.org/en-US/developers/addon/ublock-origin/versions/55…",
"is_strict_compatibility_enabled": false,
"license": {
"id": 6,
@@ -1257,22 +1257,22 @@
"url": "http://www.gnu.org/licenses/gpl-3.0.html"
},
"release_notes": {
- "en-US": "See complete release notes for <a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/7fcd41188a6953809f0fad…" rel=\"nofollow\">1.50.0</a>.\n\n<b>Fixes / changes</b>\n\n<ul><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/977347fbc293beb1b00cf4…" rel=\"nofollow\">Add support to remove attributes in <code>xml-prune</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/c9e976bb7ba563f559cb84…" rel=\"nofollow\">Fix/improve <code>href-sanitizer</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/947fbffc69bbc18f1b4f8b…" rel=\"nofollow\">Add <code>evaldata-prune</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/6fabbf1578224a96f4235c…" rel=\"nofollow\">Add support for <code>xhr</code> in <code>xml-prune</code></a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/b9b7ca5319d3556ce0d3ed…" rel=\"nofollow\">Add <code>remove-node-text.js</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/da793e19009995cada9b48…" rel=\"nofollow\">Add <code>trusted-set-constant</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/66f1f4b1da03a7a8715f78…" rel=\"nofollow\">Support injecting scriptlet in MAIN or ISOLATED world</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/3fd6afc187b7b8c1500645…" rel=\"nofollow\">Add trusted-source support for privileged scriptlets (and add <code>replace-node-text</code> scriptlet)</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/6e4b972fd0290469b171e1…" rel=\"nofollow\">Add <code>spoof-css</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/4b36cc246f707b4874b088…" rel=\"nofollow\">Add back AdGuard Tracking Protection</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/8b57c0f1ab563a91cacf8b…" rel=\"nofollow\">Expand/harden some scriptlets</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/b09d7802d09b73339452c8…" rel=\"nofollow\">Return string when storage.sync.get() promise fails</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/2790102e66a40a639271d7…" rel=\"nofollow\">Do not bail out when <code>content-disposition</code> is <code>inline</code></a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/a84de6a39a7b337bb548e9…" rel=\"nofollow\">Fix improperly unselecting imported lists</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/a38daad10b996d4d90b5a8…" rel=\"nofollow\">Report injected scriptlets in troubleshooting information</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/38b66ee4efd37b2af4acfc…" rel=\"nofollow\">Fix rendering issue of row-filter icon in popup panel</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/554f8ab9f03ac96103840e…" rel=\"nofollow\">Add \"scriptlet\" filter expression to logger</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/ca5c705729c8d4abd4daa7…" rel=\"nofollow\">Fix hostname-detecting regex</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/73dff2c4f0d68678b7155e…" rel=\"nofollow\">Add support for sublists in \"Filter lists\" pane</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/bb5992c336ad2779412f27…" rel=\"nofollow\">Properly handle converted procedural filters in logger</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/ba761870d0433aa47eda9b…" rel=\"nofollow\">Mind small screen size in asset viewer</a></li><li>...</li></ul>\n<a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/5564d601607fa4079ea0e6…" rel=\"nofollow\">Commits history since last version</a>."
+ "en-US": "See complete release notes for <a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/57eadd553bcb629be4f757…" rel=\"nofollow\">1.51.0</a>.\n\n<b>Fixes / changes</b>\n\n<ul><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/a578674b791ed67b926b31…" rel=\"nofollow\">Remove obsolete web<em>accessible</em>resources</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/7071379ad6c88fec4e40b3…" rel=\"nofollow\">Add missing (deprecated) method to google ima</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/bf46690e10ed8a086d9d50…" rel=\"nofollow\">Fix regression in handling of experimental <code>header=</code> filter option</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/f2328063ec5c7512d5899f…" rel=\"nofollow\">Only already normalized CSS selectors can be fast path-compiled</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/e271cd306c9578e0ed17c7…" rel=\"nofollow\">Improve compatibility with AdGuard's scriptlets</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/f42373a2522c9739807b48…" rel=\"nofollow\">Add static network filter option: <code>permissions</code></a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/f502abdb178413a344a43d…" rel=\"nofollow\">Add <code>set-attr</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/46449872121aa9a39f8fe5…" rel=\"nofollow\">Do not bail too early when trapping properties in <code>acs</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/76b28688717445a36e5ee4…" rel=\"nofollow\">Fix regression in cloud storage import of \"Filter lists\" pane</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/eb0f0fdfbd50904d7cd8e2…" rel=\"nofollow\">Add <code>set-session-storage-item</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/f125a8290e220a02336532…" rel=\"nofollow\">Prevent negative position when widget size is greater than viewport size</a><ul><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/e49ec519e35ce90b1ce424…" rel=\"nofollow\">Ensure no negative value for <code>top</code> property of floating widget in logger</a></li></ul></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/2398a39690c82a85f3fb23…" rel=\"nofollow\">Add visual hint when not all sublists are enabled</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/f549cc526fa10665161c86…" rel=\"nofollow\">Add support for AdGuard's noop (<code>_</code>) network filter option</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/c649c1ddb8b1d7f280a068…" rel=\"nofollow\">Add \"tabless\" filter expression for logger output</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/3f7e7d0a06e918e4c8b3f8…" rel=\"nofollow\">Add support for logical expressions to <code>!#if</code> directive</a><ul><li>Also added support for <code>!#else</code></li></ul></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/f1e827e5c4e256a0c832f9…" rel=\"nofollow\">Add resource aliases for increased compatibility with AdGuard lists</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/6f42d070e087002ada8f37…" rel=\"nofollow\">Add compatibility with AdGuard's <code>#%#//scriptlet(...)</code> syntax</a><ul><li>Also added support for quoted parameters in <code>##+js(...)</code> syntax</li></ul></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/50632bd7b34e7e7185c764…" rel=\"nofollow\">Fix syntax highlighter throwing with invalid patterns</a></li><li>...</li></ul>\n<a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/7c755863346ab5ff9e77ae…" rel=\"nofollow\">Commits history since last version</a>."
},
- "reviewed": "2023-06-12T17:49:10Z",
- "version": "1.50.0",
+ "reviewed": "2023-07-25T09:58:22Z",
+ "version": "1.51.0",
"files": [
{
- "id": 4121906,
- "created": "2023-06-07T14:50:07Z",
- "hash": "sha256:10618003e70b528c3f17996e373146d39e6b15f777ac4ca1f214da2ffdb7a5b3",
+ "id": 4141256,
+ "created": "2023-07-19T23:09:25Z",
+ "hash": "sha256:8b73468bc233a11dd2895219466381783d19123857dd0b6fd16a01820fca4834",
"is_restart_required": false,
"is_webextension": true,
"is_mozilla_signed_extension": false,
"platform": "all",
- "size": 3504841,
+ "size": 3538418,
"status": "public",
- "url": "https://addons.mozilla.org/firefox/downloads/file/4121906/ublock_origin-1.5…",
+ "url": "https://addons.mozilla.org/firefox/downloads/file/4141256/ublock_origin-1.5…",
"permissions": [
"dns",
"menus",
@@ -1388,7 +1388,7 @@
},
"is_disabled": false,
"is_experimental": false,
- "last_updated": "2023-06-29T19:20:30Z",
+ "last_updated": "2023-07-31T14:35:40Z",
"name": {
"ar": "uBlock Origin",
"bg": "uBlock Origin",
@@ -1533,10 +1533,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.7818,
- "bayesian_average": 4.781401064910532,
- "count": 15597,
- "text_count": 4062
+ "average": 4.7821,
+ "bayesian_average": 4.78170472062552,
+ "count": 15763,
+ "text_count": 4095
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/reviews/",
"requires_payment": false,
@@ -1598,7 +1598,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/versions/",
- "weekly_downloads": 124486
+ "weekly_downloads": 131014
},
"notes": null
},
@@ -1614,7 +1614,7 @@
"picture_url": null
}
],
- "average_daily_users": 168312,
+ "average_daily_users": 167538,
"categories": {
"android": [
"photos-media"
@@ -1713,10 +1713,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.492,
- "bayesian_average": 4.486860720506839,
- "count": 1122,
- "text_count": 420
+ "average": 4.4916,
+ "bayesian_average": 4.486471885365025,
+ "count": 1129,
+ "text_count": 422
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/video-background-play-fix/re…",
"requires_payment": false,
@@ -1738,7 +1738,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/video-background-play-fix/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/video-background-play-fix/ve…",
- "weekly_downloads": 341
+ "weekly_downloads": 312
},
"notes": null
},
@@ -1754,7 +1754,7 @@
"picture_url": null
}
],
- "average_daily_users": 87436,
+ "average_daily_users": 85413,
"categories": {
"android": [
"experimental",
@@ -1867,9 +1867,9 @@
],
"promoted": null,
"ratings": {
- "average": 4.37,
- "bayesian_average": 4.356186612333998,
- "count": 400,
+ "average": 4.3766,
+ "bayesian_average": 4.362648333186986,
+ "count": 401,
"text_count": 112
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-possum/reviews/",
@@ -1892,7 +1892,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-possum/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-possum/versions/",
- "weekly_downloads": 1599
+ "weekly_downloads": 1759
},
"notes": null
},
@@ -1908,7 +1908,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/64/9064/12929064/12929064.pn…"
}
],
- "average_daily_users": 259583,
+ "average_daily_users": 257591,
"categories": {
"android": [
"photos-media",
@@ -1922,7 +1922,7 @@
"contributions_url": "https://www.paypal.com/donate?hosted_button_id=GLL4UNSNU6SQN&utm_content=pr…",
"created": "2017-06-17T15:23:33Z",
"current_version": {
- "id": 5574786,
+ "id": 5588477,
"compatibility": {
"firefox": {
"min": "91.0",
@@ -1933,7 +1933,7 @@
"max": "*"
}
},
- "edit_url": "https://addons.mozilla.org/en-US/developers/addon/search_by_image/versions/…",
+ "edit_url": "https://addons.mozilla.org/en-US/developers/addon/search_by_image/versions/…",
"is_strict_compatibility_enabled": false,
"license": {
"id": 6,
@@ -1946,20 +1946,20 @@
"release_notes": {
"en-US": "Learn more about this release from the <a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/d50855f24f77fa6f2614b9…" rel=\"nofollow\">changelog</a>."
},
- "reviewed": "2023-06-13T17:09:40Z",
- "version": "5.6.0",
+ "reviewed": "2023-07-06T11:07:12Z",
+ "version": "5.7.0",
"files": [
{
- "id": 4119128,
- "created": "2023-06-01T20:36:45Z",
- "hash": "sha256:fb347a4756e87858fb7ad1e8cb44d3cc4374440d1abdb0fcb3d048c6d5b9c522",
+ "id": 4132819,
+ "created": "2023-07-02T12:35:20Z",
+ "hash": "sha256:9149335f16762c6d4f33ce39f036db763b8c4a3250f5e04e915b827da22a0eb1",
"is_restart_required": false,
"is_webextension": true,
"is_mozilla_signed_extension": false,
"platform": "all",
- "size": 1183625,
+ "size": 1198456,
"status": "public",
- "url": "https://addons.mozilla.org/firefox/downloads/file/4119128/search_by_image-5…",
+ "url": "https://addons.mozilla.org/firefox/downloads/file/4132819/search_by_image-5…",
"permissions": [
"alarms",
"clipboardRead",
@@ -2001,7 +2001,7 @@
},
"is_disabled": false,
"is_experimental": false,
- "last_updated": "2023-06-13T17:09:40Z",
+ "last_updated": "2023-07-06T11:07:12Z",
"name": {
"en-US": "Search by Image"
},
@@ -2127,10 +2127,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.6496,
- "bayesian_average": 4.6449294901011795,
- "count": 1287,
- "text_count": 248
+ "average": 4.6525,
+ "bayesian_average": 4.647859623714072,
+ "count": 1298,
+ "text_count": 250
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/search_by_image/reviews/",
"requires_payment": false,
@@ -2151,7 +2151,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/search_by_image/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/search_by_image/versions/",
- "weekly_downloads": 3731
+ "weekly_downloads": 3948
},
"notes": null
},
@@ -2174,7 +2174,7 @@
"picture_url": null
}
],
- "average_daily_users": 111659,
+ "average_daily_users": 111141,
"categories": {
"android": [
"other"
@@ -2457,10 +2457,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.4396,
- "bayesian_average": 4.43492961003513,
- "count": 1217,
- "text_count": 323
+ "average": 4.4207,
+ "bayesian_average": 4.416093483315006,
+ "count": 1229,
+ "text_count": 332
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/google-search-fixer/reviews/",
"requires_payment": false,
@@ -2480,7 +2480,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/google-search-fixer/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/google-search-fixer/versions/",
- "weekly_downloads": 17
+ "weekly_downloads": 52
},
"notes": null
},
@@ -2496,7 +2496,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/43/0143/143/143.png?modified…"
}
],
- "average_daily_users": 307856,
+ "average_daily_users": 301882,
"categories": {
"android": [
"performance",
@@ -2510,7 +2510,7 @@
"contributions_url": "https://www.paypal.com/donate/?hosted_button_id=9ERKTU5MBH4EW&utm_content=p…",
"created": "2005-05-13T10:51:32Z",
"current_version": {
- "id": 5587303,
+ "id": 5597003,
"compatibility": {
"firefox": {
"min": "59.0",
@@ -2521,7 +2521,7 @@
"max": "*"
}
},
- "edit_url": "https://addons.mozilla.org/en-US/developers/addon/noscript/versions/5587303",
+ "edit_url": "https://addons.mozilla.org/en-US/developers/addon/noscript/versions/5597003",
"is_strict_compatibility_enabled": false,
"license": {
"id": 13,
@@ -2532,22 +2532,22 @@
"url": "http://www.gnu.org/licenses/gpl-2.0.html"
},
"release_notes": {
- "en-US": "v 11.4.24\n============================================================\nx [XSS] Fix Base64 hash checks interfering with query string\n checks (thanks barbaz for reporting)\nx [TabGuard] Stop exempting domains bidirectionally by\n default\nx [TabGuard] Fix destination domain being reported as the\n trigger of a warning prompt when all the other tab-tied\n domains have been exempted (thanks barbaz for report)"
+ "en-US": "v 11.4.26\n============================================================\nx [Android] Fixed regression preventing NoScript prompts\n from being shown\nx [XSS] Fallback to execute most demanding regular\n expressions asynchronously\nx [XSS] Removed obsolete Flash-related checks\nx [XSS] Make InjectionChecker's regular expressions easier\n to debug\nx [XSS] Updated OpenID regexp"
},
- "reviewed": "2023-06-29T16:56:20Z",
- "version": "11.4.24",
+ "reviewed": "2023-07-25T09:58:54Z",
+ "version": "11.4.26",
"files": [
{
- "id": 4131645,
- "created": "2023-06-29T15:56:08Z",
- "hash": "sha256:e4b69777d7b9e06e93fcba93d065a246a53c2fa5e113605207836374e48a4fb5",
+ "id": 4141345,
+ "created": "2023-07-20T07:16:01Z",
+ "hash": "sha256:283db0eaebbd2888c1a852f5acabaa8e0225ff1eb1a97a25bceaedfd14d9f44c",
"is_restart_required": false,
"is_webextension": true,
"is_mozilla_signed_extension": false,
"platform": "all",
- "size": 950051,
+ "size": 952442,
"status": "public",
- "url": "https://addons.mozilla.org/firefox/downloads/file/4131645/noscript-11.4.24.…",
+ "url": "https://addons.mozilla.org/firefox/downloads/file/4141345/noscript-11.4.26.…",
"permissions": [
"contextMenus",
"storage",
@@ -2614,7 +2614,7 @@
},
"is_disabled": false,
"is_experimental": false,
- "last_updated": "2023-06-29T16:56:20Z",
+ "last_updated": "2023-07-25T09:58:54Z",
"name": {
"de": "NoScript",
"el": "NoScript",
@@ -2686,10 +2686,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.4062,
- "bayesian_average": 4.403489797240767,
- "count": 2080,
- "text_count": 807
+ "average": 4.4024,
+ "bayesian_average": 4.399703348010946,
+ "count": 2090,
+ "text_count": 811
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/noscript/reviews/",
"requires_payment": false,
@@ -2733,7 +2733,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/noscript/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/noscript/versions/",
- "weekly_downloads": 6997
+ "weekly_downloads": 7947
},
"notes": null
},
@@ -2749,7 +2749,7 @@
"picture_url": null
}
],
- "average_daily_users": 150711,
+ "average_daily_users": 149808,
"categories": {
"android": [
"performance",
@@ -2864,10 +2864,10 @@
"category": "recommended"
},
"ratings": {
- "average": 3.901,
- "bayesian_average": 3.8967503054386836,
- "count": 1141,
- "text_count": 403
+ "average": 3.9005,
+ "bayesian_average": 3.89624887816371,
+ "count": 1146,
+ "text_count": 406
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/youtube-high-definition/revi…",
"requires_payment": false,
@@ -2886,7 +2886,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/youtube-high-definition/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/youtube-high-definition/vers…",
- "weekly_downloads": 1697
+ "weekly_downloads": 1645
},
"notes": null
}
=====================================
projects/browser/config
=====================================
@@ -103,12 +103,12 @@ input_files:
enable: '[% ! c("var/android") %]'
- filename: Bundle-Data
enable: '[% ! c("var/android") %]'
- - URL: https://addons.mozilla.org/firefox/downloads/file/4131645/noscript-11.4.24.…
+ - URL: https://addons.mozilla.org/firefox/downloads/file/4141345/noscript-11.4.26.…
name: noscript
- sha256sum: e4b69777d7b9e06e93fcba93d065a246a53c2fa5e113605207836374e48a4fb5
- - URL: https://addons.mozilla.org/firefox/downloads/file/4121906/ublock_origin-1.5…
+ sha256sum: 283db0eaebbd2888c1a852f5acabaa8e0225ff1eb1a97a25bceaedfd14d9f44c
+ - URL: https://addons.mozilla.org/firefox/downloads/file/4141256/ublock_origin-1.5…
name: ublock-origin
- sha256sum: 10618003e70b528c3f17996e373146d39e6b15f777ac4ca1f214da2ffdb7a5b3
+ sha256sum: 8b73468bc233a11dd2895219466381783d19123857dd0b6fd16a01820fca4834
enable: '[% c("var/mullvad-browser") %]'
- URL: https://github.com/mullvad/browser-extension/releases/download/v0.8.3-firef…
name: mullvad-extension
=====================================
projects/firefox/config
=====================================
@@ -13,7 +13,7 @@ container:
use_container: 1
var:
- firefox_platform_version: 102.13.0
+ firefox_platform_version: 102.14.0
firefox_version: '[% c("var/firefox_platform_version") %]esr'
browser_series: '12.5'
browser_branch: '[% c("var/browser_series") %]-1'
=====================================
projects/geckoview/config
=====================================
@@ -13,7 +13,7 @@ container:
use_container: 1
var:
- geckoview_version: 102.13.0esr
+ geckoview_version: 102.14.0esr
browser_branch: 12.5-1
browser_build: 2
copyright_year: '[% exec("git show -s --format=%ci").remove("-.*") %]'
=====================================
projects/go/config
=====================================
@@ -1,5 +1,5 @@
# vim: filetype=yaml sw=2
-version: 1.20.5
+version: 1.20.6
filename: '[% project %]-[% c("version") %]-[% c("var/osname") %]-[% c("var/build_id") %].tar.gz'
container:
use_container: 1
@@ -119,7 +119,7 @@ input_files:
enable: '[% ! c("var/linux") %]'
- URL: 'https://golang.org/dl/go[% c("version") %].src.tar.gz'
name: go
- sha256sum: 9a15c133ba2cfafe79652f4815b62e7cfc267f68df1b9454c6ab2a3ca8b96a88
+ sha256sum: 62ee5bc6fb55b8bae8f705e0cb8df86d6453626b4ecf93279e2867092e0b7f70
- project: go-bootstrap
name: go-bootstrap
target_replace:
=====================================
projects/manual/config
=====================================
@@ -1,7 +1,7 @@
# vim: filetype=yaml sw=2
# To update, see doc/how-to-update-the-manual.txt
# Remember to update also the package's hash, with the version!
-version: 86602
+version: 88998
filename: 'manual-[% c("version") %]-[% c("var/build_id") %].tar.gz'
container:
use_container: 1
@@ -17,8 +17,8 @@ var:
input_files:
- project: container-image
- - URL: 'https://people.torproject.org/~pierov/tbb_files/manual_[% c("version") %].zip'
+ - URL: 'https://people.torproject.org/~richard/tbb_files/manual_[% c("version") %].zip'
name: manual
- sha256sum: ee3c5b7fbe9aa3dfaca546e2f6a57f2f740fb3d6332e8c827e5ba6cbf99299b3
+ sha256sum: 1be6cf35a3c9f243998b7611e9531d4a99591cc257cb55f3924f504b9ead71a7
- filename: packagemanual.py
name: package_script
=====================================
projects/tor/config
=====================================
@@ -1,6 +1,6 @@
# vim: filetype=yaml sw=2
filename: '[% project %]-[% c("version") %]-[% c("var/osname") %]-[% c("var/build_id") %].tar.gz'
-version: 0.4.7.13
+version: 0.4.7.14
git_hash: 'tor-[% c("version") %]'
git_url: https://gitlab.torproject.org/tpo/core/tor.git
git_submodule: 1
=====================================
projects/translation/config
=====================================
@@ -6,19 +6,19 @@ version: '[% c("abbrev") %]'
steps:
base-browser:
base-browser: '[% INCLUDE build %]'
- git_hash: f43ccce2bc26ec711d94ef3e0246000f16d012df
+ git_hash: 3fd9777d984fb3f3c31f92c1a6be957413c3c4c7
targets:
nightly:
git_hash: 'base-browser'
base-browser-fluent:
base-browser-fluent: '[% INCLUDE build %]'
- git_hash: 1d597e0a5b6f1402c1170e2f65642810bdd586e3
+ git_hash: 6f64004400616a5956d1823a0e8176b60d212090
targets:
nightly:
git_hash: 'basebrowser-newidentityftl'
tor-browser:
tor-browser: '[% INCLUDE build %]'
- git_hash: ac9790fa9367c36fc0e2771409b1f0f3661d168d
+ git_hash: 70f7283dc31e6bd7b7ab954296ac960301d474f4
targets:
nightly:
git_hash: 'tor-browser'
@@ -26,7 +26,7 @@ steps:
fenix: '[% INCLUDE build %]'
# We need to bump the commit before releasing but just pointing to a branch
# might cause too much rebuidling of the Firefox part.
- git_hash: 399d0fcee55eacdc7e2d68cd84c824c4d924357f
+ git_hash: e037147c72348192ddd38c2a21712c65031b912c
targets:
nightly:
git_hash: 'fenix-torbrowserstringsxml'
=====================================
rbm.conf
=====================================
@@ -94,12 +94,11 @@ buildconf:
git_signtag_opt: '-s'
var:
- torbrowser_version: '12.5.1'
+ torbrowser_version: '12.5.2'
torbrowser_build: 'build1'
torbrowser_incremental_from:
+ - 12.5.1
- 12.5
- - 12.0.7
- - 12.0.6
updater_enabled: 1
build_mar: 1
mar_channel_id: '[% c("var/projectname") %]-torproject-[% c("var/channel") %]'
@@ -277,7 +276,6 @@ targets:
exe_name: mullvadbrowser
mar_channel_id: '[% c("var/projectname") %]-mullvad-[% c("var/channel") %]'
locales: []
- torbrowser_build: 'build1'
torbrowser-testbuild:
- testbuild
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/2…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/2…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser] Pushed new tag base-browser-115.1.0esr-13.0-1-build2
by ma1 (@ma1) 01 Aug '23
by ma1 (@ma1) 01 Aug '23
01 Aug '23
ma1 pushed new tag base-browser-115.1.0esr-13.0-1-build2 at The Tor Project / Applications / Tor Browser
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/tree/base-brow…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser] Pushed new tag tor-browser-115.1.0esr-13.0-1-build2
by ma1 (@ma1) 01 Aug '23
by ma1 (@ma1) 01 Aug '23
01 Aug '23
ma1 pushed new tag tor-browser-115.1.0esr-13.0-1-build2 at The Tor Project / Applications / Tor Browser
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/tree/tor-brows…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][base-browser-115.1.0esr-13.0-1] 4 commits: Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
by ma1 (@ma1) 01 Aug '23
by ma1 (@ma1) 01 Aug '23
01 Aug '23
ma1 pushed to branch base-browser-115.1.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
45b89a93 by Edgar Chen at 2023-08-01T17:39:54+02:00
Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
Fullscreen/PointerLock warnings are initialized with hidden="true", but
change to hidden="" after being shown and hidden again. I think this
started happening when we began using HTML elements instead of XUL as
they handle hidden attribute differently.
Differential Revision: https://phabricator.services.mozilla.com/D177790
- - - - -
1b031e60 by Edgar Chen at 2023-08-01T17:39:54+02:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
- - - - -
33af6b34 by Eitan Isaacson at 2023-08-01T17:39:55+02:00
Bug 1819160 - Map Android ids to doc/accessible id pairs. r=Jamie
Differential Revision: https://phabricator.services.mozilla.com/D179737
- - - - -
65183e25 by Jon Coppeard at 2023-08-01T17:39:55+02:00
Bug 1828024 - Require the helper thread lock in the GC helper thread count getter r=sfink
This makes us take a lock to read this state (we already lock when writing it).
Also it adds a release assert in case something goes wrong with the thread
count calculations, as a crash is preferable to the potential deadlock.
Differential Revision: https://phabricator.services.mozilla.com/D181257
- - - - -
12 changed files:
- accessible/android/SessionAccessibility.cpp
- accessible/android/SessionAccessibility.h
- accessible/ipc/DocAccessibleParent.cpp
- accessible/ipc/DocAccessibleParent.h
- accessible/ipc/moz.build
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/base/content/fullscreen-and-pointerlock.inc.xhtml
- browser/base/content/test/fullscreen/browser_fullscreen_warning.js
- dom/tests/browser/browser_pointerlock_warning.js
- js/src/gc/GC.cpp
- js/src/gc/ParallelMarking.cpp
- js/src/vm/HelperThreadState.h
Changes:
=====================================
accessible/android/SessionAccessibility.cpp
=====================================
@@ -269,12 +269,9 @@ RefPtr<SessionAccessibility> SessionAccessibility::GetInstanceFor(
return GetInstanceFor(doc->GetPresShell());
}
} else {
- DocAccessibleParent* remoteDoc = aAccessible->AsRemote()->Document();
- if (remoteDoc->mSessionAccessibility) {
- return remoteDoc->mSessionAccessibility;
- }
dom::CanonicalBrowsingContext* cbc =
- static_cast<dom::BrowserParent*>(remoteDoc->Manager())
+ static_cast<dom::BrowserParent*>(
+ aAccessible->AsRemote()->Document()->Manager())
->GetBrowsingContext()
->Top();
dom::BrowserParent* bp = cbc->GetBrowserParent();
@@ -285,10 +282,7 @@ RefPtr<SessionAccessibility> SessionAccessibility::GetInstanceFor(
if (auto element = bp->GetOwnerElement()) {
if (auto doc = element->OwnerDoc()) {
if (nsPresContext* presContext = doc->GetPresContext()) {
- RefPtr<SessionAccessibility> sessionAcc =
- GetInstanceFor(presContext->PresShell());
- remoteDoc->mSessionAccessibility = sessionAcc;
- return sessionAcc;
+ return GetInstanceFor(presContext->PresShell());
}
} else {
MOZ_ASSERT_UNREACHABLE(
@@ -684,14 +678,7 @@ void SessionAccessibility::PopulateNodeInfo(
}
Accessible* SessionAccessibility::GetAccessibleByID(int32_t aID) const {
- Accessible* accessible = mIDToAccessibleMap.Get(aID);
- if (accessible && accessible->IsLocal() &&
- accessible->AsLocal()->IsDefunct()) {
- MOZ_ASSERT_UNREACHABLE("Registered accessible is defunct!");
- return nullptr;
- }
-
- return accessible;
+ return mIDToAccessibleMap.Get(aID);
}
#ifdef DEBUG
@@ -705,6 +692,58 @@ static bool IsDetachedDoc(Accessible* aAccessible) {
}
#endif
+SessionAccessibility::IDMappingEntry::IDMappingEntry(Accessible* aAccessible)
+ : mInternalID(0) {
+ *this = aAccessible;
+}
+
+SessionAccessibility::IDMappingEntry&
+SessionAccessibility::IDMappingEntry::operator=(Accessible* aAccessible) {
+ mInternalID = aAccessible->ID();
+ MOZ_ASSERT(!(mInternalID & IS_REMOTE), "First bit is used in accessible ID!");
+ if (aAccessible->IsRemote()) {
+ mInternalID |= IS_REMOTE;
+ }
+
+ Accessible* docAcc = nsAccUtils::DocumentFor(aAccessible);
+ MOZ_ASSERT(docAcc);
+ if (docAcc) {
+ MOZ_ASSERT(docAcc->IsRemote() == aAccessible->IsRemote());
+ if (docAcc->IsRemote()) {
+ mDoc = docAcc->AsRemote()->AsDoc();
+ } else {
+ mDoc = docAcc->AsLocal();
+ }
+ }
+
+ return *this;
+}
+
+SessionAccessibility::IDMappingEntry::operator Accessible*() const {
+ if (mInternalID == 0) {
+ return static_cast<LocalAccessible*>(mDoc.get());
+ }
+
+ if (mInternalID == IS_REMOTE) {
+ return static_cast<DocAccessibleParent*>(mDoc.get());
+ }
+
+ if (mInternalID & IS_REMOTE) {
+ return static_cast<DocAccessibleParent*>(mDoc.get())
+ ->GetAccessible(mInternalID & ~IS_REMOTE);
+ }
+
+ Accessible* accessible =
+ static_cast<LocalAccessible*>(mDoc.get())
+ ->AsDoc()
+ ->GetAccessibleByUniqueID(reinterpret_cast<void*>(mInternalID));
+ // If the accessible is retrievable from the DocAccessible, it can't be
+ // defunct.
+ MOZ_ASSERT(!accessible->AsLocal()->IsDefunct());
+
+ return accessible;
+}
+
void SessionAccessibility::RegisterAccessible(Accessible* aAccessible) {
if (IPCAccessibilityActive()) {
// Don't register accessible in content process.
@@ -766,7 +805,6 @@ void SessionAccessibility::UnregisterAccessible(Accessible* aAccessible) {
}
RefPtr<SessionAccessibility> sessionAcc = GetInstanceFor(aAccessible);
- MOZ_ASSERT(sessionAcc, "Need SessionAccessibility to unregister Accessible!");
if (sessionAcc) {
Accessible* registeredAcc =
sessionAcc->mIDToAccessibleMap.Get(virtualViewID);
=====================================
accessible/android/SessionAccessibility.h
=====================================
@@ -110,10 +110,34 @@ class SessionAccessibility final
jni::NativeWeakPtr<widget::GeckoViewSupport> mWindow; // Parent only
java::SessionAccessibility::NativeProvider::GlobalRef mSessionAccessibility;
+ class IDMappingEntry {
+ public:
+ explicit IDMappingEntry(Accessible* aAccessible);
+
+ IDMappingEntry& operator=(Accessible* aAccessible);
+
+ operator Accessible*() const;
+
+ private:
+ // A strong reference to a DocAccessible or DocAccessibleParent. They don't
+ // share any useful base class except nsISupports, so we use that.
+ // When we retrieve the document from this reference we cast it to
+ // LocalAccessible in the DocAccessible case because DocAccessible has
+ // multiple inheritance paths for nsISupports.
+ RefPtr<nsISupports> mDoc;
+ // The ID of the accessible as used in the internal doc mapping.
+ // We rely on this ID being pointer derived and therefore divisible by two
+ // so we can use the first bit to mark if it is remote or not.
+ uint64_t mInternalID;
+
+ static const uintptr_t IS_REMOTE = 0x1;
+ };
+
/*
* This provides a mapping from 32 bit id to accessible objects.
*/
- nsTHashMap<nsUint32HashKey, Accessible*> mIDToAccessibleMap;
+ nsBaseHashtable<nsUint32HashKey, IDMappingEntry, Accessible*>
+ mIDToAccessibleMap;
};
} // namespace a11y
=====================================
accessible/ipc/DocAccessibleParent.cpp
=====================================
@@ -29,7 +29,6 @@
#endif
#if defined(ANDROID)
-# include "mozilla/a11y/SessionAccessibility.h"
# define ACQUIRE_ANDROID_LOCK \
MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
#else
=====================================
accessible/ipc/DocAccessibleParent.h
=====================================
@@ -29,10 +29,6 @@ class xpcAccessibleGeneric;
class DocAccessiblePlatformExtParent;
#endif
-#ifdef ANDROID
-class SessionAccessibility;
-#endif
-
/*
* These objects live in the main process and comunicate with and represent
* an accessible document in a content process.
@@ -348,10 +344,6 @@ class DocAccessibleParent : public RemoteAccessible,
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) override;
-#ifdef ANDROID
- RefPtr<SessionAccessibility> mSessionAccessibility;
-#endif
-
private:
~DocAccessibleParent();
=====================================
accessible/ipc/moz.build
=====================================
@@ -24,11 +24,6 @@ else:
LOCAL_INCLUDES += [
"/accessible/mac",
]
- elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
- LOCAL_INCLUDES += [
- "/accessible/android",
- "/widget/android",
- ]
else:
LOCAL_INCLUDES += [
"/accessible/other",
=====================================
browser/base/content/browser-fullScreenAndPointerLock.js
=====================================
@@ -62,9 +62,14 @@ var PointerlockFsWarning = {
this._element = document.getElementById(elementId);
// Setup event listeners
this._element.addEventListener("transitionend", this);
+ this._element.addEventListener("transitioncancel", this);
window.addEventListener("mousemove", this, true);
+ window.addEventListener("activate", this);
+ window.addEventListener("deactivate", this);
// The timeout to hide the warning box after a while.
this._timeoutHide = new this.Timeout(() => {
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
this._state = "hidden";
}, timeout);
// The timeout to show the warning box when the pointer is at the top
@@ -116,11 +121,10 @@ var PointerlockFsWarning = {
return;
}
- // Explicitly set the last state to hidden to avoid the warning
- // box being hidden immediately because of mousemove.
- this._state = "onscreen";
- this._lastState = "hidden";
- this._timeoutHide.start();
+ if (Services.focus.activeWindow == window) {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ }
},
/**
@@ -148,7 +152,10 @@ var PointerlockFsWarning = {
this._element.hidden = true;
// Remove all event listeners
this._element.removeEventListener("transitionend", this);
+ this._element.removeEventListener("transitioncancel", this);
window.removeEventListener("mousemove", this, true);
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
// Clear fields
this._element = null;
this._timeoutHide = null;
@@ -186,7 +193,7 @@ var PointerlockFsWarning = {
}
if (newState != "hidden") {
if (currentState != "hidden") {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
} else {
// When the previous state is hidden, the display was none,
// thus no box was constructed. We need to wait for the new
@@ -197,7 +204,7 @@ var PointerlockFsWarning = {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (this._element) {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
}
});
});
@@ -217,7 +224,7 @@ var PointerlockFsWarning = {
} else if (this._timeoutShow.delay >= 0) {
this._timeoutShow.start();
}
- } else {
+ } else if (state != "onscreen") {
let elemRect = this._element.getBoundingClientRect();
if (state == "hiding" && this._lastState != "hidden") {
// If we are on the hiding transition, and the pointer
@@ -239,12 +246,23 @@ var PointerlockFsWarning = {
}
break;
}
- case "transitionend": {
+ case "transitionend":
+ case "transitioncancel": {
if (this._state == "hiding") {
this._element.hidden = true;
}
break;
}
+ case "activate": {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ break;
+ }
+ case "deactivate": {
+ this._state = "hidden";
+ this._timeoutHide.cancel();
+ break;
+ }
}
},
};
=====================================
browser/base/content/fullscreen-and-pointerlock.inc.xhtml
=====================================
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<html:div id="fullscreen-and-pointerlock-wrapper">
- <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
@@ -20,7 +20,7 @@
</html:button>
</html:div>
- <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
=====================================
browser/base/content/test/fullscreen/browser_fullscreen_warning.js
=====================================
@@ -3,14 +3,35 @@
"use strict";
-add_task(async function test_fullscreen_display_none() {
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
+add_setup(async function init() {
await SpecialPowers.pushPrefEnv({
set: [
["full-screen-api.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
],
});
+});
+add_task(async function test_fullscreen_display_none() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
@@ -30,11 +51,13 @@ add_task(async function test_fullscreen_display_none() {
},
async function (browser) {
let warning = document.getElementById("fullscreen-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
warning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
);
+
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
// Enter fullscreen
await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
@@ -54,39 +77,33 @@ add_task(async function test_fullscreen_display_none() {
);
document.getElementById("fullscreen-exit-button").click();
await exitFullscreenPromise;
+
+ checkWarningState(
+ warning,
+ "hidden",
+ "Should hide fullscreen warning after exiting fullscreen"
+ );
}
);
});
add_task(async function test_fullscreen_pointerlock_conflict() {
- await SpecialPowers.pushPrefEnv({
- set: [
- ["full-screen-api.enabled", true],
- ["full-screen-api.allow-trusted-requests-only", false],
- ],
- });
-
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let fsWarning = document.getElementById("fullscreen-warning");
let plWarning = document.getElementById("pointerlock-warning");
- is(
- fsWarning.getAttribute("onscreen"),
- null,
- "Should not show full screen warning initially."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning initially."
- );
-
- let fsWarningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
fsWarning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
+ );
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning initially"
);
+ let fsWarningShownPromise = waitForWarningState(fsWarning, "onscreen");
info("Entering full screen and pointer lock.");
await SpecialPowers.spawn(browser, [], async () => {
await content.document.body.requestFullscreen();
@@ -94,15 +111,10 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
});
await fsWarningShownPromise;
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should show full screen warning."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
info("Exiting pointerlock");
@@ -110,18 +122,19 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
await content.document.exitPointerLock();
});
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should still show full screen warning."
+ checkWarningState(
+ fsWarning,
+ "onscreen",
+ "Should still show full screen warning"
);
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
// Cleanup
+ info("Exiting fullscreen");
await document.exitFullscreen();
});
});
=====================================
dom/tests/browser/browser_pointerlock_warning.js
=====================================
@@ -15,6 +15,25 @@ const FRAME_TEST_URL =
encodeURI(BODY_URL) +
'"></iframe></body>';
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
// Make sure the pointerlock warning is shown and exited with the escape key
add_task(async function show_pointerlock_warning_escape() {
let urls = [TEST_URL, FRAME_TEST_URL];
@@ -24,11 +43,7 @@ add_task(async function show_pointerlock_warning_escape() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let warning = document.getElementById("pointerlock-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
- warning,
- "true"
- );
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
let expectedWarningText;
@@ -49,11 +64,7 @@ add_task(async function show_pointerlock_warning_escape() {
ok(true, "Pointerlock warning shown");
- let warningHiddenPromise = BrowserTestUtils.waitForAttribute(
- "hidden",
- warning,
- ""
- );
+ let warningHiddenPromise = waitForWarningState(warning, "hidden");
await BrowserTestUtils.waitForCondition(
() => warning.innerText == expectedWarningText,
=====================================
js/src/gc/GC.cpp
=====================================
@@ -1331,6 +1331,11 @@ void GCRuntime::assertNoMarkingWork() const {
}
#endif
+static size_t GetGCParallelThreadCount() {
+ AutoLockHelperThreadState lock;
+ return HelperThreadState().getGCParallelThreadCount(lock);
+}
+
bool GCRuntime::updateMarkersVector() {
MOZ_ASSERT(helperThreadCount >= 1,
"There must always be at least one mark task");
@@ -1339,8 +1344,8 @@ bool GCRuntime::updateMarkersVector() {
// Limit worker count to number of GC parallel tasks that can run
// concurrently, otherwise one thread can deadlock waiting on another.
- size_t targetCount = std::min(markingWorkerCount(),
- HelperThreadState().getGCParallelThreadCount());
+ size_t targetCount =
+ std::min(markingWorkerCount(), GetGCParallelThreadCount());
if (markers.length() > targetCount) {
return markers.resize(targetCount);
=====================================
js/src/gc/ParallelMarking.cpp
=====================================
@@ -103,6 +103,10 @@ bool ParallelMarker::markOneColor(MarkColor color, SliceBudget& sliceBudget) {
{
AutoLockHelperThreadState lock;
+ // There should always be enough parallel tasks to run our marking work.
+ MOZ_RELEASE_ASSERT(HelperThreadState().getGCParallelThreadCount(lock) >=
+ workerCount());
+
for (size_t i = 0; i < workerCount(); i++) {
gc->startTask(*tasks[i], lock);
}
=====================================
js/src/vm/HelperThreadState.h
=====================================
@@ -333,9 +333,11 @@ class GlobalHelperThreadState {
GCParallelTaskList& gcParallelWorklist() { return gcParallelWorklist_; }
- size_t getGCParallelThreadCount() const { return gcParallelThreadCount; }
+ size_t getGCParallelThreadCount(const AutoLockHelperThreadState& lock) const {
+ return gcParallelThreadCount;
+ }
void setGCParallelThreadCount(size_t count,
- const AutoLockHelperThreadState&) {
+ const AutoLockHelperThreadState& lock) {
MOZ_ASSERT(count >= 1);
MOZ_ASSERT(count <= threadCount);
gcParallelThreadCount = count;
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/c847c7…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/c847c7…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][maint-12.5] Bug 31546 (fix): Remove the -linux64 suffix from geckodriver
by richard (@richard) 01 Aug '23
by richard (@richard) 01 Aug '23
01 Aug '23
richard pushed to branch maint-12.5 at The Tor Project / Applications / tor-browser-build
Commits:
ed3f291b by Pier Angelo Vendrame at 2023-08-01T16:59:15+02:00
Bug 31546 (fix): Remove the -linux64 suffix from geckodriver
We removed the -linux64 suffix from GeckoDriver, because we intend
enabling it also for other platforms than Linux-x86_64 and for more
consistency with the other artifacts.
However, I forgot to update the filename in projects/firefox/build on
my previous commit.
- - - - -
1 changed file:
- projects/firefox/build
Changes:
=====================================
projects/firefox/build
=====================================
@@ -351,7 +351,7 @@ END;
[% IF c("var/linux-x86_64") && !c("var/asan") -%]
[% c('tar', {
tar_src => [ 'geckodriver' ],
- tar_args => '-cJf ' _ dest_dir _ '/' _ c('filename') _ '/geckodriver-linux64.tar.xz',
+ tar_args => '-cJf ' _ dest_dir _ '/' _ c('filename') _ '/geckodriver.tar.xz',
}) %]
[% END %]
[% ELSIF c("var/windows") -%]
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/e…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/e…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-115.1.0esr-13.0-1] 4 commits: Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
by ma1 (@ma1) 01 Aug '23
by ma1 (@ma1) 01 Aug '23
01 Aug '23
ma1 pushed to branch tor-browser-115.1.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
a9279174 by Edgar Chen at 2023-07-31T23:49:06+02:00
Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
Fullscreen/PointerLock warnings are initialized with hidden="true", but
change to hidden="" after being shown and hidden again. I think this
started happening when we began using HTML elements instead of XUL as
they handle hidden attribute differently.
Differential Revision: https://phabricator.services.mozilla.com/D177790
- - - - -
9f2eaedb by Edgar Chen at 2023-07-31T23:49:06+02:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
- - - - -
30d19aa0 by Eitan Isaacson at 2023-07-31T23:49:07+02:00
Bug 1819160 - Map Android ids to doc/accessible id pairs. r=Jamie
Differential Revision: https://phabricator.services.mozilla.com/D179737
- - - - -
efee8978 by Jon Coppeard at 2023-07-31T23:49:07+02:00
Bug 1828024 - Require the helper thread lock in the GC helper thread count getter r=sfink
This makes us take a lock to read this state (we already lock when writing it).
Also it adds a release assert in case something goes wrong with the thread
count calculations, as a crash is preferable to the potential deadlock.
Differential Revision: https://phabricator.services.mozilla.com/D181257
- - - - -
12 changed files:
- accessible/android/SessionAccessibility.cpp
- accessible/android/SessionAccessibility.h
- accessible/ipc/DocAccessibleParent.cpp
- accessible/ipc/DocAccessibleParent.h
- accessible/ipc/moz.build
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/base/content/fullscreen-and-pointerlock.inc.xhtml
- browser/base/content/test/fullscreen/browser_fullscreen_warning.js
- dom/tests/browser/browser_pointerlock_warning.js
- js/src/gc/GC.cpp
- js/src/gc/ParallelMarking.cpp
- js/src/vm/HelperThreadState.h
Changes:
=====================================
accessible/android/SessionAccessibility.cpp
=====================================
@@ -269,12 +269,9 @@ RefPtr<SessionAccessibility> SessionAccessibility::GetInstanceFor(
return GetInstanceFor(doc->GetPresShell());
}
} else {
- DocAccessibleParent* remoteDoc = aAccessible->AsRemote()->Document();
- if (remoteDoc->mSessionAccessibility) {
- return remoteDoc->mSessionAccessibility;
- }
dom::CanonicalBrowsingContext* cbc =
- static_cast<dom::BrowserParent*>(remoteDoc->Manager())
+ static_cast<dom::BrowserParent*>(
+ aAccessible->AsRemote()->Document()->Manager())
->GetBrowsingContext()
->Top();
dom::BrowserParent* bp = cbc->GetBrowserParent();
@@ -285,10 +282,7 @@ RefPtr<SessionAccessibility> SessionAccessibility::GetInstanceFor(
if (auto element = bp->GetOwnerElement()) {
if (auto doc = element->OwnerDoc()) {
if (nsPresContext* presContext = doc->GetPresContext()) {
- RefPtr<SessionAccessibility> sessionAcc =
- GetInstanceFor(presContext->PresShell());
- remoteDoc->mSessionAccessibility = sessionAcc;
- return sessionAcc;
+ return GetInstanceFor(presContext->PresShell());
}
} else {
MOZ_ASSERT_UNREACHABLE(
@@ -684,14 +678,7 @@ void SessionAccessibility::PopulateNodeInfo(
}
Accessible* SessionAccessibility::GetAccessibleByID(int32_t aID) const {
- Accessible* accessible = mIDToAccessibleMap.Get(aID);
- if (accessible && accessible->IsLocal() &&
- accessible->AsLocal()->IsDefunct()) {
- MOZ_ASSERT_UNREACHABLE("Registered accessible is defunct!");
- return nullptr;
- }
-
- return accessible;
+ return mIDToAccessibleMap.Get(aID);
}
#ifdef DEBUG
@@ -705,6 +692,58 @@ static bool IsDetachedDoc(Accessible* aAccessible) {
}
#endif
+SessionAccessibility::IDMappingEntry::IDMappingEntry(Accessible* aAccessible)
+ : mInternalID(0) {
+ *this = aAccessible;
+}
+
+SessionAccessibility::IDMappingEntry&
+SessionAccessibility::IDMappingEntry::operator=(Accessible* aAccessible) {
+ mInternalID = aAccessible->ID();
+ MOZ_ASSERT(!(mInternalID & IS_REMOTE), "First bit is used in accessible ID!");
+ if (aAccessible->IsRemote()) {
+ mInternalID |= IS_REMOTE;
+ }
+
+ Accessible* docAcc = nsAccUtils::DocumentFor(aAccessible);
+ MOZ_ASSERT(docAcc);
+ if (docAcc) {
+ MOZ_ASSERT(docAcc->IsRemote() == aAccessible->IsRemote());
+ if (docAcc->IsRemote()) {
+ mDoc = docAcc->AsRemote()->AsDoc();
+ } else {
+ mDoc = docAcc->AsLocal();
+ }
+ }
+
+ return *this;
+}
+
+SessionAccessibility::IDMappingEntry::operator Accessible*() const {
+ if (mInternalID == 0) {
+ return static_cast<LocalAccessible*>(mDoc.get());
+ }
+
+ if (mInternalID == IS_REMOTE) {
+ return static_cast<DocAccessibleParent*>(mDoc.get());
+ }
+
+ if (mInternalID & IS_REMOTE) {
+ return static_cast<DocAccessibleParent*>(mDoc.get())
+ ->GetAccessible(mInternalID & ~IS_REMOTE);
+ }
+
+ Accessible* accessible =
+ static_cast<LocalAccessible*>(mDoc.get())
+ ->AsDoc()
+ ->GetAccessibleByUniqueID(reinterpret_cast<void*>(mInternalID));
+ // If the accessible is retrievable from the DocAccessible, it can't be
+ // defunct.
+ MOZ_ASSERT(!accessible->AsLocal()->IsDefunct());
+
+ return accessible;
+}
+
void SessionAccessibility::RegisterAccessible(Accessible* aAccessible) {
if (IPCAccessibilityActive()) {
// Don't register accessible in content process.
@@ -766,7 +805,6 @@ void SessionAccessibility::UnregisterAccessible(Accessible* aAccessible) {
}
RefPtr<SessionAccessibility> sessionAcc = GetInstanceFor(aAccessible);
- MOZ_ASSERT(sessionAcc, "Need SessionAccessibility to unregister Accessible!");
if (sessionAcc) {
Accessible* registeredAcc =
sessionAcc->mIDToAccessibleMap.Get(virtualViewID);
=====================================
accessible/android/SessionAccessibility.h
=====================================
@@ -110,10 +110,34 @@ class SessionAccessibility final
jni::NativeWeakPtr<widget::GeckoViewSupport> mWindow; // Parent only
java::SessionAccessibility::NativeProvider::GlobalRef mSessionAccessibility;
+ class IDMappingEntry {
+ public:
+ explicit IDMappingEntry(Accessible* aAccessible);
+
+ IDMappingEntry& operator=(Accessible* aAccessible);
+
+ operator Accessible*() const;
+
+ private:
+ // A strong reference to a DocAccessible or DocAccessibleParent. They don't
+ // share any useful base class except nsISupports, so we use that.
+ // When we retrieve the document from this reference we cast it to
+ // LocalAccessible in the DocAccessible case because DocAccessible has
+ // multiple inheritance paths for nsISupports.
+ RefPtr<nsISupports> mDoc;
+ // The ID of the accessible as used in the internal doc mapping.
+ // We rely on this ID being pointer derived and therefore divisible by two
+ // so we can use the first bit to mark if it is remote or not.
+ uint64_t mInternalID;
+
+ static const uintptr_t IS_REMOTE = 0x1;
+ };
+
/*
* This provides a mapping from 32 bit id to accessible objects.
*/
- nsTHashMap<nsUint32HashKey, Accessible*> mIDToAccessibleMap;
+ nsBaseHashtable<nsUint32HashKey, IDMappingEntry, Accessible*>
+ mIDToAccessibleMap;
};
} // namespace a11y
=====================================
accessible/ipc/DocAccessibleParent.cpp
=====================================
@@ -29,7 +29,6 @@
#endif
#if defined(ANDROID)
-# include "mozilla/a11y/SessionAccessibility.h"
# define ACQUIRE_ANDROID_LOCK \
MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
#else
=====================================
accessible/ipc/DocAccessibleParent.h
=====================================
@@ -29,10 +29,6 @@ class xpcAccessibleGeneric;
class DocAccessiblePlatformExtParent;
#endif
-#ifdef ANDROID
-class SessionAccessibility;
-#endif
-
/*
* These objects live in the main process and comunicate with and represent
* an accessible document in a content process.
@@ -348,10 +344,6 @@ class DocAccessibleParent : public RemoteAccessible,
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) override;
-#ifdef ANDROID
- RefPtr<SessionAccessibility> mSessionAccessibility;
-#endif
-
private:
~DocAccessibleParent();
=====================================
accessible/ipc/moz.build
=====================================
@@ -24,11 +24,6 @@ else:
LOCAL_INCLUDES += [
"/accessible/mac",
]
- elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
- LOCAL_INCLUDES += [
- "/accessible/android",
- "/widget/android",
- ]
else:
LOCAL_INCLUDES += [
"/accessible/other",
=====================================
browser/base/content/browser-fullScreenAndPointerLock.js
=====================================
@@ -62,9 +62,14 @@ var PointerlockFsWarning = {
this._element = document.getElementById(elementId);
// Setup event listeners
this._element.addEventListener("transitionend", this);
+ this._element.addEventListener("transitioncancel", this);
window.addEventListener("mousemove", this, true);
+ window.addEventListener("activate", this);
+ window.addEventListener("deactivate", this);
// The timeout to hide the warning box after a while.
this._timeoutHide = new this.Timeout(() => {
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
this._state = "hidden";
}, timeout);
// The timeout to show the warning box when the pointer is at the top
@@ -116,11 +121,10 @@ var PointerlockFsWarning = {
return;
}
- // Explicitly set the last state to hidden to avoid the warning
- // box being hidden immediately because of mousemove.
- this._state = "onscreen";
- this._lastState = "hidden";
- this._timeoutHide.start();
+ if (Services.focus.activeWindow == window) {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ }
},
/**
@@ -148,7 +152,10 @@ var PointerlockFsWarning = {
this._element.hidden = true;
// Remove all event listeners
this._element.removeEventListener("transitionend", this);
+ this._element.removeEventListener("transitioncancel", this);
window.removeEventListener("mousemove", this, true);
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
// Clear fields
this._element = null;
this._timeoutHide = null;
@@ -186,7 +193,7 @@ var PointerlockFsWarning = {
}
if (newState != "hidden") {
if (currentState != "hidden") {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
} else {
// When the previous state is hidden, the display was none,
// thus no box was constructed. We need to wait for the new
@@ -197,7 +204,7 @@ var PointerlockFsWarning = {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (this._element) {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
}
});
});
@@ -217,7 +224,7 @@ var PointerlockFsWarning = {
} else if (this._timeoutShow.delay >= 0) {
this._timeoutShow.start();
}
- } else {
+ } else if (state != "onscreen") {
let elemRect = this._element.getBoundingClientRect();
if (state == "hiding" && this._lastState != "hidden") {
// If we are on the hiding transition, and the pointer
@@ -239,12 +246,23 @@ var PointerlockFsWarning = {
}
break;
}
- case "transitionend": {
+ case "transitionend":
+ case "transitioncancel": {
if (this._state == "hiding") {
this._element.hidden = true;
}
break;
}
+ case "activate": {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ break;
+ }
+ case "deactivate": {
+ this._state = "hidden";
+ this._timeoutHide.cancel();
+ break;
+ }
}
},
};
=====================================
browser/base/content/fullscreen-and-pointerlock.inc.xhtml
=====================================
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<html:div id="fullscreen-and-pointerlock-wrapper">
- <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
@@ -20,7 +20,7 @@
</html:button>
</html:div>
- <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
=====================================
browser/base/content/test/fullscreen/browser_fullscreen_warning.js
=====================================
@@ -3,14 +3,35 @@
"use strict";
-add_task(async function test_fullscreen_display_none() {
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
+add_setup(async function init() {
await SpecialPowers.pushPrefEnv({
set: [
["full-screen-api.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
],
});
+});
+add_task(async function test_fullscreen_display_none() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
@@ -30,11 +51,13 @@ add_task(async function test_fullscreen_display_none() {
},
async function (browser) {
let warning = document.getElementById("fullscreen-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
warning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
);
+
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
// Enter fullscreen
await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
@@ -54,39 +77,33 @@ add_task(async function test_fullscreen_display_none() {
);
document.getElementById("fullscreen-exit-button").click();
await exitFullscreenPromise;
+
+ checkWarningState(
+ warning,
+ "hidden",
+ "Should hide fullscreen warning after exiting fullscreen"
+ );
}
);
});
add_task(async function test_fullscreen_pointerlock_conflict() {
- await SpecialPowers.pushPrefEnv({
- set: [
- ["full-screen-api.enabled", true],
- ["full-screen-api.allow-trusted-requests-only", false],
- ],
- });
-
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let fsWarning = document.getElementById("fullscreen-warning");
let plWarning = document.getElementById("pointerlock-warning");
- is(
- fsWarning.getAttribute("onscreen"),
- null,
- "Should not show full screen warning initially."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning initially."
- );
-
- let fsWarningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
fsWarning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
+ );
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning initially"
);
+ let fsWarningShownPromise = waitForWarningState(fsWarning, "onscreen");
info("Entering full screen and pointer lock.");
await SpecialPowers.spawn(browser, [], async () => {
await content.document.body.requestFullscreen();
@@ -94,15 +111,10 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
});
await fsWarningShownPromise;
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should show full screen warning."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
info("Exiting pointerlock");
@@ -110,18 +122,19 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
await content.document.exitPointerLock();
});
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should still show full screen warning."
+ checkWarningState(
+ fsWarning,
+ "onscreen",
+ "Should still show full screen warning"
);
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
// Cleanup
+ info("Exiting fullscreen");
await document.exitFullscreen();
});
});
=====================================
dom/tests/browser/browser_pointerlock_warning.js
=====================================
@@ -15,6 +15,25 @@ const FRAME_TEST_URL =
encodeURI(BODY_URL) +
'"></iframe></body>';
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
// Make sure the pointerlock warning is shown and exited with the escape key
add_task(async function show_pointerlock_warning_escape() {
let urls = [TEST_URL, FRAME_TEST_URL];
@@ -24,11 +43,7 @@ add_task(async function show_pointerlock_warning_escape() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let warning = document.getElementById("pointerlock-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
- warning,
- "true"
- );
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
let expectedWarningText;
@@ -49,11 +64,7 @@ add_task(async function show_pointerlock_warning_escape() {
ok(true, "Pointerlock warning shown");
- let warningHiddenPromise = BrowserTestUtils.waitForAttribute(
- "hidden",
- warning,
- ""
- );
+ let warningHiddenPromise = waitForWarningState(warning, "hidden");
await BrowserTestUtils.waitForCondition(
() => warning.innerText == expectedWarningText,
=====================================
js/src/gc/GC.cpp
=====================================
@@ -1331,6 +1331,11 @@ void GCRuntime::assertNoMarkingWork() const {
}
#endif
+static size_t GetGCParallelThreadCount() {
+ AutoLockHelperThreadState lock;
+ return HelperThreadState().getGCParallelThreadCount(lock);
+}
+
bool GCRuntime::updateMarkersVector() {
MOZ_ASSERT(helperThreadCount >= 1,
"There must always be at least one mark task");
@@ -1339,8 +1344,8 @@ bool GCRuntime::updateMarkersVector() {
// Limit worker count to number of GC parallel tasks that can run
// concurrently, otherwise one thread can deadlock waiting on another.
- size_t targetCount = std::min(markingWorkerCount(),
- HelperThreadState().getGCParallelThreadCount());
+ size_t targetCount =
+ std::min(markingWorkerCount(), GetGCParallelThreadCount());
if (markers.length() > targetCount) {
return markers.resize(targetCount);
=====================================
js/src/gc/ParallelMarking.cpp
=====================================
@@ -103,6 +103,10 @@ bool ParallelMarker::markOneColor(MarkColor color, SliceBudget& sliceBudget) {
{
AutoLockHelperThreadState lock;
+ // There should always be enough parallel tasks to run our marking work.
+ MOZ_RELEASE_ASSERT(HelperThreadState().getGCParallelThreadCount(lock) >=
+ workerCount());
+
for (size_t i = 0; i < workerCount(); i++) {
gc->startTask(*tasks[i], lock);
}
=====================================
js/src/vm/HelperThreadState.h
=====================================
@@ -333,9 +333,11 @@ class GlobalHelperThreadState {
GCParallelTaskList& gcParallelWorklist() { return gcParallelWorklist_; }
- size_t getGCParallelThreadCount() const { return gcParallelThreadCount; }
+ size_t getGCParallelThreadCount(const AutoLockHelperThreadState& lock) const {
+ return gcParallelThreadCount;
+ }
void setGCParallelThreadCount(size_t count,
- const AutoLockHelperThreadState&) {
+ const AutoLockHelperThreadState& lock) {
MOZ_ASSERT(count >= 1);
MOZ_ASSERT(count <= threadCount);
gcParallelThreadCount = count;
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/c4e8cd…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/c4e8cd…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][main] Bug 40905: Avoid replacing .*browser-testbuild targets
by boklm (@boklm) 01 Aug '23
by boklm (@boklm) 01 Aug '23
01 Aug '23
boklm pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
d8fe33ad by Nicolas Vigier at 2023-08-01T10:53:55+02:00
Bug 40905: Avoid replacing .*browser-testbuild targets
In some places we use target_replace to replace .*browser-.* targets, in
order to replace the torbrowser-$os-$arch targets. However the regexp we
used would also replace the torbrowser-testbuild target, so we need to
update the regexp to exclude the testbuild target.
- - - - -
7 changed files:
- projects/conjure/config
- projects/go/config
- projects/lyrebird/config
- projects/snowflake/config
- projects/tor-android-service/config
- projects/tor-onion-proxy-library/config
- projects/webtunnel/config
Changes:
=====================================
projects/conjure/config
=====================================
@@ -21,4 +21,4 @@ steps:
norec:
sha256sum: 2b403d6edf075777003bf2194a43fb178a28a4eaa7d23ec8f104563d9bbd7e53
target_replace:
- '^torbrowser-.*': 'torbrowser-linux-x86_64'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-linux-x86_64'
=====================================
projects/go/config
=====================================
@@ -123,6 +123,6 @@ input_files:
- project: go-bootstrap
name: go-bootstrap
target_replace:
- '^.*browser-.*': 'basebrowser-linux-x86_64'
+ '^.*browser-(?!testbuild).*': 'basebrowser-linux-x86_64'
- filename: 0001-Use-fixed-go-build-tmp-directory.patch
enable: '[% c("var/android") %]'
=====================================
projects/lyrebird/config
=====================================
@@ -35,4 +35,4 @@ steps:
norec:
sha256sum: '[% c("var/go_vendor_sha256sum") %]'
target_replace:
- '^torbrowser-.*': 'torbrowser-linux-x86_64'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-linux-x86_64'
=====================================
projects/snowflake/config
=====================================
@@ -22,4 +22,4 @@ steps:
norec:
sha256sum: 62f9065881f5a3cbe5ea5a9802e961e1821d9e468cb2a85ebab1e8afcc0cc953
target_replace:
- '^torbrowser-.*': 'torbrowser-linux-x86_64'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-linux-x86_64'
=====================================
projects/tor-android-service/config
=====================================
@@ -26,19 +26,19 @@ input_files:
- project: tor-expert-bundle
name: tor-expert-bundle-armv7
target_replace:
- '^torbrowser-.*': 'torbrowser-android-armv7'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-android-armv7'
- project: tor-expert-bundle
name: tor-expert-bundle-aarch64
target_replace:
- '^torbrowser-.*': 'torbrowser-android-aarch64'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-android-aarch64'
- project: tor-expert-bundle
name: tor-expert-bundle-x86
target_replace:
- '^torbrowser-.*': 'torbrowser-android-x86'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-android-x86'
- project: tor-expert-bundle
name: tor-expert-bundle-x86_64
target_replace:
- '^torbrowser-.*': 'torbrowser-android-x86_64'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-android-x86_64'
- URL: 'https://dl.google.com/dl/android/studio/jetifier-zips/1.0.0-beta10/jetifier…'
name: jetifier
sha256sum: 38186db9c9d1b745890b3d35c0667da1cac146ceb3c26aae5bf0802119472c1b
=====================================
projects/tor-onion-proxy-library/config
=====================================
@@ -21,19 +21,19 @@ input_files:
- project: tor-expert-bundle
name: tor-expert-bundle-armv7
target_replace:
- '^torbrowser-.*': 'torbrowser-android-armv7'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-android-armv7'
- project: tor-expert-bundle
name: tor-expert-bundle-aarch64
target_replace:
- '^torbrowser-.*': 'torbrowser-android-aarch64'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-android-aarch64'
- project: tor-expert-bundle
name: tor-expert-bundle-x86
target_replace:
- '^torbrowser-.*': 'torbrowser-android-x86'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-android-x86'
- project: tor-expert-bundle
name: tor-expert-bundle-x86_64
target_replace:
- '^torbrowser-.*': 'torbrowser-android-x86_64'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-android-x86_64'
- filename: 'gradle-dependencies-[% c("var/gradle_dependencies_version") %]'
name: gradle-dependencies
exec: '[% INCLUDE "fetch-gradle-dependencies" %]'
=====================================
projects/webtunnel/config
=====================================
@@ -21,4 +21,4 @@ steps:
norec:
sha256sum: e3b5a9b3c3939aafa5389246f3a7a7e78d70fe623bed495f99c39cc37bbbe645
target_replace:
- '^torbrowser-.*': 'torbrowser-linux-x86_64'
+ '^torbrowser-(?!testbuild).*': 'torbrowser-linux-x86_64'
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/d…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/d…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][main] Bug 40615: Add a README for the bundled font directory.
by Pier Angelo Vendrame (@pierov) 01 Aug '23
by Pier Angelo Vendrame (@pierov) 01 Aug '23
01 Aug '23
Pier Angelo Vendrame pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
571d86aa by FlexFoot at 2023-08-01T08:47:20+00:00
Bug 40615: Add a README for the bundled font directory.
Include a README in the final fonts directory to discourage users from
modifying the bundled fonts and to warn them about the consequences
this could have.
- - - - -
3 changed files:
- + projects/fonts/README.txt
- projects/fonts/build
- projects/fonts/config
Changes:
=====================================
projects/fonts/README.txt
=====================================
@@ -0,0 +1,7 @@
+DO NOT MODIFY THE CONTENTS OF THIS DIRECTORY
+
+Any adjustment to bundled fonts will result in an altered fingerprint. Font
+fingerprinting is more than just detecting what fonts you have, it also includes
+font fallbacks and characters (unicode code points) and any change in those can
+be measured.
+
=====================================
projects/fonts/build
=====================================
@@ -32,6 +32,7 @@ mv noto-fonts-* noto-fonts
[% IF c("var/linux") %]
cp {NotoSansJP-Regular.otf,NotoSansKR-Regular.otf,NotoSansSC-Regular.otf,NotoSansTC-Regular.otf} $distdir/
[% END %]
+cp README.txt "$distdir/000_README.txt"
cd /var/tmp/dist
[% c('tar', {
tar_src => [ 'fonts' ],
=====================================
projects/fonts/config
=====================================
@@ -161,6 +161,7 @@ var:
input_files:
- project: container-image
+ - filename: README.txt
- filename: 'noto-fonts-[% c("var/noto_git_hash") %]-[% c("version") %]'
name: noto-fonts
exec: '[% INCLUDE "fetch-noto-fonts" %]'
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/5…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/5…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][maint-12.5] Bug 31546: Copy Firefox PDBs for Windows
by richard (@richard) 31 Jul '23
by richard (@richard) 31 Jul '23
31 Jul '23
richard pushed to branch maint-12.5 at The Tor Project / Applications / tor-browser-build
Commits:
3ba21986 by Pier Angelo Vendrame at 2023-07-31T20:37:13+00:00
Bug 31546: Copy Firefox PDBs for Windows
Also copy debug symbols after stripping on Linux 32-bit (we only copied
them in Linux 64-bit) and for all our browsers (previously we copied
them only for Tor Browser).
Include the headers directory with the symbols, because some of them
are generated during the build, but they are needed for debugging.
- - - - -
2 changed files:
- projects/browser/build
- projects/firefox/build
Changes:
=====================================
projects/browser/build
=====================================
@@ -397,13 +397,13 @@ SCRIPT_EOF
[% IF c("var/updater_enabled") -%]
cp $rootdir/[% c('input_files_by_name/firefox') %]/mar-tools-*.zip "$OUTDIR"/
[% END -%]
-[% IF c("var/linux-x86_64") -%]
- [% IF c("var/tor-browser") -%]
- cp $rootdir/[% c('input_files_by_name/firefox') %]/browser-debug.tar.xz "$OUTDIR"/[% c("var/project-name") %]-[% c("var/mar_osname") %]-debug.tar.xz
- [% END -%]
- [% IF !c("var/asan") -%]
- cp $rootdir/[% c('input_files_by_name/firefox') %]/geckodriver-linux64.tar.xz "$OUTDIR"/
+[% IF c("var/linux") -%]
+ cp $rootdir/[% c('input_files_by_name/firefox') %]/browser-debug.tar.xz "$OUTDIR/[% c('var/project-name') %]-[% c('var/mar_osname') %]-debug.tar.xz"
+ [% IF c("var/linux-x86_64") && !c("var/asan") -%]
+ cp $rootdir/[% c('input_files_by_name/firefox') %]/geckodriver.tar.xz "$OUTDIR/geckodriver-[% c('var/mar_osname') %].tar.xz"
[% END -%]
+[% ELSIF c("var/windows") -%]
+ cp $rootdir/[% c('input_files_by_name/firefox') %]/browser-debug.zip "$OUTDIR/[% c('var/project-name') %]-[% c('var/mar_osname') %]-debug.zip"
[% END -%]
[%IF c("var/tor-browser") -%]
tor_expert_bundle_src="[% c("input_files_by_name/tor-expert-bundle") %]"
=====================================
projects/firefox/build
=====================================
@@ -211,6 +211,10 @@ export LANG=C.UTF-8
cp obj-*/testing/geckodriver/x86_64-unknown-linux-gnu/release/geckodriver $distdir
[% END %]
cp -a obj-*/dist/[% c('var/exe_name') %]/* $distdir/Browser/
+ mkdir -p $distdir/Debug
+ # Some include files are symlinks, so use -Lr, or the tarball will fail
+ # silently. Also, on Linux we populate the debug symbols by stripping later.
+ cp -Lr obj-*/dist/include $distdir/Debug/
# Remove firefox-bin (we don't use it, see ticket #10126)
rm -f "$distdir/Browser/[% c('var/exe_name') %]-bin"
# TODO: There goes FIPS-140.. We could upload these somewhere unique and
@@ -232,6 +236,11 @@ RBM_TB_EOF
[% ELSE %]
cp -a /var/tmp/dist/fxc2/bin/d3dcompiler_47.dll $distdir/Browser
[% END %]
+ mkdir -p $distdir/Debug/Browser
+ pushd obj-*
+ cp -Lr dist/include $distdir/Debug/
+ find . \( -path ./dist -o -path ./_tests \) -prune -o -name '*.pdb' -exec cp -l {} $distdir/Debug/Browser/ \;
+ popd
[% END %]
[% IF c("var/updater_enabled") -%]
@@ -279,8 +288,8 @@ RBM_TB_EOF
cd $distdir
-[% IF c("var/linux-x86_64") %]
- [% IF !c("var/asan") %]
+[% IF c("var/linux") -%]
+ [% IF c("var/linux-x86_64") && !c("var/asan") -%]
# No need for an unstripped geckodriver
strip geckodriver
[% END %]
@@ -334,17 +343,22 @@ END;
tar_args => '-czf ' _ dest_dir _ '/' _ c('filename') _ '/browser.tar.gz',
}) %]
-[% IF c("var/linux-x86_64") %]
+[% IF c("var/linux") -%]
[% c('tar', {
tar_src => [ 'Debug' ],
tar_args => '-cJf ' _ dest_dir _ '/' _ c('filename') _ '/browser-debug.tar.xz',
}) %]
- [% IF !c("var/asan") %]
+ [% IF c("var/linux-x86_64") && !c("var/asan") -%]
[% c('tar', {
tar_src => [ 'geckodriver' ],
tar_args => '-cJf ' _ dest_dir _ '/' _ c('filename') _ '/geckodriver-linux64.tar.xz',
}) %]
[% END %]
+[% ELSIF c("var/windows") -%]
+ [% c('zip', {
+ zip_src => [ 'Debug' ],
+ zip_args => dest_dir _ '/' _ c('filename') _ '/browser-debug.zip',
+ }) %]
[% END %]
[% IF c("var/updater_enabled") -%]
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/3…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/3…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][maint-12.5] Bug 40909: Add dan_b and ma1 to list of taggers in relevant projects
by richard (@richard) 31 Jul '23
by richard (@richard) 31 Jul '23
31 Jul '23
richard pushed to branch maint-12.5 at The Tor Project / Applications / tor-browser-build
Commits:
5f27b741 by Richard Pospesel at 2023-07-31T19:23:09+00:00
Bug 40909: Add dan_b and ma1 to list of taggers in relevant projects
- - - - -
4 changed files:
- projects/android-components/config
- projects/fenix/config
- projects/firefox/config
- projects/geckoview/config
Changes:
=====================================
projects/android-components/config
=====================================
@@ -5,6 +5,8 @@ git_hash: '[% project %]-[% c("var/android_components_version") %]-[% c("var/bro
git_url: https://gitlab.torproject.org/tpo/applications/android-components.git
tag_gpg_id: 1
gpg_keyring:
+ - dan_b.gpg
+ - ma1.gpg
- pierov.gpg
- richard.gpg
variant: '[% IF c("var/release") %]Release[% ELSE %]Beta[% END %]'
=====================================
projects/fenix/config
=====================================
@@ -5,6 +5,8 @@ git_hash: 'tor-browser-[% c("var/fenix_version") %]-[% c("var/browser_branch") %
git_url: https://gitlab.torproject.org/tpo/applications/fenix.git
tag_gpg_id: 1
gpg_keyring:
+ - dan_b.gpg
+ - ma1.gpg
- pierov.gpg
- richard.gpg
variant: Beta
=====================================
projects/firefox/config
=====================================
@@ -5,6 +5,8 @@ git_hash: '[% c("var/project-name") %]-[% c("var/firefox_version") %]-[% c("var/
tag_gpg_id: 1
git_url: https://gitlab.torproject.org/tpo/applications/tor-browser.git
gpg_keyring:
+ - dan_b.gpg
+ - ma1.gpg
- pierov.gpg
- richard.gpg
container:
=====================================
projects/geckoview/config
=====================================
@@ -5,6 +5,8 @@ git_hash: 'tor-browser-[% c("var/geckoview_version") %]-[% c("var/browser_branch
tag_gpg_id: 1
git_url: https://gitlab.torproject.org/tpo/applications/tor-browser.git
gpg_keyring:
+ - dan_b.gpg
+ - ma1.gpg
- pierov.gpg
- richard.gpg
container:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/5…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/5…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][main] Bug 40909: Add dan_b and ma1 to list of taggers in relevant projects
by richard (@richard) 31 Jul '23
by richard (@richard) 31 Jul '23
31 Jul '23
richard pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
13122472 by Richard Pospesel at 2023-07-31T19:19:03+00:00
Bug 40909: Add dan_b and ma1 to list of taggers in relevant projects
- - - - -
4 changed files:
- projects/android-components/config
- projects/fenix/config
- projects/firefox/config
- projects/geckoview/config
Changes:
=====================================
projects/android-components/config
=====================================
@@ -5,6 +5,8 @@ git_hash: '[% project %]-[% c("var/android_components_version") %]-[% c("var/bro
git_url: https://gitlab.torproject.org/tpo/applications/android-components.git
tag_gpg_id: 1
gpg_keyring:
+ - dan_b.gpg
+ - ma1.gpg
- pierov.gpg
- richard.gpg
variant: '[% IF c("var/release") %]Release[% ELSE %]Beta[% END %]'
=====================================
projects/fenix/config
=====================================
@@ -5,6 +5,8 @@ git_hash: 'tor-browser-[% c("var/fenix_version") %]-[% c("var/browser_branch") %
git_url: https://gitlab.torproject.org/tpo/applications/fenix.git
tag_gpg_id: 1
gpg_keyring:
+ - dan_b.gpg
+ - ma1.gpg
- pierov.gpg
- richard.gpg
variant: Beta
=====================================
projects/firefox/config
=====================================
@@ -5,6 +5,8 @@ git_hash: '[% c("var/project-name") %]-[% c("var/firefox_version") %]-[% c("var/
tag_gpg_id: 1
git_url: https://gitlab.torproject.org/tpo/applications/tor-browser.git
gpg_keyring:
+ - dan_b.gpg
+ - ma1.gpg
- pierov.gpg
- richard.gpg
container:
=====================================
projects/geckoview/config
=====================================
@@ -5,6 +5,8 @@ git_hash: 'tor-browser-[% c("var/geckoview_version") %]-[% c("var/browser_branch
tag_gpg_id: 1
git_url: https://gitlab.torproject.org/tpo/applications/tor-browser.git
gpg_keyring:
+ - dan_b.gpg
+ - ma1.gpg
- pierov.gpg
- richard.gpg
container:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/1…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/1…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser] Pushed new tag base-browser-102.14.0esr-12.5-1-build2
by ma1 (@ma1) 31 Jul '23
by ma1 (@ma1) 31 Jul '23
31 Jul '23
ma1 pushed new tag base-browser-102.14.0esr-12.5-1-build2 at The Tor Project / Applications / Tor Browser
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/tree/base-brow…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][base-browser-102.14.0esr-12.5-1] 2 commits: Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
by ma1 (@ma1) 31 Jul '23
by ma1 (@ma1) 31 Jul '23
31 Jul '23
ma1 pushed to branch base-browser-102.14.0esr-12.5-1 at The Tor Project / Applications / Tor Browser
Commits:
f24d6cd4 by Edgar Chen at 2023-07-31T21:15:57+02:00
Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
Fullscreen/PointerLock warnings are initialized with hidden="true", but
change to hidden="" after being shown and hidden again. I think this
started happening when we began using HTML elements instead of XUL as
they handle hidden attribute differently.
Differential Revision: https://phabricator.services.mozilla.com/D177790
- - - - -
53142727 by Edgar Chen at 2023-07-31T21:16:28+02:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
- - - - -
4 changed files:
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/base/content/fullscreen-and-pointerlock.inc.xhtml
- browser/base/content/test/fullscreen/browser_fullscreen_warning.js
- dom/tests/browser/browser_pointerlock_warning.js
Changes:
=====================================
browser/base/content/browser-fullScreenAndPointerLock.js
=====================================
@@ -62,9 +62,14 @@ var PointerlockFsWarning = {
this._element = document.getElementById(elementId);
// Setup event listeners
this._element.addEventListener("transitionend", this);
+ this._element.addEventListener("transitioncancel", this);
window.addEventListener("mousemove", this, true);
+ window.addEventListener("activate", this);
+ window.addEventListener("deactivate", this);
// The timeout to hide the warning box after a while.
this._timeoutHide = new this.Timeout(() => {
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
this._state = "hidden";
}, timeout);
// The timeout to show the warning box when the pointer is at the top
@@ -116,11 +121,10 @@ var PointerlockFsWarning = {
return;
}
- // Explicitly set the last state to hidden to avoid the warning
- // box being hidden immediately because of mousemove.
- this._state = "onscreen";
- this._lastState = "hidden";
- this._timeoutHide.start();
+ if (Services.focus.activeWindow == window) {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ }
},
/**
@@ -148,7 +152,10 @@ var PointerlockFsWarning = {
this._element.hidden = true;
// Remove all event listeners
this._element.removeEventListener("transitionend", this);
+ this._element.removeEventListener("transitioncancel", this);
window.removeEventListener("mousemove", this, true);
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
// Clear fields
this._element = null;
this._timeoutHide = null;
@@ -186,7 +193,7 @@ var PointerlockFsWarning = {
}
if (newState != "hidden") {
if (currentState != "hidden") {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
} else {
// When the previous state is hidden, the display was none,
// thus no box was constructed. We need to wait for the new
@@ -197,7 +204,7 @@ var PointerlockFsWarning = {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (this._element) {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
}
});
});
@@ -217,7 +224,7 @@ var PointerlockFsWarning = {
} else if (this._timeoutShow.delay >= 0) {
this._timeoutShow.start();
}
- } else {
+ } else if (state != "onscreen") {
let elemRect = this._element.getBoundingClientRect();
if (state == "hiding" && this._lastState != "hidden") {
// If we are on the hiding transition, and the pointer
@@ -239,12 +246,23 @@ var PointerlockFsWarning = {
}
break;
}
- case "transitionend": {
+ case "transitionend":
+ case "transitioncancel": {
if (this._state == "hiding") {
this._element.hidden = true;
}
break;
}
+ case "activate": {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ break;
+ }
+ case "deactivate": {
+ this._state = "hidden";
+ this._timeoutHide.cancel();
+ break;
+ }
}
},
};
=====================================
browser/base/content/fullscreen-and-pointerlock.inc.xhtml
=====================================
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<html:div id="fullscreen-and-pointerlock-wrapper">
- <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
@@ -20,7 +20,7 @@
</html:button>
</html:div>
- <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
=====================================
browser/base/content/test/fullscreen/browser_fullscreen_warning.js
=====================================
@@ -3,14 +3,35 @@
"use strict";
-add_task(async function test_fullscreen_display_none() {
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
+add_setup(async function init() {
await SpecialPowers.pushPrefEnv({
set: [
["full-screen-api.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
],
});
+});
+add_task(async function test_fullscreen_display_none() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
@@ -30,11 +51,13 @@ add_task(async function test_fullscreen_display_none() {
},
async function(browser) {
let warning = document.getElementById("fullscreen-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
warning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
);
+
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
// Enter fullscreen
await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
@@ -54,39 +77,33 @@ add_task(async function test_fullscreen_display_none() {
);
document.getElementById("fullscreen-exit-button").click();
await exitFullscreenPromise;
+
+ checkWarningState(
+ warning,
+ "hidden",
+ "Should hide fullscreen warning after exiting fullscreen"
+ );
}
);
});
add_task(async function test_fullscreen_pointerlock_conflict() {
- await SpecialPowers.pushPrefEnv({
- set: [
- ["full-screen-api.enabled", true],
- ["full-screen-api.allow-trusted-requests-only", false],
- ],
- });
-
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let fsWarning = document.getElementById("fullscreen-warning");
let plWarning = document.getElementById("pointerlock-warning");
- is(
- fsWarning.getAttribute("onscreen"),
- null,
- "Should not show full screen warning initially."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning initially."
- );
-
- let fsWarningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
fsWarning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
+ );
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning initially"
);
+ let fsWarningShownPromise = waitForWarningState(fsWarning, "onscreen");
info("Entering full screen and pointer lock.");
await SpecialPowers.spawn(browser, [], async () => {
await content.document.body.requestFullscreen();
@@ -94,15 +111,10 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
});
await fsWarningShownPromise;
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should show full screen warning."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
info("Exiting pointerlock");
@@ -110,18 +122,19 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
await content.document.exitPointerLock();
});
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should still show full screen warning."
+ checkWarningState(
+ fsWarning,
+ "onscreen",
+ "Should still show full screen warning"
);
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
// Cleanup
+ info("Exiting fullscreen");
await document.exitFullscreen();
});
});
=====================================
dom/tests/browser/browser_pointerlock_warning.js
=====================================
@@ -15,6 +15,25 @@ const FRAME_TEST_URL =
encodeURI(BODY_URL) +
'"></iframe></body>';
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
// Make sure the pointerlock warning is shown and exited with the escape key
add_task(async function show_pointerlock_warning_escape() {
let urls = [TEST_URL, FRAME_TEST_URL];
@@ -24,11 +43,7 @@ add_task(async function show_pointerlock_warning_escape() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let warning = document.getElementById("pointerlock-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
- warning,
- "true"
- );
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
let expectedWarningText;
@@ -49,11 +64,7 @@ add_task(async function show_pointerlock_warning_escape() {
ok(true, "Pointerlock warning shown");
- let warningHiddenPromise = BrowserTestUtils.waitForAttribute(
- "hidden",
- warning,
- ""
- );
+ let warningHiddenPromise = waitForWarningState(warning, "hidden");
await BrowserTestUtils.waitForCondition(
() => warning.innerText == expectedWarningText,
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/fadc59…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/fadc59…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser] Pushed new tag tor-browser-102.14.0esr-12.5-1-build2
by ma1 (@ma1) 31 Jul '23
by ma1 (@ma1) 31 Jul '23
31 Jul '23
ma1 pushed new tag tor-browser-102.14.0esr-12.5-1-build2 at The Tor Project / Applications / Tor Browser
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/tree/tor-brows…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-115.1.0esr-13.0-1] 9 commits: fixup! Add TorStrings module for localization
by Pier Angelo Vendrame (@pierov) 31 Jul '23
by Pier Angelo Vendrame (@pierov) 31 Jul '23
31 Jul '23
Pier Angelo Vendrame pushed to branch tor-browser-115.1.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
c3d2496b by Pier Angelo Vendrame at 2023-07-27T21:07:52+02:00
fixup! Add TorStrings module for localization
Move the `getLocale` function here from TorButton util.js and stop
importing it.
- - - - -
642df684 by Pier Angelo Vendrame at 2023-07-27T21:07:53+02:00
fixup! Bug 40933: Add tor-launcher functionality
Fix a couple of problems in TorLauncherUtil and TorParsers.
Also, moved the function to parse bridges in TorParsers.
- - - - -
9e825b61 by Pier Angelo Vendrame at 2023-07-27T21:07:53+02:00
fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
Use the bridge line parser from TorParsers.
- - - - -
8061f810 by Pier Angelo Vendrame at 2023-07-27T21:07:53+02:00
fixup! Bug 40933: Add tor-launcher functionality
Use actual private members for TorProcess.
- - - - -
f5a3f4af by Pier Angelo Vendrame at 2023-07-27T21:07:54+02:00
fixup! Bug 40933: Add tor-launcher functionality
Group arg pushes in one line (keys and values together).
- - - - -
71b08c4e by Pier Angelo Vendrame at 2023-07-27T21:07:54+02:00
fixup! Bug 40933: Add tor-launcher functionality
TorProcess: use real private properties instead of _, and removed the
dependency on TorProtocolService (temporarily moved it to
TorMonitorService, but eventually we should unify TorProtocolService
and TorMonitorService, to then split them again in a smarter way).
- - - - -
e1a69b4e by Pier Angelo Vendrame at 2023-07-27T21:07:55+02:00
fixup! Bug 10760: Integrate TorButton to TorBrowser core
Move the SOCKS preference updater to TorProtocolService.
We will need to refactor all this kind of stuff, but at least let's get
it in a single place.
Also, since this was the last bit of the startup service, remove the
file, the component and what else was needed to add them.
- - - - -
d457b6f8 by Pier Angelo Vendrame at 2023-07-31T20:42:54+02:00
fixup! Bug 40933: Add tor-launcher functionality
Hashing the control port password is needed only on the process, so move
this function to TorProcess.
- - - - -
c4e8cd0f by Pier Angelo Vendrame at 2023-07-31T20:42:57+02:00
fixup! Bug 10760: Integrate TorButton to TorBrowser core
The hashpassword parameter has been removed.
- - - - -
13 changed files:
- browser/components/torpreferences/content/connectionPane.js
- browser/installer/package-manifest.in
- browser/modules/TorStrings.jsm
- toolkit/components/tor-launcher/TorLauncherUtil.sys.mjs
- toolkit/components/tor-launcher/TorMonitorService.sys.mjs
- toolkit/components/tor-launcher/TorParsers.sys.mjs
- toolkit/components/tor-launcher/TorProcess.sys.mjs
- toolkit/components/tor-launcher/TorProtocolService.sys.mjs
- toolkit/torbutton/chrome/content/torbutton.js
- toolkit/torbutton/components.conf
- − toolkit/torbutton/modules/TorbuttonStartupObserver.jsm
- toolkit/torbutton/moz.build
- − toolkit/torbutton/torbutton.manifest
Changes:
=====================================
browser/components/torpreferences/content/connectionPane.js
=====================================
@@ -14,8 +14,11 @@ const { setTimeout, clearTimeout } = ChromeUtils.import(
const { TorSettings, TorSettingsTopics, TorSettingsData, TorBridgeSource } =
ChromeUtils.import("resource:///modules/TorSettings.jsm");
-const { TorProtocolService } = ChromeUtils.import(
- "resource://gre/modules/TorProtocolService.jsm"
+const { TorParsers } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorParsers.sys.mjs"
+);
+const { TorProtocolService } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorProtocolService.sys.mjs"
);
const { TorMonitorService, TorMonitorTopics } = ChromeUtils.import(
"resource://gre/modules/TorMonitorService.jsm"
@@ -495,7 +498,7 @@ const gConnectionPane = (function () {
});
const idString = TorStrings.settings.bridgeId;
const id = card.querySelector(selectors.bridges.cardId);
- const details = parseBridgeLine(bridgeString);
+ const details = TorParsers.parseBridgeLine(bridgeString);
if (details && details.id !== undefined) {
card.setAttribute("data-bridge-id", details.id);
}
@@ -1111,23 +1114,3 @@ function makeBridgeId(bridgeString) {
hash & 0x000000ff,
];
}
-
-function parseBridgeLine(line) {
- const re =
- /^\s*(\S+\s+)?([0-9a-fA-F\.\[\]\:]+:\d{1,5})(\s+[0-9a-fA-F]{40})?(\s+.+)?/;
- const matches = line.match(re);
- if (!matches) {
- return null;
- }
- let bridge = { addr: matches[2] };
- if (matches[1] !== undefined) {
- bridge.transport = matches[1].trim();
- }
- if (matches[3] !== undefined) {
- bridge.id = matches[3].trim().toUpperCase();
- }
- if (matches[4] !== undefined) {
- bridge.args = matches[4].trim();
- }
- return bridge;
-}
=====================================
browser/installer/package-manifest.in
=====================================
@@ -228,7 +228,6 @@
@RESPATH@/components/tor-launcher.manifest
@RESPATH@/chrome/torbutton.manifest
@RESPATH@/chrome/torbutton/*
-@RESPATH@/components/torbutton.manifest
@RESPATH@/chrome/toolkit@JAREXT@
@RESPATH@/chrome/toolkit.manifest
#ifdef MOZ_GTK
=====================================
browser/modules/TorStrings.jsm
=====================================
@@ -11,9 +11,11 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
-const { getLocale } = ChromeUtils.import(
- "resource://torbutton/modules/utils.js"
-);
+
+function getLocale() {
+ const locale = Services.locale.appLocaleAsBCP47;
+ return locale === "ja-JP-macos" ? "ja" : locale;
+}
/*
Tor Property String Bundle
=====================================
toolkit/components/tor-launcher/TorLauncherUtil.sys.mjs
=====================================
@@ -5,6 +5,12 @@
* Tor Launcher Util JS Module
*************************************************************************/
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ FileUtils: "resource://gre/modules/FileUtils.sys.jsm",
+});
+
const kPropBundleURI = "chrome://torbutton/locale/torlauncher.properties";
const kPropNamePrefix = "torlauncher.";
const kIPCDirPrefName = "extensions.torlauncher.tmp_ipc_dir";
@@ -209,14 +215,15 @@ class TorFile {
// and return a file object. The control and SOCKS IPC objects will be
// created by tor.
normalize() {
- if (!this.file.exists() && !this.isIPC) {
+ if (this.file.exists()) {
+ try {
+ this.file.normalize();
+ } catch (e) {
+ console.warn("Normalization of the path failed", e);
+ }
+ } else if (!this.isIPC) {
throw new Error(`${this.fileType} file not found: ${this.file.path}`);
}
- try {
- this.file.normalize();
- } catch (e) {
- console.warn("Normalization of the path failed", e);
- }
// Ensure that the IPC path length is short enough for use by the
// operating system. If not, create and use a unique directory under
@@ -452,6 +459,154 @@ export const TorLauncherUtil = Object.freeze({
return result ? result : "";
},
+ /**
+ * Determine what kind of SOCKS port has been requested for this session or
+ * the browser has been configured for.
+ * On Windows (where Unix domain sockets are not supported), TCP is always
+ * used.
+ *
+ * The following environment variables are supported and take precedence over
+ * preferences:
+ * TOR_TRANSPROXY (do not use a proxy)
+ * TOR_SOCKS_IPC_PATH (file system path; ignored on Windows)
+ * TOR_SOCKS_HOST
+ * TOR_SOCKS_PORT
+ *
+ * The following preferences are consulted:
+ * network.proxy.socks
+ * network.proxy.socks_port
+ * extensions.torlauncher.socks_port_use_ipc (Boolean)
+ * extensions.torlauncher.socks_ipc_path (file system path)
+ * If extensions.torlauncher.socks_ipc_path is empty, a default path is used.
+ *
+ * When using TCP, if a value is not defined via an env variable it is
+ * taken from the corresponding browser preference if possible. The
+ * exceptions are:
+ * If network.proxy.socks contains a file: URL, a default value of
+ * "127.0.0.1" is used instead.
+ * If the network.proxy.socks_port value is not valid (outside the
+ * (0; 65535] range), a default value of 9150 is used instead.
+ *
+ * The SOCKS configuration will not influence the launch of a tor daemon and
+ * the configuration of the control port in any way.
+ * When a SOCKS configuration is required without TOR_SKIP_LAUNCH, the browser
+ * will try to configure the tor instance to use the required configuration.
+ * This also applies to TOR_TRANSPROXY (at least for now): tor will be
+ * launched with its defaults.
+ *
+ * TODO: add a preference to ignore the current configuration, and let tor
+ * listen on any free port. Then, the browser will prompt the daemon the port
+ * to use through the control port (even though this is quite dangerous at the
+ * moment, because with network disabled tor will disable also the SOCKS
+ * listeners, so it means that we will have to check it every time we change
+ * the network status).
+ */
+ getPreferredSocksConfiguration() {
+ if (Services.env.exists("TOR_TRANSPROXY")) {
+ Services.prefs.setBoolPref("network.proxy.socks_remote_dns", false);
+ Services.prefs.setIntPref("network.proxy.type", 0);
+ Services.prefs.setIntPref("network.proxy.socks_port", 0);
+ Services.prefs.setCharPref("network.proxy.socks", "");
+ return { transproxy: true };
+ }
+
+ let useIPC;
+ const socksPortInfo = {
+ transproxy: false,
+ };
+
+ if (!this.isWindows && Services.env.exists("TOR_SOCKS_IPC_PATH")) {
+ useIPC = true;
+ const ipcPath = Services.env.get("TOR_SOCKS_IPC_PATH");
+ if (ipcPath) {
+ socksPortInfo.ipcFile = new lazy.FileUtils.File(ipcPath);
+ }
+ } else {
+ // Check for TCP host and port environment variables.
+ if (Services.env.exists("TOR_SOCKS_HOST")) {
+ socksPortInfo.host = Services.env.get("TOR_SOCKS_HOST");
+ useIPC = false;
+ }
+ if (Services.env.exists("TOR_SOCKS_PORT")) {
+ const port = parseInt(Services.env.get("TOR_SOCKS_PORT"), 10);
+ if (Number.isInteger(port) && port > 0 && port <= 65535) {
+ socksPortInfo.port = port;
+ useIPC = false;
+ }
+ }
+ }
+
+ if (useIPC === undefined) {
+ socksPortInfo.useIPC =
+ !this.isWindows &&
+ Services.prefs.getBoolPref(
+ "extensions.torlauncher.socks_port_use_ipc",
+ false
+ );
+ }
+
+ // Fill in missing SOCKS info from prefs.
+ if (socksPortInfo.useIPC) {
+ if (!socksPortInfo.ipcFile) {
+ socksPortInfo.ipcFile = TorLauncherUtil.getTorFile("socks_ipc", false);
+ }
+ } else {
+ if (!socksPortInfo.host) {
+ let socksAddr = Services.prefs.getCharPref(
+ "network.proxy.socks",
+ "127.0.0.1"
+ );
+ let socksAddrHasHost = socksAddr && !socksAddr.startsWith("file:");
+ socksPortInfo.host = socksAddrHasHost ? socksAddr : "127.0.0.1";
+ }
+
+ if (!socksPortInfo.port) {
+ let socksPort = Services.prefs.getIntPref(
+ "network.proxy.socks_port",
+ 0
+ );
+ // This pref is set as 0 by default in Firefox, use 9150 if we get 0.
+ socksPortInfo.port =
+ socksPort > 0 && socksPort <= 65535 ? socksPort : 9150;
+ }
+ }
+
+ return socksPortInfo;
+ },
+
+ setProxyConfiguration(socksPortInfo) {
+ if (socksPortInfo.transproxy) {
+ return;
+ }
+
+ if (socksPortInfo.useIPC) {
+ const fph = Services.io
+ .getProtocolHandler("file")
+ .QueryInterface(Ci.nsIFileProtocolHandler);
+ const fileURI = fph.newFileURI(socksPortInfo.ipcFile);
+ Services.prefs.setCharPref("network.proxy.socks", fileURI.spec);
+ Services.prefs.setIntPref("network.proxy.socks_port", 0);
+ } else {
+ if (socksPortInfo.host) {
+ Services.prefs.setCharPref("network.proxy.socks", socksPortInfo.host);
+ }
+ if (socksPortInfo.port) {
+ Services.prefs.setIntPref(
+ "network.proxy.socks_port",
+ socksPortInfo.port
+ );
+ }
+ }
+
+ if (socksPortInfo.ipcFile || socksPortInfo.host || socksPortInfo.port) {
+ Services.prefs.setBoolPref("network.proxy.socks_remote_dns", true);
+ Services.prefs.setIntPref("network.proxy.type", 1);
+ }
+
+ // Force prefs to be synced to disk
+ Services.prefs.savePrefFile(null);
+ },
+
get shouldStartAndOwnTor() {
const kPrefStartTor = "extensions.torlauncher.start_tor";
try {
=====================================
toolkit/components/tor-launcher/TorMonitorService.sys.mjs
=====================================
@@ -13,6 +13,10 @@ import { TorLauncherUtil } from "resource://gre/modules/TorLauncherUtil.sys.mjs"
const lazy = {};
+ChromeUtils.defineESModuleGetters(lazy, {
+ TorProtocolService: "resource://gre/modules/TorProtocolService.sys.mjs",
+});
+
ChromeUtils.defineModuleGetter(
lazy,
"controller",
@@ -233,7 +237,10 @@ export const TorMonitorService = {
// TorProcess should be instanced once, then always reused and restarted
// only through the prompt it exposes when the controlled process dies.
if (!this._torProcess) {
- this._torProcess = new TorProcess();
+ this._torProcess = new TorProcess(
+ lazy.TorProtocolService.torControlPortInfo,
+ lazy.TorProtocolService.torSOCKSPortInfo
+ );
this._torProcess.onExit = () => {
this._shutDownEventMonitor();
Services.obs.notifyObservers(null, TorTopics.ProcessExited);
@@ -254,6 +261,7 @@ export const TorMonitorService = {
await this._torProcess.start();
if (this._torProcess.isRunning) {
logger.info("tor started");
+ this._torProcessStartTime = Date.now();
}
} catch (e) {
// TorProcess already logs the error.
=====================================
toolkit/components/tor-launcher/TorParsers.sys.mjs
=====================================
@@ -267,4 +267,18 @@ export const TorParsers = Object.freeze({
rv += aStr.substring(lastAdded, aStr.length - 1);
return rv;
},
+
+ parseBridgeLine(line) {
+ const re =
+ /\s*(?:(?<transport>\S+)\s+)?(?<addr>[0-9a-fA-F\.\[\]\:]+:\d{1,5})(?:\s+(?<id>[0-9a-fA-F]{40}))?(?:\s+(?<args>.+))?/;
+ const match = re.exec(line);
+ if (!match) {
+ throw new Error("Invalid bridge line.");
+ }
+ const bridge = match.groups;
+ if (!bridge.transport) {
+ bridge.transport = "vanilla";
+ }
+ return bridge;
+ },
});
=====================================
toolkit/components/tor-launcher/TorProcess.sys.mjs
=====================================
@@ -1,21 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
import { setTimeout } from "resource://gre/modules/Timer.sys.mjs";
import { ConsoleAPI } from "resource://gre/modules/Console.sys.mjs";
import { Subprocess } from "resource://gre/modules/Subprocess.sys.mjs";
const lazy = {};
-ChromeUtils.defineModuleGetter(
- lazy,
- "TorProtocolService",
- "resource://gre/modules/TorProtocolService.jsm"
-);
-const { TorLauncherUtil } = ChromeUtils.import(
- "resource://gre/modules/TorLauncherUtil.jsm"
-);
-
-const { TorParsers } = ChromeUtils.import(
- "resource://gre/modules/TorParsers.jsm"
-);
+ChromeUtils.defineESModuleGetters(lazy, {
+ TorLauncherUtil: "resource://gre/modules/TorLauncherUtil.sys.mjs",
+ TorParsers: "resource://gre/modules/TorParsers.sys.mjs",
+});
const TorProcessStatus = Object.freeze({
Unknown: 0,
@@ -30,53 +26,86 @@ const logger = new ConsoleAPI({
});
export class TorProcess {
- _exeFile = null;
- _dataDir = null;
- _args = [];
- _subprocess = null;
- _status = TorProcessStatus.Unknown;
- _torProcessStartTime = null; // JS Date.now()
- _didConnectToTorControlPort = false; // Have we ever made a connection?
+ #controlSettings;
+ #socksSettings;
+ #exeFile = null;
+ #dataDir = null;
+ #args = [];
+ #subprocess = null;
+ #status = TorProcessStatus.Unknown;
+ // Have we ever made a connection on the control port?
+ #didConnectToTorControlPort = false;
+
+ onExit = exitCode => {};
+ onRestart = () => {};
+
+ constructor(controlSettings, socksSettings) {
+ if (
+ controlSettings &&
+ !controlSettings.password &&
+ !controlSettings.cookieFilePath
+ ) {
+ throw new Error("Unauthenticated control port is not supported");
+ }
- onExit = null;
- onRestart = null;
+ const checkPort = port =>
+ port === undefined ||
+ (Number.isInteger(controlSettings.port) &&
+ controlSettings.port > 0 &&
+ controlSettings.port < 65535);
+ if (!checkPort(controlSettings?.port)) {
+ throw new Error("Invalid control port");
+ }
+ if (!checkPort(socksSettings.port)) {
+ throw new Error("Invalid port specified for the SOCKS port");
+ }
+
+ this.#controlSettings = { ...controlSettings };
+ const ipcFileToString = file =>
+ "unix:" + lazy.TorParsers.escapeString(file.path);
+ if (controlSettings.ipcFile) {
+ this.#controlSettings.ipcFile = ipcFileToString(controlSettings.ipcFile);
+ }
+ this.#socksSettings = { ...socksSettings };
+ if (socksSettings.ipcFile) {
+ this.#socksSettings.ipcFile = ipcFileToString(socksSettings.ipcFile);
+ }
+ }
get status() {
- return this._status;
+ return this.#status;
}
get isRunning() {
return (
- this._status === TorProcessStatus.Starting ||
- this._status === TorProcessStatus.Running
+ this.#status === TorProcessStatus.Starting ||
+ this.#status === TorProcessStatus.Running
);
}
async start() {
- if (this._subprocess) {
+ if (this.#subprocess) {
return;
}
- this._status = TorProcessStatus.Unknown;
+ this.#status = TorProcessStatus.Unknown;
try {
- this._makeArgs();
- this._addControlPortArg();
- this._addSocksPortArg();
+ this.#makeArgs();
+ this.#addControlPortArgs();
+ this.#addSocksPortArg();
const pid = Services.appinfo.processID;
if (pid !== 0) {
- this._args.push("__OwningControllerProcess");
- this._args.push("" + pid);
+ this.#args.push("__OwningControllerProcess", pid.toString());
}
- if (TorLauncherUtil.shouldShowNetworkSettings) {
- this._args.push("DisableNetwork");
- this._args.push("1");
+ if (lazy.TorLauncherUtil.shouldShowNetworkSettings) {
+ this.#args.push("DisableNetwork", "1");
}
- this._status = TorProcessStatus.Starting;
- this._didConnectToTorControlPort = false;
+ this.#status = TorProcessStatus.Starting;
+ this.#didConnectToTorControlPort = false;
// useful for simulating slow tor daemon launch
const kPrefTorDaemonLaunchDelay = "extensions.torlauncher.launch_delay";
@@ -88,29 +117,31 @@ export class TorProcess {
await new Promise(resolve => setTimeout(() => resolve(), launchDelay));
}
- logger.debug(`Starting ${this._exeFile.path}`, this._args);
+ logger.debug(`Starting ${this.#exeFile.path}`, this.#args);
const options = {
- command: this._exeFile.path,
- arguments: this._args,
+ command: this.#exeFile.path,
+ arguments: this.#args,
stderr: "stdout",
- workdir: TorLauncherUtil.getTorFile("pt-startup-dir", false).path,
+ workdir: lazy.TorLauncherUtil.getTorFile("pt-startup-dir", false).path,
};
- this._subprocess = await Subprocess.call(options);
- this._dumpStdout();
- this._watchProcess();
- this._status = TorProcessStatus.Running;
- this._torProcessStartTime = Date.now();
+ this.#subprocess = await Subprocess.call(options);
+ this.#status = TorProcessStatus.Running;
} catch (e) {
- this._status = TorProcessStatus.Exited;
- this._subprocess = null;
+ this.#status = TorProcessStatus.Exited;
+ this.#subprocess = null;
logger.error("startTor error:", e);
throw e;
}
+
+ // Do not await the following functions, as they will return only when the
+ // process exits.
+ this.#dumpStdout();
+ this.#watchProcess();
}
// Forget about a process.
//
- // Instead of killing the tor process, we rely on the TAKEOWNERSHIP feature
+ // Instead of killing the tor process, we rely on the TAKEOWNERSHIP feature
// to shut down tor when we close the control port connection.
//
// Previously, we sent a SIGNAL HALT command to the tor control port,
@@ -123,36 +154,38 @@ export class TorProcess {
// Still, before closing the owning connection, this class should forget about
// the process, so that future notifications will be ignored.
forget() {
- this._subprocess = null;
- this._status = TorProcessStatus.Exited;
+ this.#subprocess = null;
+ this.#status = TorProcessStatus.Exited;
}
// The owner of the process can use this function to tell us that they
// successfully connected to the control port. This information will be used
// only to decide which text to show in the confirmation dialog if tor exits.
connectionWorked() {
- this._didConnectToTorControlPort = true;
+ this.#didConnectToTorControlPort = true;
}
- async _dumpStdout() {
+ async #dumpStdout() {
let string;
while (
- this._subprocess &&
- (string = await this._subprocess.stdout.readString())
+ this.#subprocess &&
+ (string = await this.#subprocess.stdout.readString())
) {
dump(string);
}
}
- async _watchProcess() {
- const watched = this._subprocess;
+ async #watchProcess() {
+ const watched = this.#subprocess;
if (!watched) {
return;
}
+ let processExitCode;
try {
const { exitCode } = await watched.wait();
+ processExitCode = exitCode;
- if (watched !== this._subprocess) {
+ if (watched !== this.#subprocess) {
logger.debug(`A Tor process exited with code ${exitCode}.`);
} else if (exitCode) {
logger.warn(`The watched Tor process exited with code ${exitCode}.`);
@@ -163,30 +196,31 @@ export class TorProcess {
logger.error("Failed to watch the tor process", e);
}
- if (watched === this._subprocess) {
- this._processExitedUnexpectedly();
+ if (watched === this.#subprocess) {
+ this.#processExitedUnexpectedly(processExitCode);
}
}
- _processExitedUnexpectedly() {
- this._subprocess = null;
- this._status = TorProcessStatus.Exited;
+ #processExitedUnexpectedly(exitCode) {
+ this.#subprocess = null;
+ this.#status = TorProcessStatus.Exited;
// TODO: Move this logic somewhere else?
let s;
- if (!this._didConnectToTorControlPort) {
+ if (!this.#didConnectToTorControlPort) {
// tor might be misconfigured, becauser we could never connect to it
const key = "tor_exited_during_startup";
- s = TorLauncherUtil.getLocalizedString(key);
+ s = lazy.TorLauncherUtil.getLocalizedString(key);
} else {
// tor exited suddenly, so configuration should be okay
s =
- TorLauncherUtil.getLocalizedString("tor_exited") +
+ lazy.TorLauncherUtil.getLocalizedString("tor_exited") +
"\n\n" +
- TorLauncherUtil.getLocalizedString("tor_exited2");
+ lazy.TorLauncherUtil.getLocalizedString("tor_exited2");
}
logger.info(s);
- const defaultBtnLabel = TorLauncherUtil.getLocalizedString("restart_tor");
+ const defaultBtnLabel =
+ lazy.TorLauncherUtil.getLocalizedString("restart_tor");
let cancelBtnLabel = "OK";
try {
const kSysBundleURI = "chrome://global/locale/commonDialogs.properties";
@@ -196,51 +230,43 @@ export class TorProcess {
logger.warn("Could not localize the cancel button", e);
}
- const restart = TorLauncherUtil.showConfirm(
+ const restart = lazy.TorLauncherUtil.showConfirm(
null,
s,
defaultBtnLabel,
cancelBtnLabel
);
if (restart) {
- this.start().then(() => {
- if (this.onRestart) {
- this.onRestart();
- }
- });
- } else if (this.onExit) {
- this.onExit();
+ this.start().then(this.onRestart);
+ } else {
+ this.onExit(exitCode);
}
}
- _makeArgs() {
- // Ideally, we would cd to the Firefox application directory before
- // starting tor (but we don't know how to do that). Instead, we
- // rely on the TBB launcher to start Firefox from the right place.
-
+ #makeArgs() {
+ this.#exeFile = lazy.TorLauncherUtil.getTorFile("tor", false);
+ const torrcFile = lazy.TorLauncherUtil.getTorFile("torrc", true);
// Get the Tor data directory first so it is created before we try to
// construct paths to files that will be inside it.
- this._exeFile = TorLauncherUtil.getTorFile("tor", false);
- const torrcFile = TorLauncherUtil.getTorFile("torrc", true);
- this._dataDir = TorLauncherUtil.getTorFile("tordatadir", true);
- const onionAuthDir = TorLauncherUtil.getTorFile("toronionauthdir", true);
- const hashedPassword = lazy.TorProtocolService.torGetPassword(true);
+ this.#dataDir = lazy.TorLauncherUtil.getTorFile("tordatadir", true);
+ const onionAuthDir = lazy.TorLauncherUtil.getTorFile(
+ "toronionauthdir",
+ true
+ );
let detailsKey;
- if (!this._exeFile) {
+ if (!this.#exeFile) {
detailsKey = "tor_missing";
} else if (!torrcFile) {
detailsKey = "torrc_missing";
- } else if (!this._dataDir) {
+ } else if (!this.#dataDir) {
detailsKey = "datadir_missing";
} else if (!onionAuthDir) {
detailsKey = "onionauthdir_missing";
- } else if (!hashedPassword) {
- detailsKey = "password_hash_missing";
}
if (detailsKey) {
- const details = TorLauncherUtil.getLocalizedString(detailsKey);
+ const details = lazy.TorLauncherUtil.getLocalizedString(detailsKey);
const key = "unable_to_start_tor";
- const err = TorLauncherUtil.getFormattedLocalizedString(
+ const err = lazy.TorLauncherUtil.getFormattedLocalizedString(
key,
[details],
1
@@ -248,7 +274,7 @@ export class TorProcess {
throw new Error(err);
}
- const torrcDefaultsFile = TorLauncherUtil.getTorFile(
+ const torrcDefaultsFile = lazy.TorLauncherUtil.getTorFile(
"torrc-defaults",
false
);
@@ -258,77 +284,131 @@ export class TorProcess {
const geoip6File = torrcDefaultsFile.clone();
geoip6File.leafName = "geoip6";
- this._args = [];
+ this.#args = [];
if (torrcDefaultsFile) {
- this._args.push("--defaults-torrc");
- this._args.push(torrcDefaultsFile.path);
+ this.#args.push("--defaults-torrc", torrcDefaultsFile.path);
}
- this._args.push("-f");
- this._args.push(torrcFile.path);
- this._args.push("DataDirectory");
- this._args.push(this._dataDir.path);
- this._args.push("ClientOnionAuthDir");
- this._args.push(onionAuthDir.path);
- this._args.push("GeoIPFile");
- this._args.push(geoipFile.path);
- this._args.push("GeoIPv6File");
- this._args.push(geoip6File.path);
- this._args.push("HashedControlPassword");
- this._args.push(hashedPassword);
+ this.#args.push("-f", torrcFile.path);
+ this.#args.push("DataDirectory", this.#dataDir.path);
+ this.#args.push("ClientOnionAuthDir", onionAuthDir.path);
+ this.#args.push("GeoIPFile", geoipFile.path);
+ this.#args.push("GeoIPv6File", geoip6File.path);
}
- _addControlPortArg() {
- // Include a ControlPort argument to support switching between
- // a TCP port and an IPC port (e.g., a Unix domain socket). We
- // include a "+__" prefix so that (1) this control port is added
- // to any control ports that the user has defined in their torrc
- // file and (2) it is never written to torrc.
+ /**
+ * Add all the arguments related to the control port.
+ * We use the + prefix so that the the port is added to any other port already
+ * defined in the torrc, and the __ prefix so that it is never written to
+ * torrc.
+ */
+ #addControlPortArgs() {
+ if (!this.#controlSettings) {
+ return;
+ }
+
let controlPortArg;
- const controlIPCFile = lazy.TorProtocolService.torGetControlIPCFile();
- const controlPort = lazy.TorProtocolService.torGetControlPort();
- if (controlIPCFile) {
- controlPortArg = this._ipcPortArg(controlIPCFile);
- } else if (controlPort) {
- controlPortArg = "" + controlPort;
+ if (this.#controlSettings.ipcFile) {
+ controlPortArg = this.#controlSettings.ipcFile;
+ } else if (this.#controlSettings.port) {
+ controlPortArg = this.#controlSettings.host
+ ? `${this.#controlSettings.host}:${this.#controlSettings.port}`
+ : this.#controlSettings.port.toString();
}
if (controlPortArg) {
- this._args.push("+__ControlPort");
- this._args.push(controlPortArg);
+ this.#args.push("+__ControlPort", controlPortArg);
+ }
+
+ if (this.#controlSettings.password) {
+ this.#args.push(
+ "HashedControlPassword",
+ this.#hashPassword(this.#controlSettings.password)
+ );
+ }
+ if (this.#controlSettings.cookieFilePath) {
+ this.#args.push("CookieAuthentication", "1");
+ this.#args.push("CookieAuthFile", this.#controlSettings.cookieFilePath);
}
}
- _addSocksPortArg() {
- // Include a SocksPort argument to support switching between
- // a TCP port and an IPC port (e.g., a Unix domain socket). We
- // include a "+__" prefix so that (1) this SOCKS port is added
- // to any SOCKS ports that the user has defined in their torrc
- // file and (2) it is never written to torrc.
- const socksPortInfo = lazy.TorProtocolService.torGetSOCKSPortInfo();
- if (socksPortInfo) {
- let socksPortArg;
- if (socksPortInfo.ipcFile) {
- socksPortArg = this._ipcPortArg(socksPortInfo.ipcFile);
- } else if (socksPortInfo.host && socksPortInfo.port != 0) {
- socksPortArg = socksPortInfo.host + ":" + socksPortInfo.port;
- }
- if (socksPortArg) {
- let socksPortFlags = Services.prefs.getCharPref(
- "extensions.torlauncher.socks_port_flags",
- "IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth"
- );
- if (socksPortFlags) {
- socksPortArg += " " + socksPortFlags;
- }
- this._args.push("+__SocksPort");
- this._args.push(socksPortArg);
+ /**
+ * Add the argument related to the control port.
+ * We use the + prefix so that the the port is added to any other port already
+ * defined in the torrc, and the __ prefix so that it is never written to
+ * torrc.
+ */
+ #addSocksPortArg() {
+ let socksPortArg;
+ if (this.#socksSettings.ipcFile) {
+ socksPortArg = this.#socksSettings.ipcFile;
+ } else if (this.#socksSettings.port != 0) {
+ socksPortArg = this.#socksSettings.host
+ ? `${this.#socksSettings.host}:${this.#socksSettings.port}`
+ : this.#socksSettings.port.toString();
+ }
+ if (socksPortArg) {
+ const socksPortFlags = Services.prefs.getCharPref(
+ "extensions.torlauncher.socks_port_flags",
+ "IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth"
+ );
+ if (socksPortFlags) {
+ socksPortArg += " " + socksPortFlags;
}
+ this.#args.push("+__SocksPort", socksPortArg);
+ }
+ }
+
+ // Based on Vidalia's TorSettings::hashPassword().
+ #hashPassword(aHexPassword) {
+ if (!aHexPassword) {
+ return null;
}
+
+ // Generate a random, 8 byte salt value.
+ const salt = Array.from(crypto.getRandomValues(new Uint8Array(8)));
+
+ // Convert hex-encoded password to an array of bytes.
+ const password = [];
+ for (let i = 0; i < aHexPassword.length; i += 2) {
+ password.push(parseInt(aHexPassword.substring(i, i + 2), 16));
+ }
+
+ // Run through the S2K algorithm and convert to a string.
+ const toHex = v => v.toString(16).padStart(2, "0");
+ const arrayToHex = aArray => aArray.map(toHex).join("");
+ const kCodedCount = 96;
+ const hashVal = this.#cryptoSecretToKey(password, salt, kCodedCount);
+ return "16:" + arrayToHex(salt) + toHex(kCodedCount) + arrayToHex(hashVal);
}
- // Return a ControlPort or SocksPort argument for aIPCFile (an nsIFile).
- // The result is unix:/path or unix:"/path with spaces" with appropriate
- // C-style escaping within the path portion.
- _ipcPortArg(aIPCFile) {
- return "unix:" + TorParsers.escapeString(aIPCFile.path);
+ // #cryptoSecretToKey() is similar to Vidalia's crypto_secret_to_key().
+ // It generates and returns a hash of aPassword by following the iterated
+ // and salted S2K algorithm (see RFC 2440 section 3.6.1.3).
+ // See also https://gitlab.torproject.org/tpo/core/torspec/-/blob/main/control-spec.txt….
+ // Returns an array of bytes.
+ #cryptoSecretToKey(aPassword, aSalt, aCodedCount) {
+ const inputArray = aSalt.concat(aPassword);
+
+ // Subtle crypto only has the final digest, and does not allow incremental
+ // updates.
+ const hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
+ Ci.nsICryptoHash
+ );
+ hasher.init(hasher.SHA1);
+ const kEXPBIAS = 6;
+ let count = (16 + (aCodedCount & 15)) << ((aCodedCount >> 4) + kEXPBIAS);
+ while (count > 0) {
+ if (count > inputArray.length) {
+ hasher.update(inputArray, inputArray.length);
+ count -= inputArray.length;
+ } else {
+ const finalArray = inputArray.slice(0, count);
+ hasher.update(finalArray, finalArray.length);
+ count = 0;
+ }
+ }
+ return hasher
+ .finish(false)
+ .split("")
+ .map(b => b.charCodeAt(0));
}
}
=====================================
toolkit/components/tor-launcher/TorProtocolService.sys.mjs
=====================================
@@ -289,9 +289,8 @@ export const TorProtocolService = {
// are also used in torbutton.
// Returns Tor password string or null if an error occurs.
- torGetPassword(aPleaseHash) {
- const pw = this._controlPassword;
- return aPleaseHash ? this._hashPassword(pw) : pw;
+ torGetPassword() {
+ return this._controlPassword;
},
torGetControlIPCFile() {
@@ -306,6 +305,24 @@ export const TorProtocolService = {
return this._SOCKSPortInfo;
},
+ get torControlPortInfo() {
+ const info = {
+ password: this._controlPassword,
+ };
+ if (this._controlIPCFile) {
+ info.ipcFile = this._controlIPCFile?.clone();
+ }
+ if (this._controlPort) {
+ info.host = this._controlHost;
+ info.port = this._controlPort;
+ }
+ return info;
+ },
+
+ get torSOCKSPortInfo() {
+ return this._SOCKSPortInfo;
+ },
+
// Public, but called only internally
// Executes a command on the control port.
@@ -469,115 +486,8 @@ export const TorProtocolService = {
this._controlPassword = this._generateRandomPassword();
}
- // Determine what kind of SOCKS port Tor and the browser will use.
- // On Windows (where Unix domain sockets are not supported), TCP is
- // always used.
- //
- // The following environment variables are supported and take
- // precedence over preferences:
- // TOR_SOCKS_IPC_PATH (file system path; ignored on Windows)
- // TOR_SOCKS_HOST
- // TOR_SOCKS_PORT
- //
- // The following preferences are consulted:
- // network.proxy.socks
- // network.proxy.socks_port
- // extensions.torlauncher.socks_port_use_ipc (Boolean)
- // extensions.torlauncher.socks_ipc_path (file system path)
- // If extensions.torlauncher.socks_ipc_path is empty, a default
- // path is used (<tor-data-directory>/socks.socket).
- //
- // When using TCP, if a value is not defined via an env variable it is
- // taken from the corresponding browser preference if possible. The
- // exceptions are:
- // If network.proxy.socks contains a file: URL, a default value of
- // "127.0.0.1" is used instead.
- // If the network.proxy.socks_port value is 0, a default value of
- // 9150 is used instead.
- //
- // Supported scenarios:
- // 1. By default, an IPC object at a default path is used.
- // 2. If extensions.torlauncher.socks_port_use_ipc is set to false,
- // a TCP socket at 127.0.0.1:9150 is used, unless different values
- // are set in network.proxy.socks and network.proxy.socks_port.
- // 3. If the TOR_SOCKS_IPC_PATH env var is set, an IPC object at that
- // path is used (e.g., a Unix domain socket).
- // 4. If the TOR_SOCKS_HOST and/or TOR_SOCKS_PORT env vars are set, TCP
- // is used. Values not set via env vars will be taken from the
- // network.proxy.socks and network.proxy.socks_port prefs as described
- // above.
- // 5. If extensions.torlauncher.socks_port_use_ipc is true and
- // extensions.torlauncher.socks_ipc_path is set, an IPC object at
- // the specified path is used.
- // 6. Tor Launcher is disabled. Torbutton will respect the env vars if
- // present; if not, the values in network.proxy.socks and
- // network.proxy.socks_port are used without modification.
-
- let useIPC;
- this._SOCKSPortInfo = { ipcFile: undefined, host: undefined, port: 0 };
- if (!isWindows && Services.env.exists("TOR_SOCKS_IPC_PATH")) {
- let ipcPath = Services.env.get("TOR_SOCKS_IPC_PATH");
- this._SOCKSPortInfo.ipcFile = new lazy.FileUtils.File(ipcPath);
- useIPC = true;
- } else {
- // Check for TCP host and port environment variables.
- if (Services.env.exists("TOR_SOCKS_HOST")) {
- this._SOCKSPortInfo.host = Services.env.get("TOR_SOCKS_HOST");
- useIPC = false;
- }
- if (Services.env.exists("TOR_SOCKS_PORT")) {
- this._SOCKSPortInfo.port = parseInt(
- Services.env.get("TOR_SOCKS_PORT"),
- 10
- );
- useIPC = false;
- }
- }
-
- if (useIPC === undefined) {
- useIPC =
- !isWindows &&
- Services.prefs.getBoolPref(
- "extensions.torlauncher.socks_port_use_ipc",
- false
- );
- }
-
- // Fill in missing SOCKS info from prefs.
- if (useIPC) {
- if (!this._SOCKSPortInfo.ipcFile) {
- this._SOCKSPortInfo.ipcFile = TorLauncherUtil.getTorFile(
- "socks_ipc",
- false
- );
- }
- } else {
- if (!this._SOCKSPortInfo.host) {
- let socksAddr = Services.prefs.getCharPref(
- "network.proxy.socks",
- "127.0.0.1"
- );
- let socksAddrHasHost = socksAddr && !socksAddr.startsWith("file:");
- this._SOCKSPortInfo.host = socksAddrHasHost ? socksAddr : "127.0.0.1";
- }
-
- if (!this._SOCKSPortInfo.port) {
- let socksPort = Services.prefs.getIntPref(
- "network.proxy.socks_port",
- 0
- );
- // This pref is set as 0 by default in Firefox, use 9150 if we get 0.
- this._SOCKSPortInfo.port = socksPort != 0 ? socksPort : 9150;
- }
- }
-
- logger.info("SOCKS port type: " + (useIPC ? "IPC" : "TCP"));
- if (useIPC) {
- logger.info(`ipcFile: ${this._SOCKSPortInfo.ipcFile.path}`);
- } else {
- logger.info(`SOCKS host: ${this._SOCKSPortInfo.host}`);
- logger.info(`SOCKS port: ${this._SOCKSPortInfo.port}`);
- }
+ this._SOCKSPortInfo = TorLauncherUtil.getPreferredSocksConfiguration();
+ TorLauncherUtil.setProxyConfiguration(this._SOCKSPortInfo);
// Set the global control port info parameters.
// These values may be overwritten by torbutton when it initializes, but
@@ -781,38 +691,6 @@ export const TorProtocolService = {
return pwd;
},
- // Based on Vidalia's TorSettings::hashPassword().
- _hashPassword(aHexPassword) {
- if (!aHexPassword) {
- return null;
- }
-
- // Generate a random, 8 byte salt value.
- const salt = Array.from(crypto.getRandomValues(new Uint8Array(8)));
-
- // Convert hex-encoded password to an array of bytes.
- const password = [];
- for (let i = 0; i < aHexPassword.length; i += 2) {
- password.push(parseInt(aHexPassword.substring(i, i + 2), 16));
- }
-
- // Run through the S2K algorithm and convert to a string.
- const kCodedCount = 96;
- const hashVal = this._cryptoSecretToKey(password, salt, kCodedCount);
- if (!hashVal) {
- logger.error("_cryptoSecretToKey() failed");
- return null;
- }
-
- const arrayToHex = aArray =>
- aArray.map(item => this._toHex(item, 2)).join("");
- let rv = "16:";
- rv += arrayToHex(salt);
- rv += this._toHex(kCodedCount, 2);
- rv += arrayToHex(hashVal);
- return rv;
- },
-
// Returns -1 upon failure.
_cryptoRandInt(aMax) {
// Based on tor's crypto_rand_int().
@@ -831,43 +709,6 @@ export const TorProtocolService = {
return val % aMax;
},
- // _cryptoSecretToKey() is similar to Vidalia's crypto_secret_to_key().
- // It generates and returns a hash of aPassword by following the iterated
- // and salted S2K algorithm (see RFC 2440 section 3.6.1.3).
- // Returns an array of bytes.
- _cryptoSecretToKey(aPassword, aSalt, aCodedCount) {
- if (!aPassword || !aSalt) {
- return null;
- }
-
- const inputArray = aSalt.concat(aPassword);
-
- // Subtle crypto only has the final digest, and does not allow incremental
- // updates. Also, it is async, so we should hash and keep the hash in a
- // variable if we wanted to switch to getters.
- // So, keeping this implementation should be okay for now.
- const hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
- Ci.nsICryptoHash
- );
- hasher.init(hasher.SHA1);
- const kEXPBIAS = 6;
- let count = (16 + (aCodedCount & 15)) << ((aCodedCount >> 4) + kEXPBIAS);
- while (count > 0) {
- if (count > inputArray.length) {
- hasher.update(inputArray, inputArray.length);
- count -= inputArray.length;
- } else {
- const finalArray = inputArray.slice(0, count);
- hasher.update(finalArray, finalArray.length);
- count = 0;
- }
- }
- return hasher
- .finish(false)
- .split("")
- .map(b => b.charCodeAt(0));
- },
-
_toHex(aValue, aMinLen) {
return aValue.toString(16).padStart(aMinLen, "0");
},
=====================================
toolkit/torbutton/chrome/content/torbutton.js
=====================================
@@ -60,7 +60,7 @@ var torbutton_init;
} else {
try {
// Try to get password from Tor Launcher.
- m_tb_control_pass = TorProtocolService.torGetPassword(false);
+ m_tb_control_pass = TorProtocolService.torGetPassword();
} catch (e) {}
}
=====================================
toolkit/torbutton/components.conf
=====================================
@@ -1,12 +1,4 @@
Classes = [
- {
- "cid": "{06322def-6fde-4c06-aef6-47ae8e799629}",
- "contract_ids": [
- "@torproject.org/startup-observer;1"
- ],
- "jsm": "resource://torbutton/modules/TorbuttonStartupObserver.jsm",
- "constructor": "StartupObserver",
- },
{
"cid": "{f36d72c9-9718-4134-b550-e109638331d7}",
"contract_ids": [
=====================================
toolkit/torbutton/modules/TorbuttonStartupObserver.jsm deleted
=====================================
@@ -1,138 +0,0 @@
-// Bug 1506 P1-3: This code is mostly hackish remnants of session store
-// support. There are a couple of observer events that *might* be worth
-// listening to. Search for 1506 in the code.
-
-/*************************************************************************
- * Startup observer (JavaScript XPCOM component)
- *
- * Cases tested (each during Tor and Non-Tor, FF4 and FF3.6)
- * 1. Crash
- * 2. Upgrade
- * 3. Fresh install
- *
- *************************************************************************/
-
-var EXPORTED_SYMBOLS = ["StartupObserver"];
-
-const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const { XPCOMUtils } = ChromeUtils.import(
- "resource://gre/modules/XPCOMUtils.jsm"
-);
-
-const { TorProtocolService } = ChromeUtils.import(
- "resource://gre/modules/TorProtocolService.jsm"
-);
-
-const lazy = {};
-
-XPCOMUtils.defineLazyModuleGetters(lazy, {
- FileUtils: "resource://gre/modules/FileUtils.jsm",
-});
-
-function StartupObserver() {
- this.logger = Cc["@torproject.org/torbutton-logger;1"].getService(
- Ci.nsISupports
- ).wrappedJSObject;
- this._prefs = Services.prefs;
- this.logger.log(3, "Startup Observer created");
-
- try {
- // XXX: We're in a race with HTTPS-Everywhere to update our proxy settings
- // before the initial SSL-Observatory test... If we lose the race, Firefox
- // caches the old proxy settings for check.tp.o somehwere, and it never loads :(
- this.setProxySettings();
- } catch (e) {
- this.logger.log(
- 4,
- "Early proxy change failed. Will try again at profile load. Error: " + e
- );
- }
-}
-
-StartupObserver.prototype = {
- // Bug 6803: We need to get the env vars early due to
- // some weird proxy caching code that showed up in FF15.
- // Otherwise, homepage domain loads fail forever.
- setProxySettings() {
- // Bug 1506: Still want to get these env vars
- if (Services.env.exists("TOR_TRANSPROXY")) {
- this.logger.log(3, "Resetting Tor settings to transproxy");
- this._prefs.setBoolPref("network.proxy.socks_remote_dns", false);
- this._prefs.setIntPref("network.proxy.type", 0);
- this._prefs.setIntPref("network.proxy.socks_port", 0);
- this._prefs.setCharPref("network.proxy.socks", "");
- } else {
- // Try to retrieve SOCKS proxy settings from Tor Launcher.
- let socksPortInfo;
- try {
- socksPortInfo = TorProtocolService.torGetSOCKSPortInfo();
- } catch (e) {
- this.logger.log(3, "tor launcher failed " + e);
- }
-
- // If Tor Launcher is not available, check environment variables.
- if (!socksPortInfo) {
- socksPortInfo = { ipcFile: undefined, host: undefined, port: 0 };
-
- let isWindows = Services.appinfo.OS === "WINNT";
- if (!isWindows && Services.env.exists("TOR_SOCKS_IPC_PATH")) {
- socksPortInfo.ipcFile = new lazy.FileUtils.File(
- Services.env.get("TOR_SOCKS_IPC_PATH")
- );
- } else {
- if (Services.env.exists("TOR_SOCKS_HOST")) {
- socksPortInfo.host = Services.env.get("TOR_SOCKS_HOST");
- }
- if (Services.env.exists("TOR_SOCKS_PORT")) {
- socksPortInfo.port = parseInt(Services.env.get("TOR_SOCKS_PORT"));
- }
- }
- }
-
- // Adjust network.proxy prefs.
- if (socksPortInfo.ipcFile) {
- let fph = Services.io
- .getProtocolHandler("file")
- .QueryInterface(Ci.nsIFileProtocolHandler);
- let fileURI = fph.newFileURI(socksPortInfo.ipcFile);
- this.logger.log(3, "Reset socks to " + fileURI.spec);
- this._prefs.setCharPref("network.proxy.socks", fileURI.spec);
- this._prefs.setIntPref("network.proxy.socks_port", 0);
- } else {
- if (socksPortInfo.host) {
- this._prefs.setCharPref("network.proxy.socks", socksPortInfo.host);
- this.logger.log(3, "Reset socks host to " + socksPortInfo.host);
- }
- if (socksPortInfo.port) {
- this._prefs.setIntPref(
- "network.proxy.socks_port",
- socksPortInfo.port
- );
- this.logger.log(3, "Reset socks port to " + socksPortInfo.port);
- }
- }
-
- if (socksPortInfo.ipcFile || socksPortInfo.host || socksPortInfo.port) {
- this._prefs.setBoolPref("network.proxy.socks_remote_dns", true);
- this._prefs.setIntPref("network.proxy.type", 1);
- }
- }
-
- // Force prefs to be synced to disk
- Services.prefs.savePrefFile(null);
-
- this.logger.log(3, "Synced network settings to environment.");
- },
-
- observe(subject, topic, data) {
- if (topic == "profile-after-change") {
- this.setProxySettings();
- }
-
- // In all cases, force prefs to be synced to disk
- Services.prefs.savePrefFile(null);
- },
-
- // Hack to get us registered early to observe recovery
- _xpcom_categories: [{ category: "profile-after-change" }],
-};
=====================================
toolkit/torbutton/moz.build
=====================================
@@ -8,7 +8,3 @@ JAR_MANIFESTS += ['jar.mn']
XPCOM_MANIFESTS += [
"components.conf",
]
-
-EXTRA_COMPONENTS += [
- "torbutton.manifest",
-]
=====================================
toolkit/torbutton/torbutton.manifest deleted
=====================================
@@ -1 +0,0 @@
-category profile-after-change StartupObserver @torproject.org/startup-observer;1
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/f0493f…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/f0493f…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][base-browser-115.0.2esr-13.0-1] Deleted 2 commits: Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
by richard (@richard) 31 Jul '23
by richard (@richard) 31 Jul '23
31 Jul '23
richard pushed to branch base-browser-115.0.2esr-13.0-1 at The Tor Project / Applications / Tor Browser
WARNING: The push did not contain any new commits, but force pushed to delete the commits and changes below.
Deleted commits:
60fefea4 by Edgar Chen at 2023-07-31T17:56:34+00:00
Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
Fullscreen/PointerLock warnings are initialized with hidden="true", but
change to hidden="" after being shown and hidden again. I think this
started happening when we began using HTML elements instead of XUL as
they handle hidden attribute differently.
Differential Revision: https://phabricator.services.mozilla.com/D177790
- - - - -
524c7622 by Edgar Chen at 2023-07-31T17:56:38+00:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
- - - - -
4 changed files:
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/base/content/fullscreen-and-pointerlock.inc.xhtml
- browser/base/content/test/fullscreen/browser_fullscreen_warning.js
- dom/tests/browser/browser_pointerlock_warning.js
Changes:
=====================================
browser/base/content/browser-fullScreenAndPointerLock.js
=====================================
@@ -62,9 +62,14 @@ var PointerlockFsWarning = {
this._element = document.getElementById(elementId);
// Setup event listeners
this._element.addEventListener("transitionend", this);
+ this._element.addEventListener("transitioncancel", this);
window.addEventListener("mousemove", this, true);
+ window.addEventListener("activate", this);
+ window.addEventListener("deactivate", this);
// The timeout to hide the warning box after a while.
this._timeoutHide = new this.Timeout(() => {
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
this._state = "hidden";
}, timeout);
// The timeout to show the warning box when the pointer is at the top
@@ -116,11 +121,10 @@ var PointerlockFsWarning = {
return;
}
- // Explicitly set the last state to hidden to avoid the warning
- // box being hidden immediately because of mousemove.
- this._state = "onscreen";
- this._lastState = "hidden";
- this._timeoutHide.start();
+ if (Services.focus.activeWindow == window) {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ }
},
/**
@@ -148,7 +152,10 @@ var PointerlockFsWarning = {
this._element.hidden = true;
// Remove all event listeners
this._element.removeEventListener("transitionend", this);
+ this._element.removeEventListener("transitioncancel", this);
window.removeEventListener("mousemove", this, true);
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
// Clear fields
this._element = null;
this._timeoutHide = null;
@@ -186,7 +193,7 @@ var PointerlockFsWarning = {
}
if (newState != "hidden") {
if (currentState != "hidden") {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
} else {
// When the previous state is hidden, the display was none,
// thus no box was constructed. We need to wait for the new
@@ -197,7 +204,7 @@ var PointerlockFsWarning = {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (this._element) {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
}
});
});
@@ -217,7 +224,7 @@ var PointerlockFsWarning = {
} else if (this._timeoutShow.delay >= 0) {
this._timeoutShow.start();
}
- } else {
+ } else if (state != "onscreen") {
let elemRect = this._element.getBoundingClientRect();
if (state == "hiding" && this._lastState != "hidden") {
// If we are on the hiding transition, and the pointer
@@ -239,12 +246,23 @@ var PointerlockFsWarning = {
}
break;
}
- case "transitionend": {
+ case "transitionend":
+ case "transitioncancel": {
if (this._state == "hiding") {
this._element.hidden = true;
}
break;
}
+ case "activate": {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ break;
+ }
+ case "deactivate": {
+ this._state = "hidden";
+ this._timeoutHide.cancel();
+ break;
+ }
}
},
};
=====================================
browser/base/content/fullscreen-and-pointerlock.inc.xhtml
=====================================
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<html:div id="fullscreen-and-pointerlock-wrapper">
- <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
@@ -20,7 +20,7 @@
</html:button>
</html:div>
- <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
=====================================
browser/base/content/test/fullscreen/browser_fullscreen_warning.js
=====================================
@@ -3,14 +3,35 @@
"use strict";
-add_task(async function test_fullscreen_display_none() {
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
+add_setup(async function init() {
await SpecialPowers.pushPrefEnv({
set: [
["full-screen-api.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
],
});
+});
+add_task(async function test_fullscreen_display_none() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
@@ -30,11 +51,13 @@ add_task(async function test_fullscreen_display_none() {
},
async function (browser) {
let warning = document.getElementById("fullscreen-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
warning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
);
+
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
// Enter fullscreen
await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
@@ -54,39 +77,33 @@ add_task(async function test_fullscreen_display_none() {
);
document.getElementById("fullscreen-exit-button").click();
await exitFullscreenPromise;
+
+ checkWarningState(
+ warning,
+ "hidden",
+ "Should hide fullscreen warning after exiting fullscreen"
+ );
}
);
});
add_task(async function test_fullscreen_pointerlock_conflict() {
- await SpecialPowers.pushPrefEnv({
- set: [
- ["full-screen-api.enabled", true],
- ["full-screen-api.allow-trusted-requests-only", false],
- ],
- });
-
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let fsWarning = document.getElementById("fullscreen-warning");
let plWarning = document.getElementById("pointerlock-warning");
- is(
- fsWarning.getAttribute("onscreen"),
- null,
- "Should not show full screen warning initially."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning initially."
- );
-
- let fsWarningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
fsWarning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
+ );
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning initially"
);
+ let fsWarningShownPromise = waitForWarningState(fsWarning, "onscreen");
info("Entering full screen and pointer lock.");
await SpecialPowers.spawn(browser, [], async () => {
await content.document.body.requestFullscreen();
@@ -94,15 +111,10 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
});
await fsWarningShownPromise;
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should show full screen warning."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
info("Exiting pointerlock");
@@ -110,18 +122,19 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
await content.document.exitPointerLock();
});
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should still show full screen warning."
+ checkWarningState(
+ fsWarning,
+ "onscreen",
+ "Should still show full screen warning"
);
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
// Cleanup
+ info("Exiting fullscreen");
await document.exitFullscreen();
});
});
=====================================
dom/tests/browser/browser_pointerlock_warning.js
=====================================
@@ -15,6 +15,25 @@ const FRAME_TEST_URL =
encodeURI(BODY_URL) +
'"></iframe></body>';
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
// Make sure the pointerlock warning is shown and exited with the escape key
add_task(async function show_pointerlock_warning_escape() {
let urls = [TEST_URL, FRAME_TEST_URL];
@@ -24,11 +43,7 @@ add_task(async function show_pointerlock_warning_escape() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let warning = document.getElementById("pointerlock-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
- warning,
- "true"
- );
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
let expectedWarningText;
@@ -49,11 +64,7 @@ add_task(async function show_pointerlock_warning_escape() {
ok(true, "Pointerlock warning shown");
- let warningHiddenPromise = BrowserTestUtils.waitForAttribute(
- "hidden",
- warning,
- ""
- );
+ let warningHiddenPromise = waitForWarningState(warning, "hidden");
await BrowserTestUtils.waitForCondition(
() => warning.innerText == expectedWarningText,
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/f3faeb…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/f3faeb…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-115.0.2esr-13.0-1] Deleted 2 commits: Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
by richard (@richard) 31 Jul '23
by richard (@richard) 31 Jul '23
31 Jul '23
richard pushed to branch tor-browser-115.0.2esr-13.0-1 at The Tor Project / Applications / Tor Browser
WARNING: The push did not contain any new commits, but force pushed to delete the commits and changes below.
Deleted commits:
6a6c68cf by Edgar Chen at 2023-07-31T17:56:02+00:00
Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
Fullscreen/PointerLock warnings are initialized with hidden="true", but
change to hidden="" after being shown and hidden again. I think this
started happening when we began using HTML elements instead of XUL as
they handle hidden attribute differently.
Differential Revision: https://phabricator.services.mozilla.com/D177790
- - - - -
5e8c1b08 by Edgar Chen at 2023-07-31T17:56:07+00:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
- - - - -
4 changed files:
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/base/content/fullscreen-and-pointerlock.inc.xhtml
- browser/base/content/test/fullscreen/browser_fullscreen_warning.js
- dom/tests/browser/browser_pointerlock_warning.js
Changes:
=====================================
browser/base/content/browser-fullScreenAndPointerLock.js
=====================================
@@ -62,9 +62,14 @@ var PointerlockFsWarning = {
this._element = document.getElementById(elementId);
// Setup event listeners
this._element.addEventListener("transitionend", this);
+ this._element.addEventListener("transitioncancel", this);
window.addEventListener("mousemove", this, true);
+ window.addEventListener("activate", this);
+ window.addEventListener("deactivate", this);
// The timeout to hide the warning box after a while.
this._timeoutHide = new this.Timeout(() => {
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
this._state = "hidden";
}, timeout);
// The timeout to show the warning box when the pointer is at the top
@@ -116,11 +121,10 @@ var PointerlockFsWarning = {
return;
}
- // Explicitly set the last state to hidden to avoid the warning
- // box being hidden immediately because of mousemove.
- this._state = "onscreen";
- this._lastState = "hidden";
- this._timeoutHide.start();
+ if (Services.focus.activeWindow == window) {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ }
},
/**
@@ -148,7 +152,10 @@ var PointerlockFsWarning = {
this._element.hidden = true;
// Remove all event listeners
this._element.removeEventListener("transitionend", this);
+ this._element.removeEventListener("transitioncancel", this);
window.removeEventListener("mousemove", this, true);
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
// Clear fields
this._element = null;
this._timeoutHide = null;
@@ -186,7 +193,7 @@ var PointerlockFsWarning = {
}
if (newState != "hidden") {
if (currentState != "hidden") {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
} else {
// When the previous state is hidden, the display was none,
// thus no box was constructed. We need to wait for the new
@@ -197,7 +204,7 @@ var PointerlockFsWarning = {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (this._element) {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
}
});
});
@@ -217,7 +224,7 @@ var PointerlockFsWarning = {
} else if (this._timeoutShow.delay >= 0) {
this._timeoutShow.start();
}
- } else {
+ } else if (state != "onscreen") {
let elemRect = this._element.getBoundingClientRect();
if (state == "hiding" && this._lastState != "hidden") {
// If we are on the hiding transition, and the pointer
@@ -239,12 +246,23 @@ var PointerlockFsWarning = {
}
break;
}
- case "transitionend": {
+ case "transitionend":
+ case "transitioncancel": {
if (this._state == "hiding") {
this._element.hidden = true;
}
break;
}
+ case "activate": {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ break;
+ }
+ case "deactivate": {
+ this._state = "hidden";
+ this._timeoutHide.cancel();
+ break;
+ }
}
},
};
=====================================
browser/base/content/fullscreen-and-pointerlock.inc.xhtml
=====================================
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<html:div id="fullscreen-and-pointerlock-wrapper">
- <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
@@ -20,7 +20,7 @@
</html:button>
</html:div>
- <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
=====================================
browser/base/content/test/fullscreen/browser_fullscreen_warning.js
=====================================
@@ -3,14 +3,35 @@
"use strict";
-add_task(async function test_fullscreen_display_none() {
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
+add_setup(async function init() {
await SpecialPowers.pushPrefEnv({
set: [
["full-screen-api.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
],
});
+});
+add_task(async function test_fullscreen_display_none() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
@@ -30,11 +51,13 @@ add_task(async function test_fullscreen_display_none() {
},
async function (browser) {
let warning = document.getElementById("fullscreen-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
warning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
);
+
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
// Enter fullscreen
await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
@@ -54,39 +77,33 @@ add_task(async function test_fullscreen_display_none() {
);
document.getElementById("fullscreen-exit-button").click();
await exitFullscreenPromise;
+
+ checkWarningState(
+ warning,
+ "hidden",
+ "Should hide fullscreen warning after exiting fullscreen"
+ );
}
);
});
add_task(async function test_fullscreen_pointerlock_conflict() {
- await SpecialPowers.pushPrefEnv({
- set: [
- ["full-screen-api.enabled", true],
- ["full-screen-api.allow-trusted-requests-only", false],
- ],
- });
-
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let fsWarning = document.getElementById("fullscreen-warning");
let plWarning = document.getElementById("pointerlock-warning");
- is(
- fsWarning.getAttribute("onscreen"),
- null,
- "Should not show full screen warning initially."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning initially."
- );
-
- let fsWarningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
fsWarning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
+ );
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning initially"
);
+ let fsWarningShownPromise = waitForWarningState(fsWarning, "onscreen");
info("Entering full screen and pointer lock.");
await SpecialPowers.spawn(browser, [], async () => {
await content.document.body.requestFullscreen();
@@ -94,15 +111,10 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
});
await fsWarningShownPromise;
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should show full screen warning."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
info("Exiting pointerlock");
@@ -110,18 +122,19 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
await content.document.exitPointerLock();
});
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should still show full screen warning."
+ checkWarningState(
+ fsWarning,
+ "onscreen",
+ "Should still show full screen warning"
);
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
// Cleanup
+ info("Exiting fullscreen");
await document.exitFullscreen();
});
});
=====================================
dom/tests/browser/browser_pointerlock_warning.js
=====================================
@@ -15,6 +15,25 @@ const FRAME_TEST_URL =
encodeURI(BODY_URL) +
'"></iframe></body>';
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
// Make sure the pointerlock warning is shown and exited with the escape key
add_task(async function show_pointerlock_warning_escape() {
let urls = [TEST_URL, FRAME_TEST_URL];
@@ -24,11 +43,7 @@ add_task(async function show_pointerlock_warning_escape() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let warning = document.getElementById("pointerlock-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
- warning,
- "true"
- );
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
let expectedWarningText;
@@ -49,11 +64,7 @@ add_task(async function show_pointerlock_warning_escape() {
ok(true, "Pointerlock warning shown");
- let warningHiddenPromise = BrowserTestUtils.waitForAttribute(
- "hidden",
- warning,
- ""
- );
+ let warningHiddenPromise = waitForWarningState(warning, "hidden");
await BrowserTestUtils.waitForCondition(
() => warning.innerText == expectedWarningText,
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/93ef5b…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/93ef5b…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-115.0.2esr-13.0-1] 2 commits: Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
by richard (@richard) 31 Jul '23
by richard (@richard) 31 Jul '23
31 Jul '23
richard pushed to branch tor-browser-115.0.2esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
6a6c68cf by Edgar Chen at 2023-07-31T17:56:02+00:00
Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
Fullscreen/PointerLock warnings are initialized with hidden="true", but
change to hidden="" after being shown and hidden again. I think this
started happening when we began using HTML elements instead of XUL as
they handle hidden attribute differently.
Differential Revision: https://phabricator.services.mozilla.com/D177790
- - - - -
5e8c1b08 by Edgar Chen at 2023-07-31T17:56:07+00:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
- - - - -
4 changed files:
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/base/content/fullscreen-and-pointerlock.inc.xhtml
- browser/base/content/test/fullscreen/browser_fullscreen_warning.js
- dom/tests/browser/browser_pointerlock_warning.js
Changes:
=====================================
browser/base/content/browser-fullScreenAndPointerLock.js
=====================================
@@ -62,9 +62,14 @@ var PointerlockFsWarning = {
this._element = document.getElementById(elementId);
// Setup event listeners
this._element.addEventListener("transitionend", this);
+ this._element.addEventListener("transitioncancel", this);
window.addEventListener("mousemove", this, true);
+ window.addEventListener("activate", this);
+ window.addEventListener("deactivate", this);
// The timeout to hide the warning box after a while.
this._timeoutHide = new this.Timeout(() => {
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
this._state = "hidden";
}, timeout);
// The timeout to show the warning box when the pointer is at the top
@@ -116,11 +121,10 @@ var PointerlockFsWarning = {
return;
}
- // Explicitly set the last state to hidden to avoid the warning
- // box being hidden immediately because of mousemove.
- this._state = "onscreen";
- this._lastState = "hidden";
- this._timeoutHide.start();
+ if (Services.focus.activeWindow == window) {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ }
},
/**
@@ -148,7 +152,10 @@ var PointerlockFsWarning = {
this._element.hidden = true;
// Remove all event listeners
this._element.removeEventListener("transitionend", this);
+ this._element.removeEventListener("transitioncancel", this);
window.removeEventListener("mousemove", this, true);
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
// Clear fields
this._element = null;
this._timeoutHide = null;
@@ -186,7 +193,7 @@ var PointerlockFsWarning = {
}
if (newState != "hidden") {
if (currentState != "hidden") {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
} else {
// When the previous state is hidden, the display was none,
// thus no box was constructed. We need to wait for the new
@@ -197,7 +204,7 @@ var PointerlockFsWarning = {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (this._element) {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
}
});
});
@@ -217,7 +224,7 @@ var PointerlockFsWarning = {
} else if (this._timeoutShow.delay >= 0) {
this._timeoutShow.start();
}
- } else {
+ } else if (state != "onscreen") {
let elemRect = this._element.getBoundingClientRect();
if (state == "hiding" && this._lastState != "hidden") {
// If we are on the hiding transition, and the pointer
@@ -239,12 +246,23 @@ var PointerlockFsWarning = {
}
break;
}
- case "transitionend": {
+ case "transitionend":
+ case "transitioncancel": {
if (this._state == "hiding") {
this._element.hidden = true;
}
break;
}
+ case "activate": {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ break;
+ }
+ case "deactivate": {
+ this._state = "hidden";
+ this._timeoutHide.cancel();
+ break;
+ }
}
},
};
=====================================
browser/base/content/fullscreen-and-pointerlock.inc.xhtml
=====================================
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<html:div id="fullscreen-and-pointerlock-wrapper">
- <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
@@ -20,7 +20,7 @@
</html:button>
</html:div>
- <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
=====================================
browser/base/content/test/fullscreen/browser_fullscreen_warning.js
=====================================
@@ -3,14 +3,35 @@
"use strict";
-add_task(async function test_fullscreen_display_none() {
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
+add_setup(async function init() {
await SpecialPowers.pushPrefEnv({
set: [
["full-screen-api.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
],
});
+});
+add_task(async function test_fullscreen_display_none() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
@@ -30,11 +51,13 @@ add_task(async function test_fullscreen_display_none() {
},
async function (browser) {
let warning = document.getElementById("fullscreen-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
warning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
);
+
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
// Enter fullscreen
await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
@@ -54,39 +77,33 @@ add_task(async function test_fullscreen_display_none() {
);
document.getElementById("fullscreen-exit-button").click();
await exitFullscreenPromise;
+
+ checkWarningState(
+ warning,
+ "hidden",
+ "Should hide fullscreen warning after exiting fullscreen"
+ );
}
);
});
add_task(async function test_fullscreen_pointerlock_conflict() {
- await SpecialPowers.pushPrefEnv({
- set: [
- ["full-screen-api.enabled", true],
- ["full-screen-api.allow-trusted-requests-only", false],
- ],
- });
-
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let fsWarning = document.getElementById("fullscreen-warning");
let plWarning = document.getElementById("pointerlock-warning");
- is(
- fsWarning.getAttribute("onscreen"),
- null,
- "Should not show full screen warning initially."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning initially."
- );
-
- let fsWarningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
fsWarning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
+ );
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning initially"
);
+ let fsWarningShownPromise = waitForWarningState(fsWarning, "onscreen");
info("Entering full screen and pointer lock.");
await SpecialPowers.spawn(browser, [], async () => {
await content.document.body.requestFullscreen();
@@ -94,15 +111,10 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
});
await fsWarningShownPromise;
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should show full screen warning."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
info("Exiting pointerlock");
@@ -110,18 +122,19 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
await content.document.exitPointerLock();
});
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should still show full screen warning."
+ checkWarningState(
+ fsWarning,
+ "onscreen",
+ "Should still show full screen warning"
);
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
// Cleanup
+ info("Exiting fullscreen");
await document.exitFullscreen();
});
});
=====================================
dom/tests/browser/browser_pointerlock_warning.js
=====================================
@@ -15,6 +15,25 @@ const FRAME_TEST_URL =
encodeURI(BODY_URL) +
'"></iframe></body>';
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
// Make sure the pointerlock warning is shown and exited with the escape key
add_task(async function show_pointerlock_warning_escape() {
let urls = [TEST_URL, FRAME_TEST_URL];
@@ -24,11 +43,7 @@ add_task(async function show_pointerlock_warning_escape() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let warning = document.getElementById("pointerlock-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
- warning,
- "true"
- );
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
let expectedWarningText;
@@ -49,11 +64,7 @@ add_task(async function show_pointerlock_warning_escape() {
ok(true, "Pointerlock warning shown");
- let warningHiddenPromise = BrowserTestUtils.waitForAttribute(
- "hidden",
- warning,
- ""
- );
+ let warningHiddenPromise = waitForWarningState(warning, "hidden");
await BrowserTestUtils.waitForCondition(
() => warning.innerText == expectedWarningText,
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/93ef5b…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/93ef5b…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][base-browser-115.0.2esr-13.0-1] 2 commits: Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
by richard (@richard) 31 Jul '23
by richard (@richard) 31 Jul '23
31 Jul '23
richard pushed to branch base-browser-115.0.2esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
60fefea4 by Edgar Chen at 2023-07-31T17:56:34+00:00
Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
Fullscreen/PointerLock warnings are initialized with hidden="true", but
change to hidden="" after being shown and hidden again. I think this
started happening when we began using HTML elements instead of XUL as
they handle hidden attribute differently.
Differential Revision: https://phabricator.services.mozilla.com/D177790
- - - - -
524c7622 by Edgar Chen at 2023-07-31T17:56:38+00:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
- - - - -
4 changed files:
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/base/content/fullscreen-and-pointerlock.inc.xhtml
- browser/base/content/test/fullscreen/browser_fullscreen_warning.js
- dom/tests/browser/browser_pointerlock_warning.js
Changes:
=====================================
browser/base/content/browser-fullScreenAndPointerLock.js
=====================================
@@ -62,9 +62,14 @@ var PointerlockFsWarning = {
this._element = document.getElementById(elementId);
// Setup event listeners
this._element.addEventListener("transitionend", this);
+ this._element.addEventListener("transitioncancel", this);
window.addEventListener("mousemove", this, true);
+ window.addEventListener("activate", this);
+ window.addEventListener("deactivate", this);
// The timeout to hide the warning box after a while.
this._timeoutHide = new this.Timeout(() => {
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
this._state = "hidden";
}, timeout);
// The timeout to show the warning box when the pointer is at the top
@@ -116,11 +121,10 @@ var PointerlockFsWarning = {
return;
}
- // Explicitly set the last state to hidden to avoid the warning
- // box being hidden immediately because of mousemove.
- this._state = "onscreen";
- this._lastState = "hidden";
- this._timeoutHide.start();
+ if (Services.focus.activeWindow == window) {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ }
},
/**
@@ -148,7 +152,10 @@ var PointerlockFsWarning = {
this._element.hidden = true;
// Remove all event listeners
this._element.removeEventListener("transitionend", this);
+ this._element.removeEventListener("transitioncancel", this);
window.removeEventListener("mousemove", this, true);
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
// Clear fields
this._element = null;
this._timeoutHide = null;
@@ -186,7 +193,7 @@ var PointerlockFsWarning = {
}
if (newState != "hidden") {
if (currentState != "hidden") {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
} else {
// When the previous state is hidden, the display was none,
// thus no box was constructed. We need to wait for the new
@@ -197,7 +204,7 @@ var PointerlockFsWarning = {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (this._element) {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
}
});
});
@@ -217,7 +224,7 @@ var PointerlockFsWarning = {
} else if (this._timeoutShow.delay >= 0) {
this._timeoutShow.start();
}
- } else {
+ } else if (state != "onscreen") {
let elemRect = this._element.getBoundingClientRect();
if (state == "hiding" && this._lastState != "hidden") {
// If we are on the hiding transition, and the pointer
@@ -239,12 +246,23 @@ var PointerlockFsWarning = {
}
break;
}
- case "transitionend": {
+ case "transitionend":
+ case "transitioncancel": {
if (this._state == "hiding") {
this._element.hidden = true;
}
break;
}
+ case "activate": {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ break;
+ }
+ case "deactivate": {
+ this._state = "hidden";
+ this._timeoutHide.cancel();
+ break;
+ }
}
},
};
=====================================
browser/base/content/fullscreen-and-pointerlock.inc.xhtml
=====================================
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<html:div id="fullscreen-and-pointerlock-wrapper">
- <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
@@ -20,7 +20,7 @@
</html:button>
</html:div>
- <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
=====================================
browser/base/content/test/fullscreen/browser_fullscreen_warning.js
=====================================
@@ -3,14 +3,35 @@
"use strict";
-add_task(async function test_fullscreen_display_none() {
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
+add_setup(async function init() {
await SpecialPowers.pushPrefEnv({
set: [
["full-screen-api.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
],
});
+});
+add_task(async function test_fullscreen_display_none() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
@@ -30,11 +51,13 @@ add_task(async function test_fullscreen_display_none() {
},
async function (browser) {
let warning = document.getElementById("fullscreen-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
warning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
);
+
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
// Enter fullscreen
await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
@@ -54,39 +77,33 @@ add_task(async function test_fullscreen_display_none() {
);
document.getElementById("fullscreen-exit-button").click();
await exitFullscreenPromise;
+
+ checkWarningState(
+ warning,
+ "hidden",
+ "Should hide fullscreen warning after exiting fullscreen"
+ );
}
);
});
add_task(async function test_fullscreen_pointerlock_conflict() {
- await SpecialPowers.pushPrefEnv({
- set: [
- ["full-screen-api.enabled", true],
- ["full-screen-api.allow-trusted-requests-only", false],
- ],
- });
-
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let fsWarning = document.getElementById("fullscreen-warning");
let plWarning = document.getElementById("pointerlock-warning");
- is(
- fsWarning.getAttribute("onscreen"),
- null,
- "Should not show full screen warning initially."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning initially."
- );
-
- let fsWarningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
fsWarning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
+ );
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning initially"
);
+ let fsWarningShownPromise = waitForWarningState(fsWarning, "onscreen");
info("Entering full screen and pointer lock.");
await SpecialPowers.spawn(browser, [], async () => {
await content.document.body.requestFullscreen();
@@ -94,15 +111,10 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
});
await fsWarningShownPromise;
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should show full screen warning."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
info("Exiting pointerlock");
@@ -110,18 +122,19 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
await content.document.exitPointerLock();
});
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should still show full screen warning."
+ checkWarningState(
+ fsWarning,
+ "onscreen",
+ "Should still show full screen warning"
);
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
// Cleanup
+ info("Exiting fullscreen");
await document.exitFullscreen();
});
});
=====================================
dom/tests/browser/browser_pointerlock_warning.js
=====================================
@@ -15,6 +15,25 @@ const FRAME_TEST_URL =
encodeURI(BODY_URL) +
'"></iframe></body>';
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
// Make sure the pointerlock warning is shown and exited with the escape key
add_task(async function show_pointerlock_warning_escape() {
let urls = [TEST_URL, FRAME_TEST_URL];
@@ -24,11 +43,7 @@ add_task(async function show_pointerlock_warning_escape() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let warning = document.getElementById("pointerlock-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
- warning,
- "true"
- );
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
let expectedWarningText;
@@ -49,11 +64,7 @@ add_task(async function show_pointerlock_warning_escape() {
ok(true, "Pointerlock warning shown");
- let warningHiddenPromise = BrowserTestUtils.waitForAttribute(
- "hidden",
- warning,
- ""
- );
+ let warningHiddenPromise = waitForWarningState(warning, "hidden");
await BrowserTestUtils.waitForCondition(
() => warning.innerText == expectedWarningText,
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/f3faeb…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/f3faeb…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-102.14.0esr-12.5-1] 2 commits: Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
by richard (@richard) 31 Jul '23
by richard (@richard) 31 Jul '23
31 Jul '23
richard pushed to branch tor-browser-102.14.0esr-12.5-1 at The Tor Project / Applications / Tor Browser
Commits:
f70fa908 by Edgar Chen at 2023-07-28T23:08:31+02:00
Bug 1821884 - Ensure consistent state for fullscreen/pointerlock warnings; r=Gijs
Fullscreen/PointerLock warnings are initialized with hidden="true", but
change to hidden="" after being shown and hidden again. I think this
started happening when we began using HTML elements instead of XUL as
they handle hidden attribute differently.
Differential Revision: https://phabricator.services.mozilla.com/D177790
- - - - -
d27c6a1b by Edgar Chen at 2023-07-28T23:09:46+02:00
Bug 1821884 - Reshow initial fullscreen notification; r=Gijs
Depends on D177790
Differential Revision: https://phabricator.services.mozilla.com/D178339
- - - - -
4 changed files:
- browser/base/content/browser-fullScreenAndPointerLock.js
- browser/base/content/fullscreen-and-pointerlock.inc.xhtml
- browser/base/content/test/fullscreen/browser_fullscreen_warning.js
- dom/tests/browser/browser_pointerlock_warning.js
Changes:
=====================================
browser/base/content/browser-fullScreenAndPointerLock.js
=====================================
@@ -62,9 +62,14 @@ var PointerlockFsWarning = {
this._element = document.getElementById(elementId);
// Setup event listeners
this._element.addEventListener("transitionend", this);
+ this._element.addEventListener("transitioncancel", this);
window.addEventListener("mousemove", this, true);
+ window.addEventListener("activate", this);
+ window.addEventListener("deactivate", this);
// The timeout to hide the warning box after a while.
this._timeoutHide = new this.Timeout(() => {
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
this._state = "hidden";
}, timeout);
// The timeout to show the warning box when the pointer is at the top
@@ -116,11 +121,10 @@ var PointerlockFsWarning = {
return;
}
- // Explicitly set the last state to hidden to avoid the warning
- // box being hidden immediately because of mousemove.
- this._state = "onscreen";
- this._lastState = "hidden";
- this._timeoutHide.start();
+ if (Services.focus.activeWindow == window) {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ }
},
/**
@@ -148,7 +152,10 @@ var PointerlockFsWarning = {
this._element.hidden = true;
// Remove all event listeners
this._element.removeEventListener("transitionend", this);
+ this._element.removeEventListener("transitioncancel", this);
window.removeEventListener("mousemove", this, true);
+ window.removeEventListener("activate", this);
+ window.removeEventListener("deactivate", this);
// Clear fields
this._element = null;
this._timeoutHide = null;
@@ -186,7 +193,7 @@ var PointerlockFsWarning = {
}
if (newState != "hidden") {
if (currentState != "hidden") {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
} else {
// When the previous state is hidden, the display was none,
// thus no box was constructed. We need to wait for the new
@@ -197,7 +204,7 @@ var PointerlockFsWarning = {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
if (this._element) {
- this._element.setAttribute(newState, true);
+ this._element.setAttribute(newState, "");
}
});
});
@@ -217,7 +224,7 @@ var PointerlockFsWarning = {
} else if (this._timeoutShow.delay >= 0) {
this._timeoutShow.start();
}
- } else {
+ } else if (state != "onscreen") {
let elemRect = this._element.getBoundingClientRect();
if (state == "hiding" && this._lastState != "hidden") {
// If we are on the hiding transition, and the pointer
@@ -239,12 +246,23 @@ var PointerlockFsWarning = {
}
break;
}
- case "transitionend": {
+ case "transitionend":
+ case "transitioncancel": {
if (this._state == "hiding") {
this._element.hidden = true;
}
break;
}
+ case "activate": {
+ this._state = "onscreen";
+ this._timeoutHide.start();
+ break;
+ }
+ case "deactivate": {
+ this._state = "hidden";
+ this._timeoutHide.cancel();
+ break;
+ }
}
},
};
=====================================
browser/base/content/fullscreen-and-pointerlock.inc.xhtml
=====================================
@@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<html:div id="fullscreen-and-pointerlock-wrapper">
- <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="fullscreen-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
@@ -20,7 +20,7 @@
</html:button>
</html:div>
- <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="true">
+ <html:div id="pointerlock-warning" class="pointerlockfswarning" hidden="">
<html:div class="pointerlockfswarning-domain-text">
<html:span class="pointerlockfswarning-domain" data-l10n-name="domain"/>
</html:div>
=====================================
browser/base/content/test/fullscreen/browser_fullscreen_warning.js
=====================================
@@ -3,14 +3,35 @@
"use strict";
-add_task(async function test_fullscreen_display_none() {
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
+add_setup(async function init() {
await SpecialPowers.pushPrefEnv({
set: [
["full-screen-api.enabled", true],
["full-screen-api.allow-trusted-requests-only", false],
],
});
+});
+add_task(async function test_fullscreen_display_none() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
@@ -30,11 +51,13 @@ add_task(async function test_fullscreen_display_none() {
},
async function(browser) {
let warning = document.getElementById("fullscreen-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
warning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
);
+
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
// Enter fullscreen
await SpecialPowers.spawn(browser, [], async () => {
let frame = content.document.querySelector("iframe");
@@ -54,39 +77,33 @@ add_task(async function test_fullscreen_display_none() {
);
document.getElementById("fullscreen-exit-button").click();
await exitFullscreenPromise;
+
+ checkWarningState(
+ warning,
+ "hidden",
+ "Should hide fullscreen warning after exiting fullscreen"
+ );
}
);
});
add_task(async function test_fullscreen_pointerlock_conflict() {
- await SpecialPowers.pushPrefEnv({
- set: [
- ["full-screen-api.enabled", true],
- ["full-screen-api.allow-trusted-requests-only", false],
- ],
- });
-
await BrowserTestUtils.withNewTab("https://example.com", async browser => {
let fsWarning = document.getElementById("fullscreen-warning");
let plWarning = document.getElementById("pointerlock-warning");
- is(
- fsWarning.getAttribute("onscreen"),
- null,
- "Should not show full screen warning initially."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning initially."
- );
-
- let fsWarningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
+ checkWarningState(
fsWarning,
- "true"
+ "hidden",
+ "Should not show full screen warning initially"
+ );
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning initially"
);
+ let fsWarningShownPromise = waitForWarningState(fsWarning, "onscreen");
info("Entering full screen and pointer lock.");
await SpecialPowers.spawn(browser, [], async () => {
await content.document.body.requestFullscreen();
@@ -94,15 +111,10 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
});
await fsWarningShownPromise;
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should show full screen warning."
- );
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
info("Exiting pointerlock");
@@ -110,18 +122,19 @@ add_task(async function test_fullscreen_pointerlock_conflict() {
await content.document.exitPointerLock();
});
- is(
- fsWarning.getAttribute("onscreen"),
- "true",
- "Should still show full screen warning."
+ checkWarningState(
+ fsWarning,
+ "onscreen",
+ "Should still show full screen warning"
);
- is(
- plWarning.getAttribute("onscreen"),
- null,
- "Should not show pointer lock warning."
+ checkWarningState(
+ plWarning,
+ "hidden",
+ "Should not show pointer lock warning"
);
// Cleanup
+ info("Exiting fullscreen");
await document.exitFullscreen();
});
});
=====================================
dom/tests/browser/browser_pointerlock_warning.js
=====================================
@@ -15,6 +15,25 @@ const FRAME_TEST_URL =
encodeURI(BODY_URL) +
'"></iframe></body>';
+function checkWarningState(aWarningElement, aExpectedState, aMsg) {
+ ["hidden", "ontop", "onscreen"].forEach(state => {
+ is(
+ aWarningElement.hasAttribute(state),
+ state == aExpectedState,
+ `${aMsg} - check ${state} attribute.`
+ );
+ });
+}
+
+async function waitForWarningState(aWarningElement, aExpectedState) {
+ await BrowserTestUtils.waitForAttribute(aExpectedState, aWarningElement, "");
+ checkWarningState(
+ aWarningElement,
+ aExpectedState,
+ `Wait for ${aExpectedState} state`
+ );
+}
+
// Make sure the pointerlock warning is shown and exited with the escape key
add_task(async function show_pointerlock_warning_escape() {
let urls = [TEST_URL, FRAME_TEST_URL];
@@ -24,11 +43,7 @@ add_task(async function show_pointerlock_warning_escape() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let warning = document.getElementById("pointerlock-warning");
- let warningShownPromise = BrowserTestUtils.waitForAttribute(
- "onscreen",
- warning,
- "true"
- );
+ let warningShownPromise = waitForWarningState(warning, "onscreen");
let expectedWarningText;
@@ -49,11 +64,7 @@ add_task(async function show_pointerlock_warning_escape() {
ok(true, "Pointerlock warning shown");
- let warningHiddenPromise = BrowserTestUtils.waitForAttribute(
- "hidden",
- warning,
- ""
- );
+ let warningHiddenPromise = waitForWarningState(warning, "hidden");
await BrowserTestUtils.waitForCondition(
() => warning.innerText == expectedWarningText,
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/855b69…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/855b69…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-115.1.0esr-13.0-1] fixup! Bug 40597: Implement TorSettings module
by richard (@richard) 27 Jul '23
by richard (@richard) 27 Jul '23
27 Jul '23
richard pushed to branch tor-browser-115.1.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
f0493f9f by Pier Angelo Vendrame at 2023-07-27T18:20:08+00:00
fixup! Bug 40597: Implement TorSettings module
Bug 41907: Change state after the process becomes ready only when we
are in the initial state.
- - - - -
1 changed file:
- browser/modules/TorConnect.jsm
Changes:
=====================================
browser/modules/TorConnect.jsm
=====================================
@@ -874,6 +874,18 @@ const TorConnect = (() => {
switch (topic) {
/* We need to wait until TorSettings have been loaded and applied before we can Quickstart */
case TorSettingsTopics.Ready: {
+ // tor-browser#41907: This is only a workaround to avoid users being
+ // bounced back to the initial panel without any explanation.
+ // Longer term we should disable the clickable elements, or find a UX
+ // to prevent this from happening (e.g., allow buttons to be clicked,
+ // but show an intermediate starting state, or a message that tor is
+ // starting while the butons are disabled, etc...).
+ if (this.state !== TorConnectState.Initial) {
+ console.warn(
+ "TorConnect: Seen the torsettings:ready after the state has already changed, ignoring the notification."
+ );
+ break;
+ }
if (this.shouldQuickStart) {
// Quickstart
this._changeState(TorConnectState.Bootstrapping);
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/f0493f9…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/f0493f9…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-115.1.0esr-13.0-1] 7 commits: fixup! Bug 40933: Add tor-launcher functionality
by richard (@richard) 27 Jul '23
by richard (@richard) 27 Jul '23
27 Jul '23
richard pushed to branch tor-browser-115.1.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
66229717 by Pier Angelo Vendrame at 2023-07-27T18:11:55+02:00
fixup! Bug 40933: Add tor-launcher functionality
Bug 41844: Added a couple of wrappers for Onion Auth on
TorProtocolService.
- - - - -
2cde9fc3 by Pier Angelo Vendrame at 2023-07-27T18:11:56+02:00
fixup! Bug 30237: Add v3 onion services client authentication prompt
Bug 41844: Stop using the control port directly
- - - - -
b2cd0ee8 by Pier Angelo Vendrame at 2023-07-27T18:11:57+02:00
fixup! Bug 40933: Add tor-launcher functionality
Small improvements on event registration.
- - - - -
26152fa9 by Pier Angelo Vendrame at 2023-07-27T18:11:57+02:00
fixup! Bug 40933: Add tor-launcher functionality
Bug 41844: Do not use a the control port directly.
Collect the bridge node for the about:preferences#connection page in
TorMonitorService.
Also, move parts of the circuit display to TorMonitorService and
TorProtocolService.
- - - - -
749aeaca by Pier Angelo Vendrame at 2023-07-27T18:11:58+02:00
fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
Bug 41844: Do not use the control port directly
Do not use the controller in the settings frontend.
Instead, let TorMonitorService collect the first node's fingerprint.
- - - - -
20641450 by Pier Angelo Vendrame at 2023-07-27T18:11:58+02:00
fixup! Bug 3455: Add DomainIsolator, for isolating circuit by domain.
Bug 41844: Do not use the control port directly.
Use TorDomainIsolator also as a backend for the circuit display.
- - - - -
1a8be7b1 by Pier Angelo Vendrame at 2023-07-27T18:11:59+02:00
fixup! Bug 41600: Add a tor circuit display panel.
Bug 41844: Have a separate backend for the tor circuits
Remove the backend stuff from the circuit display.
- - - - -
11 changed files:
- browser/base/content/browser.js
- browser/components/onionservices/content/authPrompt.js
- browser/components/onionservices/content/savedKeysDialog.js
- browser/components/torcircuit/content/torCircuitPanel.js
- browser/components/torpreferences/content/connectionPane.js
- toolkit/components/tor-launcher/TorDomainIsolator.jsm → toolkit/components/tor-launcher/TorDomainIsolator.sys.mjs
- toolkit/components/tor-launcher/TorMonitorService.sys.mjs
- toolkit/components/tor-launcher/TorParsers.sys.mjs
- toolkit/components/tor-launcher/TorProtocolService.sys.mjs
- toolkit/components/tor-launcher/TorStartupService.sys.mjs
- toolkit/components/tor-launcher/moz.build
Changes:
=====================================
browser/base/content/browser.js
=====================================
@@ -66,6 +66,7 @@ ChromeUtils.defineESModuleGetters(this, {
TabsSetupFlowManager:
"resource:///modules/firefox-view-tabs-setup-manager.sys.mjs",
TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.sys.mjs",
+ TorDomainIsolator: "resource://gre/modules/TorDomainIsolator.sys.mjs",
TranslationsParent: "resource://gre/actors/TranslationsParent.sys.mjs",
UITour: "resource:///modules/UITour.sys.mjs",
UpdateUtils: "resource://gre/modules/UpdateUtils.sys.mjs",
@@ -100,7 +101,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
TorConnect: "resource:///modules/TorConnect.jsm",
TorConnectState: "resource:///modules/TorConnect.jsm",
TorConnectTopics: "resource:///modules/TorConnect.jsm",
- TorDomainIsolator: "resource://gre/modules/TorDomainIsolator.jsm",
Translation: "resource:///modules/translation/TranslationParent.jsm",
webrtcUI: "resource:///modules/webrtcUI.jsm",
ZoomUI: "resource:///modules/ZoomUI.jsm",
=====================================
browser/components/onionservices/content/authPrompt.js
=====================================
@@ -7,6 +7,7 @@
XPCOMUtils.defineLazyModuleGetters(this, {
OnionAuthUtil: "chrome://browser/content/onionservices/authUtil.jsm",
CommonUtils: "resource://services-common/utils.js",
+ TorProtocolService: "resource://gre/modules/TorProtocolService.jsm",
TorStrings: "resource:///modules/TorStrings.jsm",
});
@@ -192,10 +193,6 @@ const OnionAuthPrompt = (function () {
let controllerFailureMsg =
TorStrings.onionServices.authPrompt.failedToSetKey;
try {
- let { controller } = ChromeUtils.import(
- "resource://torbutton/modules/tor-control-port.js"
- );
- let torController = await controller();
// ^(subdomain.)*onionserviceid.onion$ (case-insensitive)
const onionServiceIdRegExp =
/^(.*\.)*(?<onionServiceId>[a-z2-7]{56})\.onion$/i;
@@ -206,8 +203,7 @@ const OnionAuthPrompt = (function () {
let checkboxElem = this._getCheckboxElement();
let isPermanent = checkboxElem && checkboxElem.checked;
- torController
- .onionAuthAdd(onionServiceId, base64key, isPermanent)
+ TorProtocolService.onionAuthAdd(onionServiceId, base64key, isPermanent)
.then(aResponse => {
// Success! Reload the page.
this._browser.sendMessageToActor(
=====================================
browser/components/onionservices/content/savedKeysDialog.js
=====================================
@@ -10,8 +10,8 @@ ChromeUtils.defineModuleGetter(
ChromeUtils.defineModuleGetter(
this,
- "controller",
- "resource://torbutton/modules/tor-control-port.js"
+ "TorProtocolService",
+ "resource://gre/modules/TorProtocolService.jsm"
);
var gOnionServicesSavedKeysDialog = {
@@ -49,11 +49,9 @@ var gOnionServicesSavedKeysDialog = {
const controllerFailureMsg =
TorStrings.onionServices.authPreferences.failedToRemoveKey;
try {
- const torController = await controller();
-
// Remove in reverse index order to avoid issues caused by index changes.
for (let i = indexesToDelete.length - 1; i >= 0; --i) {
- await this._deleteOneKey(torController, indexesToDelete[i]);
+ await this._deleteOneKey(indexesToDelete[i]);
}
} catch (e) {
if (e.torMessage) {
@@ -127,8 +125,7 @@ var gOnionServicesSavedKeysDialog = {
try {
this._tree.view = this;
- const torController = await controller();
- const keyInfoList = await torController.onionAuthViewKeys();
+ const keyInfoList = await TorProtocolService.onionAuthViewKeys();
if (keyInfoList) {
// Filter out temporary keys.
this._keyInfoList = keyInfoList.filter(aKeyInfo => {
@@ -165,9 +162,9 @@ var gOnionServicesSavedKeysDialog = {
},
// This method may throw; callers should catch errors.
- async _deleteOneKey(aTorController, aIndex) {
+ async _deleteOneKey(aIndex) {
const keyInfoObj = this._keyInfoList[aIndex];
- await aTorController.onionAuthRemove(keyInfoObj.hsAddress);
+ await TorProtocolService.onionAuthRemove(keyInfoObj.hsAddress);
this._tree.view.selection.clearRange(aIndex, aIndex);
this._keyInfoList.splice(aIndex, 1);
this._tree.rowCountChanged(aIndex + 1, -1);
=====================================
browser/components/torcircuit/content/torCircuitPanel.js
=====================================
@@ -1,18 +1,5 @@
/* eslint-env mozilla/browser-window */
-/**
- * Stores the data associated with a circuit node.
- *
- * @typedef NodeData
- * @property {string[]} ipAddrs - The ip addresses associated with this node.
- * @property {string?} bridgeType - The bridge type for this node, or "" if the
- * node is a bridge but the type is unknown, or null if this is not a bridge
- * node.
- * @property {string?} regionCode - An upper case 2-letter ISO3166-1 code for
- * the first ip address, or null if there is no region. This should also be a
- * valid BCP47 Region subtag.
- */
-
/**
* Data about the current domain and circuit for a xul:browser.
*
@@ -35,29 +22,6 @@ var gTorCircuitPanel = {
* @type {Element}
*/
toolbarButton: null,
- /**
- * A list of IDs for "mature" circuits (those that have conveyed a stream).
- *
- * @type {string[]}
- */
- _knownCircuitIDs: [],
- /**
- * Stores the circuit nodes for each SOCKS username/password pair. The keys
- * are of the form "<username>|<password>".
- *
- * @type {Map<string, NodeData[]>}
- */
- _credentialsToCircuitNodes: new Map(),
- /**
- * Browser data for their currently shown page.
- *
- * This data may be stale for a given browser since we only update this data
- * when loading a new page in the currently selected browser, when switching
- * tabs, or if we find a new circuit for the current browser.
- *
- * @type {WeakMap<MozBrowser, BrowserCircuitData>}
- */
- _browserData: new WeakMap(),
/**
* The data for the currently shown browser.
*
@@ -71,6 +35,13 @@ var gTorCircuitPanel = {
*/
_isActive: false,
+ /**
+ * The topic on which circuit changes are broadcast.
+ *
+ * @type {string}
+ */
+ TOR_CIRCUIT_TOPIC: "TorCircuitChange",
+
/**
* Initialize the panel.
*/
@@ -86,31 +57,6 @@ var gTorCircuitPanel = {
maxLogLevelPref: "browser.torcircuitpanel.loglevel",
});
- const { wait_for_controller } = ChromeUtils.import(
- "resource://torbutton/modules/tor-control-port.js"
- );
- wait_for_controller().then(
- controller => {
- if (!this._isActive) {
- // uninit() was called before resolution.
- return;
- }
- // FIXME: We should be using some dedicated integrated back end to
- // store circuit information, rather than collecting it all here in the
- // front end. See tor-browser#41700.
- controller.watchEvent(
- "STREAM",
- streamEvent => streamEvent.StreamStatus === "SENTCONNECT",
- streamEvent => this._collectCircuit(controller, streamEvent)
- );
- },
- error => {
- this._log.error(
- `Not collecting circuits because of an error: ${error.message}`
- );
- }
- );
-
this.panel = document.getElementById("tor-circuit-panel");
this._panelElements = {
heading: document.getElementById("tor-circuit-heading"),
@@ -245,6 +191,9 @@ var gTorCircuitPanel = {
// Notified of new locations for the currently selected browser (tab) *and*
// switching selected browser.
gBrowser.addProgressListener(this._locationListener);
+
+ // Get notifications for circuit changes.
+ Services.obs.addObserver(this, this.TOR_CIRCUIT_TOPIC);
},
/**
@@ -253,6 +202,17 @@ var gTorCircuitPanel = {
uninit() {
this._isActive = false;
gBrowser.removeProgressListener(this._locationListener);
+ Services.obs.removeObserver(this, this.TOR_CIRCUIT_TOPIC);
+ },
+
+ /**
+ * Observe circuit changes.
+ */
+ observe(subject, topic, data) {
+ if (topic === this.TOR_CIRCUIT_TOPIC) {
+ // TODO: Maybe check if we actually need to do something earlier.
+ this._updateCurrentBrowser();
+ }
},
/**
@@ -286,109 +246,6 @@ var gTorCircuitPanel = {
window.openWebLinkIn(this._panelElements.aliasLink.href, where);
},
- /**
- * Collect circuit data for the found circuits, to be used later for display.
- *
- * @param {controller} controller - The tor controller.
- * @param {object} streamEvent - The streamEvent for the new circuit.
- */
- async _collectCircuit(controller, streamEvent) {
- const id = streamEvent.CircuitID;
- if (this._knownCircuitIDs.includes(id)) {
- return;
- }
- this._log.debug(`New streamEvent.CircuitID: ${id}.`);
- // FIXME: This list grows and is never freed. See tor-browser#41700.
- this._knownCircuitIDs.push(id);
- const circuitStatus = (await controller.getInfo("circuit-status"))?.find(
- circuit => circuit.id === id
- );
- if (!circuitStatus?.SOCKS_USERNAME || !circuitStatus?.SOCKS_PASSWORD) {
- return;
- }
- const nodes = await Promise.all(
- circuitStatus.circuit.map(names =>
- this._nodeDataForCircuit(controller, names)
- )
- );
- // Remove quotes from the strings.
- const username = circuitStatus.SOCKS_USERNAME.replace(/^"(.*)"$/, "$1");
- const password = circuitStatus.SOCKS_PASSWORD.replace(/^"(.*)"$/, "$1");
- const credentials = `${username}|${password}`;
- // FIXME: This map grows and is never freed. We cannot simply request this
- // information when needed because it is no longer available once the
- // circuit is dropped, even if the web page is still displayed.
- // See tor-browser#41700.
- this._credentialsToCircuitNodes.set(credentials, nodes);
- // Update the circuit in case the current page gains a new circuit whilst
- // the popup is still open.
- this._updateCurrentBrowser(credentials);
- },
-
- /**
- * Fetch the node data for the given circuit node.
- *
- * @param {controller} controller - The tor controller.
- * @param {string[]} circuitNodeNames - The names for the circuit node. Only
- * the first name, the node id, will be used.
- *
- * @returns {NodeData} - The data for this circuit node.
- */
- async _nodeDataForCircuit(controller, circuitNodeNames) {
- // The first "name" in circuitNodeNames is the id.
- // Remove the leading '$' if present.
- const id = circuitNodeNames[0].replace(/^\$/, "");
- let result = { ipAddrs: [], bridgeType: null, regionCode: null };
- const bridge = (await controller.getConf("bridge"))?.find(
- foundBridge => foundBridge.ID?.toUpperCase() === id.toUpperCase()
- );
- const addrRe = /^\[?([^\]]+)\]?:\d+$/;
- if (bridge) {
- result.bridgeType = bridge.type ?? "";
- // Attempt to get an IP address from bridge address string.
- const ip = bridge.address.match(addrRe)?.[1];
- if (ip && !ip.startsWith("0.")) {
- result.ipAddrs.push(ip);
- }
- } else {
- // Either dealing with a relay, or a bridge whose fingerprint is not saved
- // in torrc.
- let statusMap;
- try {
- statusMap = await controller.getInfo("ns/id/" + id);
- } catch {
- // getInfo will throw if the given id is not a relay.
- // This probably means we are dealing with a user-provided bridge with
- // no fingerprint.
- // We don't know the ip/ipv6 or type, so leave blank.
- result.bridgeType = "";
- return result;
- }
- if (statusMap.IP && !statusMap.IP.startsWith("0.")) {
- result.ipAddrs.push(statusMap.IP);
- }
- const ip6 = statusMap.IPv6?.match(addrRe)?.[1];
- if (ip6) {
- result.ipAddrs.push(ip6);
- }
- }
- if (result.ipAddrs.length) {
- // Get the country code for the node's IP address.
- let regionCode;
- try {
- // Expect a 2-letter ISO3166-1 code, which should also be a valid BCP47
- // Region subtag.
- regionCode = await controller.getInfo(
- "ip-to-country/" + result.ipAddrs[0]
- );
- } catch {}
- if (regionCode && regionCode !== "??") {
- result.regionCode = regionCode.toUpperCase();
- }
- }
- return result;
- },
-
/**
* A list of schemes to never show the circuit display for.
*
@@ -398,71 +255,50 @@ var gTorCircuitPanel = {
*
* @type {string[]}
*/
- // FIXME: Have a back end that handles this instead. See tor-browser#41700.
+ // FIXME: Check if we find a UX to handle some of these cases, and if we
+ // manage to solve some technical issues.
+ // See tor-browser#41700 and tor-browser!699.
_ignoredSchemes: ["about", "file", "chrome", "resource"],
/**
* Update the current circuit and domain data for the currently selected
* browser, possibly changing the UI.
- *
- * @param {string?} [matchingCredentials=null] - If given, only update the
- * current browser data if the current browser's credentials match.
*/
- _updateCurrentBrowser(matchingCredentials = null) {
+ _updateCurrentBrowser() {
const browser = gBrowser.selectedBrowser;
const domain = TorDomainIsolator.getDomainForBrowser(browser);
+ const nodes = TorDomainIsolator.getCircuit(
+ browser,
+ domain,
+ browser.contentPrincipal.originAttributes.userContextId
+ );
// We choose the currentURI, which matches what is shown in the URL bar and
// will match up with the domain.
// In contrast, documentURI corresponds to the shown page. E.g. it could
// point to "about:certerror".
const scheme = browser.currentURI?.scheme;
- let credentials = TorDomainIsolator.getSocksProxyCredentials(
- domain,
- browser.contentPrincipal.originAttributes.userContextId
- );
- if (credentials) {
- credentials = `${credentials.username}|${credentials.password}`;
- }
-
- if (matchingCredentials && matchingCredentials !== credentials) {
- // This update was triggered by the circuit update for some other browser
- // or process.
- return;
- }
-
- let nodes = this._credentialsToCircuitNodes.get(credentials) ?? [];
-
- const prevData = this._browserData.get(browser);
- if (
- prevData &&
- prevData.domain &&
- prevData.domain === domain &&
- prevData.scheme === scheme &&
- prevData.nodes.length &&
- !nodes.length
- ) {
- // Since this is the same domain, for the same browser, and we used to
- // have circuit nodes, we *assume* we are re-generating a circuit. So we
- // keep the old circuit data around for the time being.
- // FIXME: Have a back end that makes this explicit, rather than an
- // assumption. See tor-browser#41700.
- nodes = prevData.nodes;
- this._log.debug(`Keeping old circuit for ${domain}.`);
- }
-
- this._browserData.set(browser, { domain, scheme, nodes });
if (
this._currentBrowserData &&
this._currentBrowserData.domain === domain &&
this._currentBrowserData.scheme === scheme &&
- this._currentBrowserData.nodes === nodes
+ this._currentBrowserData.nodes.length === nodes.length &&
+ // If non-null, the fingerprints of the nodes match.
+ (!nodes ||
+ nodes.every(
+ (n, index) =>
+ n.fingerprint === this._currentBrowserData.nodes[index].fingerprint
+ ))
) {
// No change.
+ this._log.debug(
+ "Skipping browser update because the data is already up to date."
+ );
return;
}
- this._currentBrowserData = this._browserData.get(browser);
+ this._currentBrowserData = { domain, scheme, nodes };
+ this._log.debug("Updating current browser.", this._currentBrowserData);
if (
// Schemes where we always want to hide the display.
=====================================
browser/components/torpreferences/content/connectionPane.js
=====================================
@@ -17,6 +17,9 @@ const { TorSettings, TorSettingsTopics, TorSettingsData, TorBridgeSource } =
const { TorProtocolService } = ChromeUtils.import(
"resource://gre/modules/TorProtocolService.jsm"
);
+const { TorMonitorService, TorMonitorTopics } = ChromeUtils.import(
+ "resource://gre/modules/TorMonitorService.jsm"
+);
const { TorConnect, TorConnectTopics, TorConnectState, TorCensorshipLevel } =
ChromeUtils.import("resource:///modules/TorConnect.jsm");
@@ -144,8 +147,6 @@ const gConnectionPane = (function () {
_internetStatus: InternetStatus.Unknown,
- _controller: null,
-
_currentBridgeId: null,
// populate xul with strings and cache the relevant elements
@@ -727,9 +728,10 @@ const gConnectionPane = (function () {
};
// Use a promise to avoid blocking the population of the page
// FIXME: Stop using a JSON file, and switch to properties
- fetch(
+ const annotationPromise = fetch(
"chrome://browser/content/torpreferences/bridgemoji/annotations.json"
- ).then(async res => {
+ );
+ annotationPromise.then(async res => {
const annotations = await res.json();
const bcp47 = Services.locale.appLocaleAsBCP47;
const dash = bcp47.indexOf("-");
@@ -749,6 +751,7 @@ const gConnectionPane = (function () {
".currently-connected"
)) {
card.classList.remove("currently-connected");
+ card.querySelector(selectors.bridges.cardQrGrid).style.height = "";
}
if (!this._currentBridgeId) {
return;
@@ -769,72 +772,17 @@ const gConnectionPane = (function () {
placeholder.replaceWith(...cards);
this._checkBridgeCardsHeight();
};
- try {
- const { controller } = ChromeUtils.import(
- "resource://torbutton/modules/tor-control-port.js"
- );
- // Avoid the cache because we set our custom event watcher, and at the
- // moment, watchers cannot be removed from a controller.
- controller(true).then(aController => {
- this._controller = aController;
- // Getting the circuits may be enough, if we have bootstrapped for a
- // while, but at the beginning it gives many bridges as connected,
- // because tor pokes all the bridges to find the best one.
- // Also, watching circuit events does not work, at the moment, but in
- // any case, checking the stream has the advantage that we can see if
- // it really used for a connection, rather than tor having created
- // this circuit to check if the bridge can be used. We do this by
- // checking if the stream has SOCKS username, which actually contains
- // the destination of the stream.
- // FIXME: We only know the currentBridge *after* a circuit event, but
- // if the circuit event is sent *before* about:torpreferences is
- // opened we will miss it. Therefore this approach only works if a
- // circuit is created after opening about:torconnect. A dedicated
- // backend outside of about:preferences would help, and could be
- // shared with gTorCircuitPanel. See tor-browser#41700.
- this._controller.watchEvent(
- "STREAM",
- event =>
- event.StreamStatus === "SUCCEEDED" && "SOCKS_USERNAME" in event,
- async event => {
- const circuitStatuses = await this._controller.getInfo(
- "circuit-status"
- );
- if (!circuitStatuses) {
- return;
- }
- for (const status of circuitStatuses) {
- if (status.id === event.CircuitID && status.circuit.length) {
- // The id in the circuit begins with a $ sign.
- const id = status.circuit[0][0].replace(/^\$/, "");
- if (id !== this._currentBridgeId) {
- const bridge = (
- await this._controller.getConf("bridge")
- )?.find(
- foundBridge =>
- foundBridge.ID?.toUpperCase() === id.toUpperCase()
- );
- if (!bridge) {
- // Either there is no bridge, or bridge with no
- // fingerprint.
- this._currentBridgeId = null;
- } else {
- this._currentBridgeId = id;
- }
- this._updateConnectedBridges();
- }
- break;
- }
- }
- }
- );
- });
- } catch (err) {
- console.warn(
- "We could not load torbutton, bridge statuses will not be updated",
- err
- );
- }
+ this._checkConnectedBridge = () => {
+ // TODO: We could make sure TorSettings is in sync by monitoring also
+ // changes of settings. At that point, we could query it, instead of
+ // doing a query over the control port.
+ const bridge = TorMonitorService.currentBridge;
+ if (bridge?.fingerprint !== this._currentBridgeId) {
+ this._currentBridgeId = bridge?.fingerprint ?? null;
+ this._updateConnectedBridges();
+ }
+ };
+ annotationPromise.then(this._checkConnectedBridge.bind(this));
// Add a new bridge
prefpane.querySelector(selectors.bridges.addHeader).textContent =
@@ -927,6 +875,7 @@ const gConnectionPane = (function () {
});
Services.obs.addObserver(this, TorConnectTopics.StateChange);
+ Services.obs.addObserver(this, TorMonitorTopics.BridgeChanged);
},
init() {
@@ -950,11 +899,7 @@ const gConnectionPane = (function () {
// unregister our observer topics
Services.obs.removeObserver(this, TorSettingsTopics.SettingChanged);
Services.obs.removeObserver(this, TorConnectTopics.StateChange);
-
- if (this._controller !== null) {
- this._controller.close();
- this._controller = null;
- }
+ Services.obs.removeObserver(this, TorMonitorTopics.BridgeChanged);
},
// whether the page should be present in about:preferences
@@ -985,6 +930,12 @@ const gConnectionPane = (function () {
this.onStateChange();
break;
}
+ case TorMonitorTopics.BridgeChanged: {
+ if (data?.fingerprint !== this._currentBridgeId) {
+ this._checkConnectedBridge();
+ }
+ break;
+ }
}
},
@@ -1028,7 +979,7 @@ const gConnectionPane = (function () {
onRemoveAllBridges() {
TorSettings.bridges.enabled = false;
TorSettings.bridges.bridge_strings = "";
- if (TorSettings.bridges.source == TorBridgeSource.BuiltIn) {
+ if (TorSettings.bridges.source === TorBridgeSource.BuiltIn) {
TorSettings.bridges.builtin_type = "";
}
TorSettings.saveToPrefs();
=====================================
toolkit/components/tor-launcher/TorDomainIsolator.jsm → toolkit/components/tor-launcher/TorDomainIsolator.sys.mjs
=====================================
@@ -1,13 +1,14 @@
-// A component for Tor Browser that puts requests from different
-// first party domains on separate Tor circuits.
-
-var EXPORTED_SYMBOLS = ["TorDomainIsolator"];
+/**
+ * A component for Tor Browser that puts requests from different first party
+ * domains on separate Tor circuits.
+ */
-const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const { XPCOMUtils } = ChromeUtils.import(
- "resource://gre/modules/XPCOMUtils.jsm"
-);
-const { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm");
+import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
+import { ConsoleAPI } from "resource://gre/modules/Console.sys.mjs";
+import {
+ clearInterval,
+ setInterval,
+} from "resource://gre/modules/Timer.sys.mjs";
const lazy = {};
@@ -18,11 +19,10 @@ XPCOMUtils.defineLazyServiceGetters(lazy, {
],
});
-ChromeUtils.defineModuleGetter(
- lazy,
- "TorProtocolService",
- "resource://gre/modules/TorProtocolService.jsm"
-);
+ChromeUtils.defineESModuleGetters(lazy, {
+ TorMonitorTopics: "resource://gre/modules/TorMonitorService.sys.mjs",
+ TorProtocolService: "resource://gre/modules/TorProtocolService.sys.mjs",
+});
const logger = new ConsoleAPI({
prefix: "TorDomainIsolator",
@@ -33,6 +33,12 @@ const logger = new ConsoleAPI({
// The string to use instead of the domain when it is not known.
const CATCHALL_DOMAIN = "--unknown--";
+// The maximum lifetime for the catch-all circuit in milliseconds.
+// When the catch-all circuit is needed, we check if more than this amount of
+// time has passed since we last changed it nonce, and in case we change it
+// again.
+const CATCHALL_MAX_LIFETIME = 600_000;
+
// The preference to observe, to know whether isolation should be enabled or
// disabled.
const NON_TOR_PROXY_PREF = "extensions.torbutton.use_nontor_proxy";
@@ -40,23 +46,92 @@ const NON_TOR_PROXY_PREF = "extensions.torbutton.use_nontor_proxy";
// The topic of new identity, to observe to cleanup all the nonces.
const NEW_IDENTITY_TOPIC = "new-identity-requested";
+// The topic on which we broacast circuit change notifications.
+const TOR_CIRCUIT_TOPIC = "TorCircuitChange";
+
+// We have an interval to delete circuits that are not reclaimed by any browser.
+const CLEAR_TIMEOUT = 600_000;
+
+/**
+ * @typedef {string} CircuitId A string that we use to identify a circuit.
+ * Currently, it is a string that combines SOCKS credentials, to make it easier
+ * to use as a map key.
+ * It is not related to Tor's CircuitIDs.
+ */
+/**
+ * @typedef {number} BrowserId
+ */
+/**
+ * @typedef {NodeData[]} CircuitData The data about the nodes, ordered from
+ * guard (or bridge) to exit.
+ */
+/**
+ * @typedef BrowserCircuits Circuits related to a certain combination of
+ * isolators (first-party domain and user context ID, currently).
+ * @property {CircuitId} current The id of the last known circuit that has been
+ * used to fetch data for the isolated context.
+ * @property {CircuitId?} pending The id of the last used circuit for this
+ * isolation context. We might or might not know data about it, yet. But if we
+ * know it, we should move this id into current.
+ */
+
class TorDomainIsolatorImpl {
- // A mutable map that records what nonce we are using for each domain.
+ /**
+ * A mutable map that records what nonce we are using for each domain.
+ *
+ * @type {Map<string, string>}
+ */
#noncesForDomains = new Map();
- // A mutable map that records what nonce we are using for each tab container.
+ /**
+ * A mutable map that records what nonce we are using for each tab container.
+ *
+ * @type {Map<string, string>}
+ */
#noncesForUserContextId = new Map();
- // A bool that controls if we use SOCKS auth for isolation or not.
+ /**
+ * Tell whether we use SOCKS auth for isolation or not.
+ *
+ * @type {boolean}
+ */
#isolationEnabled = true;
- // Specifies when the current catch-all circuit was first used
+ /**
+ * Specifies when the current catch-all circuit was first used.
+ *
+ * @type {integer}
+ */
#catchallDirtySince = Date.now();
+ /**
+ * A map that associates circuit ids to the circuit information.
+ *
+ * @type {Map<CircuitId, CircuitData>}
+ */
+ #knownCircuits = new Map();
+
+ /**
+ * A map that associates a certain browser to all the circuits it used or it
+ * is going to use.
+ * The circuits are keyed on the SOCKS username, which we take for granted
+ * being a combination of the first-party domain and the user context id.
+ *
+ * @type {Map<BrowserId, Map<string, BrowserCircuits>>}
+ */
+ #browsers = new Map();
+
+ /**
+ * The handle of the interval we use to cleanup old circuit data.
+ *
+ * @type {number?}
+ */
+ #cleanupIntervalId = null;
+
/**
* Initialize the domain isolator.
- * This function will setup the proxy filter that injects the credentials and
- * register some observers.
+ * This function will setup the proxy filter that injects the credentials,
+ * register some observers, and setup the cleaning interval.
*/
init() {
logger.info("Setup circuit isolation by domain and user context");
@@ -68,14 +143,25 @@ class TorDomainIsolatorImpl {
Services.prefs.addObserver(NON_TOR_PROXY_PREF, this);
Services.obs.addObserver(this, NEW_IDENTITY_TOPIC);
+ Services.obs.addObserver(this, lazy.TorMonitorTopics.StreamSucceeded);
+
+ this.#cleanupIntervalId = setInterval(
+ this.#clearKnownCircuits.bind(this),
+ CLEAR_TIMEOUT
+ );
}
/**
- * Removes the observers added in the initialization.
+ * Removes the observers added in the initialization and stops the cleaning
+ * interval.
*/
uninit() {
Services.prefs.removeObserver(NON_TOR_PROXY_PREF, this);
Services.obs.removeObserver(this, NEW_IDENTITY_TOPIC);
+ Services.obs.removeObserver(this, lazy.TorMonitorTopics.StreamSucceeded);
+ clearInterval(this.#cleanupIntervalId);
+ this.#cleanupIntervalId = null;
+ this.clearIsolation();
}
enable() {
@@ -89,52 +175,52 @@ class TorDomainIsolatorImpl {
}
/**
- * Return the credentials to use as username and password for the SOCKS proxy,
- * given a certain domain and userContextId. Optionally, create them.
+ * Get the last circuit used in a certain browser.
+ * The returned data is created when the circuit is first seen, therefore it
+ * could be stale (i.e., the circuit might not be available anymore).
*
- * @param {string} firstPartyDomain The first party domain associated to the requests
- * @param {string} userContextId The context ID associated to the request
- * @param {bool} create Whether to create the nonce, if it is not available
- * @returns {object|null} Either the credential, or null if we do not have them and create is
- * false.
+ * @param {MozBrowser} browser The browser to get data for
+ * @param {string} domain The first party domain we want to get the circuit
+ * for
+ * @param {number} userContextId The user context domain we want to get the
+ * circuit for
+ * @returns {NodeData[]} The node data, or an empty array if we do not have
+ * data for the requested key.
*/
- getSocksProxyCredentials(firstPartyDomain, userContextId, create = false) {
- if (!this.#noncesForDomains.has(firstPartyDomain)) {
- if (!create) {
- return null;
- }
- const nonce = this.#nonce();
- logger.info(`New nonce for first party ${firstPartyDomain}: ${nonce}`);
- this.#noncesForDomains.set(firstPartyDomain, nonce);
+ getCircuit(browser, domain, userContextId) {
+ const username = this.#makeUsername(domain, userContextId);
+ const circuits = this.#browsers.get(browser.browserId)?.get(username);
+ // This is the only place where circuit data can go out, so the only place
+ // where it makes a difference to check whether the pending circuit is still
+ // pending, or it has actually got data.
+ const pending = this.#knownCircuits.get(circuits?.pending);
+ if (pending?.length) {
+ circuits.current = circuits.pending;
+ circuits.pending = null;
+ return pending;
}
- if (!this.#noncesForUserContextId.has(userContextId)) {
- if (!create) {
- return null;
- }
- const nonce = this.#nonce();
- logger.info(`New nonce for userContextId ${userContextId}: ${nonce}`);
- this.#noncesForUserContextId.set(userContextId, nonce);
- }
- return {
- username: this.#makeUsername(firstPartyDomain, userContextId),
- password:
- this.#noncesForDomains.get(firstPartyDomain) +
- this.#noncesForUserContextId.get(userContextId),
- };
+ // TODO: At this point we already know if we expect a circuit change for
+ // this key: (circuit?.pending && !pending). However, we do not consume this
+ // data yet in the frontend, so do not send it for now.
+ return this.#knownCircuits.get(circuits?.current) ?? [];
}
/**
* Create a new nonce for the FP domain of the selected browser and reload the
* tab with a new circuit.
*
- * @param {object} browser Should be the gBrowser from the context of the
- * caller
+ * @param {object} globalBrowser Should be the gBrowser from the context of
+ * the caller
*/
- newCircuitForBrowser(browser) {
- const firstPartyDomain = getDomainForBrowser(browser.selectedBrowser);
+ newCircuitForBrowser(globalBrowser) {
+ const browser = globalBrowser.selectedBrowser;
+ const firstPartyDomain = getDomainForBrowser(browser);
this.#newCircuitForDomain(firstPartyDomain);
- // TODO: How to properly handle the user context? Should we use
- // (domain, userContextId) pairs, instead of concatenating nonces?
+ const { username, password } = this.#getSocksProxyCredentials(
+ firstPartyDomain,
+ browser.contentPrincipal.originAttributes.userContextId
+ );
+ this.#trackBrowser(browser, username, password);
browser.reloadWithFlags(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE);
}
@@ -147,12 +233,15 @@ class TorDomainIsolatorImpl {
// Per-domain and per contextId nonces are stored in maps, so simply clear
// them.
+ // Notice that the catch-all circuit is included in #noncesForDomains, so we
+ // are implicilty cleaning it. Should this change, we should change its
+ // nonce explicitly here.
this.#noncesForDomains.clear();
this.#noncesForUserContextId.clear();
+ this.#catchallDirtySince = Date.now();
- // Force a rotation on the next catch-all circuit use by setting the
- // creation time to the epoch.
- this.#catchallDirtySince = 0;
+ this.#knownCircuits.clear();
+ this.#browsers.clear();
}
async observe(subject, topic, data) {
@@ -173,55 +262,20 @@ class TorDomainIsolatorImpl {
logger.error("Could not send the newnym command", e);
// TODO: What UX to use here? See tor-browser#41708
}
+ } else if (topic === lazy.TorMonitorTopics.StreamSucceeded) {
+ const { username, password, circuit } = subject.wrappedJSObject;
+ this.#updateCircuit(username, password, circuit);
}
}
/**
- * Setup a filter that for every HTTPChannel, replaces the default SOCKS proxy
- * with one that authenticates to the SOCKS server (the tor client process)
- * with a username (the first party domain and userContextId) and a nonce
- * password.
- * Tor provides a separate circuit for each username+password combination.
+ * Setup a filter that for every HTTPChannel.
*/
#setupProxyFilter() {
- const filterFunction = (aChannel, aProxy) => {
- if (!this.#isolationEnabled) {
- return aProxy;
- }
- try {
- const channel = aChannel.QueryInterface(Ci.nsIChannel);
- let firstPartyDomain =
- channel.loadInfo.originAttributes.firstPartyDomain;
- const userContextId = channel.loadInfo.originAttributes.userContextId;
- if (firstPartyDomain === "") {
- firstPartyDomain = CATCHALL_DOMAIN;
- if (Date.now() - this.#catchallDirtySince > 1000 * 10 * 60) {
- logger.info(
- "tor catchall circuit has been dirty for over 10 minutes. Rotating."
- );
- this.#newCircuitForDomain(CATCHALL_DOMAIN);
- this.#catchallDirtySince = Date.now();
- }
- }
- const replacementProxy = this.#applySocksProxyCredentials(
- aProxy,
- firstPartyDomain,
- userContextId
- );
- logger.debug(
- `Requested ${channel.URI.spec} via ${replacementProxy.username}:${replacementProxy.password}`
- );
- return replacementProxy;
- } catch (e) {
- logger.error("Error while setting a new proxy", e);
- return null;
- }
- };
-
lazy.ProtocolProxyService.registerChannelFilter(
{
- applyFilter(aChannel, aProxy, aCallback) {
- aCallback.onProxyFilterResult(filterFunction(aChannel, aProxy));
+ applyFilter: (aChannel, aProxy, aCallback) => {
+ aCallback.onProxyFilterResult(this.#proxyFilter(aChannel, aProxy));
},
},
0
@@ -229,33 +283,96 @@ class TorDomainIsolatorImpl {
}
/**
- * Takes a proxyInfo object (originalProxy) and returns a new proxyInfo
- * object with the same properties, except the username is set to the
- * the domain and userContextId, and the password is a nonce.
+ * Replaces the default SOCKS proxy with one that authenticates to the SOCKS
+ * server (the tor client process) with a username (the first party domain and
+ * userContextId) and a nonce password.
+ * Tor provides a separate circuit for each username+password combination.
+ *
+ * @param {nsIChannel} aChannel The channel we are setting the proxy for
+ * @param {nsIProxyInfo} aProxy The original proxy
+ * @returns {nsIProxyInfo} The new proxy to use
*/
- #applySocksProxyCredentials(originalProxy, domain, userContextId) {
- const proxy = originalProxy.QueryInterface(Ci.nsIProxyInfo);
- const { username, password } = this.getSocksProxyCredentials(
- domain,
- userContextId,
- true
- );
- return lazy.ProtocolProxyService.newProxyInfoWithAuth(
- "socks",
- proxy.host,
- proxy.port,
- username,
- password,
- "", // aProxyAuthorizationHeader
- "", // aConnectionIsolationKey
- proxy.flags,
- proxy.failoverTimeout,
- proxy.failoverProxy
- );
+ #proxyFilter(aChannel, aProxy) {
+ if (!this.#isolationEnabled) {
+ return aProxy;
+ }
+ try {
+ const channel = aChannel.QueryInterface(Ci.nsIChannel);
+ let firstPartyDomain = channel.loadInfo.originAttributes.firstPartyDomain;
+ const userContextId = channel.loadInfo.originAttributes.userContextId;
+ if (!firstPartyDomain) {
+ firstPartyDomain = CATCHALL_DOMAIN;
+ if (Date.now() - this.#catchallDirtySince > CATCHALL_MAX_LIFETIME) {
+ logger.info(
+ "tor catchall circuit has reached its maximum lifetime. Rotating."
+ );
+ this.#newCircuitForDomain(CATCHALL_DOMAIN);
+ }
+ }
+ const { username, password } = this.#getSocksProxyCredentials(
+ firstPartyDomain,
+ userContextId
+ );
+ const browser = this.#getBrowserForChannel(channel);
+ if (browser) {
+ this.#trackBrowser(browser, username, password);
+ }
+ logger.debug(`Requested ${channel.URI.spec} via ${username}:${password}`);
+ const proxy = aProxy.QueryInterface(Ci.nsIProxyInfo);
+ return lazy.ProtocolProxyService.newProxyInfoWithAuth(
+ "socks",
+ proxy.host,
+ proxy.port,
+ username,
+ password,
+ "", // aProxyAuthorizationHeader
+ "", // aConnectionIsolationKey
+ proxy.flags,
+ proxy.failoverTimeout,
+ proxy.failoverProxy
+ );
+ } catch (e) {
+ logger.error("Error while setting a new proxy", e);
+ return null;
+ }
+ }
+
+ /**
+ * Return the credentials to use as username and password for the SOCKS proxy,
+ * given a certain domain and userContextId.
+ * A new random password will be created if not available yet.
+ *
+ * @param {string} firstPartyDomain The first party domain associated to the
+ * requests
+ * @param {number} userContextId The context ID associated to the request
+ * @returns {object} The credentials
+ */
+ #getSocksProxyCredentials(firstPartyDomain, userContextId) {
+ if (!this.#noncesForDomains.has(firstPartyDomain)) {
+ const nonce = this.#nonce();
+ logger.info(`New nonce for first party ${firstPartyDomain}: ${nonce}`);
+ this.#noncesForDomains.set(firstPartyDomain, nonce);
+ }
+ if (!this.#noncesForUserContextId.has(userContextId)) {
+ const nonce = this.#nonce();
+ logger.info(`New nonce for userContextId ${userContextId}: ${nonce}`);
+ this.#noncesForUserContextId.set(userContextId, nonce);
+ }
+ // TODO: How to properly handle the user-context? Should we use
+ // (domain, userContextId) pairs, instead of concatenating nonces?
+ return {
+ username: this.#makeUsername(firstPartyDomain, userContextId),
+ password:
+ this.#noncesForDomains.get(firstPartyDomain) +
+ this.#noncesForUserContextId.get(userContextId),
+ };
}
/**
* Combine the needed data into a username for the proxy.
+ *
+ * @param {string} domain The first-party domain associated to the request
+ * @param {integer} userContextId The userContextId associated to the request
*/
#makeUsername(domain, userContextId) {
if (!domain) {
@@ -264,12 +381,26 @@ class TorDomainIsolatorImpl {
return `${domain}:${userContextId}`;
}
+ /**
+ * Combine SOCKS username and password into a string to use as ID.
+ *
+ * @param {string} username The SOCKS username
+ * @param {string} password The SOCKS password
+ * @returns {CircuitId} A string that combines username and password and can
+ * be used for map lookups.
+ */
+ #credentialsToId(username, password) {
+ return `${username}|${password}`;
+ }
+
/**
* Generate a new 128 bit random tag.
*
* Strictly speaking both using a cryptographic entropy source and using 128
* bits of entropy for the tag are likely overkill, as correct behavior only
* depends on how unlikely it is for there to be a collision.
+ *
+ * @returns {string} The random nonce
*/
#nonce() {
return Array.from(crypto.getRandomValues(new Uint8Array(16)), byte =>
@@ -279,12 +410,18 @@ class TorDomainIsolatorImpl {
/**
* Re-generate the nonce for a certain domain.
+ *
+ * @param {string?} domain The first-party domain to re-create the nonce for.
+ * If empty or null, the catchall domain will be used.
*/
#newCircuitForDomain(domain) {
if (!domain) {
domain = CATCHALL_DOMAIN;
}
this.#noncesForDomains.set(domain, this.#nonce());
+ if (domain === CATCHALL_DOMAIN) {
+ this.#catchallDirtySince = Date.now();
+ }
logger.info(
`New domain isolation for ${domain}: ${this.#noncesForDomains.get(
domain
@@ -296,6 +433,8 @@ class TorDomainIsolatorImpl {
* Re-generate the nonce for a userContextId.
*
* Currently, this function is not hooked to anything.
+ *
+ * @param {integer} userContextId The userContextId to re-create the nonce for
*/
#newCircuitForUserContextId(userContextId) {
this.#noncesForUserContextId.set(userContextId, this.#nonce());
@@ -305,13 +444,182 @@ class TorDomainIsolatorImpl {
)}`
);
}
+
+ /**
+ * Try to extract a browser from a channel.
+ *
+ * @param {nsIChannel} channel The channel to extract the browser from
+ * @returns {MozBrowser?} The browser the channel is associated to
+ */
+ #getBrowserForChannel(channel) {
+ const browsers =
+ channel.loadInfo.browsingContext?.topChromeWindow?.gBrowser.browsers;
+ if (!browsers || !channel.loadInfo.browsingContext?.browserId) {
+ return null;
+ }
+ for (const browser of browsers) {
+ if (browser.browserId === channel.loadInfo.browsingContext.browserId) {
+ logger.debug(
+ "Matched browser with browserId",
+ channel.loadInfo.browsingContext.browserId
+ );
+ return browser;
+ }
+ }
+ // Expected to arrive here for example for the update checker.
+ // If we find a way to check that, we could raise the level to a warn.
+ logger.debug("Browser not matched", channel);
+ return null;
+ }
+
+ /**
+ * Associate the SOCKS credentials to a browser.
+ * If needed (the browser is associated for the first time, or it was already
+ * known but its credential changed), notify the related circuit display.
+ *
+ * @param {MozBrowser} browser The browser to track
+ * @param {string} username The SOCKS username
+ * @param {string} password The SOCKS password
+ */
+ #trackBrowser(browser, username, password) {
+ let browserCircuits = this.#browsers.get(browser.browserId);
+ if (!browserCircuits) {
+ browserCircuits = new Map();
+ this.#browsers.set(browser.browserId, browserCircuits);
+ }
+ const circuitIds = browserCircuits.get(username) ?? {};
+ const id = this.#credentialsToId(username, password);
+ if (circuitIds.current === id) {
+ // The circuit with these credentials was already built (we already knew
+ // its nodes, or we would not have promoted it to the current circuit).
+ // We do not need to do anything else, because we cannot detect a change
+ // of nodes here.
+ return;
+ }
+
+ logger.debug(
+ `Found new credentials ${username} ${password} for browser`,
+ browser
+ );
+ const circuit = this.#knownCircuits.get(id);
+ if (circuit?.length) {
+ circuitIds.current = id;
+ if (circuitIds.pending === id) {
+ circuitIds.pending = null;
+ }
+ browserCircuits.set(username, circuitIds);
+ // FIXME: We only notify the circuit display when we have a change that
+ // involves circuits whose nodes are known, for now. We need to resolve a
+ // few other techical problems (e.g., associate the circuit to the
+ // document?) and develop a UX with some animation to notify the circuit
+ // display more often.
+ // See tor-browser#41700 and tor-browser!699.
+ // In any case, notify the circuit display only after the internal map has
+ // been updated.
+ this.#notifyCircuitDisplay();
+ } else if (circuitIds.pending !== id) {
+ // We do not have node data, so we store that we might need to track this.
+ // Otherwise, when a circuit is ready, we do not know which browser was it
+ // used for.
+ circuitIds.pending = id;
+ browserCircuits.set(username, circuitIds);
+ }
+ }
+
+ /**
+ * Update a circuit, and notify the related circuit displays if it changed.
+ *
+ * This function is called when a certain stream has succeeded and so we can
+ * associate its SOCKS credential to the circuit it is using.
+ * We receive only the fingerprints of the circuit nodes, but they are enough
+ * to check if the circuit has changed. If it has, we also get the nodes'
+ * information through the control port.
+ *
+ * @param {string} username The SOCKS username
+ * @param {string} password The SOCKS password
+ * @param {NodeFingerprint[]} circuit The fingerprints of the nodes that
+ * compose the circuit
+ */
+ async #updateCircuit(username, password, circuit) {
+ const id = this.#credentialsToId(username, password);
+ let data = this.#knownCircuits.get(id) ?? [];
+ // Should we modify the lower layer to send a circuit identifier, instead?
+ if (
+ circuit.length === data.length &&
+ circuit.every((id, index) => id === data[index].fingerprint)
+ ) {
+ return;
+ }
+
+ data = await Promise.all(
+ circuit.map(fingerprint =>
+ lazy.TorProtocolService.getNodeInfo(fingerprint)
+ )
+ );
+ this.#knownCircuits.set(id, data);
+ // We know that something changed, but we cannot know if anyone is
+ // interested in this change. So, we have to notify all the possible
+ // consumers of the data in any case.
+ // Not being specific and let them check if they need to do something allows
+ // us to keep a simpler structure.
+ this.#notifyCircuitDisplay();
+ }
+
+ /**
+ * Broadcast a notification when a circuit changed, or a browser is changing
+ * circuit (which might happen also in case of navigation).
+ */
+ #notifyCircuitDisplay() {
+ Services.obs.notifyObservers(null, TOR_CIRCUIT_TOPIC);
+ }
+
+ /**
+ * Clear the known circuit information, when they are not needed anymore.
+ *
+ * We keep circuit data around for a while. We decouple it from the underlying
+ * tor circuit management in case the user clicks on the circuit display when
+ * circuit has long gone.
+ * However, data accumulate during a session. So, since we store all the
+ * browsers that used a circuit anyway, every now and then we check if we
+ * still know browsers using a certain circuits. If there are not, we forget
+ * about it.
+ *
+ * This function is run by an interval.
+ */
+ #clearKnownCircuits() {
+ logger.info("Running the circuit cleanup");
+ const windows = [];
+ const enumerator = Services.wm.getEnumerator("navigator:browser");
+ while (enumerator.hasMoreElements()) {
+ windows.push(enumerator.getNext());
+ }
+ const browsers = windows
+ .flatMap(win => win.gBrowser.browsers.map(b => b.browserId))
+ .filter(id => this.#browsers.has(id));
+ this.#browsers = new Map(browsers.map(id => [id, this.#browsers.get(id)]));
+ this.#knownCircuits = new Map(
+ Array.from(this.#browsers.values(), circuits =>
+ Array.from(circuits.values(), ids => {
+ const r = [];
+ const current = this.#knownCircuits.get(ids.current);
+ if (current) {
+ r.push([ids.current, current]);
+ }
+ const pending = this.#knownCircuits.get(ids.pending);
+ if (pending) {
+ r.push([ids.pending, pending]);
+ }
+ return r;
+ })
+ ).flat(2)
+ );
+ }
}
/**
* Get the first party domain for a certain browser.
*
- * @param browser The browser to get the FP-domain for.
- *
+ * @param {MozBrowser} browser The browser to get the FP-domain for.
* Please notice that it should be gBrowser.selectedBrowser, because
* browser.documentURI is the actual shown page, and might be an error page.
* In this case, we rely on currentURI, which for gBrowser is an alias of
@@ -358,6 +666,6 @@ function getDomainForBrowser(browser) {
return fpd;
}
-const TorDomainIsolator = new TorDomainIsolatorImpl();
+export const TorDomainIsolator = new TorDomainIsolatorImpl();
// Reduce global vars pollution
TorDomainIsolator.getDomainForBrowser = getDomainForBrowser;
=====================================
toolkit/components/tor-launcher/TorMonitorService.sys.mjs
=====================================
@@ -19,6 +19,10 @@ ChromeUtils.defineModuleGetter(
"resource://torbutton/modules/tor-control-port.js"
);
+ChromeUtils.defineESModuleGetters(lazy, {
+ TorProtocolService: "resource://gre/modules/TorProtocolService.sys.mjs",
+});
+
const logger = new ConsoleAPI({
maxLogLevel: "warn",
maxLogLevelPref: "browser.tor_monitor_service.log_level",
@@ -37,12 +41,34 @@ const TorTopics = Object.freeze({
ProcessRestarted: "TorProcessRestarted",
});
+export const TorMonitorTopics = Object.freeze({
+ BridgeChanged: "TorBridgeChanged",
+ StreamSucceeded: "TorStreamSucceeded",
+});
+
const ControlConnTimings = Object.freeze({
initialDelayMS: 25, // Wait 25ms after the process has started, before trying to connect
maxRetryMS: 10000, // Retry at most every 10 seconds
timeoutMS: 5 * 60 * 1000, // Wait at most 5 minutes for tor to start
});
+/**
+ * From control-spec.txt:
+ * CircuitID = 1*16 IDChar
+ * IDChar = ALPHA / DIGIT
+ * Currently, Tor only uses digits, but this may change.
+ *
+ * @typedef {string} CircuitID
+ */
+/**
+ * The fingerprint of a node.
+ * From control-spec.txt:
+ * Fingerprint = "$" 40*HEXDIG
+ * However, we do not keep the $ in our structures.
+ *
+ * @typedef {string} NodeFingerprint
+ */
+
/**
* This service monitors an existing Tor instance, or starts one, if needed, and
* then starts monitoring it.
@@ -52,7 +78,7 @@ const ControlConnTimings = Object.freeze({
*/
export const TorMonitorService = {
_connection: null,
- _eventsToMonitor: Object.freeze(["STATUS_CLIENT", "NOTICE", "WARN", "ERR"]),
+ _eventHandlers: {},
_torLog: [], // Array of objects with date, type, and msg properties.
_startTimeout: null,
@@ -64,6 +90,28 @@ export const TorMonitorService = {
_inited: false,
+ /**
+ * Stores the nodes of a circuit. Keys are cicuit IDs, and values are the node
+ * fingerprints.
+ *
+ * Theoretically, we could hook this map up to the new identity notification,
+ * but in practice it does not work. Tor pre-builds circuits, and the NEWNYM
+ * signal does not affect them. So, we might end up using a circuit that was
+ * built before the new identity but not yet used. If we cleaned the map, we
+ * risked of not having the data about it.
+ *
+ * @type {Map<CircuitID, NodeFingerprint[]>}
+ */
+ _circuits: new Map(),
+ /**
+ * The last used bridge, or null if bridges are not in use or if it was not
+ * possible to detect the bridge. This needs the user to have specified bridge
+ * lines with fingerprints to work.
+ *
+ * @type {NodeFingerprint?}
+ */
+ _currentBridge: null,
+
// Public methods
// Starts Tor, if needed, and starts monitoring for events
@@ -72,14 +120,28 @@ export const TorMonitorService = {
return;
}
this._inited = true;
+
+ // We always liten to these events, because they are needed for the circuit
+ // display.
+ this._eventHandlers = new Map([
+ ["CIRC", this._processCircEvent.bind(this)],
+ ["STREAM", this._processStreamEvent.bind(this)],
+ ]);
+
if (this.ownsTorDaemon) {
+ // When we own the tor daemon, we listen to more events, that are used
+ // for about:torconnect or for showing the logs in the settings page.
+ this._eventHandlers.set("STATUS_CLIENT", (_eventType, lines) =>
+ this._processBootstrapStatus(lines[0], false)
+ );
+ this._eventHandlers.set("NOTICE", this._processLog.bind(this));
+ this._eventHandlers.set("WARN", this._processLog.bind(this));
+ this._eventHandlers.set("ERR", this._processLog.bind(this));
this._controlTor();
} else {
- logger.info(
- "Not starting the event monitor, as we do not own the Tor daemon."
- );
+ this._startEventMonitor();
}
- logger.debug("TorMonitorService initialized");
+ logger.info("TorMonitorService initialized");
},
// Closes the connection that monitors for events.
@@ -153,6 +215,18 @@ export const TorMonitorService = {
return !!this._connection;
},
+ /**
+ * Return the data about the current bridge, if any, or null.
+ * We can detect bridge only when the configured bridge lines include the
+ * fingerprints.
+ *
+ * @returns {NodeData?} The node information, or null if the first node
+ * is not a bridge, or no circuit has been opened, yet.
+ */
+ get currentBridge() {
+ return this._currentBridge;
+ },
+
// Private methods
async _startProcess() {
@@ -272,7 +346,7 @@ export const TorMonitorService = {
// TODO: optionally monitor INFO and DEBUG log messages.
let reply = await conn.sendCommand(
- "SETEVENTS " + this._eventsToMonitor.join(" ")
+ "SETEVENTS " + Array.from(this._eventHandlers.keys()).join(" ")
);
reply = TorParsers.parseCommandResponse(reply);
if (!TorParsers.commandSucceeded(reply)) {
@@ -281,14 +355,10 @@ export const TorMonitorService = {
return false;
}
- // FIXME: At the moment it is not possible to start the event monitor
- // when we do start the tor process. So, does it make sense to keep this
- // control?
if (this._torProcess) {
this._torProcess.connectionWorked();
}
-
- if (!TorLauncherUtil.shouldOnlyConfigureTor) {
+ if (this.ownsTorDaemon && !TorLauncherUtil.shouldOnlyConfigureTor) {
try {
await this._takeTorOwnership(conn);
} catch (e) {
@@ -297,7 +367,31 @@ export const TorMonitorService = {
}
this._connection = conn;
- this._waitForEventData();
+
+ for (const [type, callback] of this._eventHandlers.entries()) {
+ this._monitorEvent(type, callback);
+ }
+
+ // Populate the circuit map already, in case we are connecting to an
+ // external tor daemon.
+ try {
+ const reply = await this._connection.sendCommand(
+ "GETINFO circuit-status"
+ );
+ const lines = reply.split(/\r?\n/);
+ if (lines.shift() === "250+circuit-status=") {
+ for (const line of lines) {
+ if (line === ".") {
+ break;
+ }
+ // _processCircEvent processes only one line at a time
+ this._processCircEvent("CIRC", [line]);
+ }
+ }
+ } catch (e) {
+ logger.warn("Could not populate the initial circuit map", e);
+ }
+
return true;
},
@@ -318,65 +412,49 @@ export const TorMonitorService = {
}
},
- _waitForEventData() {
- if (!this._connection) {
- return;
- }
- logger.debug("Start watching events:", this._eventsToMonitor);
+ _monitorEvent(type, callback) {
+ logger.info(`Watching events of type ${type}.`);
let replyObj = {};
- for (const torEvent of this._eventsToMonitor) {
- this._connection.watchEvent(
- torEvent,
- null,
- line => {
- if (!line) {
- return;
- }
- logger.debug("Event response: ", line);
- const isComplete = TorParsers.parseReplyLine(line, replyObj);
- if (isComplete) {
- this._processEventReply(replyObj);
- replyObj = {};
- }
- },
- true
- );
- }
+ this._connection.watchEvent(
+ type,
+ null,
+ line => {
+ if (!line) {
+ return;
+ }
+ logger.debug("Event response: ", line);
+ const isComplete = TorParsers.parseReplyLine(line, replyObj);
+ if (!isComplete || replyObj._parseError || !replyObj.lineArray.length) {
+ return;
+ }
+ const reply = replyObj;
+ replyObj = {};
+ if (reply.statusCode !== TorStatuses.EventNotification) {
+ logger.error("Unexpected event status code:", reply.statusCode);
+ return;
+ }
+ if (!reply.lineArray[0].startsWith(`${type} `)) {
+ logger.error("Wrong format for the first line:", reply.lineArray[0]);
+ return;
+ }
+ reply.lineArray[0] = reply.lineArray[0].substring(type.length + 1);
+ try {
+ callback(type, reply.lineArray);
+ } catch (e) {
+ logger.error("Exception while handling an event", reply, e);
+ }
+ },
+ true
+ );
},
- _processEventReply(aReply) {
- if (aReply._parseError || !aReply.lineArray.length) {
- return;
- }
-
- if (aReply.statusCode !== TorStatuses.EventNotification) {
- logger.warn("Unexpected event status code:", aReply.statusCode);
- return;
- }
-
- // TODO: do we need to handle multiple lines?
- const s = aReply.lineArray[0];
- const idx = s.indexOf(" ");
- if (idx === -1) {
- return;
- }
- const eventType = s.substring(0, idx);
- const msg = s.substring(idx + 1).trim();
-
- if (eventType === "STATUS_CLIENT") {
- this._processBootstrapStatus(msg, false);
- return;
- } else if (!this._eventsToMonitor.includes(eventType)) {
- logger.debug(`Dropping unlistened event ${eventType}`);
- return;
- }
-
- if (eventType === "WARN" || eventType === "ERR") {
+ _processLog(type, lines) {
+ if (type === "WARN" || type === "ERR") {
// Notify so that Copy Log can be enabled.
Services.obs.notifyObservers(null, TorTopics.HasWarnOrErr);
}
- const now = new Date();
+ const date = new Date();
const maxEntries = Services.prefs.getIntPref(
"extensions.torlauncher.max_tor_log_entries",
1000
@@ -384,8 +462,10 @@ export const TorMonitorService = {
if (maxEntries > 0 && this._torLog.length >= maxEntries) {
this._torLog.splice(0, 1);
}
- this._torLog.push({ date: now, type: eventType, msg });
- const logString = `Tor ${eventType}: ${msg}`;
+
+ const msg = lines.join("\n");
+ this._torLog.push({ date, type, msg });
+ const logString = `Tor ${type}: ${msg}`;
logger.info(logString);
},
@@ -461,8 +541,108 @@ export const TorMonitorService = {
}
},
+ async _processCircEvent(_type, lines) {
+ const builtEvent =
+ /^(?<CircuitID>[a-zA-Z0-9]{1,16})\sBUILT\s(?<Path>(?:,?\$[0-9a-fA-F]{40}(?:~[a-zA-Z0-9]{1,19})?)+)/.exec(
+ lines[0]
+ );
+ const closedEvent = /^(?<ID>[a-zA-Z0-9]{1,16})\sCLOSED/.exec(lines[0]);
+ if (builtEvent) {
+ const fp = /\$([0-9a-fA-F]{40})/g;
+ const nodes = Array.from(builtEvent.groups.Path.matchAll(fp), g =>
+ g[1].toUpperCase()
+ );
+ this._circuits.set(builtEvent.groups.CircuitID, nodes);
+ // Ignore circuits of length 1, that are used, for example, to probe
+ // bridges. So, only store them, since we might see streams that use them,
+ // but then early-return.
+ if (nodes.length === 1) {
+ return;
+ }
+ // In some cases, we might already receive SOCKS credentials in the line.
+ // However, this might be a problem with onion services: we get also a
+ // 4-hop circuit that we likely do not want to show to the user,
+ // especially because it is used only temporarily, and it would need a
+ // technical explaination.
+ // this._checkCredentials(lines[0], nodes);
+ if (this._currentBridge?.fingerprint !== nodes[0]) {
+ const nodeInfo = await lazy.TorProtocolService.getNodeInfo(nodes[0]);
+ let notify = false;
+ if (nodeInfo?.bridgeType) {
+ logger.info(`Bridge changed to ${nodes[0]}`);
+ this._currentBridge = nodeInfo;
+ notify = true;
+ } else if (this._currentBridge) {
+ logger.info("Bridges disabled");
+ this._currentBridge = null;
+ notify = true;
+ }
+ if (notify) {
+ Services.obs.notifyObservers(
+ null,
+ TorMonitorTopics.BridgeChanged,
+ this._currentBridge
+ );
+ }
+ }
+ } else if (closedEvent) {
+ this._circuits.delete(closedEvent.groups.ID);
+ }
+ },
+
+ _processStreamEvent(_type, lines) {
+ // The first block is the stream ID, which we do not need at the moment.
+ const succeeedEvent =
+ /^[a-zA-Z0-9]{1,16}\sSUCCEEDED\s(?<CircuitID>[a-zA-Z0-9]{1,16})/.exec(
+ lines[0]
+ );
+ if (!succeeedEvent) {
+ return;
+ }
+ const circuit = this._circuits.get(succeeedEvent.groups.CircuitID);
+ if (!circuit) {
+ logger.error(
+ "Seen a STREAM SUCCEEDED with an unknown circuit. Not notifying observers.",
+ lines[0]
+ );
+ return;
+ }
+ this._checkCredentials(lines[0], circuit);
+ },
+
+ /**
+ * Check if a STREAM or CIRC response line contains SOCKS_USERNAME and
+ * SOCKS_PASSWORD. In case, notify observers that we could associate a certain
+ * circuit to these credentials.
+ *
+ * @param {string} line The circ or stream line to check
+ * @param {NodeFingerprint[]} circuit The fingerprints of the nodes in the
+ * circuit.
+ */
+ _checkCredentials(line, circuit) {
+ const username = /SOCKS_USERNAME=("(?:[^"\\]|\\.)*")/.exec(line);
+ const password = /SOCKS_PASSWORD=("(?:[^"\\]|\\.)*")/.exec(line);
+ if (!username || !password) {
+ return;
+ }
+ Services.obs.notifyObservers(
+ {
+ wrappedJSObject: {
+ username: TorParsers.unescapeString(username[1]),
+ password: TorParsers.unescapeString(password[1]),
+ circuit,
+ },
+ },
+ TorMonitorTopics.StreamSucceeded
+ );
+ },
+
_shutDownEventMonitor() {
- this._connection?.close();
+ try {
+ this._connection?.close();
+ } catch (e) {
+ logger.error("Could not close the connection to the control port", e);
+ }
this._connection = null;
if (this._startTimeout !== null) {
clearTimeout(this._startTimeout);
=====================================
toolkit/components/tor-launcher/TorParsers.sys.mjs
=====================================
@@ -181,12 +181,12 @@ export const TorParsers = Object.freeze({
return aStr;
}
const escaped = aStr
- .replace("\\", "\\\\")
- .replace('"', '\\"')
- .replace("\n", "\\n")
- .replace("\r", "\\r")
- .replace("\t", "\\t")
- .replace(/[^\x20-\x7e]+/g, text => {
+ .replaceAll("\\", "\\\\")
+ .replaceAll('"', '\\"')
+ .replaceAll("\n", "\\n")
+ .replaceAll("\r", "\\r")
+ .replaceAll("\t", "\\t")
+ .replaceAll(/[^\x20-\x7e]+/g, text => {
const encoder = new TextEncoder();
return Array.from(
encoder.encode(text),
=====================================
toolkit/components/tor-launcher/TorProtocolService.sys.mjs
=====================================
@@ -40,6 +40,20 @@ const logger = new ConsoleAPI({
prefix: "TorProtocolService",
});
+/**
+ * Stores the data associated with a circuit node.
+ *
+ * @typedef NodeData
+ * @property {string} fingerprint The node fingerprint.
+ * @property {string[]} ipAddrs - The ip addresses associated with this node.
+ * @property {string?} bridgeType - The bridge type for this node, or "" if the
+ * node is a bridge but the type is unknown, or null if this is not a bridge
+ * node.
+ * @property {string?} regionCode - An upper case 2-letter ISO3166-1 code for
+ * the first ip address, or null if there is no region. This should also be a
+ * valid BCP47 Region subtag.
+ */
+
// Manage the connection to tor's control port, to update its settings and query
// other useful information.
//
@@ -188,6 +202,89 @@ export const TorProtocolService = {
return TorParsers.parseReply(cmd, keyword, response);
},
+ async getBridges() {
+ // Ideally, we would not need this function, because we should be the one
+ // setting them with TorSettings. However, TorSettings is not notified of
+ // change of settings. So, asking tor directly with the control connection
+ // is the most reliable way of getting the configured bridges, at the
+ // moment. Also, we are using this for the circuit display, which should
+ // work also when we are not configuring the tor daemon, but just using it.
+ return this._withConnection(conn => {
+ return conn.getConf("bridge");
+ });
+ },
+
+ /**
+ * Returns tha data about a relay or a bridge.
+ *
+ * @param {string} id The fingerprint of the node to get data about
+ * @returns {NodeData}
+ */
+ async getNodeInfo(id) {
+ return this._withConnection(async conn => {
+ const node = {
+ fingerprint: id,
+ ipAddrs: [],
+ bridgeType: null,
+ regionCode: null,
+ };
+ const bridge = (await conn.getConf("bridge"))?.find(
+ foundBridge => foundBridge.ID?.toUpperCase() === id.toUpperCase()
+ );
+ const addrRe = /^\[?([^\]]+)\]?:\d+$/;
+ if (bridge) {
+ node.bridgeType = bridge.type ?? "";
+ // Attempt to get an IP address from bridge address string.
+ const ip = bridge.address.match(addrRe)?.[1];
+ if (ip && !ip.startsWith("0.")) {
+ node.ipAddrs.push(ip);
+ }
+ } else {
+ // Either dealing with a relay, or a bridge whose fingerprint is not
+ // saved in torrc.
+ const info = await conn.getInfo(`ns/id/${id}`);
+ if (info.IP && !info.IP.startsWith("0.")) {
+ node.ipAddrs.push(info.IP);
+ }
+ const ip6 = info.IPv6?.match(addrRe)?.[1];
+ if (ip6) {
+ node.ipAddrs.push(ip6);
+ }
+ }
+ if (node.ipAddrs.length) {
+ // Get the country code for the node's IP address.
+ let regionCode;
+ try {
+ // Expect a 2-letter ISO3166-1 code, which should also be a valid
+ // BCP47 Region subtag.
+ regionCode = await conn.getInfo("ip-to-country/" + node.ipAddrs[0]);
+ } catch {}
+ if (regionCode && regionCode !== "??") {
+ node.regionCode = regionCode.toUpperCase();
+ }
+ }
+ return node;
+ });
+ },
+
+ async onionAuthAdd(hsAddress, b64PrivateKey, isPermanent) {
+ return this._withConnection(conn => {
+ return conn.onionAuthAdd(hsAddress, b64PrivateKey, isPermanent);
+ });
+ },
+
+ async onionAuthRemove(hsAddress) {
+ return this._withConnection(conn => {
+ return conn.onionAuthRemove(hsAddress);
+ });
+ },
+
+ async onionAuthViewKeys() {
+ return this._withConnection(conn => {
+ return conn.onionAuthViewKeys();
+ });
+ },
+
// TODO: transform the following 4 functions in getters. At the moment they
// are also used in torbutton.
@@ -630,6 +727,16 @@ export const TorProtocolService = {
}
},
+ async _withConnection(func) {
+ // TODO: Make more robust?
+ const conn = await this._getConnection();
+ try {
+ return await func(conn);
+ } finally {
+ this._returnConnection();
+ }
+ },
+
// If aConn is omitted, the cached connection is closed.
_closeConnection() {
if (this._controlConnection) {
=====================================
toolkit/components/tor-launcher/TorStartupService.sys.mjs
=====================================
@@ -3,6 +3,7 @@ const lazy = {};
// We will use the modules only when the profile is loaded, so prefer lazy
// loading
ChromeUtils.defineESModuleGetters(lazy, {
+ TorDomainIsolator: "resource://gre/modules/TorDomainIsolator.sys.mjs",
TorLauncherUtil: "resource://gre/modules/TorLauncherUtil.sys.mjs",
TorMonitorService: "resource://gre/modules/TorMonitorService.sys.mjs",
TorProtocolService: "resource://gre/modules/TorProtocolService.sys.mjs",
@@ -19,12 +20,6 @@ ChromeUtils.defineModuleGetter(
"resource:///modules/TorSettings.jsm"
);
-ChromeUtils.defineModuleGetter(
- lazy,
- "TorDomainIsolator",
- "resource://gre/modules/TorDomainIsolator.jsm"
-);
-
/* Browser observer topis */
const BrowserTopics = Object.freeze({
ProfileAfterChange: "profile-after-change",
=====================================
toolkit/components/tor-launcher/moz.build
=====================================
@@ -1,6 +1,6 @@
EXTRA_JS_MODULES += [
"TorBootstrapRequest.sys.mjs",
- "TorDomainIsolator.jsm",
+ "TorDomainIsolator.sys.mjs",
"TorLauncherUtil.sys.mjs",
"TorMonitorService.sys.mjs",
"TorParsers.sys.mjs",
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/bdda46…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/bdda46…
You're receiving this email because of your account on gitlab.torproject.org.
1
0