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
- 18612 discussions

[Git][tpo/applications/tor-browser-build][main] Bug 41051: Update changelogs for Tor Browser 13.5a4
by richard (@richard) 31 Jan '24
by richard (@richard) 31 Jan '24
31 Jan '24
richard pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
b87a696a by Richard Pospesel at 2024-01-31T12:10:10+00:00
Bug 41051: Update changelogs for Tor Browser 13.5a4
- - - - -
1 changed file:
- projects/browser/Bundle-Data/Docs-TBB/ChangeLog.txt
Changes:
=====================================
projects/browser/Bundle-Data/Docs-TBB/ChangeLog.txt
=====================================
@@ -1,4 +1,4 @@
-Tor Browser 13.5a4 - January 29 2024
+Tor Browser 13.5a4 - January 31 2024
* All Platforms
* Updated zlib to 1.3.1
* Updated Snowflake to 2.8.1
@@ -13,10 +13,15 @@ Tor Browser 13.5a4 - January 29 2024
* Bug 42374: spoof english leaks via numberingSystem: numbers (non-latn) or decimal separator (latn) [tor-browser]
* Bug 42384: Regression: quickstart doesn't work anymore [tor-browser]
* Bug 41058: Update Snowflake to 2.8.1 [tor-browser-build]
+ * Bug 262: Mouse-over long links causes the browser element to re-center relative to width of status tooltip [mullvad-browser]
* Windows + macOS + Linux
* Updated Firefox to 115.7.0esr
* Bug 41917: Make the appearance of letterboxing look more intentional [tor-browser]
+ * Bug 42036: Design and build a user interface for Lox [tor-browser]
* Bug 42338: Changing circuit programmatically in Tor Browser not working anymore! [tor-browser]
+ * Bug 42387: Visual noise in 13.5a4 letterboxing [tor-browser]
+ * Linux
+ * Bug 42293: Updater is disabled when tor-browser is run by torbrowser-launcher flatpak [tor-browser]
* Android
* Updated GeckoView to 115.7.0esr
* Bug 42252: Plumb down TorConnect commands from firefox-android to GeckoView [tor-browser]
@@ -25,14 +30,15 @@ Tor Browser 13.5a4 - January 29 2024
* Bug 42355: Fullscreen on Android doesn't hide system bars [tor-browser]
* Bug 42367: Backport Android security fixes from Firefox 122 [tor-browser]
* Bug 42368: Tor Browser 13.5a3 crashes during start-up because of API26+ methods [tor-browser]
- * Linux
- * Bug 42293: Updater is disabled when tor-browser is run by torbrowser-launcher flatpak [tor-browser]
* Build System
* All Platforms
* Updated Go to 1.20.13 and 1.21.6
* Bug 41037: Set time on signing machine before starting signing [tor-browser-build]
+ * Bug 41038: Add RPM dependencies to README [tor-browser-build]
* Bug 41059: Update keyring/torbrowser.gpg with updated key [tor-browser-build]
* Bug 41063: Run "file $keyring" in tools/keyring/list-all-keyrings [tor-browser-build]
+ * Bug 41067: Use Capture::Tiny instead of IO::CaptureOutput [tor-browser-build]
+ * Bug 41073: Update documention about required packages for container-less build [tor-browser-build]
* Bug 40067: Use --no-verbose wget option when not running in a terminal [rbm]
* Windows
* Bug 40606: Use Clang to compile NSIS [tor-browser-build]
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/firefox-android] Pushed new tag firefox-android-115.2.1-13.5-1-build5
by richard (@richard) 31 Jan '24
by richard (@richard) 31 Jan '24
31 Jan '24
richard pushed new tag firefox-android-115.2.1-13.5-1-build5 at The Tor Project / Applications / firefox-android
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/tree/firef…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser] Pushed new tag tor-browser-115.7.0esr-13.5-1-build2
by richard (@richard) 31 Jan '24
by richard (@richard) 31 Jan '24
31 Jan '24
richard pushed new tag tor-browser-115.7.0esr-13.5-1-build2 at The Tor Project / Applications / Tor Browser
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/tree/tor-brows…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/mullvad-browser][mullvad-browser-115.7.0esr-13.5-1] fixup! Bug 32308: use direct browser sizing for letterboxing.
by richard (@richard) 31 Jan '24
by richard (@richard) 31 Jan '24
31 Jan '24
richard pushed to branch mullvad-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Mullvad Browser
Commits:
f74a854e by hackademix at 2024-01-31T13:44:56+00:00
fixup! Bug 32308: use direct browser sizing for letterboxing.
Bug 42387: hide visual artifacts and fix the status label on rounded letterboxing borders.
- - - - -
3 changed files:
- browser/base/content/browser.css
- browser/base/content/tabbrowser.js
- toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
Changes:
=====================================
browser/base/content/browser.css
=====================================
@@ -127,6 +127,11 @@ body {
-moz-window-dragging: drag;
}
+/**
+ Never modify the following selector without synchronizing
+ LETTERBOX_CSS_SELECTOR in RFPHelper.sys.jsm, where
+ --letterboxing-width & --letterboxing-height are actually set.
+**/
.letterboxing .browserContainer {
/*
From Firefox 115 on, .browserContainer layout is flex / column,
@@ -137,6 +142,14 @@ body {
background: var(--letterboxing-bgcolor);
}
+.browserDecorator {
+ display: none;
+ pointer-events: none;
+ background: transparent;
+ position: relative;
+ z-index: 1;
+}
+
.letterboxing {
--letterboxing-border-radius: 8px;
--letterboxing-border-top-radius: 0;
@@ -145,6 +158,7 @@ body {
--letterboxing-bgcolor: var(--tabpanel-background-color);
--letterboxing-gradient-color1: var(--letterboxing-bgcolor);
--letterboxing-gradient-color2: color-mix(in srgb, var(--chrome-content-separator-color) 50%, var(--letterboxing-bgcolor));
+ --letterboxing-border-color: var(--letterboxing-bgcolor);
}
.letterboxing.letterboxing-vcenter .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
@@ -157,6 +171,26 @@ body {
box-shadow: rgba(0, 0, 0, 0.5) 0px -1px 2px;
}
+:root:not([inDOMFullscreen]) .letterboxing .browserContainer:not(.responsive-mode)
+ > .browserStack:not(.exclude-letterboxing)
+ > .browserDecorator {
+ display: initial;
+ visibility: visible;
+ border-radius: var(--letterboxing-border-radius);
+ border-top-left-radius: var(--letterboxing-border-top-radius);
+ border-top-right-radius: var(--letterboxing-border-top-radius);
+ box-shadow: var(--letterboxing-border-color) 0px 0px .1px inset, var(--letterboxing-border-color) 0 0 .1px;
+ border: .1px solid var(--letterboxing-border-color);
+ outline: .1px solid var(--letterboxing-bgcolor);
+ height: calc(var(--letterboxing-height) + 1px);
+ top: -1px;
+}
+
+.letterboxing-vcenter .browserDecorator {
+ height: auto !important;
+ top: 0 !important;
+}
+
/*
Align status bar with content.
TODO: switch to nested CSS selectors for conciseness when available (Firefox >= 117)
@@ -167,6 +201,7 @@ body {
place-self: end left;
left: 0;
right: 0;
+ z-index: 2;
--letterboxing-status-left-radius: var(--letterboxing-border-radius);
--letterboxing-status-right-radius: 0;
}
@@ -184,23 +219,24 @@ body {
.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
#statuspanel-label {
border-radius: 0 0 var(--letterboxing-status-right-radius) var(--letterboxing-status-left-radius);
+ margin: 0;
+ border: 1px solid var(--letterboxing-border-color);
+ max-width: calc(var(--letterboxing-width) * .5);
}
-/**
- Never modify the following selector without synchronizing
- LETTERBOX_CSS_SELECTOR in RFPHelper.jsm!
-**/
.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
- /* width & height to be dynamically set by RFPHelper.jsm */
box-shadow: 0px 4px 8px 0px var(--letterboxing-shadow-color);
border-radius: var(--letterboxing-border-radius);
border-top-left-radius: var(--letterboxing-border-top-radius);
border-top-right-radius: var(--letterboxing-border-top-radius);
+ width: var(--letterboxing-width) !important;
+ height: var(--letterboxing-height) !important;
}
:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode)
> .browserStack:not(.exclude-letterboxing) {
place-content: var(--letterboxing-vertical-alignment) center;
+ background: var(--letterboxing-bgcolor);
}
#toolbar-menubar[autohide="true"] {
=====================================
browser/base/content/tabbrowser.js
=====================================
@@ -2238,6 +2238,10 @@
stack.className = "browserStack";
stack.appendChild(b);
+ let decorator = document.createXULElement("hbox");
+ decorator.className = "browserDecorator";
+ stack.appendChild(decorator);
+
let browserContainer = document.createXULElement("vbox");
browserContainer.className = "browserContainer";
browserContainer.appendChild(notificationbox);
=====================================
toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
=====================================
@@ -447,8 +447,7 @@ class _RFPHelper {
// find the rule applying the default letterboxing styles to browsers
// preemptively in order to beat race conditions on tab/window creation
const LETTERBOX_CSS_URL = "chrome://browser/content/browser.css";
- const LETTERBOX_CSS_SELECTOR =
- ".letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser";
+ const LETTERBOX_CSS_SELECTOR = ".letterboxing .browserContainer";
for (let ss of document.styleSheets) {
if (ss.href !== LETTERBOX_CSS_URL) {
continue;
@@ -572,8 +571,8 @@ class _RFPHelper {
const r = (width, height) => {
lastRoundedSize = {width, height};
return {
- width: `var(--rdm-width, ${width}px)`,
- height: `var(--rdm-height, ${height}px)`,
+ "--letterboxing-width": `var(--rdm-width, ${width}px)`,
+ "--letterboxing-height": `var(--rdm-height, ${height}px)`,
}
};
@@ -637,7 +636,7 @@ class _RFPHelper {
for (let [name, value] of Object.entries(props)) {
if (style[name] !== value) {
this.push(() => {
- style.setProperty(name, value, "important");
+ style.setProperty(name, value);
});
}
}
@@ -668,8 +667,11 @@ class _RFPHelper {
? // optional UI components such as the notification box, the find bar
// or devtools are constraining this browser's size: recompute custom
roundDimensions(parentWidth, parentHeight)
- : { width: "", height: "" }; // otherwise we can keep the default (rounded) size
- styleChanges.queueIfNeeded(aBrowser, roundedInline);
+ : {
+ "--letterboxing-width": "",
+ "--letterboxing-height": "",
+ }; // otherwise we can keep the default (rounded) size
+ styleChanges.queueIfNeeded(browserParent, roundedInline);
if (lastRoundedSize) {
// check wether the letterboxing margin is less than the border radius, and if so flatten the borders
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/f74…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/f74…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.7.0esr-13.5-1] fixup! Bug 32308: use direct browser sizing for letterboxing.
by richard (@richard) 31 Jan '24
by richard (@richard) 31 Jan '24
31 Jan '24
richard pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
922c0f76 by hackademix at 2024-01-31T14:22:39+01:00
fixup! Bug 32308: use direct browser sizing for letterboxing.
Bug 42387: hide visual artifacts and fix the status label on rounded letterboxing borders.
- - - - -
3 changed files:
- browser/base/content/browser.css
- browser/base/content/tabbrowser.js
- toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
Changes:
=====================================
browser/base/content/browser.css
=====================================
@@ -127,6 +127,11 @@ body {
-moz-window-dragging: drag;
}
+/**
+ Never modify the following selector without synchronizing
+ LETTERBOX_CSS_SELECTOR in RFPHelper.sys.jsm, where
+ --letterboxing-width & --letterboxing-height are actually set.
+**/
.letterboxing .browserContainer {
/*
From Firefox 115 on, .browserContainer layout is flex / column,
@@ -137,6 +142,14 @@ body {
background: var(--letterboxing-bgcolor);
}
+.browserDecorator {
+ display: none;
+ pointer-events: none;
+ background: transparent;
+ position: relative;
+ z-index: 1;
+}
+
.letterboxing {
--letterboxing-border-radius: 8px;
--letterboxing-border-top-radius: 0;
@@ -145,6 +158,7 @@ body {
--letterboxing-bgcolor: var(--tabpanel-background-color);
--letterboxing-gradient-color1: var(--letterboxing-bgcolor);
--letterboxing-gradient-color2: color-mix(in srgb, var(--chrome-content-separator-color) 50%, var(--letterboxing-bgcolor));
+ --letterboxing-border-color: var(--letterboxing-bgcolor);
}
.letterboxing.letterboxing-vcenter .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
@@ -157,6 +171,26 @@ body {
box-shadow: rgba(0, 0, 0, 0.5) 0px -1px 2px;
}
+:root:not([inDOMFullscreen]) .letterboxing .browserContainer:not(.responsive-mode)
+ > .browserStack:not(.exclude-letterboxing)
+ > .browserDecorator {
+ display: initial;
+ visibility: visible;
+ border-radius: var(--letterboxing-border-radius);
+ border-top-left-radius: var(--letterboxing-border-top-radius);
+ border-top-right-radius: var(--letterboxing-border-top-radius);
+ box-shadow: var(--letterboxing-border-color) 0px 0px .1px inset, var(--letterboxing-border-color) 0 0 .1px;
+ border: .1px solid var(--letterboxing-border-color);
+ outline: .1px solid var(--letterboxing-bgcolor);
+ height: calc(var(--letterboxing-height) + 1px);
+ top: -1px;
+}
+
+.letterboxing-vcenter .browserDecorator {
+ height: auto !important;
+ top: 0 !important;
+}
+
/*
Align status bar with content.
TODO: switch to nested CSS selectors for conciseness when available (Firefox >= 117)
@@ -167,6 +201,7 @@ body {
place-self: end left;
left: 0;
right: 0;
+ z-index: 2;
--letterboxing-status-left-radius: var(--letterboxing-border-radius);
--letterboxing-status-right-radius: 0;
}
@@ -184,23 +219,24 @@ body {
.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
#statuspanel-label {
border-radius: 0 0 var(--letterboxing-status-right-radius) var(--letterboxing-status-left-radius);
+ margin: 0;
+ border: 1px solid var(--letterboxing-border-color);
+ max-width: calc(var(--letterboxing-width) * .5);
}
-/**
- Never modify the following selector without synchronizing
- LETTERBOX_CSS_SELECTOR in RFPHelper.jsm!
-**/
.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
- /* width & height to be dynamically set by RFPHelper.jsm */
box-shadow: 0px 4px 8px 0px var(--letterboxing-shadow-color);
border-radius: var(--letterboxing-border-radius);
border-top-left-radius: var(--letterboxing-border-top-radius);
border-top-right-radius: var(--letterboxing-border-top-radius);
+ width: var(--letterboxing-width) !important;
+ height: var(--letterboxing-height) !important;
}
:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode)
> .browserStack:not(.exclude-letterboxing) {
place-content: var(--letterboxing-vertical-alignment) center;
+ background: var(--letterboxing-bgcolor);
}
#toolbar-menubar[autohide="true"] {
=====================================
browser/base/content/tabbrowser.js
=====================================
@@ -2238,6 +2238,10 @@
stack.className = "browserStack";
stack.appendChild(b);
+ let decorator = document.createXULElement("hbox");
+ decorator.className = "browserDecorator";
+ stack.appendChild(decorator);
+
let browserContainer = document.createXULElement("vbox");
browserContainer.className = "browserContainer";
browserContainer.appendChild(notificationbox);
=====================================
toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
=====================================
@@ -447,8 +447,7 @@ class _RFPHelper {
// find the rule applying the default letterboxing styles to browsers
// preemptively in order to beat race conditions on tab/window creation
const LETTERBOX_CSS_URL = "chrome://browser/content/browser.css";
- const LETTERBOX_CSS_SELECTOR =
- ".letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser";
+ const LETTERBOX_CSS_SELECTOR = ".letterboxing .browserContainer";
for (let ss of document.styleSheets) {
if (ss.href !== LETTERBOX_CSS_URL) {
continue;
@@ -572,8 +571,8 @@ class _RFPHelper {
const r = (width, height) => {
lastRoundedSize = {width, height};
return {
- width: `var(--rdm-width, ${width}px)`,
- height: `var(--rdm-height, ${height}px)`,
+ "--letterboxing-width": `var(--rdm-width, ${width}px)`,
+ "--letterboxing-height": `var(--rdm-height, ${height}px)`,
}
};
@@ -637,7 +636,7 @@ class _RFPHelper {
for (let [name, value] of Object.entries(props)) {
if (style[name] !== value) {
this.push(() => {
- style.setProperty(name, value, "important");
+ style.setProperty(name, value);
});
}
}
@@ -668,8 +667,11 @@ class _RFPHelper {
? // optional UI components such as the notification box, the find bar
// or devtools are constraining this browser's size: recompute custom
roundDimensions(parentWidth, parentHeight)
- : { width: "", height: "" }; // otherwise we can keep the default (rounded) size
- styleChanges.queueIfNeeded(aBrowser, roundedInline);
+ : {
+ "--letterboxing-width": "",
+ "--letterboxing-height": "",
+ }; // otherwise we can keep the default (rounded) size
+ styleChanges.queueIfNeeded(browserParent, roundedInline);
if (lastRoundedSize) {
// check wether the letterboxing margin is less than the border radius, and if so flatten the borders
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/922c0f7…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/922c0f7…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.7.0esr-13.5-1] 2 commits: fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in...
by richard (@richard) 31 Jan '24
by richard (@richard) 31 Jan '24
31 Jan '24
richard pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
d66eecaa by Henry Wilkes at 2024-01-31T09:28:02+00:00
fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
Bug 42385: Add lox invite dialog.
- - - - -
48110609 by Henry Wilkes at 2024-01-31T09:28:03+00:00
fixup! Tor Browser strings
Bug 42385: Add lox invite dialog strings.
- - - - -
6 changed files:
- browser/components/torpreferences/content/connectionPane.js
- + browser/components/torpreferences/content/loxInviteDialog.js
- + browser/components/torpreferences/content/loxInviteDialog.xhtml
- browser/components/torpreferences/content/torPreferences.css
- browser/components/torpreferences/jar.mn
- browser/locales/en-US/browser/tor-browser.ftl
Changes:
=====================================
browser/components/torpreferences/content/connectionPane.js
=====================================
@@ -1321,7 +1321,17 @@ const gLoxStatus = {
);
this._invitesButton.addEventListener("click", () => {
- // TODO: Show invites.
+ gSubDialog.open(
+ "chrome://browser/content/torpreferences/loxInviteDialog.xhtml",
+ {
+ features: "resizable=yes",
+ closedCallback: () => {
+ // TODO: Listen for events from Lox, rather than call _updateInvites
+ // directly.
+ this._updateInvites();
+ },
+ }
+ );
});
this._unlockAlertButton.addEventListener("click", () => {
// TODO: Have a way to ensure that the cleared event data matches the
=====================================
browser/components/torpreferences/content/loxInviteDialog.js
=====================================
@@ -0,0 +1,347 @@
+"use strict";
+
+const { TorSettings, TorSettingsTopics, TorBridgeSource } =
+ ChromeUtils.importESModule("resource://gre/modules/TorSettings.sys.mjs");
+
+const { Lox, LoxErrors } = ChromeUtils.importESModule(
+ "resource://gre/modules/Lox.sys.mjs"
+);
+
+/**
+ * Fake Lox module
+
+const LoxErrors = {
+ LoxServerUnreachable: "LoxServerUnreachable",
+ Other: "Other",
+};
+
+const Lox = {
+ remainingInvites: 5,
+ getRemainingInviteCount() {
+ return this.remainingInvites;
+ },
+ invites: [
+ '{"invite": [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22]}',
+ '{"invite": [9,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22]}',
+ ],
+ getInvites() {
+ return this.invites;
+ },
+ failError: null,
+ generateInvite() {
+ return new Promise((res, rej) => {
+ setTimeout(() => {
+ if (this.failError) {
+ rej({ type: this.failError });
+ return;
+ }
+ if (!this.remainingInvites) {
+ rej({ type: LoxErrors.Other });
+ return;
+ }
+ const invite = JSON.stringify({
+ invite: Array.from({ length: 100 }, () =>
+ Math.floor(Math.random() * 265)
+ ),
+ });
+ this.invites.push(invite);
+ this.remainingInvites--;
+ res(invite);
+ }, 4000);
+ });
+ },
+};
+*/
+
+const gLoxInvites = {
+ /**
+ * Initialize the dialog.
+ */
+ init() {
+ this._dialog = document.getElementById("lox-invite-dialog");
+ this._remainingInvitesEl = document.getElementById(
+ "lox-invite-dialog-remaining"
+ );
+ this._generateButton = document.getElementById(
+ "lox-invite-dialog-generate-button"
+ );
+ this._connectingEl = document.getElementById(
+ "lox-invite-dialog-connecting"
+ );
+ this._errorEl = document.getElementById("lox-invite-dialog-error-message");
+ this._inviteListEl = document.getElementById("lox-invite-dialog-list");
+
+ this._generateButton.addEventListener("click", () => {
+ this._generateNewInvite();
+ });
+
+ const menu = document.getElementById("lox-invite-dialog-item-menu");
+ this._inviteListEl.addEventListener("contextmenu", event => {
+ if (!this._inviteListEl.selectedItem) {
+ return;
+ }
+ menu.openPopupAtScreen(event.screenX, event.screenY, true);
+ });
+ menu.addEventListener("popuphidden", () => {
+ menu.setAttribute("aria-hidden", "true");
+ });
+ menu.addEventListener("popupshowing", () => {
+ menu.removeAttribute("aria-hidden");
+ });
+ document
+ .getElementById("lox-invite-dialog-copy-menu-item")
+ .addEventListener("command", () => {
+ const selected = this._inviteListEl.selectedItem;
+ if (!selected) {
+ return;
+ }
+ const clipboard = Cc[
+ "@mozilla.org/widget/clipboardhelper;1"
+ ].getService(Ci.nsIClipboardHelper);
+ clipboard.copyString(selected.textContent);
+ });
+
+ // NOTE: TorSettings should already be initialized when this dialog is
+ // opened.
+ Services.obs.addObserver(this, TorSettingsTopics.SettingsChanged);
+ // TODO: Listen for new invites from Lox, when supported.
+
+ // Set initial _loxId value. Can close this dialog.
+ this._updateLoxId();
+
+ this._updateRemainingInvites();
+ this._updateExistingInvites();
+ },
+
+ /**
+ * Un-initialize the dialog.
+ */
+ uninit() {
+ Services.obs.removeObserver(this, TorSettingsTopics.SettingsChanged);
+ },
+
+ observe(subject, topic, data) {
+ switch (topic) {
+ case TorSettingsTopics.SettingsChanged:
+ const { changes } = subject.wrappedJSObject;
+ if (
+ changes.includes("bridges.source") ||
+ changes.includes("bridges.lox_id")
+ ) {
+ this._updateLoxId();
+ }
+ break;
+ }
+ },
+
+ /**
+ * The loxId this dialog is shown for. null if uninitailized.
+ *
+ * @type {string?}
+ */
+ _loxId: null,
+ /**
+ * Update the _loxId value. Will close the dialog if it changes after
+ * initialization.
+ */
+ _updateLoxId() {
+ const loxId =
+ TorSettings.bridges.source === TorBridgeSource.Lox
+ ? TorSettings.bridges.lox_id
+ : "";
+ if (!loxId || (this._loxId !== null && loxId !== this._loxId)) {
+ // No lox id, or it changed. Close this dialog.
+ this._dialog.cancelDialog();
+ }
+ this._loxId = loxId;
+ },
+
+ /**
+ * The invites that are already shown.
+ *
+ * @type {Set<string>}
+ */
+ _shownInvites: new Set(),
+
+ /**
+ * Add a new invite at the start of the list.
+ *
+ * @param {string} invite - The invite to add.
+ */
+ _addInvite(invite) {
+ if (this._shownInvites.has(invite)) {
+ return;
+ }
+ const newInvite = document.createXULElement("richlistitem");
+ newInvite.classList.add("lox-invite-dialog-list-item");
+ newInvite.textContent = invite;
+
+ this._inviteListEl.prepend(newInvite);
+ this._shownInvites.add(invite);
+ },
+
+ /**
+ * Update the display of the existing invites.
+ */
+ _updateExistingInvites() {
+ // Add new invites.
+
+ // NOTE: we only expect invites to be appended, so we won't re-order any.
+ // NOTE: invites are ordered with the oldest first.
+ for (const invite of Lox.getInvites()) {
+ this._addInvite(invite);
+ }
+ },
+
+ /**
+ * The shown number or remaining invites we have.
+ *
+ * @type {integer}
+ */
+ _remainingInvites: 0,
+
+ /**
+ * Update the display of the remaining invites.
+ */
+ _updateRemainingInvites() {
+ this._remainingInvites = Lox.getRemainingInviteCount();
+
+ document.l10n.setAttributes(
+ this._remainingInvitesEl,
+ "tor-bridges-lox-remaining-invites",
+ { numInvites: this._remainingInvites }
+ );
+ this._updateGenerateButtonState();
+ },
+
+ /**
+ * Whether we are currently generating an invite.
+ *
+ * @type {boolean}
+ */
+ _generating: false,
+ /**
+ * Set whether we are generating an invite.
+ *
+ * @param {boolean} isGenerating - Whether we are generating.
+ */
+ _setGenerating(isGenerating) {
+ this._generating = isGenerating;
+ this._updateGenerateButtonState();
+ this._connectingEl.classList.toggle("show-connecting", isGenerating);
+ },
+
+ /**
+ * Update the state of the generate button.
+ */
+ _updateGenerateButtonState() {
+ this._generateButton.disabled = this._generating || !this._remainingInvites;
+ },
+
+ /**
+ * Start generating a new invite.
+ */
+ _generateNewInvite() {
+ if (this._generating) {
+ console.error("Already generating an invite");
+ return;
+ }
+ this._setGenerating(true);
+ // Clear the previous error.
+ this._updateGenerateError(null);
+ // Move focus from the button to the connecting element, since button is
+ // now disabled.
+ this._connectingEl.focus();
+
+ let lostFocus = false;
+ Lox.generateInvite()
+ .finally(() => {
+ // Fetch whether the connecting label still has focus before we hide it.
+ lostFocus = this._connectingEl.contains(document.activeElement);
+ this._setGenerating(false);
+ })
+ .then(
+ invite => {
+ this._addInvite(invite);
+
+ if (!this._inviteListEl.contains(document.activeElement)) {
+ // Does not have focus, change the selected item to be the new
+ // invite (at index 0).
+ this._inviteListEl.selectedIndex = 0;
+ }
+
+ if (lostFocus) {
+ // Move focus to the new invite before we hide the "Connecting"
+ // message.
+ this._inviteListEl.focus();
+ }
+
+ // TODO: When Lox sends out notifications, let the observer handle the
+ // change rather than calling _updateRemainingInvites directly.
+ this._updateRemainingInvites();
+ },
+ loxError => {
+ console.error("Failed to generate an invite", loxError);
+ switch (loxError.type) {
+ case LoxErrors.LoxServerUnreachable:
+ this._updateGenerateError("no-server");
+ break;
+ default:
+ this._updateGenerateError("generic");
+ break;
+ }
+
+ if (lostFocus) {
+ // Move focus back to the button before we hide the "Connecting"
+ // message.
+ this._generateButton.focus();
+ }
+ }
+ );
+ },
+
+ /**
+ * Update the shown generation error.
+ *
+ * @param {string?} type - The error type, or null if no error should be
+ * shown.
+ */
+ _updateGenerateError(type) {
+ // First clear the existing error.
+ this._errorEl.removeAttribute("data-l10n-id");
+ this._errorEl.textContent = "";
+ this._errorEl.classList.toggle("show-error", !!type);
+
+ if (!type) {
+ return;
+ }
+
+ let errorId;
+ switch (type) {
+ case "no-server":
+ errorId = "lox-invite-dialog-no-server-error";
+ break;
+ case "generic":
+ // Generic error.
+ errorId = "lox-invite-dialog-generic-invite-error";
+ break;
+ }
+
+ document.l10n.setAttributes(this._errorEl, errorId);
+ },
+};
+
+window.addEventListener(
+ "DOMContentLoaded",
+ () => {
+ gLoxInvites.init();
+ window.addEventListener(
+ "unload",
+ () => {
+ gLoxInvites.uninit();
+ },
+ { once: true }
+ );
+ },
+ { once: true }
+);
=====================================
browser/components/torpreferences/content/loxInviteDialog.xhtml
=====================================
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
+<?xml-stylesheet href="chrome://browser/content/torpreferences/torPreferences.css"?>
+
+<window
+ type="child"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ data-l10n-id="lox-invite-dialog-title"
+>
+ <!-- Context menu, aria-hidden whilst not shown so it does not appear in the
+ - document content. -->
+ <menupopup id="lox-invite-dialog-item-menu" aria-hidden="true">
+ <menuitem
+ id="lox-invite-dialog-copy-menu-item"
+ data-l10n-id="lox-invite-dialog-menu-item-copy-invite"
+ />
+ </menupopup>
+ <dialog id="lox-invite-dialog" buttons="accept">
+ <linkset>
+ <html:link rel="localization" href="browser/tor-browser.ftl" />
+ </linkset>
+
+ <script src="chrome://browser/content/torpreferences/loxInviteDialog.js" />
+
+ <description data-l10n-id="lox-invite-dialog-description"></description>
+ <html:div id="lox-invite-dialog-generate-area">
+ <html:span id="lox-invite-dialog-remaining"></html:span>
+ <html:button
+ id="lox-invite-dialog-generate-button"
+ data-l10n-id="lox-invite-dialog-request-button"
+ ></html:button>
+ <html:div id="lox-invite-dialog-message-area">
+ <html:span
+ id="lox-invite-dialog-error-message"
+ role="alert"
+ ></html:span>
+ <html:span
+ id="lox-invite-dialog-connecting"
+ role="alert"
+ tabindex="0"
+ data-l10n-id="lox-invite-dialog-connecting"
+ ></html:span>
+ </html:div>
+ </html:div>
+ <html:div
+ id="lox-invite-dialog-list-label"
+ data-l10n-id="lox-invite-dialog-invites-label"
+ ></html:div>
+ <richlistbox
+ id="lox-invite-dialog-list"
+ aria-labelledby="lox-invite-dialog-list-label"
+ ></richlistbox>
+ </dialog>
+</window>
=====================================
browser/components/torpreferences/content/torPreferences.css
=====================================
@@ -820,6 +820,75 @@ dialog#torPreferences-requestBridge-dialog > hbox {
background: var(--qr-one);
}
+/* Lox invite dialog */
+
+#lox-invite-dialog-generate-area {
+ flex: 0 0 auto;
+ display: grid;
+ grid-template:
+ ". remaining button" min-content
+ "message message message" auto
+ / 1fr max-content max-content;
+ gap: 8px;
+ margin-block: 16px 8px;
+ align-items: center;
+}
+
+#lox-invite-dialog-remaining {
+ grid-area: remaining;
+}
+
+#lox-invite-dialog-generate-button {
+ grid-area: button;
+}
+
+#lox-invite-dialog-message-area {
+ grid-area: message;
+ justify-self: end;
+}
+
+#lox-invite-dialog-message-area::after {
+ /* Zero width space, to ensure we are always one line high. */
+ content: "\200B";
+}
+
+#lox-invite-dialog-error-message {
+ color: var(--in-content-error-text-color);
+}
+
+#lox-invite-dialog-error-message:not(.show-error) {
+ display: none;
+}
+
+#lox-invite-dialog-connecting {
+ color: var(--text-color-deemphasized);
+ /* TODO: Add spinner ::before */
+}
+
+#lox-invite-dialog-connecting:not(.show-connecting) {
+ display: none;
+}
+
+#lox-invite-dialog-list-label {
+ font-weight: 700;
+}
+
+#lox-invite-dialog-list {
+ flex: 1 1 auto;
+ /* basis height */
+ height: 10em;
+ margin-block: 8px;
+}
+
+.lox-invite-dialog-list-item {
+ white-space: nowrap;
+ overflow-x: hidden;
+ /* FIXME: ellipsis does not show. */
+ text-overflow: ellipsis;
+ padding-block: 6px;
+ padding-inline: 8px;
+}
+
/* Builtin bridge dialog */
#torPreferences-builtinBridge-header {
margin: 8px 0 10px 0;
=====================================
browser/components/torpreferences/jar.mn
=====================================
@@ -9,6 +9,8 @@ browser.jar:
content/browser/torpreferences/lox-success.svg (content/lox-success.svg)
content/browser/torpreferences/lox-complete-ring.svg (content/lox-complete-ring.svg)
content/browser/torpreferences/lox-progress-ring.svg (content/lox-progress-ring.svg)
+ content/browser/torpreferences/loxInviteDialog.xhtml (content/loxInviteDialog.xhtml)
+ content/browser/torpreferences/loxInviteDialog.js (content/loxInviteDialog.js)
content/browser/torpreferences/bridgeQrDialog.xhtml (content/bridgeQrDialog.xhtml)
content/browser/torpreferences/bridgeQrDialog.js (content/bridgeQrDialog.js)
content/browser/torpreferences/builtinBridgeDialog.xhtml (content/builtinBridgeDialog.xhtml)
=====================================
browser/locales/en-US/browser/tor-browser.ftl
=====================================
@@ -296,3 +296,17 @@ user-provide-bridge-dialog-result-invite = The following bridges were shared wit
user-provide-bridge-dialog-result-addresses = The following bridges were entered by you.
user-provide-bridge-dialog-next-button =
.label = Next
+
+## Bridge pass invite dialog. Temporary.
+
+lox-invite-dialog-title =
+ .title = Bridge pass invites
+lox-invite-dialog-description = You can ask the bridge bot to create a new invite, which you can share with a trusted contact to give them their own bridge pass. Each invite can only be redeemed once, but you will unlock access to more invites over time.
+lox-invite-dialog-request-button = Request new invite
+lox-invite-dialog-connecting = Connecting to bridge pass server…
+lox-invite-dialog-no-server-error = Unable to connect to bridge pass server.
+lox-invite-dialog-generic-invite-error = Failed to create a new invite.
+lox-invite-dialog-invites-label = Created invites:
+lox-invite-dialog-menu-item-copy-invite =
+ .label = Copy invite
+ .accesskey = C
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/8069e4…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/8069e4…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.7.0esr-13.5-1] 3 commits: fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in...
by richard (@richard) 31 Jan '24
by richard (@richard) 31 Jan '24
31 Jan '24
richard pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
277b6464 by Henry Wilkes at 2024-01-30T15:58:12+00:00
fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
Bug 42036: Add Lox to settings UI.
- - - - -
9209ad02 by Henry Wilkes at 2024-01-30T15:58:12+00:00
fixup! Tor Browser strings
Bug 42036: Add strings for Lox UI.
- - - - -
8069e4ee by Henry Wilkes at 2024-01-30T15:58:13+00:00
fixup! Lox integration
- - - - -
14 changed files:
- browser/components/torpreferences/content/connectionPane.js
- browser/components/torpreferences/content/connectionPane.xhtml
- + browser/components/torpreferences/content/lox-bridge-icon.svg
- + browser/components/torpreferences/content/lox-bridge-pass.svg
- + browser/components/torpreferences/content/lox-complete-ring.svg
- + browser/components/torpreferences/content/lox-invite-icon.svg
- + browser/components/torpreferences/content/lox-progress-ring.svg
- + browser/components/torpreferences/content/lox-success.svg
- browser/components/torpreferences/content/provideBridgeDialog.js
- browser/components/torpreferences/content/provideBridgeDialog.xhtml
- browser/components/torpreferences/content/torPreferences.css
- browser/components/torpreferences/jar.mn
- browser/locales/en-US/browser/tor-browser.ftl
- toolkit/components/lox/Lox.sys.mjs
Changes:
=====================================
browser/components/torpreferences/content/connectionPane.js
=====================================
@@ -36,6 +36,60 @@ const { TorStrings } = ChromeUtils.importESModule(
"resource://gre/modules/TorStrings.sys.mjs"
);
+const { Lox } = ChromeUtils.importESModule(
+ "resource://gre/modules/Lox.sys.mjs"
+);
+
+/*
+ * Fake Lox module:
+
+const Lox = {
+ levelHistory: [0, 1],
+ // levelHistory: [1, 2],
+ // levelHistory: [2, 3],
+ // levelHistory: [3, 4],
+ // levelHistory: [0, 1, 2],
+ // levelHistory: [1, 2, 3],
+ // levelHistory: [4, 3],
+ // levelHistory: [4, 1],
+ // levelHistory: [2, 1],
+ //levelHistory: [2, 3, 4, 1, 2],
+ // Gain some invites and then loose them all. Shouldn't show any change.
+ // levelHistory: [0, 1, 2, 1],
+ // levelHistory: [1, 2, 3, 1],
+ getEventData() {
+ let prevLevel = this.levelHistory[0];
+ const events = [];
+ for (let i = 1; i < this.levelHistory.length; i++) {
+ const level = this.levelHistory[i];
+ events.push({ type: level > prevLevel ? "levelup" : "blockage", newLevel: level });
+ prevLevel = level;
+ }
+ return events;
+ },
+ clearEventData() {
+ this.levelHistory = [];
+ },
+ nextUnlock: { date: "2024-01-31T00:00:00Z", nextLevel: 1 },
+ //nextUnlock: { date: "2024-01-31T00:00:00Z", nextLevel: 2 },
+ //nextUnlock: { date: "2024-01-31T00:00:00Z", nextLevel: 3 },
+ //nextUnlock: { date: "2024-01-31T00:00:00Z", nextLevel: 4 },
+ getNextUnlock() {
+ return this.nextUnlock;
+ },
+ remainingInvites: 3,
+ // remainingInvites: 0,
+ getRemainingInviteCount() {
+ return this.remainingInvites;
+ },
+ invites: [],
+ // invites: ["a", "b"],
+ getInvites() {
+ return this.invites;
+ },
+};
+*/
+
const InternetStatus = Object.freeze({
Unknown: 0,
Online: 1,
@@ -678,15 +732,23 @@ const gBridgeGrid = {
row.optionsButton.focus();
});
- row.menu
- .querySelector(".tor-bridges-options-qr-one-menu-item")
- .addEventListener("click", () => {
- const bridgeLine = row.bridgeLine;
- if (!bridgeLine) {
- return;
- }
- showBridgeQr(bridgeLine);
- });
+ const qrItem = row.menu.querySelector(
+ ".tor-bridges-options-qr-one-menu-item"
+ );
+ row.menu.addEventListener("showing", () => {
+ qrItem.hidden = !(
+ this._bridgeSource === TorBridgeSource.UserProvided ||
+ this._bridgeSource === TorBridgeSource.BridgeDB
+ );
+ });
+
+ qrItem.addEventListener("click", () => {
+ const bridgeLine = row.bridgeLine;
+ if (!bridgeLine) {
+ return;
+ }
+ showBridgeQr(bridgeLine);
+ });
row.menu
.querySelector(".tor-bridges-options-copy-one-menu-item")
.addEventListener("click", () => {
@@ -734,7 +796,11 @@ const gBridgeGrid = {
*
* @type {string[]}
*/
- _supportedSources: [TorBridgeSource.BridgeDB, TorBridgeSource.UserProvided],
+ _supportedSources: [
+ TorBridgeSource.BridgeDB,
+ TorBridgeSource.UserProvided,
+ TorBridgeSource.Lox,
+ ],
/**
* Update the grid to show the latest bridge strings.
@@ -1169,6 +1235,335 @@ const gBuiltinBridgesArea = {
},
};
+/**
+ * Controls the bridge pass area.
+ */
+const gLoxStatus = {
+ /**
+ * The status area.
+ *
+ * @type {Element?}
+ */
+ _area: null,
+ /**
+ * The area for showing the next unlock and invites.
+ *
+ * @type {Element?}
+ */
+ _detailsArea: null,
+ /**
+ * The day counter for the next unlock.
+ *
+ * @type {Element?}
+ */
+ _nextUnlockCounterEl: null,
+ /**
+ * Shows the number of remaining invites.
+ *
+ * @type {Element?}
+ */
+ _remainingInvitesEl: null,
+ /**
+ * The button to show the invites.
+ *
+ * @type {Element?}
+ */
+ _invitesButton: null,
+ /**
+ * The alert for new unlocks.
+ *
+ * @type {Element?}
+ */
+ _unlockAlert: null,
+ /**
+ * The alert title.
+ *
+ * @type {Element?}
+ */
+ _unlockAlertTitle: null,
+ /**
+ * The alert invites item.
+ *
+ * @type {Element?}
+ */
+ _unlockAlertInvitesItem: null,
+ /**
+ * Button for the user to dismiss the alert.
+ *
+ * @type {Element?}
+ */
+ _unlockAlertButton: null,
+
+ /**
+ * Initialize the bridge pass area.
+ */
+ init() {
+ this._area = document.getElementById("tor-bridges-lox-status");
+ this._detailsArea = document.getElementById("tor-bridges-lox-details");
+ this._nextUnlockCounterEl = document.getElementById(
+ "tor-bridges-lox-next-unlock-counter"
+ );
+ this._remainingInvitesEl = document.getElementById(
+ "tor-bridges-lox-remaining-invites"
+ );
+ this._invitesButton = document.getElementById(
+ "tor-bridges-lox-show-invites-button"
+ );
+ this._unlockAlert = document.getElementById("tor-bridges-lox-unlock-alert");
+ this._unlockAlertTitle = document.getElementById(
+ "tor-bridge-unlock-alert-title"
+ );
+ this._unlockAlertInviteItem = document.getElementById(
+ "tor-bridges-lox-unlock-alert-invites"
+ );
+ this._unlockAlertButton = document.getElementById(
+ "tor-bridges-lox-unlock-alert-button"
+ );
+
+ this._invitesButton.addEventListener("click", () => {
+ // TODO: Show invites.
+ });
+ this._unlockAlertButton.addEventListener("click", () => {
+ // TODO: Have a way to ensure that the cleared event data matches the
+ // current _loxId
+ Lox.clearEventData();
+ // TODO: Listen for events from Lox, rather than call _updateUnlocks
+ // directly.
+ this._updateUnlocks();
+ });
+
+ Services.obs.addObserver(this, TorSettingsTopics.SettingsChanged);
+ // TODO: Listen for new events from Lox, when it is supported.
+
+ // NOTE: Before initializedPromise completes, this area is hidden.
+ TorSettings.initializedPromise.then(() => {
+ this._updateLoxId();
+ });
+ },
+
+ /**
+ * Uninitialize the built-in bridges area.
+ */
+ uninit() {
+ Services.obs.removeObserver(this, TorSettingsTopics.SettingsChanged);
+ },
+
+ observe(subject, topic, data) {
+ switch (topic) {
+ case TorSettingsTopics.SettingsChanged:
+ const { changes } = subject.wrappedJSObject;
+ if (
+ changes.includes("bridges.source") ||
+ changes.includes("bridges.lox_id")
+ ) {
+ this._updateLoxId();
+ }
+ break;
+ }
+ },
+
+ /**
+ * The Lox id currently shown. Empty if deactivated, and null if
+ * uninitialized.
+ *
+ * @type {string?}
+ */
+ _loxId: null,
+
+ /**
+ * Update the shown bridge pass.
+ */
+ async _updateLoxId() {
+ let loxId =
+ TorSettings.bridges.source === TorBridgeSource.Lox
+ ? TorSettings.bridges.lox_id
+ : "";
+ if (loxId !== this._loxId) {
+ this._loxId = loxId;
+ this._updateUnlocks();
+ this._updateInvites();
+ }
+ },
+
+ /**
+ * Update the display of the current or next unlock.
+ */
+ async _updateUnlocks() {
+ // Cache the loxId before we await.
+ const loxId = this._loxId;
+
+ if (!loxId) {
+ // NOTE: This area should already be hidden by the change in Lox source,
+ // but we clean up for the next non-empty id.
+ this._area.classList.remove("show-unlock-alert");
+ this._area.classList.remove("show-next-unlock");
+ return;
+ }
+
+ let pendingEvents;
+ let nextUnlock;
+ let numInvites;
+ // Fetch the latest events or details about the next unlock.
+ try {
+ nextUnlock = await Lox.getNextUnlock();
+ pendingEvents = Lox.getEventData();
+ numInvites = Lox.getRemainingInviteCount();
+ } catch (e) {
+ console.error("Failed get get lox updates", e);
+ return;
+ }
+
+ if (loxId !== this._loxId) {
+ // Replaced during await.
+ return;
+ }
+
+ // Grab focus state before changing visibility.
+ const alertHadFocus = this._unlockAlert.contains(document.activeElement);
+ const detailsHadFocus = this._detailsArea.contains(document.activeElement);
+
+ const showAlert = !!pendingEvents.length;
+ this._area.classList.toggle("show-unlock-alert", showAlert);
+ this._area.classList.toggle("show-next-unlock", !showAlert);
+
+ if (showAlert) {
+ // At level 0 and level 1, we do not have any invites.
+ // If the user starts and ends on level 0 or 1, then overall they would
+ // have had no change in their invites. So we do not want to show their
+ // latest updates.
+ // NOTE: If the user starts at level > 1 and ends with level 1 (levelling
+ // down to level 0 should not be possible), then we *do* want to show the
+ // user that they now have "0" invites.
+ // NOTE: pendingEvents are time-ordered, with the most recent event
+ // *last*.
+ const firstEvent = pendingEvents[0];
+ // NOTE: We cannot get a blockage event when the user starts at level 1 or
+ // 0.
+ const startingAtLowLevel =
+ firstEvent.type === "levelup" && firstEvent.newLevel <= 2;
+ const lastEvent = pendingEvents[pendingEvents.length - 1];
+ const endingAtLowLevel = lastEvent.newLevel <= 1;
+
+ const showInvites = !(startingAtLowLevel && endingAtLowLevel);
+
+ let blockage = false;
+ let levelUp = false;
+ let bridgeGain = false;
+ // Go through events, in the order that they occurred.
+ for (const loxEvent of pendingEvents) {
+ if (loxEvent.type === "levelup") {
+ levelUp = true;
+ if (loxEvent.newLevel === 1) {
+ // Gain 2 bridges from level 0 to 1.
+ bridgeGain = true;
+ }
+ } else {
+ blockage = true;
+ }
+ }
+ let alertTitleId;
+ if (levelUp && !blockage) {
+ alertTitleId = "tor-bridges-lox-upgrade";
+ } else {
+ // Show as blocked bridges replaced.
+ // Even if we have a mixture of level ups as well.
+ alertTitleId = "tor-bridges-lox-blocked";
+ }
+ document.l10n.setAttributes(this._unlockAlertTitle, alertTitleId);
+ document.l10n.setAttributes(
+ this._unlockAlertInviteItem,
+ "tor-bridges-lox-new-invites",
+ { numInvites }
+ );
+ this._unlockAlert.classList.toggle(
+ "lox-unlock-upgrade",
+ levelUp && !blockage
+ );
+ this._unlockAlert.classList.toggle("lox-unlock-new-bridges", blockage);
+ this._unlockAlert.classList.toggle("lox-unlock-gain-bridges", bridgeGain);
+ this._unlockAlert.classList.toggle("lox-unlock-invites", showInvites);
+ } else {
+ // Show next unlock.
+ // Number of days until the next unlock, rounded up.
+ const numDays = Math.max(
+ 1,
+ Math.ceil(
+ (new Date(nextUnlock.date).getTime() - Date.now()) /
+ (24 * 60 * 60 * 1000)
+ )
+ );
+ document.l10n.setAttributes(
+ this._nextUnlockCounterEl,
+ "tor-bridges-lox-days-until-unlock",
+ { numDays }
+ );
+
+ // Gain 2 bridges from level 0 to 1. After that gain invites.
+ const bridgeGain = nextUnlock.nextLevel === 1;
+ const firstInvites = nextUnlock.nextLevel === 2;
+ const moreInvites = nextUnlock.nextLevel > 2;
+
+ this._detailsArea.classList.toggle("lox-next-gain-bridges", bridgeGain);
+ this._detailsArea.classList.toggle(
+ "lox-next-first-invites",
+ firstInvites
+ );
+ this._detailsArea.classList.toggle("lox-next-more-invites", moreInvites);
+ }
+
+ if (alertHadFocus && !showAlert) {
+ // Has become hidden.
+ this._nextUnlockCounterEl.focus();
+ } else if (detailsHadFocus && showAlert) {
+ this._unlockAlertButton.focus();
+ }
+ },
+
+ /**
+ * Update the invites area.
+ */
+ _updateInvites() {
+ if (!this._loxId) {
+ return;
+ }
+
+ let remainingInvites;
+ let existingInvites;
+ // Fetch the latest events or details about the next unlock.
+ try {
+ remainingInvites = Lox.getRemainingInviteCount();
+ existingInvites = Lox.getInvites().length;
+ } catch (e) {
+ console.error("Failed get get remaining invites", e);
+ return;
+ }
+
+ const hasInvites = !!existingInvites || !!remainingInvites;
+
+ if (!hasInvites) {
+ if (
+ this._remainingInvitesEl.contains(document.activeElement) ||
+ this._invitesButton.contains(document.activeElement)
+ ) {
+ // About to loose focus.
+ // Unexpected for the lox level to loose all invites.
+ // Move to the top of the details area, which should be visible if we
+ // just had focus.
+ this._nextUnlockCounterEl.focus();
+ }
+ }
+ // Hide the invite elements if we have no historic invites or a way of
+ // creating new ones.
+ this._detailsArea.classList.toggle("lox-has-invites", hasInvites);
+
+ document.l10n.setAttributes(
+ this._remainingInvitesEl,
+ "tor-bridges-lox-remaining-invites",
+ { numInvites: remainingInvites }
+ );
+ },
+};
+
/**
* Controls the bridge settings.
*/
@@ -1295,6 +1690,7 @@ const gBridgeSettings = {
gBridgeGrid.init();
gBuiltinBridgesArea.init();
+ gLoxStatus.init();
this._initBridgesMenu();
this._initShareArea();
@@ -1315,6 +1711,7 @@ const gBridgeSettings = {
uninit() {
gBridgeGrid.uninit();
gBuiltinBridgesArea.uninit();
+ gLoxStatus.uninit();
Services.obs.removeObserver(this, TorSettingsTopics.SettingsChanged);
},
@@ -1387,6 +1784,10 @@ const gBridgeSettings = {
"source-requested",
bridgeSource === TorBridgeSource.BridgeDB
);
+ this._bridgesEl.classList.toggle(
+ "source-lox",
+ bridgeSource === TorBridgeSource.Lox
+ );
// Force the menu to close whenever the source changes.
// NOTE: If the menu had focus then hadFocus will be true, and focus will be
@@ -1615,7 +2016,10 @@ const gBridgeSettings = {
this._bridgesMenu.addEventListener("showing", () => {
const canCopy = this._bridgeSource !== TorBridgeSource.BuiltIn;
- qrItem.hidden = !this._canQRBridges || !canCopy;
+ const canShare =
+ this._bridgeSource === TorBridgeSource.UserProvided ||
+ this._bridgeSource === TorBridgeSource.BridgeDB;
+ qrItem.hidden = !canShare || !this._canQRBridges;
copyItem.hidden = !canCopy;
editItem.hidden = this._bridgeSource !== TorBridgeSource.UserProvided;
});
@@ -1763,13 +2167,19 @@ const gBridgeSettings = {
"chrome://browser/content/torpreferences/provideBridgeDialog.xhtml",
{ mode },
result => {
- if (!result.bridges?.length) {
+ const loxId = result.loxId;
+ if (!loxId && !result.addresses?.length) {
return null;
}
return setTorSettings(() => {
TorSettings.bridges.enabled = true;
- TorSettings.bridges.source = TorBridgeSource.UserProvided;
- TorSettings.bridges.bridge_strings = result.bridges;
+ if (loxId) {
+ TorSettings.bridges.source = TorBridgeSource.Lox;
+ TorSettings.bridges.lox_id = loxId;
+ } else {
+ TorSettings.bridges.source = TorBridgeSource.UserProvided;
+ TorSettings.bridges.bridge_strings = result.addresses;
+ }
});
}
);
=====================================
browser/components/torpreferences/content/connectionPane.xhtml
=====================================
@@ -172,6 +172,10 @@
id="tor-bridges-requested-label"
data-l10n-id="tor-bridges-source-requested"
></html:span>
+ <html:span id="tor-bridges-lox-label">
+ <html:img id="tor-bridges-lox-label-icon" alt="" />
+ <html:span data-l10n-id="tor-bridges-source-lox"></html:span>
+ </html:span>
<html:button
id="tor-bridges-all-options-button"
class="tor-bridges-options-button"
@@ -275,7 +279,7 @@
</html:span>
</html:div>
</html:template>
- <html:div id="tor-bridges-share">
+ <html:div id="tor-bridges-share" class="tor-bridges-details-box">
<html:h3
id="tor-bridges-share-heading"
data-l10n-id="tor-bridges-share-heading"
@@ -293,6 +297,77 @@
data-l10n-id="tor-bridges-qr-addresses-button"
></html:button>
</html:div>
+ <html:div id="tor-bridges-lox-status">
+ <html:div data-l10n-id="tor-bridges-lox-description"></html:div>
+ <html:div
+ id="tor-bridges-lox-details"
+ class="tor-bridges-details-box tor-bridges-lox-box"
+ >
+ <html:img alt="" class="tor-bridges-lox-image-inner" />
+ <html:img alt="" class="tor-bridges-lox-image-outer" />
+ <html:div
+ id="tor-bridges-lox-next-unlock-counter"
+ class="tor-bridges-lox-intro"
+ tabindex="-1"
+ ></html:div>
+ <html:ul class="tor-bridges-lox-list">
+ <html:li
+ id="tor-bridges-lox-next-unlock-gain-bridges"
+ class="tor-bridges-lox-list-item tor-bridges-lox-list-item-bridge"
+ data-l10n-id="tor-bridges-lox-unlock-two-bridges"
+ ></html:li>
+ <html:li
+ id="tor-bridges-lox-next-unlock-first-invites"
+ class="tor-bridges-lox-list-item tor-bridges-lox-list-item-invite"
+ data-l10n-id="tor-bridges-lox-unlock-first-invites"
+ ></html:li>
+ <html:li
+ id="tor-bridges-lox-next-unlock-more-invites"
+ class="tor-bridges-lox-list-item tor-bridges-lox-list-item-invite"
+ data-l10n-id="tor-bridges-lox-unlock-more-invites"
+ ></html:li>
+ </html:ul>
+ <html:div id="tor-bridges-lox-remaining-invites"></html:div>
+ <html:button
+ id="tor-bridges-lox-show-invites-button"
+ class="tor-bridges-lox-button"
+ data-l10n-id="tor-bridges-lox-show-invites-button"
+ ></html:button>
+ </html:div>
+ <html:div
+ id="tor-bridges-lox-unlock-alert"
+ role="alert"
+ class="tor-bridges-details-box tor-bridges-lox-box"
+ >
+ <html:img alt="" class="tor-bridges-lox-image-inner" />
+ <html:img alt="" class="tor-bridges-lox-image-outer" />
+ <html:div
+ id="tor-bridge-unlock-alert-title"
+ class="tor-bridges-lox-intro"
+ ></html:div>
+ <html:ul class="tor-bridges-lox-list">
+ <html:li
+ id="tor-bridges-lox-unlock-alert-gain-bridges"
+ class="tor-bridges-lox-list-item tor-bridges-lox-list-item-bridge"
+ data-l10n-id="tor-bridges-lox-gained-two-bridges"
+ ></html:li>
+ <html:li
+ id="tor-bridges-lox-unlock-alert-new-bridges"
+ class="tor-bridges-lox-list-item tor-bridges-lox-list-item-bridge"
+ data-l10n-id="tor-bridges-lox-new-bridges"
+ ></html:li>
+ <html:li
+ id="tor-bridges-lox-unlock-alert-invites"
+ class="tor-bridges-lox-list-item tor-bridges-lox-list-item-invite"
+ ></html:li>
+ </html:ul>
+ <html:button
+ id="tor-bridges-lox-unlock-alert-button"
+ class="tor-bridges-lox-button"
+ data-l10n-id="tor-bridges-lox-got-it-button"
+ ></html:button>
+ </html:div>
+ </html:div>
</html:div>
<html:h2 id="tor-bridges-change-heading"></html:h2>
<hbox align="center">
=====================================
browser/components/torpreferences/content/lox-bridge-icon.svg
=====================================
@@ -0,0 +1,6 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="0.5" y="0.5" width="17" height="17" rx="1.5" stroke="context-stroke"/>
+<path d="M14.625 11.625C14.625 8.5184 12.1066 6 9 6C5.8934 6 3.375 8.5184 3.375 11.625V12.5596H4.25391V11.625C4.25391 9.0038 6.3788 6.87891 9 6.87891C11.6212 6.87891 13.7461 9.0038 13.7461 11.625V12.5596H14.625V11.625Z" fill="context-fill"/>
+<path d="M12.9375 11.625C12.9375 9.45037 11.1746 7.6875 9 7.6875C6.82537 7.6875 5.0625 9.45037 5.0625 11.625L5.06242 12.5596H5.94132L5.9414 11.625C5.9414 9.93578 7.31078 8.5664 9 8.5664C10.6892 8.5664 12.0586 9.93578 12.0586 11.625L12.0587 12.5596H12.9376L12.9375 11.625Z" fill="context-fill"/>
+<path d="M9 9.375C10.2426 9.375 11.25 10.3824 11.25 11.625L11.2502 12.5596H10.3713L10.3711 11.625C10.3711 10.8678 9.75724 10.2539 9 10.2539C8.24277 10.2539 7.62891 10.8678 7.62891 11.625L7.62873 12.5596H6.74982V11.625C6.74982 10.3824 7.75736 9.375 9 9.375Z" fill="context-fill"/>
+</svg>
=====================================
browser/components/torpreferences/content/lox-bridge-pass.svg
=====================================
@@ -0,0 +1,6 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M0.825958 10.1991C0.191356 9.56445 0.191356 8.53556 0.825958 7.90095L7.89702 0.829887C8.53163 0.195285 9.56052 0.195285 10.1951 0.829887L11.3198 1.95455C11.5751 2.2099 11.6412 2.59873 11.4846 2.92409C11.0031 3.9241 12.0507 4.97168 13.0507 4.4902C13.376 4.33354 13.7649 4.39962 14.0202 4.65497L15.1449 5.77963C15.7795 6.41424 15.7795 7.44313 15.1449 8.07773L8.0738 15.1488C7.4392 15.7834 6.41031 15.7834 5.7757 15.1488L4.65104 14.0241C4.39569 13.7688 4.32961 13.38 4.48627 13.0546C4.96775 12.0546 3.92017 11.007 2.92016 11.4885C2.5948 11.6451 2.20597 11.5791 1.95062 11.3237L0.825958 10.1991ZM1.70984 8.78484C1.56339 8.93128 1.56339 9.16872 1.70984 9.31517L2.64555 10.2509C4.53493 9.58573 6.38902 11.4398 5.72388 13.3292L6.65959 14.2649C6.80603 14.4114 7.04347 14.4114 7.18992 14.2649L14.261 7.19385C14.4074 7.0474 14.4074 6.80996 14.261 6.66352L13.3253 5.7278C11.4359 6.39295 9.5818 4.53886 10.247 2.64948L9.31124 1.71377C9.16479 1.56732 8.92735 1.56732 8.78091 1.71377L1.70984 8.78484Z" fill="context-fill"/>
+ <path d="M8.87637 9.78539L9.76025 8.90151L10.6441 9.78539L9.76025 10.6693L8.87637 9.78539Z" fill="context-fill"/>
+ <path d="M7.1086 8.01763L7.99249 7.13374L8.87637 8.01763L7.99249 8.90151L7.1086 8.01763Z" fill="context-fill"/>
+ <path d="M5.34084 6.24986L6.22472 5.36598L7.1086 6.24986L6.22472 7.13374L5.34084 6.24986Z" fill="context-fill"/>
+</svg>
=====================================
browser/components/torpreferences/content/lox-complete-ring.svg
=====================================
@@ -0,0 +1,12 @@
+<svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="ring-blur" x="0" y="0" width="44" height="44" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+ <feColorMatrix in="SourceGraphic" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0"/>
+ <feGaussianBlur stdDeviation="2"/>
+ <feBlend mode="normal" in="SourceGraphic"/>
+ </filter>
+</defs>
+<g filter="url(#ring-blur)">
+<path d="M40 22C40 31.9411 31.9411 40 22 40C12.0589 40 4 31.9411 4 22C4 12.0589 12.0589 4 22 4C31.9411 4 40 12.0589 40 22ZM6.25 22C6.25 30.6985 13.3015 37.75 22 37.75C30.6985 37.75 37.75 30.6985 37.75 22C37.75 13.3015 30.6985 6.25 22 6.25C13.3015 6.25 6.25 13.3015 6.25 22Z" fill="context-fill"/>
+</g>
+</svg>
=====================================
browser/components/torpreferences/content/lox-invite-icon.svg
=====================================
@@ -0,0 +1,4 @@
+<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect x="0.5" y="0.5" width="17" height="17" rx="1.5" stroke="context-stroke"/>
+<path d="M9 9C8.45 9 7.97917 8.80417 7.5875 8.4125C7.19583 8.02083 7 7.55 7 7C7 6.45 7.19583 5.97917 7.5875 5.5875C7.97917 5.19583 8.45 5 9 5C9.55 5 10.0208 5.19583 10.4125 5.5875C10.8042 5.97917 11 6.45 11 7C11 7.55 10.8042 8.02083 10.4125 8.4125C10.0208 8.80417 9.55 9 9 9ZM5 12V11.6C5 11.3167 5.07292 11.0563 5.21875 10.8187C5.36458 10.5812 5.55833 10.4 5.8 10.275C6.31667 10.0167 6.84167 9.82292 7.375 9.69375C7.90833 9.56458 8.45 9.5 9 9.5C9.55 9.5 10.0917 9.56458 10.625 9.69375C11.1583 9.82292 11.6833 10.0167 12.2 10.275C12.4417 10.4 12.6354 10.5812 12.7812 10.8187C12.9271 11.0563 13 11.3167 13 11.6V12C13 12.275 12.9021 12.5104 12.7063 12.7063C12.5104 12.9021 12.275 13 12 13H6C5.725 13 5.48958 12.9021 5.29375 12.7063C5.09792 12.5104 5 12.275 5 12ZM6 12H12V11.6C12 11.5083 11.9771 11.425 11.9313 11.35C11.8854 11.275 11.825 11.2167 11.75 11.175C11.3 10.95 10.8458 10.7813 10.3875 10.6688C9.92917 10.5563 9.46667 10.5 9 10.5C8.53333 10.5 8.07083 10.5563 7.6125 10.6688C7.15417 10.7813 6.7 10.95 6.25 11.175C6.175 11.2167 6.11458 11.275 6.06875 11.35C6.02292 11.425 6 11.5083 6 11.6V12ZM9 8C9.275 8 9.51042 7.90208 9.70625 7.70625C9.90208 7.51042 10 7.275 10 7C10 6.725 9.90208 6.48958 9.70625 6.29375C9.51042 6.09792 9.275 6 9 6C8.725 6 8.48958 6.09792 8.29375 6.29375C8.09792 6.48958 8 6.725 8 7C8 7.275 8.09792 7.51042 8.29375 7.70625C8.48958 7.90208 8.725 8 9 8Z" fill="context-fill"/>
+</svg>
=====================================
browser/components/torpreferences/content/lox-progress-ring.svg
=====================================
@@ -0,0 +1,13 @@
+<svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
+<defs>
+ <filter id="ring-blur" x="0" y="0" width="44" height="44" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+ <feColorMatrix in="SourceGraphic" type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.5 0"/>
+ <feGaussianBlur stdDeviation="2"/>
+ <feBlend mode="normal" in="SourceGraphic"/>
+ </filter>
+</defs>
+<path d="M 40,22 C 40,31.9411 31.9411,40 22,40 12.05887,40 4,31.9411 4,22 4,12.0589 12.05887,4 22,4 31.9411,4 40,12.0589 40,22 Z M 6.25,22 c 0,8.6985 7.05152,15.75 15.75,15.75 8.6985,0 15.75,-7.0515 15.75,-15.75 C 37.75,13.3015 30.6985,6.25 22,6.25 13.30152,6.25 6.25,13.3015 6.25,22 Z" fill="context-stroke"/>
+<g filter="url(#ring-blur)">
+ <path d="m 22,5.125 c 0,-0.62132 0.5042,-1.12866 1.1243,-1.08986 3.0298,0.18958 5.963,1.14263 8.5256,2.77013 0.5245,0.3331 0.6342,1.03991 0.269,1.54257 C 31.5537,8.8505 30.852,8.95814 30.3246,8.62974 28.1505,7.27609 25.6786,6.47291 23.1241,6.29015 22.5044,6.24582 22,5.74632 22,5.125 Z" fill="context-fill"/>
+</g>
+</svg>
=====================================
browser/components/torpreferences/content/lox-success.svg
=====================================
@@ -0,0 +1,5 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+ <path d="M10 14C9.62059 14.0061 9.25109 13.8787 8.95594 13.6403C8.6608 13.4018 8.45874 13.0672 8.385 12.695L8.028 11.028C7.97202 10.7692 7.84264 10.5321 7.65536 10.345C7.46807 10.1579 7.23081 10.0287 6.972 9.973L5.305 9.616C4.524 9.447 4 8.798 4 8C4 7.202 4.524 6.553 5.305 6.385L6.972 6.028C7.23078 5.97185 7.46794 5.84243 7.65519 5.65519C7.84243 5.46794 7.97185 5.23078 8.028 4.972L8.386 3.305C8.553 2.524 9.202 2 10 2C10.798 2 11.447 2.524 11.615 3.305L11.972 4.972C12.086 5.5 12.5 5.914 13.028 6.027L14.695 6.384C15.476 6.553 16 7.202 16 8C16 8.798 15.476 9.447 14.695 9.615L13.028 9.972C12.769 10.028 12.5316 10.1575 12.3443 10.345C12.157 10.5324 12.0277 10.7699 11.972 11.029L11.614 12.695C11.5407 13.0672 11.3388 13.4019 11.0438 13.6404C10.7488 13.8789 10.3793 14.0062 10 14ZM10 3.25C9.902 3.25 9.669 3.28 9.608 3.566L9.25 5.234C9.14333 5.72828 8.89643 6.18132 8.53888 6.53888C8.18132 6.89643 7.72828 7.14333 7.234 7.25L5.567 7.607C5.281 7.669 5.25 7.902 5.25 8C5.25 8.098 5.281 8.331 5.567 8.393L7.234 8.75C7.72828 8.85667 8.18132 9.10357 8.53888 9.46112C8.89643 9.81868 9.14333 10.2717 9.25 10.766L9.608 12.434C9.669 12.72 9.902 12.75 10 12.75C10.098 12.75 10.331 12.72 10.392 12.434L10.75 10.767C10.8565 10.2725 11.1033 9.81928 11.4609 9.46154C11.8185 9.10379 12.2716 8.85674 12.766 8.75L14.433 8.393C14.719 8.331 14.75 8.098 14.75 8C14.75 7.902 14.719 7.669 14.433 7.607L12.766 7.25C12.2717 7.14333 11.8187 6.89643 11.4611 6.53888C11.1036 6.18132 10.8567 5.72828 10.75 5.234L10.392 3.566C10.331 3.28 10.098 3.25 10 3.25Z" fill="context-fill"/>
+ <path d="M2.44399 12.151L2.62599 11.302C2.71199 10.9 3.28599 10.9 3.37299 11.302L3.55499 12.151C3.57035 12.2229 3.60618 12.2888 3.65817 12.3408C3.71016 12.3928 3.77609 12.4286 3.84799 12.444L4.69699 12.626C5.09899 12.712 5.09899 13.286 4.69699 13.373L3.84799 13.555C3.77609 13.5704 3.71016 13.6062 3.65817 13.6582C3.60618 13.7102 3.57035 13.7761 3.55499 13.848L3.37299 14.697C3.28699 15.099 2.71299 15.099 2.62599 14.697L2.44399 13.848C2.42863 13.7761 2.39279 13.7102 2.3408 13.6582C2.28881 13.6062 2.22289 13.5704 2.15099 13.555L1.30199 13.373C0.899988 13.287 0.899988 12.713 1.30199 12.626L2.15099 12.444C2.22294 12.4288 2.28893 12.393 2.34094 12.341C2.39295 12.2889 2.42875 12.223 2.44399 12.151Z" fill="context-fill"/>
+ <path d="M2.44399 2.151L2.62599 1.302C2.71199 0.900004 3.28599 0.900004 3.37299 1.302L3.55499 2.151C3.57035 2.22291 3.60618 2.28883 3.65817 2.34082C3.71016 2.39281 3.77609 2.42864 3.84799 2.444L4.69699 2.626C5.09899 2.712 5.09899 3.286 4.69699 3.373L3.84899 3.556C3.77703 3.57125 3.71105 3.60704 3.65904 3.65905C3.60703 3.71106 3.57123 3.77705 3.55599 3.849L3.37299 4.698C3.28699 5.1 2.71299 5.1 2.62599 4.698L2.44399 3.849C2.42875 3.77705 2.39295 3.71106 2.34094 3.65905C2.28893 3.60704 2.22294 3.57125 2.15099 3.556L1.30199 3.373C0.899988 3.287 0.899988 2.713 1.30199 2.626L2.15099 2.444C2.22294 2.42876 2.28893 2.39296 2.34094 2.34095C2.39295 2.28894 2.42875 2.22296 2.44399 2.151Z" fill="context-fill"/>
+</svg>
=====================================
browser/components/torpreferences/content/provideBridgeDialog.js
=====================================
@@ -15,6 +15,46 @@ const { TorParsers } = ChromeUtils.importESModule(
"resource://gre/modules/TorParsers.sys.mjs"
);
+const { Lox, LoxErrors } = ChromeUtils.importESModule(
+ "resource://gre/modules/Lox.sys.mjs"
+);
+
+/*
+ * Fake Lox module:
+
+const LoxErrors = {
+ BadInvite: "BadInvite",
+ LoxServerUnreachable: "LoxServerUnreachable",
+ Other: "Other",
+};
+
+const Lox = {
+ failError: null,
+ // failError: LoxErrors.BadInvite,
+ // failError: LoxErrors.LoxServerUnreachable,
+ // failError: LoxErrors.Other,
+ redeemInvite(invite) {
+ return new Promise((res, rej) => {
+ setTimeout(() => {
+ if (this.failError) {
+ rej({ type: this.failError });
+ }
+ res("lox-id-000000");
+ }, 4000);
+ });
+ },
+ validateInvitation(invite) {
+ return invite.startsWith("lox-invite");
+ },
+ getBridges(id) {
+ return [
+ "0:0 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "0:1 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
+ ];
+ },
+};
+*/
+
const gProvideBridgeDialog = {
init() {
this._result = window.arguments[0];
@@ -36,10 +76,14 @@ const gProvideBridgeDialog = {
document.l10n.setAttributes(document.documentElement, titleId);
+ // TODO: Make conditional on Lox being enabled.
+ this._allowLoxInvite = mode !== "edit"; // && Lox.enabled
+
document.l10n.setAttributes(
document.getElementById("user-provide-bridge-textarea-label"),
- // TODO change string when we can also accept Lox share codes.
- "user-provide-bridge-dialog-textarea-addresses-label"
+ this._allowLoxInvite
+ ? "user-provide-bridge-dialog-textarea-addresses-or-invite-label"
+ : "user-provide-bridge-dialog-textarea-addresses-label"
);
this._dialog = document.getElementById("user-provide-bridge-dialog");
@@ -48,6 +92,9 @@ const gProvideBridgeDialog = {
this._errorEl = document.getElementById(
"user-provide-bridge-error-message"
);
+ this._connectingEl = document.getElementById(
+ "user-provide-bridge-connecting"
+ );
this._resultDescription = document.getElementById(
"user-provide-result-description"
);
@@ -68,8 +115,9 @@ const gProvideBridgeDialog = {
// Set placeholder if not editing.
document.l10n.setAttributes(
this._textarea,
- // TODO: change string when we can also accept Lox share codes.
- "user-provide-bridge-dialog-textarea-addresses"
+ this._allowLoxInvite
+ ? "user-provide-bridge-dialog-textarea-addresses-or-invite"
+ : "user-provide-bridge-dialog-textarea-addresses"
);
}
@@ -98,7 +146,17 @@ const gProvideBridgeDialog = {
this._page = page;
this._dialog.classList.toggle("show-entry-page", page === "entry");
this._dialog.classList.toggle("show-result-page", page === "result");
- if (page === "entry") {
+ this.takeFocus();
+ this.updateResult();
+ this.updateAcceptDisabled();
+ this.onAcceptStateChange();
+ },
+
+ /**
+ * Reset focus position in the dialog.
+ */
+ takeFocus() {
+ if (this._page === "entry") {
this._textarea.focus();
} else {
// Move focus to the <xul:window> element.
@@ -106,9 +164,6 @@ const gProvideBridgeDialog = {
// button (with now different text).
document.documentElement.focus();
}
-
- this.updateAcceptDisabled();
- this.onAcceptStateChange();
},
/**
@@ -149,7 +204,36 @@ const gProvideBridgeDialog = {
*/
updateAcceptDisabled() {
this._acceptButton.disabled =
- this._page === "entry" && validateBridgeLines(this._textarea.value).empty;
+ this._page === "entry" && (this.isEmpty() || this._loxLoading);
+ },
+
+ /**
+ * The lox loading state.
+ *
+ * @type {boolean}
+ */
+ _loxLoading: false,
+
+ /**
+ * Set the lox loading state. I.e. whether we are connecting to the lox
+ * server.
+ *
+ * @param {boolean} isLoading - Whether we are loading or not.
+ */
+ setLoxLoading(isLoading) {
+ this._loxLoading = isLoading;
+ this._textarea.readOnly = isLoading;
+ this._connectingEl.classList.toggle("show-connecting", isLoading);
+ if (
+ isLoading &&
+ this._acceptButton.contains(
+ this._acceptButton.getRootNode().activeElement
+ )
+ ) {
+ // Move focus to the alert before we disable the button.
+ this._connectingEl.focus();
+ }
+ this.updateAcceptDisabled();
},
/**
@@ -166,23 +250,63 @@ const gProvideBridgeDialog = {
// Prevent closing the dialog.
event.preventDefault();
- const bridges = this.checkValue();
- if (!bridges.length) {
+ if (this._loxLoading) {
+ // User can still click Next whilst loading.
+ console.error("Already have a pending lox invite");
+ return;
+ }
+
+ // Clear the result from any previous attempt.
+ delete this._result.loxId;
+ delete this._result.addresses;
+ // Clear any previous error.
+ this.updateError(null);
+
+ const value = this.checkValue();
+ if (!value) {
+ // Not valid.
+ return;
+ }
+ if (value.loxInvite) {
+ this.setLoxLoading(true);
+ Lox.redeemInvite(value.loxInvite)
+ .finally(() => {
+ // Set set the loading to false before setting the errors.
+ this.setLoxLoading(false);
+ })
+ .then(
+ loxId => {
+ this._result.loxId = loxId;
+ this.setPage("result");
+ },
+ loxError => {
+ console.error("Redeeming failed", loxError);
+ switch (loxError.type) {
+ case LoxErrors.BadInvite:
+ // TODO: distinguish between a bad invite, an invite that has
+ // expired, and an invite that has already been redeemed.
+ this.updateError({ type: "bad-invite" });
+ break;
+ case LoxErrors.LoxServerUnreachable:
+ this.updateError({ type: "no-server" });
+ break;
+ default:
+ this.updateError({ type: "invite-error" });
+ break;
+ }
+ }
+ );
+ return;
+ }
+
+ if (!value.addresses?.length) {
// Not valid
return;
}
- this._result.bridges = bridges;
- this.updateResult();
+ this._result.addresses = value.addresses;
this.setPage("result");
},
- /**
- * The current timeout for updating the error.
- *
- * @type {integer?}
- */
- _updateErrorTimeout: null,
-
/**
* Update the displayed error.
*
@@ -191,14 +315,13 @@ const gProvideBridgeDialog = {
*/
updateError(error) {
// First clear the existing error.
- if (this._updateErrorTimeout !== null) {
- clearTimeout(this._updateErrorTimeout);
- }
- this._updateErrorTimeout = null;
this._errorEl.removeAttribute("data-l10n-id");
this._errorEl.textContent = "";
if (error) {
this._textarea.setAttribute("aria-invalid", "true");
+ // Move focus back to the text area, likely away from the Next button or
+ // the "Connecting..." alert.
+ this._textarea.focus();
} else {
this._textarea.removeAttribute("aria-invalid");
}
@@ -216,54 +339,122 @@ const gProvideBridgeDialog = {
errorId = "user-provide-bridge-dialog-address-error";
errorArgs = { line: error.line };
break;
+ case "multiple-invites":
+ errorId = "user-provide-bridge-dialog-multiple-invites-error";
+ break;
+ case "mixed":
+ errorId = "user-provide-bridge-dialog-mixed-error";
+ break;
+ case "not-allowed-invite":
+ errorId = "user-provide-bridge-dialog-invite-not-allowed-error";
+ break;
+ case "bad-invite":
+ errorId = "user-provide-bridge-dialog-bad-invite-error";
+ break;
+ case "no-server":
+ errorId = "user-provide-bridge-dialog-no-server-error";
+ break;
+ case "invite-error":
+ // Generic invite error.
+ errorId = "user-provide-bridge-dialog-generic-invite-error";
+ break;
}
- // Wait a small amount of time to actually set the textContent. Otherwise
- // the screen reader (tested with Orca) may not pick up on the change in
- // text.
- this._updateErrorTimeout = setTimeout(() => {
- document.l10n.setAttributes(this._errorEl, errorId, errorArgs);
- }, 500);
+ document.l10n.setAttributes(this._errorEl, errorId, errorArgs);
+ },
+
+ /**
+ * The condition for the value to be empty.
+ *
+ * @type {RegExp}
+ */
+ _emptyRegex: /^\s*$/,
+ /**
+ * Whether the input is considered empty.
+ *
+ * @returns {boolean} true if it is considered empty.
+ */
+ isEmpty() {
+ return this._emptyRegex.test(this._textarea.value);
},
/**
* Check the current value in the textarea.
*
- * @returns {string[]} - The bridge addresses, if the entry is valid.
+ * @returns {object?} - The bridge addresses, or lox invite, or null if no
+ * valid value.
*/
checkValue() {
- let bridges = [];
- let error = null;
- const validation = validateBridgeLines(this._textarea.value);
- if (!validation.empty) {
+ if (this.isEmpty()) {
// If empty, we just disable the button, rather than show an error.
- if (validation.errorLines.length) {
- // Report first error.
- error = {
- type: "invalid-address",
- line: validation.errorLines[0],
- };
- } else {
- bridges = validation.validBridges;
+ this.updateError(null);
+ return null;
+ }
+
+ let loxInvite = null;
+ for (let line of this._textarea.value.split(/\r?\n/)) {
+ line = line.trim();
+ if (!line) {
+ continue;
+ }
+ // TODO: Once we have a Lox invite encoding, distinguish between a valid
+ // invite and something that looks like it should be an invite.
+ const isLoxInvite = Lox.validateInvitation(line);
+ if (isLoxInvite) {
+ if (!this._allowLoxInvite) {
+ this.updateError({ type: "not-allowed-invite" });
+ return null;
+ }
+ if (loxInvite) {
+ this.updateError({ type: "multiple-invites" });
+ return null;
+ }
+ loxInvite = line;
+ } else if (loxInvite) {
+ this.updateError({ type: "mixed" });
+ return null;
}
}
- this.updateError(error);
- return bridges;
+
+ if (loxInvite) {
+ return { loxInvite };
+ }
+
+ const validation = validateBridgeLines(this._textarea.value);
+ if (validation.errorLines.length) {
+ // Report first error.
+ this.updateError({
+ type: "invalid-address",
+ line: validation.errorLines[0],
+ });
+ return null;
+ }
+
+ return { addresses: validation.validBridges };
},
/**
* Update the shown result on the last page.
*/
updateResult() {
+ if (this._page !== "result") {
+ return;
+ }
+
+ const loxId = this._result.loxId;
+
document.l10n.setAttributes(
this._resultDescription,
- // TODO: Use a different id when added through Lox invite.
- "user-provide-bridge-dialog-result-addresses"
+ loxId
+ ? "user-provide-bridge-dialog-result-invite"
+ : "user-provide-bridge-dialog-result-addresses"
);
this._bridgeGrid.replaceChildren();
- for (const bridgeLine of this._result.bridges) {
+ const bridgeResult = loxId ? Lox.getBridges(loxId) : this._result.addresses;
+
+ for (const bridgeLine of bridgeResult) {
let details;
try {
details = TorParsers.parseBridgeLine(bridgeLine);
@@ -305,6 +496,11 @@ const gProvideBridgeDialog = {
},
};
+document.subDialogSetDefaultFocus = () => {
+ // Set the focus to the text area on load.
+ gProvideBridgeDialog.takeFocus();
+};
+
window.addEventListener(
"DOMContentLoaded",
() => {
=====================================
browser/components/torpreferences/content/provideBridgeDialog.xhtml
=====================================
@@ -48,8 +48,15 @@
<html:div id="user-provide-bridge-message-area">
<html:span
id="user-provide-bridge-error-message"
+ role="alert"
aria-live="assertive"
></html:span>
+ <html:span
+ id="user-provide-bridge-connecting"
+ role="alert"
+ tabindex="0"
+ data-l10n-id="user-provide-bridge-dialog-connecting"
+ ></html:span>
</html:div>
</html:div>
<html:div id="user-provide-bridge-result-page">
=====================================
browser/components/torpreferences/content/torPreferences.css
=====================================
@@ -161,6 +161,10 @@
display: none;
}
+#tor-bridges-current:not(.source-lox) #tor-bridges-lox-label {
+ display: none;
+}
+
#tor-bridges-current:not(
.source-user,
.source-requested
@@ -168,6 +172,10 @@
display: none;
}
+#tor-bridges-current:not(.source-lox) #tor-bridges-lox-status {
+ display: none;
+}
+
#tor-bridges-none,
#tor-bridges-current {
margin-inline: 0;
@@ -214,6 +222,24 @@
flex: 0 0 auto;
}
+#tor-bridges-lox-label {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+#tor-bridges-lox-label > * {
+ flex: 0 0 auto;
+}
+
+#tor-bridges-lox-label-icon {
+ content: url("chrome://browser/content/torpreferences/lox-bridge-pass.svg");
+ width: 16px;
+ height: 16px;
+ -moz-context-properties: fill;
+ fill: var(--in-content-icon-color);
+}
+
#tor-bridges-current-heading {
margin: 0;
margin-inline-end: 2em;
@@ -397,11 +423,14 @@
clip-path: inset(50%);
}
-#tor-bridges-share {
+.tor-bridges-details-box {
margin-block-start: 24px;
border-radius: 4px;
border: 1px solid var(--in-content-border-color);
padding: 16px;
+}
+
+#tor-bridges-share {
display: grid;
grid-template:
"heading heading heading" min-content
@@ -452,6 +481,169 @@
fill: currentColor;
}
+#tor-bridges-lox-status {
+ margin-block-start: 8px;
+}
+
+#tor-bridges-lox-status:not(.show-next-unlock) #tor-bridges-lox-details {
+ display: none;
+}
+
+#tor-bridges-lox-status:not(.show-unlock-alert) #tor-bridges-lox-unlock-alert {
+ display: none;
+}
+
+.tor-bridges-lox-box {
+ display: grid;
+ grid-template:
+ "image intro intro" min-content
+ ". list list" auto
+ ". invites button" min-content
+ / min-content 1fr max-content;
+ align-items: start;
+ gap: 0 8px;
+}
+
+.tor-bridges-lox-image-outer {
+ grid-area: image;
+ /* The ring is 36px by 36px, but has 4px of padding for a Gaussian blur. */
+ width: 44px;
+ height: 44px;
+ margin: -4px;
+ align-self: center;
+ justify-self: center;
+ /* fill is the progress, stroke is the empty ring. */
+ -moz-context-properties: fill, stroke;
+ fill: var(--in-content-success-icon-color);
+ stroke: var(--in-content-border-color);
+ content: url("chrome://browser/content/torpreferences/lox-progress-ring.svg");
+}
+
+#tor-bridges-lox-unlock-alert.lox-unlock-upgrade .tor-bridges-lox-image-outer {
+ content: url("chrome://browser/content/torpreferences/lox-complete-ring.svg");
+}
+
+.tor-bridges-lox-image-inner {
+ grid-area: image;
+ /* Extra 4px space for gaussian blur. */
+ width: 16px;
+ height: 16px;
+ align-self: center;
+ justify-self: center;
+ -moz-context-properties: fill;
+ fill: var(--in-content-icon-color);
+}
+
+#tor-bridges-lox-details .tor-bridges-lox-image-inner {
+ content: url("chrome://browser/content/torpreferences/lox-bridge-pass.svg");
+}
+
+#tor-bridges-lox-unlock-alert .tor-bridges-lox-image-inner {
+ content: url("chrome://browser/content/torpreferences/bridge.svg");
+}
+
+#tor-bridges-lox-unlock-alert.lox-unlock-upgrade .tor-bridges-lox-image-inner {
+ content: url("chrome://browser/content/torpreferences/lox-success.svg");
+}
+
+.tor-bridges-lox-intro {
+ grid-area: intro;
+ font-weight: 700;
+ align-self: center;
+}
+
+.tor-bridges-lox-list {
+ grid-area: list;
+ margin: 0;
+ padding: 0;
+ display: grid;
+ /* Align the icons, as if list markers. */
+ grid-template-columns: max-content 1fr;
+ align-items: start;
+}
+
+.tor-bridges-lox-list-item {
+ display: contents;
+}
+
+.tor-bridges-lox-list-item::before {
+ /* We use ::before rather than list-style-image to have more control. */
+ display: block;
+ box-sizing: content-box;
+ width: 18px;
+ height: 18px;
+ margin-inline: 4px 6px;
+ /* We want the icons to be center-aligned relative to the *first* line. */
+ /* TODO: After firefox 120, can use line-height unit "lh" to do proper
+ * center-alignment: calc((1lh - 18px) / 2)
+ * For now, we use 3.4ex as an approximation for 1lh */
+ margin-block-start: calc((3.4ex - 18px) / 2);
+ /* fill is the icon color, stroke is the border color. */
+ -moz-context-properties: fill, stroke;
+ fill: var(--in-content-icon-color);
+}
+
+.tor-bridges-lox-list-item-bridge::before {
+ content: url("chrome://browser/content/torpreferences/lox-bridge-icon.svg");
+}
+
+.tor-bridges-lox-list-item-invite::before {
+ content: url("chrome://browser/content/torpreferences/lox-invite-icon.svg");
+}
+
+#tor-bridges-lox-details .tor-bridges-lox-list-item::before {
+ stroke: var(--in-content-border-color);
+}
+
+#tor-bridges-lox-unlock-alert .tor-bridges-lox-list-item::before {
+ stroke: var(--in-content-success-icon-color);
+}
+
+#tor-bridges-lox-details:not(.lox-next-gain-bridges) #tor-bridges-lox-next-unlock-gain-bridges {
+ display: none;
+}
+
+#tor-bridges-lox-details:not(.lox-next-first-invites) #tor-bridges-lox-next-unlock-first-invites {
+ display: none;
+}
+
+#tor-bridges-lox-details:not(.lox-next-more-invites) #tor-bridges-lox-next-unlock-more-invites {
+ display: none;
+}
+
+
+#tor-bridges-lox-unlock-alert:not(.lox-unlock-gain-bridges) #tor-bridges-lox-unlock-alert-gain-bridges {
+ display: none;
+}
+
+#tor-bridges-lox-unlock-alert:not(.lox-unlock-new-bridges) #tor-bridges-lox-unlock-alert-new-bridges {
+ display: none;
+}
+
+#tor-bridges-lox-unlock-alert:not(.lox-unlock-invites) #tor-bridges-lox-unlock-alert-invites {
+ display: none;
+}
+
+#tor-bridges-lox-remaining-invites {
+ grid-area: invites;
+ justify-self: end;
+ align-self: center;
+}
+
+#tor-bridges-lox-details:not(.lox-has-invites) :is(
+ #tor-bridges-lox-remaining-invites,
+ #tor-bridges-lox-show-invites-button
+) {
+ display: none;
+}
+
+.tor-bridges-lox-button {
+ grid-area: button;
+ margin: 0;
+ line-height: 1;
+ align-self: center;
+}
+
#tor-bridges-provider-heading {
font-size: 1.14em;
margin-block: 48px 8px;
@@ -723,6 +915,15 @@ groupbox#torPreferences-bridges-group textarea {
display: none;
}
+#user-provide-bridge-connecting {
+ color: var(--text-color-deemphasized);
+ /* TODO: Add spinner ::before */
+}
+
+#user-provide-bridge-connecting:not(.show-connecting) {
+ display: none;
+}
+
#user-provide-bridge-result-page {
flex: 1 1 0;
min-height: 0;
=====================================
browser/components/torpreferences/jar.mn
=====================================
@@ -3,6 +3,12 @@ browser.jar:
content/browser/torpreferences/bridge-qr.svg (content/bridge-qr.svg)
content/browser/torpreferences/telegram-logo.svg (content/telegram-logo.svg)
content/browser/torpreferences/bridge-bot.svg (content/bridge-bot.svg)
+ content/browser/torpreferences/lox-invite-icon.svg (content/lox-invite-icon.svg)
+ content/browser/torpreferences/lox-bridge-icon.svg (content/lox-bridge-icon.svg)
+ content/browser/torpreferences/lox-bridge-pass.svg (content/lox-bridge-pass.svg)
+ content/browser/torpreferences/lox-success.svg (content/lox-success.svg)
+ content/browser/torpreferences/lox-complete-ring.svg (content/lox-complete-ring.svg)
+ content/browser/torpreferences/lox-progress-ring.svg (content/lox-progress-ring.svg)
content/browser/torpreferences/bridgeQrDialog.xhtml (content/bridgeQrDialog.xhtml)
content/browser/torpreferences/bridgeQrDialog.js (content/bridgeQrDialog.js)
content/browser/torpreferences/builtinBridgeDialog.xhtml (content/builtinBridgeDialog.xhtml)
=====================================
browser/locales/en-US/browser/tor-browser.ftl
=====================================
@@ -56,6 +56,10 @@ tor-bridges-your-bridges = Your bridges
tor-bridges-source-user = Added by you
tor-bridges-source-built-in = Built-in
tor-bridges-source-requested = Requested from Tor
+# Here "Bridge pass" is a noun: a bridge pass gives users access to some tor bridges.
+# So "pass" is referring to something that gives permission or access. Similar to "token", "permit" or "voucher", but for permanent use rather than one-time.
+# This is shown when the user is getting their bridges from Lox.
+tor-bridges-source-lox = Bridge pass
# The "..." menu button for all current bridges.
tor-bridges-options-button =
.title = All bridges
@@ -116,12 +120,75 @@ tor-bridges-update-changed-bridges = Your Tor bridges have changed.
# Shown for requested bridges and bridges added by the user.
tor-bridges-share-heading = Help others connect
-#
tor-bridges-share-description = Share your bridges with trusted contacts.
tor-bridges-copy-addresses-button = Copy addresses
tor-bridges-qr-addresses-button =
.title = Show QR code
+# Shown when using a "bridge pass", i.e. using Lox.
+# Here "bridge pass" is a noun: a bridge pass gives users access to some tor bridges.
+# So "pass" is referring to something that gives permission or access. Similar to "token", "permit" or "voucher", but for permanent use rather than one-time.
+# Here "bridge bot" refers to a service that automatically gives out bridges for the user to use, i.e. the Lox authority.
+tor-bridges-lox-description = With a bridge pass, the bridge bot will send you new bridges when your bridges get blocked. If your bridges don’t get blocked, you’ll unlock invites that let you share bridges with trusted contacts.
+# The number of days until the user's "bridge pass" is upgraded.
+# $numDays (Number) - The number of days until the next upgrade, an integer (1 or higher).
+# The "[one]" and "[other]" are special Fluent syntax to mark plural categories that depend on the value of "$numDays". You can use any number of plural categories that work for your locale: "[zero]", "[one]", "[two]", "[few]", "[many]" and/or "[other]". The "*" marks a category as default, and is required.
+# See https://projectfluent.org/fluent/guide/selectors.html .
+# So in English, the first form will be used if $numDays is "1" (singular) and the second form will be used if $numDays is anything else (plural).
+tor-bridges-lox-days-until-unlock =
+ { $numDays ->
+ [one] { $numDays } day until you unlock:
+ *[other] { $numDays } days until you unlock:
+ }
+# This is shown as a list item after "N days until you unlock:" when the user will gain two more bridges in the future.
+# Here "bridge bot" refers to a service that automatically gives out bridges for the user to use, i.e. the Lox authority.
+tor-bridges-lox-unlock-two-bridges = +2 bridges from the bridge bot
+# This is shown as a list item after "N days until you unlock:" when the user will gain access to invites for the first time.
+# Here "invites" is a noun, short for "invitations".
+tor-bridges-lox-unlock-first-invites = Invites for your trusted contacts
+# This is shown as a list item after "N days until you unlock:" when the user already has invites.
+# Here "invites" is a noun, short for "invitations".
+tor-bridges-lox-unlock-more-invites = More invites for your trusted contacts
+# Here "invite" is a noun, short for "invitation".
+# $numInvites (Number) - The number of invites remaining, an integer (0 or higher).
+# The "[one]" and "[other]" are special Fluent syntax to mark plural categories that depend on the value of "$numInvites". You can use any number of plural categories that work for your locale: "[zero]", "[one]", "[two]", "[few]", "[many]" and/or "[other]". The "*" marks a category as default, and is required.
+# See https://projectfluent.org/fluent/guide/selectors.html .
+# So in English, the first form will be used if $numInvites is "1" (singular) and the second form will be used if $numInvites is anything else (plural).
+tor-bridges-lox-remaining-invites =
+ { $numInvites ->
+ [one] { $numInvites } invite remaining
+ *[other] { $numInvites } invites remaining
+ }
+# Here "invites" is a noun, short for "invitations".
+tor-bridges-lox-show-invites-button = Show invites
+
+# Shown when the user's "bridge pass" has been upgraded.
+# Here "bridge pass" is a noun: a bridge pass gives users access to some tor bridges.
+# So "pass" is referring to something that gives permission or access. Similar to "token", "permit" or "voucher", but for permanent use rather than one-time.
+tor-bridges-lox-upgrade = Your bridge pass has been upgraded!
+# Shown when the user's bridges accessed through "bridge pass" have been blocked.
+tor-bridges-lox-blocked = Your blocked bridges have been replaced
+# Shown *after* the user has had their blocked bridges replaced.
+# Here "bridge bot" refers to a service that automatically gives out bridges for the user to use, i.e. the Lox authority.
+tor-bridges-lox-new-bridges = New bridges from the bridge bot
+# Shown *after* the user has gained two more bridges.
+# Here "bridge bot" refers to a service that automatically gives out bridges for the user to use, i.e. the Lox authority.
+tor-bridges-lox-gained-two-bridges = +2 bridges from the bridge bot
+# Shown *after* a user's "bridge pass" has changed.
+# Here "invite" is a noun, short for "invitation".
+# $numInvites (Number) - The number of invites remaining, an integer (0 or higher).
+# The "[one]" and "[other]" are special Fluent syntax to mark plural categories that depend on the value of "$numInvites". You can use any number of plural categories that work for your locale: "[zero]", "[one]", "[two]", "[few]", "[many]" and/or "[other]". The "*" marks a category as default, and is required.
+# See https://projectfluent.org/fluent/guide/selectors.html .
+# So in English, the first form will be used if $numInvites is "1" (singular) and the second form will be used if $numInvites is anything else (plural).
+tor-bridges-lox-new-invites =
+ { $numInvites ->
+ [one] You now have { $numInvites } remaining invite for your trusted contacts
+ *[other] You now have { $numInvites } remaining invites for your trusted contacts
+ }
+# Button for the user to acknowledge a change in their "bridge pass".
+tor-bridges-lox-got-it-button = Got it
+
+
# Shown as a heading when the user has no current bridges.
tor-bridges-add-bridges-heading = Add bridges
# Shown as a heading when the user has existing bridges that can be replaced.
@@ -182,13 +249,50 @@ user-provide-bridge-dialog-description = Use bridges provided by a trusted organ
user-provide-bridge-dialog-learn-more = Learn more
# Short accessible name for the bridge addresses text area.
user-provide-bridge-dialog-textarea-addresses-label = Bridge addresses
+# Here "invite" is a noun, short for "invitation".
+# Short accessible name for text area when it can accept either bridge address or a single "bridge pass" invite.
+user-provide-bridge-dialog-textarea-addresses-or-invite-label = Bridge addresses or invite
# Placeholder shown when adding new bridge addresses.
user-provide-bridge-dialog-textarea-addresses =
.placeholder = Paste your bridge addresses here
+# Placeholder shown when the user can add new bridge addresses or a single "bridge pass" invite.
+# Here "bridge pass invite" is a noun: a bridge pass invite can be shared with other users to give them their own bridge pass, so they can get access to tor bridges.
+# So "pass" is referring to something that gives permission or access. Similar to "token", "permit" or "voucher", but for permanent use rather than one-time.
+# And "invite" is simply short for "invitation".
+# NOTE: "invite" is singular, whilst "addresses" is plural.
+user-provide-bridge-dialog-textarea-addresses-or-invite =
+ .placeholder = Paste your bridge addresses or a bridge pass invite here
# Error shown when one of the address lines is invalid.
# $line (Number) - The line number for the invalid address.
user-provide-bridge-dialog-address-error = Incorrectly formatted bridge address on line { $line }.
+# Error shown when the user has entered more than one "bridge pass" invite.
+# Here "invite" is a noun, short for "invitation".
+user-provide-bridge-dialog-multiple-invites-error = Cannot include more than one invite.
+# Error shown when the user has mixed their invite with addresses.
+# Here "invite" is a noun, short for "invitation".
+user-provide-bridge-dialog-mixed-error = Cannot mix bridge addresses with an invite.
+# Error shown when the user has entered an invite when it is not supported.
+# Here "bridge pass invite" is a noun: a bridge pass invite can be shared with other users to give them their own bridge pass, so they can get access to tor bridges.
+# So "pass" is referring to something that gives permission or access. Similar to "token", "permit" or "voucher", but for permanent use rather than one-time.
+# And "invite" is simply short for "invitation".
+user-provide-bridge-dialog-invite-not-allowed-error = Cannot include a bridge pass invite.
+# Error shown when the invite was not accepted by the server.
+user-provide-bridge-dialog-bad-invite-error = Invite was not accepted. Try a different one.
+# Error shown when the "bridge pass" server does not respond.
+# Here "bridge pass" is a noun: a bridge pass gives users access to some tor bridges.
+# So "pass" is referring to something that gives permission or access. Similar to "token", "permit" or "voucher", but for permanent use rather than one-time.
+user-provide-bridge-dialog-no-server-error = Unable to connect to bridge pass server.
+# Generic error when an invite failed.
+# Here "invite" is a noun, short for "invitation".
+user-provide-bridge-dialog-generic-invite-error = Failed to redeem invite.
+
+# Here "bridge pass" is a noun: a bridge pass gives users access to some tor bridges.
+# So "pass" is referring to something that gives permission or access. Similar to "token", "permit" or "voucher", but for permanent use rather than one-time.
+user-provide-bridge-dialog-connecting = Connecting to bridge pass server…
+# Shown after the user has entered a "bridge pass" invite.
+user-provide-bridge-dialog-result-invite = The following bridges were shared with you.
+# Shown after the user has entered bridge addresses.
user-provide-bridge-dialog-result-addresses = The following bridges were entered by you.
user-provide-bridge-dialog-next-button =
.label = Next
=====================================
toolkit/components/lox/Lox.sys.mjs
=====================================
@@ -128,12 +128,12 @@ class LoxImpl {
}
/**
- * Formats and returns bridges from the stored Lox credential
+ * Formats and returns bridges from the stored Lox credential.
*
- * @param {string} loxid The id string associated with a lox credential
+ * @param {string} loxid The id string associated with a lox credential.
*
* @returns {string[]} An array of formatted bridge lines. The array is empty
- * if there are no bridges.
+ * if there are no bridges.
*/
getBridges(loxid) {
if (!this.#initialized) {
@@ -250,6 +250,7 @@ class LoxImpl {
this.#pubKeyPromise = this.#makeRequest("pubkeys", [])
.then(pubKeys => {
this.#pubKeys = JSON.stringify(pubKeys);
+ this.#store();
})
.catch(() => {
// We always try to update, but if that doesn't work fall back to stored data
@@ -266,6 +267,7 @@ class LoxImpl {
this.#encTablePromise = this.#makeRequest("reachability", [])
.then(encTable => {
this.#encTable = JSON.stringify(encTable);
+ this.#store();
})
.catch(() => {
// Try to update first, but if that doesn't work fall back to stored data
@@ -283,6 +285,7 @@ class LoxImpl {
this.#constantsPromise = this.#makeRequest("constants", [])
.then(constants => {
this.#constants = JSON.stringify(constants);
+ this.#store();
})
.catch(() => {
if (!this.#constants) {
@@ -389,18 +392,17 @@ class LoxImpl {
}
/**
- * Parses an input string to check if it is a valid Lox invitation
+ * Parses an input string to check if it is a valid Lox invitation.
*
- * @param {string} invite A Lox invitation
- * @returns {Promise<bool>} A promise that resolves to true if the value passed
- * in was a Lox invitation and false if it is not
+ * @param {string} invite A Lox invitation.
+ * @returns {bool} Whether the value passed in was a Lox invitation.
*/
- async validateInvitation(invite) {
+ validateInvitation(invite) {
if (!this.#initialized) {
throw new LoxError(LoxErrors.NotInitialized);
}
try {
- await lazy.invitation_is_trusted(invite);
+ lazy.invitation_is_trusted(invite);
} catch (err) {
console.log(err);
return false;
@@ -420,22 +422,27 @@ class LoxImpl {
}
/**
- * Redeems a Lox invitation to obtain a credential and bridges
+ * Redeems a Lox invitation to obtain a credential and bridges.
*
- * @param {string} invite A Lox invitation
- * @returns {Promise<string>} A promise with the loxid of the associated credential on success
+ * @param {string} invite A Lox invitation.
+ * @returns {string} The loxid of the associated credential on success.
*/
async redeemInvite(invite) {
if (!this.#initialized) {
throw new LoxError(LoxErrors.NotInitialized);
}
await this.#getPubKeys();
- let request = await lazy.open_invite(invite.invite);
+ let request = await lazy.open_invite(JSON.parse(invite).invite);
let id = this.#genLoxId();
- let response = await this.#makeRequest(
- "openreq",
- JSON.parse(request).request
- );
+ let response;
+ try {
+ response = await this.#makeRequest(
+ "openreq",
+ JSON.parse(request).request
+ );
+ } catch {
+ throw new LoxError(LoxErrors.LoxServerUnreachable);
+ }
console.log("openreq response: ", response);
if (response.hasOwnProperty("error")) {
throw new LoxError(LoxErrors.BadInvite);
@@ -451,9 +458,9 @@ class LoxImpl {
}
/**
- * Get metadata on all invites historically generated by this credential
+ * Get metadata on all invites historically generated by this credential.
*
- * @returns {object[]} A list of all historical invites
+ * @returns {string[]} A list of all historical invites.
*/
getInvites() {
if (!this.#initialized) {
@@ -463,12 +470,14 @@ class LoxImpl {
}
/**
- * Generates a new trusted Lox invitation that a user can pass to their contacts
+ * Generates a new trusted Lox invitation that a user can pass to their
+ * contacts.
*
- * @returns {Promise<string>} A promise that resolves to a valid Lox invitation. The promise
- * will reject if:
- * - there is no saved Lox credential
- * - the saved credential does not have any invitations available
+ * Throws if:
+ * - there is no saved Lox credential, or
+ * - the saved credential does not have any invitations available.
+ *
+ * @returns {string} A valid Lox invitation.
*/
async generateInvite() {
if (!this.#initialized) {
@@ -514,11 +523,10 @@ class LoxImpl {
}
/**
- * Get the number of invites that a user has remaining
+ * Get the number of invites that a user has remaining.
*
- * @returns {Promise<int>} A promise with the number of invites that can still be generated
- * by a user's credential. This promise will reject if:
- * - There is no credential
+ * @returns {int} The number of invites that can still be generated by a
+ * user's credential.
*/
getRemainingInviteCount() {
if (!this.#initialized) {
@@ -691,11 +699,10 @@ class LoxImpl {
*/
/**
- * Get a list of accumulated events
+ * Get a list of accumulated events.
*
- * @returns {Promise<EventData[]>} A promise with a list of the accumulated,
- * unacknowledged events associated with a user's credential. This promise will reject if
- * - There is no credential
+ * @returns {EventData[]} A list of the accumulated, unacknowledged events
+ * associated with a user's credential.
*/
getEventData() {
if (!this.#initialized) {
@@ -709,7 +716,7 @@ class LoxImpl {
}
/**
- * Clears accumulated event data
+ * Clears accumulated event data.
*/
clearEventData() {
if (!this.#initialized) {
@@ -720,7 +727,7 @@ class LoxImpl {
}
/**
- * Clears accumulated invitations
+ * Clears accumulated invitations.
*/
clearInvites() {
if (!this.#initialized) {
@@ -739,7 +746,9 @@ class LoxImpl {
*/
/**
- * Get dates at which access to new features will unlock
+ * Get details about the next feature unlock.
+ *
+ * @returns {UnlockData} - Details about the next unlock.
*/
async getNextUnlock() {
if (!this.#initialized) {
@@ -753,10 +762,10 @@ class LoxImpl {
let nextUnlocks = JSON.parse(
lazy.get_next_unlock(this.#constants, this.#credentials[loxid])
);
- const level = lazy.get_trust_level(this.#credentials[loxid]);
+ const level = parseInt(lazy.get_trust_level(this.#credentials[loxid]));
const unlocks = {
date: nextUnlocks.trust_level_unlock_date,
- level: level + 1,
+ nextLevel: level + 1,
};
return unlocks;
}
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/fd4565…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/fd4565…
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 41067: Use Capture::Tiny instead of IO::CaptureOutput
by richard (@richard) 31 Jan '24
by richard (@richard) 31 Jan '24
31 Jan '24
richard pushed to branch maint-13.0 at The Tor Project / Applications / tor-browser-build
Commits:
74602df1 by Nicolas Vigier at 2024-01-31T08:51:48+00:00
Bug 41067: Use Capture::Tiny instead of IO::CaptureOutput
The IO::CaptureOutput perl module is deprecated, so we switch to
Capture::Tiny. We also remove some uses of IO::CaptureOutput where it
was not needed.
- - - - -
8 changed files:
- README
- rbm.conf
- tools/clean-old
- tools/dmg2mar
- tools/download-torbrowser
- tools/signing/machines-setup/setup-signing-machine
- tools/update-responses/README.md
- tools/update-responses/update_responses
Changes:
=====================================
README
=====================================
@@ -21,7 +21,7 @@ You also need a few perl modules installed:
- Getopt::Long
- Template
- IO::Handle
-- IO::CaptureOutput
+- Capture::Tiny
- JSON
- File::Temp
- Path::Tiny
@@ -41,7 +41,7 @@ If you are running Debian or Ubuntu, you can install them with:
# apt-get install libdata-dump-perl libdata-uuid-perl libdatetime-perl \
libdigest-sha-perl libfile-copy-recursive-perl \
- libfile-slurp-perl libio-all-perl libio-captureoutput-perl \
+ libfile-slurp-perl libio-all-perl libcapture-tiny-perl \
libio-handle-util-perl libjson-perl \
libparallel-forkmanager-perl libpath-tiny-perl \
libsort-versions-perl libstring-shellquote-perl \
@@ -51,7 +51,7 @@ If you are running Debian or Ubuntu, you can install them with:
If you are running an Arch based system, you should be able to install them with:
# pacman -S perl-datetime perl-path-tiny perl-yaml perl-yaml-libyaml \
- perl-yaml-tiny perl-template-toolkit perl-io-captureoutput \
+ perl-yaml-tiny perl-template-toolkit perl-capture-tiny \
perl-file-copy-recursive perl-string-shellquote \
perl-sort-versions perl-data-uuid perl-data-dump perl-json \
perl-digest-sha1 perl-io-all perl-file-slurp perl-sys-syscall \
=====================================
rbm.conf
=====================================
@@ -705,7 +705,6 @@ gpg_allow_expired_keys: 1
--- |
# This part of the file contains options written in perl
- use IO::CaptureOutput qw(capture_exec);
(
var_p => {
nightly_torbrowser_version => sub {
=====================================
tools/clean-old
=====================================
@@ -1,6 +1,5 @@
#!/usr/bin/perl -w
use strict;
-use IO::CaptureOutput qw(capture_exec);
use FindBin;
use lib "$FindBin::Bin/../rbm/lib";
use RBM;
=====================================
tools/dmg2mar
=====================================
@@ -29,7 +29,7 @@
# $ export "PATH=$p7zipdir/bin:$PATH"
use strict;
-use IO::CaptureOutput qw(capture_exec);
+use Capture::Tiny qw(capture);
use File::Slurp;
use File::Find;
use Parallel::ForkManager;
@@ -48,6 +48,15 @@ sub exit_error {
exit (exists $_[1] ? $_[1] : 1);
}
+sub capture_exec {
+ my @cmd = @_;
+ my ($stdout, $stderr, $exit) = capture {
+ system(@cmd);
+ };
+ return ($stdout, $stderr, $exit == 0, $exit) if wantarray();
+ return $stdout;
+}
+
sub osname {
my ($osname) = capture_exec('uname', '-s');
my ($arch) = capture_exec('uname', '-m');
=====================================
tools/download-torbrowser
=====================================
@@ -6,7 +6,6 @@
use strict;
use English;
use LWP::Simple;
-use IO::CaptureOutput qw(capture_exec);
use File::Temp;
use File::Basename qw(fileparse);
use FindBin;
=====================================
tools/signing/machines-setup/setup-signing-machine
=====================================
@@ -100,7 +100,7 @@ authorized_keys richard richard.pub
# Install rbm deps
install_packages libyaml-libyaml-perl libtemplate-perl libdatetime-perl \
libio-handle-util-perl libio-all-perl \
- libio-captureoutput-perl libjson-perl libpath-tiny-perl \
+ libcapture-tiny-perl libjson-perl libpath-tiny-perl \
libstring-shellquote-perl libsort-versions-perl \
libdigest-sha-perl libdata-uuid-perl libdata-dump-perl \
libfile-copy-recursive-perl libfile-slurp-perl
=====================================
tools/update-responses/README.md
=====================================
@@ -13,14 +13,14 @@ Dependencies
The following perl modules need to be installed to run the script:
FindBin YAML::XS File::Slurp Digest::SHA XML::Writer File::Temp
- IO::CaptureOutput Parallel::ForkManager XML::LibXML LWP JSON
+ Capture::Tiny Parallel::ForkManager XML::LibXML LWP JSON
On Debian / Ubuntu you can install them with:
```
# apt-get install libfindbin-libs-perl libyaml-libyaml-perl \
libfile-slurp-perl libdigest-sha-perl libxml-writer-perl \
- libio-captureoutput-perl libparallel-forkmanager-perl \
+ libcapture-tiny-perl libparallel-forkmanager-perl \
libxml-libxml-perl libwww-perl libjson-perl
```
@@ -28,7 +28,7 @@ On Red Hat / Fedora you can install them with:
```
# for module in FindBin YAML::XS File::Slurp Digest::SHA XML::Writer \
- File::Temp IO::CaptureOutput Parallel::ForkManager \
+ File::Temp Capture::Tiny Parallel::ForkManager \
XML::LibXML LWP JSON
do yum install "perl($module)"; done
```
=====================================
tools/update-responses/update_responses
=====================================
@@ -14,7 +14,7 @@ use File::Copy;
use File::Temp;
use File::Find;
use POSIX qw(setlocale LC_ALL);
-use IO::CaptureOutput qw(capture_exec);
+use Capture::Tiny qw(capture);
use Parallel::ForkManager;
use File::Basename;
use XML::LibXML '1.70';
@@ -265,9 +265,11 @@ sub create_incremental_mar {
local $ENV{MOZ_PRODUCT_VERSION} = $new_version;
local $ENV{MAR_CHANNEL_ID} = get_config($config, $new_version, $os, 'mar_channel_id');
local $ENV{TMPDIR} = $tmpdir;
- my ($out, $err, $success) = capture_exec('make_incremental_update.sh',
- $mar_file_path, "$tmpdir/A", "$tmpdir/B");
- if (!$success) {
+ my ($out, $err, $exit) = capture {
+ system('make_incremental_update.sh',
+ $mar_file_path, "$tmpdir/A", "$tmpdir/B");
+ };
+ if ($exit) {
unlink $mar_file_path if -f $mar_file_path;
exit_error "making incremental mar:\n" . $err;
}
@@ -490,9 +492,11 @@ sub extract_martools {
$martools_tmpdir = get_tmpdir($config);
my $old_cwd = getcwd;
chdir $martools_tmpdir;
- my (undef, undef, $success) = capture_exec('unzip', $marzip);
+ my (undef, undef, $exit) = capture {
+ system('unzip', $marzip);
+ };
chdir $old_cwd;
- exit_error "Error extracting $marzip" unless $success;
+ exit_error "Error extracting $marzip" if $exit;
$ENV{PATH} = "$martools_tmpdir/mar-tools:$initPATH";
if ($initLD_LIBRARY_PATH) {
$ENV{LD_LIBRARY_PATH} = "$initLD_LIBRARY_PATH:$martools_tmpdir/mar-tools";
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/7…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/7…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build][main] Bug 41067: Use Capture::Tiny instead of IO::CaptureOutput
by richard (@richard) 30 Jan '24
by richard (@richard) 30 Jan '24
30 Jan '24
richard pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
0ed7a191 by Nicolas Vigier at 2024-01-30T11:49:05+01:00
Bug 41067: Use Capture::Tiny instead of IO::CaptureOutput
The IO::CaptureOutput perl module is deprecated, so we switch to
Capture::Tiny. We also remove some uses of IO::CaptureOutput where it
was not needed.
- - - - -
8 changed files:
- README
- rbm.conf
- tools/clean-old
- tools/dmg2mar
- tools/download-torbrowser
- tools/signing/machines-setup/setup-signing-machine
- tools/update-responses/README.md
- tools/update-responses/update_responses
Changes:
=====================================
README
=====================================
@@ -21,7 +21,7 @@ You also need a few perl modules installed:
- Getopt::Long
- Template
- IO::Handle
-- IO::CaptureOutput
+- Capture::Tiny
- JSON
- File::Temp
- Path::Tiny
@@ -41,7 +41,7 @@ If you are running Debian or Ubuntu, you can install them with:
# apt-get install libdata-dump-perl libdata-uuid-perl libdatetime-perl \
libdigest-sha-perl libfile-copy-recursive-perl \
- libfile-slurp-perl libio-all-perl libio-captureoutput-perl \
+ libfile-slurp-perl libio-all-perl libcapture-tiny-perl \
libio-handle-util-perl libjson-perl \
libparallel-forkmanager-perl libpath-tiny-perl \
libsort-versions-perl libstring-shellquote-perl \
@@ -51,7 +51,7 @@ If you are running Debian or Ubuntu, you can install them with:
If you are running Fedora, CentOS or RHEL, you can install them with:
# dnf install "perl(YAML::XS)" "perl(File::Basename)" "perl(Getopt::Long)" \
- "perl(Template)" "perl(IO::Handle)" "perl(IO::CaptureOutput)" \
+ "perl(Template)" "perl(IO::Handle)" "perl(Capture::Tiny)" \
"perl(JSON)" "perl(File::Temp)" "perl(Path::Tiny)" \
"perl(File::Path)" "perl(File::Slurp)" \
"perl(File::Copy::Recursive)" "perl(String::ShellQuote)"
@@ -62,7 +62,7 @@ If you are running Fedora, CentOS or RHEL, you can install them with:
If you are running an Arch based system, you should be able to install them with:
# pacman -S perl-datetime perl-path-tiny perl-yaml perl-yaml-libyaml \
- perl-yaml-tiny perl-template-toolkit perl-io-captureoutput \
+ perl-yaml-tiny perl-template-toolkit perl-capture-tiny \
perl-file-copy-recursive perl-string-shellquote \
perl-sort-versions perl-data-uuid perl-data-dump perl-json \
perl-digest-sha1 perl-io-all perl-file-slurp perl-sys-syscall \
=====================================
rbm.conf
=====================================
@@ -704,7 +704,6 @@ gpg_allow_expired_keys: 1
--- |
# This part of the file contains options written in perl
- use IO::CaptureOutput qw(capture_exec);
(
var_p => {
nightly_torbrowser_version => sub {
=====================================
tools/clean-old
=====================================
@@ -1,6 +1,5 @@
#!/usr/bin/perl -w
use strict;
-use IO::CaptureOutput qw(capture_exec);
use FindBin;
use lib "$FindBin::Bin/../rbm/lib";
use RBM;
=====================================
tools/dmg2mar
=====================================
@@ -29,7 +29,7 @@
# $ export "PATH=$p7zipdir/bin:$PATH"
use strict;
-use IO::CaptureOutput qw(capture_exec);
+use Capture::Tiny qw(capture);
use File::Slurp;
use File::Find;
use Parallel::ForkManager;
@@ -48,6 +48,15 @@ sub exit_error {
exit (exists $_[1] ? $_[1] : 1);
}
+sub capture_exec {
+ my @cmd = @_;
+ my ($stdout, $stderr, $exit) = capture {
+ system(@cmd);
+ };
+ return ($stdout, $stderr, $exit == 0, $exit) if wantarray();
+ return $stdout;
+}
+
sub osname {
my ($osname) = capture_exec('uname', '-s');
my ($arch) = capture_exec('uname', '-m');
=====================================
tools/download-torbrowser
=====================================
@@ -6,7 +6,6 @@
use strict;
use English;
use LWP::Simple;
-use IO::CaptureOutput qw(capture_exec);
use File::Temp;
use File::Basename qw(fileparse);
use FindBin;
=====================================
tools/signing/machines-setup/setup-signing-machine
=====================================
@@ -100,7 +100,7 @@ authorized_keys richard richard.pub
# Install rbm deps
install_packages libyaml-libyaml-perl libtemplate-perl libdatetime-perl \
libio-handle-util-perl libio-all-perl \
- libio-captureoutput-perl libjson-perl libpath-tiny-perl \
+ libcapture-tiny-perl libjson-perl libpath-tiny-perl \
libstring-shellquote-perl libsort-versions-perl \
libdigest-sha-perl libdata-uuid-perl libdata-dump-perl \
libfile-copy-recursive-perl libfile-slurp-perl
=====================================
tools/update-responses/README.md
=====================================
@@ -13,14 +13,14 @@ Dependencies
The following perl modules need to be installed to run the script:
FindBin YAML::XS File::Slurp Digest::SHA XML::Writer File::Temp
- IO::CaptureOutput Parallel::ForkManager XML::LibXML LWP JSON
+ Capture::Tiny Parallel::ForkManager XML::LibXML LWP JSON
On Debian / Ubuntu you can install them with:
```
# apt-get install libfindbin-libs-perl libyaml-libyaml-perl \
libfile-slurp-perl libdigest-sha-perl libxml-writer-perl \
- libio-captureoutput-perl libparallel-forkmanager-perl \
+ libcapture-tiny-perl libparallel-forkmanager-perl \
libxml-libxml-perl libwww-perl libjson-perl
```
@@ -28,7 +28,7 @@ On Red Hat / Fedora you can install them with:
```
# for module in FindBin YAML::XS File::Slurp Digest::SHA XML::Writer \
- File::Temp IO::CaptureOutput Parallel::ForkManager \
+ File::Temp Capture::Tiny Parallel::ForkManager \
XML::LibXML LWP JSON
do yum install "perl($module)"; done
```
=====================================
tools/update-responses/update_responses
=====================================
@@ -14,7 +14,7 @@ use File::Copy;
use File::Temp;
use File::Find;
use POSIX qw(setlocale LC_ALL);
-use IO::CaptureOutput qw(capture_exec);
+use Capture::Tiny qw(capture);
use Parallel::ForkManager;
use File::Basename;
use XML::LibXML '1.70';
@@ -265,9 +265,11 @@ sub create_incremental_mar {
local $ENV{MOZ_PRODUCT_VERSION} = $new_version;
local $ENV{MAR_CHANNEL_ID} = get_config($config, $new_version, $os, 'mar_channel_id');
local $ENV{TMPDIR} = $tmpdir;
- my ($out, $err, $success) = capture_exec('make_incremental_update.sh',
- $mar_file_path, "$tmpdir/A", "$tmpdir/B");
- if (!$success) {
+ my ($out, $err, $exit) = capture {
+ system('make_incremental_update.sh',
+ $mar_file_path, "$tmpdir/A", "$tmpdir/B");
+ };
+ if ($exit) {
unlink $mar_file_path if -f $mar_file_path;
exit_error "making incremental mar:\n" . $err;
}
@@ -490,9 +492,11 @@ sub extract_martools {
$martools_tmpdir = get_tmpdir($config);
my $old_cwd = getcwd;
chdir $martools_tmpdir;
- my (undef, undef, $success) = capture_exec('unzip', $marzip);
+ my (undef, undef, $exit) = capture {
+ system('unzip', $marzip);
+ };
chdir $old_cwd;
- exit_error "Error extracting $marzip" unless $success;
+ exit_error "Error extracting $marzip" if $exit;
$ENV{PATH} = "$martools_tmpdir/mar-tools:$initPATH";
if ($initLD_LIBRARY_PATH) {
$ENV{LD_LIBRARY_PATH} = "$initLD_LIBRARY_PATH:$martools_tmpdir/mar-tools";
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/0…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/0…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build][maint-13.0] Update rbm for rbm#40068 and rbm#40069
by boklm (@boklm) 30 Jan '24
by boklm (@boklm) 30 Jan '24
30 Jan '24
boklm pushed to branch maint-13.0 at The Tor Project / Applications / tor-browser-build
Commits:
cfa73f9c by Nicolas Vigier at 2024-01-30T16:46:23+01:00
Update rbm for rbm#40068 and rbm#40069
- - - - -
1 changed file:
- rbm
Changes:
=====================================
rbm
=====================================
@@ -1 +1 @@
-Subproject commit b5e5b04aaf677c4bacfb5ace45598313286bfdf6
+Subproject commit 067c30ee4cf3baa1c0b7e3674d785cf9e5bec8fe
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/rbm][main] Bug 40069: Fix encoding of stdout and stderr
by richard (@richard) 30 Jan '24
by richard (@richard) 30 Jan '24
30 Jan '24
richard pushed to branch main at The Tor Project / Applications / RBM
Commits:
067c30ee by Nicolas Vigier at 2024-01-30T12:50:32+01:00
Bug 40069: Fix encoding of stdout and stderr
Set stdout and stder encoding based on nl_langinfo, or LC_ALL and LANG
locale environment variables, as suggested on
https://perldoc.perl.org/open.
- - - - -
1 changed file:
- rbm
Changes:
=====================================
rbm
=====================================
@@ -1,6 +1,7 @@
#!/usr/bin/perl -w
use strict;
+use open OUT => ':locale';
use File::Basename;
use lib dirname($0) . '/lib';
use RBM;
View it on GitLab: https://gitlab.torproject.org/tpo/applications/rbm/-/commit/067c30ee4cf3baa…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/rbm/-/commit/067c30ee4cf3baa…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/mullvad-browser-update-responses][main] alpha: new version, 13.5a4
by richard (@richard) 30 Jan '24
by richard (@richard) 30 Jan '24
30 Jan '24
richard pushed to branch main at The Tor Project / Applications / mullvad-browser-update-responses
Commits:
4a352531 by Richard Pospesel at 2024-01-30T11:59:07+00:00
alpha: new version, 13.5a4
- - - - -
29 changed files:
- update_1/alpha/.htaccess
- − update_1/alpha/13.0a6-13.5a3-linux-x86_64-ALL.xml
- − update_1/alpha/13.0a6-13.5a3-macos-ALL.xml
- − update_1/alpha/13.0a6-13.5a3-windows-x86_64-ALL.xml
- − update_1/alpha/13.5a1-13.5a3-linux-x86_64-ALL.xml
- − update_1/alpha/13.5a1-13.5a3-macos-ALL.xml
- − update_1/alpha/13.5a1-13.5a3-windows-x86_64-ALL.xml
- + update_1/alpha/13.5a1-13.5a4-linux-x86_64-ALL.xml
- + update_1/alpha/13.5a1-13.5a4-macos-ALL.xml
- + update_1/alpha/13.5a1-13.5a4-windows-x86_64-ALL.xml
- − update_1/alpha/13.5a2-13.5a3-linux-x86_64-ALL.xml
- − update_1/alpha/13.5a2-13.5a3-macos-ALL.xml
- − update_1/alpha/13.5a2-13.5a3-windows-x86_64-ALL.xml
- + update_1/alpha/13.5a2-13.5a4-linux-x86_64-ALL.xml
- + update_1/alpha/13.5a2-13.5a4-macos-ALL.xml
- + update_1/alpha/13.5a2-13.5a4-windows-x86_64-ALL.xml
- + update_1/alpha/13.5a3-13.5a4-linux-x86_64-ALL.xml
- + update_1/alpha/13.5a3-13.5a4-macos-ALL.xml
- + update_1/alpha/13.5a3-13.5a4-windows-x86_64-ALL.xml
- − update_1/alpha/13.5a3-linux-x86_64-ALL.xml
- − update_1/alpha/13.5a3-macos-ALL.xml
- − update_1/alpha/13.5a3-windows-x86_64-ALL.xml
- + update_1/alpha/13.5a4-linux-x86_64-ALL.xml
- + update_1/alpha/13.5a4-macos-ALL.xml
- + update_1/alpha/13.5a4-windows-x86_64-ALL.xml
- update_1/alpha/download-linux-x86_64.json
- update_1/alpha/download-macos.json
- update_1/alpha/download-windows-x86_64.json
- update_1/alpha/downloads.json
Changes:
=====================================
update_1/alpha/.htaccess
=====================================
@@ -1,22 +1,22 @@
RewriteEngine On
-RewriteRule ^[^/]+/13.5a3/ no-update.xml [last]
-RewriteRule ^Linux_x86_64-gcc3/13.0a6/ALL 13.0a6-13.5a3-linux-x86_64-ALL.xml [last]
-RewriteRule ^Linux_x86_64-gcc3/13.5a1/ALL 13.5a1-13.5a3-linux-x86_64-ALL.xml [last]
-RewriteRule ^Linux_x86_64-gcc3/13.5a2/ALL 13.5a2-13.5a3-linux-x86_64-ALL.xml [last]
-RewriteRule ^Linux_x86_64-gcc3/[^/]+/ALL 13.5a3-linux-x86_64-ALL.xml [last]
-RewriteRule ^Linux_x86_64-gcc3/ 13.5a3-linux-x86_64-ALL.xml [last]
-RewriteRule ^Darwin_x86_64-gcc3/13.0a6/ALL 13.0a6-13.5a3-macos-ALL.xml [last]
-RewriteRule ^Darwin_x86_64-gcc3/13.5a1/ALL 13.5a1-13.5a3-macos-ALL.xml [last]
-RewriteRule ^Darwin_x86_64-gcc3/13.5a2/ALL 13.5a2-13.5a3-macos-ALL.xml [last]
-RewriteRule ^Darwin_x86_64-gcc3/[^/]+/ALL 13.5a3-macos-ALL.xml [last]
-RewriteRule ^Darwin_x86_64-gcc3/ 13.5a3-macos-ALL.xml [last]
-RewriteRule ^Darwin_aarch64-gcc3/13.0a6/ALL 13.0a6-13.5a3-macos-ALL.xml [last]
-RewriteRule ^Darwin_aarch64-gcc3/13.5a1/ALL 13.5a1-13.5a3-macos-ALL.xml [last]
-RewriteRule ^Darwin_aarch64-gcc3/13.5a2/ALL 13.5a2-13.5a3-macos-ALL.xml [last]
-RewriteRule ^Darwin_aarch64-gcc3/[^/]+/ALL 13.5a3-macos-ALL.xml [last]
-RewriteRule ^Darwin_aarch64-gcc3/ 13.5a3-macos-ALL.xml [last]
-RewriteRule ^WINNT_x86_64-gcc3-x64/13.0a6/ALL 13.0a6-13.5a3-windows-x86_64-ALL.xml [last]
-RewriteRule ^WINNT_x86_64-gcc3-x64/13.5a1/ALL 13.5a1-13.5a3-windows-x86_64-ALL.xml [last]
-RewriteRule ^WINNT_x86_64-gcc3-x64/13.5a2/ALL 13.5a2-13.5a3-windows-x86_64-ALL.xml [last]
-RewriteRule ^WINNT_x86_64-gcc3-x64/[^/]+/ALL 13.5a3-windows-x86_64-ALL.xml [last]
-RewriteRule ^WINNT_x86_64-gcc3-x64/ 13.5a3-windows-x86_64-ALL.xml [last]
+RewriteRule ^[^/]+/13.5a4/ no-update.xml [last]
+RewriteRule ^Linux_x86_64-gcc3/13.5a1/ALL 13.5a1-13.5a4-linux-x86_64-ALL.xml [last]
+RewriteRule ^Linux_x86_64-gcc3/13.5a2/ALL 13.5a2-13.5a4-linux-x86_64-ALL.xml [last]
+RewriteRule ^Linux_x86_64-gcc3/13.5a3/ALL 13.5a3-13.5a4-linux-x86_64-ALL.xml [last]
+RewriteRule ^Linux_x86_64-gcc3/[^/]+/ALL 13.5a4-linux-x86_64-ALL.xml [last]
+RewriteRule ^Linux_x86_64-gcc3/ 13.5a4-linux-x86_64-ALL.xml [last]
+RewriteRule ^Darwin_x86_64-gcc3/13.5a1/ALL 13.5a1-13.5a4-macos-ALL.xml [last]
+RewriteRule ^Darwin_x86_64-gcc3/13.5a2/ALL 13.5a2-13.5a4-macos-ALL.xml [last]
+RewriteRule ^Darwin_x86_64-gcc3/13.5a3/ALL 13.5a3-13.5a4-macos-ALL.xml [last]
+RewriteRule ^Darwin_x86_64-gcc3/[^/]+/ALL 13.5a4-macos-ALL.xml [last]
+RewriteRule ^Darwin_x86_64-gcc3/ 13.5a4-macos-ALL.xml [last]
+RewriteRule ^Darwin_aarch64-gcc3/13.5a1/ALL 13.5a1-13.5a4-macos-ALL.xml [last]
+RewriteRule ^Darwin_aarch64-gcc3/13.5a2/ALL 13.5a2-13.5a4-macos-ALL.xml [last]
+RewriteRule ^Darwin_aarch64-gcc3/13.5a3/ALL 13.5a3-13.5a4-macos-ALL.xml [last]
+RewriteRule ^Darwin_aarch64-gcc3/[^/]+/ALL 13.5a4-macos-ALL.xml [last]
+RewriteRule ^Darwin_aarch64-gcc3/ 13.5a4-macos-ALL.xml [last]
+RewriteRule ^WINNT_x86_64-gcc3-x64/13.5a1/ALL 13.5a1-13.5a4-windows-x86_64-ALL.xml [last]
+RewriteRule ^WINNT_x86_64-gcc3-x64/13.5a2/ALL 13.5a2-13.5a4-windows-x86_64-ALL.xml [last]
+RewriteRule ^WINNT_x86_64-gcc3-x64/13.5a3/ALL 13.5a3-13.5a4-windows-x86_64-ALL.xml [last]
+RewriteRule ^WINNT_x86_64-gcc3-x64/[^/]+/ALL 13.5a4-windows-x86_64-ALL.xml [last]
+RewriteRule ^WINNT_x86_64-gcc3-x64/ 13.5a4-windows-x86_64-ALL.xml [last]
=====================================
update_1/alpha/13.0a6-13.5a3-linux-x86_64-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64-13.5a3_…" hashFunction="SHA512" hashValue="ad2914a4f0c2b78f7d740fc8d1077767e3c42f12857fbda706c87b5f52cb2e4a415aaa0e4e732764f2fe463ae335b73fe52db6943b02e50fafef11fc42864475" size="106795579" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64--13.0a6…" hashFunction="SHA512" hashValue="d06ef52fb1061cc60e2b4455845cef391a956b12827d6687e80ef82b685dd7e4b08b163426d4692733c8bc8fc0b69d1c32d840d39638eb99866d83c8c716e100" size="9198850" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.0a6-13.5a3-macos-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedOSVersion="16.0.0"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos-13.5a3_ALL.mar" hashFunction="SHA512" hashValue="b3c91729bb0f42aab67440d4119f2574d917c501b0ee958d41eb36914acdf9c2ba40d1aa12755a84744b073941d4ccc1c792e86007fbe05fb545e53dd96aac5f" size="114855415" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos--13.0a6-13.5a3…" hashFunction="SHA512" hashValue="ef939f5a129df1a0b253e9ccd5d2d43389d6cdf1883da2cb81e3dd24cb756ba378935630c1234ed5223da078aaf6f980fefdb66ef2cc0b94375dbf61902e06c3" size="14294193" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.0a6-13.5a3-windows-x86_64-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedOSVersion="6.1" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64-13.5a…" hashFunction="SHA512" hashValue="a6ce2a3d2ed55b42354f6559e9cf48f5971728d13f83070331bda042a114bb02d0e06b5dd7dad2db6fc3376ec152d0f92a7fb87d21cf00da398a9bb5577dc1f5" size="88815824" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64--13.0…" hashFunction="SHA512" hashValue="28c5d75219d14249a9363cf42518ea6954dd00f76fa8100d3c7a52c72430eeb8f370176376082fda5df19b62c36f4ed7373979ab2b3f52bb31d118278abdfb45" size="9817942" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a1-13.5a3-linux-x86_64-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64-13.5a3_…" hashFunction="SHA512" hashValue="ad2914a4f0c2b78f7d740fc8d1077767e3c42f12857fbda706c87b5f52cb2e4a415aaa0e4e732764f2fe463ae335b73fe52db6943b02e50fafef11fc42864475" size="106795579" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64--13.5a1…" hashFunction="SHA512" hashValue="b60a8436420fc9e904499ca9c073e792c207a6b9ef94433bff2f9895c12f482fdfb70d6511c72d548d597562dda90b59e9afd96c7789785f8e8ac5a342423bd4" size="8508777" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a1-13.5a3-macos-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedOSVersion="16.0.0"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos-13.5a3_ALL.mar" hashFunction="SHA512" hashValue="b3c91729bb0f42aab67440d4119f2574d917c501b0ee958d41eb36914acdf9c2ba40d1aa12755a84744b073941d4ccc1c792e86007fbe05fb545e53dd96aac5f" size="114855415" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos--13.5a1-13.5a3…" hashFunction="SHA512" hashValue="238d6a426fc36ab8f117032c54198dfcd36272d03f7e2ed0c2e9b139bfa2ffb6197b3082e57dae827226b137305e10a244de4a3619c8b88d4c00799c41cb3505" size="13597253" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a1-13.5a3-windows-x86_64-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedOSVersion="6.1" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64-13.5a…" hashFunction="SHA512" hashValue="a6ce2a3d2ed55b42354f6559e9cf48f5971728d13f83070331bda042a114bb02d0e06b5dd7dad2db6fc3376ec152d0f92a7fb87d21cf00da398a9bb5577dc1f5" size="88815824" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64--13.5…" hashFunction="SHA512" hashValue="9e289c8b83afbdd9b09bcadbcd93f3f66c36d2ea7965cfd04a6a4e492d0541f3a652361c8db099e2d11a6db0c07023c2acfae478defbb6660c41deb17e45900c" size="9179529" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a1-13.5a4-linux-x86_64-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64-13.5a4_…" hashFunction="SHA512" hashValue="f4807be1248046f3115f381dbead91fdf8731f3f3ffc76a7eb7bf32eb58f37e3e4cd76861bf6783c53662de6dfd8e3f5e2e193ae49c2828ca8c70eaad512ae9c" size="107916327" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64--13.5a1…" hashFunction="SHA512" hashValue="7929965bcf3f97ffe3a856248271d3dcbb5999b228858b75f3e1d993bfcfe5d06efecce70f1325edd1fde4edabd0d556b44e6ee56149a0f73e54c55bd773b34a" size="15875405" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a1-13.5a4-macos-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedOSVersion="16.0.0"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos-13.5a4_ALL.mar" hashFunction="SHA512" hashValue="05aa6ee66d4dea52c6fec07d45cb0bc96dc813b3f86db418eb86ecf6dccd44e85c0fb1c7c2450d50b35b1ad8da0a7d16ed16f2083fef7e3e1135774ad278908b" size="115308515" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos--13.5a1-13.5a4…" hashFunction="SHA512" hashValue="e49a99198e0046cc0133a69991bc204ec89e4fe07216be40d7a669ecd3b8ac26c889de3a0d161b6be726105369e46d2e92c84177cdde14df968005a5aafe1b1f" size="17266465" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a1-13.5a4-windows-x86_64-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedOSVersion="6.1" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64-13.5a…" hashFunction="SHA512" hashValue="2681c3052302fa2e791e6c82d2ad48569d8f1622400bd433efe31e7757e8002c0f5c1f2930949f89ee059bc61b2cea2101d56b67f2c506eb6222a0ff709948f6" size="89263680" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64--13.5…" hashFunction="SHA512" hashValue="69038008b474bf188b13e1c41331de90f0b591f93f961145b744d9df552a423b5e1c17ad36db608e53a68c31249e9c9f31ddba6b7ab066b91ea44aa0c2b17640" size="12871701" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a2-13.5a3-linux-x86_64-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64-13.5a3_…" hashFunction="SHA512" hashValue="ad2914a4f0c2b78f7d740fc8d1077767e3c42f12857fbda706c87b5f52cb2e4a415aaa0e4e732764f2fe463ae335b73fe52db6943b02e50fafef11fc42864475" size="106795579" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64--13.5a2…" hashFunction="SHA512" hashValue="8a7d10996b6b801f1d2858c200049ddf95117ccdcaacc3cb8b5e818312f4b195b231f18bd8f61e5cb1513c1f1791ece281fe503209250896c430c1766b1797af" size="5627360" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a2-13.5a3-macos-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedOSVersion="16.0.0"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos-13.5a3_ALL.mar" hashFunction="SHA512" hashValue="b3c91729bb0f42aab67440d4119f2574d917c501b0ee958d41eb36914acdf9c2ba40d1aa12755a84744b073941d4ccc1c792e86007fbe05fb545e53dd96aac5f" size="114855415" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos--13.5a2-13.5a3…" hashFunction="SHA512" hashValue="e2441d94986928b77ec1606b07cfca59e56f1cba1e6f466e14c8482fff7e33ec0aa78429787b25ba3d0f573060c6bfaad6a6094a26cd28e60c8e2a38891fff18" size="10532560" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a2-13.5a3-windows-x86_64-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedOSVersion="6.1" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64-13.5a…" hashFunction="SHA512" hashValue="a6ce2a3d2ed55b42354f6559e9cf48f5971728d13f83070331bda042a114bb02d0e06b5dd7dad2db6fc3376ec152d0f92a7fb87d21cf00da398a9bb5577dc1f5" size="88815824" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64--13.5…" hashFunction="SHA512" hashValue="07b3258657393586dce54e2c508de7e87969fb6516988dd992573ef57585e9f99a0798afdd1c0c5100f4485c42664e2c88f4566c8022c0c7ba3d90a315fd9cbc" size="6257559" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a2-13.5a4-linux-x86_64-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64-13.5a4_…" hashFunction="SHA512" hashValue="f4807be1248046f3115f381dbead91fdf8731f3f3ffc76a7eb7bf32eb58f37e3e4cd76861bf6783c53662de6dfd8e3f5e2e193ae49c2828ca8c70eaad512ae9c" size="107916327" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64--13.5a2…" hashFunction="SHA512" hashValue="615a7a213ae930ab0072f3e4f0eb6ff823e371fb2931e6ea50ab82b47a30acbdc2904e790bd186886da8540e2dc89fa5f8383938acb9de3a81a7552f53527577" size="14878410" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a2-13.5a4-macos-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedOSVersion="16.0.0"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos-13.5a4_ALL.mar" hashFunction="SHA512" hashValue="05aa6ee66d4dea52c6fec07d45cb0bc96dc813b3f86db418eb86ecf6dccd44e85c0fb1c7c2450d50b35b1ad8da0a7d16ed16f2083fef7e3e1135774ad278908b" size="115308515" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos--13.5a2-13.5a4…" hashFunction="SHA512" hashValue="dcabe3438794aae6e64d72bfe836ad65cf8454e6db2aef9acaaa07d83d341912a5bf9ccf1b3125ff0cc00846fe6b79b0d775e0d47c3bf1f5777a97356a7148c7" size="16017493" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a2-13.5a4-windows-x86_64-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedOSVersion="6.1" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64-13.5a…" hashFunction="SHA512" hashValue="2681c3052302fa2e791e6c82d2ad48569d8f1622400bd433efe31e7757e8002c0f5c1f2930949f89ee059bc61b2cea2101d56b67f2c506eb6222a0ff709948f6" size="89263680" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64--13.5…" hashFunction="SHA512" hashValue="ffe9a835049d044d17e66bcb06c035f145c7cd6913de0f23755fda6a164406bc86fa9dc5297a9fec7eac1b23014f742e9733bd4ddf7cd89a7a979525b2570657" size="11825429" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a3-13.5a4-linux-x86_64-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64-13.5a4_…" hashFunction="SHA512" hashValue="f4807be1248046f3115f381dbead91fdf8731f3f3ffc76a7eb7bf32eb58f37e3e4cd76861bf6783c53662de6dfd8e3f5e2e193ae49c2828ca8c70eaad512ae9c" size="107916327" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64--13.5a3…" hashFunction="SHA512" hashValue="5d8408d9e6e701a3ba9ff4e697b55f23d86e6909aa406b23730772631893cb5b6ca8f472fa5a2ffa448bcbf055375afc0775ad82d583ee45a1a1d64e8a3db761" size="13991539" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a3-13.5a4-macos-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedOSVersion="16.0.0"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos-13.5a4_ALL.mar" hashFunction="SHA512" hashValue="05aa6ee66d4dea52c6fec07d45cb0bc96dc813b3f86db418eb86ecf6dccd44e85c0fb1c7c2450d50b35b1ad8da0a7d16ed16f2083fef7e3e1135774ad278908b" size="115308515" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos--13.5a3-13.5a4…" hashFunction="SHA512" hashValue="bf3ef67f38db8d9bb85f07dc92c2ee3e70e767c1954c07e9538c1bb6a84a1c98ca1ce280977b78cf90154ceb96e68bb905667e01407de581e1d5556a2ccea26c" size="14099283" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a3-13.5a4-windows-x86_64-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedOSVersion="6.1" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64-13.5a…" hashFunction="SHA512" hashValue="2681c3052302fa2e791e6c82d2ad48569d8f1622400bd433efe31e7757e8002c0f5c1f2930949f89ee059bc61b2cea2101d56b67f2c506eb6222a0ff709948f6" size="89263680" type="complete"></patch><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64--13.5…" hashFunction="SHA512" hashValue="55cd47c65f8c38296547bad978c4fae0e51733de4f7970e1ac9f4d01083ebdc06eecee506bf92f6eb2e64c476fa707c5af33ea0c7838acf44217b8706102471e" size="9557366" type="partial"></patch></update></updates>
=====================================
update_1/alpha/13.5a3-linux-x86_64-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64-13.5a3_…" hashFunction="SHA512" hashValue="ad2914a4f0c2b78f7d740fc8d1077767e3c42f12857fbda706c87b5f52cb2e4a415aaa0e4e732764f2fe463ae335b73fe52db6943b02e50fafef11fc42864475" size="106795579" type="complete"></patch></update></updates>
=====================================
update_1/alpha/13.5a3-macos-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedOSVersion="16.0.0"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos-13.5a3_ALL.mar" hashFunction="SHA512" hashValue="b3c91729bb0f42aab67440d4119f2574d917c501b0ee958d41eb36914acdf9c2ba40d1aa12755a84744b073941d4ccc1c792e86007fbe05fb545e53dd96aac5f" size="114855415" type="complete"></patch></update></updates>
=====================================
update_1/alpha/13.5a3-windows-x86_64-ALL.xml deleted
=====================================
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<updates><update type="minor" displayVersion="13.5a3" appVersion="13.5a3" platformVersion="115.6.0" buildID="20231219113348" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a3" minSupportedOSVersion="6.1" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64-13.5a…" hashFunction="SHA512" hashValue="a6ce2a3d2ed55b42354f6559e9cf48f5971728d13f83070331bda042a114bb02d0e06b5dd7dad2db6fc3376ec152d0f92a7fb87d21cf00da398a9bb5577dc1f5" size="88815824" type="complete"></patch></update></updates>
=====================================
update_1/alpha/13.5a4-linux-x86_64-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64-13.5a4_…" hashFunction="SHA512" hashValue="f4807be1248046f3115f381dbead91fdf8731f3f3ffc76a7eb7bf32eb58f37e3e4cd76861bf6783c53662de6dfd8e3f5e2e193ae49c2828ca8c70eaad512ae9c" size="107916327" type="complete"></patch></update></updates>
=====================================
update_1/alpha/13.5a4-macos-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedOSVersion="16.0.0"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos-13.5a4_ALL.mar" hashFunction="SHA512" hashValue="05aa6ee66d4dea52c6fec07d45cb0bc96dc813b3f86db418eb86ecf6dccd44e85c0fb1c7c2450d50b35b1ad8da0a7d16ed16f2083fef7e3e1135774ad278908b" size="115308515" type="complete"></patch></update></updates>
=====================================
update_1/alpha/13.5a4-windows-x86_64-ALL.xml
=====================================
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<updates><update type="minor" displayVersion="13.5a4" appVersion="13.5a4" platformVersion="115.7.0" buildID="20240129155630" detailsURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" actions="showURL" openURL="https://github.com/mullvad/mullvad-browser/releases/13.5a4" minSupportedOSVersion="6.1" minSupportedInstructionSet="SSE2"><patch URL="https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64-13.5a…" hashFunction="SHA512" hashValue="2681c3052302fa2e791e6c82d2ad48569d8f1622400bd433efe31e7757e8002c0f5c1f2930949f89ee059bc61b2cea2101d56b67f2c506eb6222a0ff709948f6" size="89263680" type="complete"></patch></update></updates>
=====================================
update_1/alpha/download-linux-x86_64.json
=====================================
@@ -1 +1 @@
-{"binary":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64-13.5a3.…","git_tag":"mb-13.5a3-build1","sig":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64-13.5a3.…","version":"13.5a3"}
\ No newline at end of file
+{"binary":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64-13.5a4.…","git_tag":"mb-13.5a4-build1","sig":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64-13.5a4.…","version":"13.5a4"}
\ No newline at end of file
=====================================
update_1/alpha/download-macos.json
=====================================
@@ -1 +1 @@
-{"binary":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos-13.5a3.dmg","git_tag":"mb-13.5a3-build1","sig":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos-13.5a3.dmg.asc","version":"13.5a3"}
\ No newline at end of file
+{"binary":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos-13.5a4.dmg","git_tag":"mb-13.5a4-build1","sig":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos-13.5a4.dmg.asc","version":"13.5a4"}
\ No newline at end of file
=====================================
update_1/alpha/download-windows-x86_64.json
=====================================
@@ -1 +1 @@
-{"binary":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64-porta…","git_tag":"mb-13.5a3-build1","sig":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64-porta…","version":"13.5a3"}
\ No newline at end of file
+{"binary":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64-porta…","git_tag":"mb-13.5a4-build1","sig":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64-porta…","version":"13.5a4"}
\ No newline at end of file
=====================================
update_1/alpha/downloads.json
=====================================
@@ -1 +1 @@
-{"downloads":{"linux-x86_64":{"ALL":{"binary":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64-13.5a3.…","sig":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-linux-x86_64-13.5a3.…"}},"macos":{"ALL":{"binary":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos-13.5a3.dmg","sig":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-macos-13.5a3.dmg.asc"}},"win64":{"ALL":{"binary":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64-porta…","sig":"https://cdn.mullvad.net/browser/13.5a3/mullvad-browser-windows-x86_64-porta…"}}},"tag":"mb-13.5a3-build1","version":"13.5a3"}
\ No newline at end of file
+{"downloads":{"linux-x86_64":{"ALL":{"binary":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64-13.5a4.…","sig":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-linux-x86_64-13.5a4.…"}},"macos":{"ALL":{"binary":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos-13.5a4.dmg","sig":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-macos-13.5a4.dmg.asc"}},"win64":{"ALL":{"binary":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64-porta…","sig":"https://cdn.mullvad.net/browser/13.5a4/mullvad-browser-windows-x86_64-porta…"}}},"tag":"mb-13.5a4-build1","version":"13.5a4"}
\ No newline at end of file
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser-update-respo…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser-update-respo…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build][main] 2 commits: Fixed indentation in README.
by Pier Angelo Vendrame (@pierov) 30 Jan '24
by Pier Angelo Vendrame (@pierov) 30 Jan '24
30 Jan '24
Pier Angelo Vendrame pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
81929890 by Pier Angelo Vendrame at 2024-01-30T10:34:43+01:00
Fixed indentation in README.
- - - - -
e486334e by NoisyCoil at 2024-01-30T10:34:51+01:00
Bug 41038: Add RPM dependencies to README.
Tested in Fedora 39.
- - - - -
1 changed file:
- README
Changes:
=====================================
README
=====================================
@@ -48,6 +48,17 @@ If you are running Debian or Ubuntu, you can install them with:
libtemplate-perl libxml-libxml-perl libxml-writer-perl \
libyaml-libyaml-perl git mercurial uidmap zstd
+If you are running Fedora, CentOS or RHEL, you can install them with:
+
+# dnf install "perl(YAML::XS)" "perl(File::Basename)" "perl(Getopt::Long)" \
+ "perl(Template)" "perl(IO::Handle)" "perl(IO::CaptureOutput)" \
+ "perl(JSON)" "perl(File::Temp)" "perl(Path::Tiny)" \
+ "perl(File::Path)" "perl(File::Slurp)" \
+ "perl(File::Copy::Recursive)" "perl(String::ShellQuote)"
+ "perl(Sort::Versions)" "perl(Digest::SHA)" "perl(Data::UUID)" \
+ "perl(Data::Dump)" "perl(DateTime)" "perl(XML::Writer)" \
+ "perl(Parallel::ForkManager)" perl-ph mercurial git zstd
+
If you are running an Arch based system, you should be able to install them with:
# pacman -S perl-datetime perl-path-tiny perl-yaml perl-yaml-libyaml \
@@ -228,10 +239,9 @@ be done with the following command:
# apt-get install build-essential python3 automake libtool zip unzip \
autoconf2.13 openjdk-11-jdk gettext-base autotools-dev \
- automake autoconf libtool autopoint libssl-dev \
- pkg-config zlib1g-dev libparallel-forkmanager-perl \
- libfile-slurp-perl bzip2 xz-utils apksigner yasm wget \
- bison gyp tcl python3-venv 7zip jq
+ automake autoconf libtool autopoint libssl-dev pkg-config \
+ zlib1g-dev libparallel-forkmanager-perl libfile-slurp-perl bzip2 \
+ xz-utils apksigner yasm wget bison gyp tcl python3-venv 7zip jq
Note that Debian Bullseye requires the bullseye-backports repository to
get the 7zip package.
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/compare/…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/compare/…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build][main] Bug 41072: Set correct updater_url for Mullvad Browser nightly builds
by boklm (@boklm) 30 Jan '24
by boklm (@boklm) 30 Jan '24
30 Jan '24
boklm pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
f1ecbc88 by Nicolas Vigier at 2024-01-30T09:05:17+01:00
Bug 41072: Set correct updater_url for Mullvad Browser nightly builds
- - - - -
1 changed file:
- projects/firefox/config
Changes:
=====================================
projects/firefox/config
=====================================
@@ -89,6 +89,7 @@ targets:
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/'
+ nightly_updates_publish_dir_prefix: mullvadbrowser-
linux-x86_64:
var:
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/f…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/f…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build][main] Bug 41073: Add required packages for container-less build
by boklm (@boklm) 30 Jan '24
by boklm (@boklm) 30 Jan '24
30 Jan '24
boklm pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
056eeab3 by Mynacol at 2024-01-30T08:38:35+01:00
Bug 41073: Add required packages for container-less build
jq and 7zip are both absolutely required, 7zip just recently.
bison, tcl, gyp and python3-venv are scattered around as dependency.
wget is also definitely required, but it's not available in a minimal
docker image.
Besides this, python3, not python2 is required, similarly jdk 11 instead
of 8.
- - - - -
1 changed file:
- README
Changes:
=====================================
README
=====================================
@@ -222,15 +222,19 @@ of containers: the container-image project is still called, but it will
just create an empty file instead of a real container image.
The build without containers is currently only supported for the Android
-builds, and will require that you run Debian Buster and install build
-dependencies for all the components that are built. This can be done
-with the following command:
+builds, and will require that you run Debian Bullseye or Bookworm and
+install build dependencies for all the components that are built. This can
+be done with the following command:
- # apt-get install build-essential python automake libtool zip unzip \
- autoconf2.13 openjdk-8-jdk gettext-base autotools-dev \
+ # apt-get install build-essential python3 automake libtool zip unzip \
+ autoconf2.13 openjdk-11-jdk gettext-base autotools-dev \
automake autoconf libtool autopoint libssl-dev \
pkg-config zlib1g-dev libparallel-forkmanager-perl \
- libfile-slurp-perl bzip2 xz-utils apksigner yasm
+ libfile-slurp-perl bzip2 xz-utils apksigner yasm wget \
+ bison gyp tcl python3-venv 7zip jq
+
+Note that Debian Bullseye requires the bullseye-backports repository to
+get the 7zip package.
Common Build Errors
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/0…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/0…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/firefox-android][firefox-android-115.2.1-13.5-1] fixup! Add Tor integration and UI
by Dan Ballard (@dan) 30 Jan '24
by Dan Ballard (@dan) 30 Jan '24
30 Jan '24
Dan Ballard pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android
Commits:
faf7e9bd by clairehurst at 2024-01-29T16:07:17-07:00
fixup! Add Tor integration and UI
- - - - -
30 changed files:
- − fenix/app/src/beta/ic_launcher_monochrome-playstore.png
- − fenix/app/src/debug/ic_launcher-web.png
- − fenix/app/src/main/ic_launcher-web.png
- fenix/app/src/main/java/org/mozilla/fenix/experiments/view/ResearchSurfaceSurvey.kt
- − fenix/app/src/main/res/drawable-hdpi/ic_logo_wordmark_normal.png
- − fenix/app/src/main/res/drawable-hdpi/ic_logo_wordmark_private.png
- − fenix/app/src/main/res/drawable-hdpi/onboarding_default_browser.webp
- − fenix/app/src/main/res/drawable-hdpi/onboarding_notification.webp
- − fenix/app/src/main/res/drawable-hdpi/onboarding_sync.webp
- − fenix/app/src/main/res/drawable-ldrtl/onboarding_dark_theme.xml
- − fenix/app/src/main/res/drawable-ldrtl/onboarding_light_theme.xml
- − fenix/app/src/main/res/drawable-mdpi/ic_logo_wordmark_normal.png
- − fenix/app/src/main/res/drawable-mdpi/ic_logo_wordmark_private.png
- − fenix/app/src/main/res/drawable-night/ic_logo_wordmark_normal.xml
- − fenix/app/src/main/res/drawable-xhdpi/ic_logo_wordmark_normal.png
- − fenix/app/src/main/res/drawable-xhdpi/ic_logo_wordmark_private.png
- − fenix/app/src/main/res/drawable-xhdpi/onboarding_default_browser.webp
- − fenix/app/src/main/res/drawable-xhdpi/onboarding_notification.webp
- − fenix/app/src/main/res/drawable-xhdpi/onboarding_sync.webp
- − fenix/app/src/main/res/drawable-xxhdpi/ic_logo_wordmark_normal.png
- − fenix/app/src/main/res/drawable-xxhdpi/ic_logo_wordmark_private.png
- − fenix/app/src/main/res/drawable-xxhdpi/onboarding_default_browser.webp
- − fenix/app/src/main/res/drawable-xxhdpi/onboarding_notification.webp
- − fenix/app/src/main/res/drawable-xxhdpi/onboarding_sync.webp
- − fenix/app/src/main/res/drawable-xxxhdpi/ic_logo_wordmark_normal.png
- − fenix/app/src/main/res/drawable-xxxhdpi/ic_logo_wordmark_private.png
- − fenix/app/src/main/res/drawable/ic_firefox.xml
- − fenix/app/src/main/res/drawable/ic_launcher_monochrome.xml
- − fenix/app/src/main/res/drawable/ic_scan.xml
- − fenix/app/src/main/res/drawable/ic_wordmark_logo.png
The diff was not included because it is too large.
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/faf…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/faf…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.7.0esr-13.5-1] 4 commits: fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in...
by richard (@richard) 29 Jan '24
by richard (@richard) 29 Jan '24
29 Jan '24
richard pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
e16caa30 by Henry Wilkes at 2024-01-29T18:34:30+00:00
fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
Bug 41913: Add basic validation to user provided bridge dialog, and a
confirmation step.
- - - - -
6fe742ee by Henry Wilkes at 2024-01-29T18:34:30+00:00
fixup! Tor Browser strings
Bug 41913: Add strings for user provided bridge dialog.
- - - - -
7abc2cc1 by Henry Wilkes at 2024-01-29T18:34:30+00:00
fixup! Bug 40597: Implement TorSettings module
Bug 41913: Add public validateBridgeLines method.
- - - - -
fd4565d1 by Henry Wilkes at 2024-01-29T18:34:30+00:00
fixup! Add TorStrings module for localization
Bug 41913: Remove old strings for user provided bridge addresses.
- - - - -
12 changed files:
- browser/components/preferences/preferences.xhtml
- + browser/components/torpreferences/content/bridgemoji/BridgeEmoji.js
- browser/components/torpreferences/content/connectionPane.js
- browser/components/torpreferences/content/connectionPane.xhtml
- browser/components/torpreferences/content/provideBridgeDialog.js
- browser/components/torpreferences/content/provideBridgeDialog.xhtml
- browser/components/torpreferences/content/torPreferences.css
- browser/components/torpreferences/jar.mn
- browser/locales/en-US/browser/tor-browser.ftl
- toolkit/modules/TorSettings.sys.mjs
- toolkit/modules/TorStrings.sys.mjs
- toolkit/torbutton/chrome/locale/en-US/settings.properties
Changes:
=====================================
browser/components/preferences/preferences.xhtml
=====================================
@@ -70,6 +70,7 @@
<script type="module" src="chrome://global/content/elements/moz-support-link.mjs"/>
<script src="chrome://browser/content/migration/migration-wizard.mjs" type="module"></script>
<script type="module" src="chrome://global/content/elements/moz-toggle.mjs"/>
+ <script src="chrome://browser/content/torpreferences/bridgemoji/BridgeEmoji.js"/>
</head>
<html:body xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
=====================================
browser/components/torpreferences/content/bridgemoji/BridgeEmoji.js
=====================================
@@ -0,0 +1,199 @@
+"use strict";
+
+{
+ /**
+ * Element to display a single bridge emoji, with a localized name.
+ */
+ class BridgeEmoji extends HTMLElement {
+ static #activeInstances = new Set();
+ static #observer(subject, topic, data) {
+ if (topic === "intl:app-locales-changed") {
+ BridgeEmoji.#updateEmojiLangCode();
+ }
+ }
+
+ static #addActiveInstance(inst) {
+ if (this.#activeInstances.size === 0) {
+ Services.obs.addObserver(this.#observer, "intl:app-locales-changed");
+ this.#updateEmojiLangCode();
+ }
+ this.#activeInstances.add(inst);
+ }
+
+ static #removeActiveInstance(inst) {
+ this.#activeInstances.delete(inst);
+ if (this.#activeInstances.size === 0) {
+ Services.obs.removeObserver(this.#observer, "intl:app-locales-changed");
+ }
+ }
+
+ /**
+ * The language code for emoji annotations.
+ *
+ * null if unset.
+ *
+ * @type {string?}
+ */
+ static #emojiLangCode = null;
+ /**
+ * A promise that resolves to two JSON structures for bridge-emojis.json and
+ * annotations.json, respectively.
+ *
+ * @type {Promise}
+ */
+ static #emojiPromise = Promise.all([
+ fetch(
+ "chrome://browser/content/torpreferences/bridgemoji/bridge-emojis.json"
+ ).then(response => response.json()),
+ fetch(
+ "chrome://browser/content/torpreferences/bridgemoji/annotations.json"
+ ).then(response => response.json()),
+ ]);
+
+ static #unknownStringPromise = null;
+
+ /**
+ * Update #emojiLangCode.
+ */
+ static async #updateEmojiLangCode() {
+ let langCode;
+ const emojiAnnotations = (await BridgeEmoji.#emojiPromise)[1];
+ // Find the first desired locale we have annotations for.
+ // Add "en" as a fallback.
+ for (const bcp47 of [...Services.locale.appLocalesAsBCP47, "en"]) {
+ langCode = bcp47;
+ if (langCode in emojiAnnotations) {
+ break;
+ }
+ // Remove everything after the dash, if there is one.
+ langCode = bcp47.replace(/-.*/, "");
+ if (langCode in emojiAnnotations) {
+ break;
+ }
+ }
+ if (langCode !== this.#emojiLangCode) {
+ this.#emojiLangCode = langCode;
+ this.#unknownStringPromise = document.l10n.formatValue(
+ "tor-bridges-emoji-unknown"
+ );
+ for (const inst of this.#activeInstances) {
+ inst.update();
+ }
+ }
+ }
+
+ /**
+ * Update the bridge emoji to show their corresponding emoji with an
+ * annotation that matches the current locale.
+ */
+ async update() {
+ if (!this.#active) {
+ return;
+ }
+
+ if (!BridgeEmoji.#emojiLangCode) {
+ // No lang code yet, wait until it is updated.
+ return;
+ }
+
+ const doc = this.ownerDocument;
+ const [unknownString, [emojiList, emojiAnnotations]] = await Promise.all([
+ BridgeEmoji.#unknownStringPromise,
+ BridgeEmoji.#emojiPromise,
+ ]);
+
+ const emoji = emojiList[this.#index];
+ let emojiName;
+ if (!emoji) {
+ // Unexpected.
+ this.#img.removeAttribute("src");
+ } else {
+ const cp = emoji.codePointAt(0).toString(16);
+ this.#img.setAttribute(
+ "src",
+ `chrome://browser/content/torpreferences/bridgemoji/svgs/${cp}.svg`
+ );
+ emojiName = emojiAnnotations[BridgeEmoji.#emojiLangCode][cp];
+ }
+ if (!emojiName) {
+ doc.defaultView.console.error(`No emoji for index ${this.#index}`);
+ emojiName = unknownString;
+ }
+ doc.l10n.setAttributes(this, "tor-bridges-emoji-cell", {
+ emojiName,
+ });
+ }
+
+ /**
+ * The index for this bridge emoji.
+ *
+ * @type {integer?}
+ */
+ #index = null;
+ /**
+ * Whether we are active (i.e. in the DOM).
+ *
+ * @type {boolean}
+ */
+ #active = false;
+ /**
+ * The image element.
+ *
+ * @type {HTMLImgElement?}
+ */
+ #img = null;
+
+ constructor(index) {
+ super();
+ this.#index = index;
+ }
+
+ connectedCallback() {
+ if (!this.#img) {
+ this.#img = this.ownerDocument.createElement("img");
+ this.#img.classList.add("tor-bridges-emoji-icon");
+ this.#img.setAttribute("alt", "");
+ this.appendChild(this.#img);
+ }
+
+ this.#active = true;
+ BridgeEmoji.#addActiveInstance(this);
+ this.update();
+ }
+
+ disconnectedCallback() {
+ this.#active = false;
+ BridgeEmoji.#removeActiveInstance(this);
+ }
+
+ /**
+ * Create four bridge emojis for the given address.
+ *
+ * @param {string} bridgeLine - The bridge address.
+ *
+ * @returns {BridgeEmoji[4]} - The bridge emoji elements.
+ */
+ static createForAddress(bridgeLine) {
+ // JS uses UTF-16. While most of these emojis are surrogate pairs, a few
+ // ones fit one UTF-16 character. So we could not use neither indices,
+ // nor substr, nor some function to split the string.
+ // FNV-1a implementation that is compatible with other languages
+ const prime = 0x01000193;
+ const offset = 0x811c9dc5;
+ let hash = offset;
+ const encoder = new TextEncoder();
+ for (const byte of encoder.encode(bridgeLine)) {
+ hash = Math.imul(hash ^ byte, prime);
+ }
+
+ return [
+ ((hash & 0x7f000000) >> 24) | (hash < 0 ? 0x80 : 0),
+ (hash & 0x00ff0000) >> 16,
+ (hash & 0x0000ff00) >> 8,
+ hash & 0x000000ff,
+ ].map(index => new BridgeEmoji(index));
+ }
+ }
+
+ customElements.define("tor-bridge-emoji", BridgeEmoji);
+}
=====================================
browser/components/torpreferences/content/connectionPane.js
=====================================
@@ -299,12 +299,10 @@ const gBridgeGrid = {
this._active = true;
- Services.obs.addObserver(this, "intl:app-locales-changed");
Services.obs.addObserver(this, TorProviderTopics.BridgeChanged);
this._grid.classList.add("grid-active");
- this._updateEmojiLangCode();
this._updateConnectedBridge();
},
@@ -322,7 +320,6 @@ const gBridgeGrid = {
this._grid.classList.remove("grid-active");
- Services.obs.removeObserver(this, "intl:app-locales-changed");
Services.obs.removeObserver(this, TorProviderTopics.BridgeChanged);
},
@@ -337,9 +334,6 @@ const gBridgeGrid = {
this._updateRows();
}
break;
- case "intl:app-locales-changed":
- this._updateEmojiLangCode();
- break;
case TorProviderTopics.BridgeChanged:
this._updateConnectedBridge();
break;
@@ -573,97 +567,6 @@ const gBridgeGrid = {
}
},
- /**
- * The language code for emoji annotations.
- *
- * null if unset.
- *
- * @type {string?}
- */
- _emojiLangCode: null,
- /**
- * A promise that resolves to two JSON structures for bridge-emojis.json and
- * annotations.json, respectively.
- *
- * @type {Promise}
- */
- _emojiPromise: Promise.all([
- fetch(
- "chrome://browser/content/torpreferences/bridgemoji/bridge-emojis.json"
- ).then(response => response.json()),
- fetch(
- "chrome://browser/content/torpreferences/bridgemoji/annotations.json"
- ).then(response => response.json()),
- ]),
-
- /**
- * Update _emojiLangCode.
- */
- async _updateEmojiLangCode() {
- let langCode;
- const emojiAnnotations = (await this._emojiPromise)[1];
- // Find the first desired locale we have annotations for.
- // Add "en" as a fallback.
- for (const bcp47 of [...Services.locale.appLocalesAsBCP47, "en"]) {
- langCode = bcp47;
- if (langCode in emojiAnnotations) {
- break;
- }
- // Remove everything after the dash, if there is one.
- langCode = bcp47.replace(/-.*/, "");
- if (langCode in emojiAnnotations) {
- break;
- }
- }
- if (langCode !== this._emojiLangCode) {
- this._emojiLangCode = langCode;
- for (const row of this._rows) {
- this._updateRowEmojis(row);
- }
- }
- },
-
- /**
- * Update the bridge emojis to show their corresponding emoji with an
- * annotation that matches the current locale.
- *
- * @param {BridgeGridRow} row - The row to update the emojis of.
- */
- async _updateRowEmojis(row) {
- if (!this._emojiLangCode) {
- // No lang code yet, wait until it is updated.
- return;
- }
-
- const [emojiList, emojiAnnotations] = await this._emojiPromise;
- const unknownString = await document.l10n.formatValue(
- "tor-bridges-emoji-unknown"
- );
-
- for (const { cell, img, index } of row.emojis) {
- const emoji = emojiList[index];
- let emojiName;
- if (!emoji) {
- // Unexpected.
- img.removeAttribute("src");
- } else {
- const cp = emoji.codePointAt(0).toString(16);
- img.setAttribute(
- "src",
- `chrome://browser/content/torpreferences/bridgemoji/svgs/${cp}.svg`
- );
- emojiName = emojiAnnotations[this._emojiLangCode][cp];
- }
- if (!emojiName) {
- console.error(`No emoji for index ${index}`);
- emojiName = unknownString;
- }
- document.l10n.setAttributes(cell, "tor-bridges-emoji-cell", {
- emojiName,
- });
- }
- },
-
/**
* Create a new row for the grid.
*
@@ -688,23 +591,14 @@ const gBridgeGrid = {
};
const emojiBlock = row.element.querySelector(".tor-bridges-emojis-block");
- row.emojis = makeBridgeId(bridgeLine).map(index => {
- const cell = document.createElement("span");
- // Each emoji is its own cell, we rely on the fact that makeBridgeId
- // always returns four indices.
+ const BridgeEmoji = customElements.get("tor-bridge-emoji");
+ for (const cell of BridgeEmoji.createForAddress(bridgeLine)) {
+ // Each emoji is its own cell, we rely on the fact that createForAddress
+ // always returns four elements.
cell.setAttribute("role", "gridcell");
cell.classList.add("tor-bridges-grid-cell", "tor-bridges-emoji-cell");
-
- const img = document.createElement("img");
- img.classList.add("tor-bridges-emoji-icon");
- // Accessible name will be set on the cell itself.
- img.setAttribute("alt", "");
-
- cell.appendChild(img);
- emojiBlock.appendChild(cell);
- // Image and text is set in _updateRowEmojis.
- return { cell, img, index };
- });
+ emojiBlock.append(cell);
+ }
for (const [columnIndex, element] of row.element
.querySelectorAll(".tor-bridges-grid-cell")
@@ -735,7 +629,6 @@ const gBridgeGrid = {
this._initRowMenu(row);
this._updateRowStatus(row);
- this._updateRowEmojis(row);
return row;
},
@@ -1870,13 +1763,13 @@ const gBridgeSettings = {
"chrome://browser/content/torpreferences/provideBridgeDialog.xhtml",
{ mode },
result => {
- if (!result.bridgeStrings) {
+ if (!result.bridges?.length) {
return null;
}
return setTorSettings(() => {
TorSettings.bridges.enabled = true;
TorSettings.bridges.source = TorBridgeSource.UserProvided;
- TorSettings.bridges.bridge_strings = result.bridgeStrings;
+ TorSettings.bridges.bridge_strings = result.bridges;
});
}
);
@@ -2292,32 +2185,3 @@ const gConnectionPane = (function () {
};
return retval;
})(); /* gConnectionPane */
-
-/**
- * Convert the given bridgeString into an array of emoji indices between 0 and
- * 255.
- *
- * @param {string} bridgeString - The bridge string.
- *
- * @returns {integer[]} - A list of emoji indices between 0 and 255.
- */
-function makeBridgeId(bridgeString) {
- // JS uses UTF-16. While most of these emojis are surrogate pairs, a few
- // ones fit one UTF-16 character. So we could not use neither indices,
- // nor substr, nor some function to split the string.
- // FNV-1a implementation that is compatible with other languages
- const prime = 0x01000193;
- const offset = 0x811c9dc5;
- let hash = offset;
- const encoder = new TextEncoder();
- for (const byte of encoder.encode(bridgeString)) {
- hash = Math.imul(hash ^ byte, prime);
- }
-
- return [
- ((hash & 0x7f000000) >> 24) | (hash < 0 ? 0x80 : 0),
- (hash & 0x00ff0000) >> 16,
- (hash & 0x0000ff00) >> 8,
- hash & 0x000000ff,
- ];
-}
=====================================
browser/components/torpreferences/content/connectionPane.xhtml
=====================================
@@ -218,6 +218,7 @@
</html:div>
<html:div
id="tor-bridges-grid-display"
+ class="tor-bridges-grid"
role="grid"
aria-labelledby="tor-bridges-current-heading"
></html:div>
=====================================
browser/components/torpreferences/content/provideBridgeDialog.js
=====================================
@@ -4,14 +4,17 @@ const { TorStrings } = ChromeUtils.importESModule(
"resource://gre/modules/TorStrings.sys.mjs"
);
-const { TorSettings, TorBridgeSource } = ChromeUtils.importESModule(
- "resource://gre/modules/TorSettings.sys.mjs"
-);
+const { TorSettings, TorBridgeSource, validateBridgeLines } =
+ ChromeUtils.importESModule("resource://gre/modules/TorSettings.sys.mjs");
const { TorConnect, TorConnectTopics } = ChromeUtils.importESModule(
"resource://gre/modules/TorConnect.sys.mjs"
);
+const { TorParsers } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorParsers.sys.mjs"
+);
+
const gProvideBridgeDialog = {
init() {
this._result = window.arguments[0];
@@ -33,72 +36,264 @@ const gProvideBridgeDialog = {
document.l10n.setAttributes(document.documentElement, titleId);
- const learnMore = document.createXULElement("label");
- learnMore.className = "learnMore text-link";
- learnMore.setAttribute("is", "text-link");
- learnMore.setAttribute("value", TorStrings.settings.learnMore);
- learnMore.addEventListener("click", () => {
- window.top.openTrustedLinkIn(
- TorStrings.settings.learnMoreBridgesURL,
- "tab"
- );
- });
-
- const pieces = TorStrings.settings.provideBridgeDescription.split("%S");
- document
- .getElementById("torPreferences-provideBridge-description")
- .replaceChildren(pieces[0], learnMore, pieces[1] || "");
+ document.l10n.setAttributes(
+ document.getElementById("user-provide-bridge-textarea-label"),
+ // TODO change string when we can also accept Lox share codes.
+ "user-provide-bridge-dialog-textarea-addresses-label"
+ );
- this._textarea = document.getElementById(
- "torPreferences-provideBridge-textarea"
+ this._dialog = document.getElementById("user-provide-bridge-dialog");
+ this._acceptButton = this._dialog.getButton("accept");
+ this._textarea = document.getElementById("user-provide-bridge-textarea");
+ this._errorEl = document.getElementById(
+ "user-provide-bridge-error-message"
+ );
+ this._resultDescription = document.getElementById(
+ "user-provide-result-description"
+ );
+ this._bridgeGrid = document.getElementById(
+ "user-provide-bridge-grid-display"
);
- this._textarea.setAttribute(
- "placeholder",
- TorStrings.settings.provideBridgePlaceholder
+ this._rowTemplate = document.getElementById(
+ "user-provide-bridge-row-template"
);
- this._textarea.addEventListener("input", () => this.onValueChange());
- if (TorSettings.bridges.source == TorBridgeSource.UserProvided) {
- this._textarea.value = TorSettings.bridges.bridge_strings.join("\n");
+ if (mode === "edit") {
+ // Only expected if the bridge source is UseProvided, but verify to be
+ // sure.
+ if (TorSettings.bridges.source == TorBridgeSource.UserProvided) {
+ this._textarea.value = TorSettings.bridges.bridge_strings.join("\n");
+ }
+ } else {
+ // Set placeholder if not editing.
+ document.l10n.setAttributes(
+ this._textarea,
+ // TODO: change string when we can also accept Lox share codes.
+ "user-provide-bridge-dialog-textarea-addresses"
+ );
}
- const dialog = document.getElementById(
- "torPreferences-provideBridge-dialog"
- );
- dialog.addEventListener("dialogaccept", e => {
- this._result.accepted = true;
- });
+ this._textarea.addEventListener("input", () => this.onValueChange());
- this._acceptButton = dialog.getButton("accept");
+ this._dialog.addEventListener("dialogaccept", event =>
+ this.onDialogAccept(event)
+ );
Services.obs.addObserver(this, TorConnectTopics.StateChange);
- this.onValueChange();
- this.onAcceptStateChange();
+ this.setPage("entry");
+ this.checkValue();
},
uninit() {
Services.obs.removeObserver(this, TorConnectTopics.StateChange);
},
+ /**
+ * Set the page to display.
+ *
+ * @param {string} page - The page to show.
+ */
+ setPage(page) {
+ this._page = page;
+ this._dialog.classList.toggle("show-entry-page", page === "entry");
+ this._dialog.classList.toggle("show-result-page", page === "result");
+ if (page === "entry") {
+ this._textarea.focus();
+ } else {
+ // Move focus to the <xul:window> element.
+ // In particular, we do not want to keep the focus on the (same) accept
+ // button (with now different text).
+ document.documentElement.focus();
+ }
+
+ this.updateAcceptDisabled();
+ this.onAcceptStateChange();
+ },
+
+ /**
+ * Callback for whenever the input value changes.
+ */
onValueChange() {
- // TODO: Do some proper value parsing and error reporting. See
- // tor-browser#40552.
- const value = this._textarea.value.trim();
- this._acceptButton.disabled = !value;
- this._result.bridgeStrings = value;
+ this.updateAcceptDisabled();
+ // Reset errors whenever the value changes.
+ this.updateError(null);
},
+ /**
+ * Callback for whenever the accept button may need to change.
+ */
onAcceptStateChange() {
- const connect = TorConnect.canBeginBootstrap;
- this._result.connect = connect;
-
- this._acceptButton.setAttribute(
- "label",
- connect
- ? TorStrings.settings.bridgeButtonConnect
- : TorStrings.settings.bridgeButtonAccept
+ if (this._page === "entry") {
+ document.l10n.setAttributes(
+ this._acceptButton,
+ "user-provide-bridge-dialog-next-button"
+ );
+ this._result.connect = false;
+ } else {
+ this._acceptButton.removeAttribute("data-l10n-id");
+ const connect = TorConnect.canBeginBootstrap;
+ this._result.connect = connect;
+
+ this._acceptButton.setAttribute(
+ "label",
+ connect
+ ? TorStrings.settings.bridgeButtonConnect
+ : TorStrings.settings.bridgeButtonAccept
+ );
+ }
+ },
+
+ /**
+ * Callback for whenever the accept button's might need to be disabled.
+ */
+ updateAcceptDisabled() {
+ this._acceptButton.disabled =
+ this._page === "entry" && validateBridgeLines(this._textarea.value).empty;
+ },
+
+ /**
+ * Callback for when the accept button is pressed.
+ *
+ * @param {Event} event - The dialogaccept event.
+ */
+ onDialogAccept(event) {
+ if (this._page === "result") {
+ this._result.accepted = true;
+ // Continue to close the dialog.
+ return;
+ }
+ // Prevent closing the dialog.
+ event.preventDefault();
+
+ const bridges = this.checkValue();
+ if (!bridges.length) {
+ // Not valid
+ return;
+ }
+ this._result.bridges = bridges;
+ this.updateResult();
+ this.setPage("result");
+ },
+
+ /**
+ * The current timeout for updating the error.
+ *
+ * @type {integer?}
+ */
+ _updateErrorTimeout: null,
+
+ /**
+ * Update the displayed error.
+ *
+ * @param {object?} error - The error to show, or null if no error should be
+ * shown. Should include the "type" property.
+ */
+ updateError(error) {
+ // First clear the existing error.
+ if (this._updateErrorTimeout !== null) {
+ clearTimeout(this._updateErrorTimeout);
+ }
+ this._updateErrorTimeout = null;
+ this._errorEl.removeAttribute("data-l10n-id");
+ this._errorEl.textContent = "";
+ if (error) {
+ this._textarea.setAttribute("aria-invalid", "true");
+ } else {
+ this._textarea.removeAttribute("aria-invalid");
+ }
+ this._textarea.classList.toggle("invalid-input", !!error);
+ this._errorEl.classList.toggle("show-error", !!error);
+
+ if (!error) {
+ return;
+ }
+
+ let errorId;
+ let errorArgs;
+ switch (error.type) {
+ case "invalid-address":
+ errorId = "user-provide-bridge-dialog-address-error";
+ errorArgs = { line: error.line };
+ break;
+ }
+
+ // Wait a small amount of time to actually set the textContent. Otherwise
+ // the screen reader (tested with Orca) may not pick up on the change in
+ // text.
+ this._updateErrorTimeout = setTimeout(() => {
+ document.l10n.setAttributes(this._errorEl, errorId, errorArgs);
+ }, 500);
+ },
+
+ /**
+ * Check the current value in the textarea.
+ *
+ * @returns {string[]} - The bridge addresses, if the entry is valid.
+ */
+ checkValue() {
+ let bridges = [];
+ let error = null;
+ const validation = validateBridgeLines(this._textarea.value);
+ if (!validation.empty) {
+ // If empty, we just disable the button, rather than show an error.
+ if (validation.errorLines.length) {
+ // Report first error.
+ error = {
+ type: "invalid-address",
+ line: validation.errorLines[0],
+ };
+ } else {
+ bridges = validation.validBridges;
+ }
+ }
+ this.updateError(error);
+ return bridges;
+ },
+
+ /**
+ * Update the shown result on the last page.
+ */
+ updateResult() {
+ document.l10n.setAttributes(
+ this._resultDescription,
+ // TODO: Use a different id when added through Lox invite.
+ "user-provide-bridge-dialog-result-addresses"
);
+
+ this._bridgeGrid.replaceChildren();
+
+ for (const bridgeLine of this._result.bridges) {
+ let details;
+ try {
+ details = TorParsers.parseBridgeLine(bridgeLine);
+ } catch (e) {
+ console.error(`Detected invalid bridge line: ${bridgeLine}`, e);
+ }
+
+ const rowEl = this._rowTemplate.content.children[0].cloneNode(true);
+
+ const emojiBlock = rowEl.querySelector(".tor-bridges-emojis-block");
+ const BridgeEmoji = customElements.get("tor-bridge-emoji");
+ for (const cell of BridgeEmoji.createForAddress(bridgeLine)) {
+ // Each emoji is its own cell, we rely on the fact that createForAddress
+ // always returns four elements.
+ cell.setAttribute("role", "gridcell");
+ cell.classList.add("tor-bridges-grid-cell", "tor-bridges-emoji-cell");
+ emojiBlock.append(cell);
+ }
+
+ // TODO: properly handle "vanilla" bridges?
+ document.l10n.setAttributes(
+ rowEl.querySelector(".tor-bridges-type-cell"),
+ "tor-bridges-type-prefix",
+ { type: details?.transport ?? "vanilla" }
+ );
+
+ rowEl.querySelector(".tor-bridges-address-cell").textContent = bridgeLine;
+
+ this._bridgeGrid.append(rowEl);
+ }
},
observe(subject, topic, data) {
=====================================
browser/components/torpreferences/content/provideBridgeDialog.xhtml
=====================================
@@ -8,22 +8,77 @@
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"
>
- <dialog id="torPreferences-provideBridge-dialog" buttons="accept,cancel">
+ <dialog
+ id="user-provide-bridge-dialog"
+ buttons="accept,cancel"
+ class="show-entry-page"
+ >
<linkset>
<html:link rel="localization" href="browser/tor-browser.ftl" />
</linkset>
+ <script src="chrome://browser/content/torpreferences/bridgemoji/BridgeEmoji.js" />
<script src="chrome://browser/content/torpreferences/provideBridgeDialog.js" />
- <description>
- <html:div id="torPreferences-provideBridge-description"
- >​<br />​</html:div
- >
- </description>
- <html:textarea
- id="torPreferences-provideBridge-textarea"
- multiline="true"
- rows="3"
- />
+ <html:div id="user-provide-bridge-entry-page">
+ <description id="user-provide-bridge-description">
+ <html:span
+ class="tail-with-learn-more"
+ data-l10n-id="user-provide-bridge-dialog-description"
+ ></html:span>
+ <label
+ is="text-link"
+ class="learnMore text-link"
+ href="about:manual#bridges"
+ useoriginprincipal="true"
+ data-l10n-id="user-provide-bridge-dialog-learn-more"
+ />
+ </description>
+ <html:label
+ id="user-provide-bridge-textarea-label"
+ for="user-provide-bridge-textarea"
+ ></html:label>
+ <html:textarea
+ id="user-provide-bridge-textarea"
+ multiline="true"
+ rows="3"
+ aria-describedby="user-provide-bridge-description"
+ aria-errormessage="user-provide-bridge-error-message"
+ />
+ <html:div id="user-provide-bridge-message-area">
+ <html:span
+ id="user-provide-bridge-error-message"
+ aria-live="assertive"
+ ></html:span>
+ </html:div>
+ </html:div>
+ <html:div id="user-provide-bridge-result-page">
+ <description id="user-provide-result-description" />
+ <!-- NOTE: Unlike #tor-bridge-grid-display, this element is not
+ - interactive, and not a tab-stop. So we use the "table" role rather
+ - than "grid".
+ - NOTE: Using a <html:table> would not allow us the same structural
+ - freedom, so we use a generic div and add the semantics manually. -->
+ <html:div
+ id="user-provide-bridge-grid-display"
+ class="tor-bridges-grid"
+ role="table"
+ ></html:div>
+ <html:template id="user-provide-bridge-row-template">
+ <html:div class="tor-bridges-grid-row" role="row">
+ <html:span
+ class="tor-bridges-type-cell tor-bridges-grid-cell"
+ role="gridcell"
+ ></html:span>
+ <html:span class="tor-bridges-emojis-block" role="none"></html:span>
+ <html:span class="tor-bridges-grid-end-block" role="none">
+ <html:span
+ class="tor-bridges-address-cell tor-bridges-grid-cell"
+ role="gridcell"
+ ></html:span>
+ </html:span>
+ </html:div>
+ </html:template>
+ </html:div>
</dialog>
</window>
=====================================
browser/components/torpreferences/content/torPreferences.css
=====================================
@@ -270,11 +270,14 @@
grid-area: description;
}
-#tor-bridges-grid-display {
+.tor-bridges-grid {
display: grid;
grid-template-columns: max-content repeat(4, max-content) 1fr;
--tor-bridges-grid-column-gap: 8px;
--tor-bridges-grid-column-short-gap: 4px;
+ /* For #tor-bridges-grid-display we want each grid item to have the same
+ * height so that their focus outlines match. */
+ align-items: stretch;
}
#tor-bridges-grid-display:not(.grid-active) {
@@ -283,11 +286,12 @@
.tor-bridges-grid-row {
/* We want each row to act as a row of three items in the
- * #tor-bridges-grid-display grid layout.
+ * .tor-bridges-grid grid layout.
* We also want a 16px spacing between rows, and 8px spacing between columns,
- * which are outside the .tor-bridges-grid-cell's border area. So that
- * clicking these gaps will not focus any item, and their focus outlines do
- * not overlap.
+ * which are outside the .tor-bridges-grid-cell's border area.
+ *
+ * For #tor-bridges-grid-display this should ensure that clicking these gaps
+ * will not focus any item, and their focus outlines do not overlap.
* Moreover, we also want each row to show its .tor-bridges-options-cell when
* the .tor-bridges-grid-row has :hover.
*
@@ -311,7 +315,8 @@
padding-block: 8px;
}
-.tor-bridges-grid-cell:focus-visible {
+#tor-bridges-grid-display .tor-bridges-grid-cell:focus-visible {
+ /* #tor-bridges-grid-display has focus management for its cells. */
outline: var(--in-content-focus-outline);
outline-offset: var(--in-content-focus-outline-offset);
}
@@ -662,8 +667,77 @@ groupbox#torPreferences-bridges-group textarea {
}
/* Provide bridge dialog */
-#torPreferences-provideBridge-textarea {
- margin-top: 16px;
+
+#user-provide-bridge-dialog:not(.show-entry-page) #user-provide-bridge-entry-page {
+ display: none;
+}
+
+#user-provide-bridge-dialog:not(.show-result-page) #user-provide-bridge-result-page {
+ display: none;
+}
+
+#user-provide-bridge-entry-page {
+ flex: 1 0 auto;
+ display: flex;
+ flex-direction: column;
+}
+
+#user-provide-bridge-description {
+ flex: 0 0 auto;
+}
+
+#user-provide-bridge-textarea-label {
+ margin-block: 16px 6px;
+ flex: 0 0 auto;
+ align-self: start;
+}
+
+#user-provide-bridge-textarea {
+ flex: 1 0 auto;
+ align-self: stretch;
+ line-height: 1.3;
+ margin: 0;
+}
+
+#user-provide-bridge-message-area {
+ flex: 0 0 auto;
+ margin-block: 8px 12px;
+ align-self: end;
+}
+
+#user-provide-bridge-message-area::after {
+ /* Zero width space, to ensure we are always one line high. */
+ content: "\200B";
+}
+
+#user-provide-bridge-textarea.invalid-input {
+ border-color: var(--in-content-danger-button-background);
+ outline-color: var(--in-content-danger-button-background);
+}
+
+#user-provide-bridge-error-message {
+ color: var(--in-content-error-text-color);
+}
+
+#user-provide-bridge-error-message.not(.show-error) {
+ display: none;
+}
+
+#user-provide-bridge-result-page {
+ flex: 1 1 0;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
+}
+
+#user-provide-result-description {
+ flex: 0 0 auto;
+}
+
+#user-provide-bridge-grid-display {
+ flex: 0 1 auto;
+ overflow: auto;
+ margin-block: 8px;
}
/* Connection settings dialog */
=====================================
browser/components/torpreferences/jar.mn
=====================================
@@ -22,6 +22,7 @@ browser.jar:
content/browser/torpreferences/connectionPane.xhtml (content/connectionPane.xhtml)
content/browser/torpreferences/torPreferences.css (content/torPreferences.css)
content/browser/torpreferences/bridge-qr-onion-mask.svg (content/bridge-qr-onion-mask.svg)
+ content/browser/torpreferences/bridgemoji/BridgeEmoji.js (content/bridgemoji/BridgeEmoji.js)
content/browser/torpreferences/bridgemoji/bridge-emojis.json (content/bridgemoji/bridge-emojis.json)
content/browser/torpreferences/bridgemoji/annotations.json (content/bridgemoji/annotations.json)
content/browser/torpreferences/bridgemoji/svgs/ (content/bridgemoji/svgs/*.svg)
=====================================
browser/locales/en-US/browser/tor-browser.ftl
=====================================
@@ -176,3 +176,19 @@ user-provide-bridge-dialog-add-title =
# Used when the user is replacing their existing bridges with new ones.
user-provide-bridge-dialog-replace-title =
.title = Replace your bridges
+# Description shown when adding new bridges, replacing existing bridges, or editing existing bridges.
+user-provide-bridge-dialog-description = Use bridges provided by a trusted organisation or someone you know.
+# "Learn more" link shown in the "Add new bridges"/"Replace your bridges" dialog.
+user-provide-bridge-dialog-learn-more = Learn more
+# Short accessible name for the bridge addresses text area.
+user-provide-bridge-dialog-textarea-addresses-label = Bridge addresses
+# Placeholder shown when adding new bridge addresses.
+user-provide-bridge-dialog-textarea-addresses =
+ .placeholder = Paste your bridge addresses here
+# Error shown when one of the address lines is invalid.
+# $line (Number) - The line number for the invalid address.
+user-provide-bridge-dialog-address-error = Incorrectly formatted bridge address on line { $line }.
+
+user-provide-bridge-dialog-result-addresses = The following bridges were entered by you.
+user-provide-bridge-dialog-next-button =
+ .label = Next
=====================================
toolkit/modules/TorSettings.sys.mjs
=====================================
@@ -9,6 +9,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs",
TorProviderTopics: "resource://gre/modules/TorProviderBuilder.sys.mjs",
Lox: "resource://gre/modules/Lox.sys.mjs",
+ TorParsers: "resource://gre/modules/TorParsers.sys.mjs",
});
ChromeUtils.defineLazyGetter(lazy, "logger", () => {
@@ -103,26 +104,61 @@ export const TorProxyType = Object.freeze({
* Split a blob of bridge lines into an array with single lines.
* Lines are delimited by \r\n or \n and each bridge string can also optionally
* have 'bridge' at the beginning.
- * We split the text by \r\n, we trim the lines, remove the bridge prefix and
- * filter out any remaiing empty item.
+ * We split the text by \r\n, we trim the lines, remove the bridge prefix.
*
- * @param {string} aBridgeStrings The text with the lines
+ * @param {string} bridgeLines The text with the lines
* @returns {string[]} An array where each bridge line is an item
*/
-function parseBridgeStrings(aBridgeStrings) {
- // replace carriage returns ('\r') with new lines ('\n')
- aBridgeStrings = aBridgeStrings.replace(/\r/g, "\n");
- // then replace contiguous new lines ('\n') with a single one
- aBridgeStrings = aBridgeStrings.replace(/[\n]+/g, "\n");
-
+function splitBridgeLines(bridgeLines) {
// Split on the newline and for each bridge string: trim, remove starting
// 'bridge' string.
- // Finally, discard entries that are empty strings; empty strings could occur
- // if we receive a new line containing only whitespace.
- const splitStrings = aBridgeStrings.split("\n");
- return splitStrings
- .map(val => val.trim().replace(/^bridge\s+/i, ""))
- .filter(bridgeString => bridgeString !== "");
+ // Replace whitespace with standard " ".
+ // NOTE: We only remove the bridge string part if it is followed by a
+ // non-whitespace.
+ return bridgeLines.split(/\r?\n/).map(val =>
+ val
+ .trim()
+ .replace(/^bridge\s+(\S)/i, "$1")
+ .replace(/\s+/, " ")
+ );
+}
+
+/**
+ * @typedef {Object} BridgeValidationResult
+ *
+ * @property {integer[]} errorLines - The lines that contain errors. Counting
+ * from 1.
+ * @property {boolean} empty - Whether the given string contains no bridges.
+ * @property {string[]} validBridges - The valid bridge lines found.
+ */
+/**
+ * Validate the given bridge lines.
+ *
+ * @param {string} bridgeLines - The bridge lines to validate, separated by
+ * newlines.
+ *
+ * @returns {BridgeValidationResult}
+ */
+export function validateBridgeLines(bridgeLines) {
+ let empty = true;
+ const errorLines = [];
+ const validBridges = [];
+ for (const [index, bridge] of splitBridgeLines(bridgeLines).entries()) {
+ if (!bridge) {
+ // Empty line.
+ continue;
+ }
+ empty = false;
+ try {
+ // TODO: Have a more comprehensive validation parser.
+ lazy.TorParsers.parseBridgeLine(bridge);
+ } catch {
+ errorLines.push(index + 1);
+ continue;
+ }
+ validBridges.push(bridge);
+ }
+ return { empty, errorLines, validBridges };
}
/**
@@ -269,7 +305,8 @@ class TorSettingsImpl {
if (Array.isArray(val)) {
return [...val];
}
- return parseBridgeStrings(val);
+ // Split the bridge strings, discarding empty.
+ return splitBridgeLines(val).filter(val => val);
},
copy: val => [...val],
equal: (val1, val2) => this.#arrayEqual(val1, val2),
=====================================
toolkit/modules/TorStrings.sys.mjs
=====================================
@@ -139,10 +139,6 @@ const Loader = {
solveTheCaptcha: "Solve the CAPTCHA to request a bridge.",
captchaTextboxPlaceholder: "Enter the characters from the image",
incorrectCaptcha: "The solution is not correct. Please try again.",
- // Provide bridge dialog
- provideBridgeDescription:
- "Add a bridge provided by a trusted organization or someone you know. If you don’t have a bridge, you can request one from the Tor Project. %S",
- provideBridgePlaceholder: "type address:port (one per line)",
// Connection settings dialog
connectionSettingsDialogTitle: "Connection Settings",
connectionSettingsDialogHeader:
=====================================
toolkit/torbutton/chrome/locale/en-US/settings.properties
=====================================
@@ -75,10 +75,6 @@ settings.solveTheCaptcha=Solve the CAPTCHA to request a bridge.
settings.captchaTextboxPlaceholder=Enter the characters from the image
settings.incorrectCaptcha=The solution is not correct. Please try again.
-# Translation note: %S is a Learn more link.
-settings.provideBridgeDescription=Add a bridge provided by a trusted organization or someone you know. If you don’t have a bridge, you can request one from the Tor Project. %S
-settings.provideBridgePlaceholder=type address:port (one per line)
-
# Connection settings dialog
settings.connectionSettingsDialogTitle=Connection Settings
settings.connectionSettingsDialogHeader=Configure how Tor Browser connects to the Internet
@@ -126,3 +122,6 @@ settings.bridgeAddManually=Add a Bridge Manually…
# Provide bridge dialog
settings.provideBridgeTitleAdd=Add a Bridge Manually
+# Translation note: %S is a Learn more link.
+settings.provideBridgeDescription=Add a bridge provided by a trusted organization or someone you know. If you don’t have a bridge, you can request one from the Tor Project. %S
+settings.provideBridgePlaceholder=type address:port (one per line)
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/366c81…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/366c81…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build] Pushed new tag mb-13.5a4-build1
by richard (@richard) 29 Jan '24
by richard (@richard) 29 Jan '24
29 Jan '24
richard pushed new tag mb-13.5a4-build1 at The Tor Project / Applications / tor-browser-build
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/tree/mb-…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/mullvad-browser] Pushed new tag mullvad-browser-115.7.0esr-13.5-1-build2
by richard (@richard) 29 Jan '24
by richard (@richard) 29 Jan '24
29 Jan '24
richard pushed new tag mullvad-browser-115.7.0esr-13.5-1-build2 at The Tor Project / Applications / Mullvad Browser
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/tree/mullv…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build][main] Bug 41051, 41052: Tor, Mullvad Browser 13.5a4 Release Prep
by richard (@richard) 29 Jan '24
by richard (@richard) 29 Jan '24
29 Jan '24
richard pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
ecb3b0bf by Richard Pospesel at 2024-01-29T17:40:35+00:00
Bug 41051,41052: Tor,Mullvad Browser 13.5a4 Release Prep
- - - - -
12 changed files:
- projects/browser/Bundle-Data/Docs-MB/ChangeLog.txt
- projects/browser/Bundle-Data/Docs-TBB/ChangeLog.txt
- projects/browser/allowed_addons.json
- projects/browser/config
- projects/firefox-android/config
- projects/firefox/config
- projects/geckoview/config
- projects/go/config
- projects/manual/config
- projects/translation/config
- projects/zlib/config
- rbm.conf
Changes:
=====================================
projects/browser/Bundle-Data/Docs-MB/ChangeLog.txt
=====================================
@@ -1,3 +1,47 @@
+Mullvad Browser 13.5a4 - January 29 2024
+ * All Platforms
+ * Updated Firefox to 115.7.0esr
+ * Updated uBlock Origin to 1.55.0
+ * Bug 261: Rebase Mullvad Browser Alpha onto Firefox 115.7.0esr [mullvad-browser]
+ * Bug 41917: Make the appearance of letterboxing look more intentional [tor-browser]
+ * Bug 42374: spoof english leaks via numberingSystem: numbers (non-latn) or decimal separator (latn) [tor-browser]
+ * Build System
+ * All Platforms
+ * Bug 42337: Enable GeckoDriver for all desktop platforms [tor-browser]
+ * Bug 41037: Set time on signing machine before starting signing [tor-browser-build]
+ * Bug 41045: Dump more information about build times on Firefox [tor-browser-build]
+ * Bug 41056: Make it possible to use templates in var/torbrowser_incremental_from [tor-browser-build]
+ * Bug 41057: make fetch is not fetching mullvad repo [tor-browser-build]
+ * Bug 41059: Update keyring/torbrowser.gpg with updated key [tor-browser-build]
+ * Windows
+ * Bug 40606: Use Clang to compile NSIS [tor-browser-build]
+ * Bug 40900: Update NSIS to 3.09 [tor-browser-build]
+ * Bug 41065: Do a cleanup of the NSIS script [tor-browser-build]
+ * Linux
+ * Bug 41046: Use the final path for Linux debug symbols [tor-browser-build]
+
+Mullvad Browser 13.0.9 - January 23 2024
+ * All Platforms
+ * Updated Firefox to 115.7.0esr
+ * Updated uBlock Origin to 1.55.0
+ * Bug 249: BrowserHost has null mRoot when applying initial window size in debug [mullvad-browser]
+ * Bug 260: Rebase Mullvad Browser Stable onto Firefox 115.7.0esr [mullvad-browser]
+ * Bug 42189: Assertion failure: the value of mPrivateBrowsingId in the loadContext and in the loadInfo are not the same! [tor-browser]
+ * Bug 41044: Add tbb_version.json-like file for Mullvad Browser [tor-browser-build]
+ * Linux
+ * Bug 41050: Improve the disk leak sanitization on start-$browser [tor-browser-build]
+ * Build System
+ * All Platforms
+ * Bug 41042: Add options to include updates in the changelog scripts [tor-browser-build]
+ * Bug 41043: Create script to push build requests to Mullvad build servers [tor-browser-build]
+ * Bug 41056: Make it possible to use templates in var/torbrowser_incremental_from [tor-browser-build]
+ * Bug 41059: Update keyring/torbrowser.gpg with updated key [tor-browser-build]
+ * Bug 40067: Use --no-verbose wget option when not running in a terminal [rbm]
+ * Windows + macOS
+ * Bug 41016: Switch from bullseye to bookworm for desktop platforms [tor-browser-build]
+ * Windows
+ * Bug 41015: Enable std::filesystem on libc++ on Windows [tor-browser-build]
+
Mullvad Browser 13.5a3 - December 20 2023
* All Platforms
* Updated Firefox to 115.6.0esr
=====================================
projects/browser/Bundle-Data/Docs-TBB/ChangeLog.txt
=====================================
@@ -1,3 +1,77 @@
+Tor Browser 13.5a4 - January 29 2024
+ * All Platforms
+ * Updated zlib to 1.3.1
+ * Updated Snowflake to 2.8.1
+ * Bug 42343: Consume pt_config.json in the browser [tor-browser]
+ * Bug 42348: TorSettings.defaultSettings() removed but still referenced by Moat.sys.mjs [tor-browser]
+ * Bug 42354: Refactor exclusions in ShouldSanitizePreference() to the pref list. [tor-browser]
+ * Bug 42358: Separate the domain fronted requests from Moat [tor-browser]
+ * Bug 42359: Handle firewall and proxy in TorSettings.setSettings [tor-browser]
+ * Bug 42363: Tab thumbnails enhancements [tor-browser]
+ * Bug 42366: Rebase Tor Browser Alpha onto Firefox 115.7.0esr [tor-browser]
+ * Bug 42369: Revert YEC 2023 changes [tor-browser]
+ * Bug 42374: spoof english leaks via numberingSystem: numbers (non-latn) or decimal separator (latn) [tor-browser]
+ * Bug 42384: Regression: quickstart doesn't work anymore [tor-browser]
+ * Bug 41058: Update Snowflake to 2.8.1 [tor-browser-build]
+ * Windows + macOS + Linux
+ * Updated Firefox to 115.7.0esr
+ * Bug 41917: Make the appearance of letterboxing look more intentional [tor-browser]
+ * Bug 42338: Changing circuit programmatically in Tor Browser not working anymore! [tor-browser]
+ * Android
+ * Updated GeckoView to 115.7.0esr
+ * Bug 42252: Plumb down TorConnect commands from firefox-android to GeckoView [tor-browser]
+ * Bug 42346: Crash in firefox-android originating in backported FullScreenNotificationDialog patch [tor-browser]
+ * Bug 42353: Fix Android NoScript automatic updates [tor-browser]
+ * Bug 42355: Fullscreen on Android doesn't hide system bars [tor-browser]
+ * Bug 42367: Backport Android security fixes from Firefox 122 [tor-browser]
+ * Bug 42368: Tor Browser 13.5a3 crashes during start-up because of API26+ methods [tor-browser]
+ * Linux
+ * Bug 42293: Updater is disabled when tor-browser is run by torbrowser-launcher flatpak [tor-browser]
+ * Build System
+ * All Platforms
+ * Updated Go to 1.20.13 and 1.21.6
+ * Bug 41037: Set time on signing machine before starting signing [tor-browser-build]
+ * Bug 41059: Update keyring/torbrowser.gpg with updated key [tor-browser-build]
+ * Bug 41063: Run "file $keyring" in tools/keyring/list-all-keyrings [tor-browser-build]
+ * Bug 40067: Use --no-verbose wget option when not running in a terminal [rbm]
+ * Windows
+ * Bug 40606: Use Clang to compile NSIS [tor-browser-build]
+ * Bug 40900: Update NSIS to 3.09 [tor-browser-build]
+ * Bug 41065: Do a cleanup of the NSIS script [tor-browser-build]
+
+Tor Browser 13.0.9 - January 23 2024
+ * All Platforms
+ * Updated Snowflake to 2.8.1
+ * Bug 42363: Tab thumbnails enhancements [tor-browser]
+ * Bug 42365: Rebase Tor Browser Stable onto Firefox 115.7.0esr [tor-browser]
+ * Bug 42367: Backport Android security fixes from Firefox 122 [tor-browser]
+ * Bug 42369: Revert YEC 2023 changes [tor-browser]
+ * Bug 41058: Update Snowflake to 2.8.1 [tor-browser-build]
+ * Windows + macOS + Linux
+ * Updated Firefox to 115.7.0esr
+ * Bug 42099: Blind cross-origin requests to .tor.onion domains [tor-browser]
+ * Bug 42189: Assertion failure: the value of mPrivateBrowsingId in the loadContext and in the loadInfo are not the same! [tor-browser]
+ * Android
+ * Updated GeckoView to 115.7.0esr
+ * Bug 42313: Enable One UI Sans KR as a possible font for Korean (MozBug 1865238) [tor-browser]
+ * Bug 42324: Onion Location on Android is ignored [tor-browser]
+ * Bug 42346: Crash in firefox-android originating in backported FullScreenNotificationDialog patch [tor-browser]
+ * Bug 42353: Fix Android NoScript automatic updates [tor-browser]
+ * Bug 42355: Fullscreen on Android doesn't hide system bars [tor-browser]
+ * Build System
+ * All Platforms
+ * Updated Go to 1.20.13 and 1.21.6
+ * Bug 41059: Update keyring/torbrowser.gpg with updated key [tor-browser-build]
+ * Bug 41063: Run "file $keyring" in tools/keyring/list-all-keyrings [tor-browser-build]
+ * Windows + macOS + Linux
+ * Bug 41056: Make it possible to use templates in var/torbrowser_incremental_from [tor-browser-build]
+ * Windows + macOS
+ * Bug 41016: Switch from bullseye to bookworm for desktop platforms [tor-browser-build]
+ * Windows
+ * Bug 41015: Enable std::filesystem on libc++ on Windows [tor-browser-build]
+ * Android
+ * Bug 41066: The Android x86 APK for 13.0.9 is too big [tor-browser-build]
+
Tor Browser 13.5a3 - December 22 2023
* All Platforms
* Updated Tor to 0.4.8.10
=====================================
projects/browser/allowed_addons.json
=====================================
@@ -17,7 +17,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/34/9734/13299734/13299734.pn…"
}
],
- "average_daily_users": 1113519,
+ "average_daily_users": 1149777,
"categories": {
"firefox": [
"web-development",
@@ -28,7 +28,7 @@
"contributions_url": "https://opencollective.com/darkreader?utm_content=product-page-contribute&u…",
"created": "2017-09-19T07:03:00Z",
"current_version": {
- "id": 5661222,
+ "id": 5678786,
"compatibility": {
"firefox": {
"min": "54.0",
@@ -39,7 +39,7 @@
"max": "*"
}
},
- "edit_url": "https://addons.mozilla.org/en-US/developers/addon/darkreader/versions/56612…",
+ "edit_url": "https://addons.mozilla.org/en-US/developers/addon/darkreader/versions/56787…",
"is_strict_compatibility_enabled": false,
"license": {
"id": 22,
@@ -50,22 +50,22 @@
"url": "http://www.opensource.org/license/mit"
},
"release_notes": {
- "en-US": "- Improved subdomain handling in Site List.\n- Improved dark theme detection.\n- Fixed page crashes (Slack issue).\n- Fixed Site List migration.\n- Reduced image analysis memory usage.\n- Users' fixes for websites."
+ "en-US": "- Improved dark theme detection.\n- Dynamic mode bug fixes.\n- Users' fixes for websites."
},
- "reviewed": "2023-12-08T12:55:44Z",
- "version": "4.9.73",
+ "reviewed": "2024-01-22T11:18:14Z",
+ "version": "4.9.76",
"files": [
{
- "id": 4205543,
- "created": "2023-12-06T15:41:16Z",
- "hash": "sha256:7c399ff32561886bb80dad0cafaf8f629792b0b71ff1efcf12667e05a2b38f1a",
+ "id": 4223104,
+ "created": "2024-01-17T14:17:21Z",
+ "hash": "sha256:d3afe139928c3c30bd11347c08a3360fa3417be4667c47f3de19fdc0ab92da9f",
"is_restart_required": false,
"is_webextension": true,
"is_mozilla_signed_extension": false,
"platform": "all",
- "size": 682962,
+ "size": 723386,
"status": "public",
- "url": "https://addons.mozilla.org/firefox/downloads/file/4205543/darkreader-4.9.73…",
+ "url": "https://addons.mozilla.org/firefox/downloads/file/4223104/darkreader-4.9.76…",
"permissions": [
"alarms",
"contextMenus",
@@ -143,7 +143,7 @@
},
"is_disabled": false,
"is_experimental": false,
- "last_updated": "2023-12-08T12:55:44Z",
+ "last_updated": "2024-01-22T11:18:14Z",
"name": {
"ar": "Dark Reader",
"bn": "Dark Reader",
@@ -218,10 +218,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.5518,
- "bayesian_average": 4.550675591135547,
- "count": 5306,
- "text_count": 1668
+ "average": 4.5479,
+ "bayesian_average": 4.546785102314431,
+ "count": 5377,
+ "text_count": 1689
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/darkreader/reviews/",
"requires_payment": false,
@@ -318,7 +318,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/darkreader/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/darkreader/versions/",
- "weekly_downloads": 39727
+ "weekly_downloads": 25711
},
"notes": null
},
@@ -334,7 +334,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/56/7656/6937656/6937656.png?…"
}
],
- "average_daily_users": 263643,
+ "average_daily_users": 267473,
"categories": {
"firefox": [
"privacy-security"
@@ -547,10 +547,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.8027,
- "bayesian_average": 4.798106734548776,
- "count": 1384,
- "text_count": 245
+ "average": 4.8014,
+ "bayesian_average": 4.796833851849327,
+ "count": 1400,
+ "text_count": 250
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/decentraleyes/reviews/",
"requires_payment": false,
@@ -635,7 +635,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/decentraleyes/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/decentraleyes/versions/",
- "weekly_downloads": 3543
+ "weekly_downloads": 3594
},
"notes": null
},
@@ -651,7 +651,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/73/4073/5474073/5474073.png?…"
}
],
- "average_daily_users": 1198252,
+ "average_daily_users": 1220177,
"categories": {
"firefox": [
"privacy-security"
@@ -1170,10 +1170,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.7991,
- "bayesian_average": 4.796396010098387,
- "count": 2350,
- "text_count": 445
+ "average": 4.796,
+ "bayesian_average": 4.793312997020196,
+ "count": 2377,
+ "text_count": 449
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-badger17/reviews/",
"requires_payment": false,
@@ -1197,7 +1197,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-badger17/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-badger17/versions/",
- "weekly_downloads": 22327
+ "weekly_downloads": 25171
},
"notes": null
},
@@ -1213,7 +1213,7 @@
"picture_url": null
}
],
- "average_daily_users": 7397430,
+ "average_daily_users": 7634996,
"categories": {
"firefox": [
"privacy-security"
@@ -1222,7 +1222,7 @@
"contributions_url": "",
"created": "2015-04-25T07:26:22Z",
"current_version": {
- "id": 5654508,
+ "id": 5672315,
"compatibility": {
"firefox": {
"min": "78.0",
@@ -1233,7 +1233,7 @@
"max": "*"
}
},
- "edit_url": "https://addons.mozilla.org/en-US/developers/addon/ublock-origin/versions/56…",
+ "edit_url": "https://addons.mozilla.org/en-US/developers/addon/ublock-origin/versions/56…",
"is_strict_compatibility_enabled": false,
"license": {
"id": 6,
@@ -1244,23 +1244,24 @@
"url": "http://www.gnu.org/licenses/gpl-3.0.html"
},
"release_notes": {
- "en-US": "See complete release notes for <a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/4c736806dc9702f9496c1c…" rel=\"nofollow\">1.54.0</a>.\n\n<b>Fixes / changes</b>\n\n<ul><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/30ee045a42c04a557ec92d…" rel=\"nofollow\">Enable path for native <code>has()</code> selector in Firefox</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/26aaa3263afd1e6e450a7f…" rel=\"nofollow\">Allow scriptlets to be injected in <code>about:blank</code></a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/5967388a2432967ee63e77…" rel=\"nofollow\">Fix faulty <code>as</code> vararg in <code>set-constant</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/b9a3ce2fd67895cc3fd06f…" rel=\"nofollow\">Add support to redirect to <code>noop.json</code></a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/1a7fcce826cb83449490e3…" rel=\"nofollow\">More improvements to the <code>google-ima</code> shim script</a> (by @kzar)</li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/56d921f7e251fb313a4be0…" rel=\"nofollow\">All exceptions filters are exempt from requiring a trusted source</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/b3b9c520dd7fef26a4f129…" rel=\"nofollow\">Add <code>trusted-set-session-storage-item</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/5f347a4a217555ac7ff920…" rel=\"nofollow\">Allow the use of quotes in <code>set-cookie</code> scriptlet </a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/fe9490248b43262e2613b2…" rel=\"nofollow\">Allow the use of quotes in <code>set-(local|session)-storage-item</code></a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/92d58a934e2392a346a587…" rel=\"nofollow\">Add ability to trigger cookie removal on specific events</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/23e952e408915752c90dc3…" rel=\"nofollow\">Ensure CSSTree does not hold a reference onto last parsed string</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/302676f334820cdfe567f7…" rel=\"nofollow\">Lower minimum Expires value to 4h</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/03ac48dee7ecbf33ac2dd4…" rel=\"nofollow\">Properly reset needle length in unserialized buffer</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/d4babab0e0c4b624992f8f…" rel=\"nofollow\">Add additional flags to regional lists</a> (by @DandelionSprout)</li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/a09bd04e017892dd0b0d12…" rel=\"nofollow\">Harden scriptlets which need to serialize function code into string</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/1a5be5c8aa0baa49879f92…" rel=\"nofollow\">Reset <code>g</code> regexes before use in <code>rmnt</code>/<code>rpnt</code> scriptlets</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/f2e3dd373c3a474ca27bad…" rel=\"nofollow\">Apply response filtering according to mime type</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/12cfcbade6a208e02352fd…" rel=\"nofollow\">Add t/f to set-cookie</a> (by @ryanbr)</li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/7856310df6fe39bff4e1b0…" rel=\"nofollow\">Have <code>urltransform=</code> use the same syntax as <code>replace=</code></a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/520b2f8c295d638b0c72f5…" rel=\"nofollow\">Implement network filter option <code>replace=</code></a></li><li>...</li></ul>\n<a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/3f4f5634b3bdd26c8e335f…" rel=\"nofollow\">Commits history since last version</a>"
+ "en-US": "See complete release notes for <a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/514b85ddd154153a63fe9c…" rel=\"nofollow\">1.55.0</a>.\n\n<b>Fixes / changes</b>\n\n<ul><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/1e03af965f6b7a76aa94f6…" rel=\"nofollow\">Mind drop events in filter expression field of logger</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/e018352ca30c61b4a80c2a…" rel=\"nofollow\">Improve <code>xml-prune</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/ec6b213ac8c38077b676e1…" rel=\"nofollow\">Fix message entries overflowing in logger</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/a6311ada7aec5e36a802c2…" rel=\"nofollow\">Add support for <code>application/x-javascript</code> in <code>replace=</code> option</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/8b0f4ac6d1a68a10f0736a…" rel=\"nofollow\">Extend support for differential updates to imported lists</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/5e2218ad38a67bad16b5a2…" rel=\"nofollow\">Add detection of mismatched <code>!#if</code>-<code>!#endif</code> in linter</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/d3d5708132bbca2b9b3232…" rel=\"nofollow\">Support links to update lists which are differential update-friendly</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/5da8dae3bfc5fd15895013…" rel=\"nofollow\">Remove \"Purge all caches\" button from \"Filter lists\" pane</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/f9bd0d08194525f2457cf5…" rel=\"nofollow\">Add support for <code>all</code> list token in updater-link feature</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/f266c7ca3a6228a20999be…" rel=\"nofollow\">Fix logging of broad exception filter <code>#@#+js()</code></a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/444dcf1f11a8dacef0553e…" rel=\"nofollow\">Improve <code>no-xhr-if</code> scriptlet</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/5f699ca11537ba17c330a8…" rel=\"nofollow\">Ensure cache storage backend is selected before access</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/983fbc3b50419c274040d9…" rel=\"nofollow\">Fix popup panel rendering when embedded in logger</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/2f972ff52f4edc3dc99084…" rel=\"nofollow\">Add visual hint in support information re. differential update</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/75541b4012443bd5602cc0…" rel=\"nofollow\">Remove obsolete web accessible resources</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/8eb76fbc2577032e63698e…" rel=\"nofollow\">Rename <code>urltransform</code> to <code>uritransform</code></a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/43e266ca8d07228388c2a6…" rel=\"nofollow\">Vertically expand/collapse in steps in dom inspector</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/d1f0669c5cf9357a9528d8…" rel=\"nofollow\">Reset the DOM inspector when URL in top context changes</a></li><li><a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/d2f70a310ccc2ce2b2c97c…" rel=\"nofollow\">Support shadow-piercing combinator <code>>>></code> in <code>trusted-click-element</code></a></li><li>[...]</li></ul>\n<a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/7d13ab8046ad75d1230ea5…" rel=\"nofollow\">Commits history since last version</a>"
},
- "reviewed": "2023-11-27T08:08:01Z",
- "version": "1.54.0",
+ "reviewed": "2024-01-08T10:26:54Z",
+ "version": "1.55.0",
"files": [
{
- "id": 4198829,
- "created": "2023-11-22T16:24:35Z",
- "hash": "sha256:9797160908191710ff0858536ba6dc29ecad9923c30b2ad6d3e5e371d759e44d",
+ "id": 4216633,
+ "created": "2024-01-03T20:24:50Z",
+ "hash": "sha256:a02ca1d32737c3437f97553e5caaead6479a66ac1f8ff3b84a06cfa6bb0c7647",
"is_restart_required": false,
"is_webextension": true,
"is_mozilla_signed_extension": false,
"platform": "all",
- "size": 3630690,
+ "size": 3647341,
"status": "public",
- "url": "https://addons.mozilla.org/firefox/downloads/file/4198829/ublock_origin-1.5…",
+ "url": "https://addons.mozilla.org/firefox/downloads/file/4216633/ublock_origin-1.5…",
"permissions": [
+ "alarms",
"dns",
"menus",
"privacy",
@@ -1378,7 +1379,7 @@
},
"is_disabled": false,
"is_experimental": false,
- "last_updated": "2023-12-18T15:55:24Z",
+ "last_updated": "2024-01-21T19:40:21Z",
"name": {
"ar": "uBlock Origin",
"bg": "uBlock Origin",
@@ -1523,10 +1524,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.7863,
- "bayesian_average": 4.785924647292365,
- "count": 16885,
- "text_count": 4402
+ "average": 4.7869,
+ "bayesian_average": 4.786526880140991,
+ "count": 17099,
+ "text_count": 4466
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/reviews/",
"requires_payment": false,
@@ -1589,7 +1590,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/versions/",
- "weekly_downloads": 181326
+ "weekly_downloads": 191212
},
"notes": null
},
@@ -1605,7 +1606,7 @@
"picture_url": null
}
],
- "average_daily_users": 174830,
+ "average_daily_users": 177037,
"categories": {
"firefox": [
"photos-music-videos",
@@ -1701,10 +1702,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.4823,
- "bayesian_average": 4.47726114447234,
- "count": 1161,
- "text_count": 436
+ "average": 4.4783,
+ "bayesian_average": 4.473306026343802,
+ "count": 1177,
+ "text_count": 445
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/video-background-play-fix/re…",
"requires_payment": false,
@@ -1726,7 +1727,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/video-background-play-fix/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/video-background-play-fix/ve…",
- "weekly_downloads": 379
+ "weekly_downloads": 433
},
"notes": null
},
@@ -1742,7 +1743,7 @@
"picture_url": null
}
],
- "average_daily_users": 85074,
+ "average_daily_users": 81898,
"categories": {
"firefox": [
"privacy-security",
@@ -1852,10 +1853,10 @@
],
"promoted": null,
"ratings": {
- "average": 4.3766,
- "bayesian_average": 4.362648333186986,
- "count": 401,
- "text_count": 112
+ "average": 4.3802,
+ "bayesian_average": 4.366169675126323,
+ "count": 405,
+ "text_count": 113
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-possum/reviews/",
"requires_payment": false,
@@ -1877,7 +1878,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-possum/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/privacy-possum/versions/",
- "weekly_downloads": 965
+ "weekly_downloads": 1389
},
"notes": null
},
@@ -1893,7 +1894,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/64/9064/12929064/12929064.pn…"
}
],
- "average_daily_users": 288929,
+ "average_daily_users": 299174,
"categories": {
"firefox": [
"search-tools",
@@ -1904,7 +1905,7 @@
"contributions_url": "https://www.paypal.com/donate?hosted_button_id=GLL4UNSNU6SQN&utm_content=pr…",
"created": "2017-06-17T15:23:33Z",
"current_version": {
- "id": 5645237,
+ "id": 5665608,
"compatibility": {
"firefox": {
"min": "115.0",
@@ -1915,7 +1916,7 @@
"max": "*"
}
},
- "edit_url": "https://addons.mozilla.org/en-US/developers/addon/search_by_image/versions/…",
+ "edit_url": "https://addons.mozilla.org/en-US/developers/addon/search_by_image/versions/…",
"is_strict_compatibility_enabled": false,
"license": {
"id": 6,
@@ -1928,20 +1929,20 @@
"release_notes": {
"en-US": "Learn more about this release from the <a href=\"https://prod.outgoing.prod.webservices.mozgcp.net/v1/d50855f24f77fa6f2614b9…" rel=\"nofollow\">changelog</a>."
},
- "reviewed": "2023-11-07T07:33:21Z",
- "version": "6.1.0",
+ "reviewed": "2023-12-19T14:03:13Z",
+ "version": "6.1.1",
"files": [
{
- "id": 4189577,
- "created": "2023-11-02T18:15:34Z",
- "hash": "sha256:1de51c7522b8bf3aca5c2bc4fbd94f5fb092d4418ea8fe4583c8dff2b71b4209",
+ "id": 4209928,
+ "created": "2023-12-17T01:28:51Z",
+ "hash": "sha256:254d78084e332190a2b6ccb1959a42257bdc287addc0685419fcde7df1a52e76",
"is_restart_required": false,
"is_webextension": true,
"is_mozilla_signed_extension": false,
"platform": "all",
- "size": 1156452,
+ "size": 1165289,
"status": "public",
- "url": "https://addons.mozilla.org/firefox/downloads/file/4189577/search_by_image-6…",
+ "url": "https://addons.mozilla.org/firefox/downloads/file/4209928/search_by_image-6…",
"permissions": [
"alarms",
"contextMenus",
@@ -1984,7 +1985,7 @@
},
"is_disabled": false,
"is_experimental": false,
- "last_updated": "2023-11-07T07:33:21Z",
+ "last_updated": "2023-12-19T14:03:13Z",
"name": {
"en-US": "Search by Image"
},
@@ -2110,10 +2111,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.651,
- "bayesian_average": 4.646505118537081,
- "count": 1361,
- "text_count": 264
+ "average": 4.6458,
+ "bayesian_average": 4.641373152099238,
+ "count": 1389,
+ "text_count": 269
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/search_by_image/reviews/",
"requires_payment": false,
@@ -2134,7 +2135,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/search_by_image/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/search_by_image/versions/",
- "weekly_downloads": 6399
+ "weekly_downloads": 6874
},
"notes": null
},
@@ -2157,7 +2158,7 @@
"picture_url": null
}
],
- "average_daily_users": 118743,
+ "average_daily_users": 123628,
"categories": {
"firefox": [
"search-tools",
@@ -2438,10 +2439,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.3703,
- "bayesian_average": 4.365894611018555,
- "count": 1288,
- "text_count": 364
+ "average": 4.3745,
+ "bayesian_average": 4.37014166071391,
+ "count": 1311,
+ "text_count": 371
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/google-search-fixer/reviews/",
"requires_payment": false,
@@ -2461,7 +2462,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/google-search-fixer/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/google-search-fixer/versions/",
- "weekly_downloads": 83
+ "weekly_downloads": 52
},
"notes": null
},
@@ -2477,7 +2478,7 @@
"picture_url": "https://addons.mozilla.org/user-media/userpics/43/0143/143/143.png?modified…"
}
],
- "average_daily_users": 313134,
+ "average_daily_users": 313064,
"categories": {
"firefox": [
"web-development",
@@ -2664,10 +2665,10 @@
"category": "recommended"
},
"ratings": {
- "average": 4.3967,
- "bayesian_average": 4.394045030071559,
- "count": 2153,
- "text_count": 831
+ "average": 4.3947,
+ "bayesian_average": 4.3920505434632835,
+ "count": 2171,
+ "text_count": 837
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/noscript/reviews/",
"requires_payment": false,
@@ -2711,7 +2712,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/noscript/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/noscript/versions/",
- "weekly_downloads": 7965
+ "weekly_downloads": 7762
},
"notes": null
},
@@ -2727,7 +2728,7 @@
"picture_url": null
}
],
- "average_daily_users": 158407,
+ "average_daily_users": 162394,
"categories": {
"firefox": [
"photos-music-videos",
@@ -2836,10 +2837,10 @@
"category": "recommended"
},
"ratings": {
- "average": 3.8702,
- "bayesian_average": 3.8661363785150384,
- "count": 1202,
- "text_count": 435
+ "average": 3.8734,
+ "bayesian_average": 3.869354081107614,
+ "count": 1216,
+ "text_count": 441
},
"ratings_url": "https://addons.mozilla.org/en-US/firefox/addon/youtube-high-definition/revi…",
"requires_payment": false,
@@ -2858,7 +2859,7 @@
"type": "extension",
"url": "https://addons.mozilla.org/en-US/firefox/addon/youtube-high-definition/",
"versions_url": "https://addons.mozilla.org/en-US/firefox/addon/youtube-high-definition/vers…",
- "weekly_downloads": 1957
+ "weekly_downloads": 3206
},
"notes": null
}
=====================================
projects/browser/config
=====================================
@@ -99,9 +99,9 @@ input_files:
- URL: https://addons.mozilla.org/firefox/downloads/file/4206186/noscript-11.4.29.…
name: noscript
sha256sum: 05b98840b05ef2acbac333543e4b7c3d40fee2ce5fb4e29260b05e2ff6fe24cd
- - URL: https://addons.mozilla.org/firefox/downloads/file/4198829/ublock_origin-1.5…
+ - URL: https://addons.mozilla.org/firefox/downloads/file/4216633/ublock_origin-1.5…
name: ublock-origin
- sha256sum: 9797160908191710ff0858536ba6dc29ecad9923c30b2ad6d3e5e371d759e44d
+ sha256sum: a02ca1d32737c3437f97553e5caaead6479a66ac1f8ff3b84a06cfa6bb0c7647
enable: '[% c("var/mullvad-browser") %]'
- URL: https://cdn.mullvad.net/browser-extension/0.8.4/mullvad-browser-extension-0…
name: mullvad-extension
=====================================
projects/firefox-android/config
=====================================
@@ -16,7 +16,7 @@ container:
var:
fenix_version: 115.2.1
browser_branch: 13.5-1
- browser_build: 4
+ browser_build: 5
variant: Beta
# This should be updated when the list of gradle dependencies is changed.
gradle_dependencies_version: 1
=====================================
projects/firefox/config
=====================================
@@ -18,7 +18,7 @@ var:
firefox_version: '[% c("var/firefox_platform_version") %]esr'
browser_series: '13.5'
browser_branch: '[% c("var/browser_series") %]-1'
- browser_build: 1
+ browser_build: 2
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") %]'
=====================================
projects/geckoview/config
=====================================
@@ -16,7 +16,7 @@ container:
var:
geckoview_version: 115.7.0esr
browser_branch: 13.5-1
- browser_build: 1
+ browser_build: 2
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/go/config
=====================================
@@ -1,5 +1,5 @@
# vim: filetype=yaml sw=2
-version: '[% IF c("var/use_go_1_20") %]1.20.12[% ELSE %]1.21.5[% END %]'
+version: '[% IF c("var/use_go_1_20") %]1.20.13[% ELSE %]1.21.6[% END %]'
filename: '[% project %]-[% c("version") %]-[% c("var/osname") %]-[% c("var/build_id") %].tar.[% c("compress_tar") %]'
container:
use_container: 1
@@ -121,11 +121,11 @@ input_files:
enable: '[% ! c("var/linux") %]'
- URL: 'https://go.dev/dl/go[% c("version") %].src.tar.gz'
name: go
- sha256sum: 285cbbdf4b6e6e62ed58f370f3f6d8c30825d6e56c5853c66d3c23bcdb09db19
+ sha256sum: 124926a62e45f78daabbaedb9c011d97633186a33c238ffc1e25320c02046248
enable: '[% !c("var/use_go_1_20") %]'
- URL: 'https://go.dev/dl/go[% c("version") %].src.tar.gz'
name: go
- sha256sum: c5bf934751d31c315c1d0bb5fb02296545fa6d08923566f7a5afec81f2ed27d6
+ sha256sum: 0fe745c530f2f1d67193af3c5ea25246be077989ec5178df266e975f3532449e
enable: '[% c("var/use_go_1_20") %]'
- project: go-bootstrap
name: go-bootstrap
=====================================
projects/manual/config
=====================================
@@ -1,7 +1,7 @@
# vim: filetype=yaml sw=2
# To update, see doc/how-to-update-the-manual.txt
# Remember to update also the package's hash, with the version!
-version: 122062
+version: 136210
filename: 'manual-[% c("version") %]-[% c("var/build_id") %].tar.[% c("compress_tar") %]'
container:
use_container: 1
@@ -23,6 +23,6 @@ input_files:
- project: container-image
- URL: 'https://build-sources.tbb.torproject.org/manual_[% c("version") %].zip'
name: manual
- sha256sum: d51ebe27077817bcdabc0b5616c0c58fc14ea6d06f1a0b459051d67a4c13c348
+ sha256sum: 6731381fd992cf65dd01e56e2b924005af633369da5ac9eb905fd8025255b386
- filename: packagemanual.py
name: package_script
=====================================
projects/translation/config
=====================================
@@ -12,13 +12,13 @@ compress_tar: 'gz'
steps:
base-browser:
base-browser: '[% INCLUDE build %]'
- git_hash: 5490489a8d356a44d792300b4dfddba792d10f2e
+ git_hash: cbd9b6c415ec2edb99237ef67ccd4f033a7b9c2a
targets:
nightly:
git_hash: 'base-browser'
tor-browser:
tor-browser: '[% INCLUDE build %]'
- git_hash: e92772b4a11ced855c27eafd299cf972bef5cd8f
+ git_hash: 799998ee13be225222afc6cfda1687cf63d6cc9e
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: 38741697dc418d7ea90e67cab30ae7cfa4b9c858
+ git_hash: 9622d5c3f3ffd2400fc1bbd4bb7c507f257f9bbb
compress_tar: 'zst'
targets:
nightly:
=====================================
projects/zlib/config
=====================================
@@ -1,6 +1,6 @@
# vim: filetype=yaml sw=2
filename: '[% project %]-[% c("version") %]-[% c("var/osname") %]-[% c("var/build_id") %].tar.[% c("compress_tar") %]'
-version: '1.3'
+version: '1.3.1'
git_hash: 'v[% c("version") %]'
git_url: https://github.com/madler/zlib.git
gpg_keyring: zlib.gpg
=====================================
rbm.conf
=====================================
@@ -81,12 +81,12 @@ buildconf:
git_signtag_opt: '-s'
var:
- torbrowser_version: '13.5a3'
- torbrowser_build: 'build2'
+ torbrowser_version: '13.5a4'
+ torbrowser_build: 'build1'
torbrowser_incremental_from:
- - '13.0a6'
- '13.5a1'
- '13.5a2'
+ - '13.5a3'
updater_enabled: 1
build_mar: 1
mar_channel_id: '[% c("var/projectname") %]-torproject-[% c("var/channel") %]'
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/e…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/e…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser-build][main] Bug 41065: Cleanup the NSIS script
by Pier Angelo Vendrame (@pierov) 29 Jan '24
by Pier Angelo Vendrame (@pierov) 29 Jan '24
29 Jan '24
Pier Angelo Vendrame pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
1a571c59 by Pier Angelo Vendrame at 2024-01-29T10:16:12+01:00
Bug 41065: Cleanup the NSIS script
Improve the formatting of the installer, and update the language list
to match the one in rbm.conf (even though it would be good to keep the
lists synchronized automatically).
Also, include the channel name in the displayed name and in the default
install directory (except for release).
Since we are changing many lines, I took the ocasion to switch to LF
line endings (NSIS accepts them).
- - - - -
2 changed files:
- projects/browser/build
- projects/browser/windows-installer.nsi
Changes:
=====================================
projects/browser/build
=====================================
@@ -305,11 +305,6 @@ done
cat > $distdir/windows-installer/browser-portable.nsi << 'BROWSER_NSI'
[% INCLUDE 'windows-installer.nsi' %]
BROWSER_NSI
- [% IF c('var/mullvad-browser') -%]
- cat > $distdir/windows-installer/browser-system.nsi << 'BROWSER_NSI'
-[% INCLUDE 'windows-installer.nsi' system_install_mode = 1 %]
-BROWSER_NSI
- [% END -%]
mv ${TB_STAGE_DIR} $distdir/windows-installer/"[% c('var/Project_Name') %]"
mv $distdir/windows-installer ${TB_STAGE_DIR}
[% END %]
@@ -389,11 +384,6 @@ cd $distdir
# Working around NSIS braindamage
python3 $rootdir/pe_checksum_fix.py browser-install.exe
mv browser-install.exe $OUTDIR/[% c("var/project-name") %]-[% c("var/osname") %]-portable-[% c("var/torbrowser_version") %].exe
- [% IF c('var/mullvad-browser') -%]
- makensis browser-system.nsi
- python3 $rootdir/pe_checksum_fix.py browser-install.exe
- mv browser-install.exe $OUTDIR/[% c("var/project-name") %]-[% c("var/osname") %]-install-[% c("var/torbrowser_version") %].exe
- [% END -%]
popd
[% END %]
rm -rf $distdir/${PKG_DIR}
=====================================
projects/browser/windows-installer.nsi
=====================================
@@ -1,248 +1,169 @@
-;NSIS Installer for Tor/Base/Mullvad Browser
-;Written by Moritz Bartl
-;released under Public Domain
-
-;--------------------------------
-;Modern UI
-
- !include "FileFunc.nsh"
- !include "MUI2.nsh"
- !include "LogicLib.nsh"
- !include "WinVer.nsh"
-
-;--------------------------------
-;General
-
- ;Location of Tor/Base/Mullvad Browser to put into installer
- !define PROGRAM_SOURCE ".\[% c('var/Project_Name') %]\"
-
- Name "[% c('var/Project_Name') %]"
- OutFile "browser-install.exe"
-
- ;Default installation folder
-[% IF system_install_mode -%]
- InstallDir "$PROGRAMFILES\[% c('var/Project_Name') %]"
-[% ELSE -%]
- InstallDir "$DESKTOP\[% c('var/Project_Name') %]"
-[% END -%]
-
- ;Best (but slowest) compression
- SetCompressor /SOLID lzma
- SetCompressorDictSize 32
-
- ;Request application privileges for Windows Vista
-[% IF system_install_mode -%]
- RequestExecutionLevel admin
-[% ELSE -%]
- RequestExecutionLevel user
-[% END -%]
-
- ;Support HiDPI displays
- ManifestDPIAware true
-
-[% IF system_install_mode -%]
- ;Registry keys to uninstall system-wide installs
- !define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\[% c('var/ProjectName') %]"
-[% END -%]
-
-;--------------------------------
-;Metadata
-
- VIProductVersion "[% pc("firefox", "var/browser_series") %].0.0"
- VIAddVersionKey "ProductName" "[% c('var/Project_Name') %]"
- VIAddVersionKey "ProductVersion" "[% c('var/torbrowser_version') %]"
- VIAddVersionKey "FileDescription" "[% c('var/Project_Name') %][% IF system_install_mode -%] System[% END -%] Installer"
- VIAddVersionKey "LegalCopyright" "© [% pc("firefox", "var/copyright_year") %] [% IF c('var/mullvad-browser') -%]Mullvad, Tor Browser and Mozilla Developers[% ELSE -%]The Tor Project[% END -%]"
-
-;--------------------------------
-;Interface Configuration
-
- !define MUI_ICON "[% c('var/projectname') %][% IF !c('var/base-browser') -%]-[% c('var/channel') %][% END -%].ico"
- !define MUI_ABORTWARNING
-
-;--------------------------------
-;Modern UI settings
- !define MUI_FINISHPAGE_NOREBOOTSUPPORT ; we don't require a reboot
- !define MUI_FINISHPAGE_RUN
- !define MUI_FINISHPAGE_RUN_FUNCTION "StartBrowser"
- !define MUI_FINISHPAGE_SHOWREADME ; misuse for option to create shortcut; less ugly than MUI_PAGE_COMPONENTS
- !define MUI_FINISHPAGE_SHOWREADME_TEXT "&Add Start Menu && Desktop shortcuts"
- !define MUI_FINISHPAGE_SHOWREADME_FUNCTION "CreateShortCuts"
-;--------------------------------
-;Pages
-
- !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckIfTargetDirectoryExists
- !insertmacro MUI_PAGE_DIRECTORY
- !insertmacro MUI_PAGE_INSTFILES
- !insertmacro MUI_PAGE_FINISH
-
-;--------------------------------
-;Languages
-
- !insertmacro MUI_LANGUAGE "English" ;first language is the default language
- !insertmacro MUI_LANGUAGE "French"
- !insertmacro MUI_LANGUAGE "German"
- !insertmacro MUI_LANGUAGE "Spanish"
- !insertmacro MUI_LANGUAGE "SpanishInternational"
- !insertmacro MUI_LANGUAGE "SimpChinese"
- !insertmacro MUI_LANGUAGE "TradChinese"
- !insertmacro MUI_LANGUAGE "Japanese"
- !insertmacro MUI_LANGUAGE "Korean"
- !insertmacro MUI_LANGUAGE "Italian"
- !insertmacro MUI_LANGUAGE "Dutch"
- !insertmacro MUI_LANGUAGE "Danish"
- !insertmacro MUI_LANGUAGE "Swedish"
- !insertmacro MUI_LANGUAGE "Norwegian"
- !insertmacro MUI_LANGUAGE "NorwegianNynorsk"
- !insertmacro MUI_LANGUAGE "Finnish"
- !insertmacro MUI_LANGUAGE "Greek"
- !insertmacro MUI_LANGUAGE "Russian"
- !insertmacro MUI_LANGUAGE "Portuguese"
- !insertmacro MUI_LANGUAGE "PortugueseBR"
- !insertmacro MUI_LANGUAGE "Polish"
- !insertmacro MUI_LANGUAGE "Ukrainian"
- !insertmacro MUI_LANGUAGE "Czech"
- !insertmacro MUI_LANGUAGE "Slovak"
- !insertmacro MUI_LANGUAGE "Croatian"
- !insertmacro MUI_LANGUAGE "Bulgarian"
- !insertmacro MUI_LANGUAGE "Hungarian"
- !insertmacro MUI_LANGUAGE "Thai"
- !insertmacro MUI_LANGUAGE "Romanian"
- !insertmacro MUI_LANGUAGE "Latvian"
- !insertmacro MUI_LANGUAGE "Macedonian"
- !insertmacro MUI_LANGUAGE "Estonian"
- !insertmacro MUI_LANGUAGE "Turkish"
- !insertmacro MUI_LANGUAGE "Lithuanian"
- !insertmacro MUI_LANGUAGE "Slovenian"
- !insertmacro MUI_LANGUAGE "Serbian"
- !insertmacro MUI_LANGUAGE "SerbianLatin"
- !insertmacro MUI_LANGUAGE "Arabic"
- !insertmacro MUI_LANGUAGE "Farsi"
- !insertmacro MUI_LANGUAGE "Hebrew"
- !insertmacro MUI_LANGUAGE "Indonesian"
- !insertmacro MUI_LANGUAGE "Mongolian"
- !insertmacro MUI_LANGUAGE "Luxembourgish"
- !insertmacro MUI_LANGUAGE "Albanian"
- !insertmacro MUI_LANGUAGE "Breton"
- !insertmacro MUI_LANGUAGE "Belarusian"
- !insertmacro MUI_LANGUAGE "Icelandic"
- !insertmacro MUI_LANGUAGE "Malay"
- !insertmacro MUI_LANGUAGE "Bosnian"
- !insertmacro MUI_LANGUAGE "Kurdish"
- !insertmacro MUI_LANGUAGE "Irish"
- !insertmacro MUI_LANGUAGE "Uzbek"
- !insertmacro MUI_LANGUAGE "Galician"
- !insertmacro MUI_LANGUAGE "Afrikaans"
- !insertmacro MUI_LANGUAGE "Catalan"
- !insertmacro MUI_LANGUAGE "Esperanto"
-
-;--------------------------------
-;Multi Language support: Read strings from separate file
-
-; !include [% c('var/projectname') %]-langstrings.nsi
-
-;--------------------------------
-;Reserve Files
-
- ;If you are using solid compression, files that are required before
- ;the actual installation should be stored first in the data block,
- ;because this will make your installer start faster.
-
- !insertmacro MUI_RESERVEFILE_LANGDLL
-
-;--------------------------------
-;Installer Sections
-
-Section "[% c('var/Project_Name') %]" SecBrowser
-
- SetOutPath "$INSTDIR"
-[% IF !system_install_mode -%]
- File /r "${PROGRAM_SOURCE}\*.*"
- CreateShortCut "$INSTDIR\Start [% c('var/Project_Name') %].lnk" "$INSTDIR\Browser\[% c('var/exe_name') %].exe"
-[% ELSE -%]
- File /r "${PROGRAM_SOURCE}\Browser\*.*"
-
- ;Enable system-wide install in the browser
- FileOpen $0 "$INSTDIR\system-install" w
- FileClose $0
-
- ;Write the uninstaller
- WriteUninstaller $INSTDIR\uninstall.exe
-
- ;Add the uninstaller to the control panel
- WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "[% c('var/Project_Name') %]"
- WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
- WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
- WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "[% IF c('var/mullvad-browser') -%]Mullvad VPN[% ELSE -%]The Tor Project[% END -%]"
- WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$\"$INSTDIR\[% c('var/exe_name') %].exe$\""
- WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "[% c('var/torbrowser_version') %]"
- WriteRegDWORD HKLM "${UNINST_KEY}" "NoModify" "1"
- WriteRegDWORD HKLM "${UNINST_KEY}" "NoRepair" "1"
- ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
- IntFmt $0 "0x%08X" $0
- WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
-[% END -%]
-
-SectionEnd
-
-[% IF system_install_mode -%]
-Section "Uninstall"
- RMDir /r "$INSTDIR"
- DeleteRegKey HKLM "${UNINST_KEY}"
- SetShellVarContext all
- Delete "$SMPROGRAMS\[% c('var/Project_Name') %].lnk"
- Delete "$DESKTOP\[% c('var/Project_Name') %].lnk"
-SectionEnd
-[% END -%]
-
-Function CreateShortcuts
-[% IF system_install_mode -%]
- SetShellVarContext all
-[% END -%]
- CreateShortCut "$SMPROGRAMS\[% c('var/Project_Name') %].lnk" "$INSTDIR\[% IF !system_install_mode -%]Browser\[% END -%][% c('var/exe_name') %].exe"
- CreateShortCut "$DESKTOP\[% c('var/Project_Name') %].lnk" "$INSTDIR\[% IF !system_install_mode -%]Browser\[% END -%][% c('var/exe_name') %].exe"
-
-FunctionEnd
-;--------------------------------
-;Installer Functions
-
-Function .onInit
-
- ${IfNot} ${AtLeastWin7}
- MessageBox MB_USERICON|MB_OK "[% c('var/Project_Name') %] requires at least Windows 7"
- SetErrorLevel 1
- Quit
- ${EndIf}
-
- ; Don't install on systems that don't support SSE2. The parameter value of
- ; 10 is for PF_XMMI64_INSTRUCTIONS_AVAILABLE which will check whether the
- ; SSE2 instruction set is available.
- System::Call "kernel32::IsProcessorFeaturePresent(i 10)i .R7"
-
- ${If} "$R7" == "0"
- MessageBox MB_OK|MB_ICONSTOP "Sorry, [% c('var/Project_Name') %] can't be installed. This version of [% c('var/Project_Name') %] requires a processor with SSE2 support."
- Abort
- ${EndIf}
-
- !insertmacro MUI_LANGDLL_DISPLAY
-
-FunctionEnd
-
-;--------------------------------
-;Helper Functions
-
-Function CheckIfTargetDirectoryExists
-${If} ${FileExists} "$INSTDIR\*.*"
- MessageBox MB_YESNO "The destination directory already exists. You can try to upgrade the [% c('var/Project_Name') %], but if you run into any problems, use a new directory instead. Continue?" IDYES NoAbort
- Abort
- NoAbort:
-${EndIf}
-FunctionEnd
-
-Function StartBrowser
-[% IF !system_install_mode -%]
- ExecShell "open" "$INSTDIR/Start [% c('var/Project_Name') %].lnk"
-[% ELSE -%]
- ExecShell "open" "$INSTDIR/[% c('var/exe_name') %].exe"
-[% END -%]
-FunctionEnd
+; NSIS Installer for Tor/Base/Mullvad Browser
+; Based on NSIS examples by Joost Verburg.
+; Originally adapted to Tor Browser by Moritz Bartl
+; https://github.com/moba/tbb-windows-installer
+; Released under the zlib/libpng license.
+
+;--------------------------------
+ !include "FileFunc.nsh"
+ !include "LogicLib.nsh"
+ !include "MUI2.nsh"
+ !include "WinVer.nsh"
+
+;--------------------------------
+; General
+ ; Location of Tor/Base/Mullvad Browser to put into installer
+ !define PROGRAM_SOURCE ".\[% c('var/Project_Name') %]\"
+
+[% IF c("var/channel") == "release";
+ SET display_name = c('var/Project_Name');
+ ELSIF c("var/testbuild");
+ SET display_name = c('var/Project_Name') _ " Testbuild";
+ ELSE;
+ SET display_name = c('var/Project_Name_Channel');
+ END
+-%]
+ Name "[% display_name %]"
+ OutFile "browser-install.exe"
+
+ ; Default installation folder
+ InstallDir "$DESKTOP\[% display_name %]"
+
+ ; Best (but slowest) compression
+ SetCompressor /SOLID lzma
+ SetCompressorDictSize 32
+
+ ; Do not require elevated privileges
+ RequestExecutionLevel user
+
+ ; Support HiDPI displays
+ ManifestDPIAware true
+
+;--------------------------------
+; Metadata
+ VIProductVersion "[% pc('firefox', 'var/browser_series') %].0.0"
+ VIAddVersionKey "ProductName" "[% display_name %]"
+ VIAddVersionKey "ProductVersion" "[% c('var/torbrowser_version') %]"
+ VIAddVersionKey "FileDescription" "[% display_name %] Portable Installer"
+ VIAddVersionKey "LegalCopyright" "© [% pc('firefox', 'var/copyright_year') %] [% IF c('var/mullvad-browser') %]Mullvad, Tor Browser and Mozilla Developers[% ELSE %]The Tor Project[% END %]"
+
+;--------------------------------
+; Interface Configuration
+ !define MUI_ICON "[% c('var/projectname') %][% IF !c('var/base-browser') %]-[% c('var/channel') %][% END %].ico"
+ !define MUI_ABORTWARNING
+
+;--------------------------------
+; Modern UI settings
+ !define MUI_FINISHPAGE_NOREBOOTSUPPORT ; Reboot not required
+ !define MUI_FINISHPAGE_RUN
+ !define MUI_FINISHPAGE_RUN_FUNCTION "StartBrowser"
+
+ ; Misuse the option to show the readme to create the shortcuts.
+ ; Less ugly than MUI_PAGE_COMPONENTS.
+ !define MUI_FINISHPAGE_SHOWREADME
+ !define MUI_FINISHPAGE_SHOWREADME_TEXT "&Add Start Menu && Desktop shortcuts"
+ !define MUI_FINISHPAGE_SHOWREADME_FUNCTION "CreateShortCuts"
+
+;--------------------------------
+; Pages
+ !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckIfTargetDirectoryExists
+ !insertmacro MUI_PAGE_DIRECTORY
+ !insertmacro MUI_PAGE_INSTFILES
+ !insertmacro MUI_PAGE_FINISH
+
+;--------------------------------
+; Languages
+ !insertmacro MUI_LANGUAGE "English" ; First language is the default language
+ !insertmacro MUI_LANGUAGE "Arabic" ; ar
+ !insertmacro MUI_LANGUAGE "Catalan" ; ca
+ !insertmacro MUI_LANGUAGE "Czech" ; cs
+ !insertmacro MUI_LANGUAGE "Danish" ; da
+ !insertmacro MUI_LANGUAGE "German" ; de
+ !insertmacro MUI_LANGUAGE "Greek" ; el
+ !insertmacro MUI_LANGUAGE "Spanish" ; es-ES
+ !insertmacro MUI_LANGUAGE "Farsi" ; fa
+ !insertmacro MUI_LANGUAGE "Finnish" ; fi
+ !insertmacro MUI_LANGUAGE "French" ; fr
+ !insertmacro MUI_LANGUAGE "ScotsGaelic" ; ga-IE
+ !insertmacro MUI_LANGUAGE "Hebrew" ; he
+ !insertmacro MUI_LANGUAGE "Hungarian" ; hu
+ !insertmacro MUI_LANGUAGE "Indonesian"; id
+ !insertmacro MUI_LANGUAGE "Icelandic" ; is
+ !insertmacro MUI_LANGUAGE "Italian" ; it
+ !insertmacro MUI_LANGUAGE "Japanese" ; ja
+ !insertmacro MUI_LANGUAGE "Georgian" ; ka
+ !insertmacro MUI_LANGUAGE "Korean" ; ko
+ !insertmacro MUI_LANGUAGE "Lithuanian" ; lt
+ !insertmacro MUI_LANGUAGE "Macedonian" ; mk
+ !insertmacro MUI_LANGUAGE "Malay" ; ms
+ ; Burmese - my: not available on NSIS
+ !insertmacro MUI_LANGUAGE "Norwegian" ; nb-NO
+ !insertmacro MUI_LANGUAGE "Dutch" ; nl
+ !insertmacro MUI_LANGUAGE "Polish" ; pl
+ !insertmacro MUI_LANGUAGE "PortugueseBR" ; pt-BR
+ !insertmacro MUI_LANGUAGE "Romanian" ; ro
+ !insertmacro MUI_LANGUAGE "Russian" ; ru
+ !insertmacro MUI_LANGUAGE "Albanian" ; sq
+ !insertmacro MUI_LANGUAGE "Swedish" ; sv-SE
+ !insertmacro MUI_LANGUAGE "Thai" ; th
+ !insertmacro MUI_LANGUAGE "Turkish" ; tr
+ !insertmacro MUI_LANGUAGE "Ukrainian" ; uk
+ !insertmacro MUI_LANGUAGE "Vietnamese" ; vi
+ !insertmacro MUI_LANGUAGE "SimpChinese" ; zh-hans, zh-cn
+ !insertmacro MUI_LANGUAGE "TradChinese" ; zh-hant, zh-tw
+
+;--------------------------------
+; Reserve Files
+
+ ; If you are using solid compression, files that are required before
+ ; the actual installation should be stored first in the data block,
+ ; because this will make your installer start faster.
+
+ !insertmacro MUI_RESERVEFILE_LANGDLL
+
+;--------------------------------
+; Installer Sections
+
+Section "Browser" SecBrowser
+ SetOutPath "$INSTDIR"
+ File /r "${PROGRAM_SOURCE}\*.*"
+ CreateShortCut "$INSTDIR\[% display_name %].lnk" "$INSTDIR\Browser\[% c('var/exe_name') %].exe"
+SectionEnd
+
+;--------------------------------
+; Installer Functions
+
+Function .onInit
+ ${IfNot} ${AtLeastWin7}
+ MessageBox MB_USERICON|MB_OK "[% c('var/Project_Name') %] requires at least Windows 7"
+ SetErrorLevel 1
+ Quit
+ ${EndIf}
+
+ ; Don't install on systems that don't support SSE2. The parameter value of
+ ; 10 is for PF_XMMI64_INSTRUCTIONS_AVAILABLE which will check whether the
+ ; SSE2 instruction set is available.
+ System::Call "kernel32::IsProcessorFeaturePresent(i 10)i .R7"
+ ${If} "$R7" == "0"
+ MessageBox MB_OK|MB_ICONSTOP "Sorry, [% c('var/Project_Name') %] can't be installed. This version of [% c('var/Project_Name') %] requires a processor with SSE2 support."
+ Abort
+ ${EndIf}
+
+ !insertmacro MUI_LANGDLL_DISPLAY
+FunctionEnd
+
+Function CheckIfTargetDirectoryExists
+ ${If} ${FileExists} "$INSTDIR\*.*"
+ MessageBox MB_YESNO "The destination directory already exists. Do you want to continue anyway?" IDYES +2
+ Abort
+ ${EndIf}
+FunctionEnd
+
+Function CreateShortcuts
+ CreateShortCut "$SMPROGRAMS\[% display_name %].lnk" "$INSTDIR\[% IF !system_install_mode -%]Browser\[% END -%][% c('var/exe_name') %].exe"
+ CreateShortCut "$DESKTOP\[% display_name %].lnk" "$INSTDIR\[% IF !system_install_mode -%]Browser\[% END -%][% c('var/exe_name') %].exe"
+FunctionEnd
+
+Function StartBrowser
+ ExecShell "open" "$INSTDIR/[% display_name %].lnk"
+FunctionEnd
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/1…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/1…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/mullvad-browser][mullvad-browser-115.7.0esr-13.5-1] fixup! Bug 32308: use direct browser sizing for letterboxing.
by ma1 (@ma1) 29 Jan '24
by ma1 (@ma1) 29 Jan '24
29 Jan '24
ma1 pushed to branch mullvad-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Mullvad Browser
Commits:
c55896fb by hackademix at 2024-01-29T16:33:56+01:00
fixup! Bug 32308: use direct browser sizing for letterboxing.
Bug 41917: Make the appearance of letterboxing look more intentional
- - - - -
3 changed files:
- browser/app/profile/001-base-profile.js
- browser/base/content/browser.css
- toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
Changes:
=====================================
browser/app/profile/001-base-profile.js
=====================================
@@ -375,6 +375,10 @@ pref("security.remote_settings.intermediates.enabled", false);
pref("dom.use_components_shim", false);
// Enable letterboxing
pref("privacy.resistFingerprinting.letterboxing", true);
+// tor-browser#41917 center letterboxed area vertically
+pref("privacy.resistFingerprinting.letterboxing.vcenter", true);
+// tor-browser#41917 letterboxing gradient background
+pref("privacy.resistFingerprinting.letterboxing.gradient", true);
// tor-browser#41695: how many warnings we show if user closes them without restoring the window size
pref("privacy.resistFingerprinting.resizeWarnings", 3);
// tor-browser#33282: new windows start at 1400x900 when there's enough screen space, otherwise down by 200x100 blocks
=====================================
browser/base/content/browser.css
=====================================
@@ -134,6 +134,56 @@ body {
doesn't get notified on horizontal shrinking.
*/
overflow-x: hidden;
+ background: var(--letterboxing-bgcolor);
+}
+
+.letterboxing {
+ --letterboxing-border-radius: 8px;
+ --letterboxing-border-top-radius: 0;
+ --letterboxing-vertical-alignment: start;
+ --letterboxing-shadow-color: rgba(12, 12, 13, 0.10);
+ --letterboxing-bgcolor: var(--tabpanel-background-color);
+ --letterboxing-gradient-color1: var(--letterboxing-bgcolor);
+ --letterboxing-gradient-color2: color-mix(in srgb, var(--chrome-content-separator-color) 50%, var(--letterboxing-bgcolor));
+}
+
+.letterboxing.letterboxing-vcenter .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
+ --letterboxing-border-top-radius: var(--letterboxing-border-radius);
+ --letterboxing-vertical-alignment: center;
+}
+
+.letterboxing.letterboxing-gradient .browserContainer {
+ background: linear-gradient(283deg, var(--letterboxing-gradient-color1) 0%, var(--letterboxing-gradient-color2) 100%), var(--letterboxing-bgcolor);
+ box-shadow: rgba(0, 0, 0, 0.5) 0px -1px 2px;
+}
+
+/*
+ Align status bar with content.
+ TODO: switch to nested CSS selectors for conciseness when available (Firefox >= 117)
+*/
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+ > #statuspanel:not([hidden]) {
+ position: relative;
+ place-self: end left;
+ left: 0;
+ right: 0;
+ --letterboxing-status-left-radius: var(--letterboxing-border-radius);
+ --letterboxing-status-right-radius: 0;
+}
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+ > #statuspanel:not([mirror]):-moz-locale-dir(rtl),
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+ > #statuspanel[mirror]:-moz-locale-dir(ltr) {
+ left: 0;
+ right: 0;
+ --letterboxing-status-right-radius: var(--letterboxing-border-radius);
+ --letterboxing-status-left-radius: 0;
+ justify-self: right;
+}
+
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+#statuspanel-label {
+ border-radius: 0 0 var(--letterboxing-status-right-radius) var(--letterboxing-status-left-radius);
}
/**
@@ -142,21 +192,15 @@ body {
**/
.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
/* width & height to be dynamically set by RFPHelper.jsm */
- outline: 1px solid var(--chrome-content-separator-color);
+ box-shadow: 0px 4px 8px 0px var(--letterboxing-shadow-color);
+ border-radius: var(--letterboxing-border-radius);
+ border-top-left-radius: var(--letterboxing-border-top-radius);
+ border-top-right-radius: var(--letterboxing-border-top-radius);
}
-.exclude-letterboxing > browser {
- outline: initial;
-}
-
-:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
- place-content: start center;
-}
-
-/* extend down the toolbar's colors when letterboxing is enabled */
-.letterboxing {
- background-color: var(--toolbar-bgcolor);
- background-image: var(--toolbar-bgimage);
+:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode)
+ > .browserStack:not(.exclude-letterboxing) {
+ place-content: var(--letterboxing-vertical-alignment) center;
}
#toolbar-menubar[autohide="true"] {
=====================================
toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
=====================================
@@ -14,6 +14,11 @@ const kPrefLetterboxingDimensions =
"privacy.resistFingerprinting.letterboxing.dimensions";
const kPrefLetterboxingTesting =
"privacy.resistFingerprinting.letterboxing.testing";
+const kPrefLetterboxingVcenter =
+ "privacy.resistFingerprinting.letterboxing.vcenter";
+const kPrefLetterboxingGradient =
+ "privacy.resistFingerprinting.letterboxing.gradient";
+
const kTopicDOMWindowOpened = "domwindowopened";
const kPrefResizeWarnings = "privacy.resistFingerprinting.resizeWarnings";
@@ -140,6 +145,9 @@ class _RFPHelper {
// Add unconditional observers
Services.prefs.addObserver(kPrefResistFingerprinting, this);
Services.prefs.addObserver(kPrefLetterboxing, this);
+ Services.prefs.addObserver(kPrefLetterboxingVcenter, this);
+ Services.prefs.addObserver(kPrefLetterboxingGradient, this);
+
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_letterboxingDimensions",
@@ -171,6 +179,8 @@ class _RFPHelper {
// Remove unconditional observers
Services.prefs.removeObserver(kPrefResistFingerprinting, this);
+ Services.prefs.removeObserver(kPrefLetterboxingGradient, this);
+ Services.prefs.removeObserver(kPrefLetterboxingVcenter, this);
Services.prefs.removeObserver(kPrefLetterboxing, this);
// Remove the RFP observers, swallowing exceptions if they weren't present
this._removeRFPObservers();
@@ -218,6 +228,8 @@ class _RFPHelper {
this._handleSpoofEnglishChanged();
break;
case kPrefLetterboxing:
+ case kPrefLetterboxingVcenter:
+ case kPrefLetterboxingGradient:
this._handleLetterboxingPrefChanged();
break;
default:
@@ -429,8 +441,7 @@ class _RFPHelper {
});
}
- getLetterboxingDefaultRule(aBrowser) {
- let document = aBrowser.ownerDocument;
+ getLetterboxingDefaultRule(document) {
return (document._letterBoxingSizingRule ||= (() => {
// If not already cached on the document object, traverse the CSSOM and
// find the rule applying the default letterboxing styles to browsers
@@ -555,11 +566,16 @@ class _RFPHelper {
return;
}
+ let lastRoundedSize;
+
const roundDimensions = (aWidth, aHeight) => {
- const r = (aWidth, aHeight) => ({
- width: `var(--rdm-width, ${aWidth}px)`,
- height: `var(--rdm-height, ${aHeight}px)`,
- });
+ const r = (width, height) => {
+ lastRoundedSize = {width, height};
+ return {
+ width: `var(--rdm-width, ${width}px)`,
+ height: `var(--rdm-height, ${height}px)`,
+ }
+ };
let result;
@@ -642,7 +658,7 @@ class _RFPHelper {
const roundedDefault = roundDimensions(containerWidth, containerHeight);
styleChanges.queueIfNeeded(
- this.getLetterboxingDefaultRule(aBrowser),
+ this.getLetterboxingDefaultRule(aBrowser.ownerDocument),
roundedDefault
);
@@ -655,6 +671,21 @@ class _RFPHelper {
: { width: "", height: "" }; // otherwise we can keep the default (rounded) size
styleChanges.queueIfNeeded(aBrowser, roundedInline);
+ if (lastRoundedSize) {
+ // check wether the letterboxing margin is less than the border radius, and if so flatten the borders
+ let borderRadius = parseInt(win.getComputedStyle(browserContainer).getPropertyValue("--letterboxing-border-radius"));
+ if (borderRadius &&
+ (parentWidth - lastRoundedSize.width < borderRadius &&
+ parentHeight - lastRoundedSize.height < borderRadius)) {
+ borderRadius = 0;
+ } else {
+ borderRadius = "";
+ }
+ styleChanges.queueIfNeeded(browserParent, {
+ '--letterboxing-border-radius': borderRadius
+ });
+ }
+
// If the size of the content is already quantized, we do nothing.
if (!styleChanges.length) {
log(`${logPrefix} is_rounded == true`);
@@ -690,6 +721,10 @@ class _RFPHelper {
_updateSizeForTabsInWindow(aWindow) {
let tabBrowser = aWindow.gBrowser;
tabBrowser.tabpanels?.classList.add("letterboxing");
+ tabBrowser.tabpanels?.classList.toggle("letterboxing-vcenter",
+ Services.prefs.getBoolPref(kPrefLetterboxingVcenter, false));
+ tabBrowser.tabpanels?.classList.toggle("letterboxing-gradient",
+ Services.prefs.getBoolPref(kPrefLetterboxingGradient, false));
for (let tab of tabBrowser.tabs) {
let browser = tab.linkedBrowser;
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/c55…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/c55…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][base-browser-115.7.0esr-13.5-1] fixup! Bug 32308: use direct browser sizing for letterboxing.
by ma1 (@ma1) 29 Jan '24
by ma1 (@ma1) 29 Jan '24
29 Jan '24
ma1 pushed to branch base-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
0cb13087 by hackademix at 2024-01-29T16:32:32+01:00
fixup! Bug 32308: use direct browser sizing for letterboxing.
Bug 41917: Make the appearance of letterboxing look more intentional
- - - - -
3 changed files:
- browser/app/profile/001-base-profile.js
- browser/base/content/browser.css
- toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
Changes:
=====================================
browser/app/profile/001-base-profile.js
=====================================
@@ -376,6 +376,10 @@ pref("security.remote_settings.intermediates.enabled", false);
pref("dom.use_components_shim", false);
// Enable letterboxing
pref("privacy.resistFingerprinting.letterboxing", true);
+// tor-browser#41917 center letterboxed area vertically
+pref("privacy.resistFingerprinting.letterboxing.vcenter", true);
+// tor-browser#41917 letterboxing gradient background
+pref("privacy.resistFingerprinting.letterboxing.gradient", true);
// tor-browser#41695: how many warnings we show if user closes them without restoring the window size
pref("privacy.resistFingerprinting.resizeWarnings", 3);
// tor-browser#33282: new windows start at 1400x900 when there's enough screen space, otherwise down by 200x100 blocks
=====================================
browser/base/content/browser.css
=====================================
@@ -134,6 +134,56 @@ body {
doesn't get notified on horizontal shrinking.
*/
overflow-x: hidden;
+ background: var(--letterboxing-bgcolor);
+}
+
+.letterboxing {
+ --letterboxing-border-radius: 8px;
+ --letterboxing-border-top-radius: 0;
+ --letterboxing-vertical-alignment: start;
+ --letterboxing-shadow-color: rgba(12, 12, 13, 0.10);
+ --letterboxing-bgcolor: var(--tabpanel-background-color);
+ --letterboxing-gradient-color1: var(--letterboxing-bgcolor);
+ --letterboxing-gradient-color2: color-mix(in srgb, var(--chrome-content-separator-color) 50%, var(--letterboxing-bgcolor));
+}
+
+.letterboxing.letterboxing-vcenter .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
+ --letterboxing-border-top-radius: var(--letterboxing-border-radius);
+ --letterboxing-vertical-alignment: center;
+}
+
+.letterboxing.letterboxing-gradient .browserContainer {
+ background: linear-gradient(283deg, var(--letterboxing-gradient-color1) 0%, var(--letterboxing-gradient-color2) 100%), var(--letterboxing-bgcolor);
+ box-shadow: rgba(0, 0, 0, 0.5) 0px -1px 2px;
+}
+
+/*
+ Align status bar with content.
+ TODO: switch to nested CSS selectors for conciseness when available (Firefox >= 117)
+*/
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+ > #statuspanel:not([hidden]) {
+ position: relative;
+ place-self: end left;
+ left: 0;
+ right: 0;
+ --letterboxing-status-left-radius: var(--letterboxing-border-radius);
+ --letterboxing-status-right-radius: 0;
+}
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+ > #statuspanel:not([mirror]):-moz-locale-dir(rtl),
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+ > #statuspanel[mirror]:-moz-locale-dir(ltr) {
+ left: 0;
+ right: 0;
+ --letterboxing-status-right-radius: var(--letterboxing-border-radius);
+ --letterboxing-status-left-radius: 0;
+ justify-self: right;
+}
+
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+#statuspanel-label {
+ border-radius: 0 0 var(--letterboxing-status-right-radius) var(--letterboxing-status-left-radius);
}
/**
@@ -142,21 +192,15 @@ body {
**/
.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
/* width & height to be dynamically set by RFPHelper.jsm */
- outline: 1px solid var(--chrome-content-separator-color);
+ box-shadow: 0px 4px 8px 0px var(--letterboxing-shadow-color);
+ border-radius: var(--letterboxing-border-radius);
+ border-top-left-radius: var(--letterboxing-border-top-radius);
+ border-top-right-radius: var(--letterboxing-border-top-radius);
}
-.exclude-letterboxing > browser {
- outline: initial;
-}
-
-:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
- place-content: start center;
-}
-
-/* extend down the toolbar's colors when letterboxing is enabled */
-.letterboxing {
- background-color: var(--toolbar-bgcolor);
- background-image: var(--toolbar-bgimage);
+:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode)
+ > .browserStack:not(.exclude-letterboxing) {
+ place-content: var(--letterboxing-vertical-alignment) center;
}
#toolbar-menubar[autohide="true"] {
=====================================
toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
=====================================
@@ -14,6 +14,11 @@ const kPrefLetterboxingDimensions =
"privacy.resistFingerprinting.letterboxing.dimensions";
const kPrefLetterboxingTesting =
"privacy.resistFingerprinting.letterboxing.testing";
+const kPrefLetterboxingVcenter =
+ "privacy.resistFingerprinting.letterboxing.vcenter";
+const kPrefLetterboxingGradient =
+ "privacy.resistFingerprinting.letterboxing.gradient";
+
const kTopicDOMWindowOpened = "domwindowopened";
const kPrefResizeWarnings = "privacy.resistFingerprinting.resizeWarnings";
@@ -140,6 +145,9 @@ class _RFPHelper {
// Add unconditional observers
Services.prefs.addObserver(kPrefResistFingerprinting, this);
Services.prefs.addObserver(kPrefLetterboxing, this);
+ Services.prefs.addObserver(kPrefLetterboxingVcenter, this);
+ Services.prefs.addObserver(kPrefLetterboxingGradient, this);
+
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_letterboxingDimensions",
@@ -171,6 +179,8 @@ class _RFPHelper {
// Remove unconditional observers
Services.prefs.removeObserver(kPrefResistFingerprinting, this);
+ Services.prefs.removeObserver(kPrefLetterboxingGradient, this);
+ Services.prefs.removeObserver(kPrefLetterboxingVcenter, this);
Services.prefs.removeObserver(kPrefLetterboxing, this);
// Remove the RFP observers, swallowing exceptions if they weren't present
this._removeRFPObservers();
@@ -218,6 +228,8 @@ class _RFPHelper {
this._handleSpoofEnglishChanged();
break;
case kPrefLetterboxing:
+ case kPrefLetterboxingVcenter:
+ case kPrefLetterboxingGradient:
this._handleLetterboxingPrefChanged();
break;
default:
@@ -429,8 +441,7 @@ class _RFPHelper {
});
}
- getLetterboxingDefaultRule(aBrowser) {
- let document = aBrowser.ownerDocument;
+ getLetterboxingDefaultRule(document) {
return (document._letterBoxingSizingRule ||= (() => {
// If not already cached on the document object, traverse the CSSOM and
// find the rule applying the default letterboxing styles to browsers
@@ -555,11 +566,16 @@ class _RFPHelper {
return;
}
+ let lastRoundedSize;
+
const roundDimensions = (aWidth, aHeight) => {
- const r = (aWidth, aHeight) => ({
- width: `var(--rdm-width, ${aWidth}px)`,
- height: `var(--rdm-height, ${aHeight}px)`,
- });
+ const r = (width, height) => {
+ lastRoundedSize = {width, height};
+ return {
+ width: `var(--rdm-width, ${width}px)`,
+ height: `var(--rdm-height, ${height}px)`,
+ }
+ };
let result;
@@ -642,7 +658,7 @@ class _RFPHelper {
const roundedDefault = roundDimensions(containerWidth, containerHeight);
styleChanges.queueIfNeeded(
- this.getLetterboxingDefaultRule(aBrowser),
+ this.getLetterboxingDefaultRule(aBrowser.ownerDocument),
roundedDefault
);
@@ -655,6 +671,21 @@ class _RFPHelper {
: { width: "", height: "" }; // otherwise we can keep the default (rounded) size
styleChanges.queueIfNeeded(aBrowser, roundedInline);
+ if (lastRoundedSize) {
+ // check wether the letterboxing margin is less than the border radius, and if so flatten the borders
+ let borderRadius = parseInt(win.getComputedStyle(browserContainer).getPropertyValue("--letterboxing-border-radius"));
+ if (borderRadius &&
+ (parentWidth - lastRoundedSize.width < borderRadius &&
+ parentHeight - lastRoundedSize.height < borderRadius)) {
+ borderRadius = 0;
+ } else {
+ borderRadius = "";
+ }
+ styleChanges.queueIfNeeded(browserParent, {
+ '--letterboxing-border-radius': borderRadius
+ });
+ }
+
// If the size of the content is already quantized, we do nothing.
if (!styleChanges.length) {
log(`${logPrefix} is_rounded == true`);
@@ -690,6 +721,10 @@ class _RFPHelper {
_updateSizeForTabsInWindow(aWindow) {
let tabBrowser = aWindow.gBrowser;
tabBrowser.tabpanels?.classList.add("letterboxing");
+ tabBrowser.tabpanels?.classList.toggle("letterboxing-vcenter",
+ Services.prefs.getBoolPref(kPrefLetterboxingVcenter, false));
+ tabBrowser.tabpanels?.classList.toggle("letterboxing-gradient",
+ Services.prefs.getBoolPref(kPrefLetterboxingGradient, false));
for (let tab of tabBrowser.tabs) {
let browser = tab.linkedBrowser;
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/0cb1308…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/0cb1308…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.7.0esr-13.5-1] 2 commits: fixup! Bug 32308: use direct browser sizing for letterboxing.
by ma1 (@ma1) 29 Jan '24
by ma1 (@ma1) 29 Jan '24
29 Jan '24
ma1 pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
8d25c1cc by hackademix at 2024-01-29T16:28:12+01:00
fixup! Bug 32308: use direct browser sizing for letterboxing.
Bug 41917: Make the appearance of letterboxing look more intentional
- - - - -
366c81df by hackademix at 2024-01-29T16:28:18+01:00
Bug 41917: Tor brand-specific styles.
- - - - -
6 changed files:
- browser/app/profile/001-base-profile.js
- browser/base/content/browser.css
- browser/themes/shared/browser-shared.css
- browser/themes/shared/jar.inc.mn
- + browser/themes/shared/tor-branding.css
- toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
Changes:
=====================================
browser/app/profile/001-base-profile.js
=====================================
@@ -376,6 +376,10 @@ pref("security.remote_settings.intermediates.enabled", false);
pref("dom.use_components_shim", false);
// Enable letterboxing
pref("privacy.resistFingerprinting.letterboxing", true);
+// tor-browser#41917 center letterboxed area vertically
+pref("privacy.resistFingerprinting.letterboxing.vcenter", true);
+// tor-browser#41917 letterboxing gradient background
+pref("privacy.resistFingerprinting.letterboxing.gradient", true);
// tor-browser#41695: how many warnings we show if user closes them without restoring the window size
pref("privacy.resistFingerprinting.resizeWarnings", 3);
// tor-browser#33282: new windows start at 1400x900 when there's enough screen space, otherwise down by 200x100 blocks
=====================================
browser/base/content/browser.css
=====================================
@@ -134,6 +134,56 @@ body {
doesn't get notified on horizontal shrinking.
*/
overflow-x: hidden;
+ background: var(--letterboxing-bgcolor);
+}
+
+.letterboxing {
+ --letterboxing-border-radius: 8px;
+ --letterboxing-border-top-radius: 0;
+ --letterboxing-vertical-alignment: start;
+ --letterboxing-shadow-color: rgba(12, 12, 13, 0.10);
+ --letterboxing-bgcolor: var(--tabpanel-background-color);
+ --letterboxing-gradient-color1: var(--letterboxing-bgcolor);
+ --letterboxing-gradient-color2: color-mix(in srgb, var(--chrome-content-separator-color) 50%, var(--letterboxing-bgcolor));
+}
+
+.letterboxing.letterboxing-vcenter .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
+ --letterboxing-border-top-radius: var(--letterboxing-border-radius);
+ --letterboxing-vertical-alignment: center;
+}
+
+.letterboxing.letterboxing-gradient .browserContainer {
+ background: linear-gradient(283deg, var(--letterboxing-gradient-color1) 0%, var(--letterboxing-gradient-color2) 100%), var(--letterboxing-bgcolor);
+ box-shadow: rgba(0, 0, 0, 0.5) 0px -1px 2px;
+}
+
+/*
+ Align status bar with content.
+ TODO: switch to nested CSS selectors for conciseness when available (Firefox >= 117)
+*/
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+ > #statuspanel:not([hidden]) {
+ position: relative;
+ place-self: end left;
+ left: 0;
+ right: 0;
+ --letterboxing-status-left-radius: var(--letterboxing-border-radius);
+ --letterboxing-status-right-radius: 0;
+}
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+ > #statuspanel:not([mirror]):-moz-locale-dir(rtl),
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+ > #statuspanel[mirror]:-moz-locale-dir(ltr) {
+ left: 0;
+ right: 0;
+ --letterboxing-status-right-radius: var(--letterboxing-border-radius);
+ --letterboxing-status-left-radius: 0;
+ justify-self: right;
+}
+
+.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing)
+#statuspanel-label {
+ border-radius: 0 0 var(--letterboxing-status-right-radius) var(--letterboxing-status-left-radius);
}
/**
@@ -142,21 +192,15 @@ body {
**/
.letterboxing .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) > browser {
/* width & height to be dynamically set by RFPHelper.jsm */
- outline: 1px solid var(--chrome-content-separator-color);
+ box-shadow: 0px 4px 8px 0px var(--letterboxing-shadow-color);
+ border-radius: var(--letterboxing-border-radius);
+ border-top-left-radius: var(--letterboxing-border-top-radius);
+ border-top-right-radius: var(--letterboxing-border-top-radius);
}
-.exclude-letterboxing > browser {
- outline: initial;
-}
-
-:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode) > .browserStack:not(.exclude-letterboxing) {
- place-content: start center;
-}
-
-/* extend down the toolbar's colors when letterboxing is enabled */
-.letterboxing {
- background-color: var(--toolbar-bgcolor);
- background-image: var(--toolbar-bgimage);
+:root:not([inDOMFullscreen]) .letterboxing.letterboxing-ready .browserContainer:not(.responsive-mode)
+ > .browserStack:not(.exclude-letterboxing) {
+ place-content: var(--letterboxing-vertical-alignment) center;
}
#toolbar-menubar[autohide="true"] {
=====================================
browser/themes/shared/browser-shared.css
=====================================
@@ -24,6 +24,7 @@
@import url("chrome://browser/skin/UITour.css");
@import url("chrome://global/skin/browser-colors.css");
@import url("chrome://browser/skin/tor-urlbar-button.css");
+@import url("chrome://browser/skin/tor-branding.css");
@import url("chrome://browser/skin/onionlocation.css");
@namespace html url("http://www.w3.org/1999/xhtml");
=====================================
browser/themes/shared/jar.inc.mn
=====================================
@@ -29,6 +29,7 @@
skin/classic/browser/tabs.css (../shared/tabs.css)
skin/classic/browser/toolbarbuttons.css (../shared/toolbarbuttons.css)
skin/classic/browser/toolbarbutton-icons.css (../shared/toolbarbutton-icons.css)
+ skin/classic/browser/tor-branding.css (../shared/tor-branding.css)
skin/classic/browser/tor-urlbar-button.css (../shared/tor-urlbar-button.css)
skin/classic/browser/urlbar-dynamic-results.css (../shared/urlbar-dynamic-results.css)
skin/classic/browser/urlbar-searchbar.css (../shared/urlbar-searchbar.css)
=====================================
browser/themes/shared/tor-branding.css
=====================================
@@ -0,0 +1,13 @@
+.letterboxing {
+ --letterboxing-bgcolor: var(--color-grey-light-20, #F0F0F4);
+ --letterboxing-gradient-color1: rgba(0, 219, 222, 0.02);
+ --letterboxing-gradient-color2: rgba(252, 0, 255, 0.02);
+}
+
+@media (prefers-color-scheme: dark) {
+ .letterboxing {
+ --letterboxing-bgcolor: var(--color-grey-dark-10, #52525E);
+ --letterboxing-gradient-color1: rgba(0, 219, 222, 0.06);
+ --letterboxing-gradient-color2: rgba(252, 0, 255, 0.06);
+ }
+}
\ No newline at end of file
=====================================
toolkit/components/resistfingerprinting/RFPHelper.sys.mjs
=====================================
@@ -14,6 +14,11 @@ const kPrefLetterboxingDimensions =
"privacy.resistFingerprinting.letterboxing.dimensions";
const kPrefLetterboxingTesting =
"privacy.resistFingerprinting.letterboxing.testing";
+const kPrefLetterboxingVcenter =
+ "privacy.resistFingerprinting.letterboxing.vcenter";
+const kPrefLetterboxingGradient =
+ "privacy.resistFingerprinting.letterboxing.gradient";
+
const kTopicDOMWindowOpened = "domwindowopened";
const kPrefResizeWarnings = "privacy.resistFingerprinting.resizeWarnings";
@@ -140,6 +145,9 @@ class _RFPHelper {
// Add unconditional observers
Services.prefs.addObserver(kPrefResistFingerprinting, this);
Services.prefs.addObserver(kPrefLetterboxing, this);
+ Services.prefs.addObserver(kPrefLetterboxingVcenter, this);
+ Services.prefs.addObserver(kPrefLetterboxingGradient, this);
+
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_letterboxingDimensions",
@@ -171,6 +179,8 @@ class _RFPHelper {
// Remove unconditional observers
Services.prefs.removeObserver(kPrefResistFingerprinting, this);
+ Services.prefs.removeObserver(kPrefLetterboxingGradient, this);
+ Services.prefs.removeObserver(kPrefLetterboxingVcenter, this);
Services.prefs.removeObserver(kPrefLetterboxing, this);
// Remove the RFP observers, swallowing exceptions if they weren't present
this._removeRFPObservers();
@@ -218,6 +228,8 @@ class _RFPHelper {
this._handleSpoofEnglishChanged();
break;
case kPrefLetterboxing:
+ case kPrefLetterboxingVcenter:
+ case kPrefLetterboxingGradient:
this._handleLetterboxingPrefChanged();
break;
default:
@@ -429,8 +441,7 @@ class _RFPHelper {
});
}
- getLetterboxingDefaultRule(aBrowser) {
- let document = aBrowser.ownerDocument;
+ getLetterboxingDefaultRule(document) {
return (document._letterBoxingSizingRule ||= (() => {
// If not already cached on the document object, traverse the CSSOM and
// find the rule applying the default letterboxing styles to browsers
@@ -555,11 +566,16 @@ class _RFPHelper {
return;
}
+ let lastRoundedSize;
+
const roundDimensions = (aWidth, aHeight) => {
- const r = (aWidth, aHeight) => ({
- width: `var(--rdm-width, ${aWidth}px)`,
- height: `var(--rdm-height, ${aHeight}px)`,
- });
+ const r = (width, height) => {
+ lastRoundedSize = {width, height};
+ return {
+ width: `var(--rdm-width, ${width}px)`,
+ height: `var(--rdm-height, ${height}px)`,
+ }
+ };
let result;
@@ -642,7 +658,7 @@ class _RFPHelper {
const roundedDefault = roundDimensions(containerWidth, containerHeight);
styleChanges.queueIfNeeded(
- this.getLetterboxingDefaultRule(aBrowser),
+ this.getLetterboxingDefaultRule(aBrowser.ownerDocument),
roundedDefault
);
@@ -655,6 +671,21 @@ class _RFPHelper {
: { width: "", height: "" }; // otherwise we can keep the default (rounded) size
styleChanges.queueIfNeeded(aBrowser, roundedInline);
+ if (lastRoundedSize) {
+ // check wether the letterboxing margin is less than the border radius, and if so flatten the borders
+ let borderRadius = parseInt(win.getComputedStyle(browserContainer).getPropertyValue("--letterboxing-border-radius"));
+ if (borderRadius &&
+ (parentWidth - lastRoundedSize.width < borderRadius &&
+ parentHeight - lastRoundedSize.height < borderRadius)) {
+ borderRadius = 0;
+ } else {
+ borderRadius = "";
+ }
+ styleChanges.queueIfNeeded(browserParent, {
+ '--letterboxing-border-radius': borderRadius
+ });
+ }
+
// If the size of the content is already quantized, we do nothing.
if (!styleChanges.length) {
log(`${logPrefix} is_rounded == true`);
@@ -690,6 +721,10 @@ class _RFPHelper {
_updateSizeForTabsInWindow(aWindow) {
let tabBrowser = aWindow.gBrowser;
tabBrowser.tabpanels?.classList.add("letterboxing");
+ tabBrowser.tabpanels?.classList.toggle("letterboxing-vcenter",
+ Services.prefs.getBoolPref(kPrefLetterboxingVcenter, false));
+ tabBrowser.tabpanels?.classList.toggle("letterboxing-gradient",
+ Services.prefs.getBoolPref(kPrefLetterboxingGradient, false));
for (let tab of tabBrowser.tabs) {
let browser = tab.linkedBrowser;
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/478dde…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/478dde…
You're receiving this email because of your account on gitlab.torproject.org.
1
0

[Git][tpo/applications/tor-browser][tor-browser-115.7.0esr-13.5-1] 3 commits: Temporary commit: manually place generated wasm files
by Pier Angelo Vendrame (@pierov) 26 Jan '24
by Pier Angelo Vendrame (@pierov) 26 Jan '24
26 Jan '24
Pier Angelo Vendrame pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
ebfac0ab by Cecylia Bocovich at 2024-01-26T16:27:01+00:00
Temporary commit: manually place generated wasm files
These files are built reproducibly using tor-browser-build: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/merge_re…
We're manually adding them here while working on the interface, but
eventually these should be placed in the right location using
tor-browser-build.
- - - - -
10d5eb0b by Cecylia Bocovich at 2024-01-26T16:27:01+00:00
Lox integration
- - - - -
478ddecb by Cecylia Bocovich at 2024-01-26T16:27:01+00:00
fixup! Bug 40597: Implement TorSettings module
Implement Lox backend.
- - - - -
9 changed files:
- dom/security/nsContentSecurityUtils.cpp
- + toolkit/components/lox/Lox.sys.mjs
- + toolkit/components/lox/content/lox_wasm_bg.wasm
- + toolkit/components/lox/jar.mn
- + toolkit/components/lox/lox_wasm.jsm
- + toolkit/components/lox/moz.build
- toolkit/components/moz.build
- toolkit/components/tor-launcher/TorStartupService.sys.mjs
- toolkit/modules/TorSettings.sys.mjs
Changes:
=====================================
dom/security/nsContentSecurityUtils.cpp
=====================================
@@ -618,6 +618,9 @@ bool nsContentSecurityUtils::IsEvalAllowed(JSContext* cx,
// The Browser Toolbox/Console
"debugger"_ns,
+
+ // Tor Browser's Lox wasm integration
+ "resource://gre/modules/lox_wasm.jsm"_ns,
};
// We also permit two specific idioms in eval()-like contexts. We'd like to
=====================================
toolkit/components/lox/Lox.sys.mjs
=====================================
@@ -0,0 +1,801 @@
+import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
+import {
+ clearInterval,
+ setInterval,
+} from "resource://gre/modules/Timer.sys.mjs";
+
+const lazy = {};
+ChromeUtils.defineESModuleGetters(lazy, {
+ DomainFrontRequestBuilder:
+ "resource://gre/modules/DomainFrontedRequests.sys.mjs",
+ TorConnect: "resource://gre/modules/TorConnect.sys.mjs",
+ TorConnectState: "resource://gre/modules/TorConnect.sys.mjs",
+ TorSettings: "resource://gre/modules/TorSettings.sys.mjs",
+ TorSettingsTopics: "resource://gre/modules/TorSettings.sys.mjs",
+ TorBridgeSource: "resource://gre/modules/TorSettings.sys.mjs",
+});
+XPCOMUtils.defineLazyModuleGetters(lazy, {
+ init: "resource://gre/modules/lox_wasm.jsm",
+ open_invite: "resource://gre/modules/lox_wasm.jsm",
+ handle_new_lox_credential: "resource://gre/modules/lox_wasm.jsm",
+ set_panic_hook: "resource://gre/modules/lox_wasm.jsm",
+ invitation_is_trusted: "resource://gre/modules/lox_wasm.jsm",
+ issue_invite: "resource://gre/modules/lox_wasm.jsm",
+ prepare_invite: "resource://gre/modules/lox_wasm.jsm",
+ get_invites_remaining: "resource://gre/modules/lox_wasm.jsm",
+ get_trust_level: "resource://gre/modules/lox_wasm.jsm",
+ level_up: "resource://gre/modules/lox_wasm.jsm",
+ handle_level_up: "resource://gre/modules/lox_wasm.jsm",
+ trust_promotion: "resource://gre/modules/lox_wasm.jsm",
+ handle_trust_promotion: "resource://gre/modules/lox_wasm.jsm",
+ trust_migration: "resource://gre/modules/lox_wasm.jsm",
+ handle_trust_migration: "resource://gre/modules/lox_wasm.jsm",
+ get_next_unlock: "resource://gre/modules/lox_wasm.jsm",
+ check_blockage: "resource://gre/modules/lox_wasm.jsm",
+ handle_check_blockage: "resource://gre/modules/lox_wasm.jsm",
+ blockage_migration: "resource://gre/modules/lox_wasm.jsm",
+ handle_blockage_migration: "resource://gre/modules/lox_wasm.jsm",
+});
+
+export const LoxErrors = Object.freeze({
+ BadInvite: "BadInvite",
+ MissingCredential: "MissingCredential",
+ LoxServerUnreachable: "LoxServerUnreachable",
+ NoInvitations: "NoInvitations",
+ InitError: "InitializationError",
+ NotInitialized: "NotInitialized",
+});
+
+const LoxSettingsPrefs = Object.freeze({
+ /* string: the lox credential */
+ credentials: "lox.settings.credentials",
+ invites: "lox.settings.invites",
+ events: "lox.settings.events",
+ pubkeys: "lox.settings.pubkeys",
+ enctable: "lox.settings.enctable",
+ constants: "lox.settings.constants",
+});
+
+class LoxError extends Error {
+ constructor(type) {
+ super("");
+ this.type = type;
+ }
+}
+
+class LoxImpl {
+ #initialized = false;
+ #window = null;
+ #pubKeyPromise = null;
+ #encTablePromise = null;
+ #constantsPromise = null;
+ #domainFrontedRequests = null;
+ #invites = null;
+ #pubKeys = null;
+ #encTable = null;
+ #constants = null;
+ #credentials = null;
+ #events = [];
+ #backgroundInterval = null;
+
+ observe(subject, topic, data) {
+ switch (topic) {
+ case lazy.TorSettingsTopics.SettingsChanged:
+ const { changes } = subject.wrappedJSObject;
+ if (
+ changes.includes("bridges.enabled") ||
+ changes.includes("bridges.source") ||
+ changes.includes("bridges.lox_id")
+ ) {
+ // if lox_id has changed, clear event and invite queues
+ if (changes.includes("bridges.lox_id")) {
+ this.clearEventData();
+ this.clearInvites();
+ }
+
+ // Only run background tasks if Lox is enabled
+ if (this.#inuse) {
+ if (!this.#backgroundInterval) {
+ this.#backgroundInterval = setInterval(
+ this.#backgroundTasks.bind(this),
+ 1000 * 60 * 60 * 12
+ );
+ }
+ } else if (this.#backgroundInterval) {
+ clearInterval(this.#backgroundInterval);
+ this.#backgroundInterval = null;
+ }
+ }
+ break;
+ case lazy.TorSettingsTopics.Ready:
+ // Run background tasks every 12 hours if Lox is enabled
+ if (this.#inuse) {
+ this.#backgroundInterval = setInterval(
+ this.#backgroundTasks.bind(this),
+ 1000 * 60 * 60 * 12
+ );
+ }
+ break;
+ }
+ }
+
+ get #inuse() {
+ return (
+ lazy.TorSettings.bridges.enabled === true &&
+ lazy.TorSettings.bridges.source === lazy.TorBridgeSource.Lox &&
+ lazy.TorSettings.bridges.lox_id
+ );
+ }
+
+ /**
+ * Formats and returns bridges from the stored Lox credential
+ *
+ * @param {string} loxid The id string associated with a lox credential
+ *
+ * @returns {string[]} An array of formatted bridge lines. The array is empty
+ * if there are no bridges.
+ */
+ getBridges(loxid) {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ if (loxid === null) {
+ return [];
+ }
+ if (!this.#credentials[loxid]) {
+ // This lox id doesn't correspond to a stored credential
+ throw new LoxError(LoxErrors.MissingCredential);
+ }
+ // Note: this is messy now but can be mostly removed after we have
+ // https://gitlab.torproject.org/tpo/anti-censorship/lox/-/issues/46
+ let bridgelines = JSON.parse(this.#credentials[loxid]).bridgelines;
+ let bridges = [];
+ for (const bridge of bridgelines) {
+ let addr = bridge.addr;
+ while (addr[addr.length - 1] === 0) {
+ addr.pop();
+ }
+ addr = new Uint8Array(addr);
+ let decoder = new TextDecoder("utf-8");
+ addr = decoder.decode(addr);
+
+ let info = bridge.info;
+ while (info[info.length - 1] === 0) {
+ info.pop();
+ }
+ info = new Uint8Array(info);
+ info = decoder.decode(info);
+
+ let regexpTransport = /type=([a-zA-Z0-9]*)/;
+ let transport = info.match(regexpTransport);
+ if (transport !== null) {
+ transport = transport[1];
+ } else {
+ transport = "";
+ }
+
+ let regexpFingerprint = /fingerprint=\"([a-zA-Z0-9]*)\"/;
+ let fingerprint = info.match(regexpFingerprint);
+ if (fingerprint !== null) {
+ fingerprint = fingerprint[1];
+ } else {
+ fingerprint = "";
+ }
+
+ let regexpParams = /params=Some\(\{(.*)\}\)/;
+ let params = info.match(regexpParams);
+ if (params !== null) {
+ params = params[1]
+ .replaceAll('"', "")
+ .replaceAll(": ", "=")
+ .replaceAll(",", " ");
+ } else {
+ params = "";
+ }
+
+ bridges.push(
+ `${transport} ${addr}:${bridge.port} ${fingerprint} ${params}`
+ );
+ }
+ return bridges;
+ }
+
+ #store() {
+ Services.prefs.setStringPref(LoxSettingsPrefs.pubkeys, this.#pubKeys);
+ Services.prefs.setStringPref(LoxSettingsPrefs.enctable, this.#encTable);
+ Services.prefs.setStringPref(LoxSettingsPrefs.constants, this.#constants);
+ Services.prefs.setStringPref(
+ LoxSettingsPrefs.credentials,
+ JSON.stringify(this.#credentials)
+ );
+ Services.prefs.setStringPref(
+ LoxSettingsPrefs.invites,
+ JSON.stringify(this.#invites)
+ );
+ Services.prefs.setStringPref(
+ LoxSettingsPrefs.events,
+ JSON.stringify(this.#events)
+ );
+ }
+
+ #load() {
+ if (this.#credentials === null) {
+ let cred = Services.prefs.getStringPref(LoxSettingsPrefs.credentials, "");
+ this.#credentials = cred !== "" ? JSON.parse(cred) : {};
+ let invites = Services.prefs.getStringPref(LoxSettingsPrefs.invites, "");
+ if (invites !== "") {
+ this.#invites = JSON.parse(invites);
+ }
+ let events = Services.prefs.getStringPref(LoxSettingsPrefs.events, "");
+ if (events !== "") {
+ this.#events = JSON.parse(events);
+ }
+ }
+ this.#pubKeys = Services.prefs.getStringPref(
+ LoxSettingsPrefs.pubkeys,
+ null
+ );
+ this.#encTable = Services.prefs.getStringPref(
+ LoxSettingsPrefs.enctable,
+ null
+ );
+ this.#constants = Services.prefs.getStringPref(
+ LoxSettingsPrefs.constants,
+ null
+ );
+ }
+
+ async #getPubKeys() {
+ if (this.#pubKeyPromise === null) {
+ this.#pubKeyPromise = this.#makeRequest("pubkeys", [])
+ .then(pubKeys => {
+ this.#pubKeys = JSON.stringify(pubKeys);
+ })
+ .catch(() => {
+ // We always try to update, but if that doesn't work fall back to stored data
+ if (!this.#pubKeys) {
+ throw new LoxError(LoxErrors.LoxServerUnreachable);
+ }
+ });
+ }
+ await this.#pubKeyPromise;
+ }
+
+ async #getEncTable() {
+ if (this.#encTablePromise === null) {
+ this.#encTablePromise = this.#makeRequest("reachability", [])
+ .then(encTable => {
+ this.#encTable = JSON.stringify(encTable);
+ })
+ .catch(() => {
+ // Try to update first, but if that doesn't work fall back to stored data
+ if (!this.#encTable) {
+ throw new LoxError(LoxErrors.LoxServerUnreachable);
+ }
+ });
+ }
+ await this.#encTablePromise;
+ }
+
+ async #getConstants() {
+ if (this.#constantsPromise === null) {
+ // Try to update first, but if that doesn't work fall back to stored data
+ this.#constantsPromise = this.#makeRequest("constants", [])
+ .then(constants => {
+ this.#constants = JSON.stringify(constants);
+ })
+ .catch(() => {
+ if (!this.#constants) {
+ throw new LoxError(LoxErrors.LoxServerUnreachable);
+ }
+ });
+ }
+ await this.#constantsPromise;
+ }
+
+ /**
+ * Check for blockages and attempt to perform a levelup
+ *
+ * If either blockages or a levelup happened, add an event to the event queue
+ */
+ async #backgroundTasks() {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ const loxid = lazy.TorSettings.bridges.lox_id;
+ try {
+ const levelup = await this.#attemptUpgrade(loxid);
+ if (levelup) {
+ const level = lazy.get_trust_level(this.#credentials[loxid]);
+ const newEvent = {
+ type: "levelup",
+ newlevel: level,
+ };
+ this.#events.push(newEvent);
+ this.#store();
+ }
+ } catch (err) {
+ console.log(err);
+ }
+ try {
+ const leveldown = await this.#blockageMigration(loxid);
+ if (leveldown) {
+ let level = lazy.get_trust_level(this.#credentials[loxid]);
+ const newEvent = {
+ type: "blockage",
+ newlevel: level,
+ };
+ this.#events.push(newEvent);
+ this.#store();
+ }
+ } catch (err) {
+ console.log(err);
+ }
+ }
+
+ /**
+ * Generates a new random lox id to be associated with an invitation/credential
+ */
+ #genLoxId() {
+ return crypto.randomUUID();
+ }
+
+ async init() {
+ // If lox_id is set, load it
+ Services.obs.addObserver(this, lazy.TorSettingsTopics.SettingsChanged);
+ Services.obs.addObserver(this, lazy.TorSettingsTopics.Ready);
+
+ // Hack to make the generated wasm happy
+ this.#window = {
+ crypto,
+ };
+ this.#window.window = this.#window;
+ await lazy.init(this.#window);
+ lazy.set_panic_hook();
+ if (typeof lazy.open_invite !== "function") {
+ throw new LoxError(LoxErrors.InitError);
+ }
+ this.#invites = [];
+ this.#events = [];
+ this.#load();
+ this.#initialized = true;
+ }
+
+ async uninit() {
+ Services.obs.removeObserver(this, lazy.TorSettingsTopics.SettingsChanged);
+ Services.obs.removeObserver(this, lazy.TorSettingsTopics.Ready);
+ if (this.#domainFrontedRequests !== null) {
+ try {
+ const domainFronting = await this.#domainFrontedRequests;
+ domainFronting.uninit();
+ } catch {}
+ this.#domainFrontedRequests = null;
+ }
+ this.#initialized = false;
+ this.#window = null;
+ this.#invites = null;
+ this.#pubKeys = null;
+ this.#encTable = null;
+ this.#constants = null;
+ this.#pubKeyPromise = null;
+ this.#encTablePromise = null;
+ this.#constantsPromise = null;
+ this.#credentials = null;
+ this.#events = [];
+ if (this.#backgroundInterval) {
+ clearInterval(this.#backgroundInterval);
+ }
+ this.#backgroundInterval = null;
+ }
+
+ /**
+ * Parses an input string to check if it is a valid Lox invitation
+ *
+ * @param {string} invite A Lox invitation
+ * @returns {Promise<bool>} A promise that resolves to true if the value passed
+ * in was a Lox invitation and false if it is not
+ */
+ async validateInvitation(invite) {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ try {
+ await lazy.invitation_is_trusted(invite);
+ } catch (err) {
+ console.log(err);
+ return false;
+ }
+ return true;
+ }
+
+ // Note: This is only here for testing purposes. We're going to be using telegram
+ // to issue open invitations for Lox bridges.
+ async requestOpenInvite() {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ let invite = await this.#makeRequest("invite", []);
+ console.log(invite);
+ return invite;
+ }
+
+ /**
+ * Redeems a Lox invitation to obtain a credential and bridges
+ *
+ * @param {string} invite A Lox invitation
+ * @returns {Promise<string>} A promise with the loxid of the associated credential on success
+ */
+ async redeemInvite(invite) {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ await this.#getPubKeys();
+ let request = await lazy.open_invite(invite.invite);
+ let id = this.#genLoxId();
+ let response = await this.#makeRequest(
+ "openreq",
+ JSON.parse(request).request
+ );
+ console.log("openreq response: ", response);
+ if (response.hasOwnProperty("error")) {
+ throw new LoxError(LoxErrors.BadInvite);
+ }
+ let cred = lazy.handle_new_lox_credential(
+ request,
+ JSON.stringify(response),
+ this.#pubKeys
+ );
+ this.#credentials[id] = cred;
+ this.#store();
+ return id;
+ }
+
+ /**
+ * Get metadata on all invites historically generated by this credential
+ *
+ * @returns {object[]} A list of all historical invites
+ */
+ getInvites() {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ return this.#invites;
+ }
+
+ /**
+ * Generates a new trusted Lox invitation that a user can pass to their contacts
+ *
+ * @returns {Promise<string>} A promise that resolves to a valid Lox invitation. The promise
+ * will reject if:
+ * - there is no saved Lox credential
+ * - the saved credential does not have any invitations available
+ */
+ async generateInvite() {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ const loxid = lazy.TorSettings.bridges.lox_id;
+ if (!loxid || !this.#credentials[loxid]) {
+ throw new LoxError(LoxErrors.MissingCredential);
+ }
+ await this.#getPubKeys();
+ await this.#getEncTable();
+ let level = lazy.get_trust_level(this.#credentials[loxid]);
+ if (level < 1) {
+ throw new LoxError(LoxErrors.NoInvitations);
+ }
+ let request = lazy.issue_invite(
+ JSON.stringify(this.#credentials[loxid]),
+ this.#encTable,
+ this.#pubKeys
+ );
+ let response;
+ try {
+ response = await this.#makeRequest(
+ "issueinvite",
+ JSON.parse(request).request
+ );
+ } catch {
+ throw new LoxError(LoxErrors.LoxServerUnreachable);
+ }
+ if (response.hasOwnProperty("error")) {
+ console.log(response.error);
+ throw new LoxError(LoxErrors.NoInvitations);
+ } else {
+ this.#credentials[loxid] = response;
+ const invite = lazy.prepare_invite(response);
+ this.#invites.push(invite);
+ // cap length of stored invites
+ if (this.#invites.len > 50) {
+ this.#invites.shift();
+ }
+ return invite;
+ }
+ }
+
+ /**
+ * Get the number of invites that a user has remaining
+ *
+ * @returns {Promise<int>} A promise with the number of invites that can still be generated
+ * by a user's credential. This promise will reject if:
+ * - There is no credential
+ */
+ getRemainingInviteCount() {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ const loxid = lazy.TorSettings.bridges.lox_id;
+ if (!loxid || !this.#credentials[loxid]) {
+ throw new LoxError(LoxErrors.MissingCredential);
+ }
+ return parseInt(lazy.get_invites_remaining(this.#credentials[loxid]));
+ }
+
+ async #blockageMigration(loxid) {
+ if (!loxid || !this.#credentials[loxid]) {
+ throw new LoxError(LoxErrors.MissingCredential);
+ }
+ await this.#getPubKeys();
+ let request;
+ try {
+ request = lazy.check_blockage(this.#credentials[loxid], this.#pubKeys);
+ } catch {
+ console.log("Not ready for blockage migration");
+ return false;
+ }
+ let response = await this.#makeRequest("checkblockage", request);
+ if (response.hasOwnProperty("error")) {
+ console.log(response.error);
+ throw new LoxError(LoxErrors.LoxServerUnreachable);
+ }
+ const migrationCred = lazy.handle_check_blockage(
+ this.#credentials[loxid],
+ JSON.stringify(response)
+ );
+ request = lazy.blockage_migration(
+ this.#credentials[loxid],
+ migrationCred,
+ this.#pubKeys
+ );
+ response = await this.#makeRequest("blockagemigration", request);
+ if (response.hasOwnProperty("error")) {
+ console.log(response.error);
+ throw new LoxError(LoxErrors.LoxServerUnreachable);
+ }
+ const cred = lazy.handle_blockage_migration(
+ this.#credentials[loxid],
+ JSON.stringify(response),
+ this.#pubKeys
+ );
+ this.#credentials[loxid] = cred;
+ this.#store();
+ return true;
+ }
+
+ /** Attempts to upgrade the currently saved Lox credential.
+ * If an upgrade is available, save an event in the event list.
+ *
+ * @returns {boolean} whether a levelup event occured
+ */
+ async #attemptUpgrade(loxid) {
+ if (!loxid || !this.#credentials[loxid]) {
+ throw new LoxError(LoxErrors.MissingCredential);
+ }
+ await this.#getPubKeys();
+ await this.#getEncTable();
+ await this.#getConstants();
+ let success = false;
+ let level = lazy.get_trust_level(this.#credentials[loxid]);
+ if (level < 1) {
+ // attempt trust promotion instead
+ try {
+ success = await this.#trustMigration();
+ } catch (err) {
+ console.log(err);
+ return false;
+ }
+ } else {
+ let request = lazy.level_up(
+ this.#credentials[loxid],
+ this.#encTable,
+ this.#pubKeys
+ );
+ const response = await this.#makeRequest("levelup", request);
+ if (response.hasOwnProperty("error")) {
+ console.log(response.error);
+ throw new LoxError(LoxErrors.LoxServerUnreachable);
+ }
+ const cred = lazy.handle_level_up(
+ request,
+ JSON.stringify(response),
+ this.#pubKeys
+ );
+ this.#credentials[loxid] = cred;
+ return true;
+ }
+ return success;
+ }
+
+ /**
+ * Attempt to migrate from an untrusted to a trusted Lox credential
+ *
+ * @returns {Promise<bool>} A bool value indicated whether the credential
+ * was successfully migrated.
+ */
+ async #trustMigration() {
+ const loxid = lazy.TorSettings.bridges.lox_id;
+ if (!loxid || !this.#credentials[loxid]) {
+ throw new LoxError(LoxErrors.MissingCredential);
+ }
+ await this.#getPubKeys();
+ return new Promise((resolve, reject) => {
+ let request = "";
+ try {
+ request = lazy.trust_promotion(this.#credentials[loxid], this.#pubKeys);
+ } catch (err) {
+ console.log("Not ready to upgrade");
+ resolve(false);
+ }
+ this.#makeRequest("trustpromo", JSON.parse(request).request)
+ .then(response => {
+ if (response.hasOwnProperty("error")) {
+ resolve(false);
+ }
+ console.log("Got promotion cred");
+ console.log(response);
+ console.log(request);
+ let promoCred = lazy.handle_trust_promotion(
+ request,
+ JSON.stringify(response)
+ );
+ console.log("Formatted promotion cred");
+ request = lazy.trust_migration(
+ this.#credentials[loxid],
+ promoCred,
+ this.#pubKeys
+ );
+ console.log("Formatted migration request");
+ this.#makeRequest("trustmig", JSON.parse(request).request)
+ .then(response => {
+ if (response.hasOwnProperty("error")) {
+ resolve(false);
+ }
+ console.log("Got new credential");
+ let cred = lazy.handle_trust_migration(request, response);
+ this.#credentials[loxid] = cred;
+ this.#store();
+ resolve(true);
+ })
+ .catch(err => {
+ console.log(err);
+ console.log("Failed trust migration");
+ resolve(false);
+ });
+ })
+ .catch(err => {
+ console.log(err);
+ console.log("Failed trust promotion");
+ resolve(false);
+ });
+ });
+ }
+
+ /**
+ * @typedef {object} EventData
+ *
+ * @property {string} [type] - the type of event. This should be one of:
+ * ("levelup", "blockage")
+ * @property {integer} [newlevel] - the new level, after the event. Levels count
+ * from 0, but "blockage" events can never take the user to 0, so this will always
+ * be 1 or greater.
+ */
+
+ /**
+ * Get a list of accumulated events
+ *
+ * @returns {Promise<EventData[]>} A promise with a list of the accumulated,
+ * unacknowledged events associated with a user's credential. This promise will reject if
+ * - There is no credential
+ */
+ getEventData() {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ const loxid = lazy.TorSettings.bridges.lox_id;
+ if (!loxid || !this.#credentials[loxid]) {
+ throw new LoxError(LoxErrors.MissingCredential);
+ }
+ return this.#events;
+ }
+
+ /**
+ * Clears accumulated event data
+ */
+ clearEventData() {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ this.#events = [];
+ this.#store();
+ }
+
+ /**
+ * Clears accumulated invitations
+ */
+ clearInvites() {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ this.#invites = [];
+ this.#store();
+ }
+
+ /**
+ * @typedef {object} UnlockData
+ *
+ * @property {string} date - The date-time for the next level up, formatted as YYYY-MM-DDTHH:mm:ssZ.
+ * @property {integer} nextLevel - The next level. Levels count from 0, so this will be 1 or greater.
+ *
+ */
+
+ /**
+ * Get dates at which access to new features will unlock
+ */
+ async getNextUnlock() {
+ if (!this.#initialized) {
+ throw new LoxError(LoxErrors.NotInitialized);
+ }
+ const loxid = lazy.TorSettings.bridges.lox_id;
+ if (!loxid || !this.#credentials[loxid]) {
+ throw new LoxError(LoxErrors.MissingCredential);
+ }
+ await this.#getConstants();
+ let nextUnlocks = JSON.parse(
+ lazy.get_next_unlock(this.#constants, this.#credentials[loxid])
+ );
+ const level = lazy.get_trust_level(this.#credentials[loxid]);
+ const unlocks = {
+ date: nextUnlocks.trust_level_unlock_date,
+ level: level + 1,
+ };
+ return unlocks;
+ }
+
+ async #makeRequest(procedure, args) {
+ // TODO: Customize to for Lox
+ const serviceUrl = "https://rdsys-frontend-01.torproject.org/lox";
+ const url = `${serviceUrl}/${procedure}`;
+
+ if (lazy.TorConnect.state === lazy.TorConnectState.Bootstrapped) {
+ const request = await fetch(url, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/vnd.api+json",
+ },
+ body: JSON.stringify(args),
+ });
+ return request.json();
+ }
+
+ if (this.#domainFrontedRequests === null) {
+ this.#domainFrontedRequests = new Promise((resolve, reject) => {
+ // TODO: Customize to the values for Lox
+ const reflector = Services.prefs.getStringPref(
+ "extensions.torlauncher.bridgedb_reflector"
+ );
+ const front = Services.prefs.getStringPref(
+ "extensions.torlauncher.bridgedb_front"
+ );
+ const builder = new lazy.DomainFrontRequestBuilder();
+ builder
+ .init(reflector, front)
+ .then(() => resolve(builder))
+ .catch(reject);
+ });
+ }
+ const builder = await this.#domainFrontedRequests;
+ return builder.buildPostRequest(url, args);
+ }
+}
+
+export const Lox = new LoxImpl();
=====================================
toolkit/components/lox/content/lox_wasm_bg.wasm
=====================================
Binary files /dev/null and b/toolkit/components/lox/content/lox_wasm_bg.wasm differ
=====================================
toolkit/components/lox/jar.mn
=====================================
@@ -0,0 +1,2 @@
+toolkit.jar:
+ content/global/lox/lox_wasm_bg.wasm (content/lox_wasm_bg.wasm)
=====================================
toolkit/components/lox/lox_wasm.jsm
=====================================
@@ -0,0 +1,1217 @@
+var EXPORTED_SYMBOLS = ["set_panic_hook", "open_invite", "handle_new_lox_credential", "trust_promotion", "handle_trust_promotion", "trust_migration", "handle_trust_migration", "level_up", "handle_level_up", "issue_invite", "handle_issue_invite", "prepare_invite", "redeem_invite", "handle_redeem_invite", "check_blockage", "handle_check_blockage", "blockage_migration", "handle_blockage_migration", "get_last_upgrade_time", "get_trust_level", "get_invites_remaining", "get_issued_invite_expiry", "get_received_invite_expiry", "get_bridgelines_from_bucket", "invitation_is_trusted", "get_next_unlock", "init", "initSync"];
+
+let wasm;
+let module;
+
+const heap = new Array(128).fill(undefined);
+
+heap.push(undefined, null, true, false);
+
+function getObject(idx) { return heap[idx]; }
+
+let heap_next = heap.length;
+
+function dropObject(idx) {
+ if (idx < 132) return;
+ heap[idx] = heap_next;
+ heap_next = idx;
+}
+
+function takeObject(idx) {
+ const ret = getObject(idx);
+ dropObject(idx);
+ return ret;
+}
+
+const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
+
+if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
+
+let cachedUint8Memory0 = null;
+
+function getUint8Memory0() {
+ if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
+ cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
+ }
+ return cachedUint8Memory0;
+}
+
+function getStringFromWasm0(ptr, len) {
+ ptr = ptr >>> 0;
+ return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
+}
+
+function addHeapObject(obj) {
+ if (heap_next === heap.length) heap.push(heap.length + 1);
+ const idx = heap_next;
+ heap_next = heap[idx];
+
+ heap[idx] = obj;
+ return idx;
+}
+/**
+*/
+function set_panic_hook() {
+ wasm.set_panic_hook();
+}
+
+let WASM_VECTOR_LEN = 0;
+
+function passArray8ToWasm0(arg, malloc) {
+ const ptr = malloc(arg.length * 1, 1) >>> 0;
+ getUint8Memory0().set(arg, ptr / 1);
+ WASM_VECTOR_LEN = arg.length;
+ return ptr;
+}
+
+let cachedInt32Memory0 = null;
+
+function getInt32Memory0() {
+ if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) {
+ cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
+ }
+ return cachedInt32Memory0;
+}
+/**
+* @param {Uint8Array} invite
+* @returns {string}
+*/
+function open_invite(invite) {
+ let deferred3_0;
+ let deferred3_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passArray8ToWasm0(invite, wasm.__wbindgen_malloc);
+ const len0 = WASM_VECTOR_LEN;
+ wasm.open_invite(retptr, ptr0, len0);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr2 = r0;
+ var len2 = r1;
+ if (r3) {
+ ptr2 = 0; len2 = 0;
+ throw takeObject(r2);
+ }
+ deferred3_0 = ptr2;
+ deferred3_1 = len2;
+ return getStringFromWasm0(ptr2, len2);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
+ }
+}
+
+const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
+
+const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
+ ? function (arg, view) {
+ return cachedTextEncoder.encodeInto(arg, view);
+}
+ : function (arg, view) {
+ const buf = cachedTextEncoder.encode(arg);
+ view.set(buf);
+ return {
+ read: arg.length,
+ written: buf.length
+ };
+});
+
+function passStringToWasm0(arg, malloc, realloc) {
+
+ if (realloc === undefined) {
+ const buf = cachedTextEncoder.encode(arg);
+ const ptr = malloc(buf.length, 1) >>> 0;
+ getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
+ WASM_VECTOR_LEN = buf.length;
+ return ptr;
+ }
+
+ let len = arg.length;
+ let ptr = malloc(len, 1) >>> 0;
+
+ const mem = getUint8Memory0();
+
+ let offset = 0;
+
+ for (; offset < len; offset++) {
+ const code = arg.charCodeAt(offset);
+ if (code > 0x7F) break;
+ mem[ptr + offset] = code;
+ }
+
+ if (offset !== len) {
+ if (offset !== 0) {
+ arg = arg.slice(offset);
+ }
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
+ const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
+ const ret = encodeString(arg, view);
+
+ offset += ret.written;
+ }
+
+ WASM_VECTOR_LEN = offset;
+ return ptr;
+}
+/**
+* @param {string} open_lox_result
+* @param {string} open_lox_response
+* @param {string} lox_pub
+* @returns {string}
+*/
+function handle_new_lox_credential(open_lox_result, open_lox_response, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(open_lox_result, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(open_lox_response, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.handle_new_lox_credential(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} open_lox_cred
+* @param {string} lox_pub
+* @returns {string}
+*/
+function trust_promotion(open_lox_cred, lox_pub) {
+ let deferred4_0;
+ let deferred4_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(open_lox_cred, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ wasm.trust_promotion(retptr, ptr0, len0, ptr1, len1);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr3 = r0;
+ var len3 = r1;
+ if (r3) {
+ ptr3 = 0; len3 = 0;
+ throw takeObject(r2);
+ }
+ deferred4_0 = ptr3;
+ deferred4_1 = len3;
+ return getStringFromWasm0(ptr3, len3);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
+ }
+}
+
+/**
+* @param {string} trust_promo_request
+* @param {string} trust_promo_response
+* @returns {string}
+*/
+function handle_trust_promotion(trust_promo_request, trust_promo_response) {
+ let deferred4_0;
+ let deferred4_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(trust_promo_request, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(trust_promo_response, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ wasm.handle_trust_promotion(retptr, ptr0, len0, ptr1, len1);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr3 = r0;
+ var len3 = r1;
+ if (r3) {
+ ptr3 = 0; len3 = 0;
+ throw takeObject(r2);
+ }
+ deferred4_0 = ptr3;
+ deferred4_1 = len3;
+ return getStringFromWasm0(ptr3, len3);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
+ }
+}
+
+/**
+* @param {string} open_lox_cred
+* @param {string} trust_promo_cred
+* @param {string} lox_pub
+* @returns {string}
+*/
+function trust_migration(open_lox_cred, trust_promo_cred, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(open_lox_cred, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(trust_promo_cred, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.trust_migration(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} trust_migration_request
+* @param {string} trust_migration_response
+* @param {string} lox_pub
+* @returns {string}
+*/
+function handle_trust_migration(trust_migration_request, trust_migration_response, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(trust_migration_request, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(trust_migration_response, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.handle_trust_migration(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} level_one_cred
+* @param {string} encrypted_table
+* @param {string} lox_pub
+* @returns {string}
+*/
+function level_up(level_one_cred, encrypted_table, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(level_one_cred, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(encrypted_table, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.level_up(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} levelup_request
+* @param {string} levelup_response
+* @param {string} lox_pub
+* @returns {string}
+*/
+function handle_level_up(levelup_request, levelup_response, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(levelup_request, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(levelup_response, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.handle_level_up(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} trusted_cred
+* @param {string} encrypted_table
+* @param {string} lox_pub
+* @returns {string}
+*/
+function issue_invite(trusted_cred, encrypted_table, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(trusted_cred, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(encrypted_table, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.issue_invite(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} issue_invite_request
+* @param {string} issue_invite_response
+* @param {string} lox_pub
+* @returns {string}
+*/
+function handle_issue_invite(issue_invite_request, issue_invite_response, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(issue_invite_request, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(issue_invite_response, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.handle_issue_invite(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} invitation_cred
+* @returns {string}
+*/
+function prepare_invite(invitation_cred) {
+ let deferred3_0;
+ let deferred3_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(invitation_cred, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ wasm.prepare_invite(retptr, ptr0, len0);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr2 = r0;
+ var len2 = r1;
+ if (r3) {
+ ptr2 = 0; len2 = 0;
+ throw takeObject(r2);
+ }
+ deferred3_0 = ptr2;
+ deferred3_1 = len2;
+ return getStringFromWasm0(ptr2, len2);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
+ }
+}
+
+/**
+* @param {string} invitation
+* @param {string} lox_pub
+* @returns {string}
+*/
+function redeem_invite(invitation, lox_pub) {
+ let deferred4_0;
+ let deferred4_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(invitation, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ wasm.redeem_invite(retptr, ptr0, len0, ptr1, len1);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr3 = r0;
+ var len3 = r1;
+ if (r3) {
+ ptr3 = 0; len3 = 0;
+ throw takeObject(r2);
+ }
+ deferred4_0 = ptr3;
+ deferred4_1 = len3;
+ return getStringFromWasm0(ptr3, len3);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
+ }
+}
+
+/**
+* @param {string} redeem_invite_request
+* @param {string} redeem_invite_response
+* @param {string} lox_pub
+* @returns {string}
+*/
+function handle_redeem_invite(redeem_invite_request, redeem_invite_response, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(redeem_invite_request, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(redeem_invite_response, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.handle_redeem_invite(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} lox_cred
+* @param {string} lox_pub
+* @returns {string}
+*/
+function check_blockage(lox_cred, lox_pub) {
+ let deferred4_0;
+ let deferred4_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(lox_cred, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ wasm.check_blockage(retptr, ptr0, len0, ptr1, len1);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr3 = r0;
+ var len3 = r1;
+ if (r3) {
+ ptr3 = 0; len3 = 0;
+ throw takeObject(r2);
+ }
+ deferred4_0 = ptr3;
+ deferred4_1 = len3;
+ return getStringFromWasm0(ptr3, len3);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
+ }
+}
+
+/**
+* @param {string} check_blockage_request
+* @param {string} check_blockage_response
+* @returns {string}
+*/
+function handle_check_blockage(check_blockage_request, check_blockage_response) {
+ let deferred4_0;
+ let deferred4_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(check_blockage_request, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(check_blockage_response, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ wasm.handle_check_blockage(retptr, ptr0, len0, ptr1, len1);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr3 = r0;
+ var len3 = r1;
+ if (r3) {
+ ptr3 = 0; len3 = 0;
+ throw takeObject(r2);
+ }
+ deferred4_0 = ptr3;
+ deferred4_1 = len3;
+ return getStringFromWasm0(ptr3, len3);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
+ }
+}
+
+/**
+* @param {string} lox_cred
+* @param {string} check_migration_cred
+* @param {string} lox_pub
+* @returns {string}
+*/
+function blockage_migration(lox_cred, check_migration_cred, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(lox_cred, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(check_migration_cred, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.blockage_migration(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} blockage_migration_request
+* @param {string} blockage_migration_response
+* @param {string} lox_pub
+* @returns {string}
+*/
+function handle_blockage_migration(blockage_migration_request, blockage_migration_response, lox_pub) {
+ let deferred5_0;
+ let deferred5_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(blockage_migration_request, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(blockage_migration_response, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ const ptr2 = passStringToWasm0(lox_pub, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len2 = WASM_VECTOR_LEN;
+ wasm.handle_blockage_migration(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr4 = r0;
+ var len4 = r1;
+ if (r3) {
+ ptr4 = 0; len4 = 0;
+ throw takeObject(r2);
+ }
+ deferred5_0 = ptr4;
+ deferred5_1 = len4;
+ return getStringFromWasm0(ptr4, len4);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
+ }
+}
+
+/**
+* @param {string} lox_cred_str
+* @returns {string}
+*/
+function get_last_upgrade_time(lox_cred_str) {
+ let deferred3_0;
+ let deferred3_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(lox_cred_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ wasm.get_last_upgrade_time(retptr, ptr0, len0);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr2 = r0;
+ var len2 = r1;
+ if (r3) {
+ ptr2 = 0; len2 = 0;
+ throw takeObject(r2);
+ }
+ deferred3_0 = ptr2;
+ deferred3_1 = len2;
+ return getStringFromWasm0(ptr2, len2);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
+ }
+}
+
+/**
+* @param {string} lox_cred_str
+* @returns {string}
+*/
+function get_trust_level(lox_cred_str) {
+ let deferred3_0;
+ let deferred3_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(lox_cred_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ wasm.get_trust_level(retptr, ptr0, len0);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr2 = r0;
+ var len2 = r1;
+ if (r3) {
+ ptr2 = 0; len2 = 0;
+ throw takeObject(r2);
+ }
+ deferred3_0 = ptr2;
+ deferred3_1 = len2;
+ return getStringFromWasm0(ptr2, len2);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
+ }
+}
+
+/**
+* @param {string} lox_cred_str
+* @returns {string}
+*/
+function get_invites_remaining(lox_cred_str) {
+ let deferred3_0;
+ let deferred3_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(lox_cred_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ wasm.get_invites_remaining(retptr, ptr0, len0);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr2 = r0;
+ var len2 = r1;
+ if (r3) {
+ ptr2 = 0; len2 = 0;
+ throw takeObject(r2);
+ }
+ deferred3_0 = ptr2;
+ deferred3_1 = len2;
+ return getStringFromWasm0(ptr2, len2);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
+ }
+}
+
+/**
+* @param {string} lox_cred_str
+* @returns {string}
+*/
+function get_issued_invite_expiry(lox_cred_str) {
+ let deferred3_0;
+ let deferred3_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(lox_cred_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ wasm.get_issued_invite_expiry(retptr, ptr0, len0);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr2 = r0;
+ var len2 = r1;
+ if (r3) {
+ ptr2 = 0; len2 = 0;
+ throw takeObject(r2);
+ }
+ deferred3_0 = ptr2;
+ deferred3_1 = len2;
+ return getStringFromWasm0(ptr2, len2);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
+ }
+}
+
+/**
+* @param {string} invite_cred_str
+* @returns {string}
+*/
+function get_received_invite_expiry(invite_cred_str) {
+ let deferred3_0;
+ let deferred3_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(invite_cred_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ wasm.get_received_invite_expiry(retptr, ptr0, len0);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr2 = r0;
+ var len2 = r1;
+ if (r3) {
+ ptr2 = 0; len2 = 0;
+ throw takeObject(r2);
+ }
+ deferred3_0 = ptr2;
+ deferred3_1 = len2;
+ return getStringFromWasm0(ptr2, len2);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
+ }
+}
+
+/**
+* @param {string} lox_cred_str
+* @param {string} encrypted_table
+* @returns {string}
+*/
+function get_bridgelines_from_bucket(lox_cred_str, encrypted_table) {
+ let deferred4_0;
+ let deferred4_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(lox_cred_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(encrypted_table, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ wasm.get_bridgelines_from_bucket(retptr, ptr0, len0, ptr1, len1);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr3 = r0;
+ var len3 = r1;
+ if (r3) {
+ ptr3 = 0; len3 = 0;
+ throw takeObject(r2);
+ }
+ deferred4_0 = ptr3;
+ deferred4_1 = len3;
+ return getStringFromWasm0(ptr3, len3);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
+ }
+}
+
+/**
+* @param {string} unspecified_invitation_str
+* @returns {boolean}
+*/
+function invitation_is_trusted(unspecified_invitation_str) {
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(unspecified_invitation_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ wasm.invitation_is_trusted(retptr, ptr0, len0);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ if (r2) {
+ throw takeObject(r1);
+ }
+ return r0 !== 0;
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ }
+}
+
+/**
+* @param {string} constants_str
+* @param {string} lox_cred_str
+* @returns {string}
+*/
+function get_next_unlock(constants_str, lox_cred_str) {
+ let deferred4_0;
+ let deferred4_1;
+ try {
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
+ const ptr0 = passStringToWasm0(constants_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ptr1 = passStringToWasm0(lox_cred_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ wasm.get_next_unlock(retptr, ptr0, len0, ptr1, len1);
+ var r0 = getInt32Memory0()[retptr / 4 + 0];
+ var r1 = getInt32Memory0()[retptr / 4 + 1];
+ var r2 = getInt32Memory0()[retptr / 4 + 2];
+ var r3 = getInt32Memory0()[retptr / 4 + 3];
+ var ptr3 = r0;
+ var len3 = r1;
+ if (r3) {
+ ptr3 = 0; len3 = 0;
+ throw takeObject(r2);
+ }
+ deferred4_0 = ptr3;
+ deferred4_1 = len3;
+ return getStringFromWasm0(ptr3, len3);
+ } finally {
+ wasm.__wbindgen_add_to_stack_pointer(16);
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
+ }
+}
+
+function handleError(f, args) {
+ try {
+ return f.apply(this, args);
+ } catch (e) {
+ wasm.__wbindgen_exn_store(addHeapObject(e));
+ }
+}
+
+async function __wbg_load(module, imports) {
+ if (typeof Response === 'function' && module instanceof Response) {
+ if (typeof WebAssembly.instantiateStreaming === 'function') {
+ try {
+ return await WebAssembly.instantiateStreaming(module, imports);
+
+ } catch (e) {
+ if (module.headers.get('Content-Type') != 'application/wasm') {
+ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
+
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ const bytes = await module.arrayBuffer();
+ return await WebAssembly.instantiate(bytes, imports);
+
+ } else {
+ const instance = await WebAssembly.instantiate(module, imports);
+
+ if (instance instanceof WebAssembly.Instance) {
+ return { instance, module };
+
+ } else {
+ return instance;
+ }
+ }
+}
+
+function __wbg_get_imports(window) {
+ const imports = {};
+ imports.wbg = {};
+ imports.wbg.__wbg_new0_622c21a64f3d83ea = function() {
+ const ret = new Date();
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_getTime_9272be78826033e1 = function(arg0) {
+ const ret = getObject(arg0).getTime();
+ return ret;
+ };
+ imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
+ takeObject(arg0);
+ };
+ imports.wbg.__wbg_log_9b9925d843c39805 = function(arg0, arg1) {
+ console.log(getStringFromWasm0(arg0, arg1));
+ };
+ imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
+ const ret = getStringFromWasm0(arg0, arg1);
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_new_abda76e883ba8a5f = function() {
+ const ret = new Error();
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_stack_658279fe44541cf6 = function(arg0, arg1) {
+ const ret = getObject(arg1).stack;
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len1 = WASM_VECTOR_LEN;
+ getInt32Memory0()[arg0 / 4 + 1] = len1;
+ getInt32Memory0()[arg0 / 4 + 0] = ptr1;
+ };
+ imports.wbg.__wbg_error_f851667af71bcfc6 = function(arg0, arg1) {
+ let deferred0_0;
+ let deferred0_1;
+ try {
+ deferred0_0 = arg0;
+ deferred0_1 = arg1;
+ console.error(getStringFromWasm0(arg0, arg1));
+ } finally {
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
+ }
+ };
+ imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
+ const ret = getObject(arg0);
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_crypto_c48a774b022d20ac = function(arg0) {
+ const ret = getObject(arg0).crypto;
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbindgen_is_object = function(arg0) {
+ const val = getObject(arg0);
+ const ret = typeof(val) === 'object' && val !== null;
+ return ret;
+ };
+ imports.wbg.__wbg_process_298734cf255a885d = function(arg0) {
+ const ret = getObject(arg0).process;
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_versions_e2e78e134e3e5d01 = function(arg0) {
+ const ret = getObject(arg0).versions;
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_node_1cd7a5d853dbea79 = function(arg0) {
+ const ret = getObject(arg0).node;
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbindgen_is_string = function(arg0) {
+ const ret = typeof(getObject(arg0)) === 'string';
+ return ret;
+ };
+ imports.wbg.__wbg_require_8f08ceecec0f4fee = function() { return handleError(function () {
+ const ret = module.require;
+ return addHeapObject(ret);
+ }, arguments) };
+ imports.wbg.__wbindgen_is_function = function(arg0) {
+ const ret = typeof(getObject(arg0)) === 'function';
+ return ret;
+ };
+ imports.wbg.__wbg_call_5da1969d7cd31ccd = function() { return handleError(function (arg0, arg1, arg2) {
+ const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
+ return addHeapObject(ret);
+ }, arguments) };
+ imports.wbg.__wbg_msCrypto_bcb970640f50a1e8 = function(arg0) {
+ const ret = getObject(arg0).msCrypto;
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_newwithlength_6c2df9e2f3028c43 = function(arg0) {
+ const ret = new Uint8Array(arg0 >>> 0);
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_self_f0e34d89f33b99fd = function() { return handleError(function () {
+ const ret = window;
+ return addHeapObject(ret);
+ }, arguments) };
+ imports.wbg.__wbg_window_d3b084224f4774d7 = function() { return handleError(function () {
+ const ret = window.window;
+ return addHeapObject(ret);
+ }, arguments) };
+ imports.wbg.__wbg_globalThis_9caa27ff917c6860 = function() { return handleError(function () {
+ const ret = globalThis.globalThis;
+ return addHeapObject(ret);
+ }, arguments) };
+ imports.wbg.__wbg_global_35dfdd59a4da3e74 = function() { return handleError(function () {
+ const ret = global.global;
+ return addHeapObject(ret);
+ }, arguments) };
+ imports.wbg.__wbindgen_is_undefined = function(arg0) {
+ const ret = getObject(arg0) === undefined;
+ return ret;
+ };
+ imports.wbg.__wbg_newnoargs_c62ea9419c21fbac = function(arg0, arg1) {
+ const ret = new Function(getStringFromWasm0(arg0, arg1));
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_call_90c26b09837aba1c = function() { return handleError(function (arg0, arg1) {
+ const ret = getObject(arg0).call(getObject(arg1));
+ return addHeapObject(ret);
+ }, arguments) };
+ imports.wbg.__wbindgen_memory = function() {
+ const ret = wasm.memory;
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_buffer_a448f833075b71ba = function(arg0) {
+ const ret = getObject(arg0).buffer;
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_newwithbyteoffsetandlength_d0482f893617af71 = function(arg0, arg1, arg2) {
+ const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_randomFillSync_dc1e9a60c158336d = function() { return handleError(function (arg0, arg1) {
+ getObject(arg0).randomFillSync(takeObject(arg1));
+ }, arguments) };
+ imports.wbg.__wbg_subarray_2e940e41c0f5a1d9 = function(arg0, arg1, arg2) {
+ const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_getRandomValues_37fa2ca9e4e07fab = function() { return handleError(function (arg0, arg1) {
+ getObject(arg0).getRandomValues(getObject(arg1));
+ }, arguments) };
+ imports.wbg.__wbg_new_8f67e318f15d7254 = function(arg0) {
+ const ret = new Uint8Array(getObject(arg0));
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_set_2357bf09366ee480 = function(arg0, arg1, arg2) {
+ getObject(arg0).set(getObject(arg1), arg2 >>> 0);
+ };
+ imports.wbg.__wbindgen_throw = function(arg0, arg1) {
+ throw new Error(getStringFromWasm0(arg0, arg1));
+ };
+
+ return imports;
+}
+
+function __wbg_init_memory(imports, maybe_memory) {
+
+}
+
+function __wbg_finalize_init(instance, module) {
+ wasm = instance.exports;
+ init.__wbindgen_wasm_module = module;
+ cachedInt32Memory0 = null;
+ cachedUint8Memory0 = null;
+
+
+ return wasm;
+}
+
+function initSync(module, window) {
+ if (wasm !== undefined) return wasm;
+
+ const imports = __wbg_get_imports(window);
+
+ __wbg_init_memory(imports);
+
+ if (!(module instanceof WebAssembly.Module)) {
+ module = new WebAssembly.Module(module);
+ }
+
+ const instance = new WebAssembly.Instance(module, imports);
+
+ return __wbg_finalize_init(instance, module);
+}
+
+async function init(window, input) {
+ if (wasm !== undefined) return wasm;
+
+ if (typeof input === 'undefined') {{
+ input = "chrome://global/content/lox/lox_wasm_bg.wasm";
+ }}
+ const imports = __wbg_get_imports(window);
+
+ if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
+ input = fetch(input);
+ }
+
+ __wbg_init_memory(imports);
+
+ const { instance, module } = await __wbg_load(await input, imports);
+
+ return __wbg_finalize_init(instance, module);
+}
+
=====================================
toolkit/components/lox/moz.build
=====================================
@@ -0,0 +1,7 @@
+EXTRA_JS_MODULES += [
+ "Lox.sys.mjs",
+ # Let's keep the old jsm format until wasm-bindgen is updated
+ "lox_wasm.jsm",
+]
+
+JAR_MANIFESTS += ["jar.mn"]
=====================================
toolkit/components/moz.build
=====================================
@@ -46,6 +46,7 @@ DIRS += [
"httpsonlyerror",
"jsoncpp/src/lib_json",
"kvstore",
+ "lox",
"mediasniffer",
"mozintl",
"mozprotocol",
=====================================
toolkit/components/tor-launcher/TorStartupService.sys.mjs
=====================================
@@ -54,5 +54,6 @@ export class TorStartupService {
lazy.TorProviderBuilder.uninit();
lazy.TorLauncherUtil.cleanupTempDirectories();
+ lazy.TorSettings.uninit();
}
}
=====================================
toolkit/modules/TorSettings.sys.mjs
=====================================
@@ -8,6 +8,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
TorLauncherUtil: "resource://gre/modules/TorLauncherUtil.sys.mjs",
TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs",
TorProviderTopics: "resource://gre/modules/TorProviderBuilder.sys.mjs",
+ Lox: "resource://gre/modules/Lox.sys.mjs",
});
ChromeUtils.defineLazyGetter(lazy, "logger", () => {
@@ -40,6 +41,8 @@ const TorSettingsPrefs = Object.freeze({
enabled: "torbrowser.settings.bridges.enabled",
/* int: See TorBridgeSource */
source: "torbrowser.settings.bridges.source",
+ /* string: output of crypto.randomUUID() */
+ lox_id: "torbrowser.settings.bridges.lox_id",
/* string: obfs4|meek-azure|snowflake|etc */
builtin_type: "torbrowser.settings.bridges.builtin_type",
/* preference branch: each child branch should be a bridge string */
@@ -86,6 +89,7 @@ export const TorBridgeSource = Object.freeze({
BuiltIn: 0,
BridgeDB: 1,
UserProvided: 2,
+ Lox: 3,
});
export const TorProxyType = Object.freeze({
@@ -159,6 +163,7 @@ class TorSettingsImpl {
bridges: {
enabled: false,
source: TorBridgeSource.Invalid,
+ lox_id: "",
builtin_type: "",
bridge_strings: [],
},
@@ -292,6 +297,20 @@ class TorSettingsImpl {
this.bridges.source = TorBridgeSource.Invalid;
},
},
+ /**
+ * The lox id is used with the Lox "source", and remains set with the stored value when
+ * other sources are used.
+ *
+ * @type {string}
+ */
+ lox_id: {
+ callback: (val, addError) => {
+ if (!val) {
+ return;
+ }
+ this.bridges.bridge_strings = lazy.Lox.getBridges(val);
+ },
+ },
});
this.#addProperties("proxy", {
enabled: {},
@@ -379,6 +398,9 @@ class TorSettingsImpl {
if (this.bridges.source !== TorBridgeSource.BuiltIn) {
this.bridges.builtin_type = "";
}
+ if (this.bridges.source !== TorBridgeSource.Lox) {
+ this.bridges.lox_id = "";
+ }
if (!this.proxy.enabled) {
this.proxy.type = TorProxyType.Invalid;
this.proxy.address = "";
@@ -639,6 +661,14 @@ class TorSettingsImpl {
lazy.logger.error("Could not load the built-in PT config.", e);
}
+ // Initialize this before loading from prefs because we need Lox initialized before
+ // any calls to Lox.getBridges()
+ try {
+ await lazy.Lox.init();
+ } catch (e) {
+ lazy.logger.error("Could not initialize Lox.", e.type);
+ }
+
// TODO: We could use a shared promise, and wait for it to be fullfilled
// instead of Service.obs.
if (lazy.TorLauncherUtil.shouldStartAndOwnTor) {
@@ -668,6 +698,13 @@ class TorSettingsImpl {
}
}
+ /**
+ * Unload or uninit our settings, and unregister observers.
+ */
+ async uninit() {
+ await lazy.Lox.uninit();
+ }
+
/**
* Check whether the object has been successfully initialized, and throw if
* it has not.
@@ -738,6 +775,10 @@ class TorSettingsImpl {
TorSettingsPrefs.bridges.source,
TorBridgeSource.Invalid
);
+ this.bridges.lox_id = Services.prefs.getStringPref(
+ TorSettingsPrefs.bridges.lox_id,
+ ""
+ );
if (this.bridges.source == TorBridgeSource.BuiltIn) {
this.bridges.builtin_type = Services.prefs.getStringPref(
TorSettingsPrefs.bridges.builtin_type,
@@ -823,6 +864,10 @@ class TorSettingsImpl {
TorSettingsPrefs.bridges.builtin_type,
this.bridges.builtin_type
);
+ Services.prefs.setStringPref(
+ TorSettingsPrefs.bridges.lox_id,
+ this.bridges.lox_id
+ );
// erase existing bridge strings
const bridgeBranchPrefs = Services.prefs
.getBranch(TorSettingsPrefs.bridges.bridge_strings)
@@ -1013,6 +1058,9 @@ class TorSettingsImpl {
case TorBridgeSource.BuiltIn:
this.bridges.builtin_type = settings.bridges.builtin_type;
break;
+ case TorBridgeSource.Lox:
+ this.bridges.lox_id = settings.bridges.lox_id;
+ break;
case TorBridgeSource.Invalid:
break;
}
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/a48e43…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/a48e43…
You're receiving this email because of your account on gitlab.torproject.org.
1
0