tbb-commits
Threads by month
- ----- 2025 -----
- 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
- 18610 discussions

[Git][tpo/applications/tor-browser][base-browser-115.9.0esr-13.5-1] Bug 41916: Letterboxing preferences UI
by ma1 (@ma1) 21 Mar '24
by ma1 (@ma1) 21 Mar '24
21 Mar '24
ma1 pushed to branch base-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
d873c008 by hackademix at 2024-03-21T13:56:42+01:00
Bug 41916: Letterboxing preferences UI
- - - - -
12 changed files:
- browser/components/preferences/jar.mn
- + browser/components/preferences/letterboxing-middle-dark.svg
- + browser/components/preferences/letterboxing-middle-light.svg
- + browser/components/preferences/letterboxing-top-dark.svg
- + browser/components/preferences/letterboxing-top-light.svg
- + browser/components/preferences/letterboxing.css
- + browser/components/preferences/letterboxing.inc.xhtml
- + browser/components/preferences/letterboxing.js
- browser/components/preferences/main.inc.xhtml
- browser/components/preferences/main.js
- browser/components/preferences/preferences.xhtml
- browser/locales/en-US/browser/base-browser.ftl
Changes:
=====================================
browser/components/preferences/jar.mn
=====================================
@@ -22,3 +22,10 @@ browser.jar:
content/browser/preferences/more-from-mozilla-qr-code-simple-cn.svg
content/browser/preferences/web-appearance-dark.svg
content/browser/preferences/web-appearance-light.svg
+
+ content/browser/preferences/letterboxing.js
+ content/browser/preferences/letterboxing.css
+ content/browser/preferences/letterboxing-middle-dark.svg
+ content/browser/preferences/letterboxing-middle-light.svg
+ content/browser/preferences/letterboxing-top-dark.svg
+ content/browser/preferences/letterboxing-top-light.svg
=====================================
browser/components/preferences/letterboxing-middle-dark.svg
=====================================
@@ -0,0 +1,35 @@
+<svg width="62" height="50" viewBox="0 0 62 50" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_2272_529)">
+<g clip-path="url(#clip0_2272_529)">
+<path d="M58 3H4V45H58V3Z" fill="#42414D"/>
+<path d="M58 3H4V14H58V3Z" fill="#42414D"/>
+<path d="M58 3H4V8H58V3Z" fill="#2B2A33"/>
+<path d="M20 5H10C9.44772 5 9 5.44772 9 6C9 6.55228 9.44772 7 10 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5Z" fill="white"/>
+<path d="M56 11C56 10.4477 55.5523 10 55 10C54.4477 10 54 10.4477 54 11C54 11.5523 54.4477 12 55 12C55.5523 12 56 11.5523 56 11Z" fill="white"/>
+<path d="M8 11C8 10.4477 7.55228 10 7 10C6.44772 10 6 10.4477 6 11C6 11.5523 6.44772 12 7 12C7.55228 12 8 11.5523 8 11Z" fill="white"/>
+<path d="M12 11C12 10.4477 11.5523 10 11 10C10.4477 10 10 10.4477 10 11C10 11.5523 10.4477 12 11 12C11.5523 12 12 11.5523 12 11Z" fill="white"/>
+<path d="M51 10H15C14.4477 10 14 10.4477 14 11C14 11.5523 14.4477 12 15 12H51C51.5523 12 52 11.5523 52 11C52 10.4477 51.5523 10 51 10Z" fill="white"/>
+<path d="M58 14H4V45H58V14Z" fill="#5B5B66"/>
+<rect x="8" y="18" width="46" height="23" rx="2" fill="#3A3944"/>
+<path d="M38 22H13C12.4477 22 12 22.4477 12 23C12 23.5523 12.4477 24 13 24H38C38.5523 24 39 23.5523 39 23C39 22.4477 38.5523 22 38 22Z" fill="white"/>
+<path d="M27 26H13C12.4477 26 12 26.4477 12 27C12 27.5523 12.4477 28 13 28H27C27.5523 28 28 27.5523 28 27C28 26.4477 27.5523 26 27 26Z" fill="white"/>
+<path d="M42 30H13C12.4477 30 12 30.4477 12 31C12 31.5523 12.4477 32 13 32H42C42.5523 32 43 31.5523 43 31C43 30.4477 42.5523 30 42 30Z" fill="white"/>
+</g>
+<rect x="4.5" y="3.5" width="53" height="41" rx="1.5" stroke="#8F8F9D" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_2272_529" x="0" y="0" width="62" height="50" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="2"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2272_529"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2272_529" result="shape"/>
+</filter>
+<clipPath id="clip0_2272_529">
+<rect x="4" y="3" width="54" height="42" rx="2" fill="white"/>
+</clipPath>
+</defs>
+</svg>
=====================================
browser/components/preferences/letterboxing-middle-light.svg
=====================================
@@ -0,0 +1,35 @@
+<svg width="62" height="50" viewBox="0 0 62 50" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_202_960)">
+<g clip-path="url(#clip0_202_960)">
+<path d="M58 3H4V45H58V3Z" fill="#F0F0F4"/>
+<path d="M58 3H4V14H58V3Z" fill="#F0F0F4"/>
+<path d="M58 3H4V8H58V3Z" fill="#E0E0E6"/>
+<path d="M20 5H10C9.44772 5 9 5.44772 9 6C9 6.55228 9.44772 7 10 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5Z" fill="#52525E"/>
+<path d="M56 11C56 10.4477 55.5523 10 55 10C54.4477 10 54 10.4477 54 11C54 11.5523 54.4477 12 55 12C55.5523 12 56 11.5523 56 11Z" fill="#52525E"/>
+<path d="M8 11C8 10.4477 7.55228 10 7 10C6.44772 10 6 10.4477 6 11C6 11.5523 6.44772 12 7 12C7.55228 12 8 11.5523 8 11Z" fill="#52525E"/>
+<path d="M12 11C12 10.4477 11.5523 10 11 10C10.4477 10 10 10.4477 10 11C10 11.5523 10.4477 12 11 12C11.5523 12 12 11.5523 12 11Z" fill="#52525E"/>
+<path d="M51 10H15C14.4477 10 14 10.4477 14 11C14 11.5523 14.4477 12 15 12H51C51.5523 12 52 11.5523 52 11C52 10.4477 51.5523 10 51 10Z" fill="#52525E"/>
+<path d="M58 14H4V45H58V14Z" fill="#CFCFD8"/>
+<rect x="8" y="18" width="46" height="23" rx="2" fill="white"/>
+<path d="M38 22H13C12.4477 22 12 22.4477 12 23C12 23.5523 12.4477 24 13 24H38C38.5523 24 39 23.5523 39 23C39 22.4477 38.5523 22 38 22Z" fill="#52525E"/>
+<path d="M27 26H13C12.4477 26 12 26.4477 12 27C12 27.5523 12.4477 28 13 28H27C27.5523 28 28 27.5523 28 27C28 26.4477 27.5523 26 27 26Z" fill="#52525E"/>
+<path d="M42 30H13C12.4477 30 12 30.4477 12 31C12 31.5523 12.4477 32 13 32H42C42.5523 32 43 31.5523 43 31C43 30.4477 42.5523 30 42 30Z" fill="#52525E"/>
+</g>
+<rect x="4.5" y="3.5" width="53" height="41" rx="1.5" stroke="#8F8F9D" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_202_960" x="0" y="0" width="62" height="50" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="2"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_202_960"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_202_960" result="shape"/>
+</filter>
+<clipPath id="clip0_202_960">
+<rect x="4" y="3" width="54" height="42" rx="2" fill="white"/>
+</clipPath>
+</defs>
+</svg>
=====================================
browser/components/preferences/letterboxing-top-dark.svg
=====================================
@@ -0,0 +1,35 @@
+<svg width="62" height="50" viewBox="0 0 62 50" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_2272_508)">
+<g clip-path="url(#clip0_2272_508)">
+<path d="M58 3H4V45H58V3Z" fill="#52525E"/>
+<path d="M58 3H4V14H58V3Z" fill="#42414D"/>
+<path d="M58 3H4V8H58V3Z" fill="#2B2A33"/>
+<path d="M20 5H10C9.44772 5 9 5.44772 9 6C9 6.55228 9.44772 7 10 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5Z" fill="white"/>
+<path d="M56 11C56 10.4477 55.5523 10 55 10C54.4477 10 54 10.4477 54 11C54 11.5523 54.4477 12 55 12C55.5523 12 56 11.5523 56 11Z" fill="white"/>
+<path d="M8 11C8 10.4477 7.55228 10 7 10C6.44772 10 6 10.4477 6 11C6 11.5523 6.44772 12 7 12C7.55228 12 8 11.5523 8 11Z" fill="white"/>
+<path d="M12 11C12 10.4477 11.5523 10 11 10C10.4477 10 10 10.4477 10 11C10 11.5523 10.4477 12 11 12C11.5523 12 12 11.5523 12 11Z" fill="white"/>
+<path d="M51 10H15C14.4477 10 14 10.4477 14 11C14 11.5523 14.4477 12 15 12H51C51.5523 12 52 11.5523 52 11C52 10.4477 51.5523 10 51 10Z" fill="white"/>
+<path d="M58 14H4V45H58V14Z" fill="#5B5B66"/>
+<path d="M8 14H55V39C55 40.1046 54.1046 41 53 41H10C8.89543 41 8 40.1046 8 39V14Z" fill="#3A3944"/>
+<path d="M38 18H13C12.4477 18 12 18.4477 12 19C12 19.5523 12.4477 20 13 20H38C38.5523 20 39 19.5523 39 19C39 18.4477 38.5523 18 38 18Z" fill="white"/>
+<path d="M27 22H13C12.4477 22 12 22.4477 12 23C12 23.5523 12.4477 24 13 24H27C27.5523 24 28 23.5523 28 23C28 22.4477 27.5523 22 27 22Z" fill="white"/>
+<path d="M42 26H13C12.4477 26 12 26.4477 12 27C12 27.5523 12.4477 28 13 28H42C42.5523 28 43 27.5523 43 27C43 26.4477 42.5523 26 42 26Z" fill="white"/>
+</g>
+<rect x="4.5" y="3.5" width="53" height="41" rx="3.5" stroke="#8F8F9D" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_2272_508" x="0" y="0" width="62" height="50" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="2"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2272_508"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2272_508" result="shape"/>
+</filter>
+<clipPath id="clip0_2272_508">
+<rect x="4" y="3" width="54" height="42" rx="4" fill="white"/>
+</clipPath>
+</defs>
+</svg>
=====================================
browser/components/preferences/letterboxing-top-light.svg
=====================================
@@ -0,0 +1,35 @@
+<svg width="62" height="50" viewBox="0 0 62 50" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_202_926)">
+<g clip-path="url(#clip0_202_926)">
+<path d="M58 3H4V45H58V3Z" fill="#F0F0F4"/>
+<path d="M58 3H4V14H58V3Z" fill="#F0F0F4"/>
+<path d="M58 3H4V8H58V3Z" fill="#E0E0E6"/>
+<path d="M20 5H10C9.44772 5 9 5.44772 9 6C9 6.55228 9.44772 7 10 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5Z" fill="#52525E"/>
+<path d="M56 11C56 10.4477 55.5523 10 55 10C54.4477 10 54 10.4477 54 11C54 11.5523 54.4477 12 55 12C55.5523 12 56 11.5523 56 11Z" fill="#52525E"/>
+<path d="M8 11C8 10.4477 7.55228 10 7 10C6.44772 10 6 10.4477 6 11C6 11.5523 6.44772 12 7 12C7.55228 12 8 11.5523 8 11Z" fill="#52525E"/>
+<path d="M12 11C12 10.4477 11.5523 10 11 10C10.4477 10 10 10.4477 10 11C10 11.5523 10.4477 12 11 12C11.5523 12 12 11.5523 12 11Z" fill="#52525E"/>
+<path d="M51 10H15C14.4477 10 14 10.4477 14 11C14 11.5523 14.4477 12 15 12H51C51.5523 12 52 11.5523 52 11C52 10.4477 51.5523 10 51 10Z" fill="#52525E"/>
+<path d="M58 14H4V45H58V14Z" fill="#CFCFD8"/>
+<path d="M8 14H55V39C55 40.1046 54.1046 41 53 41H10C8.89543 41 8 40.1046 8 39V14Z" fill="white"/>
+<path d="M38 18H13C12.4477 18 12 18.4477 12 19C12 19.5523 12.4477 20 13 20H38C38.5523 20 39 19.5523 39 19C39 18.4477 38.5523 18 38 18Z" fill="#52525E"/>
+<path d="M27 22H13C12.4477 22 12 22.4477 12 23C12 23.5523 12.4477 24 13 24H27C27.5523 24 28 23.5523 28 23C28 22.4477 27.5523 22 27 22Z" fill="#52525E"/>
+<path d="M42 26H13C12.4477 26 12 26.4477 12 27C12 27.5523 12.4477 28 13 28H42C42.5523 28 43 27.5523 43 27C43 26.4477 42.5523 26 42 26Z" fill="#52525E"/>
+</g>
+<rect x="4.5" y="3.5" width="53" height="41" rx="3.5" stroke="#8F8F9D" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_202_926" x="0" y="0" width="62" height="50" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="2"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_202_926"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_202_926" result="shape"/>
+</filter>
+<clipPath id="clip0_202_926">
+<rect x="4" y="3" width="54" height="42" rx="4" fill="white"/>
+</clipPath>
+</defs>
+</svg>
=====================================
browser/components/preferences/letterboxing.css
=====================================
@@ -0,0 +1,72 @@
+.letterboxing-overview {
+ margin-block-end: 32px;
+}
+
+.letterboxing-search-overview {
+ margin-block-end: 16px;
+}
+#letterboxingAligner {
+ display: flex;
+ justify-content: start;
+ gap: 16px;
+ margin-block: 12px;
+
+ --letterboxing-alignment-img-top: url("chrome://browser/content/preferences/letterboxing-top-light.svg");
+ --letterboxing-alignment-img-middle: url("chrome://browser/content/preferences/letterboxing-middle-light.svg");
+}
+
+@media (prefers-color-scheme: dark) {
+ #letterboxingAligner {
+ --letterboxing-alignment-img-top: url("chrome://browser/content/preferences/letterboxing-top-dark.svg");
+ --letterboxing-alignment-img-middle: url("chrome://browser/content/preferences/letterboxing-middle-dark.svg");
+ }
+}
+
+#letterboxingAligner .letterboxing-align-top img {
+ content: var(--letterboxing-alignment-img-top);
+}
+#letterboxingAligner .letterboxing-align-middle img {
+ content: var(--letterboxing-alignment-img-middle);
+}
+
+#letterboxingAligner label {
+ width: 200px;
+ flex: 0 0 auto;
+}
+
+#letterboxingAligner img {
+ border: none;
+ box-shadow: none;
+}
+
+/* Hide letterboxing options depending on whether ResistFingerprinting or
+ * Letterboxing is enabled. */
+#letterboxingCategory:not(.rfp-enabled),
+#letterboxingCategory:not(.rfp-enabled) ~ #letterboxingDisabled,
+#letterboxingCategory.letterboxing-enabled ~ #letterboxingDisabled,
+#letterboxingCategory:not(.rfp-enabled.letterboxing-enabled) ~ .letterboxing-category {
+ display: none;
+}
+
+/* We duplicate the Letterboxing overview to appear in search results.
+ * We want to hide them whenever they are *not* part of a search result. */
+:is(
+ /* Hide the duplicates when the category is *not* hidden. */
+ #letterboxingCategory:not(.visually-hidden) ~ .letterboxing-category,
+ /* Also hide the duplicated overview for subsequence search results if a
+ * previous groupbox is *not* hidden. */
+ .letterboxing-category:not(.visually-hidden) ~ .letterboxing-category,
+) .letterboxing-search-overview {
+ display: none;
+}
+
+/* Similarly for #letterboxingDisabled, but we also want to hide its
+ * "Letterboxing" heading.
+ * NOTE: This should only appear in isolation, so we do not need to worry about
+ * subsequent groupboxes. */
+#letterboxingCategory:not(.visually-hidden) ~ #letterboxingDisabled :is(
+ .letterboxing-search-heading,
+ .letterboxing-search-overview
+) {
+ display: none;
+}
=====================================
browser/components/preferences/letterboxing.inc.xhtml
=====================================
@@ -0,0 +1,134 @@
+<script src="chrome://browser/content/preferences/letterboxing.js" />
+<vbox
+ id="letterboxingCategory"
+ class="subcategory"
+ hidden="true"
+ data-category="paneGeneral"
+>
+ <html:h1 data-l10n-id="letterboxing-header" />
+ <description class="letterboxing-overview">
+ <html:span
+ data-l10n-id="letterboxing-overview"
+ class="tail-with-learn-more"
+ ></html:span>
+ <label
+ data-l10n-id="letterboxing-learn-more"
+ class="learnMore text-link"
+ is="text-link"
+ href="about:manual#letterboxing"
+ useoriginprincipal="true"
+ />
+ </description>
+</vbox>
+<groupbox
+ class="letterboxing-category"
+ data-category="paneGeneral"
+ hidden="true"
+>
+ <label><html:h2
+ data-l10n-id="letterboxing-window-size-header"/></label>
+ <description class="letterboxing-search-overview">
+ <html:span
+ data-l10n-id="letterboxing-overview"
+ class="tail-with-learn-more"
+ ></html:span>
+ <label
+ data-l10n-id="letterboxing-learn-more"
+ class="learnMore text-link"
+ is="text-link"
+ href="about:manual#letterboxing"
+ useoriginprincipal="true"
+ />
+ </description>
+ <checkbox
+ id="letterboxingRememberSize"
+ data-l10n-id="letterboxing-remember-size"
+ preference="privacy.resistFingerprinting.letterboxing.rememberSize"
+ />
+</groupbox>
+<groupbox
+ class="letterboxing-category"
+ data-category="paneGeneral"
+ hidden="true"
+>
+ <label><html:h2
+ data-l10n-id="letterboxing-alignment-header"
+ /></label>
+ <description class="letterboxing-search-overview">
+ <html:span
+ data-l10n-id="letterboxing-overview"
+ class="tail-with-learn-more"
+ ></html:span>
+ <label
+ data-l10n-id="letterboxing-learn-more"
+ class="learnMore text-link"
+ is="text-link"
+ href="about:manual#letterboxing"
+ useoriginprincipal="true"
+ />
+ </description>
+ <description
+ id="letterboxingAlignmentDesc"
+ flex="1"
+ data-l10n-id="letterboxing-alignment-description"
+ />
+ <form
+ xmlns="http://www.w3.org/1999/xhtml"
+ id="letterboxingAligner"
+ autocomplete="off"
+ aria-labelledby="letterboxingAlignmentDesc"
+ >
+ <label class="web-appearance-choice letterboxing-align-top">
+ <div class="web-appearance-choice-image-container">
+ <img role="presentation" />
+ </div>
+ <div class="web-appearance-choice-footer">
+ <input type="radio" name="alignment" value="top" />
+ <span data-l10n-id="letterboxing-alignment-top"></span>
+ </div>
+ </label>
+ <label class="web-appearance-choice letterboxing-align-middle">
+ <div class="web-appearance-choice-image-container">
+ <img role="presentation" />
+ </div>
+ <div class="web-appearance-choice-footer">
+ <input type="radio" name="alignment" value="middle" />
+ <span data-l10n-id="letterboxing-alignment-middle"></span>
+ </div>
+ </label>
+ </form>
+</groupbox>
+<groupbox
+ id="letterboxingDisabled"
+ data-category="paneGeneral"
+ hidden="true"
+>
+ <label class="letterboxing-search-heading"><html:h2
+ data-l10n-id="letterboxing-header"/></label>
+ <description class="letterboxing-search-overview">
+ <html:span
+ data-l10n-id="letterboxing-overview"
+ class="tail-with-learn-more"
+ ></html:span>
+ <label
+ data-l10n-id="letterboxing-learn-more"
+ class="learnMore text-link"
+ is="text-link"
+ href="about:manual#letterboxing"
+ useoriginprincipal="true"
+ />
+ </description>
+ <hbox align="center">
+ <label
+ class="face-sad"
+ flex="1"
+ data-l10n-id="letterboxing-disabled-description"
+ />
+ <button
+ id="letterboxingEnableButton"
+ class="accessory-button"
+ is="highlightable-button"
+ data-l10n-id="letterboxing-enable-button"
+ />
+ </hbox>
+</groupbox>
=====================================
browser/components/preferences/letterboxing.js
=====================================
@@ -0,0 +1,113 @@
+/* import-globals-from /browser/components/preferences/preferences.js */
+/* import-globals-from /browser/components/preferences/findInPage.js */
+/* import-globals-from /toolkit/content/preferencesBindings.js */
+
+Preferences.addAll([
+ {
+ id: "privacy.resistFingerprinting.letterboxing.rememberSize",
+ type: "bool",
+ },
+]);
+
+{
+ const lbEnabledPref = "privacy.resistFingerprinting.letterboxing";
+ const visibilityPrefs = ["privacy.resistFingerprinting", lbEnabledPref];
+ const alignMiddlePref = "privacy.resistFingerprinting.letterboxing.vcenter";
+
+ const hideFromSearchIf = (mustHide, ...elements) => {
+ for (const element of elements) {
+ if (mustHide) {
+ element.setAttribute("data-hidden-from-search", "true");
+ } else {
+ element.removeAttribute("data-hidden-from-search");
+ }
+ }
+ };
+
+ const syncVisibility = () => {
+ const [rfpEnabled, letterboxingEnabled] = visibilityPrefs.map(pref =>
+ Services.prefs.getBoolPref(pref, false)
+ );
+ const categoryElement = document.getElementById("letterboxingCategory");
+ const { classList } = categoryElement;
+
+ // Show the letterboxing section only if resistFingerprinting is enabled
+ classList.toggle("rfp-enabled", rfpEnabled);
+ classList.toggle("letterboxing-enabled", letterboxingEnabled);
+
+ // To ensure the hidden parts do not contribute to search results, we need
+ // to add "data-hidden-from-search".
+ hideFromSearchIf(
+ !rfpEnabled || !letterboxingEnabled,
+ ...document.querySelectorAll(".letterboxing-category")
+ );
+ hideFromSearchIf(
+ !rfpEnabled || letterboxingEnabled,
+ document.getElementById("letterboxingDisabled")
+ );
+ };
+
+ const onVisibilityPrefChange = () => {
+ syncVisibility();
+ // NOTE: Firefox does not expect "data-hidden-from-search" to change
+ // dynamically after page initialization. So we need to manually recall the
+ // methods that use "data-hidden-from-search". I.e. the "search" method,
+ // using the currently shown category.
+ // NOTE: We skip this if we are just initializing on page load.
+ // NOTE: data-hidden-from-search is also used when the user has entered a
+ // search term. We do not update the results in this case. Instead, it will
+ // update when the search term changes or is cleared.
+ if (!gSearchResultsPane.query) {
+ search(gLastCategory.category, "data-category");
+ }
+ };
+
+ const alignerId = "letterboxingAligner";
+ const syncAligner = () => {
+ const value = Services.prefs.getBoolPref(alignMiddlePref)
+ ? "middle"
+ : "top";
+ document.querySelector(
+ `#${alignerId} input[value="${value}"]`
+ ).checked = true;
+ };
+
+ var gLetterboxingPrefs = {
+ init() {
+ syncVisibility();
+ document
+ .getElementById("letterboxingEnableButton")
+ .addEventListener("command", () => {
+ Services.prefs.setBoolPref(lbEnabledPref, true);
+ // Button should have focus when activated but will be hidden now,
+ // so re-assign focus to the newly revealed options.
+ Services.focus.moveFocus(
+ window,
+ document.querySelector(".letterboxing-category"),
+ Services.focus.MOVEFOCUS_FIRST,
+ 0
+ );
+ });
+ for (const pref of visibilityPrefs) {
+ Services.prefs.addObserver(pref, onVisibilityPrefChange);
+ }
+
+ syncAligner();
+ document.getElementById(alignerId).addEventListener("change", e => {
+ // NOTE: the "change" event is only fired on the checked input.
+ Services.prefs.setBoolPref(
+ alignMiddlePref,
+ e.target.value === "middle"
+ );
+ });
+ Services.prefs.addObserver(alignMiddlePref, syncAligner);
+ },
+
+ destroy() {
+ for (const pref of visibilityPrefs) {
+ Services.prefs.removeObserver(pref, onVisibilityPrefChange);
+ }
+ Services.prefs.removeObserver(alignMiddlePref, syncAligner);
+ },
+ };
+}
=====================================
browser/components/preferences/main.inc.xhtml
=====================================
@@ -130,6 +130,9 @@
</vbox>
</groupbox>
+<!-- Letterboxing -->
+#include ./letterboxing.inc.xhtml
+
<hbox id="languageAndAppearanceCategory"
class="subcategory"
hidden="true"
=====================================
browser/components/preferences/main.js
=====================================
@@ -736,6 +736,7 @@ var gMainPane = {
]);
AppearanceChooser.init();
+ gLetterboxingPrefs.init();
// Notify observers that the UI is now ready
Services.obs.notifyObservers(window, "main-pane-loaded");
@@ -2591,6 +2592,7 @@ var gMainPane = {
Services.prefs.removeObserver(PREF_CONTAINERS_EXTENSION, this);
Services.obs.removeObserver(this, AUTO_UPDATE_CHANGED_TOPIC);
Services.obs.removeObserver(this, BACKGROUND_UPDATE_CHANGED_TOPIC);
+ gLetterboxingPrefs.destroy();
AppearanceChooser.destroy();
},
=====================================
browser/components/preferences/preferences.xhtml
=====================================
@@ -12,6 +12,7 @@
<?xml-stylesheet href="chrome://browser/skin/preferences/search.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/containers.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/privacy.css"?>
+<?xml-stylesheet href="chrome://browser/content/preferences/letterboxing.css"?>
<?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelPreferences.css"?>
<!DOCTYPE html>
@@ -40,6 +41,7 @@
<!-- Links below are only used for search-l10n-ids into subdialogs -->
<link rel="localization" href="browser/aboutDialog.ftl"/>
+ <link rel="localization" href="browser/base-browser.ftl"/>
<link rel="localization" href="browser/preferences/addEngine.ftl"/>
<link rel="localization" href="browser/preferences/blocklists.ftl"/>
<link rel="localization" href="browser/preferences/clearSiteData.ftl"/>
=====================================
browser/locales/en-US/browser/base-browser.ftl
=====================================
@@ -70,3 +70,27 @@ new-identity-dialog-confirm =
new-identity-blocked-home-notification = { -brand-short-name } blocked your homepage ({ $url }) from loading because it might recognize your previous session.
# Button to continue loading the home page, despite the warning message.
new-identity-blocked-home-ignore-button = Load it anyway
+## Preferences - Letterboxing.
+
+# The word "Letterboxing" is the proper noun for the Tor Browser feature, and is therefore capitalised.
+# "Letterboxing" should be treated as a feature/product name, and likely not changed in other languages.
+letterboxing-header = Letterboxing
+# The word "Letterboxing" is the proper noun for the Tor Browser feature, and is therefore capitalised.
+# "Letterboxing" should be treated as a feature/product name, and likely not changed in other languages.
+letterboxing-overview = { -brand-short-name }'s Letterboxing feature restricts websites to display at specific sizes, making it harder to single out users on the basis of their window or screen size.
+letterboxing-learn-more = Learn more
+letterboxing-window-size-header = Window size
+letterboxing-remember-size =
+ .label = Reuse last window size when opening a new window
+ .accesskey = R
+letterboxing-alignment-header = Content Alignment
+letterboxing-alignment-description = Choose where you want to align the website’s content.
+letterboxing-alignment-top = Top
+letterboxing-alignment-middle = Middle
+# The word "Letterboxing" is the proper noun for the Tor Browser feature, and is therefore capitalised.
+# "Letterboxing" should be treated as a feature/product name, and likely not changed in other languages.
+letterboxing-disabled-description = Letterboxing is currently disabled.
+# The word "Letterboxing" is the proper noun for the Tor Browser feature, and is therefore capitalised.
+# "Letterboxing" should be treated as a feature/product name, and likely not changed in other languages.
+letterboxing-enable-button =
+ .label = Enable Letterboxing
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d873c00…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/d873c00…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.9.0esr-13.5-1] Bug 41916: Letterboxing preferences UI
by ma1 (@ma1) 21 Mar '24
by ma1 (@ma1) 21 Mar '24
21 Mar '24
ma1 pushed to branch tor-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
96be793b by hackademix at 2024-03-21T13:41:16+01:00
Bug 41916: Letterboxing preferences UI
- - - - -
12 changed files:
- browser/components/preferences/jar.mn
- + browser/components/preferences/letterboxing-middle-dark.svg
- + browser/components/preferences/letterboxing-middle-light.svg
- + browser/components/preferences/letterboxing-top-dark.svg
- + browser/components/preferences/letterboxing-top-light.svg
- + browser/components/preferences/letterboxing.css
- + browser/components/preferences/letterboxing.inc.xhtml
- + browser/components/preferences/letterboxing.js
- browser/components/preferences/main.inc.xhtml
- browser/components/preferences/main.js
- browser/components/preferences/preferences.xhtml
- browser/locales/en-US/browser/base-browser.ftl
Changes:
=====================================
browser/components/preferences/jar.mn
=====================================
@@ -22,3 +22,10 @@ browser.jar:
content/browser/preferences/more-from-mozilla-qr-code-simple-cn.svg
content/browser/preferences/web-appearance-dark.svg
content/browser/preferences/web-appearance-light.svg
+
+ content/browser/preferences/letterboxing.js
+ content/browser/preferences/letterboxing.css
+ content/browser/preferences/letterboxing-middle-dark.svg
+ content/browser/preferences/letterboxing-middle-light.svg
+ content/browser/preferences/letterboxing-top-dark.svg
+ content/browser/preferences/letterboxing-top-light.svg
=====================================
browser/components/preferences/letterboxing-middle-dark.svg
=====================================
@@ -0,0 +1,35 @@
+<svg width="62" height="50" viewBox="0 0 62 50" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_2272_529)">
+<g clip-path="url(#clip0_2272_529)">
+<path d="M58 3H4V45H58V3Z" fill="#42414D"/>
+<path d="M58 3H4V14H58V3Z" fill="#42414D"/>
+<path d="M58 3H4V8H58V3Z" fill="#2B2A33"/>
+<path d="M20 5H10C9.44772 5 9 5.44772 9 6C9 6.55228 9.44772 7 10 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5Z" fill="white"/>
+<path d="M56 11C56 10.4477 55.5523 10 55 10C54.4477 10 54 10.4477 54 11C54 11.5523 54.4477 12 55 12C55.5523 12 56 11.5523 56 11Z" fill="white"/>
+<path d="M8 11C8 10.4477 7.55228 10 7 10C6.44772 10 6 10.4477 6 11C6 11.5523 6.44772 12 7 12C7.55228 12 8 11.5523 8 11Z" fill="white"/>
+<path d="M12 11C12 10.4477 11.5523 10 11 10C10.4477 10 10 10.4477 10 11C10 11.5523 10.4477 12 11 12C11.5523 12 12 11.5523 12 11Z" fill="white"/>
+<path d="M51 10H15C14.4477 10 14 10.4477 14 11C14 11.5523 14.4477 12 15 12H51C51.5523 12 52 11.5523 52 11C52 10.4477 51.5523 10 51 10Z" fill="white"/>
+<path d="M58 14H4V45H58V14Z" fill="#5B5B66"/>
+<rect x="8" y="18" width="46" height="23" rx="2" fill="#3A3944"/>
+<path d="M38 22H13C12.4477 22 12 22.4477 12 23C12 23.5523 12.4477 24 13 24H38C38.5523 24 39 23.5523 39 23C39 22.4477 38.5523 22 38 22Z" fill="white"/>
+<path d="M27 26H13C12.4477 26 12 26.4477 12 27C12 27.5523 12.4477 28 13 28H27C27.5523 28 28 27.5523 28 27C28 26.4477 27.5523 26 27 26Z" fill="white"/>
+<path d="M42 30H13C12.4477 30 12 30.4477 12 31C12 31.5523 12.4477 32 13 32H42C42.5523 32 43 31.5523 43 31C43 30.4477 42.5523 30 42 30Z" fill="white"/>
+</g>
+<rect x="4.5" y="3.5" width="53" height="41" rx="1.5" stroke="#8F8F9D" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_2272_529" x="0" y="0" width="62" height="50" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="2"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2272_529"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2272_529" result="shape"/>
+</filter>
+<clipPath id="clip0_2272_529">
+<rect x="4" y="3" width="54" height="42" rx="2" fill="white"/>
+</clipPath>
+</defs>
+</svg>
=====================================
browser/components/preferences/letterboxing-middle-light.svg
=====================================
@@ -0,0 +1,35 @@
+<svg width="62" height="50" viewBox="0 0 62 50" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_202_960)">
+<g clip-path="url(#clip0_202_960)">
+<path d="M58 3H4V45H58V3Z" fill="#F0F0F4"/>
+<path d="M58 3H4V14H58V3Z" fill="#F0F0F4"/>
+<path d="M58 3H4V8H58V3Z" fill="#E0E0E6"/>
+<path d="M20 5H10C9.44772 5 9 5.44772 9 6C9 6.55228 9.44772 7 10 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5Z" fill="#52525E"/>
+<path d="M56 11C56 10.4477 55.5523 10 55 10C54.4477 10 54 10.4477 54 11C54 11.5523 54.4477 12 55 12C55.5523 12 56 11.5523 56 11Z" fill="#52525E"/>
+<path d="M8 11C8 10.4477 7.55228 10 7 10C6.44772 10 6 10.4477 6 11C6 11.5523 6.44772 12 7 12C7.55228 12 8 11.5523 8 11Z" fill="#52525E"/>
+<path d="M12 11C12 10.4477 11.5523 10 11 10C10.4477 10 10 10.4477 10 11C10 11.5523 10.4477 12 11 12C11.5523 12 12 11.5523 12 11Z" fill="#52525E"/>
+<path d="M51 10H15C14.4477 10 14 10.4477 14 11C14 11.5523 14.4477 12 15 12H51C51.5523 12 52 11.5523 52 11C52 10.4477 51.5523 10 51 10Z" fill="#52525E"/>
+<path d="M58 14H4V45H58V14Z" fill="#CFCFD8"/>
+<rect x="8" y="18" width="46" height="23" rx="2" fill="white"/>
+<path d="M38 22H13C12.4477 22 12 22.4477 12 23C12 23.5523 12.4477 24 13 24H38C38.5523 24 39 23.5523 39 23C39 22.4477 38.5523 22 38 22Z" fill="#52525E"/>
+<path d="M27 26H13C12.4477 26 12 26.4477 12 27C12 27.5523 12.4477 28 13 28H27C27.5523 28 28 27.5523 28 27C28 26.4477 27.5523 26 27 26Z" fill="#52525E"/>
+<path d="M42 30H13C12.4477 30 12 30.4477 12 31C12 31.5523 12.4477 32 13 32H42C42.5523 32 43 31.5523 43 31C43 30.4477 42.5523 30 42 30Z" fill="#52525E"/>
+</g>
+<rect x="4.5" y="3.5" width="53" height="41" rx="1.5" stroke="#8F8F9D" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_202_960" x="0" y="0" width="62" height="50" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="2"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_202_960"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_202_960" result="shape"/>
+</filter>
+<clipPath id="clip0_202_960">
+<rect x="4" y="3" width="54" height="42" rx="2" fill="white"/>
+</clipPath>
+</defs>
+</svg>
=====================================
browser/components/preferences/letterboxing-top-dark.svg
=====================================
@@ -0,0 +1,35 @@
+<svg width="62" height="50" viewBox="0 0 62 50" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_2272_508)">
+<g clip-path="url(#clip0_2272_508)">
+<path d="M58 3H4V45H58V3Z" fill="#52525E"/>
+<path d="M58 3H4V14H58V3Z" fill="#42414D"/>
+<path d="M58 3H4V8H58V3Z" fill="#2B2A33"/>
+<path d="M20 5H10C9.44772 5 9 5.44772 9 6C9 6.55228 9.44772 7 10 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5Z" fill="white"/>
+<path d="M56 11C56 10.4477 55.5523 10 55 10C54.4477 10 54 10.4477 54 11C54 11.5523 54.4477 12 55 12C55.5523 12 56 11.5523 56 11Z" fill="white"/>
+<path d="M8 11C8 10.4477 7.55228 10 7 10C6.44772 10 6 10.4477 6 11C6 11.5523 6.44772 12 7 12C7.55228 12 8 11.5523 8 11Z" fill="white"/>
+<path d="M12 11C12 10.4477 11.5523 10 11 10C10.4477 10 10 10.4477 10 11C10 11.5523 10.4477 12 11 12C11.5523 12 12 11.5523 12 11Z" fill="white"/>
+<path d="M51 10H15C14.4477 10 14 10.4477 14 11C14 11.5523 14.4477 12 15 12H51C51.5523 12 52 11.5523 52 11C52 10.4477 51.5523 10 51 10Z" fill="white"/>
+<path d="M58 14H4V45H58V14Z" fill="#5B5B66"/>
+<path d="M8 14H55V39C55 40.1046 54.1046 41 53 41H10C8.89543 41 8 40.1046 8 39V14Z" fill="#3A3944"/>
+<path d="M38 18H13C12.4477 18 12 18.4477 12 19C12 19.5523 12.4477 20 13 20H38C38.5523 20 39 19.5523 39 19C39 18.4477 38.5523 18 38 18Z" fill="white"/>
+<path d="M27 22H13C12.4477 22 12 22.4477 12 23C12 23.5523 12.4477 24 13 24H27C27.5523 24 28 23.5523 28 23C28 22.4477 27.5523 22 27 22Z" fill="white"/>
+<path d="M42 26H13C12.4477 26 12 26.4477 12 27C12 27.5523 12.4477 28 13 28H42C42.5523 28 43 27.5523 43 27C43 26.4477 42.5523 26 42 26Z" fill="white"/>
+</g>
+<rect x="4.5" y="3.5" width="53" height="41" rx="3.5" stroke="#8F8F9D" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_2272_508" x="0" y="0" width="62" height="50" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="2"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2272_508"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2272_508" result="shape"/>
+</filter>
+<clipPath id="clip0_2272_508">
+<rect x="4" y="3" width="54" height="42" rx="4" fill="white"/>
+</clipPath>
+</defs>
+</svg>
=====================================
browser/components/preferences/letterboxing-top-light.svg
=====================================
@@ -0,0 +1,35 @@
+<svg width="62" height="50" viewBox="0 0 62 50" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g filter="url(#filter0_d_202_926)">
+<g clip-path="url(#clip0_202_926)">
+<path d="M58 3H4V45H58V3Z" fill="#F0F0F4"/>
+<path d="M58 3H4V14H58V3Z" fill="#F0F0F4"/>
+<path d="M58 3H4V8H58V3Z" fill="#E0E0E6"/>
+<path d="M20 5H10C9.44772 5 9 5.44772 9 6C9 6.55228 9.44772 7 10 7H20C20.5523 7 21 6.55228 21 6C21 5.44772 20.5523 5 20 5Z" fill="#52525E"/>
+<path d="M56 11C56 10.4477 55.5523 10 55 10C54.4477 10 54 10.4477 54 11C54 11.5523 54.4477 12 55 12C55.5523 12 56 11.5523 56 11Z" fill="#52525E"/>
+<path d="M8 11C8 10.4477 7.55228 10 7 10C6.44772 10 6 10.4477 6 11C6 11.5523 6.44772 12 7 12C7.55228 12 8 11.5523 8 11Z" fill="#52525E"/>
+<path d="M12 11C12 10.4477 11.5523 10 11 10C10.4477 10 10 10.4477 10 11C10 11.5523 10.4477 12 11 12C11.5523 12 12 11.5523 12 11Z" fill="#52525E"/>
+<path d="M51 10H15C14.4477 10 14 10.4477 14 11C14 11.5523 14.4477 12 15 12H51C51.5523 12 52 11.5523 52 11C52 10.4477 51.5523 10 51 10Z" fill="#52525E"/>
+<path d="M58 14H4V45H58V14Z" fill="#CFCFD8"/>
+<path d="M8 14H55V39C55 40.1046 54.1046 41 53 41H10C8.89543 41 8 40.1046 8 39V14Z" fill="white"/>
+<path d="M38 18H13C12.4477 18 12 18.4477 12 19C12 19.5523 12.4477 20 13 20H38C38.5523 20 39 19.5523 39 19C39 18.4477 38.5523 18 38 18Z" fill="#52525E"/>
+<path d="M27 22H13C12.4477 22 12 22.4477 12 23C12 23.5523 12.4477 24 13 24H27C27.5523 24 28 23.5523 28 23C28 22.4477 27.5523 22 27 22Z" fill="#52525E"/>
+<path d="M42 26H13C12.4477 26 12 26.4477 12 27C12 27.5523 12.4477 28 13 28H42C42.5523 28 43 27.5523 43 27C43 26.4477 42.5523 26 42 26Z" fill="#52525E"/>
+</g>
+<rect x="4.5" y="3.5" width="53" height="41" rx="3.5" stroke="#8F8F9D" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_202_926" x="0" y="0" width="62" height="50" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="1"/>
+<feGaussianBlur stdDeviation="2"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0.0470588 0 0 0 0 0.0470588 0 0 0 0 0.0509804 0 0 0 0.1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_202_926"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_202_926" result="shape"/>
+</filter>
+<clipPath id="clip0_202_926">
+<rect x="4" y="3" width="54" height="42" rx="4" fill="white"/>
+</clipPath>
+</defs>
+</svg>
=====================================
browser/components/preferences/letterboxing.css
=====================================
@@ -0,0 +1,72 @@
+.letterboxing-overview {
+ margin-block-end: 32px;
+}
+
+.letterboxing-search-overview {
+ margin-block-end: 16px;
+}
+#letterboxingAligner {
+ display: flex;
+ justify-content: start;
+ gap: 16px;
+ margin-block: 12px;
+
+ --letterboxing-alignment-img-top: url("chrome://browser/content/preferences/letterboxing-top-light.svg");
+ --letterboxing-alignment-img-middle: url("chrome://browser/content/preferences/letterboxing-middle-light.svg");
+}
+
+@media (prefers-color-scheme: dark) {
+ #letterboxingAligner {
+ --letterboxing-alignment-img-top: url("chrome://browser/content/preferences/letterboxing-top-dark.svg");
+ --letterboxing-alignment-img-middle: url("chrome://browser/content/preferences/letterboxing-middle-dark.svg");
+ }
+}
+
+#letterboxingAligner .letterboxing-align-top img {
+ content: var(--letterboxing-alignment-img-top);
+}
+#letterboxingAligner .letterboxing-align-middle img {
+ content: var(--letterboxing-alignment-img-middle);
+}
+
+#letterboxingAligner label {
+ width: 200px;
+ flex: 0 0 auto;
+}
+
+#letterboxingAligner img {
+ border: none;
+ box-shadow: none;
+}
+
+/* Hide letterboxing options depending on whether ResistFingerprinting or
+ * Letterboxing is enabled. */
+#letterboxingCategory:not(.rfp-enabled),
+#letterboxingCategory:not(.rfp-enabled) ~ #letterboxingDisabled,
+#letterboxingCategory.letterboxing-enabled ~ #letterboxingDisabled,
+#letterboxingCategory:not(.rfp-enabled.letterboxing-enabled) ~ .letterboxing-category {
+ display: none;
+}
+
+/* We duplicate the Letterboxing overview to appear in search results.
+ * We want to hide them whenever they are *not* part of a search result. */
+:is(
+ /* Hide the duplicates when the category is *not* hidden. */
+ #letterboxingCategory:not(.visually-hidden) ~ .letterboxing-category,
+ /* Also hide the duplicated overview for subsequence search results if a
+ * previous groupbox is *not* hidden. */
+ .letterboxing-category:not(.visually-hidden) ~ .letterboxing-category,
+) .letterboxing-search-overview {
+ display: none;
+}
+
+/* Similarly for #letterboxingDisabled, but we also want to hide its
+ * "Letterboxing" heading.
+ * NOTE: This should only appear in isolation, so we do not need to worry about
+ * subsequent groupboxes. */
+#letterboxingCategory:not(.visually-hidden) ~ #letterboxingDisabled :is(
+ .letterboxing-search-heading,
+ .letterboxing-search-overview
+) {
+ display: none;
+}
=====================================
browser/components/preferences/letterboxing.inc.xhtml
=====================================
@@ -0,0 +1,134 @@
+<script src="chrome://browser/content/preferences/letterboxing.js" />
+<vbox
+ id="letterboxingCategory"
+ class="subcategory"
+ hidden="true"
+ data-category="paneGeneral"
+>
+ <html:h1 data-l10n-id="letterboxing-header" />
+ <description class="letterboxing-overview">
+ <html:span
+ data-l10n-id="letterboxing-overview"
+ class="tail-with-learn-more"
+ ></html:span>
+ <label
+ data-l10n-id="letterboxing-learn-more"
+ class="learnMore text-link"
+ is="text-link"
+ href="about:manual#letterboxing"
+ useoriginprincipal="true"
+ />
+ </description>
+</vbox>
+<groupbox
+ class="letterboxing-category"
+ data-category="paneGeneral"
+ hidden="true"
+>
+ <label><html:h2
+ data-l10n-id="letterboxing-window-size-header"/></label>
+ <description class="letterboxing-search-overview">
+ <html:span
+ data-l10n-id="letterboxing-overview"
+ class="tail-with-learn-more"
+ ></html:span>
+ <label
+ data-l10n-id="letterboxing-learn-more"
+ class="learnMore text-link"
+ is="text-link"
+ href="about:manual#letterboxing"
+ useoriginprincipal="true"
+ />
+ </description>
+ <checkbox
+ id="letterboxingRememberSize"
+ data-l10n-id="letterboxing-remember-size"
+ preference="privacy.resistFingerprinting.letterboxing.rememberSize"
+ />
+</groupbox>
+<groupbox
+ class="letterboxing-category"
+ data-category="paneGeneral"
+ hidden="true"
+>
+ <label><html:h2
+ data-l10n-id="letterboxing-alignment-header"
+ /></label>
+ <description class="letterboxing-search-overview">
+ <html:span
+ data-l10n-id="letterboxing-overview"
+ class="tail-with-learn-more"
+ ></html:span>
+ <label
+ data-l10n-id="letterboxing-learn-more"
+ class="learnMore text-link"
+ is="text-link"
+ href="about:manual#letterboxing"
+ useoriginprincipal="true"
+ />
+ </description>
+ <description
+ id="letterboxingAlignmentDesc"
+ flex="1"
+ data-l10n-id="letterboxing-alignment-description"
+ />
+ <form
+ xmlns="http://www.w3.org/1999/xhtml"
+ id="letterboxingAligner"
+ autocomplete="off"
+ aria-labelledby="letterboxingAlignmentDesc"
+ >
+ <label class="web-appearance-choice letterboxing-align-top">
+ <div class="web-appearance-choice-image-container">
+ <img role="presentation" />
+ </div>
+ <div class="web-appearance-choice-footer">
+ <input type="radio" name="alignment" value="top" />
+ <span data-l10n-id="letterboxing-alignment-top"></span>
+ </div>
+ </label>
+ <label class="web-appearance-choice letterboxing-align-middle">
+ <div class="web-appearance-choice-image-container">
+ <img role="presentation" />
+ </div>
+ <div class="web-appearance-choice-footer">
+ <input type="radio" name="alignment" value="middle" />
+ <span data-l10n-id="letterboxing-alignment-middle"></span>
+ </div>
+ </label>
+ </form>
+</groupbox>
+<groupbox
+ id="letterboxingDisabled"
+ data-category="paneGeneral"
+ hidden="true"
+>
+ <label class="letterboxing-search-heading"><html:h2
+ data-l10n-id="letterboxing-header"/></label>
+ <description class="letterboxing-search-overview">
+ <html:span
+ data-l10n-id="letterboxing-overview"
+ class="tail-with-learn-more"
+ ></html:span>
+ <label
+ data-l10n-id="letterboxing-learn-more"
+ class="learnMore text-link"
+ is="text-link"
+ href="about:manual#letterboxing"
+ useoriginprincipal="true"
+ />
+ </description>
+ <hbox align="center">
+ <label
+ class="face-sad"
+ flex="1"
+ data-l10n-id="letterboxing-disabled-description"
+ />
+ <button
+ id="letterboxingEnableButton"
+ class="accessory-button"
+ is="highlightable-button"
+ data-l10n-id="letterboxing-enable-button"
+ />
+ </hbox>
+</groupbox>
=====================================
browser/components/preferences/letterboxing.js
=====================================
@@ -0,0 +1,113 @@
+/* import-globals-from /browser/components/preferences/preferences.js */
+/* import-globals-from /browser/components/preferences/findInPage.js */
+/* import-globals-from /toolkit/content/preferencesBindings.js */
+
+Preferences.addAll([
+ {
+ id: "privacy.resistFingerprinting.letterboxing.rememberSize",
+ type: "bool",
+ },
+]);
+
+{
+ const lbEnabledPref = "privacy.resistFingerprinting.letterboxing";
+ const visibilityPrefs = ["privacy.resistFingerprinting", lbEnabledPref];
+ const alignMiddlePref = "privacy.resistFingerprinting.letterboxing.vcenter";
+
+ const hideFromSearchIf = (mustHide, ...elements) => {
+ for (const element of elements) {
+ if (mustHide) {
+ element.setAttribute("data-hidden-from-search", "true");
+ } else {
+ element.removeAttribute("data-hidden-from-search");
+ }
+ }
+ };
+
+ const syncVisibility = () => {
+ const [rfpEnabled, letterboxingEnabled] = visibilityPrefs.map(pref =>
+ Services.prefs.getBoolPref(pref, false)
+ );
+ const categoryElement = document.getElementById("letterboxingCategory");
+ const { classList } = categoryElement;
+
+ // Show the letterboxing section only if resistFingerprinting is enabled
+ classList.toggle("rfp-enabled", rfpEnabled);
+ classList.toggle("letterboxing-enabled", letterboxingEnabled);
+
+ // To ensure the hidden parts do not contribute to search results, we need
+ // to add "data-hidden-from-search".
+ hideFromSearchIf(
+ !rfpEnabled || !letterboxingEnabled,
+ ...document.querySelectorAll(".letterboxing-category")
+ );
+ hideFromSearchIf(
+ !rfpEnabled || letterboxingEnabled,
+ document.getElementById("letterboxingDisabled")
+ );
+ };
+
+ const onVisibilityPrefChange = () => {
+ syncVisibility();
+ // NOTE: Firefox does not expect "data-hidden-from-search" to change
+ // dynamically after page initialization. So we need to manually recall the
+ // methods that use "data-hidden-from-search". I.e. the "search" method,
+ // using the currently shown category.
+ // NOTE: We skip this if we are just initializing on page load.
+ // NOTE: data-hidden-from-search is also used when the user has entered a
+ // search term. We do not update the results in this case. Instead, it will
+ // update when the search term changes or is cleared.
+ if (!gSearchResultsPane.query) {
+ search(gLastCategory.category, "data-category");
+ }
+ };
+
+ const alignerId = "letterboxingAligner";
+ const syncAligner = () => {
+ const value = Services.prefs.getBoolPref(alignMiddlePref)
+ ? "middle"
+ : "top";
+ document.querySelector(
+ `#${alignerId} input[value="${value}"]`
+ ).checked = true;
+ };
+
+ var gLetterboxingPrefs = {
+ init() {
+ syncVisibility();
+ document
+ .getElementById("letterboxingEnableButton")
+ .addEventListener("command", () => {
+ Services.prefs.setBoolPref(lbEnabledPref, true);
+ // Button should have focus when activated but will be hidden now,
+ // so re-assign focus to the newly revealed options.
+ Services.focus.moveFocus(
+ window,
+ document.querySelector(".letterboxing-category"),
+ Services.focus.MOVEFOCUS_FIRST,
+ 0
+ );
+ });
+ for (const pref of visibilityPrefs) {
+ Services.prefs.addObserver(pref, onVisibilityPrefChange);
+ }
+
+ syncAligner();
+ document.getElementById(alignerId).addEventListener("change", e => {
+ // NOTE: the "change" event is only fired on the checked input.
+ Services.prefs.setBoolPref(
+ alignMiddlePref,
+ e.target.value === "middle"
+ );
+ });
+ Services.prefs.addObserver(alignMiddlePref, syncAligner);
+ },
+
+ destroy() {
+ for (const pref of visibilityPrefs) {
+ Services.prefs.removeObserver(pref, onVisibilityPrefChange);
+ }
+ Services.prefs.removeObserver(alignMiddlePref, syncAligner);
+ },
+ };
+}
=====================================
browser/components/preferences/main.inc.xhtml
=====================================
@@ -130,6 +130,9 @@
</vbox>
</groupbox>
+<!-- Letterboxing -->
+#include ./letterboxing.inc.xhtml
+
<hbox id="languageAndAppearanceCategory"
class="subcategory"
hidden="true"
=====================================
browser/components/preferences/main.js
=====================================
@@ -729,6 +729,7 @@ var gMainPane = {
]);
AppearanceChooser.init();
+ gLetterboxingPrefs.init();
// Notify observers that the UI is now ready
Services.obs.notifyObservers(window, "main-pane-loaded");
@@ -2585,6 +2586,7 @@ var gMainPane = {
Services.prefs.removeObserver(PREF_CONTAINERS_EXTENSION, this);
Services.obs.removeObserver(this, AUTO_UPDATE_CHANGED_TOPIC);
Services.obs.removeObserver(this, BACKGROUND_UPDATE_CHANGED_TOPIC);
+ gLetterboxingPrefs.destroy();
AppearanceChooser.destroy();
},
=====================================
browser/components/preferences/preferences.xhtml
=====================================
@@ -12,6 +12,7 @@
<?xml-stylesheet href="chrome://browser/skin/preferences/search.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/containers.css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/privacy.css"?>
+<?xml-stylesheet href="chrome://browser/content/preferences/letterboxing.css"?>
<?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelPreferences.css"?>
<?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?>
<?xml-stylesheet href="chrome://browser/content/onionservices/authPreferences.css"?>
@@ -42,6 +43,7 @@
<!-- Links below are only used for search-l10n-ids into subdialogs -->
<link rel="localization" href="browser/aboutDialog.ftl"/>
+ <link rel="localization" href="browser/base-browser.ftl"/>
<link rel="localization" href="browser/preferences/addEngine.ftl"/>
<link rel="localization" href="browser/preferences/blocklists.ftl"/>
<link rel="localization" href="browser/preferences/clearSiteData.ftl"/>
=====================================
browser/locales/en-US/browser/base-browser.ftl
=====================================
@@ -70,3 +70,27 @@ new-identity-dialog-confirm =
new-identity-blocked-home-notification = { -brand-short-name } blocked your homepage ({ $url }) from loading because it might recognize your previous session.
# Button to continue loading the home page, despite the warning message.
new-identity-blocked-home-ignore-button = Load it anyway
+## Preferences - Letterboxing.
+
+# The word "Letterboxing" is the proper noun for the Tor Browser feature, and is therefore capitalised.
+# "Letterboxing" should be treated as a feature/product name, and likely not changed in other languages.
+letterboxing-header = Letterboxing
+# The word "Letterboxing" is the proper noun for the Tor Browser feature, and is therefore capitalised.
+# "Letterboxing" should be treated as a feature/product name, and likely not changed in other languages.
+letterboxing-overview = { -brand-short-name }'s Letterboxing feature restricts websites to display at specific sizes, making it harder to single out users on the basis of their window or screen size.
+letterboxing-learn-more = Learn more
+letterboxing-window-size-header = Window size
+letterboxing-remember-size =
+ .label = Reuse last window size when opening a new window
+ .accesskey = R
+letterboxing-alignment-header = Content Alignment
+letterboxing-alignment-description = Choose where you want to align the website’s content.
+letterboxing-alignment-top = Top
+letterboxing-alignment-middle = Middle
+# The word "Letterboxing" is the proper noun for the Tor Browser feature, and is therefore capitalised.
+# "Letterboxing" should be treated as a feature/product name, and likely not changed in other languages.
+letterboxing-disabled-description = Letterboxing is currently disabled.
+# The word "Letterboxing" is the proper noun for the Tor Browser feature, and is therefore capitalised.
+# "Letterboxing" should be treated as a feature/product name, and likely not changed in other languages.
+letterboxing-enable-button =
+ .label = Enable Letterboxing
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/96be793…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/96be793…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/mullvad-browser][mullvad-browser-115.9.0esr-13.5-1] 3 commits: fixup! Bug 40926: Implemented the New Identity feature
by richard (@richard) 20 Mar '24
by richard (@richard) 20 Mar '24
20 Mar '24
richard pushed to branch mullvad-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Mullvad Browser
Commits:
2ce971c7 by Henry Wilkes at 2024-03-20T20:54:07+00:00
fixup! Bug 40926: Implemented the New Identity feature
Bug 42211: Migrate to Fluent.
- - - - -
5a1f3b54 by Henry Wilkes at 2024-03-20T20:54:14+00:00
fixup! Base Browser strings
Bug 42211: Migrate new identity to Fluent.
Also change some strings to sentence case in en-US.
Also removed the hard-coded "Tor Browser", which is not appropriate in
base-browser (e.g. for Mullvad Browser).
- - - - -
a8282d9c by Henry Wilkes at 2024-03-20T20:54:20+00:00
fixup! Tor Browser localization migration scripts.
Bug 42211: Migrate new identity strings to Fluent.
- - - - -
10 changed files:
- browser/base/content/appmenu-viewcache.inc.xhtml
- browser/base/content/browser-menubar.inc
- browser/base/content/navigator-toolbox.inc.xhtml
- browser/components/newidentity/content/newIdentityDialog.js
- browser/components/newidentity/content/newIdentityDialog.xhtml
- browser/components/newidentity/content/newidentity.js
- browser/locales/en-US/browser/base-browser.ftl
- − browser/locales/en-US/chrome/browser/newIdentity.properties
- browser/locales/jar.mn
- + tools/torbrowser/l10n/migrations/bug-42211-new-identity.py
Changes:
=====================================
browser/base/content/appmenu-viewcache.inc.xhtml
=====================================
@@ -57,6 +57,7 @@
<toolbarseparator/>
<toolbarbutton id="appMenu-new-identity"
class="subviewbutton"
+ data-l10n-id="appmenuitem-new-identity"
key="new-identity-key"/>
<toolbarseparator/>
<toolbarbutton id="appMenu-bookmarks-button"
=====================================
browser/base/content/browser-menubar.inc
=====================================
@@ -30,7 +30,7 @@
key="key_privatebrowsing" data-l10n-id="menu-file-new-private-window"/>
<menuseparator/>
<menuitem id="menu_newIdentity"
- key="new-identity-key"/>
+ key="new-identity-key" data-l10n-id="menu-new-identity"/>
<menuseparator/>
<menuitem id="menu_openLocation"
hidden="true"
=====================================
browser/base/content/navigator-toolbox.inc.xhtml
=====================================
@@ -590,7 +590,8 @@
ondragover="newWindowButtonObserver.onDragOver(event)"
ondragenter="newWindowButtonObserver.onDragOver(event)"/>
- <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional"/>
+ <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+ data-l10n-id="toolbar-new-identity"/>
<toolbarbutton id="fullscreen-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
observes="View:FullScreen"
=====================================
browser/components/newidentity/content/newIdentityDialog.js
=====================================
@@ -5,20 +5,13 @@
document.addEventListener("dialogaccept", () => {
const retvals = window.arguments[0];
retvals.confirmed = true;
- retvals.neverAskAgain = document.querySelector("#neverAskAgain").checked;
+ retvals.neverAskAgain = document.getElementById("neverAskAgain").checked;
});
document.addEventListener("DOMContentLoaded", () => {
- const { NewIdentityStrings } = window.arguments[0];
- const dialog = document.querySelector("#newIdentityDialog");
+ const dialog = document.getElementById("newIdentityDialog");
- dialog.querySelector("#infoTitle").textContent =
- NewIdentityStrings.new_identity_prompt_title;
- dialog.querySelector("#infoBody").textContent =
- NewIdentityStrings.new_identity_prompt;
- dialog.querySelector("#neverAskAgain").label =
- NewIdentityStrings.new_identity_ask_again;
const accept = dialog.getButton("accept");
- accept.label = NewIdentityStrings.new_identity_restart;
+ document.l10n.setAttributes(accept, "new-identity-dialog-confirm");
accept.classList.add("danger-button");
});
=====================================
browser/components/newidentity/content/newIdentityDialog.xhtml
=====================================
@@ -21,9 +21,8 @@
>
<dialog id="newIdentityDialog" buttons="accept,cancel" defaultButton="accept">
<linkset>
- <!-- Without this document.l10n is not initialized, and we need it for the
- cancel button. -->
<html:link rel="localization" href="branding/brand.ftl" />
+ <html:link rel="localization" href="browser/base-browser.ftl" />
</linkset>
<div xmlns="http://www.w3.org/1999/xhtml">
@@ -33,13 +32,18 @@
<xul:image id="infoIcon" />
</div>
<div id="infoContainer">
- <xul:description id="infoTitle" />
+ <xul:description
+ id="infoTitle"
+ data-l10n-id="new-identity-dialog-title"
+ />
<xul:description
id="infoBody"
- context="contentAreaContextMenu"
- noinitialfocus="true"
+ data-l10n-id="new-identity-dialog-description"
+ />
+ <xul:checkbox
+ id="neverAskAgain"
+ data-l10n-id="new-identity-dialog-never-ask-checkbox"
/>
- <xul:checkbox id="neverAskAgain" />
</div>
</div>
</div>
=====================================
browser/components/newidentity/content/newidentity.js
=====================================
@@ -1,40 +1,6 @@
"use strict";
-/* globals CustomizableUI Services gFindBarInitialized gFindBar
- OpenBrowserWindow PrivateBrowsingUtils XPCOMUtils
- */
-
-XPCOMUtils.defineLazyGetter(this, "NewIdentityStrings", () => {
- const brandBundle = Services.strings.createBundle(
- "chrome://branding/locale/brand.properties"
- );
- const brandShortName = brandBundle.GetStringFromName("brandShortName");
-
- const fallbackBundle = Services.strings.createBundle(
- "resource:///chrome/en-US/locale/browser/newIdentity.properties"
- );
- const strings = {};
- const brandedStrings = ["new_identity_prompt", "new_identity_restart"];
- for (let { key } of fallbackBundle.getSimpleEnumeration()) {
- strings[key] = fallbackBundle.GetStringFromName(key);
- }
- try {
- const bundle = Services.strings.createBundle(
- "chrome://browser/locale/newIdentity.properties"
- );
- for (const key of Object.keys(strings)) {
- try {
- strings[key] = bundle.GetStringFromName(key);
- } catch (e) {}
- }
- } catch (e) {
- console.warn("Could not load localized New Identity strings");
- }
- for (let key of brandedStrings) {
- strings[key] = strings[key].replaceAll("%S", brandShortName);
- }
- return strings;
-});
+/* eslint-env mozilla/browser-window */
// Use a lazy getter because NewIdentityButton is declared more than once
// otherwise.
@@ -471,11 +437,6 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
// malformed URL, bail out
return;
}
- const label =
- NewIdentityStrings.new_identity_home_notification.replace(
- "%S",
- displayAddress
- );
const callback = () => {
Services.prefs.setStringPref(trustedHomePref, homeURL);
win.BrowserHome();
@@ -484,12 +445,15 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
notificationBox.appendNotification(
"new-identity-safe-home",
{
- label,
+ label: {
+ "l10n-id": "new-identity-blocked-home-notification",
+ "l10n-args": { url: displayAddress },
+ },
priority: notificationBox.PRIORITY_INFO_MEDIUM,
},
[
{
- label: NewIdentityStrings.new_identity_home_load_button,
+ "l10n-id": "new-identity-blocked-home-ignore-button",
callback,
},
]
@@ -550,37 +514,20 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
const button =
document.getElementById("new-identity-button") ||
window.gNavToolbox.palette.querySelector("#new-identity-button");
- if (button) {
- button.setAttribute("tooltiptext", NewIdentityStrings.new_identity);
- // Include an equal label, shown in the overflow menu or during
- // customization.
- button.setAttribute("label", NewIdentityStrings.new_identity);
- button.addEventListener("command", () => {
- this.onCommand();
- });
- }
- const viewCache = document.getElementById("appMenu-viewCache").content;
- const appButton = viewCache.querySelector("#appMenu-new-identity");
- if (appButton) {
- appButton.setAttribute(
- "label",
- NewIdentityStrings.new_identity_sentence_case
- );
- appButton.addEventListener("command", () => {
+ button?.addEventListener("command", () => {
+ this.onCommand();
+ });
+ document
+ .getElementById("appMenu-viewCache")
+ .content.querySelector("#appMenu-new-identity")
+ ?.addEventListener("command", () => {
this.onCommand();
});
- }
- const menu = document.querySelector("#menu_newIdentity");
- if (menu) {
- menu.setAttribute("label", NewIdentityStrings.new_identity);
- menu.setAttribute(
- "accesskey",
- NewIdentityStrings.new_identity_menu_accesskey
- );
- menu.addEventListener("command", () => {
+ document
+ .getElementById("menu_newIdentity")
+ ?.addEventListener("command", () => {
this.onCommand();
});
- }
},
uninit() {},
@@ -598,7 +545,6 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
const shouldConfirm = Services.prefs.getBoolPref(prefConfirm, true);
if (shouldConfirm) {
const params = {
- NewIdentityStrings,
confirmed: false,
neverAskAgain: false,
};
=====================================
browser/locales/en-US/browser/base-browser.ftl
=====================================
@@ -11,20 +11,19 @@ language-notification-label-system = { -brand-short-name } has set your display
language-notification-label = { -brand-short-name } has set your display language to { $language }.
language-notification-button = Change Language…
-
## Fullscreen/maximization notification shown when letterboxing is disabled
basebrowser-rfp-maximize-warning-message = Maximizing the browser window can allow websites to determine your monitor size, which can be used to track you. We recommend that you leave browser windows in their original default size.
basebrowser-rfp-restore-window-size-button-label = Restore
basebrowser-rfp-restore-window-size-button-ak = R
-
## Tooltip for the about:addons recommended badge
basebrowser-addon-badge-recommended = Mozilla only recommends extensions that meet their standards for security and performance
basebrowser-addon-badge-verified = Mozilla has reviewed this extension to meet their standards for security and performance
## Option to show or hide the NoScript extension button/item.
+
basebrowser-addon-noscript-visibility-label = Toolbar button
basebrowser-addon-noscript-visibility-show = Show
basebrowser-addon-noscript-visibility-hide = Hide
@@ -35,3 +34,39 @@ basebrowser-addon-noscript-visibility-hide = Hide
# $version (String) - The current browser version. E.g. "12.5.3".
# $firefoxVersion (String) - The version number of Firefox the current browser is based on. E.g. "102.15.0esr".
basebrowser-about-dialog-version = { $version } (based on Mozilla Firefox { $firefoxVersion })
+
+## New identity.
+
+# File menu items use title case for English (US).
+menu-new-identity =
+ .label = New Identity
+ .accesskey = I
+
+# App menu (hamburger menu) items use sentence case for English (US).
+appmenuitem-new-identity =
+ .label = New identity
+
+# Uses sentence case for English (US).
+# ".label" is the accessible name, and is visible in the overflow menu and when
+# customizing the toolbar.
+# ".tooltiptext" will be identical to the label.
+toolbar-new-identity =
+ .label = New identity
+ .tooltiptext = { toolbar-new-identity.label }
+
+## New identity dialog.
+
+new-identity-dialog-title = Reset your identity?
+new-identity-dialog-description = { -brand-short-name } will close all windows and tabs. All website sessions will be lost.
+new-identity-dialog-never-ask-checkbox =
+ .label = Never ask me again
+new-identity-dialog-confirm =
+ .label = Restart { -brand-short-name }
+
+## New identity: blocked home page notification.
+
+# '-brand-short-name' is the localized browser name, like "Tor Browser".
+# $url (String) - The URL of the home page, possibly shortened.
+new-identity-blocked-home-notification = { -brand-short-name } blocked your homepage ({ $url }) from loading because it might recognize your previous session.
+# Button to continue loading the home page, despite the warning message.
+new-identity-blocked-home-ignore-button = Load it anyway
=====================================
browser/locales/en-US/chrome/browser/newIdentity.properties deleted
=====================================
@@ -1,13 +0,0 @@
-new_identity = New Identity
-# This is the string for the hamburger menu
-new_identity_sentence_case = New identity
-# %S is the application name. Keep it as a placeholder
-new_identity_prompt_title = Reset your identity?
-new_identity_prompt = %S will close all windows and tabs. All website sessions will be lost. \nRestart %S now to reset your identity?
-new_identity_restart = Restart %S
-new_identity_ask_again = Never ask me again
-# Shown in the File menu (use Alt to show File, if you do not see)
-new_identity_menu_accesskey = I
-new_identity_home_notification = Tor Browser blocked your homepage (%S) from loading because it might recognize your previous session.
-# %S is replaced with the custom homepage URL's domain if applicable, or some short-hand of it otherwise
-new_identity_home_load_button = Load it anyway
=====================================
browser/locales/jar.mn
=====================================
@@ -33,5 +33,4 @@
locale/browser/feeds/subscribe.properties (%chrome/browser/feeds/subscribe.properties)
locale/browser/syncSetup.properties (%chrome/browser/syncSetup.properties)
locale/browser/securityLevel.properties (%chrome/browser/securityLevel.properties)
- locale/browser/newIdentity.properties (%chrome/browser/newIdentity.properties)
% locale browser-region @AB_CD@ %locale/browser-region/
=====================================
tools/torbrowser/l10n/migrations/bug-42211-new-identity.py
=====================================
@@ -0,0 +1,48 @@
+import fluent.syntax.ast as FTL
+from fluent.migrate.helpers import TERM_REFERENCE, transforms_from
+from fluent.migrate.transforms import REPLACE
+
+
+def migrate(ctx):
+ legacy_path = "newIdentity.properties"
+
+ ctx.add_transforms(
+ "base-browser.ftl",
+ "base-browser.ftl",
+ transforms_from(
+ """
+menu-new-identity =
+ .label = { COPY(path, "new_identity") }
+ .accesskey = { COPY(path, "new_identity_menu_accesskey") }
+appmenuitem-new-identity =
+ .label = { COPY(path, "new_identity_sentence_case") }
+toolbar-new-identity =
+ .label = { COPY(path, "new_identity_sentence_case") }
+ .tooltiptext = { toolbar-new-identity.label }
+
+new-identity-dialog-title = { COPY(path, "new_identity_prompt_title") }
+new-identity-dialog-never-ask-checkbox =
+ .label = { COPY(path, "new_identity_ask_again") }
+
+new-identity-blocked-home-ignore-button = { COPY(path, "new_identity_home_load_button") }
+""",
+ path=legacy_path,
+ )
+ + [
+ # Replace "%S" with "{ -brand-short-name }" in confirm button.
+ FTL.Message(
+ id=FTL.Identifier("new-identity-dialog-confirm"),
+ value=None,
+ attributes=[
+ FTL.Attribute(
+ id=FTL.Identifier("label"),
+ value=REPLACE(
+ legacy_path,
+ "new_identity_restart",
+ {"%1$S": TERM_REFERENCE("brand-short-name")},
+ ),
+ ),
+ ],
+ ),
+ ],
+ )
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/96…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/96…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][base-browser-115.9.0esr-13.5-1] 3 commits: fixup! Bug 40926: Implemented the New Identity feature
by richard (@richard) 20 Mar '24
by richard (@richard) 20 Mar '24
20 Mar '24
richard pushed to branch base-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
83797a6f by Henry Wilkes at 2024-03-20T20:50:50+00:00
fixup! Bug 40926: Implemented the New Identity feature
Bug 42211: Migrate to Fluent.
- - - - -
d7d04937 by Henry Wilkes at 2024-03-20T20:50:58+00:00
fixup! Base Browser strings
Bug 42211: Migrate new identity to Fluent.
Also change some strings to sentence case in en-US.
Also removed the hard-coded "Tor Browser", which is not appropriate in
base-browser (e.g. for Mullvad Browser).
- - - - -
57b8a1d5 by Henry Wilkes at 2024-03-20T20:51:09+00:00
fixup! Tor Browser localization migration scripts.
Bug 42211: Migrate new identity strings to Fluent.
- - - - -
10 changed files:
- browser/base/content/appmenu-viewcache.inc.xhtml
- browser/base/content/browser-menubar.inc
- browser/base/content/navigator-toolbox.inc.xhtml
- browser/components/newidentity/content/newIdentityDialog.js
- browser/components/newidentity/content/newIdentityDialog.xhtml
- browser/components/newidentity/content/newidentity.js
- browser/locales/en-US/browser/base-browser.ftl
- − browser/locales/en-US/chrome/browser/newIdentity.properties
- browser/locales/jar.mn
- + tools/torbrowser/l10n/migrations/bug-42211-new-identity.py
Changes:
=====================================
browser/base/content/appmenu-viewcache.inc.xhtml
=====================================
@@ -57,6 +57,7 @@
<toolbarseparator/>
<toolbarbutton id="appMenu-new-identity"
class="subviewbutton"
+ data-l10n-id="appmenuitem-new-identity"
key="new-identity-key"/>
<toolbarseparator/>
<toolbarbutton id="appMenu-bookmarks-button"
=====================================
browser/base/content/browser-menubar.inc
=====================================
@@ -30,7 +30,7 @@
key="key_privatebrowsing" data-l10n-id="menu-file-new-private-window"/>
<menuseparator/>
<menuitem id="menu_newIdentity"
- key="new-identity-key"/>
+ key="new-identity-key" data-l10n-id="menu-new-identity"/>
<menuseparator/>
<menuitem id="menu_openLocation"
hidden="true"
=====================================
browser/base/content/navigator-toolbox.inc.xhtml
=====================================
@@ -590,7 +590,8 @@
ondragover="newWindowButtonObserver.onDragOver(event)"
ondragenter="newWindowButtonObserver.onDragOver(event)"/>
- <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional"/>
+ <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+ data-l10n-id="toolbar-new-identity"/>
<toolbarbutton id="fullscreen-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
observes="View:FullScreen"
=====================================
browser/components/newidentity/content/newIdentityDialog.js
=====================================
@@ -5,20 +5,13 @@
document.addEventListener("dialogaccept", () => {
const retvals = window.arguments[0];
retvals.confirmed = true;
- retvals.neverAskAgain = document.querySelector("#neverAskAgain").checked;
+ retvals.neverAskAgain = document.getElementById("neverAskAgain").checked;
});
document.addEventListener("DOMContentLoaded", () => {
- const { NewIdentityStrings } = window.arguments[0];
- const dialog = document.querySelector("#newIdentityDialog");
+ const dialog = document.getElementById("newIdentityDialog");
- dialog.querySelector("#infoTitle").textContent =
- NewIdentityStrings.new_identity_prompt_title;
- dialog.querySelector("#infoBody").textContent =
- NewIdentityStrings.new_identity_prompt;
- dialog.querySelector("#neverAskAgain").label =
- NewIdentityStrings.new_identity_ask_again;
const accept = dialog.getButton("accept");
- accept.label = NewIdentityStrings.new_identity_restart;
+ document.l10n.setAttributes(accept, "new-identity-dialog-confirm");
accept.classList.add("danger-button");
});
=====================================
browser/components/newidentity/content/newIdentityDialog.xhtml
=====================================
@@ -21,9 +21,8 @@
>
<dialog id="newIdentityDialog" buttons="accept,cancel" defaultButton="accept">
<linkset>
- <!-- Without this document.l10n is not initialized, and we need it for the
- cancel button. -->
<html:link rel="localization" href="branding/brand.ftl" />
+ <html:link rel="localization" href="browser/base-browser.ftl" />
</linkset>
<div xmlns="http://www.w3.org/1999/xhtml">
@@ -33,13 +32,18 @@
<xul:image id="infoIcon" />
</div>
<div id="infoContainer">
- <xul:description id="infoTitle" />
+ <xul:description
+ id="infoTitle"
+ data-l10n-id="new-identity-dialog-title"
+ />
<xul:description
id="infoBody"
- context="contentAreaContextMenu"
- noinitialfocus="true"
+ data-l10n-id="new-identity-dialog-description"
+ />
+ <xul:checkbox
+ id="neverAskAgain"
+ data-l10n-id="new-identity-dialog-never-ask-checkbox"
/>
- <xul:checkbox id="neverAskAgain" />
</div>
</div>
</div>
=====================================
browser/components/newidentity/content/newidentity.js
=====================================
@@ -1,40 +1,6 @@
"use strict";
-/* globals CustomizableUI Services gFindBarInitialized gFindBar
- OpenBrowserWindow PrivateBrowsingUtils XPCOMUtils
- */
-
-XPCOMUtils.defineLazyGetter(this, "NewIdentityStrings", () => {
- const brandBundle = Services.strings.createBundle(
- "chrome://branding/locale/brand.properties"
- );
- const brandShortName = brandBundle.GetStringFromName("brandShortName");
-
- const fallbackBundle = Services.strings.createBundle(
- "resource:///chrome/en-US/locale/browser/newIdentity.properties"
- );
- const strings = {};
- const brandedStrings = ["new_identity_prompt", "new_identity_restart"];
- for (let { key } of fallbackBundle.getSimpleEnumeration()) {
- strings[key] = fallbackBundle.GetStringFromName(key);
- }
- try {
- const bundle = Services.strings.createBundle(
- "chrome://browser/locale/newIdentity.properties"
- );
- for (const key of Object.keys(strings)) {
- try {
- strings[key] = bundle.GetStringFromName(key);
- } catch (e) {}
- }
- } catch (e) {
- console.warn("Could not load localized New Identity strings");
- }
- for (let key of brandedStrings) {
- strings[key] = strings[key].replaceAll("%S", brandShortName);
- }
- return strings;
-});
+/* eslint-env mozilla/browser-window */
// Use a lazy getter because NewIdentityButton is declared more than once
// otherwise.
@@ -471,11 +437,6 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
// malformed URL, bail out
return;
}
- const label =
- NewIdentityStrings.new_identity_home_notification.replace(
- "%S",
- displayAddress
- );
const callback = () => {
Services.prefs.setStringPref(trustedHomePref, homeURL);
win.BrowserHome();
@@ -484,12 +445,15 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
notificationBox.appendNotification(
"new-identity-safe-home",
{
- label,
+ label: {
+ "l10n-id": "new-identity-blocked-home-notification",
+ "l10n-args": { url: displayAddress },
+ },
priority: notificationBox.PRIORITY_INFO_MEDIUM,
},
[
{
- label: NewIdentityStrings.new_identity_home_load_button,
+ "l10n-id": "new-identity-blocked-home-ignore-button",
callback,
},
]
@@ -550,37 +514,20 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
const button =
document.getElementById("new-identity-button") ||
window.gNavToolbox.palette.querySelector("#new-identity-button");
- if (button) {
- button.setAttribute("tooltiptext", NewIdentityStrings.new_identity);
- // Include an equal label, shown in the overflow menu or during
- // customization.
- button.setAttribute("label", NewIdentityStrings.new_identity);
- button.addEventListener("command", () => {
- this.onCommand();
- });
- }
- const viewCache = document.getElementById("appMenu-viewCache").content;
- const appButton = viewCache.querySelector("#appMenu-new-identity");
- if (appButton) {
- appButton.setAttribute(
- "label",
- NewIdentityStrings.new_identity_sentence_case
- );
- appButton.addEventListener("command", () => {
+ button?.addEventListener("command", () => {
+ this.onCommand();
+ });
+ document
+ .getElementById("appMenu-viewCache")
+ .content.querySelector("#appMenu-new-identity")
+ ?.addEventListener("command", () => {
this.onCommand();
});
- }
- const menu = document.querySelector("#menu_newIdentity");
- if (menu) {
- menu.setAttribute("label", NewIdentityStrings.new_identity);
- menu.setAttribute(
- "accesskey",
- NewIdentityStrings.new_identity_menu_accesskey
- );
- menu.addEventListener("command", () => {
+ document
+ .getElementById("menu_newIdentity")
+ ?.addEventListener("command", () => {
this.onCommand();
});
- }
},
uninit() {},
@@ -598,7 +545,6 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
const shouldConfirm = Services.prefs.getBoolPref(prefConfirm, true);
if (shouldConfirm) {
const params = {
- NewIdentityStrings,
confirmed: false,
neverAskAgain: false,
};
=====================================
browser/locales/en-US/browser/base-browser.ftl
=====================================
@@ -11,20 +11,19 @@ language-notification-label-system = { -brand-short-name } has set your display
language-notification-label = { -brand-short-name } has set your display language to { $language }.
language-notification-button = Change Language…
-
## Fullscreen/maximization notification shown when letterboxing is disabled
basebrowser-rfp-maximize-warning-message = Maximizing the browser window can allow websites to determine your monitor size, which can be used to track you. We recommend that you leave browser windows in their original default size.
basebrowser-rfp-restore-window-size-button-label = Restore
basebrowser-rfp-restore-window-size-button-ak = R
-
## Tooltip for the about:addons recommended badge
basebrowser-addon-badge-recommended = Mozilla only recommends extensions that meet their standards for security and performance
basebrowser-addon-badge-verified = Mozilla has reviewed this extension to meet their standards for security and performance
## Option to show or hide the NoScript extension button/item.
+
basebrowser-addon-noscript-visibility-label = Toolbar button
basebrowser-addon-noscript-visibility-show = Show
basebrowser-addon-noscript-visibility-hide = Hide
@@ -35,3 +34,39 @@ basebrowser-addon-noscript-visibility-hide = Hide
# $version (String) - The current browser version. E.g. "12.5.3".
# $firefoxVersion (String) - The version number of Firefox the current browser is based on. E.g. "102.15.0esr".
basebrowser-about-dialog-version = { $version } (based on Mozilla Firefox { $firefoxVersion })
+
+## New identity.
+
+# File menu items use title case for English (US).
+menu-new-identity =
+ .label = New Identity
+ .accesskey = I
+
+# App menu (hamburger menu) items use sentence case for English (US).
+appmenuitem-new-identity =
+ .label = New identity
+
+# Uses sentence case for English (US).
+# ".label" is the accessible name, and is visible in the overflow menu and when
+# customizing the toolbar.
+# ".tooltiptext" will be identical to the label.
+toolbar-new-identity =
+ .label = New identity
+ .tooltiptext = { toolbar-new-identity.label }
+
+## New identity dialog.
+
+new-identity-dialog-title = Reset your identity?
+new-identity-dialog-description = { -brand-short-name } will close all windows and tabs. All website sessions will be lost.
+new-identity-dialog-never-ask-checkbox =
+ .label = Never ask me again
+new-identity-dialog-confirm =
+ .label = Restart { -brand-short-name }
+
+## New identity: blocked home page notification.
+
+# '-brand-short-name' is the localized browser name, like "Tor Browser".
+# $url (String) - The URL of the home page, possibly shortened.
+new-identity-blocked-home-notification = { -brand-short-name } blocked your homepage ({ $url }) from loading because it might recognize your previous session.
+# Button to continue loading the home page, despite the warning message.
+new-identity-blocked-home-ignore-button = Load it anyway
=====================================
browser/locales/en-US/chrome/browser/newIdentity.properties deleted
=====================================
@@ -1,13 +0,0 @@
-new_identity = New Identity
-# This is the string for the hamburger menu
-new_identity_sentence_case = New identity
-# %S is the application name. Keep it as a placeholder
-new_identity_prompt_title = Reset your identity?
-new_identity_prompt = %S will close all windows and tabs. All website sessions will be lost. \nRestart %S now to reset your identity?
-new_identity_restart = Restart %S
-new_identity_ask_again = Never ask me again
-# Shown in the File menu (use Alt to show File, if you do not see)
-new_identity_menu_accesskey = I
-new_identity_home_notification = Tor Browser blocked your homepage (%S) from loading because it might recognize your previous session.
-# %S is replaced with the custom homepage URL's domain if applicable, or some short-hand of it otherwise
-new_identity_home_load_button = Load it anyway
=====================================
browser/locales/jar.mn
=====================================
@@ -33,5 +33,4 @@
locale/browser/feeds/subscribe.properties (%chrome/browser/feeds/subscribe.properties)
locale/browser/syncSetup.properties (%chrome/browser/syncSetup.properties)
locale/browser/securityLevel.properties (%chrome/browser/securityLevel.properties)
- locale/browser/newIdentity.properties (%chrome/browser/newIdentity.properties)
% locale browser-region @AB_CD@ %locale/browser-region/
=====================================
tools/torbrowser/l10n/migrations/bug-42211-new-identity.py
=====================================
@@ -0,0 +1,48 @@
+import fluent.syntax.ast as FTL
+from fluent.migrate.helpers import TERM_REFERENCE, transforms_from
+from fluent.migrate.transforms import REPLACE
+
+
+def migrate(ctx):
+ legacy_path = "newIdentity.properties"
+
+ ctx.add_transforms(
+ "base-browser.ftl",
+ "base-browser.ftl",
+ transforms_from(
+ """
+menu-new-identity =
+ .label = { COPY(path, "new_identity") }
+ .accesskey = { COPY(path, "new_identity_menu_accesskey") }
+appmenuitem-new-identity =
+ .label = { COPY(path, "new_identity_sentence_case") }
+toolbar-new-identity =
+ .label = { COPY(path, "new_identity_sentence_case") }
+ .tooltiptext = { toolbar-new-identity.label }
+
+new-identity-dialog-title = { COPY(path, "new_identity_prompt_title") }
+new-identity-dialog-never-ask-checkbox =
+ .label = { COPY(path, "new_identity_ask_again") }
+
+new-identity-blocked-home-ignore-button = { COPY(path, "new_identity_home_load_button") }
+""",
+ path=legacy_path,
+ )
+ + [
+ # Replace "%S" with "{ -brand-short-name }" in confirm button.
+ FTL.Message(
+ id=FTL.Identifier("new-identity-dialog-confirm"),
+ value=None,
+ attributes=[
+ FTL.Attribute(
+ id=FTL.Identifier("label"),
+ value=REPLACE(
+ legacy_path,
+ "new_identity_restart",
+ {"%1$S": TERM_REFERENCE("brand-short-name")},
+ ),
+ ),
+ ],
+ ),
+ ],
+ )
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/369e13…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/369e13…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.9.0esr-13.5-1] 3 commits: fixup! Bug 40926: Implemented the New Identity feature
by richard (@richard) 20 Mar '24
by richard (@richard) 20 Mar '24
20 Mar '24
richard pushed to branch tor-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
9ef44caa by Henry Wilkes at 2024-03-20T12:24:28+00:00
fixup! Bug 40926: Implemented the New Identity feature
Bug 42211: Migrate to Fluent.
- - - - -
93302237 by Henry Wilkes at 2024-03-20T12:24:28+00:00
fixup! Base Browser strings
Bug 42211: Migrate new identity to Fluent.
Also change some strings to sentence case in en-US.
Also removed the hard-coded "Tor Browser", which is not appropriate in
base-browser (e.g. for Mullvad Browser).
- - - - -
124ce63b by Henry Wilkes at 2024-03-20T12:24:29+00:00
fixup! Tor Browser localization migration scripts.
Bug 42211: Migrate new identity strings to Fluent.
- - - - -
10 changed files:
- browser/base/content/appmenu-viewcache.inc.xhtml
- browser/base/content/browser-menubar.inc
- browser/base/content/navigator-toolbox.inc.xhtml
- browser/components/newidentity/content/newIdentityDialog.js
- browser/components/newidentity/content/newIdentityDialog.xhtml
- browser/components/newidentity/content/newidentity.js
- browser/locales/en-US/browser/base-browser.ftl
- − browser/locales/en-US/chrome/browser/newIdentity.properties
- browser/locales/jar.mn
- + tools/torbrowser/l10n/migrations/bug-42211-new-identity.py
Changes:
=====================================
browser/base/content/appmenu-viewcache.inc.xhtml
=====================================
@@ -57,6 +57,7 @@
<toolbarseparator/>
<toolbarbutton id="appMenu-new-identity"
class="subviewbutton"
+ data-l10n-id="appmenuitem-new-identity"
key="new-identity-key"/>
<toolbarbutton id="appMenuNewCircuit"
class="subviewbutton"
=====================================
browser/base/content/browser-menubar.inc
=====================================
@@ -30,7 +30,7 @@
key="key_privatebrowsing" data-l10n-id="menu-file-new-private-window"/>
<menuseparator/>
<menuitem id="menu_newIdentity"
- key="new-identity-key"/>
+ key="new-identity-key" data-l10n-id="menu-new-identity"/>
<menuitem id="menu_newCircuit"
accesskey="&torbutton.context_menu.new_circuit_key;"
key="new-circuit-key"
=====================================
browser/base/content/navigator-toolbox.inc.xhtml
=====================================
@@ -617,7 +617,8 @@
ondragover="newWindowButtonObserver.onDragOver(event)"
ondragenter="newWindowButtonObserver.onDragOver(event)"/>
- <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional"/>
+ <toolbarbutton id="new-identity-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+ data-l10n-id="toolbar-new-identity"/>
<toolbarbutton id="new-circuit-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&torbutton.context_menu.new_circuit;"
=====================================
browser/components/newidentity/content/newIdentityDialog.js
=====================================
@@ -5,20 +5,13 @@
document.addEventListener("dialogaccept", () => {
const retvals = window.arguments[0];
retvals.confirmed = true;
- retvals.neverAskAgain = document.querySelector("#neverAskAgain").checked;
+ retvals.neverAskAgain = document.getElementById("neverAskAgain").checked;
});
document.addEventListener("DOMContentLoaded", () => {
- const { NewIdentityStrings } = window.arguments[0];
- const dialog = document.querySelector("#newIdentityDialog");
+ const dialog = document.getElementById("newIdentityDialog");
- dialog.querySelector("#infoTitle").textContent =
- NewIdentityStrings.new_identity_prompt_title;
- dialog.querySelector("#infoBody").textContent =
- NewIdentityStrings.new_identity_prompt;
- dialog.querySelector("#neverAskAgain").label =
- NewIdentityStrings.new_identity_ask_again;
const accept = dialog.getButton("accept");
- accept.label = NewIdentityStrings.new_identity_restart;
+ document.l10n.setAttributes(accept, "new-identity-dialog-confirm");
accept.classList.add("danger-button");
});
=====================================
browser/components/newidentity/content/newIdentityDialog.xhtml
=====================================
@@ -21,9 +21,8 @@
>
<dialog id="newIdentityDialog" buttons="accept,cancel" defaultButton="accept">
<linkset>
- <!-- Without this document.l10n is not initialized, and we need it for the
- cancel button. -->
<html:link rel="localization" href="branding/brand.ftl" />
+ <html:link rel="localization" href="browser/base-browser.ftl" />
</linkset>
<div xmlns="http://www.w3.org/1999/xhtml">
@@ -33,13 +32,18 @@
<xul:image id="infoIcon" />
</div>
<div id="infoContainer">
- <xul:description id="infoTitle" />
+ <xul:description
+ id="infoTitle"
+ data-l10n-id="new-identity-dialog-title"
+ />
<xul:description
id="infoBody"
- context="contentAreaContextMenu"
- noinitialfocus="true"
+ data-l10n-id="new-identity-dialog-description"
+ />
+ <xul:checkbox
+ id="neverAskAgain"
+ data-l10n-id="new-identity-dialog-never-ask-checkbox"
/>
- <xul:checkbox id="neverAskAgain" />
</div>
</div>
</div>
=====================================
browser/components/newidentity/content/newidentity.js
=====================================
@@ -1,40 +1,6 @@
"use strict";
-/* globals CustomizableUI Services gFindBarInitialized gFindBar
- OpenBrowserWindow PrivateBrowsingUtils XPCOMUtils
- */
-
-XPCOMUtils.defineLazyGetter(this, "NewIdentityStrings", () => {
- const brandBundle = Services.strings.createBundle(
- "chrome://branding/locale/brand.properties"
- );
- const brandShortName = brandBundle.GetStringFromName("brandShortName");
-
- const fallbackBundle = Services.strings.createBundle(
- "resource:///chrome/en-US/locale/browser/newIdentity.properties"
- );
- const strings = {};
- const brandedStrings = ["new_identity_prompt", "new_identity_restart"];
- for (let { key } of fallbackBundle.getSimpleEnumeration()) {
- strings[key] = fallbackBundle.GetStringFromName(key);
- }
- try {
- const bundle = Services.strings.createBundle(
- "chrome://browser/locale/newIdentity.properties"
- );
- for (const key of Object.keys(strings)) {
- try {
- strings[key] = bundle.GetStringFromName(key);
- } catch (e) {}
- }
- } catch (e) {
- console.warn("Could not load localized New Identity strings");
- }
- for (let key of brandedStrings) {
- strings[key] = strings[key].replaceAll("%S", brandShortName);
- }
- return strings;
-});
+/* eslint-env mozilla/browser-window */
// Use a lazy getter because NewIdentityButton is declared more than once
// otherwise.
@@ -471,11 +437,6 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
// malformed URL, bail out
return;
}
- const label =
- NewIdentityStrings.new_identity_home_notification.replace(
- "%S",
- displayAddress
- );
const callback = () => {
Services.prefs.setStringPref(trustedHomePref, homeURL);
win.BrowserHome();
@@ -484,12 +445,15 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
notificationBox.appendNotification(
"new-identity-safe-home",
{
- label,
+ label: {
+ "l10n-id": "new-identity-blocked-home-notification",
+ "l10n-args": { url: displayAddress },
+ },
priority: notificationBox.PRIORITY_INFO_MEDIUM,
},
[
{
- label: NewIdentityStrings.new_identity_home_load_button,
+ "l10n-id": "new-identity-blocked-home-ignore-button",
callback,
},
]
@@ -550,37 +514,20 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
const button =
document.getElementById("new-identity-button") ||
window.gNavToolbox.palette.querySelector("#new-identity-button");
- if (button) {
- button.setAttribute("tooltiptext", NewIdentityStrings.new_identity);
- // Include an equal label, shown in the overflow menu or during
- // customization.
- button.setAttribute("label", NewIdentityStrings.new_identity);
- button.addEventListener("command", () => {
- this.onCommand();
- });
- }
- const viewCache = document.getElementById("appMenu-viewCache").content;
- const appButton = viewCache.querySelector("#appMenu-new-identity");
- if (appButton) {
- appButton.setAttribute(
- "label",
- NewIdentityStrings.new_identity_sentence_case
- );
- appButton.addEventListener("command", () => {
+ button?.addEventListener("command", () => {
+ this.onCommand();
+ });
+ document
+ .getElementById("appMenu-viewCache")
+ .content.querySelector("#appMenu-new-identity")
+ ?.addEventListener("command", () => {
this.onCommand();
});
- }
- const menu = document.querySelector("#menu_newIdentity");
- if (menu) {
- menu.setAttribute("label", NewIdentityStrings.new_identity);
- menu.setAttribute(
- "accesskey",
- NewIdentityStrings.new_identity_menu_accesskey
- );
- menu.addEventListener("command", () => {
+ document
+ .getElementById("menu_newIdentity")
+ ?.addEventListener("command", () => {
this.onCommand();
});
- }
},
uninit() {},
@@ -598,7 +545,6 @@ XPCOMUtils.defineLazyGetter(this, "NewIdentityButton", () => {
const shouldConfirm = Services.prefs.getBoolPref(prefConfirm, true);
if (shouldConfirm) {
const params = {
- NewIdentityStrings,
confirmed: false,
neverAskAgain: false,
};
=====================================
browser/locales/en-US/browser/base-browser.ftl
=====================================
@@ -11,20 +11,19 @@ language-notification-label-system = { -brand-short-name } has set your display
language-notification-label = { -brand-short-name } has set your display language to { $language }.
language-notification-button = Change Language…
-
## Fullscreen/maximization notification shown when letterboxing is disabled
basebrowser-rfp-maximize-warning-message = Maximizing the browser window can allow websites to determine your monitor size, which can be used to track you. We recommend that you leave browser windows in their original default size.
basebrowser-rfp-restore-window-size-button-label = Restore
basebrowser-rfp-restore-window-size-button-ak = R
-
## Tooltip for the about:addons recommended badge
basebrowser-addon-badge-recommended = Mozilla only recommends extensions that meet their standards for security and performance
basebrowser-addon-badge-verified = Mozilla has reviewed this extension to meet their standards for security and performance
## Option to show or hide the NoScript extension button/item.
+
basebrowser-addon-noscript-visibility-label = Toolbar button
basebrowser-addon-noscript-visibility-show = Show
basebrowser-addon-noscript-visibility-hide = Hide
@@ -35,3 +34,39 @@ basebrowser-addon-noscript-visibility-hide = Hide
# $version (String) - The current browser version. E.g. "12.5.3".
# $firefoxVersion (String) - The version number of Firefox the current browser is based on. E.g. "102.15.0esr".
basebrowser-about-dialog-version = { $version } (based on Mozilla Firefox { $firefoxVersion })
+
+## New identity.
+
+# File menu items use title case for English (US).
+menu-new-identity =
+ .label = New Identity
+ .accesskey = I
+
+# App menu (hamburger menu) items use sentence case for English (US).
+appmenuitem-new-identity =
+ .label = New identity
+
+# Uses sentence case for English (US).
+# ".label" is the accessible name, and is visible in the overflow menu and when
+# customizing the toolbar.
+# ".tooltiptext" will be identical to the label.
+toolbar-new-identity =
+ .label = New identity
+ .tooltiptext = { toolbar-new-identity.label }
+
+## New identity dialog.
+
+new-identity-dialog-title = Reset your identity?
+new-identity-dialog-description = { -brand-short-name } will close all windows and tabs. All website sessions will be lost.
+new-identity-dialog-never-ask-checkbox =
+ .label = Never ask me again
+new-identity-dialog-confirm =
+ .label = Restart { -brand-short-name }
+
+## New identity: blocked home page notification.
+
+# '-brand-short-name' is the localized browser name, like "Tor Browser".
+# $url (String) - The URL of the home page, possibly shortened.
+new-identity-blocked-home-notification = { -brand-short-name } blocked your homepage ({ $url }) from loading because it might recognize your previous session.
+# Button to continue loading the home page, despite the warning message.
+new-identity-blocked-home-ignore-button = Load it anyway
=====================================
browser/locales/en-US/chrome/browser/newIdentity.properties deleted
=====================================
@@ -1,13 +0,0 @@
-new_identity = New Identity
-# This is the string for the hamburger menu
-new_identity_sentence_case = New identity
-# %S is the application name. Keep it as a placeholder
-new_identity_prompt_title = Reset your identity?
-new_identity_prompt = %S will close all windows and tabs. All website sessions will be lost. \nRestart %S now to reset your identity?
-new_identity_restart = Restart %S
-new_identity_ask_again = Never ask me again
-# Shown in the File menu (use Alt to show File, if you do not see)
-new_identity_menu_accesskey = I
-new_identity_home_notification = Tor Browser blocked your homepage (%S) from loading because it might recognize your previous session.
-# %S is replaced with the custom homepage URL's domain if applicable, or some short-hand of it otherwise
-new_identity_home_load_button = Load it anyway
=====================================
browser/locales/jar.mn
=====================================
@@ -34,6 +34,5 @@
locale/browser/feeds/subscribe.properties (%chrome/browser/feeds/subscribe.properties)
locale/browser/syncSetup.properties (%chrome/browser/syncSetup.properties)
locale/browser/securityLevel.properties (%chrome/browser/securityLevel.properties)
- locale/browser/newIdentity.properties (%chrome/browser/newIdentity.properties)
locale/browser/cryptoSafetyPrompt.properties (%chrome/browser/cryptoSafetyPrompt.properties)
% locale browser-region @AB_CD@ %locale/browser-region/
=====================================
tools/torbrowser/l10n/migrations/bug-42211-new-identity.py
=====================================
@@ -0,0 +1,48 @@
+import fluent.syntax.ast as FTL
+from fluent.migrate.helpers import TERM_REFERENCE, transforms_from
+from fluent.migrate.transforms import REPLACE
+
+
+def migrate(ctx):
+ legacy_path = "newIdentity.properties"
+
+ ctx.add_transforms(
+ "base-browser.ftl",
+ "base-browser.ftl",
+ transforms_from(
+ """
+menu-new-identity =
+ .label = { COPY(path, "new_identity") }
+ .accesskey = { COPY(path, "new_identity_menu_accesskey") }
+appmenuitem-new-identity =
+ .label = { COPY(path, "new_identity_sentence_case") }
+toolbar-new-identity =
+ .label = { COPY(path, "new_identity_sentence_case") }
+ .tooltiptext = { toolbar-new-identity.label }
+
+new-identity-dialog-title = { COPY(path, "new_identity_prompt_title") }
+new-identity-dialog-never-ask-checkbox =
+ .label = { COPY(path, "new_identity_ask_again") }
+
+new-identity-blocked-home-ignore-button = { COPY(path, "new_identity_home_load_button") }
+""",
+ path=legacy_path,
+ )
+ + [
+ # Replace "%S" with "{ -brand-short-name }" in confirm button.
+ FTL.Message(
+ id=FTL.Identifier("new-identity-dialog-confirm"),
+ value=None,
+ attributes=[
+ FTL.Attribute(
+ id=FTL.Identifier("label"),
+ value=REPLACE(
+ legacy_path,
+ "new_identity_restart",
+ {"%1$S": TERM_REFERENCE("brand-short-name")},
+ ),
+ ),
+ ],
+ ),
+ ],
+ )
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/c122e1…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/c122e1…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/mullvad-browser][mullvad-browser-115.9.0esr-13.5-1] Bug 42428: Make RFP spoof the timezone of document.lastModified.
by Pier Angelo Vendrame (@pierov) 20 Mar '24
by Pier Angelo Vendrame (@pierov) 20 Mar '24
20 Mar '24
Pier Angelo Vendrame pushed to branch mullvad-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Mullvad Browser
Commits:
96ab6401 by Pier Angelo Vendrame at 2024-03-20T11:06:04+01:00
Bug 42428: Make RFP spoof the timezone of document.lastModified.
- - - - -
1 changed file:
- dom/base/Document.cpp
Changes:
=====================================
dom/base/Document.cpp
=====================================
@@ -4103,10 +4103,11 @@ void Document::SetDocumentURI(nsIURI* aURI) {
}
}
-static void GetFormattedTimeString(PRTime aTime,
+static void GetFormattedTimeString(PRTime aTime, bool aUniversal,
nsAString& aFormattedTimeString) {
PRExplodedTime prtime;
- PR_ExplodeTime(aTime, PR_LocalTimeParameters, &prtime);
+ PR_ExplodeTime(aTime, aUniversal ? PR_GMTParameters : PR_LocalTimeParameters,
+ &prtime);
// "MM/DD/YYYY hh:mm:ss"
char formatedTime[24];
if (SprintfLiteral(formatedTime, "%02d/%02d/%04d %02d:%02d:%02d",
@@ -4124,7 +4125,9 @@ void Document::GetLastModified(nsAString& aLastModified) const {
if (!mLastModified.IsEmpty()) {
aLastModified.Assign(mLastModified);
} else {
- GetFormattedTimeString(PR_Now(), aLastModified);
+ GetFormattedTimeString(PR_Now(),
+ ShouldResistFingerprinting(RFPTarget::Unknown),
+ aLastModified);
}
}
@@ -11053,7 +11056,8 @@ void Document::RetrieveRelevantHeaders(nsIChannel* aChannel) {
mLastModified.Truncate();
if (modDate != 0) {
- GetFormattedTimeString(modDate, mLastModified);
+ GetFormattedTimeString(
+ modDate, ShouldResistFingerprinting(RFPTarget::Unknown), mLastModified);
}
}
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/96a…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/96a…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][base-browser-115.9.0esr-13.5-1] Bug 42428: Make RFP spoof the timezone of document.lastModified.
by Pier Angelo Vendrame (@pierov) 20 Mar '24
by Pier Angelo Vendrame (@pierov) 20 Mar '24
20 Mar '24
Pier Angelo Vendrame pushed to branch base-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
369e1367 by Pier Angelo Vendrame at 2024-03-20T11:05:38+01:00
Bug 42428: Make RFP spoof the timezone of document.lastModified.
- - - - -
1 changed file:
- dom/base/Document.cpp
Changes:
=====================================
dom/base/Document.cpp
=====================================
@@ -4103,10 +4103,11 @@ void Document::SetDocumentURI(nsIURI* aURI) {
}
}
-static void GetFormattedTimeString(PRTime aTime,
+static void GetFormattedTimeString(PRTime aTime, bool aUniversal,
nsAString& aFormattedTimeString) {
PRExplodedTime prtime;
- PR_ExplodeTime(aTime, PR_LocalTimeParameters, &prtime);
+ PR_ExplodeTime(aTime, aUniversal ? PR_GMTParameters : PR_LocalTimeParameters,
+ &prtime);
// "MM/DD/YYYY hh:mm:ss"
char formatedTime[24];
if (SprintfLiteral(formatedTime, "%02d/%02d/%04d %02d:%02d:%02d",
@@ -4124,7 +4125,9 @@ void Document::GetLastModified(nsAString& aLastModified) const {
if (!mLastModified.IsEmpty()) {
aLastModified.Assign(mLastModified);
} else {
- GetFormattedTimeString(PR_Now(), aLastModified);
+ GetFormattedTimeString(PR_Now(),
+ ShouldResistFingerprinting(RFPTarget::Unknown),
+ aLastModified);
}
}
@@ -11053,7 +11056,8 @@ void Document::RetrieveRelevantHeaders(nsIChannel* aChannel) {
mLastModified.Truncate();
if (modDate != 0) {
- GetFormattedTimeString(modDate, mLastModified);
+ GetFormattedTimeString(
+ modDate, ShouldResistFingerprinting(RFPTarget::Unknown), mLastModified);
}
}
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/369e136…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/369e136…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.9.0esr-13.5-1] Bug 42428: Make RFP spoof the timezone of document.lastModified.
by Pier Angelo Vendrame (@pierov) 20 Mar '24
by Pier Angelo Vendrame (@pierov) 20 Mar '24
20 Mar '24
Pier Angelo Vendrame pushed to branch tor-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
c122e13b by Pier Angelo Vendrame at 2024-03-20T10:47:58+01:00
Bug 42428: Make RFP spoof the timezone of document.lastModified.
- - - - -
1 changed file:
- dom/base/Document.cpp
Changes:
=====================================
dom/base/Document.cpp
=====================================
@@ -4104,10 +4104,11 @@ void Document::SetDocumentURI(nsIURI* aURI) {
}
}
-static void GetFormattedTimeString(PRTime aTime,
+static void GetFormattedTimeString(PRTime aTime, bool aUniversal,
nsAString& aFormattedTimeString) {
PRExplodedTime prtime;
- PR_ExplodeTime(aTime, PR_LocalTimeParameters, &prtime);
+ PR_ExplodeTime(aTime, aUniversal ? PR_GMTParameters : PR_LocalTimeParameters,
+ &prtime);
// "MM/DD/YYYY hh:mm:ss"
char formatedTime[24];
if (SprintfLiteral(formatedTime, "%02d/%02d/%04d %02d:%02d:%02d",
@@ -4125,7 +4126,9 @@ void Document::GetLastModified(nsAString& aLastModified) const {
if (!mLastModified.IsEmpty()) {
aLastModified.Assign(mLastModified);
} else {
- GetFormattedTimeString(PR_Now(), aLastModified);
+ GetFormattedTimeString(PR_Now(),
+ ShouldResistFingerprinting(RFPTarget::Unknown),
+ aLastModified);
}
}
@@ -11113,7 +11116,8 @@ void Document::RetrieveRelevantHeaders(nsIChannel* aChannel) {
mLastModified.Truncate();
if (modDate != 0) {
- GetFormattedTimeString(modDate, mLastModified);
+ GetFormattedTimeString(
+ modDate, ShouldResistFingerprinting(RFPTarget::Unknown), mLastModified);
}
}
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/c122e13…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/c122e13…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.9.0esr-13.5-1] fixup! Bug 42247: Android helpers for the TorProvider
by Pier Angelo Vendrame (@pierov) 20 Mar '24
by Pier Angelo Vendrame (@pierov) 20 Mar '24
20 Mar '24
Pier Angelo Vendrame pushed to branch tor-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
c2461f1d by clairehurst at 2024-03-20T09:39:13+01:00
fixup! Bug 42247: Android helpers for the TorProvider
Moved setSettings and TorLegacyAndroidSettings.setMigrated() into a new
if block in onPostExecute() from doInBackground().
- - - - -
1 changed file:
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
Changes:
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
=====================================
@@ -181,8 +181,6 @@ public class TorIntegrationAndroid implements BundleEventListener {
TorSettings settings;
if (TorLegacyAndroidSettings.unmigrated()) {
settings = TorLegacyAndroidSettings.loadTorSettings();
- setSettings(settings, true, true);
- TorLegacyAndroidSettings.setMigrated();
} else {
GeckoBundle bundle = message.getBundle("settings");
settings = new TorSettings(bundle);
@@ -193,6 +191,10 @@ public class TorIntegrationAndroid implements BundleEventListener {
@Override
protected void onPostExecute(TorSettings torSettings) {
mSettings = torSettings;
+ if (TorLegacyAndroidSettings.unmigrated()) {
+ setSettings(mSettings, true, true);
+ TorLegacyAndroidSettings.setMigrated();
+ }
}
}
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/c2461f1…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/c2461f1…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build][maint-13.0] Bug 41107: Add new type of URL for downloading signatures from people.tpo
by boklm (@boklm) 20 Mar '24
by boklm (@boklm) 20 Mar '24
20 Mar '24
boklm pushed to branch maint-13.0 at The Tor Project / Applications / tor-browser-build
Commits:
3ff1d54a by Nicolas Vigier at 2024-03-19T16:14:48+01:00
Bug 41107: Add new type of URL for downloading signatures from people.tpo
- - - - -
1 changed file:
- tools/signing/download-unsigned-sha256sums-gpg-signatures-from-people-tpo
Changes:
=====================================
tools/signing/download-unsigned-sha256sums-gpg-signatures-from-people-tpo
=====================================
@@ -16,6 +16,7 @@ do
file="$file.asc"
urls=( \
"https://people.torproject.org/~$builder/builds/$SIGNING_PROJECTNAME/$tbb_ve…" \
+ "https://people.torproject.org/~$builder/builds/$SIGNING_PROJECTNAME/$tbb_ve…" \
"https://tb-build-02.torproject.org/~$builder/builds/$SIGNING_PROJECTNAME/$t…" \
"https://tb-build-03.torproject.org/~$builder/builds/$SIGNING_PROJECTNAME/$t…" \
)
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][main] Bug 41107: Add new type of URL for downloading signatures from people.tpo
by boklm (@boklm) 20 Mar '24
by boklm (@boklm) 20 Mar '24
20 Mar '24
boklm pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
9e7707b6 by Nicolas Vigier at 2024-03-19T16:12:58+01:00
Bug 41107: Add new type of URL for downloading signatures from people.tpo
- - - - -
1 changed file:
- tools/signing/download-unsigned-sha256sums-gpg-signatures-from-people-tpo
Changes:
=====================================
tools/signing/download-unsigned-sha256sums-gpg-signatures-from-people-tpo
=====================================
@@ -16,6 +16,7 @@ do
file="$file.asc"
urls=( \
"https://people.torproject.org/~$builder/builds/$SIGNING_PROJECTNAME/$tbb_ve…" \
+ "https://people.torproject.org/~$builder/builds/$SIGNING_PROJECTNAME/$tbb_ve…" \
"https://tb-build-02.torproject.org/~$builder/builds/$SIGNING_PROJECTNAME/$t…" \
"https://tb-build-03.torproject.org/~$builder/builds/$SIGNING_PROJECTNAME/$t…" \
)
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/9…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/9…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/mullvad-browser][mullvad-browser-115.9.0esr-13.0-1] 2 commits: fixup! Bug 42377: Hidden fonts should obey the allow list.
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch mullvad-browser-115.9.0esr-13.0-1 at The Tor Project / Applications / Mullvad Browser
Commits:
bb650dcc by Pier Angelo Vendrame at 2024-03-19T21:23:18+00:00
fixup! Bug 42377: Hidden fonts should obey the allow list.
Revert "Bug 42377: Hidden fonts should obey the allow list."
This reverts commit 3488619aedbc183d54c794ac9e9a9c2f642df4e0.
- - - - -
02311333 by Tom Ritter at 2024-03-19T21:23:24+00:00
Bug 1885258: Hidden fonts should obey the allow list r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D204571
- - - - -
0 changed files:
Changes:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/b1…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/b1…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/mullvad-browser][mullvad-browser-115.9.0esr-13.5-1] 2 commits: fixup! Bug 42377: Hidden fonts should obey the allow list.
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch mullvad-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Mullvad Browser
Commits:
3e30bb9c by Pier Angelo Vendrame at 2024-03-19T21:21:49+00:00
fixup! Bug 42377: Hidden fonts should obey the allow list.
Revert "Bug 42377: Hidden fonts should obey the allow list."
This reverts commit 3488619aedbc183d54c794ac9e9a9c2f642df4e0.
- - - - -
41286b4a by Tom Ritter at 2024-03-19T21:21:56+00:00
Bug 1885258: Hidden fonts should obey the allow list r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D204571
- - - - -
0 changed files:
Changes:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/be…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/be…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][base-browser-115.9.0esr-13.0-1] 2 commits: fixup! Bug 42377: Hidden fonts should obey the allow list.
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch base-browser-115.9.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
3b45e022 by Pier Angelo Vendrame at 2024-03-19T21:20:21+00:00
fixup! Bug 42377: Hidden fonts should obey the allow list.
Revert "Bug 42377: Hidden fonts should obey the allow list."
This reverts commit 3488619aedbc183d54c794ac9e9a9c2f642df4e0.
- - - - -
9d200f6f by Tom Ritter at 2024-03-19T21:20:28+00:00
Bug 1885258: Hidden fonts should obey the allow list r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D204571
- - - - -
0 changed files:
Changes:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/cce16c…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/cce16c…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.9.0esr-13.0-1] 2 commits: fixup! Bug 42377: Hidden fonts should obey the allow list.
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch tor-browser-115.9.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
776dc982 by Pier Angelo Vendrame at 2024-03-19T21:18:58+00:00
fixup! Bug 42377: Hidden fonts should obey the allow list.
Revert "Bug 42377: Hidden fonts should obey the allow list."
This reverts commit 3488619aedbc183d54c794ac9e9a9c2f642df4e0.
- - - - -
0acc9079 by Tom Ritter at 2024-03-19T21:19:04+00:00
Bug 1885258: Hidden fonts should obey the allow list r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D204571
- - - - -
0 changed files:
Changes:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/ae9239…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/ae9239…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][base-browser-115.9.0esr-13.5-1] 2 commits: fixup! Bug 42377: Hidden fonts should obey the allow list.
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch base-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
cc54cc20 by Pier Angelo Vendrame at 2024-03-19T21:17:03+00:00
fixup! Bug 42377: Hidden fonts should obey the allow list.
Revert "Bug 42377: Hidden fonts should obey the allow list."
This reverts commit 3488619aedbc183d54c794ac9e9a9c2f642df4e0.
- - - - -
5a94a796 by Tom Ritter at 2024-03-19T21:17:09+00:00
Bug 1885258: Hidden fonts should obey the allow list r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D204571
- - - - -
0 changed files:
Changes:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/aefa5f…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/aefa5f…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.9.0esr-13.5-1] 2 commits: fixup! Bug 42377: Hidden fonts should obey the allow list.
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch tor-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
4f66c661 by Pier Angelo Vendrame at 2024-03-19T21:14:27+00:00
fixup! Bug 42377: Hidden fonts should obey the allow list.
Revert "Bug 42377: Hidden fonts should obey the allow list."
This reverts commit 3488619aedbc183d54c794ac9e9a9c2f642df4e0.
- - - - -
efae771c by Tom Ritter at 2024-03-19T21:14:27+00:00
Bug 1885258: Hidden fonts should obey the allow list r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D204571
- - - - -
0 changed files:
Changes:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/70684f…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/70684f…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.9.0esr-13.5-1] fixup! Bug 40562: Added Tor Browser preferences to 000-tor-browser.js
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch tor-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
70684ff4 by Richard Pospesel at 2024-03-19T21:12:29+00:00
fixup! Bug 40562: Added Tor Browser preferences to 000-tor-browser.js
Bug 42458: Update the "Submit Feedback" link in "About Tor Browser"
- - - - -
1 changed file:
- browser/app/profile/000-tor-browser.js
Changes:
=====================================
browser/app/profile/000-tor-browser.js
=====================================
@@ -10,7 +10,7 @@ pref("app.releaseNotesURL", "about:blank");
// easily found in about:tor
pref("app.releaseNotesURL.aboutDialog", "about:blank");
// point to our feedback url rather than Mozilla's
-pref("app.feedback.baseURL", "https://support.torproject.org/%LOCALE%/get-in-touch/");
+pref("app.feedback.baseURL", "https://support.torproject.org/%LOCALE%/misc/bug-or-feedback/");
pref("browser.shell.checkDefaultBrowser", false);
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/70684ff…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/70684ff…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-update-responses][main] release: new version, 13.0.12
by boklm (@boklm) 19 Mar '24
by boklm (@boklm) 19 Mar '24
19 Mar '24
boklm pushed to branch main at The Tor Project / Applications / Tor Browser update responses
Commits:
0cce8359 by Nicolas Vigier at 2024-03-19T14:52:57+01:00
release: new version, 13.0.12
- - - - -
30 changed files:
- update_3/release/.htaccess
- − update_3/release/13.0.10-13.0.11-linux-i686-ALL.xml
- − update_3/release/13.0.10-13.0.11-linux-x86_64-ALL.xml
- − update_3/release/13.0.10-13.0.11-macos-ALL.xml
- − update_3/release/13.0.10-13.0.11-windows-i686-ALL.xml
- − update_3/release/13.0.10-13.0.11-windows-x86_64-ALL.xml
- + update_3/release/13.0.10-13.0.12-linux-i686-ALL.xml
- + update_3/release/13.0.10-13.0.12-linux-x86_64-ALL.xml
- + update_3/release/13.0.10-13.0.12-macos-ALL.xml
- + update_3/release/13.0.10-13.0.12-windows-i686-ALL.xml
- + update_3/release/13.0.10-13.0.12-windows-x86_64-ALL.xml
- + update_3/release/13.0.11-13.0.12-linux-i686-ALL.xml
- + update_3/release/13.0.11-13.0.12-linux-x86_64-ALL.xml
- + update_3/release/13.0.11-13.0.12-macos-ALL.xml
- + update_3/release/13.0.11-13.0.12-windows-i686-ALL.xml
- + update_3/release/13.0.11-13.0.12-windows-x86_64-ALL.xml
- − update_3/release/13.0.11-linux-i686-ALL.xml
- − update_3/release/13.0.11-linux-x86_64-ALL.xml
- − update_3/release/13.0.11-macos-ALL.xml
- − update_3/release/13.0.11-windows-i686-ALL.xml
- − update_3/release/13.0.11-windows-x86_64-ALL.xml
- + update_3/release/13.0.12-linux-i686-ALL.xml
- + update_3/release/13.0.12-linux-x86_64-ALL.xml
- + update_3/release/13.0.12-macos-ALL.xml
- + update_3/release/13.0.12-windows-i686-ALL.xml
- + update_3/release/13.0.12-windows-x86_64-ALL.xml
- − update_3/release/13.0.8-13.0.11-linux-i686-ALL.xml
- − update_3/release/13.0.8-13.0.11-linux-x86_64-ALL.xml
- − update_3/release/13.0.8-13.0.11-macos-ALL.xml
- − update_3/release/13.0.8-13.0.11-windows-i686-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][tor-browser-115.9.0esr-13.5-1] 20 commits: fixup! Bug 40597: Implement TorSettings module
by Pier Angelo Vendrame (@pierov) 19 Mar '24
by Pier Angelo Vendrame (@pierov) 19 Mar '24
19 Mar '24
Pier Angelo Vendrame pushed to branch tor-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
b8fbdc2b by Pier Angelo Vendrame at 2024-03-19T08:19:47+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Use actual private members in InternetTest, and unify the test and
testAsync methods.
- - - - -
2b75d115 by Pier Angelo Vendrame at 2024-03-19T08:19:54+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
The purpose of this commit is just to make the review easier.
It moves the various state callbacks in another part of the file (and
gives them names, to refer to them).
They are not linted/formatted on purpose, to allow checking that the
changes are minimal with the `--color-moved` option.
- - - - -
0c5e98ab by Pier Angelo Vendrame at 2024-03-19T08:19:54+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
The purpose of this commit is just to make the review easier.
It lints the previous commit to make it closer to the next form it will
take.
To review this commit, you can lint TorConnect.sys.mjs and check you
obtain the same result.
- - - - -
8708b47a by Pier Angelo Vendrame at 2024-03-19T08:19:54+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Add a specialized class for every state.
Removed TorConnectStateTransitions and store the valid transitions
inside the new classes.
- - - - -
d5d15e38 by Pier Angelo Vendrame at 2024-03-19T08:19:55+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Removes the context from StateCallback.
Instead, we will always initialize new objects.
- - - - -
929972af by Pier Angelo Vendrame at 2024-03-19T08:19:55+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Fix no-async-promise-executor on TorConnect.
Move the responsibility of starting the next state callback and broadcat
the state change from the begin function to the transition function.
This is what will actually empower us to remove the async promise
executor, because they will not have to block the state change anymore.
- - - - -
f9d3e162 by Pier Angelo Vendrame at 2024-03-19T08:19:55+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Fix no-async-promise-executor on TorConnect.
Now that callbacks have been lifted from the responsibility of blocking
the transition, they do not have to explicitly resolve anymore.
So, get rid of the various promises, and make the old callbacks regular
methods of the corresponding classes.
Also, updated the documentation.
- - - - -
d214f39b by Pier Angelo Vendrame at 2024-03-19T08:19:56+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Add the changeState method to StateCallback, other minor changes.
- - - - -
0e97bf55 by Pier Angelo Vendrame at 2024-03-19T08:19:56+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Move some parts of BootstrappingState.run to methods on their own, to
make it easier to understand this function.
- - - - -
1243f925 by Pier Angelo Vendrame at 2024-03-19T08:19:56+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Various refactors to AutoBootstrappingState.
- - - - -
34868388 by Pier Angelo Vendrame at 2024-03-19T08:19:57+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
TorConnect does not need to be defined in a function.
- - - - -
7218d77c by Pier Angelo Vendrame at 2024-03-19T08:19:57+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
First batch of changes requested in the review.
- - - - -
546449ce by Pier Angelo Vendrame at 2024-03-19T08:19:57+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
More changes on the InternetTest class.
- - - - -
5fe62195 by Pier Angelo Vendrame at 2024-03-19T08:19:58+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Additional refactor to the AutoBootstrappingState: split the run in
more methods, removed some layers of try-catch.
- - - - -
becb5e4b by Pier Angelo Vendrame at 2024-03-19T08:19:58+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Additional refactor to the AutoBootstrappingState: be consistent in
initializing private members and document that in case of race some
variables might be set to undefined.
Also, do not store the bootstrap as a member, to avoid possible race
conditions.
- - - - -
1343ed70 by Pier Angelo Vendrame at 2024-03-19T08:19:58+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
When simulating censorship, do not trigger an additional change of state
if one is already happening.
- - - - -
6bdd9dcd by Pier Angelo Vendrame at 2024-03-19T08:19:59+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Check if the current state is already transitioning, and refusing any
additional transition request.
- - - - -
22b986b8 by Pier Angelo Vendrame at 2024-03-19T08:19:59+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Do not await TorSettings.applySettings after a successfull bootstrap.
Instead, we use .catch and log any unexpected results.
- - - - -
f59ddd26 by Pier Angelo Vendrame at 2024-03-19T08:19:59+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Ignore cancel requests when in non-bootstrapping states.
- - - - -
3788b1ae by Pier Angelo Vendrame at 2024-03-19T08:20:00+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 41114: Refactor TorConnect.
Pass only the new state's name to StateCallback.end.
- - - - -
2 changed files:
- toolkit/modules/Moat.sys.mjs
- toolkit/modules/TorConnect.sys.mjs
Changes:
=====================================
toolkit/modules/Moat.sys.mjs
=====================================
@@ -85,9 +85,13 @@ export class MoatRPC {
TorLauncherPrefs.bridgedb_reflector
);
const front = Services.prefs.getStringPref(TorLauncherPrefs.bridgedb_front);
- const builder = new lazy.DomainFrontRequestBuilder();
- await builder.init(reflector, front);
- this.#requestBuilder = builder;
+ this.#requestBuilder = new lazy.DomainFrontRequestBuilder();
+ try {
+ await this.#requestBuilder.init(reflector, front);
+ } catch (e) {
+ this.#requestBuilder = null;
+ throw e;
+ }
}
async uninit() {
=====================================
toolkit/modules/TorConnect.sys.mjs
=====================================
@@ -117,52 +117,6 @@ XPCOMUtils.defineLazyGetter(
└───────────────────────┘
*/
-/* Maps allowed state transitions
- TorConnectStateTransitions[state] maps to an array of allowed states to transition to
- This is just an encoding of the above transition diagram that we verify at runtime
-*/
-const TorConnectStateTransitions = Object.freeze(
- new Map([
- [
- TorConnectState.Initial,
- [
- TorConnectState.Disabled,
- TorConnectState.Bootstrapping,
- TorConnectState.Configuring,
- TorConnectState.Error,
- ],
- ],
- [
- TorConnectState.Configuring,
- [
- TorConnectState.AutoBootstrapping,
- TorConnectState.Bootstrapping,
- TorConnectState.Error,
- ],
- ],
- [
- TorConnectState.AutoBootstrapping,
- [
- TorConnectState.Configuring,
- TorConnectState.Bootstrapped,
- TorConnectState.Error,
- ],
- ],
- [
- TorConnectState.Bootstrapping,
- [
- TorConnectState.Configuring,
- TorConnectState.Bootstrapped,
- TorConnectState.Error,
- ],
- ],
- [TorConnectState.Error, [TorConnectState.Configuring]],
- [TorConnectState.Bootstrapped, [TorConnectState.Configuring]],
- // terminal states
- [TorConnectState.Disabled, []],
- ])
-);
-
/* Topics Notified by the TorConnect module */
export const TorConnectTopics = Object.freeze({
StateChange: "torconnect:state-change",
@@ -171,81 +125,612 @@ export const TorConnectTopics = Object.freeze({
BootstrapError: "torconnect:bootstrap-error",
});
-// The StateCallback is a wrapper around an async function which executes during
-// the lifetime of a TorConnect State. A system is also provided to allow this
-// ongoing function to early-out via a per StateCallback on_transition callback
-// which may be called externally when we need to early-out and move on to another
-// state (for example, from Bootstrapping to Configuring in the event the user
-// cancels a bootstrap attempt)
+// The StateCallback is the base class to implement the various states.
+// All states should extend it and implement a `run` function, which can
+// optionally be async, and define an array of valid transitions.
+// The parent class will handle everything else, including the transition to
+// other states when the run function is complete etc...
+// A system is also provided to allow this function to early-out. The runner
+// should check the transitioning getter when appropriate and return.
+// In addition to that, a state can implement a transitionRequested callback,
+// which can be used in conjunction with a mechanism like Promise.race.
+// This allows to handle, for example, users' requests to cancel a bootstrap
+// attempt.
+// A state can optionally define a cleanup function, that will be run in all
+// cases before transitioning to the next state.
class StateCallback {
- constructor(state, callback) {
- this._state = state;
- this._callback = callback;
- this._init();
- }
+ #state;
+ #promise;
+ #transitioning = false;
- _init() {
- // this context object is bound to the callback each time transition is
- // attempted via begin()
- this._context = {
- // This callback may be overwritten in the _callback for each state
- // States may have various pieces of work which need to occur
- // before they can be exited (eg resource cleanup)
- // See the _stateCallbacks map for examples
- on_transition: nextState => {},
-
- // flag used to determine if a StateCallback should early-out
- // its work
- _transitioning: false,
-
- // may be called within the StateCallback to determine if exit is possible
- get transitioning() {
- return this._transitioning;
- },
- };
+ constructor(stateName) {
+ this.#state = stateName;
}
async begin(...args) {
- lazy.logger.trace(`Entering ${this._state} state`);
- this._init();
+ lazy.logger.trace(`Entering ${this.#state} state`);
+ // Make sure we always have an actual promise.
try {
- // this Promise will block until this StateCallback has completed its work
- await Promise.resolve(this._callback.call(this._context, ...args));
- lazy.logger.info(`Exited ${this._state} state`);
-
- // handled state transition
- Services.obs.notifyObservers(
- { state: this._nextState },
- TorConnectTopics.StateChange
- );
- TorConnect._callback(this._nextState).begin(...this._nextStateArgs);
- } catch (obj) {
- TorConnect._changeState(
- TorConnectState.Error,
- obj?.message,
- obj?.details
+ this.#promise = Promise.resolve(this.run(...args));
+ } catch (err) {
+ this.#promise = Promise.reject(err);
+ }
+ try {
+ // If the callback throws, transition to error as soon as possible.
+ await this.#promise;
+ lazy.logger.info(`${this.#state}'s run is done`);
+ } catch (err) {
+ if (this.transitioning) {
+ lazy.logger.error(
+ `A transition from ${
+ this.#state
+ } is already happening, silencing this exception.`,
+ err
+ );
+ return;
+ }
+ lazy.logger.error(
+ `${this.#state}'s run threw, transitioning to the Error state.`,
+ err
);
+ this.changeState(TorConnectState.Error, err?.message, err?.details);
+ }
+ }
+
+ async end(nextState) {
+ lazy.logger.trace(
+ `Ending state ${this.#state} (to transition to ${nextState})`
+ );
+
+ if (this.#transitioning) {
+ // Should we check turn this into an error?
+ // It will make dealing with the error state harder.
+ lazy.logger.warn("this.#transitioning is already true.");
+ }
+
+ // Signal we should bail out ASAP.
+ this.#transitioning = true;
+ if (this.transitionRequested) {
+ this.transitionRequested();
}
+
+ lazy.logger.debug(
+ `Waiting for the ${
+ this.#state
+ }'s callback to return before the transition.`
+ );
+ try {
+ await this.#promise;
+ } finally {
+ lazy.logger.debug(`Calling ${this.#state}'s cleanup, if implemented.`);
+ if (this.cleanup) {
+ try {
+ await this.cleanup(nextState);
+ lazy.logger.debug(`${this.#state}'s cleanup function done.`);
+ } catch (e) {
+ lazy.logger.warn(`${this.#state}'s cleanup function threw.`, e);
+ }
+ }
+ }
+ }
+
+ changeState(stateName, ...args) {
+ TorConnect._changeState(stateName, ...args);
}
- transition(nextState, ...args) {
- this._nextState = nextState;
- this._nextStateArgs = [...args];
+ get transitioning() {
+ return this.#transitioning;
+ }
- // calls the on_transition callback to resolve any async work or do per-state cleanup
- // this call to on_transition should resolve the async work currentlying going on in this.begin()
- this._context.on_transition(nextState);
- this._context._transitioning = true;
+ get state() {
+ return this.#state;
}
}
// async method to sleep for a given amount of time
-const debug_sleep = async ms => {
+const debugSleep = async ms => {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms);
});
};
+class InitialState extends StateCallback {
+ allowedTransitions = Object.freeze([
+ TorConnectState.Disabled,
+ TorConnectState.Bootstrapping,
+ TorConnectState.Configuring,
+ TorConnectState.Error,
+ ]);
+
+ constructor() {
+ super(TorConnectState.Initial);
+ }
+
+ run() {
+ // TODO: Block this transition until we successfully build a TorProvider.
+ }
+}
+
+class ConfiguringState extends StateCallback {
+ allowedTransitions = Object.freeze([
+ TorConnectState.AutoBootstrapping,
+ TorConnectState.Bootstrapping,
+ TorConnectState.Error,
+ ]);
+
+ constructor() {
+ super(TorConnectState.Configuring);
+ }
+
+ run() {
+ // The configuring state does not do anything.
+ }
+}
+
+class BootstrappingState extends StateCallback {
+ #bootstrap = null;
+ #bootstrapError = "";
+ #bootstrapErrorDetails = "";
+ #internetTest = null;
+ #cancelled = false;
+
+ allowedTransitions = Object.freeze([
+ TorConnectState.Configuring,
+ TorConnectState.Bootstrapped,
+ TorConnectState.Error,
+ ]);
+
+ constructor() {
+ super(TorConnectState.Bootstrapping);
+ }
+
+ async run() {
+ if (await this.#simulateCensorship()) {
+ return;
+ }
+
+ this.#bootstrap = new lazy.TorBootstrapRequest();
+ this.#bootstrap.onbootstrapstatus = (progress, status) => {
+ TorConnect._updateBootstrapStatus(progress, status);
+ };
+ this.#bootstrap.onbootstrapcomplete = () => {
+ this.#internetTest.cancel();
+ this.changeState(TorConnectState.Bootstrapped);
+ };
+ this.#bootstrap.onbootstraperror = (message, details) => {
+ if (this.#cancelled) {
+ // We ignore this error since it occurred after cancelling (by the
+ // user). We assume the error is just a side effect of the cancelling.
+ // E.g. If the cancelling is triggered late in the process, we get
+ // "Building circuits: Establishing a Tor circuit failed".
+ // TODO: Maybe move this logic deeper in the process to know when to
+ // filter out such errors triggered by cancelling.
+ lazy.logger.warn(`Post-cancel error => ${message}; ${details}`);
+ return;
+ }
+ // We have to wait for the Internet test to finish before sending the
+ // bootstrap error
+ this.#bootstrapError = message;
+ this.#bootstrapErrorDetails = details;
+ this.#maybeTransitionToError();
+ };
+
+ this.#internetTest = new InternetTest();
+ this.#internetTest.onResult = status => {
+ TorConnect._internetStatus = status;
+ this.#maybeTransitionToError();
+ };
+ this.#internetTest.onError = () => {
+ this.#maybeTransitionToError();
+ };
+
+ this.#bootstrap.bootstrap();
+ }
+
+ async cleanup(nextState) {
+ if (nextState === TorConnectState.Configuring) {
+ // stop bootstrap process if user cancelled
+ this.#cancelled = true;
+ this.#internetTest?.cancel();
+ await this.#bootstrap?.cancel();
+ }
+ }
+
+ #maybeTransitionToError() {
+ if (
+ this.#internetTest.status === InternetStatus.Unknown &&
+ this.#internetTest.error === null &&
+ this.#internetTest.enabled
+ ) {
+ // We have been called by a failed bootstrap, but the internet test has
+ // not run yet - force it to run immediately!
+ this.#internetTest.test();
+ // Return from this call, because the Internet test's callback will call
+ // us again.
+ return;
+ }
+ // Do not transition to the offline error until we are sure that also the
+ // bootstrap failed, in case Moat is down but the bootstrap can proceed
+ // anyway.
+ if (this.#bootstrapError === "") {
+ return;
+ }
+ if (this.#internetTest.status === InternetStatus.Offline) {
+ this.changeState(
+ TorConnectState.Error,
+ TorStrings.torConnect.offline,
+ ""
+ );
+ } else {
+ // Give priority to the bootstrap error, in case the Internet test fails
+ TorConnect._hasBootstrapEverFailed = true;
+ this.changeState(
+ TorConnectState.Error,
+ this.#bootstrapError,
+ this.#bootstrapErrorDetails
+ );
+ }
+ }
+
+ async #simulateCensorship() {
+ // debug hook to simulate censorship preventing bootstrapping
+ const censorshipLevel = Services.prefs.getIntPref(
+ TorConnectPrefs.censorship_level,
+ 0
+ );
+ if (censorshipLevel <= 0) {
+ return false;
+ }
+
+ await debugSleep(1500);
+ if (this.transitioning) {
+ // Already left this state.
+ return true;
+ }
+ TorConnect._hasBootstrapEverFailed = true;
+ if (censorshipLevel === 2) {
+ const codes = Object.keys(TorConnect._countryNames);
+ TorConnect._detectedLocation =
+ codes[Math.floor(Math.random() * codes.length)];
+ }
+ this.changeState(
+ TorConnectState.Error,
+ "Bootstrap failed (for debugging purposes)",
+ "Error: Censorship simulation"
+ );
+ return true;
+ }
+}
+
+class AutoBootstrappingState extends StateCallback {
+ #moat;
+ #settings;
+ #changedSettings = false;
+ #transitionPromise;
+ #transitionResolve;
+
+ allowedTransitions = Object.freeze([
+ TorConnectState.Configuring,
+ TorConnectState.Bootstrapped,
+ TorConnectState.Error,
+ ]);
+
+ constructor() {
+ super(TorConnectState.AutoBootstrapping);
+ this.#transitionPromise = new Promise(resolve => {
+ this.#transitionResolve = resolve;
+ });
+ }
+
+ async run(countryCode) {
+ if (await this.#simulateCensorship(countryCode)) {
+ return;
+ }
+ await this.#initMoat();
+ if (this.transitioning) {
+ return;
+ }
+ await this.#fetchSettings(countryCode);
+ if (this.transitioning) {
+ return;
+ }
+ await this.#trySettings();
+ }
+
+ /**
+ * Simulate a censorship event, if needed.
+ *
+ * @param {string} countryCode The country code passed to the state
+ * @returns {Promise<boolean>} true if we are simulating the censorship and
+ * the bootstrap should stop immediately, or false if the bootstrap should
+ * continue normally.
+ */
+ async #simulateCensorship(countryCode) {
+ const censorshipLevel = Services.prefs.getIntPref(
+ TorConnectPrefs.censorship_level,
+ 0
+ );
+ if (censorshipLevel <= 0) {
+ return false;
+ }
+
+ // Very severe censorship: always fail even after manually selecting
+ // location specific settings.
+ if (censorshipLevel === 3) {
+ await debugSleep(2500);
+ if (!this.transitioning) {
+ this.changeState(
+ TorConnectState.Error,
+ "Error: censorship simulation",
+ ""
+ );
+ }
+ return true;
+ }
+
+ // Severe censorship: only fail after auto selecting, but succeed after
+ // manually selecting a country.
+ if (censorshipLevel === 2 && !countryCode) {
+ await debugSleep(2500);
+ if (!this.transitioning) {
+ this.changeState(
+ TorConnectState.Error,
+ "Error: Severe Censorship simulation",
+ ""
+ );
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Initialize the MoatRPC to communicate with the backend.
+ */
+ async #initMoat() {
+ this.#moat = new lazy.MoatRPC();
+ // We need to wait Moat's initialization even when we are requested to
+ // transition to another state to be sure its uninit will have its intended
+ // effect. So, do not use Promise.race here.
+ await this.#moat.init();
+ }
+
+ /**
+ * Lookup user's potential censorship circumvention settings from Moat
+ * service.
+ */
+ async #fetchSettings(countryCode) {
+ // For now, throw any errors we receive from the backend, except when it was
+ // unable to detect user's country/region.
+ // If we use specialized error objects, we could pass the original errors to
+ // them.
+ const maybeSettings = await Promise.race([
+ this.#moat.circumvention_settings(
+ [...TorSettings.builtinBridgeTypes, "vanilla"],
+ countryCode
+ ),
+ // This might set maybeSettings to undefined.
+ this.#transitionPromise,
+ ]);
+ if (maybeSettings?.country) {
+ TorConnect._detectedLocation = maybeSettings.country;
+ }
+
+ if (maybeSettings?.settings && maybeSettings.settings.length) {
+ this.#settings = maybeSettings.settings;
+ } else if (!this.transitioning) {
+ // Keep consistency with the other call.
+ this.#settings = await Promise.race([
+ this.#moat.circumvention_defaults([
+ ...TorSettings.builtinBridgeTypes,
+ "vanilla",
+ ]),
+ // This might set this.#settings to undefined.
+ this.#transitionPromise,
+ ]);
+ }
+
+ if (!this.#settings?.length && !this.transitioning) {
+ // Both localized and fallback have, we can just throw to transition to
+ // the error state (but only if we aren't already transitioning).
+ // TODO: Let the UI layer localize the strings.
+
+ if (!TorConnect._detectedLocation) {
+ // unable to determine country
+ this.#throwError(
+ TorStrings.torConnect.autoBootstrappingFailed,
+ TorStrings.torConnect.cannotDetermineCountry
+ );
+ } else {
+ // no settings available for country
+ this.#throwError(
+ TorStrings.torConnect.autoBootstrappingFailed,
+ TorStrings.torConnect.noSettingsForCountry
+ );
+ }
+ }
+ }
+
+ /**
+ * Try to apply the settings we fetched.
+ */
+ async #trySettings() {
+ // Otherwise, apply each of our settings and try to bootstrap with each.
+ for (const [index, currentSetting] of this.#settings.entries()) {
+ if (this.transitioning) {
+ break;
+ }
+
+ lazy.logger.info(
+ `Attempting Bootstrap with configuration ${index + 1}/${
+ this.#settings.length
+ }`
+ );
+
+ // Send the new settings directly to the provider. We will save them only
+ // if the bootstrap succeeds.
+ // FIXME: We should somehow signal TorSettings users that we have set
+ // custom settings, and they should not apply theirs until we are done
+ // with trying ours.
+ // Otherwise, the new settings provided by the user while we were
+ // bootstrapping could be the ones that cause the bootstrap to succeed,
+ // but we overwrite them (unless we backup the original settings, and then
+ // save our new settings only if they have not changed).
+ // Another idea (maybe easier to implement) is to disable the settings
+ // UI while *any* bootstrap is going on.
+ // This is also documented in tor-browser#41921.
+ const provider = await lazy.TorProviderBuilder.build();
+ this.#changedSettings = true;
+ // We need to merge with old settings, in case the user is using a proxy
+ // or is behind a firewall.
+ await provider.writeSettings({
+ ...TorSettings.getSettings(),
+ ...currentSetting,
+ });
+
+ // Build out our bootstrap request.
+ const bootstrap = new lazy.TorBootstrapRequest();
+ bootstrap.onbootstrapstatus = (progress, status) => {
+ TorConnect._updateBootstrapStatus(progress, status);
+ };
+ bootstrap.onbootstraperror = (message, details) => {
+ lazy.logger.error(`Auto-Bootstrap error => ${message}; ${details}`);
+ };
+
+ // Begin the bootstrap.
+ const success = await Promise.race([
+ bootstrap.bootstrap(),
+ this.#transitionPromise,
+ ]);
+ // Either the bootstrap request has finished, or a transition (caused by
+ // an error or by user's cancelation) started.
+ // However, we cannot be already transitioning in case of success, so if
+ // we are we should cancel the current bootstrap.
+ // With the current TorProvider, this will set DisableNetwork=1 again,
+ // which is what the user wanted if they canceled.
+ if (this.transitioning) {
+ if (success) {
+ lazy.logger.warn(
+ "We were already transitioning after a success, we were not expecting this."
+ );
+ }
+ bootstrap.cancel();
+ return;
+ }
+ if (success) {
+ // Persist the current settings to preferences.
+ TorSettings.setSettings(currentSetting);
+ TorSettings.saveToPrefs();
+ // Do not await `applySettings`. Otherwise this opens up a window of
+ // time where the user can still "Cancel" the bootstrap.
+ // We are calling `applySettings` just to be on the safe side, but the
+ // settings we are passing now should be exactly the same we already
+ // passed earlier.
+ TorSettings.applySettings().catch(e =>
+ lazy.logger.error("TorSettings.applySettings threw unexpectedly.", e)
+ );
+ this.changeState(TorConnectState.Bootstrapped);
+ return;
+ }
+ }
+
+ // Only explicitly change state here if something else has not transitioned
+ // us.
+ if (!this.transitioning) {
+ this.#throwError(
+ TorStrings.torConnect.autoBootstrappingFailed,
+ TorStrings.torConnect.autoBootstrappingAllFailed
+ );
+ }
+ }
+
+ #throwError(message, details) {
+ let err = new Error(message);
+ err.details = details;
+ throw err;
+ }
+
+ transitionRequested() {
+ this.#transitionResolve();
+ }
+
+ async cleanup(nextState) {
+ // No need to await.
+ this.#moat?.uninit();
+ this.#moat = null;
+
+ if (this.#changedSettings && nextState !== TorConnectState.Bootstrapped) {
+ try {
+ await TorSettings.applySettings();
+ } catch (e) {
+ // We cannot do much if the original settings were bad or
+ // if the connection closed, so just report it in the
+ // console.
+ lazy.logger.warn("Failed to restore original settings.", e);
+ }
+ }
+ }
+}
+
+class BootstrappedState extends StateCallback {
+ // We may need to leave the bootstrapped state if the tor daemon
+ // exits (if it is restarted, we will have to bootstrap again).
+ allowedTransitions = Object.freeze([TorConnectState.Configuring]);
+
+ constructor() {
+ super(TorConnectState.Bootstrapped);
+ }
+
+ run() {
+ // Notify observers of bootstrap completion.
+ Services.obs.notifyObservers(null, TorConnectTopics.BootstrapComplete);
+ }
+}
+
+class ErrorState extends StateCallback {
+ allowedTransitions = Object.freeze([TorConnectState.Configuring]);
+
+ static #hasEverHappened = false;
+
+ constructor() {
+ super(TorConnectState.Error);
+ ErrorState.#hasEverHappened = true;
+ }
+
+ run(errorMessage, errorDetails) {
+ TorConnect._errorMessage = errorMessage;
+ TorConnect._errorDetails = errorDetails;
+ lazy.logger.error(
+ `Entering error state (${errorMessage}, ${errorDetails})`
+ );
+
+ Services.obs.notifyObservers(
+ { message: errorMessage, details: errorDetails },
+ TorConnectTopics.BootstrapError
+ );
+
+ this.changeState(TorConnectState.Configuring);
+ }
+
+ static get hasEverHappened() {
+ return ErrorState.#hasEverHappened;
+ }
+}
+
+class DisabledState extends StateCallback {
+ // Trap state: no way to leave the Disabled state.
+ allowedTransitions = Object.freeze([]);
+
+ constructor() {
+ super(TorConnectState.DisabledState);
+ }
+
+ async run() {
+ lazy.logger.debug("Entered the disabled state.");
+ }
+}
+
export const InternetStatus = Object.freeze({
Unknown: -1,
Offline: 0,
@@ -253,1005 +738,581 @@ export const InternetStatus = Object.freeze({
});
class InternetTest {
+ #enabled;
+ #status = InternetStatus.Unknown;
+ #error = null;
+ #pending = false;
+ #canceled = false;
+ #timeout = 0;
+
constructor() {
- this._enabled = Services.prefs.getBoolPref(
+ this.#enabled = Services.prefs.getBoolPref(
TorConnectPrefs.allow_internet_test,
true
);
-
- this._status = InternetStatus.Unknown;
- this._error = null;
- this._pending = false;
- if (this._enabled) {
- this._timeout = setTimeout(() => {
- this._timeout = null;
+ if (this.#enabled) {
+ this.#timeout = setTimeout(() => {
+ this.#timeout = 0;
this.test();
- }, this.timeoutRand());
+ }, this.#timeoutRand());
}
- this.onResult = (online, date) => {};
+ this.onResult = online => {};
this.onError = err => {};
}
- test() {
- if (this._pending || !this._enabled) {
+ /**
+ * Perform the internet test.
+ *
+ * While this is an async method, the callers are not expected to await it,
+ * as we are also using callbacks.
+ */
+ async test() {
+ if (this.#pending || !this.#enabled) {
return;
}
this.cancel();
- this._pending = true;
+ this.#pending = true;
+ this.#canceled = false;
lazy.logger.info("Starting the Internet test");
- this._testAsync()
- .then(status => {
- this._pending = false;
- this._status = status.successful
- ? InternetStatus.Online
- : InternetStatus.Offline;
- lazy.logger.info(`Performed Internet test, outcome ${this._status}`);
- this.onResult(this.status, status.date);
- })
- .catch(error => {
- this._error = error;
- this._pending = false;
- this.onError(error);
- });
- }
-
- cancel() {
- if (this._timeout !== null) {
- clearTimeout(this._timeout);
- this._timeout = null;
- }
- }
-
- async _testAsync() {
- // Callbacks for the Internet test are desirable, because we will be
- // waiting both for the bootstrap, and for the Internet test.
- // However, managing Moat with async/await is much easier as it avoids a
- // callback hell, and it makes extra explicit that we are uniniting it.
const mrpc = new lazy.MoatRPC();
- let status = null;
- let error = null;
try {
await mrpc.init();
- status = await mrpc.testInternetConnection();
+ const status = await mrpc.testInternetConnection();
+ this.#status = status.successful
+ ? InternetStatus.Online
+ : InternetStatus.Offline;
+ // TODO: We could consume the date we got from the HTTP request to detect
+ // big clock skews that might prevent a successfull bootstrap.
+ lazy.logger.info(`Performed Internet test, outcome ${this.#status}`);
} catch (err) {
lazy.logger.error("Error while checking the Internet connection", err);
- error = err;
+ this.#error = err;
+ this.#pending = false;
} finally {
mrpc.uninit();
}
- if (error !== null) {
- throw error;
+
+ if (this.#canceled) {
+ return;
+ }
+ if (this.#error) {
+ this.onError(this.#error);
+ } else {
+ this.onResult(this.#status);
+ }
+ }
+
+ cancel() {
+ this.#canceled = true;
+ if (this.#timeout) {
+ clearTimeout(this.#timeout);
+ this.#timeout = 0;
}
- return status;
}
get status() {
- return this._status;
+ return this.#status;
}
get error() {
- return this._error;
+ return this.#error;
}
get enabled() {
- return this._enabled;
+ return this.#enabled;
}
- // We randomize the Internet test timeout to make fingerprinting it harder, at least a little bit...
- timeoutRand() {
+ // We randomize the Internet test timeout to make fingerprinting it harder, at
+ // least a little bit...
+ #timeoutRand() {
const offset = 30000;
const randRange = 5000;
return offset + randRange * (Math.random() * 2 - 1);
}
}
-export const TorConnect = (() => {
- let retval = {
- _state: TorConnectState.Initial,
- _bootstrapProgress: 0,
- _bootstrapStatus: null,
- _internetStatus: InternetStatus.Unknown,
- // list of country codes Moat has settings for
- _countryCodes: [],
- _countryNames: Object.freeze(
- (() => {
- const codes = Services.intl.getAvailableLocaleDisplayNames("region");
- const names = Services.intl.getRegionDisplayNames(undefined, codes);
- let codesNames = {};
- for (let i = 0; i < codes.length; i++) {
- codesNames[codes[i]] = names[i];
- }
- return codesNames;
- })()
- ),
- _detectedLocation: "",
- _errorMessage: null,
- _errorDetails: null,
- _logHasWarningOrError: false,
- _hasEverFailed: false,
- _hasBootstrapEverFailed: false,
- _transitionPromise: null,
-
- // This is used as a helper to make the state of about:torconnect persistent
- // during a session, but TorConnect does not use this data at all.
- _uiState: {},
-
- /* These functions represent ongoing work associated with one of our states
- Some of these functions are mostly empty, apart from defining an
- on_transition function used to resolve their Promise */
- _stateCallbacks: Object.freeze(
- new Map([
- /* Initial is never transitioned to */
- [
- TorConnectState.Initial,
- new StateCallback(TorConnectState.Initial, async function () {
- // The initial state doesn't actually do anything, so here is a skeleton for other
- // states which do perform work
- await new Promise(async (resolve, reject) => {
- // This function is provided to signal to the callback that it is complete.
- // It is called as a result of _changeState and at the very least must
- // resolve the root Promise object within the StateCallback function
- // The on_transition callback may also perform necessary cleanup work
- this.on_transition = nextState => {
- resolve();
- };
-
- try {
- // each state may have a sequence of async work to do
- let asyncWork = async () => {};
- await asyncWork();
-
- // after each block we may check for an opportunity to early-out
- if (this.transitioning) {
- return;
- }
-
- // repeat the above pattern as necessary
- } catch (err) {
- // any thrown exceptions here will trigger a transition to the Error state
- TorConnect._changeState(
- TorConnectState.Error,
- err?.message,
- err?.details
- );
- }
- });
- }),
- ],
- /* Configuring */
- [
- TorConnectState.Configuring,
- new StateCallback(TorConnectState.Configuring, async function () {
- await new Promise(async (resolve, reject) => {
- this.on_transition = nextState => {
- resolve();
- };
- });
- }),
- ],
- /* Bootstrapping */
- [
- TorConnectState.Bootstrapping,
- new StateCallback(TorConnectState.Bootstrapping, async function () {
- // wait until bootstrap completes or we get an error
- await new Promise(async (resolve, reject) => {
- // debug hook to simulate censorship preventing bootstrapping
- if (
- Services.prefs.getIntPref(TorConnectPrefs.censorship_level, 0) >
- 0
- ) {
- this.on_transition = nextState => {
- resolve();
- };
- await debug_sleep(1500);
- TorConnect._hasBootstrapEverFailed = true;
- if (
- Services.prefs.getIntPref(
- TorConnectPrefs.censorship_level,
- 0
- ) === 2
- ) {
- const codes = Object.keys(TorConnect._countryNames);
- TorConnect._detectedLocation =
- codes[Math.floor(Math.random() * codes.length)];
- }
- TorConnect._changeState(
- TorConnectState.Error,
- "Bootstrap failed (for debugging purposes)",
- "Error: Censorship simulation",
- true
- );
- return;
- }
-
- const tbr = new lazy.TorBootstrapRequest();
- const internetTest = new InternetTest();
- let cancelled = false;
-
- let bootstrapError = "";
- let bootstrapErrorDetails = "";
- const maybeTransitionToError = () => {
- if (
- internetTest.status === InternetStatus.Unknown &&
- internetTest.error === null &&
- internetTest.enabled
- ) {
- // We have been called by a failed bootstrap, but the internet test has not run yet - force
- // it to run immediately!
- internetTest.test();
- // Return from this call, because the Internet test's callback will call us again
- return;
- }
- // Do not transition to the offline error until we are sure that also the bootstrap failed, in
- // case Moat is down but the bootstrap can proceed anyway.
- if (bootstrapError === "") {
- return;
- }
- if (internetTest.status === InternetStatus.Offline) {
- TorConnect._changeState(
- TorConnectState.Error,
- TorStrings.torConnect.offline,
- "",
- true
- );
- } else {
- // Give priority to the bootstrap error, in case the Internet test fails
- TorConnect._hasBootstrapEverFailed = true;
- TorConnect._changeState(
- TorConnectState.Error,
- bootstrapError,
- bootstrapErrorDetails,
- true
- );
- }
- };
-
- this.on_transition = async nextState => {
- if (nextState === TorConnectState.Configuring) {
- // stop bootstrap process if user cancelled
- cancelled = true;
- internetTest.cancel();
- await tbr.cancel();
- }
- resolve();
- };
-
- tbr.onbootstrapstatus = (progress, status) => {
- TorConnect._updateBootstrapStatus(progress, status);
- };
- tbr.onbootstrapcomplete = () => {
- internetTest.cancel();
- TorConnect._changeState(TorConnectState.Bootstrapped);
- };
- tbr.onbootstraperror = (message, details) => {
- if (cancelled) {
- // We ignore this error since it occurred after cancelling (by
- // the user). We assume the error is just a side effect of the
- // cancelling.
- // E.g. If the cancelling is triggered late in the process, we
- // get "Building circuits: Establishing a Tor circuit failed".
- // TODO: Maybe move this logic deeper in the process to know
- // when to filter out such errors triggered by cancelling.
- lazy.logger.warn(
- `Post-cancel error => ${message}; ${details}`
- );
- return;
- }
- // We have to wait for the Internet test to finish before sending the bootstrap error
- bootstrapError = message;
- bootstrapErrorDetails = details;
- maybeTransitionToError();
- };
-
- internetTest.onResult = (status, date) => {
- // TODO: Use the date to save the clock skew?
- TorConnect._internetStatus = status;
- maybeTransitionToError();
- };
- internetTest.onError = () => {
- maybeTransitionToError();
- };
-
- tbr.bootstrap();
- });
- }),
- ],
- /* AutoBootstrapping */
- [
- TorConnectState.AutoBootstrapping,
- new StateCallback(TorConnectState.AutoBootstrapping, async function (
- countryCode
- ) {
- await new Promise(async (resolve, reject) => {
- this.on_transition = nextState => {
- resolve();
- };
-
- // debug hook to simulate censorship preventing bootstrapping
- {
- const censorshipLevel = Services.prefs.getIntPref(
- TorConnectPrefs.censorship_level,
- 0
- );
- if (censorshipLevel > 1) {
- this.on_transition = nextState => {
- resolve();
- };
- // always fail even after manually selecting location specific settings
- if (censorshipLevel == 3) {
- await debug_sleep(2500);
- TorConnect._changeState(
- TorConnectState.Error,
- "Error: censorship simulation",
- "",
- true
- );
- return;
- // only fail after auto selecting, manually selecting succeeds
- } else if (censorshipLevel == 2 && !countryCode) {
- await debug_sleep(2500);
- TorConnect._changeState(
- TorConnectState.Error,
- "Error: Severe Censorship simulation",
- "",
- true
- );
- return;
- }
- }
- }
-
- const throw_error = (message, details) => {
- let err = new Error(message);
- err.details = details;
- throw err;
- };
-
- // lookup user's potential censorship circumvention settings from Moat service
- try {
- this.mrpc = new lazy.MoatRPC();
- await this.mrpc.init();
-
- if (this.transitioning) {
- return;
- }
-
- const settings = await this.mrpc.circumvention_settings(
- [...TorSettings.builtinBridgeTypes, "vanilla"],
- countryCode
- );
-
- if (this.transitioning) {
- return;
- }
-
- if (settings?.country) {
- TorConnect._detectedLocation = settings.country;
- }
- if (settings?.settings && settings.settings.length) {
- this.settings = settings.settings;
- } else {
- try {
- this.settings = await this.mrpc.circumvention_defaults([
- ...TorSettings.builtinBridgeTypes,
- "vanilla",
- ]);
- } catch (err) {
- lazy.logger.error(
- "We did not get localized settings, and default settings failed as well",
- err
- );
- }
- }
- if (this.settings === null || this.settings.length === 0) {
- // The fallback has failed as well, so throw the original error
- if (!TorConnect._detectedLocation) {
- // unable to determine country
- throw_error(
- TorStrings.torConnect.autoBootstrappingFailed,
- TorStrings.torConnect.cannotDetermineCountry
- );
- } else {
- // no settings available for country
- throw_error(
- TorStrings.torConnect.autoBootstrappingFailed,
- TorStrings.torConnect.noSettingsForCountry
- );
- }
- }
-
- const restoreOriginalSettings = async () => {
- try {
- await TorSettings.applySettings();
- } catch (e) {
- // We cannot do much if the original settings were bad or
- // if the connection closed, so just report it in the
- // console.
- lazy.logger.warn("Failed to restore original settings.", e);
- }
- };
-
- // apply each of our settings and try to bootstrap with each
- try {
- for (const [
- index,
- currentSetting,
- ] of this.settings.entries()) {
- // we want to break here so we can fall through and restore original settings
- if (this.transitioning) {
- break;
- }
-
- lazy.logger.info(
- `Attempting Bootstrap with configuration ${index + 1}/${
- this.settings.length
- }`
- );
-
- // Send the new settings directly to the provider. We will
- // save them only if the bootstrap succeeds.
- // FIXME: We should somehow signal TorSettings users that we
- // have set custom settings, and they should not apply
- // theirs until we are done with trying ours.
- // Otherwise, the new settings provided by the user while we
- // were bootstrapping could be the ones that cause the
- // bootstrap to succeed, but we overwrite them (unless we
- // backup the original settings, and then save our new
- // settings only if they have not changed).
- // Another idea (maybe easier to implement) is to disable
- // the settings UI while *any* bootstrap is going on.
- // This is also documented in tor-browser#41921.
- const provider = await lazy.TorProviderBuilder.build();
- // We need to merge with old settings, in case the user is
- // using a proxy or is behind a firewall.
- await provider.writeSettings({
- ...TorSettings.getSettings(),
- ...currentSetting,
- });
-
- // build out our bootstrap request
- const tbr = new lazy.TorBootstrapRequest();
- tbr.onbootstrapstatus = (progress, status) => {
- TorConnect._updateBootstrapStatus(progress, status);
- };
- tbr.onbootstraperror = (message, details) => {
- lazy.logger.error(
- `Auto-Bootstrap error => ${message}; ${details}`
- );
- };
-
- // update transition callback for user cancel
- this.on_transition = async nextState => {
- if (nextState === TorConnectState.Configuring) {
- await tbr.cancel();
- await restoreOriginalSettings();
- }
- resolve();
- };
-
- // begin bootstrap
- if (await tbr.bootstrap()) {
- // persist the current settings to preferences
- TorSettings.setSettings(currentSetting);
- TorSettings.saveToPrefs();
- await TorSettings.applySettings();
- TorConnect._changeState(TorConnectState.Bootstrapped);
- return;
- }
- }
-
- // Bootstrap failed for all potential settings, so restore the
- // original settings the provider.
- await restoreOriginalSettings();
-
- // Only explicitly change state here if something else has not
- // transitioned us.
- if (!this.transitioning) {
- throw_error(
- TorStrings.torConnect.autoBootstrappingFailed,
- TorStrings.torConnect.autoBootstrappingAllFailed
- );
- }
- return;
- } catch (err) {
- await restoreOriginalSettings();
- // throw to outer catch to transition us.
- throw err;
- }
- } catch (err) {
- if (this.mrpc?.inited) {
- // lookup countries which have settings available
- TorConnect._countryCodes =
- await this.mrpc.circumvention_countries();
- }
- if (!this.transitioning) {
- TorConnect._changeState(
- TorConnectState.Error,
- err?.message,
- err?.details,
- true
- );
- } else {
- lazy.logger.error(
- "Received AutoBootstrapping error after transitioning",
- err
- );
- }
- } finally {
- // important to uninit MoatRPC object or else the pt process will live as long as tor-browser
- this.mrpc?.uninit();
- }
- });
- }),
- ],
- /* Bootstrapped */
- [
- TorConnectState.Bootstrapped,
- new StateCallback(TorConnectState.Bootstrapped, async function () {
- await new Promise((resolve, reject) => {
- // We may need to leave the bootstrapped state if the tor daemon
- // exits (if it is restarted, we will have to bootstrap again).
- this.on_transition = nextState => {
- resolve();
- };
- // notify observers of bootstrap completion
- Services.obs.notifyObservers(
- null,
- TorConnectTopics.BootstrapComplete
- );
- });
- }),
- ],
- /* Error */
- [
- TorConnectState.Error,
- new StateCallback(TorConnectState.Error, async function (
- errorMessage,
- errorDetails,
- bootstrappingFailure
- ) {
- await new Promise((resolve, reject) => {
- this.on_transition = async nextState => {
- resolve();
- };
-
- TorConnect._errorMessage = errorMessage;
- TorConnect._errorDetails = errorDetails;
- lazy.logger.error(
- `Entering error state (${errorMessage}, ${errorDetails})`
- );
-
- Services.obs.notifyObservers(
- { message: errorMessage, details: errorDetails },
- TorConnectTopics.BootstrapError
- );
-
- TorConnect._changeState(TorConnectState.Configuring);
- });
- }),
- ],
- /* Disabled */
- [
- TorConnectState.Disabled,
- new StateCallback(TorConnectState.Disabled, async function () {
- await new Promise((resolve, reject) => {
- // no-op, on_transition not defined because no way to leave Disabled state
- });
- }),
- ],
- ])
- ),
-
- _callback(state) {
- return this._stateCallbacks.get(state);
- },
-
- _changeState(newState, ...args) {
- if (newState === TorConnectState.Error) {
- this._hasEverFailed = true;
+export const TorConnect = {
+ _stateHandler: new InitialState(),
+ _bootstrapProgress: 0,
+ _bootstrapStatus: null,
+ _internetStatus: InternetStatus.Unknown,
+ // list of country codes Moat has settings for
+ _countryCodes: [],
+ _countryNames: Object.freeze(
+ (() => {
+ const codes = Services.intl.getAvailableLocaleDisplayNames("region");
+ const names = Services.intl.getRegionDisplayNames(undefined, codes);
+ let codesNames = {};
+ for (let i = 0; i < codes.length; i++) {
+ codesNames[codes[i]] = names[i];
}
- const prevState = this._state;
+ return codesNames;
+ })()
+ ),
+ _detectedLocation: "",
+ _errorMessage: null,
+ _errorDetails: null,
+ _logHasWarningOrError: false,
+ _hasBootstrapEverFailed: false,
+ _transitionPromise: null,
+
+ // This is used as a helper to make the state of about:torconnect persistent
+ // during a session, but TorConnect does not use this data at all.
+ _uiState: {},
+
+ _stateCallbacks: Object.freeze(
+ new Map([
+ // Initial is never transitioned to
+ [TorConnectState.Initial, InitialState],
+ [TorConnectState.Configuring, ConfiguringState],
+ [TorConnectState.Bootstrapping, BootstrappingState],
+ [TorConnectState.AutoBootstrapping, AutoBootstrappingState],
+ [TorConnectState.Bootstrapped, BootstrappedState],
+ [TorConnectState.Error, ErrorState],
+ [TorConnectState.Disabled, DisabledState],
+ ])
+ ),
+
+ _makeState(state) {
+ const klass = this._stateCallbacks.get(state);
+ if (!klass) {
+ throw new Error(`${state} is not a valid state.`);
+ }
+ return new klass();
+ },
+
+ async _changeState(newState, ...args) {
+ if (this._stateHandler.transitioning) {
+ // Avoid an exception to prevent it to be propagated to the original
+ // begin call.
+ lazy.logger.warn("Already transitioning");
+ return;
+ }
+ const prevState = this._stateHandler;
+
+ // ensure this is a valid state transition
+ if (!prevState.allowedTransitions.includes(newState)) {
+ throw Error(
+ `TorConnect: Attempted invalid state transition from ${prevState.state} to ${newState}`
+ );
+ }
- // ensure this is a valid state transition
- if (!TorConnectStateTransitions.get(prevState)?.includes(newState)) {
- throw Error(
- `TorConnect: Attempted invalid state transition from ${prevState} to ${newState}`
+ lazy.logger.trace(
+ `Try transitioning from ${prevState.state} to ${newState}`,
+ args
+ );
+ try {
+ await prevState.end(newState);
+ } catch (e) {
+ // We take for granted that the begin of this state will call us again,
+ // to request the transition to the error state.
+ if (newState !== TorConnectState.Error) {
+ lazy.logger.debug(
+ `Refusing the transition from ${prevState.state} to ${newState} because the previous state threw.`
);
+ return;
}
+ }
- lazy.logger.trace(`Try transitioning from ${prevState} to ${newState}`);
-
- // set our new state first so that state transitions can themselves trigger
- // a state transition
- this._state = newState;
-
- // call our state function and forward any args
- this._callback(prevState).transition(newState, ...args);
- },
+ // Set our new state first so that state transitions can themselves
+ // trigger a state transition.
+ this._stateHandler = this._makeState(newState);
+ Services.obs.notifyObservers(
+ { state: newState },
+ TorConnectTopics.StateChange
+ );
+ this._stateHandler.begin(...args);
+ },
- _updateBootstrapStatus(progress, status) {
- this._bootstrapProgress = progress;
- this._bootstrapStatus = status;
+ _updateBootstrapStatus(progress, status) {
+ this._bootstrapProgress = progress;
+ this._bootstrapStatus = status;
- lazy.logger.info(
- `Bootstrapping ${this._bootstrapProgress}% complete (${this._bootstrapStatus})`
- );
- Services.obs.notifyObservers(
- {
- progress: TorConnect._bootstrapProgress,
- status: TorConnect._bootstrapStatus,
- hasWarnings: TorConnect._logHasWarningOrError,
- },
- TorConnectTopics.BootstrapProgress
- );
- },
+ lazy.logger.info(
+ `Bootstrapping ${this._bootstrapProgress}% complete (${this._bootstrapStatus})`
+ );
+ Services.obs.notifyObservers(
+ {
+ progress: TorConnect._bootstrapProgress,
+ status: TorConnect._bootstrapStatus,
+ hasWarnings: TorConnect._logHasWarningOrError,
+ },
+ TorConnectTopics.BootstrapProgress
+ );
+ },
+
+ // init should be called by TorStartupService
+ init() {
+ lazy.logger.debug("TorConnect.init()");
+ this._stateHandler.begin();
+
+ if (!this.enabled) {
+ // Disabled
+ this._changeState(TorConnectState.Disabled);
+ } else {
+ let observeTopic = addTopic => {
+ Services.obs.addObserver(this, addTopic);
+ lazy.logger.debug(`Observing topic '${addTopic}'`);
+ };
+
+ // Wait for TorSettings, as we will need it.
+ // We will wait for a TorProvider only after TorSettings is ready,
+ // because the TorProviderBuilder initialization might not have finished
+ // at this point, and TorSettings initialization is a prerequisite for
+ // having a provider.
+ // So, we prefer initializing TorConnect as soon as possible, so that
+ // the UI will be able to detect it is in the Initializing state and act
+ // consequently.
+ TorSettings.initializedPromise.then(() => this._settingsInitialized());
+
+ // register the Tor topics we always care about
+ observeTopic(TorTopics.ProcessExited);
+ observeTopic(TorTopics.LogHasWarnOrErr);
+ }
+ },
- // init should be called by TorStartupService
- init() {
- lazy.logger.debug("TorConnect.init()");
- this._callback(TorConnectState.Initial).begin();
+ async observe(subject, topic, data) {
+ lazy.logger.debug(`Observed ${topic}`);
- if (!this.enabled) {
- // Disabled
- this._changeState(TorConnectState.Disabled);
- } else {
- let observeTopic = addTopic => {
- Services.obs.addObserver(this, addTopic);
- lazy.logger.debug(`Observing topic '${addTopic}'`);
- };
-
- // Wait for TorSettings, as we will need it.
- // We will wait for a TorProvider only after TorSettings is ready,
- // because the TorProviderBuilder initialization might not have finished
- // at this point, and TorSettings initialization is a prerequisite for
- // having a provider.
- // So, we prefer initializing TorConnect as soon as possible, so that
- // the UI will be able to detect it is in the Initializing state and act
- // consequently.
- TorSettings.initializedPromise.then(() => this._settingsInitialized());
-
- // register the Tor topics we always care about
- observeTopic(TorTopics.ProcessExited);
- observeTopic(TorTopics.LogHasWarnOrErr);
+ switch (topic) {
+ case TorTopics.LogHasWarnOrErr: {
+ this._logHasWarningOrError = true;
+ break;
}
- },
-
- async observe(subject, topic, data) {
- lazy.logger.debug(`Observed ${topic}`);
-
- switch (topic) {
- case TorTopics.LogHasWarnOrErr: {
- this._logHasWarningOrError = true;
- break;
+ case TorTopics.ProcessExited: {
+ // Treat a failure as a possibly broken configuration.
+ // So, prevent quickstart at the next start.
+ Services.prefs.setBoolPref(TorLauncherPrefs.prompt_at_startup, true);
+ switch (this.state) {
+ case TorConnectState.Bootstrapping:
+ case TorConnectState.AutoBootstrapping:
+ case TorConnectState.Bootstrapped:
+ // If we are in the bootstrap or auto bootstrap, we could go
+ // through the error phase (and eventually we might do it, if some
+ // transition calls fail). However, this would start the
+ // connection assist, so we go directly to configuring.
+ // FIXME: Find a better way to handle this.
+ this._changeState(TorConnectState.Configuring);
+ break;
+ // Other states naturally resolve in configuration.
}
- case TorTopics.ProcessExited: {
- // Treat a failure as a possibly broken configuration.
- // So, prevent quickstart at the next start.
- Services.prefs.setBoolPref(TorLauncherPrefs.prompt_at_startup, true);
- switch (this._state) {
- case TorConnectState.Bootstrapping:
- case TorConnectState.AutoBootstrapping:
- case TorConnectState.Bootstrapped:
- // If we are in the bootstrap or auto bootstrap, we could go
- // through the error phase (and eventually we might do it, if some
- // transition calls fail). However, this would start the
- // connection assist, so we go directly to configuring.
- // FIXME: Find a better way to handle this.
- this._changeState(TorConnectState.Configuring);
- break;
- // Other states naturally resolve in configuration.
- }
- break;
- }
- default:
- // ignore
- break;
- }
- },
-
- async _settingsInitialized() {
- // TODO: Handle failures here, instead of the prompt to restart the
- // daemon when it exits (tor-browser#21053, tor-browser#41921).
- await lazy.TorProviderBuilder.build();
-
- // 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...).
- // See also tor-browser#41921.
- if (this.state !== TorConnectState.Initial) {
- lazy.logger.warn(
- "The TorProvider was built after the state had already changed."
- );
- return;
- }
- lazy.logger.debug("The TorProvider is ready, changing state.");
- if (this.shouldQuickStart) {
- // Quickstart
- this._changeState(TorConnectState.Bootstrapping);
- } else {
- // Configuring
- this._changeState(TorConnectState.Configuring);
+ break;
}
- },
-
- /*
- Various getters
- */
-
- /**
- * Whether TorConnect is enabled.
- *
- * @type {boolean}
- */
- get enabled() {
- // FIXME: This is called before the TorProvider is ready.
- // As a matter of fact, at the moment it is equivalent to the following
- // line, but this might become a problem in the future.
- return TorLauncherUtil.shouldStartAndOwnTor;
- },
-
- get shouldShowTorConnect() {
- // TorBrowser must control the daemon
- return (
- this.enabled &&
- // if we have succesfully bootstraped, then no need to show TorConnect
- this.state !== TorConnectState.Bootstrapped
- );
- },
-
- /**
- * Whether bootstrapping can currently begin.
- *
- * The value may change with TorConnectTopics.StateChanged.
- *
- * @param {boolean}
- */
- get canBeginBootstrap() {
- return TorConnectStateTransitions.get(this.state).includes(
- TorConnectState.Bootstrapping
- );
- },
-
- /**
- * Whether auto-bootstrapping can currently begin.
- *
- * The value may change with TorConnectTopics.StateChanged.
- *
- * @param {boolean}
- */
- get canBeginAutoBootstrap() {
- return TorConnectStateTransitions.get(this.state).includes(
- TorConnectState.AutoBootstrapping
- );
- },
-
- get shouldQuickStart() {
- // quickstart must be enabled
- return (
- TorSettings.quickstart.enabled &&
- // and the previous bootstrap attempt must have succeeded
- !Services.prefs.getBoolPref(TorLauncherPrefs.prompt_at_startup, true)
+ default:
+ // ignore
+ break;
+ }
+ },
+
+ async _settingsInitialized() {
+ // TODO: Handle failures here, instead of the prompt to restart the
+ // daemon when it exits (tor-browser#21053, tor-browser#41921).
+ await lazy.TorProviderBuilder.build();
+
+ // 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...).
+ // Notice that currently the initial state does not do anything.
+ // Instead of just waiting, we could move this code in its callback.
+ // See also tor-browser#41921.
+ if (this.state !== TorConnectState.Initial) {
+ lazy.logger.warn(
+ "The TorProvider was built after the state had already changed."
);
- },
-
- get state() {
- return this._state;
- },
-
- get bootstrapProgress() {
- return this._bootstrapProgress;
- },
+ return;
+ }
+ lazy.logger.debug("The TorProvider is ready, changing state.");
+ if (this.shouldQuickStart) {
+ // Quickstart
+ this._changeState(TorConnectState.Bootstrapping);
+ } else {
+ // Configuring
+ this._changeState(TorConnectState.Configuring);
+ }
+ },
- get bootstrapStatus() {
- return this._bootstrapStatus;
- },
+ /*
+ Various getters
+ */
- get internetStatus() {
- return this._internetStatus;
- },
+ /**
+ * Whether TorConnect is enabled.
+ *
+ * @type {boolean}
+ */
+ get enabled() {
+ // FIXME: This is called before the TorProvider is ready.
+ // As a matter of fact, at the moment it is equivalent to the following
+ // line, but this might become a problem in the future.
+ return TorLauncherUtil.shouldStartAndOwnTor;
+ },
+
+ get shouldShowTorConnect() {
+ // TorBrowser must control the daemon
+ return (
+ this.enabled &&
+ // if we have succesfully bootstraped, then no need to show TorConnect
+ this.state !== TorConnectState.Bootstrapped
+ );
+ },
+
+ /**
+ * Whether bootstrapping can currently begin.
+ *
+ * The value may change with TorConnectTopics.StateChanged.
+ *
+ * @param {boolean}
+ */
+ get canBeginBootstrap() {
+ return this._stateHandler.allowedTransitions.includes(
+ TorConnectState.Bootstrapping
+ );
+ },
+
+ /**
+ * Whether auto-bootstrapping can currently begin.
+ *
+ * The value may change with TorConnectTopics.StateChanged.
+ *
+ * @param {boolean}
+ */
+ get canBeginAutoBootstrap() {
+ return this._stateHandler.allowedTransitions.includes(
+ TorConnectState.AutoBootstrapping
+ );
+ },
+
+ get shouldQuickStart() {
+ // quickstart must be enabled
+ return (
+ TorSettings.quickstart.enabled &&
+ // and the previous bootstrap attempt must have succeeded
+ !Services.prefs.getBoolPref(TorLauncherPrefs.prompt_at_startup, true)
+ );
+ },
+
+ get state() {
+ return this._stateHandler.state;
+ },
+
+ get bootstrapProgress() {
+ return this._bootstrapProgress;
+ },
+
+ get bootstrapStatus() {
+ return this._bootstrapStatus;
+ },
+
+ get internetStatus() {
+ return this._internetStatus;
+ },
+
+ get countryCodes() {
+ return this._countryCodes;
+ },
+
+ get countryNames() {
+ return this._countryNames;
+ },
+
+ get detectedLocation() {
+ return this._detectedLocation;
+ },
+
+ get errorMessage() {
+ return this._errorMessage;
+ },
+
+ get errorDetails() {
+ return this._errorDetails;
+ },
+
+ get logHasWarningOrError() {
+ return this._logHasWarningOrError;
+ },
+
+ /**
+ * Whether we have ever entered the Error state.
+ *
+ * @type {boolean}
+ */
+ get hasEverFailed() {
+ return ErrorState.hasEverHappened;
+ },
+
+ /**
+ * Whether the Bootstrapping process has ever failed, not including when it
+ * failed due to not being connected to the internet.
+ *
+ * This does not include a failure in AutoBootstrapping.
+ *
+ * @type {boolean}
+ */
+ get potentiallyBlocked() {
+ return this._hasBootstrapEverFailed;
+ },
+
+ get uiState() {
+ return this._uiState;
+ },
+ set uiState(newState) {
+ this._uiState = newState;
+ },
+
+ /*
+ These functions allow external consumers to tell TorConnect to transition states
+ */
+
+ beginBootstrap() {
+ lazy.logger.debug("TorConnect.beginBootstrap()");
+ this._changeState(TorConnectState.Bootstrapping);
+ },
+
+ cancelBootstrap() {
+ lazy.logger.debug("TorConnect.cancelBootstrap()");
+ if (
+ this.state !== TorConnectState.AutoBootstrapping &&
+ this.state !== TorConnectState.Bootstrapping
+ ) {
+ lazy.logger.warn(
+ `Cannot cancel bootstrapping in the ${this.state} state`
+ );
+ return;
+ }
+ this._changeState(TorConnectState.Configuring);
+ },
+
+ beginAutoBootstrap(countryCode) {
+ lazy.logger.debug("TorConnect.beginAutoBootstrap()");
+ this._changeState(TorConnectState.AutoBootstrapping, countryCode);
+ },
+
+ /*
+ Further external commands and helper methods
+ */
+ openTorPreferences() {
+ if (TorLauncherUtil.isAndroid) {
+ lazy.EventDispatcher.instance.sendRequest({
+ type: "GeckoView:Tor:OpenSettings",
+ });
+ return;
+ }
+ const win = lazy.BrowserWindowTracker.getTopWindow();
+ win.switchToTabHavingURI("about:preferences#connection", true);
+ },
+
+ /**
+ * Open the "about:torconnect" tab.
+ *
+ * Bootstrapping or AutoBootstrapping can also be automatically triggered at
+ * the same time, if the current state allows for it.
+ *
+ * Bootstrapping will not be triggered if the connection is
+ * potentially blocked.
+ *
+ * @param {object} [options] - extra options.
+ * @property {boolean} [options.beginBootstrap=false] - Whether to try and
+ * begin Bootstrapping.
+ * @property {string} [options.beginAutoBootstrap] - The location to use to
+ * begin AutoBootstrapping, if possible.
+ */
+ openTorConnect(options) {
+ const win = lazy.BrowserWindowTracker.getTopWindow();
+ win.switchToTabHavingURI("about:torconnect", true, {
+ ignoreQueryString: true,
+ });
+ if (
+ options?.beginBootstrap &&
+ this.canBeginBootstrap &&
+ !this.potentiallyBlocked
+ ) {
+ this.beginBootstrap();
+ }
+ // options.beginAutoBootstrap can be an empty string.
+ if (
+ options?.beginAutoBootstrap !== undefined &&
+ this.canBeginAutoBootstrap
+ ) {
+ this.beginAutoBootstrap(options.beginAutoBootstrap);
+ }
+ },
- get countryCodes() {
- return this._countryCodes;
- },
-
- get countryNames() {
- return this._countryNames;
- },
-
- get detectedLocation() {
- return this._detectedLocation;
- },
-
- get errorMessage() {
- return this._errorMessage;
- },
-
- get errorDetails() {
- return this._errorDetails;
- },
-
- get logHasWarningOrError() {
- return this._logHasWarningOrError;
- },
-
- /**
- * Whether we have ever entered the Error state.
- *
- * @type {boolean}
- */
- get hasEverFailed() {
- return this._hasEverFailed;
- },
-
- /**
- * Whether the Bootstrapping process has ever failed, not including when it
- * failed due to not being connected to the internet.
- *
- * This does not include a failure in AutoBootstrapping.
- *
- * @type {boolean}
- */
- get potentiallyBlocked() {
- return this._hasBootstrapEverFailed;
- },
-
- get uiState() {
- return this._uiState;
- },
- set uiState(newState) {
- this._uiState = newState;
- },
-
- /*
- These functions allow external consumers to tell TorConnect to transition states
- */
-
- beginBootstrap() {
- lazy.logger.debug("TorConnect.beginBootstrap()");
- this._changeState(TorConnectState.Bootstrapping);
- },
+ viewTorLogs() {
+ const win = lazy.BrowserWindowTracker.getTopWindow();
+ win.switchToTabHavingURI("about:preferences#connection-viewlogs", true);
+ },
- cancelBootstrap() {
- lazy.logger.debug("TorConnect.cancelBootstrap()");
- this._changeState(TorConnectState.Configuring);
- },
-
- beginAutoBootstrap(countryCode) {
- lazy.logger.debug("TorConnect.beginAutoBootstrap()");
- this._changeState(TorConnectState.AutoBootstrapping, countryCode);
- },
-
- /*
- Further external commands and helper methods
- */
- openTorPreferences() {
- if (TorLauncherUtil.isAndroid) {
- lazy.EventDispatcher.instance.sendRequest({
- type: "GeckoView:Tor:OpenSettings",
- });
- return;
- }
- const win = lazy.BrowserWindowTracker.getTopWindow();
- win.switchToTabHavingURI("about:preferences#connection", true);
- },
-
- /**
- * Open the "about:torconnect" tab.
- *
- * Bootstrapping or AutoBootstrapping can also be automatically triggered at
- * the same time, if the current state allows for it.
- *
- * Bootstrapping will not be triggered if the connection is
- * potentially blocked.
- *
- * @param {object} [options] - extra options.
- * @property {boolean} [options.beginBootstrap=false] - Whether to try and
- * begin Bootstrapping.
- * @property {string} [options.beginAutoBootstrap] - The location to use to
- * begin AutoBootstrapping, if possible.
- */
- openTorConnect(options) {
- const win = lazy.BrowserWindowTracker.getTopWindow();
- win.switchToTabHavingURI("about:torconnect", true, {
- ignoreQueryString: true,
- });
- if (
- options?.beginBootstrap &&
- this.canBeginBootstrap &&
- !this.potentiallyBlocked
- ) {
- this.beginBootstrap();
- }
- // options.beginAutoBootstrap can be an empty string.
- if (
- options?.beginAutoBootstrap !== undefined &&
- this.canBeginAutoBootstrap
- ) {
- this.beginAutoBootstrap(options.beginAutoBootstrap);
- }
- },
-
- viewTorLogs() {
- const win = lazy.BrowserWindowTracker.getTopWindow();
- win.switchToTabHavingURI("about:preferences#connection-viewlogs", true);
- },
-
- async getCountryCodes() {
- // Difference with the getter: this is to be called by TorConnectParent, and downloads
- // the country codes if they are not already in cache.
- if (this._countryCodes.length) {
- return this._countryCodes;
- }
- const mrpc = new lazy.MoatRPC();
- try {
- await mrpc.init();
- this._countryCodes = await mrpc.circumvention_countries();
- } catch (err) {
- lazy.logger.error(
- "An error occurred while fetching country codes",
- err
- );
- } finally {
- mrpc.uninit();
- }
+ async getCountryCodes() {
+ // Difference with the getter: this is to be called by TorConnectParent, and
+ // downloads the country codes if they are not already in cache.
+ if (this._countryCodes.length) {
return this._countryCodes;
- },
-
- getRedirectURL(url) {
- return `about:torconnect?redirect=${encodeURIComponent(url)}`;
- },
-
- /**
- * Convert the given object into a list of valid URIs.
- *
- * The object is either from the user's homepage preference (which may
- * contain multiple domains separated by "|") or uris passed to the browser
- * via command-line.
- *
- * @param {string|string[]} uriVariant - The string to extract uris from.
- *
- * @return {string[]} - The array of uris found.
- */
- fixupURIs(uriVariant) {
- let uriArray;
- if (typeof uriVariant === "string") {
- uriArray = uriVariant.split("|");
- } else if (
- Array.isArray(uriVariant) &&
- uriVariant.every(entry => typeof entry === "string")
- ) {
- uriArray = uriVariant;
- } else {
- // about:tor as safe fallback
- lazy.logger.error(
- `Received unknown variant '${JSON.stringify(uriVariant)}'`
- );
- uriArray = ["about:tor"];
- }
-
- // Attempt to convert user-supplied string to a uri, fallback to
- // about:tor if cannot convert to valid uri object
- return uriArray.map(
- uriString =>
- Services.uriFixup.getFixupURIInfo(
- uriString,
- Ci.nsIURIFixup.FIXUP_FLAG_NONE
- ).preferredURI?.spec ?? "about:tor"
+ }
+ const mrpc = new lazy.MoatRPC();
+ try {
+ await mrpc.init();
+ this._countryCodes = await mrpc.circumvention_countries();
+ } catch (err) {
+ lazy.logger.error("An error occurred while fetching country codes", err);
+ } finally {
+ mrpc.uninit();
+ }
+ return this._countryCodes;
+ },
+
+ getRedirectURL(url) {
+ return `about:torconnect?redirect=${encodeURIComponent(url)}`;
+ },
+
+ /**
+ * Convert the given object into a list of valid URIs.
+ *
+ * The object is either from the user's homepage preference (which may
+ * contain multiple domains separated by "|") or uris passed to the browser
+ * via command-line.
+ *
+ * @param {string|string[]} uriVariant - The string to extract uris from.
+ *
+ * @return {string[]} - The array of uris found.
+ */
+ fixupURIs(uriVariant) {
+ let uriArray;
+ if (typeof uriVariant === "string") {
+ uriArray = uriVariant.split("|");
+ } else if (
+ Array.isArray(uriVariant) &&
+ uriVariant.every(entry => typeof entry === "string")
+ ) {
+ uriArray = uriVariant;
+ } else {
+ // about:tor as safe fallback
+ lazy.logger.error(
+ `Received unknown variant '${JSON.stringify(uriVariant)}'`
);
- },
-
- // called from browser.js on browser startup, passed in either the user's homepage(s)
- // or uris passed via command-line; we want to replace them with about:torconnect uris
- // which redirect after bootstrapping
- getURIsToLoad(uriVariant) {
- const uris = this.fixupURIs(uriVariant);
- lazy.logger.debug(`Will load after bootstrap => [${uris.join(", ")}]`);
- return uris.map(uri => this.getRedirectURL(uri));
- },
- };
- return retval;
-})(); /* TorConnect */
+ uriArray = ["about:tor"];
+ }
+
+ // Attempt to convert user-supplied string to a uri, fallback to
+ // about:tor if cannot convert to valid uri object
+ return uriArray.map(
+ uriString =>
+ Services.uriFixup.getFixupURIInfo(
+ uriString,
+ Ci.nsIURIFixup.FIXUP_FLAG_NONE
+ ).preferredURI?.spec ?? "about:tor"
+ );
+ },
+
+ // called from browser.js on browser startup, passed in either the user's homepage(s)
+ // or uris passed via command-line; we want to replace them with about:torconnect uris
+ // which redirect after bootstrapping
+ getURIsToLoad(uriVariant) {
+ const uris = this.fixupURIs(uriVariant);
+ lazy.logger.debug(`Will load after bootstrap => [${uris.join(", ")}]`);
+ return uris.map(uri => this.getRedirectURL(uri));
+ },
+};
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/522337…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/522337…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/rbm][main] Bug 40075: Create destination directory when creating input_files with `content`
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch main at The Tor Project / Applications / RBM
Commits:
05e32169 by Nicolas Vigier at 2024-03-18T13:52:40+01:00
Bug 40075: Create destination directory when creating input_files with `content`
- - - - -
1 changed file:
- lib/RBM.pm
Changes:
=====================================
lib/RBM.pm
=====================================
@@ -1001,6 +1001,8 @@ sub input_files {
my $file_gpg_id = gpg_id($t->('file_gpg_id'));
if (input_file_need_dl($input_file, $t, $fname, $action)) {
if ($t->('content')) {
+ my $dname = dirname("$proj_out_dir/$name");
+ make_path($dname) unless -d $dname;
path("$proj_out_dir/$name")->spew_utf8($t->('content'));
} elsif ($t->('URL')) {
urlget($project, {%$options, %$input_file, filename => $name}, 1);
View it on GitLab: https://gitlab.torproject.org/tpo/applications/rbm/-/commit/05e32169dfad9f3…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/rbm/-/commit/05e32169dfad9f3…
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-13.0.12-build2
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed new tag tbb-13.0.12-build2 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][maint-13.0] Bug 41084: Prepare Tor Browser 13.0.12 Part 3
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch maint-13.0 at The Tor Project / Applications / tor-browser-build
Commits:
bbafe0a0 by Richard Pospesel at 2024-03-19T00:49:01+00:00
Bug 41084: Prepare Tor Browser 13.0.12 Part 3
- - - - -
1 changed file:
- rbm.conf
Changes:
=====================================
rbm.conf
=====================================
@@ -74,7 +74,7 @@ buildconf:
var:
torbrowser_version: '13.0.12'
- torbrowser_build: 'build1'
+ torbrowser_build: 'build2'
torbrowser_incremental_from:
- '[% IF c("var/tor-browser") %]13.0.11[% END %]'
- '13.0.10'
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/b…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/b…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build][maint-13.0] Bug 41084: Prepare Tor Browser 13.0.12 Part 2
by richard (@richard) 19 Mar '24
by richard (@richard) 19 Mar '24
19 Mar '24
richard pushed to branch maint-13.0 at The Tor Project / Applications / tor-browser-build
Commits:
c92c6b96 by Richard Pospesel at 2024-03-18T22:54:21+00:00
Bug 41084: Prepare Tor Browser 13.0.12 Part 2
- - - - -
4 changed files:
- projects/browser/Bundle-Data/Docs-TBB/ChangeLog.txt
- projects/firefox/config
- projects/geckoview/config
- projects/translation/config
Changes:
=====================================
projects/browser/Bundle-Data/Docs-TBB/ChangeLog.txt
=====================================
@@ -1,17 +1,19 @@
Tor Browser 13.0.12 - March 19 2024
* All Platforms
+ * Updated Snowflake to 2.9.2
* Bug 42376: The placeholder of datetime inputs keeps being localized when spoof English is on [tor-browser]
* Bug 42378: spoof english + htmlform <details> can leak app language [tor-browser]
* Bug 42444: Remove the "Prioritize .onion sites when known" option [tor-browser]
* Bug 42448: Rebase Tor Browser stable onto Firefox 115.9.0esr [tor-browser]
* Bug 42459: Add startpage onion service to list of search providers [tor-browser]
+ * Bug 41105: Bump version of snowflake to v2.9.2 [tor-browser-build]
* Windows + macOS + Linux
* Updated Firefox to 115.9.0esr
+ * Windows
+ * Bug 42377: Hidden fonts are automatically added to the allow list [tor-browser]
* Android
* Updated GeckoView to 115.9.0esr
* Bug 42407: TTP-03-010 WP3: Potential phishing [tor-browser]
- * Windows
- * Bug 42377: Hidden fonts are automatically added to the allow list [tor-browser]
* Build System
* All Platforms
* Updated Go to 1.21.8
=====================================
projects/firefox/config
=====================================
@@ -18,7 +18,9 @@ var:
firefox_version: '[% c("var/firefox_platform_version") %]esr'
browser_series: '13.0'
browser_branch: '[% c("var/browser_series") %]-1'
- browser_build: 2
+ # update the mullvadbrowser specific override for 115.10.0
+ # torbrowser had an extra firefox build tag
+ browser_build: 3
branding_directory_prefix: 'tb'
copyright_year: '[% exec("git show -s --format=%ci").remove("-.*") %]'
nightly_updates_publish_dir: '[% c("var/nightly_updates_publish_dir_prefix") %]nightly-[% c("var/osname") %]'
@@ -102,6 +104,7 @@ targets:
mullvadbrowser:
git_url: https://gitlab.torproject.org/tpo/applications/mullvad-browser.git
var:
+ browser_build: 2
branding_directory_prefix: 'mb'
gitlab_project: https://gitlab.torproject.org/tpo/applications/mullvad-browser
updater_url: 'https://cdn.mullvad.net/browser/update_responses/update_1/'
=====================================
projects/geckoview/config
=====================================
@@ -16,7 +16,7 @@ container:
var:
geckoview_version: 115.9.0esr
browser_branch: 13.0-1
- browser_build: 2
+ browser_build: 3
copyright_year: '[% exec("git show -s --format=%ci").remove("-.*") %]'
gitlab_project: https://gitlab.torproject.org/tpo/applications/tor-browser
git_commit: '[% exec("git rev-parse HEAD") %]'
=====================================
projects/translation/config
=====================================
@@ -12,13 +12,13 @@ compress_tar: 'gz'
steps:
base-browser:
base-browser: '[% INCLUDE build %]'
- git_hash: 595dcd5efe752cddc1b6ba47082ad9f5f4917fee
+ git_hash: a4d224e82808529e135259e04fb58fb39b90da2d
targets:
nightly:
git_hash: 'base-browser'
tor-browser:
tor-browser: '[% INCLUDE build %]'
- git_hash: 9b6914a85be61ad6975e8bf483d4484d39bf5f7a
+ git_hash: e7aabc54138211e23bc60af1abe492c8bc68ce4b
targets:
nightly:
git_hash: 'tor-browser'
@@ -32,7 +32,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: 7374fbc72d2c37a4d5354447dec3b5c543fd0380
+ git_hash: ef6bef5e373108c4e633998b517e4bc8c297770a
compress_tar: 'zst'
targets:
nightly:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/c…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/c…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.9.0esr-13.5-1] 4 commits: fixup! Bug 2176: Rebrand Firefox to TorBrowser
by richard (@richard) 18 Mar '24
by richard (@richard) 18 Mar '24
18 Mar '24
richard pushed to branch tor-browser-115.9.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
ce6c08c3 by Henry Wilkes at 2024-03-14T17:44:43+00:00
fixup! Bug 2176: Rebrand Firefox to TorBrowser
Bug 42203: Migrate about dialog strings to Fluent.
- - - - -
ef8821c9 by Henry Wilkes at 2024-03-14T17:44:44+00:00
fixup! Add TorStrings module for localization
Bug 42203: Migrate about dialog strings to Fluent.
- - - - -
eb190fbe by Henry Wilkes at 2024-03-14T17:45:50+00:00
fixup! Tor Browser strings
Bug 42203: Migrate about dialog strings to Fluent.
Also renew the trademark description:
+ Use double-quotes rather than ASCII single quotes.
+ Capitalize "The" and include it as part of the trademark name and the
corporation name.
+ Add a note to translators to not translate the trademark names. The
previous translations often translated "Onion Logo" even though it is
a trademark name.
- - - - -
52233769 by Henry Wilkes at 2024-03-14T17:45:57+00:00
fixup! Tor Browser localization migration scripts.
Bug 42203: Migrate about dialog strings to Fluent.
We do not migrate the trademark description since the en-US string
changed.
- - - - -
5 changed files:
- browser/base/content/aboutDialog.xhtml
- browser/base/content/browser-doctype.inc
- browser/locales/en-US/browser/tor-browser.ftl
- − toolkit/torbutton/chrome/locale/en-US/aboutDialog.dtd
- + tools/torbrowser/l10n/migrations/bug-42203-about-dialog.py
Changes:
=====================================
browser/base/content/aboutDialog.xhtml
=====================================
@@ -9,11 +9,6 @@
<?xml-stylesheet href="chrome://branding/content/aboutDialog.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/aboutDialogTor.css" type="text/css"?>
-<!-- We need to include the localization DTDs until we migrate to Fluent -->
-<!DOCTYPE window [
-#include browser-doctype.inc
-]>
-
<window xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="aboutDialog"
@@ -37,6 +32,7 @@
<html:link rel="localization" href="branding/brand.ftl"/>
<html:link rel="localization" href="browser/aboutDialog.ftl"/>
<html:link rel="localization" href="browser/base-browser.ftl"/>
+ <html:link rel="localization" href="browser/tor-browser.ftl"/>
</linkset>
<html:div id="aboutDialogContainer">
@@ -135,35 +131,26 @@
</description>
</vbox>
<!-- Keep communityDesc and contributeDesc to avoid JS errors trying to hide them -->
- <description class="text-blurb" id="communityDesc" data-l10n-id="community-2" hidden="true"></description>
- <description class="text-blurb" id="contributeDesc" data-l10n-id="helpus" hidden="true"></description>
- <description class="text-blurb" id="projectDesc">
- &project.start;
- <label is="text-link" href="https://www.torproject.org/">
- &project.tpoLink;
- </label>&project.end;
+ <description class="text-blurb" id="communityDesc" hidden="true"></description>
+ <description class="text-blurb" id="contributeDesc" hidden="true"></description>
+ <description class="text-blurb" id="projectDesc" data-l10n-id="about-dialog-tor-project">
+ <label is="text-link" href="https://www.torproject.org/" data-l10n-name="project-link"></label>
</description>
- <description class="text-blurb" id="helpDesc">
- &help.start;
- <label is="text-link" href="https://donate.torproject.org/">
- &help.donateLink;
- </label>
- &help.or;
- <label is="text-link" href="https://community.torproject.org/">
- &help.getInvolvedLink;
- </label>&help.end;
+ <description class="text-blurb" id="helpDesc" data-l10n-id="about-dialog-help-out">
+ <label is="text-link" href="https://donate.torproject.org/" data-l10n-name="donate-link"></label>
+ <label is="text-link" href="https://community.torproject.org/" data-l10n-name="community-link"></label>
</description>
</vbox>
</vbox>
</hbox>
<vbox id="bottomBox">
<hbox id="newBottom" pack="center" position="1">
- <label is="text-link" class="bottom-link" href="https://support.torproject.org/">&bottomLinks.questions;</label>
- <label is="text-link" class="bottom-link" href="https://community.torproject.org/relay/">&bottomLinks.grow;</label>
- <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:license">&bottomLinks.license;</label>
+ <label is="text-link" class="bottom-link" href="https://support.torproject.org/" data-l10n-id="about-dialog-questions-link"></label>
+ <label is="text-link" class="bottom-link" href="https://community.torproject.org/relay/" data-l10n-id="about-dialog-grow-tor-network-link"></label>
+ <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:license" data-l10n-id="about-dialog-browser-license-link"></label>
</hbox>
<description id="trademark" data-l10n-id="trademarkInfo"></description>
- <description id="trademarkTor">&tor.TrademarkStatement;</description>
+ <description id="trademarkTor" data-l10n-id="about-dialog-trademark-statement"></description>
</vbox>
</html:div>
=====================================
browser/base/content/browser-doctype.inc
=====================================
@@ -2,5 +2,3 @@
%brandDTD;
<!ENTITY % torbuttonDTD SYSTEM "chrome://torbutton/locale/torbutton.dtd">
%torbuttonDTD;
-<!ENTITY % aboutDialogDTD SYSTEM "chrome://torbutton/locale/aboutDialog.dtd">
-%aboutDialogDTD;
=====================================
browser/locales/en-US/browser/tor-browser.ftl
=====================================
@@ -304,3 +304,25 @@ user-provide-bridge-dialog-next-button =
# The "aria-label" should use the same text, but include some ending punctuation to separate it from the sentence that follows. This is used for screen reader users.
built-in-dialog-current-bridge-label = Current bridge
.aria-label = Current bridge.
+
+## About Tor Browser dialog.
+
+# '<label data-l10n-name="project-link">' and '</label>' should wrap the link text for the Tor Project, and will link to the Tor Project web page.
+# -brand-short-name refers to 'Tor Browser', localized.
+# -vendor-short-name refers to 'Tor Project', localized.
+about-dialog-tor-project = { -brand-short-name } is developed by <label data-l10n-name="project-link">the { -vendor-short-name }</label>, a nonprofit working to defend your privacy and freedom online.
+
+# '<label data-l10n-name="donate-link">' and '</label>' should wrap the link text for donating to Tor Project, and will link to the Tor Project donation page.
+# '<label data-l10n-name="community-link">' and '</label>' should wrap the link text for getting involved with Tor Project, and will link to the Tor Project community page.
+about-dialog-help-out = Want to help? <label data-l10n-name="donate-link">Donate</label> or <label data-l10n-name="community-link">get involved</label>!
+
+# Link text for the Tor Project support page.
+about-dialog-questions-link = Questions?
+# Link text for the Tor Project page for Tor Network relay operators.
+about-dialog-grow-tor-network-link = Help the Tor Network Grow!
+# Link text for the Tor Browser license page (about:license).
+about-dialog-browser-license-link = Licensing Information
+
+# "Tor" and "The Onion Logo" are trademark names, so should not be translated (not including the quote marks, which can be localized).
+# "The Tor Project, Inc." is an organisation name.
+about-dialog-trademark-statement = “Tor” and “The Onion Logo” are registered trademarks of The Tor Project, Inc.
=====================================
toolkit/torbutton/chrome/locale/en-US/aboutDialog.dtd deleted
=====================================
@@ -1,24 +0,0 @@
-<!-- Copyright (c) 2022, The Tor Project, Inc.
- - 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/. -->
-
-<!ENTITY project.start "&brandShortName; is developed by ">
-<!-- LOCALIZATION NOTE (project.tpoLink): This is a link title that links to https://www.torproject.org -->
-<!ENTITY project.tpoLink "the &vendorShortName;">
-<!ENTITY project.end ", a nonprofit working to defend your privacy and freedom online.">
-
-<!ENTITY help.start "Want to help? ">
-<!-- LOCALIZATION NOTE (help.donate): This is a link title that links to https://donate.torproject.org/ -->
-<!ENTITY help.donateLink "Donate">
-<!ENTITY help.or " or ">
-<!-- LOCALIZATION NOTE (help.getInvolvedLink): This is a link title that links to https://community.torproject.org/ -->
-<!ENTITY help.getInvolvedLink "get involved">
-<!ENTITY help.end "!">
-<!-- LOCALIZATION NOTE (bottom.questions): This is a link title that links to https://support.torproject.org/ -->
-<!ENTITY bottomLinks.questions "Questions?">
-<!-- LOCALIZATION NOTE (bottom.questions): This is a link title that links to https://community.torproject.org/relay/ -->
-<!ENTITY bottomLinks.grow "Help the Tor Network Grow!">
-<!-- LOCALIZATION NOTE (bottom.questions): This is a link title that links to about:license -->
-<!ENTITY bottomLinks.license "Licensing Information">
-<!ENTITY tor.TrademarkStatement "'Tor' and the 'Onion Logo' are registered trademarks of the Tor Project, Inc.">
=====================================
tools/torbrowser/l10n/migrations/bug-42203-about-dialog.py
=====================================
@@ -0,0 +1,75 @@
+import fluent.syntax.ast as FTL
+from fluent.migrate.helpers import TERM_REFERENCE, transforms_from
+from fluent.migrate.transforms import CONCAT, COPY, REPLACE
+
+
+def migrate(ctx):
+ legacy_path = "aboutDialog.dtd"
+ ctx.add_transforms(
+ "tor-browser.ftl",
+ "tor-browser.ftl",
+ transforms_from(
+ """
+about-dialog-questions-link = { COPY(path, "bottomLinks.questions") }
+about-dialog-grow-tor-network-link = { COPY(path, "bottomLinks.grow") }
+about-dialog-browser-license-link = { COPY(path, "bottomLinks.license") }
+""",
+ path=legacy_path,
+ )
+ + [
+ # Concatenate as
+ # &project.start;
+ # <label data-l10n-name="project-link">&project.tpoLink;</a>
+ # &project.end;
+ #
+ # And replace any occurrence of "&brandShortName;" and
+ # "&vendorShortName;" with "-brand-short-name" and
+ # "-vendor-short-name", wherever they may appear.
+ FTL.Message(
+ id=FTL.Identifier("about-dialog-tor-project"),
+ value=CONCAT(
+ REPLACE(
+ legacy_path,
+ "project.start",
+ {
+ "&brandShortName;": TERM_REFERENCE("brand-short-name"),
+ "&vendorShortName;": TERM_REFERENCE("vendor-short-name"),
+ },
+ ),
+ FTL.TextElement('<label data-l10n-name="project-link">'),
+ REPLACE(
+ legacy_path,
+ "project.tpoLink",
+ {
+ "&brandShortName;": TERM_REFERENCE("brand-short-name"),
+ "&vendorShortName;": TERM_REFERENCE("vendor-short-name"),
+ },
+ ),
+ FTL.TextElement("</label>"),
+ REPLACE(
+ legacy_path,
+ "project.end",
+ {
+ "&brandShortName;": TERM_REFERENCE("brand-short-name"),
+ "&vendorShortName;": TERM_REFERENCE("vendor-short-name"),
+ },
+ ),
+ ),
+ ),
+ # Concatenate with two link labels.
+ FTL.Message(
+ id=FTL.Identifier("about-dialog-help-out"),
+ value=CONCAT(
+ COPY(legacy_path, "help.start"),
+ FTL.TextElement('<label data-l10n-name="donate-link">'),
+ COPY(legacy_path, "help.donateLink"),
+ FTL.TextElement("</label>"),
+ COPY(legacy_path, "help.or"),
+ FTL.TextElement('<label data-l10n-name="community-link">'),
+ COPY(legacy_path, "help.getInvolvedLink"),
+ FTL.TextElement("</label>"),
+ COPY(legacy_path, "help.end"),
+ ),
+ ),
+ ],
+ )
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/018c55…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/018c55…
You're receiving this email because of your account on gitlab.torproject.org.
1
0