tbb-commits
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 20073 discussions
[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
[Git][tpo/applications/tor-browser][tor-browser-115.7.0esr-13.5-1] 2 commits: fixup! Bug 40597: Implement TorSettings module
by richard (@richard) 26 Jan '24
by richard (@richard) 26 Jan '24
26 Jan '24
richard pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
bb028644 by Pier Angelo Vendrame at 2024-01-26T11:31:15+01:00
fixup! Bug 40597: Implement TorSettings module
Bug 42384: Use TorSettings's initialization promise to handle race
conditions
We now have a race condition for which the notification about
TorSettings being ready is sent before TorConnect can observe this
topic.
A while ago, we introduced an initialization promise to TorSettings,
therefore we can use it instead of Service.obs and avoid this race
condition.
Also, fixed quicksettings ignored in TorSettings.setSettings.
- - - - -
a48e4389 by Pier Angelo Vendrame at 2024-01-26T11:35:10+01:00
fixup! Bug 42247: Android helpers for the TorProvider
Update the cached mSettings whenever someone one the GeckoView side
changes any TorSettings settings.
- - - - -
4 changed files:
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
- toolkit/modules/TorAndroidIntegration.sys.mjs
- toolkit/modules/TorConnect.sys.mjs
- toolkit/modules/TorSettings.sys.mjs
Changes:
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
=====================================
@@ -47,6 +47,8 @@ public class TorIntegrationAndroid implements BundleEventListener {
private static final String EVENT_BOOTSTRAP_COMPLETE = "GeckoView:Tor:BootstrapComplete";
private static final String EVENT_BOOTSTRAP_ERROR = "GeckoView:Tor:BootstrapError";
private static final String EVENT_SETTINGS_OPEN = "GeckoView:Tor:OpenSettings";
+ private static final String EVENT_SETTINGS_READY = "GeckoView:Tor:SettingsReady";
+ private static final String EVENT_SETTINGS_CHANGED = "GeckoView:Tor:SettingsChanged";
// Events we emit
private static final String EVENT_SETTINGS_GET = "GeckoView:Tor:SettingsGet";
@@ -57,7 +59,6 @@ public class TorIntegrationAndroid implements BundleEventListener {
private static final String EVENT_BOOTSTRAP_BEGIN_AUTO = "GeckoView:Tor:BootstrapBeginAuto";
private static final String EVENT_BOOTSTRAP_CANCEL = "GeckoView:Tor:BootstrapCancel";
private static final String EVENT_BOOTSTRAP_GET_STATE = "GeckoView:Tor:BootstrapGetState";
- private static final String EVENT_SETTINGS_READY = "GeckoView:Tor:SettingsReady";
private static final String CONTROL_PORT_FILE = "/control-ipc";
private static final String SOCKS_FILE = "/socks-ipc";
@@ -112,6 +113,7 @@ public class TorIntegrationAndroid implements BundleEventListener {
EVENT_MEEK_START,
EVENT_MEEK_STOP,
EVENT_SETTINGS_READY,
+ EVENT_SETTINGS_CHANGED,
EVENT_BOOTSTRAP_STATE_CHANGED,
EVENT_BOOTSTRAP_PROGRESS,
EVENT_BOOTSTRAP_COMPLETE,
@@ -136,6 +138,14 @@ public class TorIntegrationAndroid implements BundleEventListener {
} catch(Exception e) {
Log.e(TAG, "SettingsLoader error: "+ e.toString());
}
+ } else if (EVENT_SETTINGS_CHANGED.equals(event)) {
+ GeckoBundle newSettings = message.getBundle("settings");
+ if (newSettings != null) {
+ // TODO: Should we notify listeners?
+ mSettings = new TorSettings(newSettings);
+ } else {
+ Log.w(TAG, "Ignoring a settings changed event that did not have the new settings.");
+ }
} else if (EVENT_BOOTSTRAP_STATE_CHANGED.equals(event)) {
String state = message.getString("state");
for (BootstrapStateChangeListener listener: mBootstrapStateListeners) {
=====================================
toolkit/modules/TorAndroidIntegration.sys.mjs
=====================================
@@ -124,6 +124,15 @@ class TorAndroidIntegrationImpl {
settings: lazy.TorSettings.getSettings(),
});
break;
+ case lazy.TorSettingsTopics.SettingsChanged:
+ // For Android we push also the settings object to avoid a round trip on
+ // the event dispatcher.
+ lazy.EventDispatcher.instance.sendRequest({
+ type: EmittedEvents.settingsChanged,
+ changes: subj.wrappedJSObject.changes ?? [],
+ settings: lazy.TorSettings.getSettings(),
+ });
+ break;
}
}
=====================================
toolkit/modules/TorConnect.sys.mjs
=====================================
@@ -878,10 +878,11 @@ export const TorConnect = (() => {
console.log(`TorConnect: Observing topic '${addTopic}'`);
};
+ TorSettings.initializedPromise.then(() => this._settingsInitialized());
+
// register the Tor topics we always care about
observeTopic(TorTopics.ProcessExited);
observeTopic(TorTopics.LogHasWarnOrErr);
- observeTopic(TorSettingsTopics.Ready);
}
},
@@ -889,29 +890,6 @@ export const TorConnect = (() => {
console.log(`TorConnect: Observed ${topic}`);
switch (topic) {
- /* We need to wait until TorSettings have been loaded and applied before we can Quickstart */
- case TorSettingsTopics.Ready: {
- // tor-browser#41907: This is only a workaround to avoid users being
- // bounced back to the initial panel without any explanation.
- // Longer term we should disable the clickable elements, or find a UX
- // to prevent this from happening (e.g., allow buttons to be clicked,
- // but show an intermediate starting state, or a message that tor is
- // starting while the butons are disabled, etc...).
- if (this.state !== TorConnectState.Initial) {
- console.warn(
- "TorConnect: Seen the torsettings:ready after the state has already changed, ignoring the notification."
- );
- break;
- }
- if (this.shouldQuickStart) {
- // Quickstart
- this._changeState(TorConnectState.Bootstrapping);
- } else {
- // Configuring
- this._changeState(TorConnectState.Configuring);
- }
- break;
- }
case TorTopics.LogHasWarnOrErr: {
this._logHasWarningOrError = true;
break;
@@ -941,6 +919,28 @@ export const TorConnect = (() => {
}
},
+ _settingsInitialized() {
+ // tor-browser#41907: This is only a workaround to avoid users being
+ // bounced back to the initial panel without any explanation.
+ // Longer term we should disable the clickable elements, or find a UX
+ // to prevent this from happening (e.g., allow buttons to be clicked,
+ // but show an intermediate starting state, or a message that tor is
+ // starting while the butons are disabled, etc...).
+ if (this.state !== TorConnectState.Initial) {
+ console.warn(
+ "TorConnect: Seen the torsettings:ready after the state has already changed, ignoring the notification."
+ );
+ return;
+ }
+ if (this.shouldQuickStart) {
+ // Quickstart
+ this._changeState(TorConnectState.Bootstrapping);
+ } else {
+ // Configuring
+ this._changeState(TorConnectState.Configuring);
+ }
+ },
+
/*
Various getters
*/
=====================================
toolkit/modules/TorSettings.sys.mjs
=====================================
@@ -992,6 +992,10 @@ class TorSettingsImpl {
// Hold off on lots of notifications until all settings are changed.
this.freezeNotifications();
try {
+ if ("quickstart" in settings) {
+ this.quickstart.enabled = !!settings.quickstart.enabled;
+ }
+
if ("bridges" in settings) {
this.bridges.enabled = !!settings.bridges.enabled;
// Currently, disabling bridges in the UI does not remove the lines,
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/db59cb…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/db59cb…
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) 26 Jan '24
by Dan Ballard (@dan) 26 Jan '24
26 Jan '24
Dan Ballard pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android
Commits:
6d0a6453 by Dan Ballard at 2024-01-25T16:15:45-08:00
fixup! Add Tor integration and UI
Bug 42252: Make TorController and interface and add a Geckoview implementation
- - - - -
4 changed files:
- fenix/app/src/main/java/org/mozilla/fenix/components/Components.kt
- fenix/app/src/main/java/org/mozilla/fenix/tor/TorController.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerGV.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerTAS.kt
Changes:
=====================================
fenix/app/src/main/java/org/mozilla/fenix/components/Components.kt
=====================================
@@ -43,7 +43,8 @@ import org.mozilla.fenix.perf.StartupActivityLog
import org.mozilla.fenix.perf.StartupStateProvider
import org.mozilla.fenix.perf.StrictModeManager
import org.mozilla.fenix.perf.lazyMonitored
-import org.mozilla.fenix.tor.TorController
+import org.mozilla.fenix.tor.TorControllerGV
+import org.mozilla.fenix.tor.TorControllerTAS
import org.mozilla.fenix.utils.ClipboardHandler
import org.mozilla.fenix.utils.Settings
import org.mozilla.fenix.wifi.WifiConnectionMonitor
@@ -201,7 +202,7 @@ class Components(private val context: Context) {
),
)
}
- val torController by lazyMonitored { TorController(context) }
+ val torController by lazyMonitored { if (settings.useNewBootstrap) TorControllerGV(context) else TorControllerTAS(context) }
}
/**
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorController.kt
=====================================
@@ -4,22 +4,7 @@
package org.mozilla.fenix.tor
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
import androidx.lifecycle.LifecycleCoroutineScope
-import androidx.localbroadcastmanager.content.LocalBroadcastManager
-
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withTimeoutOrNull
-
-import org.mozilla.fenix.BuildConfig
-
-import org.torproject.android.service.TorService
-import org.torproject.android.service.TorServiceConstants
-import org.torproject.android.service.util.Prefs
interface TorEvents {
fun onTorConnecting()
@@ -28,347 +13,59 @@ interface TorEvents {
fun onTorStopped()
}
-private enum class TorStatus {
- OFF,
- STARTING,
- ON,
- STOPPING,
- UNKNOWN;
+internal enum class TorStatus(val status: String) {
+ OFF("OFF"),
+ STARTING("STARTING"),
+ ON("ON"),
+ STOPPING("STOPPING"),
+ UNKNOWN("UNKNOWN");
- fun getStateFromString(status: String): TorStatus {
- return when (status) {
- TorServiceConstants.STATUS_ON -> ON
- TorServiceConstants.STATUS_STARTING -> STARTING
- TorServiceConstants.STATUS_STOPPING -> STOPPING
- TorServiceConstants.STATUS_OFF -> OFF
- else -> UNKNOWN
+ companion object {
+ fun fromString(status: String): TorStatus {
+ return when (status) {
+ "ON" -> ON
+ "STARTING" -> STARTING
+ "STOPPING" -> STOPPING
+ "OFF" -> OFF
+ else -> UNKNOWN
+ }
}
}
fun isOff() = this == OFF
fun isOn() = this == ON
fun isStarting() = this == STARTING
- fun isStarted() = ((this == TorStatus.STARTING) || (this == TorStatus.ON))
+ fun isStarted() = ((this == STARTING) || (this == ON))
fun isStopping() = this == STOPPING
fun isUnknown() = this == UNKNOWN
}
-@SuppressWarnings("TooManyFunctions")
-class TorController(
- private val context: Context
-) : TorEvents {
-
- private val lbm: LocalBroadcastManager = LocalBroadcastManager.getInstance(context)
- private val entries = mutableListOf<Pair<String?, String?>>()
- val logEntries get() = entries
-
- private var torListeners = mutableListOf<TorEvents>()
-
- private var pendingRegisterChangeList = mutableListOf<Pair<TorEvents, Boolean>>()
- private var lockTorListenersMutation = false
-
- private var lastKnownStatus = TorStatus.OFF
- private var wasTorBootstrapped = false
- private var isTorRestarting = false
-
- // This may be a lie
- private var isTorBootstrapped = false
- get() = ((lastKnownStatus == TorStatus.ON) && wasTorBootstrapped)
-
- val isDebugLoggingEnabled get() =
- context
- .getSharedPreferences("org.torproject.android_preferences", Context.MODE_PRIVATE)
- .getBoolean("pref_enable_logging", false)
-
- val isStarting get() = lastKnownStatus.isStarting()
- val isRestarting get() = isTorRestarting
- val isBootstrapped get() = isTorBootstrapped
- val isConnected get() = (lastKnownStatus.isStarted() && !isTorRestarting)
-
+interface TorController: TorEvents {
+ val logEntries: MutableList<Pair<String?, String?>>
+ val isStarting: Boolean
+ val isRestarting: Boolean
+ val isBootstrapped: Boolean
+ val isConnected: Boolean
var bridgesEnabled: Boolean
- get() = Prefs.bridgesEnabled()
- set(value) { Prefs.putBridgesEnabled(value) }
-
var bridgeTransport: TorBridgeTransportConfig
- get() {
- return TorBridgeTransportConfigUtil.getStringToBridgeTransport(
- Prefs.getBridgesList()
- )
- }
- set(value) {
- if (value == TorBridgeTransportConfig.USER_PROVIDED) {
- // Don't set the pref when the value is USER_PROVIDED because
- // "user_provided" is not a valid bridge or transport type.
- // This call should be followed by setting userProvidedBridges.
- return
- }
- Prefs.setBridgesList(value.transportName)
- }
-
var userProvidedBridges: String?
- get() {
- val bridges = Prefs.getBridgesList()
- val bridgeType =
- TorBridgeTransportConfigUtil.getStringToBridgeTransport(bridges)
- return when (bridgeType) {
- TorBridgeTransportConfig.USER_PROVIDED -> bridges
- else -> null
- }
- }
- set(value) {
- Prefs.setBridgesList(value)
- }
-
- fun start() {
- // Register receiver
- lbm.registerReceiver(
- persistentBroadcastReceiver,
- IntentFilter(TorServiceConstants.ACTION_STATUS)
- )
- lbm.registerReceiver(
- persistentBroadcastReceiver,
- IntentFilter(TorServiceConstants.LOCAL_ACTION_LOG)
- )
- }
- fun stop() {
- lbm.unregisterReceiver(persistentBroadcastReceiver)
- }
+ fun start()
+ fun stop()
- private val persistentBroadcastReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- if (intent.action == null ||
- (intent.action != TorServiceConstants.ACTION_STATUS &&
- intent.action != TorServiceConstants.LOCAL_ACTION_LOG)
- ) {
- return
- }
- val action = intent.action
+ override fun onTorConnecting()
+ override fun onTorConnected()
+ override fun onTorStatusUpdate(entry: String?, status: String?)
+ override fun onTorStopped()
- val logentry: String?
- val status: String?
- if (action == TorServiceConstants.LOCAL_ACTION_LOG) {
- logentry = intent.getExtras()
- ?.getCharSequence(TorServiceConstants.LOCAL_EXTRA_LOG) as? String?
- } else {
- logentry = null
- }
-
- status = intent.getExtras()
- ?.getCharSequence(TorServiceConstants.EXTRA_STATUS) as? String?
-
- if (logentry == null && status == null) {
- return
- }
-
- onTorStatusUpdate(logentry, status)
-
- if (status == null) {
- return
- }
-
- val newStatus = lastKnownStatus.getStateFromString(status)
-
- if (newStatus.isUnknown() && wasTorBootstrapped) {
- stopTor()
- }
-
- entries.add(Pair(logentry, status))
-
- if (logentry != null && logentry.contains(TorServiceConstants.TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)) {
- wasTorBootstrapped = true
- onTorConnected()
- }
-
- if (lastKnownStatus.isStopping() && newStatus.isOff()) {
- if (isTorRestarting) {
- initiateTorBootstrap()
- } else {
- onTorStopped()
- }
- }
-
- if (lastKnownStatus.isOff() && newStatus.isStarting()) {
- isTorRestarting = false
- }
-
- lastKnownStatus = newStatus
- }
- }
-
- override fun onTorConnecting() {
- lockTorListenersMutation = true
- torListeners.forEach { it.onTorConnecting() }
- lockTorListenersMutation = false
-
- handlePendingRegistrationChanges()
- }
-
- override fun onTorConnected() {
- lockTorListenersMutation = true
- torListeners.forEach { it.onTorConnected() }
- lockTorListenersMutation = false
-
- handlePendingRegistrationChanges()
- }
+ fun registerTorListener(l: TorEvents)
+ fun unregisterTorListener(l: TorEvents)
- override fun onTorStatusUpdate(entry: String?, status: String?) {
- lockTorListenersMutation = true
- torListeners.forEach { it.onTorStatusUpdate(entry, status) }
- lockTorListenersMutation = false
-
- handlePendingRegistrationChanges()
- }
-
- override fun onTorStopped() {
- lockTorListenersMutation = true
- torListeners.forEach { it.onTorStopped() }
- lockTorListenersMutation = false
-
- handlePendingRegistrationChanges()
- }
-
- fun registerTorListener(l: TorEvents) {
- if (torListeners.contains(l)) {
- return
- }
-
- if (lockTorListenersMutation) {
- pendingRegisterChangeList.add(Pair(l, true))
- } else {
- torListeners.add(l)
- }
- }
-
- fun unregisterTorListener(l: TorEvents) {
- if (!torListeners.contains(l)) {
- return
- }
-
- if (lockTorListenersMutation) {
- pendingRegisterChangeList.add(Pair(l, false))
- } else {
- torListeners.remove(l)
- }
- }
-
- private fun handlePendingRegistrationChanges() {
- pendingRegisterChangeList.forEach {
- if (it.second) {
- registerTorListener(it.first)
- } else {
- unregisterTorListener(it.first)
- }
- }
-
- pendingRegisterChangeList.clear()
- }
-
- /**
- * Receive the current Tor status.
- *
- * Send a request for the current status and receive the response.
- * Returns true if Tor is running, false otherwise.
- *
- */
- private suspend fun checkTorIsStarted(): Boolean {
- val channel = Channel<Boolean>()
-
- // Register receiver
- val lbm: LocalBroadcastManager = LocalBroadcastManager.getInstance(context)
- val localBroadcastReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- val action = intent.action ?: return
- // We only want ACTION_STATUS messages
- if (action != TorServiceConstants.ACTION_STATUS) {
- return
- }
- // The current status has the EXTRA_STATUS key
- val currentStatus =
- intent.getStringExtra(TorServiceConstants.EXTRA_STATUS)
- channel.trySend(currentStatus === TorServiceConstants.STATUS_ON)
- }
- }
- lbm.registerReceiver(
- localBroadcastReceiver,
- IntentFilter(TorServiceConstants.ACTION_STATUS)
- )
-
- // Request service status
- sendServiceAction(TorServiceConstants.ACTION_STATUS)
-
- // Wait for response and unregister receiver
- var torIsStarted = false
- withTimeoutOrNull(torServiceResponseTimeout) {
- torIsStarted = channel.receive()
- }
- lbm.unregisterReceiver(localBroadcastReceiver)
- return torIsStarted
- }
-
- fun initiateTorBootstrap(lifecycleScope: LifecycleCoroutineScope? = null, withDebugLogging: Boolean = false) {
- if (BuildConfig.DISABLE_TOR) {
- return
- }
-
- context.getSharedPreferences("org.torproject.android_preferences", Context.MODE_PRIVATE)
- .edit().putBoolean("pref_enable_logging", withDebugLogging).apply()
-
- if (lifecycleScope == null) {
- sendServiceAction(TorServiceConstants.ACTION_START)
- } else {
- lifecycleScope.launch {
- val torNeedsStart = !checkTorIsStarted()
- if (torNeedsStart) {
- sendServiceAction(TorServiceConstants.ACTION_START)
- }
- }
- }
- }
-
- fun stopTor() {
- if (BuildConfig.DISABLE_TOR) {
- return
- }
-
- val torService = Intent(context, TorService::class.java)
- context.stopService(torService)
- }
-
- fun setTorStopped() {
- lastKnownStatus = TorStatus.OFF
- onTorStopped()
- }
-
- fun restartTor() {
- // tor-android-service doesn't dynamically update the torrc file,
- // and it doesn't use SETCONF, so we completely restart the service.
- // However, don't restart if we aren't started and we weren't
- // previously started.
- if (!lastKnownStatus.isStarted() && !wasTorBootstrapped) {
- return
- }
+ fun initiateTorBootstrap(lifecycleScope: LifecycleCoroutineScope? = null, withDebugLogging: Boolean = false)
+ fun stopTor()
+ fun setTorStopped()
+ fun restartTor()
+}
- if (!lastKnownStatus.isStarted() && wasTorBootstrapped) {
- // If we aren't started, but we were previously bootstrapped,
- // then we handle a "restart" request as a "start" restart
- initiateTorBootstrap()
- } else {
- // |isTorRestarting| tracks the state of restart. When we receive an |OFF| state
- // from TorService in persistentBroadcastReceiver::onReceive we restart the Tor
- // service.
- isTorRestarting = true
- stopTor()
- }
- }
- private fun sendServiceAction(action: String) {
- val torServiceStatus = Intent(context, TorService::class.java)
- torServiceStatus.action = action
- context.startService(torServiceStatus)
- }
- companion object {
- const val torServiceResponseTimeout = 5000L
- }
-}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerGV.kt
=====================================
@@ -0,0 +1,289 @@
+package org.mozilla.fenix.tor
+
+
+import android.content.Context
+import android.util.Log
+import androidx.lifecycle.LifecycleCoroutineScope
+import mozilla.components.browser.engine.gecko.GeckoEngine
+import org.mozilla.fenix.ext.components
+import org.mozilla.geckoview.TorIntegrationAndroid
+import org.mozilla.geckoview.TorIntegrationAndroid.BootstrapStateChangeListener
+import org.mozilla.geckoview.TorSettings
+import org.mozilla.geckoview.TorSettings.BridgeBuiltinType
+import org.mozilla.geckoview.TorSettings.BridgeSource
+
+// Enum matching TorConnectState from TorConnect.sys.mjs that we get from onBootstrapStateChange
+internal enum class TorConnectState(val state: String) {
+ Initial("Initial"),
+ Configuring("Configuring"),
+ AutoBootstrapping("AutoBootstrapping"),
+ Bootstrapping("Bootstrapping"),
+ Error("Error"),
+ Bootstrapped("Bootstrapped"),
+ Disabled("Disabled");
+
+ fun isStarting() = this == Bootstrapping || this == AutoBootstrapping
+ fun isError() = this == Error
+
+ fun isStarted() = this == Bootstrapped
+
+ fun isOff() = this == Initial || this == Configuring || this == Disabled || this == Error
+
+
+ // Convert to TorStatus that firefox-android uses based on tor-android-service
+ fun toTorStatus(): TorStatus {
+ return when (this) {
+ Initial -> TorStatus.OFF
+ Configuring -> TorStatus.OFF
+ AutoBootstrapping -> TorStatus.STARTING
+ Bootstrapping -> TorStatus.STARTING
+ Error -> TorStatus.UNKNOWN
+ Bootstrapped -> TorStatus.ON
+ Disabled -> TorStatus.OFF
+ }
+ }
+}
+
+class TorControllerGV(
+ private val context: Context,
+) : TorController, TorEvents, BootstrapStateChangeListener {
+
+ private val TAG = "TorControllerGV"
+
+ private var torListeners = mutableListOf<TorEvents>()
+
+ private var lastKnownStatus = TorConnectState.Initial
+ private var wasTorBootstrapped = false
+ private var isTorRestarting = false
+
+ private var isTorBootstrapped = false
+ get() = ((lastKnownStatus.isStarted()) && wasTorBootstrapped)
+
+ private val entries = mutableListOf<Pair<String?, String?>>()
+ override val logEntries get() = entries
+ override val isStarting get() = lastKnownStatus.isStarting()
+ override val isRestarting get() = isTorRestarting
+ override val isBootstrapped get() = isTorBootstrapped
+ override val isConnected get() = (lastKnownStatus.isStarted() && !isTorRestarting)
+
+ private fun getTorIntegration(): TorIntegrationAndroid {
+ return (context.components.core.engine as GeckoEngine).getTorIntegrationController()
+ }
+
+ private fun getTorSettings(): TorSettings? {
+ return getTorIntegration().getSettings()
+ }
+
+ override var bridgesEnabled: Boolean
+ get() {
+ return getTorSettings()?.bridgesEnabled ?: false
+ }
+ set(value) {
+ getTorSettings()?.let {
+ it.bridgesEnabled = value
+ getTorIntegration().setSettings(it, true, true)
+ }
+ }
+
+
+ override var bridgeTransport: TorBridgeTransportConfig
+ get() {
+ return when (getTorSettings()?.bridgesSource) {
+ BridgeSource.BuiltIn -> {
+ when (getTorSettings()?.bridgesBuiltinType) {
+ BridgeBuiltinType.Obfs4 -> TorBridgeTransportConfig.BUILTIN_OBFS4
+ BridgeBuiltinType.MeekAzure -> TorBridgeTransportConfig.BUILTIN_MEEK_AZURE
+ BridgeBuiltinType.Snowflake -> TorBridgeTransportConfig.BUILTIN_SNOWFLAKE
+ else -> TorBridgeTransportConfig.USER_PROVIDED
+ }
+
+ }
+
+ BridgeSource.UserProvided -> TorBridgeTransportConfig.USER_PROVIDED
+ else -> TorBridgeTransportConfig.USER_PROVIDED
+ }
+ }
+ set(value) {
+ getTorSettings()?.let {
+ if (value == TorBridgeTransportConfig.USER_PROVIDED) {
+ it.bridgesSource = BridgeSource.BuiltIn
+ } else {
+ val bbt: BridgeBuiltinType = when (value) {
+ TorBridgeTransportConfig.BUILTIN_OBFS4 -> BridgeBuiltinType.Obfs4
+ TorBridgeTransportConfig.BUILTIN_MEEK_AZURE -> BridgeBuiltinType.MeekAzure
+ TorBridgeTransportConfig.BUILTIN_SNOWFLAKE -> BridgeBuiltinType.Snowflake
+ else -> BridgeBuiltinType.Invalid
+ }
+ it.bridgesBuiltinType = bbt
+ }
+ getTorIntegration().setSettings(it, true, true)
+ }
+ }
+
+
+ override var userProvidedBridges: String?
+ get() {
+ return getTorSettings()?.bridgeBridgeStrings?.joinToString("\r\n")
+ }
+ set(value) {
+ getTorSettings()?.let {
+ it.bridgeBridgeStrings = value?.split("\r\n")?.toTypedArray() ?: arrayOf<String>()
+ getTorIntegration().setSettings(it, true, true)
+ }
+ }
+
+ override fun start() {
+ getTorIntegration().registerBootstrapStateChangeListener(this)
+ }
+
+ override fun stop() {
+ getTorIntegration().unregisterBootstrapStateChangeListener(this)
+ }
+
+ // TorEvents
+ override fun onTorConnecting() {
+ synchronized(torListeners) {
+ torListeners.forEach { it.onTorConnecting() }
+ }
+ }
+
+ // TorEvents
+ override fun onTorConnected() {
+ synchronized(torListeners) {
+ torListeners.forEach { it.onTorConnected() }
+ }
+ }
+
+ // TorEvents
+ override fun onTorStatusUpdate(entry: String?, status: String?) {
+ synchronized(torListeners) {
+ torListeners.forEach { it.onTorStatusUpdate(entry, status) }
+ }
+ }
+
+ // TorEvents
+ override fun onTorStopped() {
+ synchronized(torListeners) {
+ torListeners.forEach { it.onTorStopped() }
+ }
+ }
+
+ override fun registerTorListener(l: TorEvents) {
+ synchronized(torListeners) {
+ if (torListeners.contains(l)) {
+ return
+ }
+ torListeners.add(l)
+ }
+ }
+
+ override fun unregisterTorListener(l: TorEvents) {
+ synchronized(torListeners) {
+ if (!torListeners.contains(l)) {
+ return
+ }
+ torListeners.remove(l)
+ }
+ }
+
+ override fun initiateTorBootstrap(
+ lifecycleScope: LifecycleCoroutineScope?,
+ withDebugLogging: Boolean,
+ ) {
+ getTorIntegration().beginBootstrap()
+ }
+
+ override fun stopTor() {
+ getTorIntegration().cancelBootstrap()
+ }
+
+ override fun setTorStopped() {
+ lastKnownStatus = TorConnectState.Disabled
+ onTorStopped()
+ }
+
+ override fun restartTor() {
+ if (!lastKnownStatus.isStarted() && wasTorBootstrapped) {
+ // If we aren't started, but we were previously bootstrapped,
+ // then we handle a "restart" request as a "start" restart
+ initiateTorBootstrap()
+ } else {
+ // |isTorRestarting| tracks the state of restart. When we receive an |OFF| state
+ // from TorService in persistentBroadcastReceiver::onReceive we restart the Tor
+ // service.
+ isTorRestarting = true
+ stopTor()
+ }
+ }
+
+ // TorEventsBootstrapStateChangeListener -> (lastKnowStatus, TorEvents)
+ // Handle events from GeckoView TorAndroidIntegration and map to TorEvents based events
+ // and state for firefox-android (designed for tor-android-service)
+ // fun onTorConnecting()
+ // fun onTorConnected()
+ // fun onTorStatusUpdate(entry: String?, status: String?)
+ // fun onTorStopped()
+
+ // TorEventsBootstrapStateChangeListener
+ override fun onBootstrapStateChange(newStateVal: String?) {
+ Log.d(TAG, "onBootstrapStateChange($newStateVal)")
+ val newState: TorConnectState = TorConnectState.valueOf(newStateVal ?: "Error")
+
+ if (newState.isError() && wasTorBootstrapped) {
+ stopTor()
+ }
+
+ if (newState.isStarted()) {
+ wasTorBootstrapped = true
+ onTorConnected()
+ }
+
+ if (wasTorBootstrapped && newState == TorConnectState.Configuring) {
+ wasTorBootstrapped = false
+ if (isTorRestarting) {
+ initiateTorBootstrap()
+ } else {
+ onTorStopped()
+ }
+ }
+
+ if (lastKnownStatus.isOff() && newState.isStarting()) {
+ isTorRestarting = false
+ }
+
+ lastKnownStatus = newState
+
+ }
+
+ // TorEventsBootstrapStateChangeListener
+ override fun onBootstrapProgress(progress: Double, status: String?, hasWarnings: Boolean) {
+ Log.d(TAG, "onBootstrapProgress($progress, $status, $hasWarnings)")
+ if (progress == 100.0) {
+ lastKnownStatus = TorConnectState.Bootstrapped
+ wasTorBootstrapped = true
+ onTorConnected()
+ } else {
+ lastKnownStatus = TorConnectState.Bootstrapping
+ onTorConnecting()
+
+ }
+ entries.add(Pair(status, lastKnownStatus.toTorStatus().status))
+ onTorStatusUpdate(status, lastKnownStatus.toTorStatus().status)
+ }
+
+ // TorEventsBootstrapStateChangeListener
+ override fun onBootstrapComplete() {
+ lastKnownStatus = TorConnectState.Bootstrapped
+ this.onTorConnected()
+ }
+
+ // TorEventsBootstrapStateChangeListener
+ override fun onBootstrapError(message: String?, details: String?) {
+ lastKnownStatus = TorConnectState.Error
+ }
+
+ // TorEventsBootstrapStateChangeListener
+ override fun onSettingsRequested() {
+ // noop
+ }
+}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerTAS.kt
=====================================
@@ -0,0 +1,332 @@
+package org.mozilla.fenix.tor
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import androidx.lifecycle.LifecycleCoroutineScope
+import androidx.localbroadcastmanager.content.LocalBroadcastManager
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withTimeoutOrNull
+import org.mozilla.fenix.BuildConfig
+import org.torproject.android.service.TorService
+import org.torproject.android.service.TorServiceConstants
+import org.torproject.android.service.util.Prefs
+
+@SuppressWarnings("TooManyFunctions")
+class TorControllerTAS (private val context: Context): TorController {
+ private val lbm: LocalBroadcastManager = LocalBroadcastManager.getInstance(context)
+ private val entries = mutableListOf<Pair<String?, String?>>()
+ override val logEntries get() = entries
+
+ private var torListeners = mutableListOf<TorEvents>()
+
+ private var pendingRegisterChangeList = mutableListOf<Pair<TorEvents, Boolean>>()
+ private var lockTorListenersMutation = false
+
+ private var lastKnownStatus = TorStatus.OFF
+ private var wasTorBootstrapped = false
+ private var isTorRestarting = false
+
+ // This may be a lie
+ private var isTorBootstrapped = false
+ get() = ((lastKnownStatus == TorStatus.ON) && wasTorBootstrapped)
+
+ val isDebugLoggingEnabled get() =
+ context
+ .getSharedPreferences("org.torproject.android_preferences", Context.MODE_PRIVATE)
+ .getBoolean("pref_enable_logging", false)
+
+ override val isStarting get() = lastKnownStatus.isStarting()
+ override val isRestarting get() = isTorRestarting
+ override val isBootstrapped get() = isTorBootstrapped
+ override val isConnected get() = (lastKnownStatus.isStarted() && !isTorRestarting)
+
+ override var bridgesEnabled: Boolean
+ get() = Prefs.bridgesEnabled()
+ set(value) { Prefs.putBridgesEnabled(value) }
+
+ override var bridgeTransport: TorBridgeTransportConfig
+ get() {
+ return TorBridgeTransportConfigUtil.getStringToBridgeTransport(
+ Prefs.getBridgesList()
+ )
+ }
+ set(value) {
+ if (value == TorBridgeTransportConfig.USER_PROVIDED) {
+ // Don't set the pref when the value is USER_PROVIDED because
+ // "user_provided" is not a valid bridge or transport type.
+ // This call should be followed by setting userProvidedBridges.
+ return
+ }
+ Prefs.setBridgesList(value.transportName)
+ }
+
+ override var userProvidedBridges: String?
+ get() {
+ val bridges = Prefs.getBridgesList()
+ val bridgeType =
+ TorBridgeTransportConfigUtil.getStringToBridgeTransport(bridges)
+ return when (bridgeType) {
+ TorBridgeTransportConfig.USER_PROVIDED -> bridges
+ else -> null
+ }
+ }
+ set(value) {
+ Prefs.setBridgesList(value)
+ }
+
+ override fun start() {
+ // Register receiver
+ lbm.registerReceiver(
+ persistentBroadcastReceiver,
+ IntentFilter(TorServiceConstants.ACTION_STATUS)
+ )
+ lbm.registerReceiver(
+ persistentBroadcastReceiver,
+ IntentFilter(TorServiceConstants.LOCAL_ACTION_LOG)
+ )
+ }
+
+ override fun stop() {
+ lbm.unregisterReceiver(persistentBroadcastReceiver)
+ }
+
+ private val persistentBroadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action == null ||
+ (intent.action != TorServiceConstants.ACTION_STATUS &&
+ intent.action != TorServiceConstants.LOCAL_ACTION_LOG)
+ ) {
+ return
+ }
+ val action = intent.action
+
+ val logentry: String?
+ val status: String?
+ if (action == TorServiceConstants.LOCAL_ACTION_LOG) {
+ logentry = intent.getExtras()
+ ?.getCharSequence(TorServiceConstants.LOCAL_EXTRA_LOG) as? String?
+ } else {
+ logentry = null
+ }
+
+ status = intent.getExtras()
+ ?.getCharSequence(TorServiceConstants.EXTRA_STATUS) as? String?
+
+ if (logentry == null && status == null) {
+ return
+ }
+
+ onTorStatusUpdate(logentry, status)
+
+ if (status == null) {
+ return
+ }
+
+ val newStatus = TorStatus.fromString(status)
+
+ if (newStatus.isUnknown() && wasTorBootstrapped) {
+ stopTor()
+ }
+
+ entries.add(Pair(logentry, status))
+
+ if (logentry != null && logentry.contains(TorServiceConstants.TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)) {
+ wasTorBootstrapped = true
+ onTorConnected()
+ }
+
+ if (lastKnownStatus.isStopping() && newStatus.isOff()) {
+ if (isTorRestarting) {
+ initiateTorBootstrap()
+ } else {
+ onTorStopped()
+ }
+ }
+
+ if (lastKnownStatus.isOff() && newStatus.isStarting()) {
+ isTorRestarting = false
+ }
+
+ lastKnownStatus = newStatus
+ }
+ }
+
+ override fun onTorConnecting() {
+ lockTorListenersMutation = true
+ torListeners.forEach { it.onTorConnecting() }
+ lockTorListenersMutation = false
+
+ handlePendingRegistrationChanges()
+ }
+
+ override fun onTorConnected() {
+ lockTorListenersMutation = true
+ torListeners.forEach { it.onTorConnected() }
+ lockTorListenersMutation = false
+
+ handlePendingRegistrationChanges()
+ }
+
+ override fun onTorStatusUpdate(entry: String?, status: String?) {
+ lockTorListenersMutation = true
+ torListeners.forEach { it.onTorStatusUpdate(entry, status) }
+ lockTorListenersMutation = false
+
+ handlePendingRegistrationChanges()
+ }
+
+ override fun onTorStopped() {
+ lockTorListenersMutation = true
+ torListeners.forEach { it.onTorStopped() }
+ lockTorListenersMutation = false
+
+ handlePendingRegistrationChanges()
+ }
+
+ override fun registerTorListener(l: TorEvents) {
+ if (torListeners.contains(l)) {
+ return
+ }
+
+ if (lockTorListenersMutation) {
+ pendingRegisterChangeList.add(Pair(l, true))
+ } else {
+ torListeners.add(l)
+ }
+ }
+
+ override fun unregisterTorListener(l: TorEvents) {
+ if (!torListeners.contains(l)) {
+ return
+ }
+
+ if (lockTorListenersMutation) {
+ pendingRegisterChangeList.add(Pair(l, false))
+ } else {
+ torListeners.remove(l)
+ }
+ }
+
+ private fun handlePendingRegistrationChanges() {
+ pendingRegisterChangeList.forEach {
+ if (it.second) {
+ registerTorListener(it.first)
+ } else {
+ unregisterTorListener(it.first)
+ }
+ }
+
+ pendingRegisterChangeList.clear()
+ }
+
+ /**
+ * Receive the current Tor status.
+ *
+ * Send a request for the current status and receive the response.
+ * Returns true if Tor is running, false otherwise.
+ *
+ */
+ private suspend fun checkTorIsStarted(): Boolean {
+ val channel = Channel<Boolean>()
+
+ // Register receiver
+ val lbm: LocalBroadcastManager = LocalBroadcastManager.getInstance(context)
+ val localBroadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val action = intent.action ?: return
+ // We only want ACTION_STATUS messages
+ if (action != TorServiceConstants.ACTION_STATUS) {
+ return
+ }
+ // The current status has the EXTRA_STATUS key
+ val currentStatus =
+ intent.getStringExtra(TorServiceConstants.EXTRA_STATUS)
+ channel.trySend(currentStatus === TorServiceConstants.STATUS_ON)
+ }
+ }
+ lbm.registerReceiver(
+ localBroadcastReceiver,
+ IntentFilter(TorServiceConstants.ACTION_STATUS)
+ )
+
+ // Request service status
+ sendServiceAction(TorServiceConstants.ACTION_STATUS)
+
+ // Wait for response and unregister receiver
+ var torIsStarted = false
+ withTimeoutOrNull(torServiceResponseTimeout) {
+ torIsStarted = channel.receive()
+ }
+ lbm.unregisterReceiver(localBroadcastReceiver)
+ return torIsStarted
+ }
+
+ override fun initiateTorBootstrap(lifecycleScope: LifecycleCoroutineScope?, withDebugLogging: Boolean) {
+ if (BuildConfig.DISABLE_TOR) {
+ return
+ }
+
+ context.getSharedPreferences("org.torproject.android_preferences", Context.MODE_PRIVATE)
+ .edit().putBoolean("pref_enable_logging", withDebugLogging).apply()
+
+ if (lifecycleScope == null) {
+ sendServiceAction(TorServiceConstants.ACTION_START)
+ } else {
+ lifecycleScope.launch {
+ val torNeedsStart = !checkTorIsStarted()
+ if (torNeedsStart) {
+ sendServiceAction(TorServiceConstants.ACTION_START)
+ }
+ }
+ }
+ }
+
+ override fun stopTor() {
+ if (BuildConfig.DISABLE_TOR) {
+ return
+ }
+
+ val torService = Intent(context, TorService::class.java)
+ context.stopService(torService)
+ }
+
+ override fun setTorStopped() {
+ lastKnownStatus = TorStatus.OFF
+ onTorStopped()
+ }
+
+ override fun restartTor() {
+ // tor-android-service doesn't dynamically update the torrc file,
+ // and it doesn't use SETCONF, so we completely restart the service.
+ // However, don't restart if we aren't started and we weren't
+ // previously started.
+ if (!lastKnownStatus.isStarted() && !wasTorBootstrapped) {
+ return
+ }
+
+ if (!lastKnownStatus.isStarted() && wasTorBootstrapped) {
+ // If we aren't started, but we were previously bootstrapped,
+ // then we handle a "restart" request as a "start" restart
+ initiateTorBootstrap()
+ } else {
+ // |isTorRestarting| tracks the state of restart. When we receive an |OFF| state
+ // from TorService in persistentBroadcastReceiver::onReceive we restart the Tor
+ // service.
+ isTorRestarting = true
+ stopTor()
+ }
+ }
+
+ private fun sendServiceAction(action: String) {
+ val torServiceStatus = Intent(context, TorService::class.java)
+ torServiceStatus.action = action
+ context.startService(torServiceStatus)
+ }
+
+ companion object {
+ const val torServiceResponseTimeout = 5000L
+ }
+}
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/6d0…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/6d0…
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 40597: Implement TorSettings module
by Pier Angelo Vendrame (@pierov) 25 Jan '24
by Pier Angelo Vendrame (@pierov) 25 Jan '24
25 Jan '24
Pier Angelo Vendrame pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
f49834e2 by Dan Ballard at 2024-01-25T17:05:18+00:00
fixup! Bug 40597: Implement TorSettings module
Bug 42252: Fix typo in documents
- - - - -
db59cb25 by Dan Ballard at 2024-01-25T17:05:18+00:00
fixup! Bug 42247: Android helpers for the TorProvider
Bug 42252: Add support for TorController in firefox-android
- - - - -
4 changed files:
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorSettings.java
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/TorLegacyAndroidSettings.java
- toolkit/modules/TorSettings.sys.mjs
Changes:
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
=====================================
@@ -82,6 +82,10 @@ public class TorIntegrationAndroid implements BundleEventListener {
private final HashMap<Integer, MeekTransport> mMeeks = new HashMap<>();
private int mMeekCounter;
+ // mSettings is a java side copy of the authoritative settings in the JS code.
+ // it's useful to maintain as the ui may be fetching these options often and
+ // we don't watch each fetch to be a passthrough to JS with JSON serialization and
+ // deserialization each time
private TorSettings mSettings = null;
/* package */ TorIntegrationAndroid(Context context) {
@@ -557,11 +561,38 @@ public class TorIntegrationAndroid implements BundleEventListener {
void onSettingsRequested();
}
- public @NonNull GeckoResult<GeckoBundle> getSettings() {
- return EventDispatcher.getInstance().queryBundle(EVENT_SETTINGS_GET);
+ private @NonNull void reloadSettings() {
+ EventDispatcher.getInstance().queryBundle(EVENT_SETTINGS_GET).then( new GeckoResult.OnValueListener<GeckoBundle, Void>() {
+ public GeckoResult<Void> onValue(final GeckoBundle bundle) {
+ mSettings = new TorSettings(bundle);
+ return new GeckoResult<Void>();
+ }
+ });
+ }
+
+ public TorSettings getSettings() {
+ return mSettings;
+ }
+
+ public void setSettings(final TorSettings settings, boolean save, boolean apply) {
+ mSettings = settings;
+
+ emitSetSettings(settings, save, apply).then(
+ new GeckoResult.OnValueListener<Void, Void>() {
+ public GeckoResult<Void> onValue(Void v) {
+ return new GeckoResult<Void>();
+ }
+ },
+ new GeckoResult.OnExceptionListener<Void>() {
+ public GeckoResult<Void> onException(final Throwable e) {
+ Log.e(TAG, "Failed to set settings", e);
+ reloadSettings();
+ return new GeckoResult<Void>();
+ }
+ });
}
- public @NonNull GeckoResult<Void> setSettings(final TorSettings settings, boolean save, boolean apply) {
+ private @NonNull GeckoResult<Void> emitSetSettings(final TorSettings settings, boolean save, boolean apply) {
GeckoBundle bundle = new GeckoBundle(3);
bundle.putBoolean("save", save);
bundle.putBoolean("apply", apply);
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorSettings.java
=====================================
@@ -2,24 +2,8 @@ package org.mozilla.geckoview;
import android.util.Log;
-import org.json.JSONArray;
-import org.json.JSONObject;
import org.mozilla.gecko.util.GeckoBundle;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.io.SequenceInputStream;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-import java.util.stream.Collectors;
-
public class TorSettings {
public enum BridgeSource {
@@ -76,6 +60,35 @@ public class TorSettings {
}
}
+ public enum BridgeBuiltinType {
+ /* TorSettings.sys.mjs ~ln43: string: obfs4|meek-azure|snowflake|etc */
+ Invalid("invalid"),
+ Obfs4("obfs4"),
+ MeekAzure("meek-azure"),
+ Snowflake("snowflake");
+
+
+ private String type;
+
+ BridgeBuiltinType(String type) {
+ this.type = type;
+ }
+
+ public String toString() {
+ return type;
+ }
+
+ public static BridgeBuiltinType fromString(String s) {
+ switch (s) {
+ case "obfs4": return Obfs4;
+ case "meek-azure": return MeekAzure;
+ case "snowflake": return Snowflake;
+ }
+ return Invalid;
+ }
+
+ }
+
private boolean loaded = false;
public boolean enabled = true;
@@ -85,7 +98,7 @@ public class TorSettings {
// bridges section
public boolean bridgesEnabled = false;
public BridgeSource bridgesSource = BridgeSource.Invalid;
- public String bridgesBuiltinType = "";
+ public BridgeBuiltinType bridgesBuiltinType = BridgeBuiltinType.Invalid;
public String[] bridgeBridgeStrings;
// proxy section
@@ -112,7 +125,7 @@ public class TorSettings {
bridgesEnabled = bridges.getBoolean("enabled");
bridgesSource = BridgeSource.fromInt(bridges.getInt("source"));
- bridgesBuiltinType = bridges.getString("builtin_type");
+ bridgesBuiltinType = BridgeBuiltinType.fromString(bridges.getString("builtin_type"));
bridgeBridgeStrings = bridges.getStringArray("bridge_strings");
quickstart = qs.getBoolean("enabled");
@@ -143,7 +156,7 @@ public class TorSettings {
bridges.putBoolean("enabled", bridgesEnabled);
bridges.putInt("source", bridgesSource.toInt());
- bridges.putString("builtin_type", bridgesBuiltinType);
+ bridges.putString("builtin_type", bridgesBuiltinType.toString());
bridges.putStringArray("bridge_strings", bridgeBridgeStrings);
qs.putBoolean("enabled", quickstart);
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/androidlegacysettings/TorLegacyAndroidSettings.java
=====================================
@@ -1,11 +1,5 @@
package org.mozilla.geckoview.androidlegacysettings;
-import java.io.IOException;
-
-import android.content.SharedPreferences;
-
-import org.mozilla.gecko.GeckoAppShell;
-
import org.mozilla.geckoview.TorSettings;
public class TorLegacyAndroidSettings {
@@ -54,10 +48,10 @@ public class TorLegacyAndroidSettings {
switch (userDefinedBridgeList) {
case "obfs4":
case "snowflake":
- settings.bridgesBuiltinType = userDefinedBridgeList;
+ settings.bridgesBuiltinType = TorSettings.BridgeBuiltinType.fromString(userDefinedBridgeList);
break;
case "meek":
- settings.bridgesBuiltinType = "meek-azure";
+ settings.bridgesBuiltinType = TorSettings.BridgeBuiltinType.MeekAzure;
break;
default:
settings.bridgesSource = TorSettings.BridgeSource.Invalid;
=====================================
toolkit/modules/TorSettings.sys.mjs
=====================================
@@ -40,7 +40,7 @@ const TorSettingsPrefs = Object.freeze({
enabled: "torbrowser.settings.bridges.enabled",
/* int: See TorBridgeSource */
source: "torbrowser.settings.bridges.source",
- /* string: obfs4|meek_azure|snowflake|etc */
+ /* string: obfs4|meek-azure|snowflake|etc */
builtin_type: "torbrowser.settings.bridges.builtin_type",
/* preference branch: each child branch should be a bridge string */
bridge_strings: "torbrowser.settings.bridges.bridge_strings",
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/308d6a…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/308d6a…
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 42247: Android helpers for the TorProvider
by Pier Angelo Vendrame (@pierov) 25 Jan '24
by Pier Angelo Vendrame (@pierov) 25 Jan '24
25 Jan '24
Pier Angelo Vendrame pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
308d6a64 by Pier Angelo Vendrame at 2024-01-25T17:44:22+01:00
fixup! Bug 42247: Android helpers for the TorProvider
Bug 42368: Do not use API26+ java.nio features
- - - - -
1 changed file:
- mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
Changes:
=====================================
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/TorIntegrationAndroid.java
=====================================
@@ -16,15 +16,10 @@ import androidx.annotation.Nullable;
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.attribute.PosixFilePermission;
-import java.nio.file.attribute.PosixFilePermissions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -69,9 +64,9 @@ public class TorIntegrationAndroid implements BundleEventListener {
private static final String COOKIE_AUTH_FILE = "/auth-file";
private final String mLibraryDir;
- private final Path mCacheDir;
+ private final String mCacheDir;
private final String mIpcDirectory;
- private final String mDataDir;
+ private final File mDataDir;
private TorProcess mTorProcess = null;
/**
@@ -91,9 +86,9 @@ public class TorIntegrationAndroid implements BundleEventListener {
/* package */ TorIntegrationAndroid(Context context) {
mLibraryDir = context.getApplicationInfo().nativeLibraryDir;
- mCacheDir = context.getCacheDir().toPath();
+ mCacheDir = context.getCacheDir().getAbsolutePath();
mIpcDirectory = mCacheDir + "/tor-private";
- mDataDir = context.getDataDir().getAbsolutePath() + "/tor";
+ mDataDir = new File(context.getFilesDir(), "tor");
registerListener();
}
@@ -260,7 +255,7 @@ public class TorIntegrationAndroid implements BundleEventListener {
args.add("CookieAuthFile");
args.add(ipcDir + COOKIE_AUTH_FILE);
args.add("DataDirectory");
- args.add(mDataDir);
+ args.add(mDataDir.getAbsolutePath());
boolean copied = true;
try {
copyAndUseConfigFile("--defaults-torrc", "torrc-defaults", args);
@@ -322,15 +317,19 @@ public class TorIntegrationAndroid implements BundleEventListener {
private void cleanIpcDirectory() {
File directory = new File(TorIntegrationAndroid.this.mIpcDirectory);
- if (!Files.isDirectory(directory.toPath())) {
+ if (!directory.isDirectory()) {
if (!directory.mkdirs()) {
Log.e(TAG, "Failed to create the IPC directory.");
return;
}
try {
- Set<PosixFilePermission> chmod = PosixFilePermissions.fromString("rwx------");
- Files.setPosixFilePermissions(directory.toPath(), chmod);
- } catch (IOException e) {
+ directory.setReadable(false, false);
+ directory.setReadable(true, true);
+ directory.setWritable(false, false);
+ directory.setWritable(true, true);
+ directory.setExecutable(false, false);
+ directory.setExecutable(true, true);
+ } catch (SecurityException e) {
Log.e(TAG, "Could not set the permissions to the IPC directory.", e);
}
return;
@@ -347,15 +346,46 @@ public class TorIntegrationAndroid implements BundleEventListener {
}
private void copyAndUseConfigFile(String option, String name, ArrayList<String> args) throws IOException {
- final Path path = Paths.get(mCacheDir.toFile().getAbsolutePath(), name);
- if (!mCopiedConfigFiles || !path.toFile().exists()) {
- final Context context = GeckoAppShell.getApplicationContext();
- final InputStream in = context.getAssets().open("common/" + name);
- Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING);
+ File file = copyConfigFile(name);
+ args.add(option);
+ args.add(file.getAbsolutePath());
+ }
+
+ private File copyConfigFile(String name) throws IOException {
+ final File file = new File(mCacheDir, name);
+ if (mCopiedConfigFiles && file.exists()) {
+ return file;
+ }
+
+ final Context context = GeckoAppShell.getApplicationContext();
+ final InputStream in = context.getAssets().open("common/" + name);
+ // Files.copy is API 26+, so use java.io and a loop for now.
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(file);
+ } catch (IOException e) {
in.close();
+ throw e;
}
- args.add(option);
- args.add(path.toString());
+ try {
+ byte buffer[] = new byte[4096];
+ int read;
+ while ((read = in.read(buffer)) >= 0) {
+ out.write(buffer, 0, read);
+ }
+ } finally {
+ try {
+ in.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Cannot close the input stream for " + name);
+ }
+ try {
+ out.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Cannot close the output stream for " + name);
+ }
+ }
+ return file;
}
public void shutdown() {
@@ -406,9 +436,10 @@ public class TorIntegrationAndroid implements BundleEventListener {
setName("meek-" + id);
final ProcessBuilder builder = new ProcessBuilder(mLibraryDir + "/libObfs4proxy.so");
{
+ File ptStateDir = new File(mDataDir, "pt_state");
final Map<String, String> env = builder.environment();
env.put("TOR_PT_MANAGED_TRANSPORT_VER", "1");
- env.put("TOR_PT_STATE_LOCATION", mDataDir + "/pt_state");
+ env.put("TOR_PT_STATE_LOCATION", ptStateDir.getAbsolutePath());
env.put("TOR_PT_EXIT_ON_STDIN_CLOSE", "1");
env.put("TOR_PT_CLIENT_TRANSPORTS", TRANSPORT);
}
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/308d6a6…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/308d6a6…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/rbm][main] Bug 40068: Use Capture::Tiny instead of IO::CaptureOutput
by richard (@richard) 25 Jan '24
by richard (@richard) 25 Jan '24
25 Jan '24
richard pushed to branch main at The Tor Project / Applications / RBM
Commits:
9336d42f by Nicolas Vigier at 2024-01-25T11:42:58+01:00
Bug 40068: Use Capture::Tiny instead of IO::CaptureOutput
The IO::CaptureOutput perl module is deprecated, so we switch to
Capture::Tiny.
The Capture::Tiny module does not provide a capture_exec function
similar to the one from IO::CaptureOutput, so we implement one using the
same name, which avoids changing all the places where we were using it.
- - - - -
2 changed files:
- lib/RBM.pm
- lib/RBM/DefaultConfig.pm
Changes:
=====================================
lib/RBM.pm
=====================================
@@ -10,7 +10,7 @@ use YAML::XS qw(LoadFile);
use Template;
use File::Basename;
use IO::Handle;
-use IO::CaptureOutput qw(capture_exec);
+use Capture::Tiny qw(capture);
use File::Temp;
use File::Copy;
use File::Copy::Recursive qw(fcopy);
@@ -29,7 +29,7 @@ use feature "state";
BEGIN {
require Exporter;
our @ISA = qw(Exporter);
- our @EXPORT = qw(exit_error);
+ our @EXPORT = qw(exit_error capture_exec);
}
our $config;
@@ -308,6 +308,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 set_git_gpg_wrapper {
my ($project) = @_;
my $w = project_config($project, 'gpg_wrapper');
=====================================
lib/RBM/DefaultConfig.pm
=====================================
@@ -10,9 +10,8 @@ BEGIN {
}
use File::Basename;
-use RBM;
+use RBM qw(capture_exec);
use Cwd qw(getcwd);
-use IO::CaptureOutput qw(capture_exec);
use File::Temp;
use File::Path qw(make_path);
View it on GitLab: https://gitlab.torproject.org/tpo/applications/rbm/-/commit/9336d42fdd669af…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/rbm/-/commit/9336d42fdd669af…
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#40067
by boklm (@boklm) 25 Jan '24
by boklm (@boklm) 25 Jan '24
25 Jan '24
boklm pushed to branch maint-13.0 at The Tor Project / Applications / tor-browser-build
Commits:
af1c78b5 by Nicolas Vigier at 2024-01-25T11:19:16+01:00
Update rbm for rbm#40067
- - - - -
1 changed file:
- rbm
Changes:
=====================================
rbm
=====================================
@@ -1 +1 @@
-Subproject commit 40acf540fe75055df2eb78454f070f57d0804729
+Subproject commit b5e5b04aaf677c4bacfb5ace45598313286bfdf6
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/a…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/a…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][main] Update rbm for rbm#40067
by boklm (@boklm) 25 Jan '24
by boklm (@boklm) 25 Jan '24
25 Jan '24
boklm pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
83a1a381 by Nicolas Vigier at 2024-01-25T11:17:52+01:00
Update rbm for rbm#40067
- - - - -
1 changed file:
- rbm
Changes:
=====================================
rbm
=====================================
@@ -1 +1 @@
-Subproject commit 40acf540fe75055df2eb78454f070f57d0804729
+Subproject commit b5e5b04aaf677c4bacfb5ace45598313286bfdf6
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/8…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/8…
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.0-1] fixup! Bug 41668: Tweaks to the Base Browser updater for Tor Browser
by boklm (@boklm) 25 Jan '24
by boklm (@boklm) 25 Jan '24
25 Jan '24
boklm pushed to branch tor-browser-115.7.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
6292bbc9 by Nicolas Vigier at 2024-01-25T10:26:11+01:00
fixup! Bug 41668: Tweaks to the Base Browser updater for Tor Browser
Bug 42293: Don't disable updater when run by torbrowser-launcher flatpak
When the TORBROWSER_LAUNCHER environment variable is set (which
is set by torbrowser-launcher since version 0.3.7) we assume that Tor
Browser is not installed by a Flatkpak. Although torbrowser-launcher
itself can be installed by a Flatpak, this should not prevent the
updater from working.
- - - - -
1 changed file:
- widget/gtk/WidgetUtilsGtk.cpp
Changes:
=====================================
widget/gtk/WidgetUtilsGtk.cpp
=====================================
@@ -138,6 +138,11 @@ void SetLastMousePressEvent(GdkEvent* aEvent) {
bool IsRunningUnderSnap() { return !!GetSnapInstanceName(); }
bool IsRunningUnderFlatpak() {
+ // tor-browser#42293: Don't disable updater when run by torbrowser-launcher flatpak
+ const char* torbrowserLauncher = g_getenv("TORBROWSER_LAUNCHER");
+ if (torbrowserLauncher) {
+ return false;
+ }
// https://gitlab.gnome.org/GNOME/gtk/-/blob/4300a5c609306ce77cbc8a3580c19201d…
static bool sRunning = [] {
return g_file_test("/.flatpak-info", G_FILE_TEST_EXISTS);
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/6292bbc…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/6292bbc…
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 41668: Tweaks to the Base Browser updater for Tor Browser
by boklm (@boklm) 25 Jan '24
by boklm (@boklm) 25 Jan '24
25 Jan '24
boklm pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
5898a9ab by Nicolas Vigier at 2024-01-25T10:21:48+01:00
fixup! Bug 41668: Tweaks to the Base Browser updater for Tor Browser
Bug 42293: Don't disable updater when run by torbrowser-launcher flatpak
When the TORBROWSER_LAUNCHER environment variable is set (which
is set by torbrowser-launcher since version 0.3.7) we assume that Tor
Browser is not installed by a Flatkpak. Although torbrowser-launcher
itself can be installed by a Flatpak, this should not prevent the
updater from working.
- - - - -
1 changed file:
- widget/gtk/WidgetUtilsGtk.cpp
Changes:
=====================================
widget/gtk/WidgetUtilsGtk.cpp
=====================================
@@ -138,6 +138,11 @@ void SetLastMousePressEvent(GdkEvent* aEvent) {
bool IsRunningUnderSnap() { return !!GetSnapInstanceName(); }
bool IsRunningUnderFlatpak() {
+ // tor-browser#42293: Don't disable updater when run by torbrowser-launcher flatpak
+ const char* torbrowserLauncher = g_getenv("TORBROWSER_LAUNCHER");
+ if (torbrowserLauncher) {
+ return false;
+ }
// https://gitlab.gnome.org/GNOME/gtk/-/blob/4300a5c609306ce77cbc8a3580c19201d…
static bool sRunning = [] {
return g_file_test("/.flatpak-info", G_FILE_TEST_EXISTS);
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/5898a9a…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/5898a9a…
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) 24 Jan '24
by richard (@richard) 24 Jan '24
24 Jan '24
richard pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
47afbf56 by Henry Wilkes at 2024-01-23T20:27:35+00:00
fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
Bug 42036: Replace replace/add bridges section with new design, ready
for Lox.
- - - - -
0021e3f3 by Henry Wilkes at 2024-01-23T20:27:36+00:00
fixup! Tor Browser strings
Bug 42036: Add strings for adding/replacing bridges.
- - - - -
c1bcea9d by Henry Wilkes at 2024-01-23T20:27:36+00:00
fixup! Add TorStrings module for localization
Bug 42036: Remove old strings for replacing bridges.
- - - - -
11 changed files:
- + browser/components/torpreferences/content/bridge-bot.svg
- 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/telegram-logo.svg
- browser/components/torpreferences/content/torPreferences.css
- browser/components/torpreferences/jar.mn
- browser/locales/en-US/browser/tor-browser.ftl
- toolkit/modules/TorStrings.sys.mjs
- toolkit/torbutton/chrome/locale/en-US/settings.properties
Changes:
=====================================
browser/components/torpreferences/content/bridge-bot.svg
=====================================
@@ -0,0 +1,13 @@
+<svg width="40" height="44" viewBox="0 0 40 44" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M37.1877 22.7584C38.7409 25.1504 38.9178 27.7923 37.5828 28.6591C36.2478 29.5259 33.9065 28.2895 32.3533 25.8975C30.8001 23.5055 30.6232 20.8637 31.9582 19.9969C33.2932 19.13 35.6345 20.3664 37.1877 22.7584Z" fill="#C069FF"/>
+<path d="M2.81234 22.7584C1.25915 25.1504 1.08224 27.7923 2.41721 28.6591C3.75217 29.5259 6.09349 28.2895 7.64668 25.8975C9.19987 23.5055 9.37678 20.8637 8.04181 19.9969C6.70685 19.13 4.36553 20.3664 2.81234 22.7584Z" fill="#C069FF"/>
+<path d="M32.2002 19.4754C33.9149 19.4754 35.3181 20.8678 35.1823 22.5772C34.7579 27.9186 33.2458 32.9181 30.8541 36.7668C28.0043 41.3527 24.1391 43.9291 20.1088 43.9291C16.0785 43.9291 12.2133 41.3527 9.36344 36.7668C6.97177 32.9181 5.45965 27.9186 5.03525 22.5772C4.89944 20.8678 6.30265 19.4754 8.0174 19.4754L32.2002 19.4754Z" fill="#C069FF"/>
+<path d="M28.4375 32.1121C28.4375 27.4522 24.6599 23.6746 20 23.6746C15.3401 23.6746 11.5625 27.4522 11.5625 32.1121V33.5139H12.8809V32.1121C12.8809 28.1803 16.0682 24.9929 20 24.9929C23.9318 24.9929 27.1191 28.1803 27.1191 32.1121V33.5139H28.4375V32.1121Z" fill="#15141A"/>
+<path d="M25.9062 32.1121C25.9062 28.8501 23.2619 26.2058 20 26.2058C16.7381 26.2058 14.0937 28.8501 14.0937 32.1121L14.0936 33.5139H15.412L15.4121 32.1121C15.4121 29.5782 17.4662 27.5242 20 27.5242C22.5338 27.5242 24.5879 29.5782 24.5879 32.1121L24.588 33.5139H25.9064L25.9062 32.1121Z" fill="#15141A"/>
+<path d="M20 28.7371C21.864 28.7371 23.375 30.2481 23.375 32.1121L23.3753 33.5139H22.0569L22.0566 32.1121C22.0566 30.9762 21.1359 30.0554 20 30.0554C18.8642 30.0554 17.9434 30.9762 17.9434 32.1121L17.9431 33.5139H16.6247V32.1121C16.6247 30.2481 18.136 28.7371 20 28.7371Z" fill="#15141A"/>
+<path d="M8.9145 17.8162C7.19975 17.8162 5.78665 16.4193 6.02668 14.7215C6.53221 11.1456 7.9061 7.82078 9.99195 5.21826C12.6698 1.87706 16.3018 -1.07451e-07 20.0889 0C23.8759 1.07451e-07 27.5079 1.87706 30.1858 5.21826C32.2716 7.82078 33.6455 11.1456 34.151 14.7215C34.3911 16.4193 32.978 17.8162 31.2632 17.8162H8.9145Z" fill="#C069FF"/>
+<path d="M13.1064 15.1091C11.3916 15.1091 9.96814 13.7048 10.3139 12.0252C10.7578 9.86855 11.6634 7.87853 12.956 6.27814C14.8477 3.93602 17.4134 2.62024 20.0887 2.62024C22.7639 2.62024 25.3296 3.93602 27.2213 6.27814C28.514 7.87853 29.4195 9.86855 29.8635 12.0252C30.2092 13.7048 28.7857 15.1091 27.071 15.1091H13.1064Z" fill="#EBD0FF"/>
+<path d="M17.5125 6.81215C17.5125 7.58388 16.9065 8.2095 16.1589 8.2095C15.4112 8.2095 14.8052 7.58388 14.8052 6.81215C14.8052 6.04041 15.4112 5.41479 16.1589 5.41479C16.9065 5.41479 17.5125 6.04041 17.5125 6.81215Z" fill="#15141A"/>
+<path d="M25.1981 6.81215C25.1981 7.58388 24.592 8.2095 23.8444 8.2095C23.0968 8.2095 22.4907 7.58388 22.4907 6.81215C22.4907 6.04041 23.0968 5.41479 23.8444 5.41479C24.592 5.41479 25.1981 6.04041 25.1981 6.81215Z" fill="#15141A"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M22.4395 9.01993L22.4044 9.11353C21.5971 11.2673 18.526 11.1951 17.8208 9.0058L18.427 8.81052C18.9472 10.4254 21.2125 10.4787 21.808 8.88998L21.8431 8.79639L22.4395 9.01993Z" fill="#15141A"/>
+</svg>
=====================================
browser/components/torpreferences/content/connectionPane.js
=====================================
@@ -1316,6 +1316,18 @@ const gBridgeSettings = {
* @type {Element?}
*/
_noBridgesEl: null,
+ /**
+ * The heading element for changing bridges.
+ *
+ * @type {Element?}
+ */
+ _changeHeadingEl: null,
+ /**
+ * The button for user to provide a bridge address or share code.
+ *
+ * @type {Element?}
+ */
+ _userProvideButton: null,
/**
* Initialize the bridge settings.
@@ -1345,6 +1357,47 @@ const gBridgeSettings = {
});
});
+ this._changeHeadingEl = document.getElementById(
+ "tor-bridges-change-heading"
+ );
+ this._userProvideButton = document.getElementById(
+ "tor-bridges-open-user-provide-dialog-button"
+ );
+
+ document.l10n.setAttributes(
+ document.getElementById("tor-bridges-user-provide-description"),
+ // TODO: Set a different string if we have Lox enabled.
+ "tor-bridges-add-addresses-description"
+ );
+
+ // TODO: Change to GetLoxBridges if Lox enabled, and the account is set up.
+ const telegramUserName = "GetBridgesBot";
+ const telegramInstruction = document.getElementById(
+ "tor-bridges-provider-instruction-telegram"
+ );
+ telegramInstruction.querySelector(
+ "a"
+ ).href = `https://t.me/${telegramUserName}`;
+ document.l10n.setAttributes(
+ telegramInstruction,
+ "tor-bridges-provider-telegram-instruction",
+ { telegramUserName }
+ );
+
+ document
+ .getElementById("tor-bridges-open-built-in-dialog-button")
+ .addEventListener("click", () => {
+ this._openBuiltinDialog();
+ });
+ this._userProvideButton.addEventListener("click", () => {
+ this._openUserProvideDialog(this._haveBridges ? "replace" : "add");
+ });
+ document
+ .getElementById("tor-bridges-open-request-dialog-button")
+ .addEventListener("click", () => {
+ this._openRequestDialog();
+ });
+
Services.obs.addObserver(this, TorSettingsTopics.SettingsChanged);
gBridgeGrid.init();
@@ -1488,6 +1541,17 @@ const gBridgeSettings = {
// and hidden.
this._groupEl.classList.toggle("no-bridges", !haveBridges);
this._groupEl.classList.toggle("have-bridges", haveBridges);
+
+ document.l10n.setAttributes(
+ this._changeHeadingEl,
+ haveBridges
+ ? "tor-bridges-replace-bridges-heading"
+ : "tor-bridges-add-bridges-heading"
+ );
+ document.l10n.setAttributes(
+ this._userProvideButton,
+ haveBridges ? "tor-bridges-replace-button" : "tor-bridges-add-new-button"
+ );
},
/**
@@ -1615,9 +1679,7 @@ const gBridgeSettings = {
"tor-bridges-options-edit-all-menu-item"
);
editItem.addEventListener("click", () => {
- // TODO: move to gBridgeSettings.
- // TODO: Change dialog title. Do not allow Lox invite.
- gConnectionPane.onAddBridgeManually();
+ this._openUserProvideDialog("edit");
});
// TODO: Do we want a different item for built-in bridges, rather than
@@ -1687,6 +1749,138 @@ const gBridgeSettings = {
_forceCloseBridgesMenu() {
this._bridgesMenu.hide(null, { force: true });
},
+
+ /**
+ * Open a bridge dialog that will change the users bridges.
+ *
+ * @param {string} url - The url of the dialog to open.
+ * @param {object?} inputData - The input data to send to the dialog window.
+ * @param {Function} onAccept - The method to call if the bridge dialog was
+ * accepted by the user. This will be passed a "result" object containing
+ * data set by the dialog. This should return a promise that resolves once
+ * the bridge settings have been set, or null if the settings have not
+ * been applied.
+ */
+ _openDialog(url, inputData, onAccept) {
+ const result = { accepted: false, connect: false };
+ let savedSettings = null;
+ gSubDialog.open(
+ url,
+ {
+ features: "resizable=yes",
+ closingCallback: () => {
+ if (!result.accepted) {
+ return;
+ }
+ savedSettings = onAccept(result);
+ if (!savedSettings) {
+ // No change in settings.
+ return;
+ }
+ if (!result.connect) {
+ // Do not open about:torconnect.
+ return;
+ }
+
+ // Wait until the settings are applied before bootstrapping.
+ savedSettings.then(() => {
+ // The bridge dialog button is "connect" when Tor is not
+ // bootstrapped, so do the connect.
+
+ // Start Bootstrapping, which should use the configured bridges.
+ // NOTE: We do this regardless of any previous TorConnect Error.
+ if (TorConnect.canBeginBootstrap) {
+ TorConnect.beginBootstrap();
+ }
+ // Open "about:torconnect".
+ // FIXME: If there has been a previous bootstrapping error then
+ // "about:torconnect" will be trying to get the user to use
+ // AutoBootstrapping. It is not set up to handle a forced direct
+ // entry to plain Bootstrapping from this dialog so the UI will
+ // not be aligned. In particular the
+ // AboutTorConnect.uiState.bootstrapCause will be aligned to
+ // whatever was shown previously in "about:torconnect" instead.
+ TorConnect.openTorConnect();
+ });
+ },
+ // closedCallback should be called after gSubDialog has already
+ // re-assigned focus back to the document.
+ closedCallback: () => {
+ if (!savedSettings) {
+ return;
+ }
+ // Wait until the settings have changed, so that the UI could
+ // respond, then move focus.
+ savedSettings.then(() => gBridgeSettings.takeFocus());
+ },
+ },
+ result,
+ inputData
+ );
+ },
+
+ /**
+ * Open the built-in bridge dialog.
+ */
+ _openBuiltinDialog() {
+ this._openDialog(
+ "chrome://browser/content/torpreferences/builtinBridgeDialog.xhtml",
+ null,
+ result => {
+ if (!result.type) {
+ return null;
+ }
+ return setTorSettings(() => {
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.BuiltIn;
+ TorSettings.bridges.builtin_type = result.type;
+ });
+ }
+ );
+ },
+
+ /*
+ * Open the request bridge dialog.
+ */
+ _openRequestDialog() {
+ this._openDialog(
+ "chrome://browser/content/torpreferences/requestBridgeDialog.xhtml",
+ null,
+ result => {
+ if (!result.bridges?.length) {
+ return null;
+ }
+ return setTorSettings(() => {
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.BridgeDB;
+ TorSettings.bridges.bridge_strings = result.bridges.join("\n");
+ });
+ }
+ );
+ },
+
+ /**
+ * Open the user provide dialog.
+ *
+ * @param {string} mode - The mode to open the dialog in: "add", "replace" or
+ * "edit".
+ */
+ _openUserProvideDialog(mode) {
+ this._openDialog(
+ "chrome://browser/content/torpreferences/provideBridgeDialog.xhtml",
+ { mode },
+ result => {
+ if (!result.bridgeStrings) {
+ return null;
+ }
+ return setTorSettings(() => {
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.UserProvided;
+ TorSettings.bridges.bridge_strings = result.bridgeStrings;
+ });
+ }
+ );
+ },
};
/*
@@ -1719,13 +1913,6 @@ const gConnectionPane = (function () {
location: "#torPreferences-bridges-location",
locationEntries: "#torPreferences-bridges-locationEntries",
chooseForMe: "#torPreferences-bridges-buttonChooseBridgeForMe",
- addHeader: "#torPreferences-addBridge-header",
- addBuiltinLabel: "#torPreferences-addBridge-labelBuiltinBridge",
- addBuiltinButton: "#torPreferences-addBridge-buttonBuiltinBridge",
- requestLabel: "#torPreferences-addBridge-labelRequestBridge",
- requestButton: "#torPreferences-addBridge-buttonRequestBridge",
- enterLabel: "#torPreferences-addBridge-labelEnterBridge",
- enterButton: "#torPreferences-addBridge-buttonEnterBridge",
},
advanced: {
header: "h1#torPreferences-advanced-header",
@@ -1985,39 +2172,6 @@ const gConnectionPane = (function () {
this._showAutoconfiguration();
}
- // Add a new bridge
- prefpane.querySelector(selectors.bridges.addHeader).textContent =
- TorStrings.settings.bridgeAdd;
- prefpane.querySelector(selectors.bridges.addBuiltinLabel).textContent =
- TorStrings.settings.bridgeSelectBrowserBuiltin;
- {
- const button = prefpane.querySelector(
- selectors.bridges.addBuiltinButton
- );
- button.setAttribute("label", TorStrings.settings.bridgeSelectBuiltin);
- button.addEventListener("command", e => {
- this.onAddBuiltinBridge();
- });
- }
- prefpane.querySelector(selectors.bridges.requestLabel).textContent =
- TorStrings.settings.bridgeRequestFromTorProject;
- {
- const button = prefpane.querySelector(selectors.bridges.requestButton);
- button.setAttribute("label", TorStrings.settings.bridgeRequest);
- button.addEventListener("command", e => {
- this.onRequestBridge();
- });
- }
- prefpane.querySelector(selectors.bridges.enterLabel).textContent =
- TorStrings.settings.bridgeEnterKnown;
- {
- const button = prefpane.querySelector(selectors.bridges.enterButton);
- button.setAttribute("label", TorStrings.settings.bridgeAddManually);
- button.addEventListener("command", e => {
- this.onAddBridgeManually();
- });
- }
-
// Advanced setup
prefpane.querySelector(selectors.advanced.header).innerText =
TorStrings.settings.advancedHeading;
@@ -2122,122 +2276,6 @@ const gConnectionPane = (function () {
this._showAutoconfiguration();
},
- /**
- * Open a bridge dialog that will change the users bridges.
- *
- * @param {string} url - The url of the dialog to open.
- * @param {Function} onAccept - The method to call if the bridge dialog was
- * accepted by the user. This will be passed a "result" object containing
- * data set by the dialog. This should return a promise that resolves once
- * the bridge settings have been set, or null if the settings have not
- * been applied.
- */
- openBridgeDialog(url, onAccept) {
- const result = { accepted: false, connect: false };
- let savedSettings = null;
- gSubDialog.open(
- url,
- {
- features: "resizable=yes",
- closingCallback: () => {
- if (!result.accepted) {
- return;
- }
- savedSettings = onAccept(result);
- if (!savedSettings) {
- // No change in settings.
- return;
- }
- if (!result.connect) {
- // Do not open about:torconnect.
- return;
- }
-
- // Wait until the settings are applied before bootstrapping.
- savedSettings.then(() => {
- // The bridge dialog button is "connect" when Tor is not
- // bootstrapped, so do the connect.
-
- // Start Bootstrapping, which should use the configured bridges.
- // NOTE: We do this regardless of any previous TorConnect Error.
- if (TorConnect.canBeginBootstrap) {
- TorConnect.beginBootstrap();
- }
- // Open "about:torconnect".
- // FIXME: If there has been a previous bootstrapping error then
- // "about:torconnect" will be trying to get the user to use
- // AutoBootstrapping. It is not set up to handle a forced direct
- // entry to plain Bootstrapping from this dialog so the UI will
- // not be aligned. In particular the
- // AboutTorConnect.uiState.bootstrapCause will be aligned to
- // whatever was shown previously in "about:torconnect" instead.
- TorConnect.openTorConnect();
- });
- },
- // closedCallback should be called after gSubDialog has already
- // re-assigned focus back to the document.
- closedCallback: () => {
- if (!savedSettings) {
- return;
- }
- // Wait until the settings have changed, so that the UI could
- // respond, then move focus.
- savedSettings.then(() => gCurrentBridgesArea.takeFocus());
- },
- },
- result
- );
- },
-
- onAddBuiltinBridge() {
- this.openBridgeDialog(
- "chrome://browser/content/torpreferences/builtinBridgeDialog.xhtml",
- result => {
- if (!result.type) {
- return null;
- }
- return setTorSettings(() => {
- TorSettings.bridges.enabled = true;
- TorSettings.bridges.source = TorBridgeSource.BuiltIn;
- TorSettings.bridges.builtin_type = result.type;
- });
- }
- );
- },
-
- // called when the request bridge button is activated
- onRequestBridge() {
- this.openBridgeDialog(
- "chrome://browser/content/torpreferences/requestBridgeDialog.xhtml",
- result => {
- if (!result.bridges?.length) {
- return null;
- }
- return setTorSettings(() => {
- TorSettings.bridges.enabled = true;
- TorSettings.bridges.source = TorBridgeSource.BridgeDB;
- TorSettings.bridges.bridge_strings = result.bridges.join("\n");
- });
- }
- );
- },
-
- onAddBridgeManually() {
- this.openBridgeDialog(
- "chrome://browser/content/torpreferences/provideBridgeDialog.xhtml",
- result => {
- if (!result.bridgeStrings) {
- return null;
- }
- return setTorSettings(() => {
- TorSettings.bridges.enabled = true;
- TorSettings.bridges.source = TorBridgeSource.UserProvided;
- TorSettings.bridges.bridge_strings = result.bridgeStrings;
- });
- }
- );
- },
-
onAdvancedSettings() {
gSubDialog.open(
"chrome://browser/content/torpreferences/connectionSettingsDialog.xhtml",
=====================================
browser/components/torpreferences/content/connectionPane.xhtml
=====================================
@@ -293,28 +293,102 @@
></html:button>
</html:div>
</html:div>
- <html:h2 id="torPreferences-addBridge-header"></html:h2>
+ <html:h2 id="tor-bridges-change-heading"></html:h2>
<hbox align="center">
- <label id="torPreferences-addBridge-labelBuiltinBridge" flex="1" />
- <button
- id="torPreferences-addBridge-buttonBuiltinBridge"
- class="accessory-button"
+ <description
+ flex="1"
+ data-l10n-id="tor-bridges-select-built-in-description"
/>
- </hbox>
- <hbox align="center">
- <label id="torPreferences-addBridge-labelRequestBridge" flex="1" />
- <button
- id="torPreferences-addBridge-buttonRequestBridge"
+ <html:button
+ id="tor-bridges-open-built-in-dialog-button"
class="accessory-button"
- />
+ data-l10n-id="tor-bridges-select-built-in-button"
+ ></html:button>
</hbox>
<hbox align="center">
- <label id="torPreferences-addBridge-labelEnterBridge" flex="1" />
- <button
- id="torPreferences-addBridge-buttonEnterBridge"
+ <description id="tor-bridges-user-provide-description" flex="1" />
+ <html:button
+ id="tor-bridges-open-user-provide-dialog-button"
class="accessory-button"
- />
+ ></html:button>
</hbox>
+ <html:h3
+ id="tor-bridges-provider-heading"
+ data-l10n-id="tor-bridges-find-more-heading"
+ ></html:h3>
+ <description data-l10n-id="tor-bridges-find-more-description" />
+ <html:div id="tor-bridges-provider-area">
+ <html:ul id="tor-bridges-provider-list">
+ <html:li class="tor-bridges-provider-item">
+ <html:img
+ id="tor-bridges-provider-icon-telegram"
+ class="tor-bridges-provider-icon"
+ alt=""
+ />
+ <html:div
+ class="tor-bridges-provider-name"
+ data-l10n-id="tor-bridges-provider-telegram-name"
+ ></html:div>
+ <html:div
+ id="tor-bridges-provider-instruction-telegram"
+ class="tor-bridges-provider-instruction"
+ >
+ <html:a data-l10n-name="user"></html:a>
+ </html:div>
+ </html:li>
+ <html:li class="tor-bridges-provider-item">
+ <html:img
+ id="tor-bridges-provider-icon-web"
+ class="tor-bridges-provider-icon"
+ alt=""
+ />
+ <html:div
+ class="tor-bridges-provider-name"
+ data-l10n-id="tor-bridges-provider-web-name"
+ ></html:div>
+ <html:div
+ class="tor-bridges-provider-instruction"
+ data-l10n-id="tor-bridges-provider-web-instruction"
+ data-l10n-args='{ "url": "bridges.torproject.org" }'
+ >
+ <html:a
+ href="https://bridges.torproject.org"
+ data-l10n-name="url"
+ ></html:a>
+ </html:div>
+ </html:li>
+ <html:li class="tor-bridges-provider-item">
+ <html:img
+ id="tor-bridges-provider-icon-email"
+ class="tor-bridges-provider-icon"
+ alt=""
+ />
+ <html:div
+ class="tor-bridges-provider-name"
+ data-l10n-id="tor-bridges-provider-email-name"
+ ></html:div>
+ <html:div
+ class="tor-bridges-provider-instruction"
+ data-l10n-id="tor-bridges-provider-email-instruction"
+ data-l10n-args='{ "address": "bridges(a)torproject.org" }'
+ ></html:div>
+ </html:li>
+ </html:ul>
+ <html:div id="tor-bridges-request-box">
+ <html:img
+ alt=""
+ src="chrome://browser/content/torpreferences/bridge-bot.svg"
+ ></html:img>
+ <html:div
+ id="tor-bridges-request-description"
+ data-l10n-id="tor-bridges-request-from-browser"
+ ></html:div>
+ <html:button
+ id="tor-bridges-open-request-dialog-button"
+ data-l10n-id="tor-bridges-request-button"
+ ></html:button>
+ </html:div>
+ </html:div>
</groupbox>
<!-- Advanced -->
=====================================
browser/components/torpreferences/content/provideBridgeDialog.js
=====================================
@@ -15,11 +15,24 @@ const { TorConnect, TorConnectTopics } = ChromeUtils.importESModule(
const gProvideBridgeDialog = {
init() {
this._result = window.arguments[0];
+ const mode = window.arguments[1].mode;
+
+ let titleId;
+ switch (mode) {
+ case "edit":
+ titleId = "user-provide-bridge-dialog-edit-title";
+ break;
+ case "add":
+ titleId = "user-provide-bridge-dialog-add-title";
+ break;
+ case "replace":
+ default:
+ titleId = "user-provide-bridge-dialog-replace-title";
+ break;
+ }
+
+ document.l10n.setAttributes(document.documentElement, titleId);
- document.documentElement.setAttribute(
- "title",
- TorStrings.settings.provideBridgeTitleAdd
- );
const learnMore = document.createXULElement("label");
learnMore.className = "learnMore text-link";
learnMore.setAttribute("is", "text-link");
=====================================
browser/components/torpreferences/content/provideBridgeDialog.xhtml
=====================================
@@ -9,6 +9,10 @@
xmlns:html="http://www.w3.org/1999/xhtml"
>
<dialog id="torPreferences-provideBridge-dialog" buttons="accept,cancel">
+ <linkset>
+ <html:link rel="localization" href="browser/tor-browser.ftl" />
+ </linkset>
+
<script src="chrome://browser/content/torpreferences/provideBridgeDialog.js" />
<description>
=====================================
browser/components/torpreferences/content/telegram-logo.svg
=====================================
@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="context-fill" xmlns="http://www.w3.org/2000/svg">
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M13.5527 3.74072C13.6057 3.44502 13.3069 3.21007 13.0321 3.33143L2.46222 7.99865L5.04818 8.60316L10.1001 5.29184C10.8373 4.80861 11.6593 5.7727 11.0656 6.42426L7.88895 9.91029L11.9093 12.8968L13.5527 3.74072ZM12.5272 2.18794C13.7181 1.66208 15.013 2.68016 14.783 3.96155L13.104 13.3162C12.9564 14.1382 11.9962 14.5186 11.3258 14.0205L7.03263 10.8313C6.49819 10.4343 6.42353 9.66259 6.87195 9.17049L7.47872 8.50462L5.68862 9.67797C5.4311 9.84676 5.11564 9.90263 4.81582 9.83254L1.81371 9.13075C0.762034 8.8849 0.627375 7.4424 1.61537 7.00614L12.5272 2.18794Z"/>
+</svg>
=====================================
browser/components/torpreferences/content/torPreferences.css
=====================================
@@ -447,6 +447,91 @@
fill: currentColor;
}
+#tor-bridges-provider-heading {
+ font-size: 1.14em;
+ margin-block: 48px 8px;
+}
+
+#tor-bridges-provider-area {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 16px;
+ align-items: start;
+ line-height: 1.8;
+ margin-block-start: 24px;
+}
+
+#tor-bridges-provider-list {
+ display: grid;
+ grid-template-columns: max-content max-content;
+ /* 16px gap between items. */
+ gap: 16px 12px;
+ margin-block: 16px;
+}
+
+.tor-bridges-provider-item {
+ grid-column: 1 / -1;
+ display: grid;
+ grid-template-columns: subgrid;
+ align-items: center;
+ justify-items: start;
+ /* No gap between the name and instruction. */
+ gap: 0 12px;
+}
+
+.tor-bridges-provider-icon {
+ width: 16px;
+ height: 16px;
+ -moz-context-properties: fill;
+ fill: var(--in-content-icon-color);
+}
+
+#tor-bridges-provider-icon-telegram {
+ content: url("chrome://browser/content/torpreferences/telegram-logo.svg");
+}
+
+#tor-bridges-provider-icon-web {
+ content: url("chrome://browser/content/torpreferences/network.svg");
+}
+
+#tor-bridges-provider-icon-email {
+ content: url("chrome://browser/skin/mail.svg");
+}
+
+.tor-bridges-provider-name {
+ font-weight: 600;
+ font-size: 0.85em;
+}
+
+.tor-bridges-provider-instruction {
+ grid-column: 2 / 3;
+}
+
+#tor-bridges-request-box {
+ /* Take up the full height in the container. */
+ align-self: stretch;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ padding: 16px;
+ background: var(--in-content-box-info-background);
+ border-radius: 4px;
+}
+
+#tor-bridges-request-box > * {
+ flex: 0 0 auto;
+}
+
+#tor-bridges-request-description {
+ margin-block: 12px 16px;
+}
+
+#tor-bridges-open-request-dialog-button {
+ margin: 0;
+ line-height: 1;
+}
+
#torPreferences-bridges-location {
width: 280px;
}
=====================================
browser/components/torpreferences/jar.mn
=====================================
@@ -1,6 +1,8 @@
browser.jar:
content/browser/torpreferences/bridge.svg (content/bridge.svg)
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/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
=====================================
@@ -121,3 +121,58 @@ 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 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.
+tor-bridges-replace-bridges-heading = Replace your bridges
+
+tor-bridges-select-built-in-description = Choose from one of { -brand-short-name }’s built-in bridges
+tor-bridges-select-built-in-button = Select a built-in bridge…
+
+tor-bridges-add-addresses-description = Enter bridge addresses you already know
+# Shown when the user has no current bridges.
+# Opens a dialog where the user can provide a new bridge address or share code.
+tor-bridges-add-new-button = Add new bridges…
+# Shown when the user has existing bridges.
+# Opens a dialog where the user can provide a new bridge address or share code to replace their current bridges.
+tor-bridges-replace-button = Replace bridges…
+
+tor-bridges-find-more-heading = Find more bridges
+# "Tor Project" is the organisation name.
+tor-bridges-find-more-description = Since many bridge addresses aren’t public, you may need to request some from the Tor Project.
+
+# "Telegram" is the common brand name of the Telegram Messenger application
+tor-bridges-provider-telegram-name = Telegram
+# Here "Message" is a verb, short for "Send a message to". This is an instruction to send a message to the given Telegram Messenger user to receive a new bridge.
+# $telegramUserName (String) - The Telegram Messenger user name that should receive messages. Should be wrapped in '<a data-l10n-name="user">' and '</a>'.
+# E.g. in English, "Message GetBridgesBot".
+tor-bridges-provider-telegram-instruction = Message <a data-l10n-name="user">{ $telegramUserName }</a>
+
+# "Web" is the proper noun for the "World Wide Web".
+tor-bridges-provider-web-name = Web
+# Instructions to visit the given website.
+# $url (String) - The URL for Tor Project bridges. Should be wrapped in '<a data-l10n-name"url">' and '</a>'.
+tor-bridges-provider-web-instruction = Visit <a data-l10n-name="url">{ $url }</a>
+
+# "Gmail" is the Google brand name. "Riseup" refers to the Riseup organisation at riseup.net.
+tor-bridges-provider-email-name = Gmail or Riseup
+# Here "Email" is a verb, short for "Send an email to". This is an instruction to send an email to the given address to receive a new bridge.
+# $address (String) - The email address that should receive the email.
+# E.g. in English, "Email bridges(a)torproject.org".
+tor-bridges-provider-email-instruction = Email { $address }
+
+tor-bridges-request-from-browser = You can also get bridges from the bridge bot without leaving { -brand-short-name }.
+tor-bridges-request-button = Request bridges…
+
+## User provided bridge dialog.
+
+# Used when the user is editing their existing bridge addresses.
+user-provide-bridge-dialog-edit-title =
+ .title = Edit your bridges
+# Used when the user has no existing bridges.
+user-provide-bridge-dialog-add-title =
+ .title = Add new bridges
+# Used when the user is replacing their existing bridges with new ones.
+user-provide-bridge-dialog-replace-title =
+ .title = Replace your bridges
=====================================
toolkit/modules/TorStrings.sys.mjs
=====================================
@@ -105,14 +105,6 @@ const Loader = {
bridgeRemoveAllDialogTitle: "Remove all bridges?",
bridgeRemoveAllDialogDescription:
"If these bridges were received from torproject.org or added manually, this action cannot be undone",
- bridgeAdd: "Add a New Bridge",
- bridgeSelectBrowserBuiltin:
- "Choose from one of Tor Browser’s built-in bridges",
- bridgeSelectBuiltin: "Select a Built-In Bridge…",
- bridgeRequestFromTorProject: "Request a bridge from torproject.org",
- bridgeRequest: "Request a Bridge…",
- bridgeEnterKnown: "Enter a bridge address you already know",
- bridgeAddManually: "Add a Bridge Manually…",
// Advanced settings
advancedHeading: "Advanced",
advancedLabel: "Configure how Tor Browser connects to the internet",
@@ -148,7 +140,6 @@ const Loader = {
captchaTextboxPlaceholder: "Enter the characters from the image",
incorrectCaptcha: "The solution is not correct. Please try again.",
// Provide bridge dialog
- provideBridgeTitleAdd: "Add a Bridge Manually",
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)",
=====================================
toolkit/torbutton/chrome/locale/en-US/settings.properties
=====================================
@@ -39,13 +39,6 @@ settings.bridgeDisableBuiltIn=Disable built-in bridges
settings.copied=Copied!
settings.bridgeRemoveAllDialogTitle=Remove all bridges?
settings.bridgeRemoveAllDialogDescription=If these bridges were received from torproject.org or added manually, this action cannot be undone
-settings.bridgeAdd=Add a New Bridge
-settings.bridgeSelectBrowserBuiltin=Choose from one of Tor Browser’s built-in bridges
-settings.bridgeSelectBuiltin=Select a Built-In Bridge…
-settings.bridgeRequestFromTorProject=Request a bridge from torproject.org
-settings.bridgeRequest=Request a Bridge…
-settings.bridgeEnterKnown=Enter a bridge address you already know
-settings.bridgeAddManually=Add a Bridge Manually…
# Advanced settings
settings.advancedHeading=Advanced
@@ -82,8 +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.
-# 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)
@@ -125,3 +116,13 @@ settings.bridgeShowAll=Show All Bridges
settings.bridgeShowFewer=Show Fewer Bridges
settings.allBridgesEnabled=Use current bridges
settings.bridgeRemoveAll=Remove All Bridges
+settings.bridgeAdd=Add a New Bridge
+settings.bridgeSelectBrowserBuiltin=Choose from one of Tor Browser’s built-in bridges
+settings.bridgeSelectBuiltin=Select a Built-In Bridge…
+settings.bridgeRequestFromTorProject=Request a bridge from torproject.org
+settings.bridgeRequest=Request a Bridge…
+settings.bridgeEnterKnown=Enter a bridge address you already know
+settings.bridgeAddManually=Add a Bridge Manually…
+
+# Provide bridge dialog
+settings.provideBridgeTitleAdd=Add a Bridge Manually
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/6211ed…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/6211ed…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][main] Bug 41066: Compress the APKs more
by Pier Angelo Vendrame (@pierov) 24 Jan '24
by Pier Angelo Vendrame (@pierov) 24 Jan '24
24 Jan '24
Pier Angelo Vendrame pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
23474930 by Pier Angelo Vendrame at 2024-01-24T17:08:30+01:00
Bug 41066: Compress the APKs more
Our APK was refused by the Play Store as too big.
As a workaround, for this release we can try to compress the APK more,
by extracting it and repacking it with 7-zip.
The preferred and long-term solution would be to switch to Android App
Bundles, but this might require some changes to our signing scripts.
- - - - -
2 changed files:
- projects/browser/build.android
- projects/browser/config
Changes:
=====================================
projects/browser/build.android
=====================================
@@ -46,13 +46,19 @@ mv $rootdir/[% c('input_files_by_name/noscript') %] "$noscript_path"
mv $rootdir/allowed_addons.json $assets_dir/allowed_addons.json
-[% c('zip', {
- zip_src => [ '$assets_dir' ],
- zip_args => '$apk',
- }) %]
+mkdir apk
+pushd apk
+7zz x "$apk"
+cp -R ../assets ./
+find -type f -exec touch -m -t '[% USE date; date.format(pc("firefox-android", "timestamp"), format = "%Y%m%d%H%M") %]' {} \;
+find -type f ! -name resources.arsc -printf '%P\n' | sort > ../files.txt
+7zz a -tzip -mx9 -mtc- -spf ../repacked.apk @../files.txt
+# resources.arsc must not be compressed as per the APK specifications
+7zz a -tzip -mm=Copy -mtc- ../repacked.apk resources.arsc
+popd
aligned_apk=$(basename $apk .apk)_aligned.apk
-zipalign -vp 4 $apk $aligned_apk
+zipalign -vp 4 repacked.apk $aligned_apk
# Sign a QA build. This .apk is not a debug version and doesn't contain a debug
# flag in the manifest.
=====================================
projects/browser/config
=====================================
@@ -46,7 +46,13 @@ targets:
var:
verify_allowed_addons: 1
arch_deps:
- - openjdk-11-jdk-headless
+ - 7zip
+ - openjdk-17-jdk-headless
+ container:
+ # 7zip is in backports in bullseye, and we can already use Java 17 for
+ # apksigner.
+ suite: bookworm
+ arch: amd64
torbrowser:
var:
prefs_file: 000-tor-browser.js
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/2…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/2…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/rbm][main] Bug 40067: Use --no-verbose wget option when not running in a terminal
by richard (@richard) 24 Jan '24
by richard (@richard) 24 Jan '24
24 Jan '24
richard pushed to branch main at The Tor Project / Applications / RBM
Commits:
b5e5b04a by Nicolas Vigier at 2024-01-24T10:24:19+01:00
Bug 40067: Use --no-verbose wget option when not running in a terminal
Use the `--no-verbose` option when stdout is not a tty. We avoid setting
the option when `getting_id` is set, in order to have constant
`input_file_id` when `urlget` is being used inside the `exec` script in
`input_files`.
- - - - -
2 changed files:
- doc/options_misc.asc
- lib/RBM/DefaultConfig.pm
Changes:
=====================================
doc/options_misc.asc
=====================================
@@ -21,6 +21,9 @@ abbrev_length::
This option sets the length of the abbreviated commits, when
using the +abbrev+ option.
+isatty::
+ This option is true when stdout is connected to a tty.
+
tar::
Use this options instead of 'tar' in build scripts when you want
to create deterministic tar files. This options set tar arguments
=====================================
lib/RBM/DefaultConfig.pm
=====================================
@@ -151,6 +151,7 @@ our %default_config = (
debug => 0,
compress_tar => 'gz',
version => "[%- exit_error('No version specified for ' _ project); -%]",
+ isatty => sub { -t STDOUT },
####
####
####
@@ -577,7 +578,7 @@ set -e
END;
-%]
tmpfile="\$(mktemp -p [% shell_quote(rbm_tmp_dir) %])"
-wget -O"\$tmpfile" [% shell_quote(c("URL")) %]
+wget[% IF !c("getting_id") && !c("isatty") %] --no-verbose[% END %] -O"\$tmpfile" [% shell_quote(c("URL")) %]
mv -f "\$tmpfile" [% shell_quote(dest_dir _ "/" _ c("filename")) %]
URLGET
sig_ext => [ qw(gpg asc sig) ],
View it on GitLab: https://gitlab.torproject.org/tpo/applications/rbm/-/commit/b5e5b04aaf677c4…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/rbm/-/commit/b5e5b04aaf677c4…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser-build][main] Update release-prep template with startpage contact to notify on major ESR transition
by richard (@richard) 24 Jan '24
by richard (@richard) 24 Jan '24
24 Jan '24
richard pushed to branch main at The Tor Project / Applications / tor-browser-build
Commits:
ef63c83c by Richard Pospesel at 2024-01-24T11:30:38+00:00
Update release-prep template with startpage contact to notify on major ESR transition
- - - - -
1 changed file:
- .gitlab/issue_templates/Release Prep - Tor Browser Alpha.md
Changes:
=====================================
.gitlab/issue_templates/Release Prep - Tor Browser Alpha.md
=====================================
@@ -169,6 +169,8 @@
- [ ] Email external partners:
- ***(Optional, after ESR migration)*** Cloudflare: ask-research(a)cloudflare.com
- **NOTE** : We need to provide them with updated user agent string so they can update their internal machinery to prevent Tor Browser users from getting so many CAPTCHAs
+ - ***(Optional, after ESR migration)*** Startpage: admin(a)startpage.com
+ - **NOTE** : Startpage also needs the updated user-agent string for better experience on their onion service sites.
</details>
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/e…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/commit/e…
You're receiving this email because of your account on gitlab.torproject.org.
1
0
[Git][tpo/applications/tor-browser][tor-browser-115.7.0esr-13.5-1] fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in...
by richard (@richard) 23 Jan '24
by richard (@richard) 23 Jan '24
23 Jan '24
richard pushed to branch tor-browser-115.7.0esr-13.5-1 at The Tor Project / Applications / Tor Browser
Commits:
6211ed8f by Henry Wilkes at 2024-01-23T18:27:26+00:00
fixup! Bug 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
Bug 42036: Refactor tor setting dialogs to follow firefox style.
Also, move the user focus to their new bridges when the bridge dialogs
succeed.
- - - - -
16 changed files:
- + browser/components/torpreferences/content/bridgeQrDialog.js
- − browser/components/torpreferences/content/bridgeQrDialog.mjs
- browser/components/torpreferences/content/bridgeQrDialog.xhtml
- browser/components/torpreferences/content/builtinBridgeDialog.mjs → browser/components/torpreferences/content/builtinBridgeDialog.js
- browser/components/torpreferences/content/builtinBridgeDialog.xhtml
- browser/components/torpreferences/content/connectionPane.js
- browser/components/torpreferences/content/connectionSettingsDialog.mjs → browser/components/torpreferences/content/connectionSettingsDialog.js
- browser/components/torpreferences/content/connectionSettingsDialog.xhtml
- browser/components/torpreferences/content/provideBridgeDialog.mjs → browser/components/torpreferences/content/provideBridgeDialog.js
- browser/components/torpreferences/content/provideBridgeDialog.xhtml
- browser/components/torpreferences/content/requestBridgeDialog.mjs → browser/components/torpreferences/content/requestBridgeDialog.js
- browser/components/torpreferences/content/requestBridgeDialog.xhtml
- + browser/components/torpreferences/content/torLogDialog.js
- − browser/components/torpreferences/content/torLogDialog.mjs
- browser/components/torpreferences/content/torLogDialog.xhtml
- browser/components/torpreferences/jar.mn
Changes:
=====================================
browser/components/torpreferences/content/bridgeQrDialog.js
=====================================
@@ -0,0 +1,34 @@
+"use strict";
+
+const { QRCode } = ChromeUtils.importESModule(
+ "resource://gre/modules/QRCode.sys.mjs"
+);
+
+const { TorStrings } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorStrings.sys.mjs"
+);
+
+window.addEventListener(
+ "DOMContentLoaded",
+ () => {
+ const bridgeString = window.arguments[0];
+
+ document.documentElement.setAttribute(
+ "title",
+ TorStrings.settings.scanQrTitle
+ );
+ const target = document.getElementById("bridgeQr-target");
+ const style = window.getComputedStyle(target);
+ const width = style.width.substr(0, style.width.length - 2);
+ const height = style.height.substr(0, style.height.length - 2);
+ new QRCode(target, {
+ text: bridgeString,
+ width,
+ height,
+ colorDark: style.color,
+ colorLight: style.backgroundColor,
+ document,
+ });
+ },
+ { once: true }
+);
=====================================
browser/components/torpreferences/content/bridgeQrDialog.mjs deleted
=====================================
@@ -1,44 +0,0 @@
-import { QRCode } from "resource://gre/modules/QRCode.sys.mjs";
-
-import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
-
-export class BridgeQrDialog {
- constructor() {
- this._bridgeString = "";
- }
-
- static get selectors() {
- return {
- target: "#bridgeQr-target",
- };
- }
-
- _populateXUL(window, dialog) {
- dialog.parentElement.setAttribute("title", TorStrings.settings.scanQrTitle);
- const target = dialog.querySelector(BridgeQrDialog.selectors.target);
- const style = window.getComputedStyle(target);
- const width = style.width.substr(0, style.width.length - 2);
- const height = style.height.substr(0, style.height.length - 2);
- new QRCode(target, {
- text: this._bridgeString,
- width,
- height,
- colorDark: style.color,
- colorLight: style.backgroundColor,
- document: window.document,
- });
- }
-
- init(window, dialog) {
- this._populateXUL(window, dialog);
- }
-
- openDialog(gSubDialog, bridgeString) {
- this._bridgeString = bridgeString;
- gSubDialog.open(
- "chrome://browser/content/torpreferences/bridgeQrDialog.xhtml",
- { features: "resizable=yes" },
- this
- );
- }
-}
=====================================
browser/components/torpreferences/content/bridgeQrDialog.xhtml
=====================================
@@ -9,6 +9,8 @@
xmlns:html="http://www.w3.org/1999/xhtml"
>
<dialog id="bridgeQr-dialog" buttons="accept">
+ <script src="chrome://browser/content/torpreferences/bridgeQrDialog.js" />
+
<html:div>
<html:div id="bridgeQr">
<html:div id="bridgeQr-target" />
@@ -16,16 +18,5 @@
<html:div id="bridgeQr-onion" />
</html:div>
</html:div>
- <script type="application/javascript">
- <![CDATA[
- "use strict";
-
- let dialogObject = window.arguments[0];
- document.addEventListener("DOMContentLoaded", () => {
- let dialogElement = document.getElementById("bridgeQr-dialog");
- dialogObject.init(window, dialogElement);
- });
- ]]>
- </script>
</dialog>
</window>
=====================================
browser/components/torpreferences/content/builtinBridgeDialog.mjs → browser/components/torpreferences/content/builtinBridgeDialog.js
=====================================
@@ -1,38 +1,32 @@
-import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
-
-import {
- TorSettings,
- TorBridgeSource,
-} from "resource://gre/modules/TorSettings.sys.mjs";
-
-import {
- TorConnect,
- TorConnectTopics,
-} from "resource://gre/modules/TorConnect.sys.mjs";
-
-export class BuiltinBridgeDialog {
- /**
- * Create a new instance.
- *
- * @param {Function} onSubmit - A callback for when the user accepts the
- * dialog selection.
- */
- constructor(onSubmit) {
- this.onSubmit = onSubmit;
- this._acceptButton = null;
- this._radioGroup = null;
- }
-
- _populateXUL(window, dialog) {
- const dialogWin = dialog.parentElement;
- dialogWin.setAttribute("title", TorStrings.settings.builtinBridgeHeader);
-
- dialog.querySelector(
- "#torPreferences-builtinBridge-description"
+"use strict";
+
+const { TorStrings } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorStrings.sys.mjs"
+);
+
+const { TorSettings, TorBridgeSource } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorSettings.sys.mjs"
+);
+
+const { TorConnect, TorConnectTopics } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorConnect.sys.mjs"
+);
+
+const gBuiltinBridgeDialog = {
+ init() {
+ this._result = window.arguments[0];
+
+ document.documentElement.setAttribute(
+ "title",
+ TorStrings.settings.builtinBridgeHeader
+ );
+
+ document.getElementById(
+ "torPreferences-builtinBridge-description"
).textContent = TorStrings.settings.builtinBridgeDescription2;
- this._radioGroup = dialog.querySelector(
- "#torPreferences-builtinBridge-typeSelection"
+ this._radioGroup = document.getElementById(
+ "torPreferences-builtinBridge-typeSelection"
);
const typeStrings = {
@@ -84,8 +78,12 @@ export class BuiltinBridgeDialog {
}
this._radioGroup.addEventListener("select", () => this.onSelectChange());
+
+ const dialog = document.getElementById(
+ "torPreferences-builtinBridge-dialog"
+ );
dialog.addEventListener("dialogaccept", () => {
- this.onSubmit(this._radioGroup.value, TorConnect.canBeginBootstrap);
+ this._result.accepted = true;
});
this._acceptButton = dialog.getButton("accept");
@@ -94,20 +92,28 @@ export class BuiltinBridgeDialog {
this.onSelectChange();
this.onAcceptStateChange();
- }
+ },
+
+ uninit() {
+ Services.obs.removeObserver(this, TorConnectTopics.StateChange);
+ },
onSelectChange() {
- this._acceptButton.disabled = !this._radioGroup.value;
- }
+ const value = this._radioGroup.value;
+ this._acceptButton.disabled = !value;
+ this._result.type = value;
+ },
onAcceptStateChange() {
+ const connect = TorConnect.canBeginBootstrap;
+ this._result.connect = connect;
this._acceptButton.setAttribute(
"label",
- TorConnect.canBeginBootstrap
+ connect
? TorStrings.settings.bridgeButtonConnect
: TorStrings.settings.bridgeButtonAccept
);
- }
+ },
observe(subject, topic, data) {
switch (topic) {
@@ -115,27 +121,20 @@ export class BuiltinBridgeDialog {
this.onAcceptStateChange();
break;
}
- }
-
- init(window, aDialog) {
- this._populateXUL(window, aDialog);
- }
-
- close() {
- // Unregister our observer topics.
- Services.obs.removeObserver(this, TorConnectTopics.StateChange);
- }
-
- openDialog(gSubDialog) {
- gSubDialog.open(
- "chrome://browser/content/torpreferences/builtinBridgeDialog.xhtml",
- {
- features: "resizable=yes",
- closingCallback: () => {
- this.close();
- },
+ },
+};
+
+window.addEventListener(
+ "DOMContentLoaded",
+ () => {
+ gBuiltinBridgeDialog.init();
+ window.addEventListener(
+ "unload",
+ () => {
+ gBuiltinBridgeDialog.uninit();
},
- this
+ { once: true }
);
- }
-}
+ },
+ { once: true }
+);
=====================================
browser/components/torpreferences/content/builtinBridgeDialog.xhtml
=====================================
@@ -9,6 +9,8 @@
xmlns:html="http://www.w3.org/1999/xhtml"
>
<dialog id="torPreferences-builtinBridge-dialog" buttons="accept,cancel">
+ <script src="chrome://browser/content/torpreferences/builtinBridgeDialog.js" />
+
<description id="torPreferences-builtinBridge-description"> </description>
<radiogroup id="torPreferences-builtinBridge-typeSelection">
<vbox class="builtin-bridges-option">
@@ -78,16 +80,5 @@
</html:div>
</vbox>
</radiogroup>
- <script type="application/javascript">
- <![CDATA[
- "use strict";
-
- let builtinBridgeDialog = window.arguments[0];
- document.addEventListener("DOMContentLoaded", () => {
- let dialog = document.getElementById("torPreferences-builtinBridge-dialog");
- builtinBridgeDialog.init(window, dialog);
- });
- ]]>
- </script>
</dialog>
</window>
=====================================
browser/components/torpreferences/content/connectionPane.js
=====================================
@@ -24,30 +24,6 @@ const { TorProviderBuilder, TorProviderTopics } = ChromeUtils.importESModule(
const { TorConnect, TorConnectTopics, TorConnectState, TorCensorshipLevel } =
ChromeUtils.importESModule("resource://gre/modules/TorConnect.sys.mjs");
-const { TorLogDialog } = ChromeUtils.importESModule(
- "chrome://browser/content/torpreferences/torLogDialog.mjs"
-);
-
-const { ConnectionSettingsDialog } = ChromeUtils.importESModule(
- "chrome://browser/content/torpreferences/connectionSettingsDialog.mjs"
-);
-
-const { BridgeQrDialog } = ChromeUtils.importESModule(
- "chrome://browser/content/torpreferences/bridgeQrDialog.mjs"
-);
-
-const { BuiltinBridgeDialog } = ChromeUtils.importESModule(
- "chrome://browser/content/torpreferences/builtinBridgeDialog.mjs"
-);
-
-const { RequestBridgeDialog } = ChromeUtils.importESModule(
- "chrome://browser/content/torpreferences/requestBridgeDialog.mjs"
-);
-
-const { ProvideBridgeDialog } = ChromeUtils.importESModule(
- "chrome://browser/content/torpreferences/provideBridgeDialog.mjs"
-);
-
const { MoatRPC } = ChromeUtils.importESModule(
"resource://gre/modules/Moat.sys.mjs"
);
@@ -114,6 +90,19 @@ async function getConnectedBridgeId() {
return bridge?.fingerprint ?? null;
}
+/**
+ * Show the bridge QR to the user.
+ *
+ * @param {string} bridgeString - The string to use in the QR.
+ */
+function showBridgeQr(bridgeString) {
+ gSubDialog.open(
+ "chrome://browser/content/torpreferences/bridgeQrDialog.xhtml",
+ { features: "resizable=yes" },
+ bridgeString
+ );
+}
+
// TODO: Instead of aria-live in the DOM, use the proposed ariaNotify
// API if it gets accepted into firefox and works with screen readers.
// See https://github.com/WICG/proposals/issues/112
@@ -803,8 +792,7 @@ const gBridgeGrid = {
if (!bridgeLine) {
return;
}
- const dialog = new BridgeQrDialog();
- dialog.openDialog(gSubDialog, bridgeLine);
+ showBridgeQr(bridgeLine);
});
row.menu
.querySelector(".tor-bridges-options-copy-one-menu-item")
@@ -1571,8 +1559,7 @@ const gBridgeSettings = {
if (!this._canQRBridges) {
return;
}
- const dialog = new BridgeQrDialog();
- dialog.openDialog(gSubDialog, this._bridgeStrings);
+ showBridgeQr(this._bridgeStrings);
},
/**
@@ -2136,96 +2123,133 @@ const gConnectionPane = (function () {
},
/**
- * Save and apply settings, then optionally open about:torconnect and start
- * bootstrapping.
+ * Open a bridge dialog that will change the users bridges.
*
- * @param {fucntion} changes - The changes to make.
- * @param {boolean} connect - Whether to open about:torconnect and start
- * bootstrapping if possible.
+ * @param {string} url - The url of the dialog to open.
+ * @param {Function} onAccept - The method to call if the bridge dialog was
+ * accepted by the user. This will be passed a "result" object containing
+ * data set by the dialog. This should return a promise that resolves once
+ * the bridge settings have been set, or null if the settings have not
+ * been applied.
*/
- async saveBridgeSettings(changes, connect) {
- // TODO: Move focus into the bridge area.
- // dialog.ownerGlobal.addEventListener("unload", () => gCurrentBridgesArea.takeFocus(), { once: true });
- // or use closedCallback in gSubDialog.open()
- setTorSettings(changes);
-
- if (!connect) {
- return;
- }
-
- // The bridge dialog button is "connect" when Tor is not bootstrapped,
- // so do the connect.
+ openBridgeDialog(url, onAccept) {
+ const result = { accepted: false, connect: false };
+ let savedSettings = null;
+ gSubDialog.open(
+ url,
+ {
+ features: "resizable=yes",
+ closingCallback: () => {
+ if (!result.accepted) {
+ return;
+ }
+ savedSettings = onAccept(result);
+ if (!savedSettings) {
+ // No change in settings.
+ return;
+ }
+ if (!result.connect) {
+ // Do not open about:torconnect.
+ return;
+ }
- // Start Bootstrapping, which should use the configured bridges.
- // NOTE: We do this regardless of any previous TorConnect Error.
- if (TorConnect.canBeginBootstrap) {
- TorConnect.beginBootstrap();
- }
- // Open "about:torconnect".
- // FIXME: If there has been a previous bootstrapping error then
- // "about:torconnect" will be trying to get the user to use
- // AutoBootstrapping. It is not set up to handle a forced direct
- // entry to plain Bootstrapping from this dialog so the UI will not
- // be aligned. In particular the
- // AboutTorConnect.uiState.bootstrapCause will be aligned to
- // whatever was shown previously in "about:torconnect" instead.
- TorConnect.openTorConnect();
+ // Wait until the settings are applied before bootstrapping.
+ savedSettings.then(() => {
+ // The bridge dialog button is "connect" when Tor is not
+ // bootstrapped, so do the connect.
+
+ // Start Bootstrapping, which should use the configured bridges.
+ // NOTE: We do this regardless of any previous TorConnect Error.
+ if (TorConnect.canBeginBootstrap) {
+ TorConnect.beginBootstrap();
+ }
+ // Open "about:torconnect".
+ // FIXME: If there has been a previous bootstrapping error then
+ // "about:torconnect" will be trying to get the user to use
+ // AutoBootstrapping. It is not set up to handle a forced direct
+ // entry to plain Bootstrapping from this dialog so the UI will
+ // not be aligned. In particular the
+ // AboutTorConnect.uiState.bootstrapCause will be aligned to
+ // whatever was shown previously in "about:torconnect" instead.
+ TorConnect.openTorConnect();
+ });
+ },
+ // closedCallback should be called after gSubDialog has already
+ // re-assigned focus back to the document.
+ closedCallback: () => {
+ if (!savedSettings) {
+ return;
+ }
+ // Wait until the settings have changed, so that the UI could
+ // respond, then move focus.
+ savedSettings.then(() => gCurrentBridgesArea.takeFocus());
+ },
+ },
+ result
+ );
},
onAddBuiltinBridge() {
- const builtinBridgeDialog = new BuiltinBridgeDialog(
- (bridgeType, connect) => {
- this.saveBridgeSettings(() => {
+ this.openBridgeDialog(
+ "chrome://browser/content/torpreferences/builtinBridgeDialog.xhtml",
+ result => {
+ if (!result.type) {
+ return null;
+ }
+ return setTorSettings(() => {
TorSettings.bridges.enabled = true;
TorSettings.bridges.source = TorBridgeSource.BuiltIn;
- TorSettings.bridges.builtin_type = bridgeType;
- }, connect);
+ TorSettings.bridges.builtin_type = result.type;
+ });
}
);
- builtinBridgeDialog.openDialog(gSubDialog);
},
// called when the request bridge button is activated
onRequestBridge() {
- const requestBridgeDialog = new RequestBridgeDialog(
- (aBridges, connect) => {
- if (!aBridges.length) {
- return;
+ this.openBridgeDialog(
+ "chrome://browser/content/torpreferences/requestBridgeDialog.xhtml",
+ result => {
+ if (!result.bridges?.length) {
+ return null;
}
-
- const bridgeStrings = aBridges.join("\n");
-
- this.saveBridgeSettings(() => {
+ return setTorSettings(() => {
TorSettings.bridges.enabled = true;
TorSettings.bridges.source = TorBridgeSource.BridgeDB;
- TorSettings.bridges.bridge_strings = bridgeStrings;
- }, connect);
+ TorSettings.bridges.bridge_strings = result.bridges.join("\n");
+ });
}
);
- requestBridgeDialog.openDialog(gSubDialog);
},
onAddBridgeManually() {
- const provideBridgeDialog = new ProvideBridgeDialog(
- (aBridgeString, connect) => {
- this.saveBridgeSettings(() => {
+ this.openBridgeDialog(
+ "chrome://browser/content/torpreferences/provideBridgeDialog.xhtml",
+ result => {
+ if (!result.bridgeStrings) {
+ return null;
+ }
+ return setTorSettings(() => {
TorSettings.bridges.enabled = true;
TorSettings.bridges.source = TorBridgeSource.UserProvided;
- TorSettings.bridges.bridge_strings = aBridgeString;
- }, connect);
+ TorSettings.bridges.bridge_strings = result.bridgeStrings;
+ });
}
);
- provideBridgeDialog.openDialog(gSubDialog);
},
onAdvancedSettings() {
- const connectionSettingsDialog = new ConnectionSettingsDialog();
- connectionSettingsDialog.openDialog(gSubDialog);
+ gSubDialog.open(
+ "chrome://browser/content/torpreferences/connectionSettingsDialog.xhtml",
+ { features: "resizable=yes" }
+ );
},
onViewTorLogs() {
- const torLogDialog = new TorLogDialog();
- torLogDialog.openDialog(gSubDialog);
+ gSubDialog.open(
+ "chrome://browser/content/torpreferences/torLogDialog.xhtml",
+ { features: "resizable=yes" }
+ );
},
};
return retval;
=====================================
browser/components/torpreferences/content/connectionSettingsDialog.mjs → browser/components/torpreferences/content/connectionSettingsDialog.js
=====================================
@@ -1,73 +1,67 @@
-import {
- TorSettings,
- TorProxyType,
-} from "resource://gre/modules/TorSettings.sys.mjs";
+"use strict";
-import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
+const { TorSettings, TorProxyType } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorSettings.sys.mjs"
+);
-export class ConnectionSettingsDialog {
- constructor() {
- this._dialog = null;
- this._useProxyCheckbox = null;
- this._proxyTypeLabel = null;
- this._proxyTypeMenulist = null;
- this._proxyAddressLabel = null;
- this._proxyAddressTextbox = null;
- this._proxyPortLabel = null;
- this._proxyPortTextbox = null;
- this._proxyUsernameLabel = null;
- this._proxyUsernameTextbox = null;
- this._proxyPasswordLabel = null;
- this._proxyPasswordTextbox = null;
- this._useFirewallCheckbox = null;
- this._allowedPortsLabel = null;
- this._allowedPortsTextbox = null;
- }
+const { TorStrings } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorStrings.sys.mjs"
+);
- static get selectors() {
- return {
- header: "#torPreferences-connection-header",
- useProxyCheckbox: "checkbox#torPreferences-connection-toggleProxy",
- proxyTypeLabel: "label#torPreferences-localProxy-type",
- proxyTypeList: "menulist#torPreferences-localProxy-builtinList",
- proxyAddressLabel: "label#torPreferences-localProxy-address",
- proxyAddressTextbox: "input#torPreferences-localProxy-textboxAddress",
- proxyPortLabel: "label#torPreferences-localProxy-port",
- proxyPortTextbox: "input#torPreferences-localProxy-textboxPort",
- proxyUsernameLabel: "label#torPreferences-localProxy-username",
- proxyUsernameTextbox: "input#torPreferences-localProxy-textboxUsername",
- proxyPasswordLabel: "label#torPreferences-localProxy-password",
- proxyPasswordTextbox: "input#torPreferences-localProxy-textboxPassword",
- useFirewallCheckbox: "checkbox#torPreferences-connection-toggleFirewall",
- firewallAllowedPortsLabel: "label#torPreferences-connection-allowedPorts",
- firewallAllowedPortsTextbox:
- "input#torPreferences-connection-textboxAllowedPorts",
- };
- }
+const gConnectionSettingsDialog = {
+ _useProxyCheckbox: null,
+ _proxyTypeLabel: null,
+ _proxyTypeMenulist: null,
+ _proxyAddressLabel: null,
+ _proxyAddressTextbox: null,
+ _proxyPortLabel: null,
+ _proxyPortTextbox: null,
+ _proxyUsernameLabel: null,
+ _proxyUsernameTextbox: null,
+ _proxyPasswordLabel: null,
+ _proxyPasswordTextbox: null,
+ _useFirewallCheckbox: null,
+ _allowedPortsLabel: null,
+ _allowedPortsTextbox: null,
+
+ selectors: {
+ header: "#torPreferences-connection-header",
+ useProxyCheckbox: "checkbox#torPreferences-connection-toggleProxy",
+ proxyTypeLabel: "label#torPreferences-localProxy-type",
+ proxyTypeList: "menulist#torPreferences-localProxy-builtinList",
+ proxyAddressLabel: "label#torPreferences-localProxy-address",
+ proxyAddressTextbox: "input#torPreferences-localProxy-textboxAddress",
+ proxyPortLabel: "label#torPreferences-localProxy-port",
+ proxyPortTextbox: "input#torPreferences-localProxy-textboxPort",
+ proxyUsernameLabel: "label#torPreferences-localProxy-username",
+ proxyUsernameTextbox: "input#torPreferences-localProxy-textboxUsername",
+ proxyPasswordLabel: "label#torPreferences-localProxy-password",
+ proxyPasswordTextbox: "input#torPreferences-localProxy-textboxPassword",
+ useFirewallCheckbox: "checkbox#torPreferences-connection-toggleFirewall",
+ firewallAllowedPortsLabel: "label#torPreferences-connection-allowedPorts",
+ firewallAllowedPortsTextbox:
+ "input#torPreferences-connection-textboxAllowedPorts",
+ },
// disables the provided list of elements
_setElementsDisabled(elements, disabled) {
for (let currentElement of elements) {
currentElement.disabled = disabled;
}
- }
+ },
- _populateXUL(window, aDialog) {
- const selectors = ConnectionSettingsDialog.selectors;
+ init() {
+ const selectors = this.selectors;
- this._dialog = aDialog;
- const dialogWin = this._dialog.parentElement;
- dialogWin.setAttribute(
+ document.documentElement.setAttribute(
"title",
TorStrings.settings.connectionSettingsDialogTitle
);
- this._dialog.querySelector(selectors.header).textContent =
+ document.querySelector(selectors.header).textContent =
TorStrings.settings.connectionSettingsDialogHeader;
// Local Proxy
- this._useProxyCheckbox = this._dialog.querySelector(
- selectors.useProxyCheckbox
- );
+ this._useProxyCheckbox = document.querySelector(selectors.useProxyCheckbox);
this._useProxyCheckbox.setAttribute(
"label",
TorStrings.settings.useLocalProxy
@@ -76,7 +70,7 @@ export class ConnectionSettingsDialog {
const checked = this._useProxyCheckbox.checked;
this.onToggleProxy(checked);
});
- this._proxyTypeLabel = this._dialog.querySelector(selectors.proxyTypeLabel);
+ this._proxyTypeLabel = document.querySelector(selectors.proxyTypeLabel);
this._proxyTypeLabel.setAttribute("value", TorStrings.settings.proxyType);
let mockProxies = [
@@ -90,9 +84,7 @@ export class ConnectionSettingsDialog {
},
{ value: TorProxyType.HTTPS, label: TorStrings.settings.proxyTypeHTTP },
];
- this._proxyTypeMenulist = this._dialog.querySelector(
- selectors.proxyTypeList
- );
+ this._proxyTypeMenulist = document.querySelector(selectors.proxyTypeList);
this._proxyTypeMenulist.addEventListener("command", e => {
const value = this._proxyTypeMenulist.value;
this.onSelectProxyType(value);
@@ -104,14 +96,14 @@ export class ConnectionSettingsDialog {
this._proxyTypeMenulist.querySelector("menupopup").appendChild(menuEntry);
}
- this._proxyAddressLabel = this._dialog.querySelector(
+ this._proxyAddressLabel = document.querySelector(
selectors.proxyAddressLabel
);
this._proxyAddressLabel.setAttribute(
"value",
TorStrings.settings.proxyAddress
);
- this._proxyAddressTextbox = this._dialog.querySelector(
+ this._proxyAddressTextbox = document.querySelector(
selectors.proxyAddressTextbox
);
this._proxyAddressTextbox.setAttribute(
@@ -129,33 +121,31 @@ export class ConnectionSettingsDialog {
}
}
});
- this._proxyPortLabel = this._dialog.querySelector(selectors.proxyPortLabel);
+ this._proxyPortLabel = document.querySelector(selectors.proxyPortLabel);
this._proxyPortLabel.setAttribute("value", TorStrings.settings.proxyPort);
- this._proxyPortTextbox = this._dialog.querySelector(
- selectors.proxyPortTextbox
- );
- this._proxyUsernameLabel = this._dialog.querySelector(
+ this._proxyPortTextbox = document.querySelector(selectors.proxyPortTextbox);
+ this._proxyUsernameLabel = document.querySelector(
selectors.proxyUsernameLabel
);
this._proxyUsernameLabel.setAttribute(
"value",
TorStrings.settings.proxyUsername
);
- this._proxyUsernameTextbox = this._dialog.querySelector(
+ this._proxyUsernameTextbox = document.querySelector(
selectors.proxyUsernameTextbox
);
this._proxyUsernameTextbox.setAttribute(
"placeholder",
TorStrings.settings.proxyUsernamePasswordPlaceholder
);
- this._proxyPasswordLabel = this._dialog.querySelector(
+ this._proxyPasswordLabel = document.querySelector(
selectors.proxyPasswordLabel
);
this._proxyPasswordLabel.setAttribute(
"value",
TorStrings.settings.proxyPassword
);
- this._proxyPasswordTextbox = this._dialog.querySelector(
+ this._proxyPasswordTextbox = document.querySelector(
selectors.proxyPasswordTextbox
);
this._proxyPasswordTextbox.setAttribute(
@@ -174,7 +164,7 @@ export class ConnectionSettingsDialog {
}
// Local firewall
- this._useFirewallCheckbox = this._dialog.querySelector(
+ this._useFirewallCheckbox = document.querySelector(
selectors.useFirewallCheckbox
);
this._useFirewallCheckbox.setAttribute(
@@ -185,14 +175,14 @@ export class ConnectionSettingsDialog {
const checked = this._useFirewallCheckbox.checked;
this.onToggleFirewall(checked);
});
- this._allowedPortsLabel = this._dialog.querySelector(
+ this._allowedPortsLabel = document.querySelector(
selectors.firewallAllowedPortsLabel
);
this._allowedPortsLabel.setAttribute(
"value",
TorStrings.settings.allowedPorts
);
- this._allowedPortsTextbox = this._dialog.querySelector(
+ this._allowedPortsTextbox = document.querySelector(
selectors.firewallAllowedPortsTextbox
);
this._allowedPortsTextbox.setAttribute(
@@ -207,10 +197,11 @@ export class ConnectionSettingsDialog {
TorSettings.firewall.allowed_ports.join(", ");
}
- this._dialog.addEventListener("dialogaccept", e => {
+ const dialog = document.getElementById("torPreferences-connection-dialog");
+ dialog.addEventListener("dialogaccept", e => {
this._applySettings();
});
- }
+ },
// callback when proxy is toggled
onToggleProxy(enabled) {
@@ -235,7 +226,7 @@ export class ConnectionSettingsDialog {
if (enabled) {
this.onSelectProxyType(this._proxyTypeMenulist.value);
}
- }
+ },
// callback when proxy type is changed
onSelectProxyType(value) {
@@ -308,7 +299,7 @@ export class ConnectionSettingsDialog {
break;
}
}
- }
+ },
// callback when firewall proxy is toggled
onToggleFirewall(enabled) {
@@ -319,7 +310,7 @@ export class ConnectionSettingsDialog {
[this._allowedPortsLabel, this._allowedPortsTextbox],
disabled
);
- }
+ },
// pushes settings from UI to tor
_applySettings() {
@@ -372,17 +363,13 @@ export class ConnectionSettingsDialog {
TorSettings.saveToPrefs();
TorSettings.applySettings();
- }
-
- init(window, aDialog) {
- this._populateXUL(window, aDialog);
- }
+ },
+};
- openDialog(gSubDialog) {
- gSubDialog.open(
- "chrome://browser/content/torpreferences/connectionSettingsDialog.xhtml",
- { features: "resizable=yes" },
- this
- );
- }
-}
+window.addEventListener(
+ "DOMContentLoaded",
+ () => {
+ gConnectionSettingsDialog.init();
+ },
+ { once: true }
+);
=====================================
browser/components/torpreferences/content/connectionSettingsDialog.xhtml
=====================================
@@ -9,6 +9,8 @@
xmlns:html="http://www.w3.org/1999/xhtml"
>
<dialog id="torPreferences-connection-dialog" buttons="accept,cancel">
+ <script src="chrome://browser/content/torpreferences/connectionSettingsDialog.js" />
+
<html:h3 id="torPreferences-connection-header">​</html:h3>
<!-- Local Proxy -->
<checkbox id="torPreferences-connection-toggleProxy" label="​" />
@@ -78,16 +80,5 @@
/>
</hbox>
</box>
- <script type="application/javascript">
- <![CDATA[
- "use strict";
-
- let connectionSettingsDialog = window.arguments[0];
- document.addEventListener("DOMContentLoaded", () => {
- let dialog = document.getElementById("torPreferences-connection-dialog");
- connectionSettingsDialog.init(window, dialog);
- });
- ]]>
- </script>
</dialog>
</window>
=====================================
browser/components/torpreferences/content/provideBridgeDialog.mjs → browser/components/torpreferences/content/provideBridgeDialog.js
=====================================
@@ -1,53 +1,44 @@
-import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
-
-import {
- TorSettings,
- TorBridgeSource,
-} from "resource://gre/modules/TorSettings.sys.mjs";
-
-import {
- TorConnect,
- TorConnectTopics,
-} from "resource://gre/modules/TorConnect.sys.mjs";
-
-export class ProvideBridgeDialog {
- constructor(onSubmit) {
- this.onSubmit = onSubmit;
- this._dialog = null;
- this._textarea = null;
- this._acceptButton = null;
- }
-
- static get selectors() {
- return {
- description: "#torPreferences-provideBridge-description",
- textarea: "#torPreferences-provideBridge-textarea",
- };
- }
-
- _populateXUL(window, aDialog) {
- const selectors = ProvideBridgeDialog.selectors;
-
- const openHelp = () => {
+"use strict";
+
+const { TorStrings } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorStrings.sys.mjs"
+);
+
+const { TorSettings, TorBridgeSource } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorSettings.sys.mjs"
+);
+
+const { TorConnect, TorConnectTopics } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorConnect.sys.mjs"
+);
+
+const gProvideBridgeDialog = {
+ init() {
+ this._result = window.arguments[0];
+
+ document.documentElement.setAttribute(
+ "title",
+ TorStrings.settings.provideBridgeTitleAdd
+ );
+ 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"
);
- };
+ });
- this._dialog = aDialog;
- const dialogWin = this._dialog.parentElement;
- dialogWin.setAttribute("title", TorStrings.settings.provideBridgeTitleAdd);
- const learnMore = window.document.createXULElement("label");
- learnMore.className = "learnMore text-link";
- learnMore.setAttribute("is", "text-link");
- learnMore.setAttribute("value", TorStrings.settings.learnMore);
- learnMore.addEventListener("click", openHelp);
- const descr = this._dialog.querySelector(selectors.description);
- descr.textContent = "";
const pieces = TorStrings.settings.provideBridgeDescription.split("%S");
- descr.append(pieces[0], learnMore, pieces[1] || "");
- this._textarea = this._dialog.querySelector(selectors.textarea);
+ document
+ .getElementById("torPreferences-provideBridge-description")
+ .replaceChildren(pieces[0], learnMore, pieces[1] || "");
+
+ this._textarea = document.getElementById(
+ "torPreferences-provideBridge-textarea"
+ );
this._textarea.setAttribute(
"placeholder",
TorStrings.settings.provideBridgePlaceholder
@@ -58,32 +49,44 @@ export class ProvideBridgeDialog {
this._textarea.value = TorSettings.bridges.bridge_strings.join("\n");
}
- this._dialog.addEventListener("dialogaccept", e => {
- this.onSubmit(this._textarea.value, TorConnect.canBeginBootstrap);
+ const dialog = document.getElementById(
+ "torPreferences-provideBridge-dialog"
+ );
+ dialog.addEventListener("dialogaccept", e => {
+ this._result.accepted = true;
});
- this._acceptButton = this._dialog.getButton("accept");
+ this._acceptButton = dialog.getButton("accept");
Services.obs.addObserver(this, TorConnectTopics.StateChange);
this.onValueChange();
this.onAcceptStateChange();
- }
+ },
+
+ uninit() {
+ Services.obs.removeObserver(this, TorConnectTopics.StateChange);
+ },
onValueChange() {
// TODO: Do some proper value parsing and error reporting. See
// tor-browser#40552.
- this._acceptButton.disabled = !this._textarea.value.trim();
- }
+ const value = this._textarea.value.trim();
+ this._acceptButton.disabled = !value;
+ this._result.bridgeStrings = value;
+ },
onAcceptStateChange() {
+ const connect = TorConnect.canBeginBootstrap;
+ this._result.connect = connect;
+
this._acceptButton.setAttribute(
"label",
- TorConnect.canBeginBootstrap
+ connect
? TorStrings.settings.bridgeButtonConnect
: TorStrings.settings.bridgeButtonAccept
);
- }
+ },
observe(subject, topic, data) {
switch (topic) {
@@ -91,27 +94,20 @@ export class ProvideBridgeDialog {
this.onAcceptStateChange();
break;
}
- }
-
- init(window, aDialog) {
- this._populateXUL(window, aDialog);
- }
-
- close() {
- // Unregister our observer topics.
- Services.obs.removeObserver(this, TorConnectTopics.StateChange);
- }
-
- openDialog(gSubDialog) {
- gSubDialog.open(
- "chrome://browser/content/torpreferences/provideBridgeDialog.xhtml",
- {
- features: "resizable=yes",
- closingCallback: () => {
- this.close();
- },
+ },
+};
+
+window.addEventListener(
+ "DOMContentLoaded",
+ () => {
+ gProvideBridgeDialog.init();
+ window.addEventListener(
+ "unload",
+ () => {
+ gProvideBridgeDialog.uninit();
},
- this
+ { once: true }
);
- }
-}
+ },
+ { once: true }
+);
=====================================
browser/components/torpreferences/content/provideBridgeDialog.xhtml
=====================================
@@ -9,6 +9,8 @@
xmlns:html="http://www.w3.org/1999/xhtml"
>
<dialog id="torPreferences-provideBridge-dialog" buttons="accept,cancel">
+ <script src="chrome://browser/content/torpreferences/provideBridgeDialog.js" />
+
<description>
<html:div id="torPreferences-provideBridge-description"
>​<br />​</html:div
@@ -19,16 +21,5 @@
multiline="true"
rows="3"
/>
- <script type="application/javascript">
- <![CDATA[
- "use strict";
-
- let provideBridgeDialog = window.arguments[0];
- document.addEventListener("DOMContentLoaded", () => {
- let dialog = document.getElementById("torPreferences-provideBridge-dialog");
- provideBridgeDialog.init(window, dialog);
- });
- ]]>
- </script>
</dialog>
</window>
=====================================
browser/components/torpreferences/content/requestBridgeDialog.mjs → browser/components/torpreferences/content/requestBridgeDialog.js
=====================================
@@ -1,44 +1,39 @@
-import { BridgeDB } from "resource://gre/modules/BridgeDB.sys.mjs";
-import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
-
-import {
- TorConnect,
- TorConnectTopics,
-} from "resource://gre/modules/TorConnect.sys.mjs";
-
-export class RequestBridgeDialog {
- constructor(onSubmit) {
- this.onSubmit = onSubmit;
- this._dialog = null;
- this._submitButton = null;
- this._dialogHeader = null;
- this._captchaImage = null;
- this._captchaEntryTextbox = null;
- this._captchaRefreshButton = null;
- this._incorrectCaptchaHbox = null;
- this._incorrectCaptchaLabel = null;
- }
-
- static get selectors() {
- return {
- dialogHeader: "h3#torPreferences-requestBridge-header",
- captchaImage: "image#torPreferences-requestBridge-captchaImage",
- captchaEntryTextbox: "input#torPreferences-requestBridge-captchaTextbox",
- refreshCaptchaButton:
- "button#torPreferences-requestBridge-refreshCaptchaButton",
- incorrectCaptchaHbox:
- "hbox#torPreferences-requestBridge-incorrectCaptchaHbox",
- incorrectCaptchaLabel:
- "label#torPreferences-requestBridge-incorrectCaptchaError",
- };
- }
-
- _populateXUL(window, dialog) {
- const selectors = RequestBridgeDialog.selectors;
+"use strict";
+
+const { BridgeDB } = ChromeUtils.importESModule(
+ "resource://gre/modules/BridgeDB.sys.mjs"
+);
+const { TorStrings } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorStrings.sys.mjs"
+);
+
+const { TorConnect, TorConnectTopics } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorConnect.sys.mjs"
+);
+
+const gRequestBridgeDialog = {
+ selectors: {
+ dialogHeader: "h3#torPreferences-requestBridge-header",
+ captchaImage: "image#torPreferences-requestBridge-captchaImage",
+ captchaEntryTextbox: "input#torPreferences-requestBridge-captchaTextbox",
+ refreshCaptchaButton:
+ "button#torPreferences-requestBridge-refreshCaptchaButton",
+ incorrectCaptchaHbox:
+ "hbox#torPreferences-requestBridge-incorrectCaptchaHbox",
+ incorrectCaptchaLabel:
+ "label#torPreferences-requestBridge-incorrectCaptchaError",
+ },
+
+ init() {
+ this._result = window.arguments[0];
+
+ const selectors = this.selectors;
+
+ this._dialog = document.getElementById(
+ "torPreferences-requestBridge-dialog"
+ );
- this._dialog = dialog;
- const dialogWin = dialog.parentElement;
- dialogWin.setAttribute(
+ document.documentElement.setAttribute(
"title",
TorStrings.settings.requestBridgeDialogTitle
);
@@ -104,16 +99,24 @@ export class RequestBridgeDialog {
Services.obs.addObserver(this, TorConnectTopics.StateChange);
this.onAcceptStateChange();
- }
+ },
+
+ uninit() {
+ BridgeDB.close();
+ // Unregister our observer topics.
+ Services.obs.removeObserver(this, TorConnectTopics.StateChange);
+ },
onAcceptStateChange() {
+ const connect = TorConnect.canBeginBootstrap;
+ this._result.connect = connect;
this._submitButton.setAttribute(
"label",
- TorConnect.canBeginBootstrap
+ connect
? TorStrings.settings.bridgeButtonConnect
: TorStrings.settings.submitCaptcha
);
- }
+ },
observe(subject, topic, data) {
switch (topic) {
@@ -121,7 +124,7 @@ export class RequestBridgeDialog {
this.onAcceptStateChange();
break;
}
- }
+ },
_setcaptchaImage(uri) {
if (uri != this._captchaImage.src) {
@@ -131,27 +134,17 @@ export class RequestBridgeDialog {
this._captchaEntryTextbox.focus();
this._captchaEntryTextbox.select();
}
- }
+ },
_setUIDisabled(disabled) {
this._submitButton.disabled = this._captchaGuessIsEmpty() || disabled;
this._captchaEntryTextbox.disabled = disabled;
this._captchaRefreshButton.disabled = disabled;
- }
+ },
_captchaGuessIsEmpty() {
return this._captchaEntryTextbox.value == "";
- }
-
- init(window, dialog) {
- this._populateXUL(window, dialog);
- }
-
- close() {
- BridgeDB.close();
- // Unregister our observer topics.
- Services.obs.removeObserver(this, TorConnectTopics.StateChange);
- }
+ },
/*
Event Handlers
@@ -169,8 +162,9 @@ export class RequestBridgeDialog {
BridgeDB.submitCaptchaGuess(captchaText)
.then(aBridges => {
- if (aBridges) {
- this.onSubmit(aBridges, TorConnect.canBeginBootstrap);
+ if (aBridges && aBridges.length) {
+ this._result.accepted = true;
+ this._result.bridges = aBridges;
this._submitButton.disabled = false;
// This was successful, but use cancelDialog() to close, since
// we intercept the `dialogaccept` event.
@@ -186,7 +180,7 @@ export class RequestBridgeDialog {
this._incorrectCaptchaHbox.style.visibility = "visible";
console.log(aError);
});
- }
+ },
onRefreshCaptcha() {
this._setUIDisabled(true);
@@ -198,18 +192,20 @@ export class RequestBridgeDialog {
BridgeDB.requestNewCaptchaImage().then(uri => {
this._setcaptchaImage(uri);
});
- }
-
- openDialog(gSubDialog) {
- gSubDialog.open(
- "chrome://browser/content/torpreferences/requestBridgeDialog.xhtml",
- {
- features: "resizable=yes",
- closingCallback: () => {
- this.close();
- },
+ },
+};
+
+window.addEventListener(
+ "DOMContentLoaded",
+ () => {
+ gRequestBridgeDialog.init();
+ window.addEventListener(
+ "unload",
+ () => {
+ gRequestBridgeDialog.uninit();
},
- this
+ { once: true }
);
- }
-}
+ },
+ { once: true }
+);
=====================================
browser/components/torpreferences/content/requestBridgeDialog.xhtml
=====================================
@@ -9,6 +9,8 @@
xmlns:html="http://www.w3.org/1999/xhtml"
>
<dialog id="torPreferences-requestBridge-dialog" buttons="accept,cancel">
+ <script src="chrome://browser/content/torpreferences/requestBridgeDialog.js" />
+
<!-- ok, so ​ is a zero-width space. We need to have *something* in the innerText so that XUL knows how tall the
title node is so that it can determine how large to make the dialog element's inner draw area. If we have nothing
in the innerText, then it collapse to 0 height, and the contents of the dialog ends up partially hidden >:( -->
@@ -30,16 +32,5 @@
<image id="torPreferences-requestBridge-errorIcon" />
<label id="torPreferences-requestBridge-incorrectCaptchaError" flex="1" />
</hbox>
- <script type="application/javascript">
- <![CDATA[
- "use strict";
-
- let requestBridgeDialog = window.arguments[0];
- document.addEventListener("DOMContentLoaded", () => {
- let dialog = document.getElementById("torPreferences-requestBridge-dialog");
- requestBridgeDialog.init(window, dialog);
- });
- ]]>
- </script>
</dialog>
</window>
=====================================
browser/components/torpreferences/content/torLogDialog.js
=====================================
@@ -0,0 +1,62 @@
+"use strict";
+
+const { setTimeout, clearTimeout } = ChromeUtils.importESModule(
+ "resource://gre/modules/Timer.sys.mjs"
+);
+
+const { TorProviderBuilder } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorProviderBuilder.sys.mjs"
+);
+const { TorStrings } = ChromeUtils.importESModule(
+ "resource://gre/modules/TorStrings.sys.mjs"
+);
+
+window.addEventListener(
+ "DOMContentLoaded",
+ () => {
+ document.documentElement.setAttribute(
+ "title",
+ TorStrings.settings.torLogDialogTitle
+ );
+
+ const dialog = document.getElementById("torPreferences-torLog-dialog");
+ const copyLogButton = dialog.getButton("extra1");
+ copyLogButton.setAttribute("label", TorStrings.settings.copyLog);
+
+ const logText = document.getElementById(
+ "torPreferences-torDialog-textarea"
+ );
+
+ let restoreButtonTimeout = null;
+ copyLogButton.addEventListener("command", () => {
+ // Copy tor log messages to the system clipboard.
+ let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
+ Ci.nsIClipboardHelper
+ );
+ clipboard.copyString(logText.value);
+
+ const label = copyLogButton.querySelector("label");
+ label.setAttribute("value", TorStrings.settings.copied);
+ copyLogButton.classList.add("primary");
+
+ const RESTORE_TIME = 1200;
+ if (restoreButtonTimeout !== null) {
+ clearTimeout(restoreButtonTimeout);
+ }
+ restoreButtonTimeout = setTimeout(() => {
+ label.setAttribute("value", TorStrings.settings.copyLog);
+ copyLogButton.classList.remove("primary");
+ restoreButtonTimeout = null;
+ }, RESTORE_TIME);
+ });
+
+ // A waiting state should not be needed at this point.
+ // Also, we probably cannot even arrive here if the provider failed to
+ // initialize, otherwise we could use a try/catch, and write the exception
+ // text in the logs, instead.
+ TorProviderBuilder.build().then(
+ provider => (logText.value = provider.getLog())
+ );
+ },
+ { once: true }
+);
=====================================
browser/components/torpreferences/content/torLogDialog.mjs deleted
=====================================
@@ -1,78 +0,0 @@
-import { setTimeout, clearTimeout } from "resource://gre/modules/Timer.sys.mjs";
-
-import { TorProviderBuilder } from "resource://gre/modules/TorProviderBuilder.sys.mjs";
-import { TorStrings } from "resource://gre/modules/TorStrings.sys.mjs";
-
-export class TorLogDialog {
- constructor() {
- this._dialog = null;
- this._logTextarea = null;
- this._copyLogButton = null;
- this._restoreButtonTimeout = null;
- }
-
- static get selectors() {
- return {
- copyLogButton: "extra1",
- logTextarea: "textarea#torPreferences-torDialog-textarea",
- };
- }
-
- async _populateXUL(aDialog) {
- this._dialog = aDialog;
- const dialogWin = this._dialog.parentElement;
- dialogWin.setAttribute("title", TorStrings.settings.torLogDialogTitle);
-
- this._logTextarea = this._dialog.querySelector(
- TorLogDialog.selectors.logTextarea
- );
-
- this._copyLogButton = this._dialog.getButton(
- TorLogDialog.selectors.copyLogButton
- );
- this._copyLogButton.setAttribute("label", TorStrings.settings.copyLog);
- this._copyLogButton.addEventListener("command", () => {
- this.copyTorLog();
- const label = this._copyLogButton.querySelector("label");
- label.setAttribute("value", TorStrings.settings.copied);
- this._copyLogButton.classList.add("primary");
-
- const RESTORE_TIME = 1200;
- if (this._restoreButtonTimeout !== null) {
- clearTimeout(this._restoreButtonTimeout);
- }
- this._restoreButtonTimeout = setTimeout(() => {
- label.setAttribute("value", TorStrings.settings.copyLog);
- this._copyLogButton.classList.remove("primary");
- this._restoreButtonTimeout = null;
- }, RESTORE_TIME);
- });
-
- // A waiting state should not be needed at this point.
- // Also, we probably cannot even arrive here if the provider failed to
- // initialize, otherwise we could use a try/catch, and write the exception
- // text in the logs, instead.
- const provider = await TorProviderBuilder.build();
- this._logTextarea.value = provider.getLog();
- }
-
- init(window, aDialog) {
- this._populateXUL(aDialog);
- }
-
- copyTorLog() {
- // Copy tor log messages to the system clipboard.
- let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
- Ci.nsIClipboardHelper
- );
- clipboard.copyString(this._logTextarea.value);
- }
-
- openDialog(gSubDialog) {
- gSubDialog.open(
- "chrome://browser/content/torpreferences/torLogDialog.xhtml",
- { features: "resizable=yes" },
- this
- );
- }
-}
=====================================
browser/components/torpreferences/content/torLogDialog.xhtml
=====================================
@@ -9,21 +9,12 @@
xmlns:html="http://www.w3.org/1999/xhtml"
>
<dialog id="torPreferences-torLog-dialog" buttons="accept,extra1">
+ <script src="chrome://browser/content/torpreferences/torLogDialog.js" />
+
<html:textarea
id="torPreferences-torDialog-textarea"
multiline="true"
readonly="true"
/>
- <script type="application/javascript">
- <![CDATA[
- "use strict";
-
- let torLogDialog = window.arguments[0];
- document.addEventListener("DOMContentLoaded", () => {
- let dialog = document.getElementById("torPreferences-torLog-dialog");
- torLogDialog.init(window, dialog);
- });
- ]]>
- </script>
</dialog>
</window>
=====================================
browser/components/torpreferences/jar.mn
=====================================
@@ -2,19 +2,19 @@ browser.jar:
content/browser/torpreferences/bridge.svg (content/bridge.svg)
content/browser/torpreferences/bridge-qr.svg (content/bridge-qr.svg)
content/browser/torpreferences/bridgeQrDialog.xhtml (content/bridgeQrDialog.xhtml)
- content/browser/torpreferences/bridgeQrDialog.mjs (content/bridgeQrDialog.mjs)
+ content/browser/torpreferences/bridgeQrDialog.js (content/bridgeQrDialog.js)
content/browser/torpreferences/builtinBridgeDialog.xhtml (content/builtinBridgeDialog.xhtml)
- content/browser/torpreferences/builtinBridgeDialog.mjs (content/builtinBridgeDialog.mjs)
+ content/browser/torpreferences/builtinBridgeDialog.js (content/builtinBridgeDialog.js)
content/browser/torpreferences/connectionSettingsDialog.xhtml (content/connectionSettingsDialog.xhtml)
- content/browser/torpreferences/connectionSettingsDialog.mjs (content/connectionSettingsDialog.mjs)
+ content/browser/torpreferences/connectionSettingsDialog.js (content/connectionSettingsDialog.js)
content/browser/torpreferences/network.svg (content/network.svg)
content/browser/torpreferences/network-broken.svg (content/network-broken.svg)
content/browser/torpreferences/provideBridgeDialog.xhtml (content/provideBridgeDialog.xhtml)
- content/browser/torpreferences/provideBridgeDialog.mjs (content/provideBridgeDialog.mjs)
+ content/browser/torpreferences/provideBridgeDialog.js (content/provideBridgeDialog.js)
content/browser/torpreferences/requestBridgeDialog.xhtml (content/requestBridgeDialog.xhtml)
- content/browser/torpreferences/requestBridgeDialog.mjs (content/requestBridgeDialog.mjs)
+ content/browser/torpreferences/requestBridgeDialog.js (content/requestBridgeDialog.js)
content/browser/torpreferences/connectionCategory.inc.xhtml (content/connectionCategory.inc.xhtml)
- content/browser/torpreferences/torLogDialog.mjs (content/torLogDialog.mjs)
+ content/browser/torpreferences/torLogDialog.js (content/torLogDialog.js)
content/browser/torpreferences/torLogDialog.xhtml (content/torLogDialog.xhtml)
content/browser/torpreferences/connectionPane.js (content/connectionPane.js)
content/browser/torpreferences/connectionPane.xhtml (content/connectionPane.xhtml)
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/6211ed8…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/6211ed8…
You're receiving this email because of your account on gitlab.torproject.org.
1
0