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